1094 lines
35 KiB
C++
1094 lines
35 KiB
C++
|
// MSInfo.cpp : Implementation of DLL Exports, main application object
|
||
|
// and Registry Object Map. All registry information (apart from
|
||
|
// MIDL) lives here.
|
||
|
//
|
||
|
// Copyright (c) 1998-1999 Microsoft Corporation
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "resource.h"
|
||
|
#include "initguid.h"
|
||
|
|
||
|
// This hack is required because we may be building in an environment
|
||
|
// which doesn't have a late enough version of rpcndr.h
|
||
|
#if __RPCNDR_H_VERSION__ < 440
|
||
|
#define __RPCNDR_H_VERSION__ 440
|
||
|
#define MIDL_INTERFACE(x) interface
|
||
|
#endif
|
||
|
|
||
|
#include "MSInfo.h"
|
||
|
#include "DataObj.h"
|
||
|
#include "CompData.h"
|
||
|
#include "About.h"
|
||
|
#include "Toolset.h"
|
||
|
#include "Dispatch.h"
|
||
|
|
||
|
#include "MSInfo_i.c"
|
||
|
|
||
|
static LPCTSTR cszBasePath = _T("Software\\Microsoft\\MMC");
|
||
|
static LPCTSTR cszBaseSnapinPath = _T("Software\\Microsoft\\MMC\\Snapins");
|
||
|
static LPCTSTR cszBaseNodeTypePath = _T("Software\\Microsoft\\MMC\\NodeTypes");
|
||
|
static LPCTSTR cszNameString = _T("NameString");
|
||
|
static LPCTSTR cszProvider = _T("Provider");
|
||
|
static LPCTSTR cszVersion = _T("Version");
|
||
|
static LPCTSTR cszAbout = _T("About");
|
||
|
static LPCTSTR cszStandAlone = _T("StandAlone");
|
||
|
static LPCTSTR cszNodeTypes = _T("NodeTypes");
|
||
|
static LPCTSTR cszExtensions = _T("Extensions");
|
||
|
static LPCTSTR cszNameSpace = _T("NameSpace");
|
||
|
static LPCTSTR cszTask = _T("Task");
|
||
|
|
||
|
static LPCTSTR cszMSInfoBaseKey = _T("Software\\Microsoft\\Shared Tools");
|
||
|
static LPCTSTR cszMSInfoSubKey = _T("MSInfo");
|
||
|
static LPCTSTR cszMSInfoKey = _T("Software\\Microsoft\\Shared Tools\\MSInfo");
|
||
|
static LPCTSTR cszPathValue = _T("Path");
|
||
|
static LPCTSTR cszRunKey = _T("Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\msinfo32.exe");
|
||
|
static LPCTSTR cszRunRootKey = _T("Software\\Microsoft\\Windows\\CurrentVersion\\App Paths");
|
||
|
static LPCTSTR cszRunSubKey = _T("msinfo32.exe");
|
||
|
|
||
|
static LPCTSTR cszNFOExtension = _T(".nfo");
|
||
|
static LPCTSTR cszOLERegistration = _T("MSInfo.Document");
|
||
|
static LPCTSTR cszDefaultIconKey = _T("DefaultIcon");
|
||
|
|
||
|
static LPCTSTR cszCLSIDKey = _T("CLSID");
|
||
|
static LPCTSTR cszShellKey = _T("shell");
|
||
|
static LPCTSTR cszOpenCommandKey = _T("open\\command");
|
||
|
static LPCTSTR cszPrintCommandKey = _T("print\\command");
|
||
|
static LPCTSTR cszPrintToKey = _T("printto\\command");
|
||
|
|
||
|
// note trailing quotes on file path
|
||
|
static LPCTSTR cszMSInfoPath = _T("Microsoft Shared\\MSInfo\\MSInfo32.exe\"");
|
||
|
static LPCTSTR cszDefaultIconValue = _T("Microsoft Shared\\MSInfo\\MSInfo32.exe\",0");
|
||
|
static LPCTSTR cszOpenCommand = _T("Microsoft Shared\\MSInfo\\MSInfo32.exe\" /msinfo_file \"%1\"");
|
||
|
|
||
|
// these are never referenced
|
||
|
static LPCTSTR cszMSInfoDir = _T("Common Files\\Microsoft Shared\\MSInfo\\");
|
||
|
static LPCTSTR cszPrintToCommand = _T("Common Files\\Microsoft Shared\\MSInfo\\MSInfo32.exe /pt \"%1\" \"%2\" \"%3\" \"%4\"");
|
||
|
//static LPCTSTR cszPrintCommand = _T("Common Files\\Microsoft Shared\\MSInfo\\MSInfo32.exe /p \"%1\"");
|
||
|
//a-kjaw
|
||
|
static LPCTSTR cszPrintCommand = _T("Microsoft Shared\\MSInfo\\MSInfo32.exe\" /p \"%1\"");
|
||
|
//a-kjaw
|
||
|
|
||
|
// Nodes we extend
|
||
|
static LPCTSTR cszCompMgrNode = _T("{476E6448-AAFF-11D0-B944-00C04FD8D5B0}");
|
||
|
|
||
|
CComModule _Module;
|
||
|
|
||
|
/*
|
||
|
* Object Map of Registered objects, allowing the Active Template Library to
|
||
|
* register our CLSIDs.
|
||
|
*/
|
||
|
BEGIN_OBJECT_MAP(ObjectMap)
|
||
|
OBJECT_ENTRY(CLSID_MSInfo, CSystemInfoScopePrimary)
|
||
|
OBJECT_ENTRY(CLSID_Extension, CSystemInfoScopeExtension)
|
||
|
OBJECT_ENTRY(CLSID_About, CAboutImpl)
|
||
|
OBJECT_ENTRY(CLSID_SystemInfo, CMSInfo)
|
||
|
END_OBJECT_MAP()
|
||
|
|
||
|
/*
|
||
|
* The MSInfo application object.
|
||
|
*
|
||
|
* History: a-jsari 10/1/97 Initial version.
|
||
|
*/
|
||
|
class CMSInfoApp : public CWinApp
|
||
|
{
|
||
|
public:
|
||
|
virtual BOOL InitInstance();
|
||
|
virtual int ExitInstance();
|
||
|
};
|
||
|
|
||
|
CMSInfoApp theApp;
|
||
|
|
||
|
/*
|
||
|
* InitInstance - Initialize an instance of the application.
|
||
|
*
|
||
|
* History: a-jsari 10/1/97 Initial version.
|
||
|
*/
|
||
|
|
||
|
extern void LoadDialogResources();
|
||
|
BOOL CMSInfoApp::InitInstance()
|
||
|
{
|
||
|
_Module.Init(ObjectMap, m_hInstance);
|
||
|
LoadDialogResources(); // loads dialog strings from resources
|
||
|
return CWinApp::InitInstance();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ExitInstance - Deconstruct an instance of the application.
|
||
|
*
|
||
|
* History: a-jsari 10/1/97 Initial version.
|
||
|
*/
|
||
|
int CMSInfoApp::ExitInstance()
|
||
|
{
|
||
|
_Module.Term();
|
||
|
return CWinApp::ExitInstance();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Used to determine whether the DLL can be unloaded by OLE
|
||
|
|
||
|
STDAPI DllCanUnloadNow(void)
|
||
|
{
|
||
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||
|
return (AfxDllCanUnloadNow()==S_OK && _Module.GetLockCount()==0) ? S_OK : S_FALSE;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Returns a class factory to create an object of the requested type
|
||
|
|
||
|
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
|
||
|
{
|
||
|
return _Module.GetClassObject(rclsid, riid, ppv);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* RegOpenMMCRoot - Open CRegKey
|
||
|
*
|
||
|
* History: a-jsari 9/9/97 Initial version
|
||
|
*/
|
||
|
static inline long RegOpenMMCRoot(CRegKey *pcrkMMCRoot)
|
||
|
{
|
||
|
return pcrkMMCRoot->Open(HKEY_LOCAL_MACHINE, cszBasePath);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* RegOpenMMCSnapinRoot - Return MMC's registry Snapin root
|
||
|
*
|
||
|
* History: a-jsari 9/9/97 Initial version
|
||
|
*/
|
||
|
static inline long RegOpenMMCSnapinRoot(CRegKey *pcrkSnapinRoot)
|
||
|
{
|
||
|
return pcrkSnapinRoot->Open(HKEY_LOCAL_MACHINE, cszBaseSnapinPath);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* RegOpenMMCNodeTypeRoot - Return MMC's registry NodeType root
|
||
|
*
|
||
|
* History: a-jsari 9/9/97 Initial version
|
||
|
*/
|
||
|
static inline long RegOpenMMCNodeTypeRoot(CRegKey *pcrkNodeTypesRoot)
|
||
|
{
|
||
|
return pcrkNodeTypesRoot->Open(HKEY_LOCAL_MACHINE, cszBaseNodeTypePath);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* RegisterStandaloneSnapin() - Do all registration for the Standalone
|
||
|
* portion of the snapin.
|
||
|
*
|
||
|
* History: a-jsari 9/9/97 Initial version
|
||
|
*
|
||
|
* Note: Would require AFX_MANAGE_STATE, except that the calling function
|
||
|
* handles it.
|
||
|
*/
|
||
|
static inline HRESULT RegisterStandaloneSnapin()
|
||
|
{
|
||
|
CRegKey crkRoot;
|
||
|
CRegKey crkClsid;
|
||
|
CRegKey crkIterator;
|
||
|
CString szResourceLoader;
|
||
|
|
||
|
HRESULT hr = E_FAIL;
|
||
|
|
||
|
do {
|
||
|
// HKEY_CLASSES_ROOT\.nfo
|
||
|
long lRegOpenResult = crkRoot.Create(HKEY_CLASSES_ROOT, cszNFOExtension);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
lRegOpenResult = crkRoot.SetValue(cszOLERegistration);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
crkRoot.Close();
|
||
|
|
||
|
// HKEY_CLASSES_ROOT\MSInfo.Document
|
||
|
lRegOpenResult = crkRoot.Create(HKEY_CLASSES_ROOT, cszOLERegistration);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
|
||
|
// This originally set the default value for the key to "msinfo.document", which
|
||
|
// is what would show up in the UI for a description of the NFO filetype. Fixing
|
||
|
// this to load the string from a resource (bug 10442).
|
||
|
//
|
||
|
// lRegOpenResult = crkRoot.SetValue(cszOLERegistration);
|
||
|
// if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
|
||
|
CString strDescription;
|
||
|
strDescription.LoadString(IDS_NFODESCRIPTION);
|
||
|
crkRoot.SetValue((LPCTSTR)strDescription);
|
||
|
|
||
|
lRegOpenResult = crkIterator.Create(crkRoot, cszCLSIDKey);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
lRegOpenResult = crkIterator.SetValue(cszClsidMSInfoSnapin);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
crkIterator.Close();
|
||
|
|
||
|
TCHAR szWindowsPath[MAX_PATH];
|
||
|
DWORD dwSize;
|
||
|
CString szPathValue;
|
||
|
dwSize = sizeof(szWindowsPath);
|
||
|
lRegOpenResult = crkIterator.Open(HKEY_LOCAL_MACHINE, cszWindowsCurrentKey);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
lRegOpenResult = crkIterator.QueryValue(szWindowsPath, cszCommonFilesValue, &dwSize);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
lRegOpenResult = crkIterator.Create(crkRoot, cszDefaultIconKey);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
szPathValue = _T("\"");
|
||
|
szPathValue += szWindowsPath;
|
||
|
szPathValue += _T("\\");
|
||
|
szPathValue += cszDefaultIconValue;
|
||
|
lRegOpenResult = crkIterator.SetValue(szPathValue);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
crkIterator.Close();
|
||
|
lRegOpenResult = crkRoot.Create(crkRoot, cszShellKey);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
lRegOpenResult = crkIterator.Create(crkRoot, cszOpenCommandKey);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
|
||
|
szPathValue = _T("\"");
|
||
|
szPathValue += szWindowsPath;
|
||
|
szPathValue += _T("\\");
|
||
|
szPathValue += cszOpenCommand;
|
||
|
|
||
|
lRegOpenResult = crkIterator.SetValue(szPathValue);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
crkIterator.Close();
|
||
|
//crkRoot.Close();
|
||
|
//a-kjaw
|
||
|
|
||
|
lRegOpenResult = crkIterator.Create(crkRoot, cszPrintCommandKey);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
|
||
|
szPathValue = _T("\"");
|
||
|
szPathValue += szWindowsPath;
|
||
|
szPathValue += _T("\\");
|
||
|
szPathValue += cszPrintCommand;
|
||
|
|
||
|
lRegOpenResult = crkIterator.SetValue(szPathValue);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
crkIterator.Close();
|
||
|
crkRoot.Close();
|
||
|
//a-kjaw
|
||
|
|
||
|
// HKEY_LOCAL_MACHINE\Software\Microsoft\MMC\Snapins
|
||
|
lRegOpenResult = RegOpenMMCSnapinRoot(&crkRoot);
|
||
|
|
||
|
// FIX: This fail should behave differently (registering the DLL
|
||
|
// w/o MMC registered).
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
// {45ac8c63-23e2-11e1-a696-00c04fd58bc3}
|
||
|
lRegOpenResult = crkClsid.Create(crkRoot, cszClsidMSInfoSnapin);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
// NameString = REG_SZ "Microsoft System Information"
|
||
|
VERIFY(szResourceLoader.LoadString(IDS_DESCRIPTION));
|
||
|
lRegOpenResult = crkClsid.SetValue(szResourceLoader, cszNameString);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
// About = REG_SZ "{45ac8c65-23e2-11e1-a696-00c04fd58bc3}"
|
||
|
lRegOpenResult = crkClsid.SetValue(cszClsidAboutMSInfo, cszAbout);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
// Provider = REG_SZ "Microsoft Corporation"
|
||
|
VERIFY(szResourceLoader.LoadString(IDS_COMPANY));
|
||
|
lRegOpenResult = crkClsid.SetValue(szResourceLoader, cszProvider);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
// Version = REG_SZ "5.0"
|
||
|
VERIFY(szResourceLoader.LoadString(IDS_VERSION));
|
||
|
lRegOpenResult = crkClsid.SetValue(szResourceLoader, cszVersion);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
// StandAlone
|
||
|
lRegOpenResult = crkIterator.Create(crkClsid, cszStandAlone);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
// NodeTypes
|
||
|
lRegOpenResult = crkIterator.Create(crkClsid, cszNodeTypes);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
// {45ac8c66-23e2-11e1-a696-00c04fd58bc3}
|
||
|
CRegKey crkNodeType;
|
||
|
lRegOpenResult = crkNodeType.Create(crkIterator, cszNodeTypeStatic);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
|
||
|
// Replace the SnapinRoot with the NodeType root;
|
||
|
// work from the new base.
|
||
|
// HKEY_LOCAL_MACHINE\Software\Microsoft\MMC\NodeTypes
|
||
|
lRegOpenResult = RegOpenMMCNodeTypeRoot(&crkRoot);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
// {45ac8c66-23e2-11e1-a696-00c04fd58bc3}
|
||
|
// = REG_SZ "Microsoft System Information Root"
|
||
|
VERIFY(szResourceLoader.LoadString(IDS_NODEDESCRIPTION));
|
||
|
lRegOpenResult = crkRoot.SetKeyValue(cszNodeTypeStatic, szResourceLoader);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) break;
|
||
|
hr = S_OK;
|
||
|
} while (0);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* HRESULT UnregisterStandaloneSnapin - Remove all registry entries for
|
||
|
* the standalone portion of the snapin.
|
||
|
*
|
||
|
* History: a-jsari 9/9/97 Initial version.
|
||
|
*/
|
||
|
static inline HRESULT UnregisterStandaloneSnapin()
|
||
|
{
|
||
|
CRegKey crkSnapinRoot;
|
||
|
|
||
|
// Remove HKEY_CLASSES_ROOT\.nfo
|
||
|
long lRegOpenResult = crkSnapinRoot.Open(HKEY_CLASSES_ROOT, NULL);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) {
|
||
|
if (lRegOpenResult != ERROR_FILE_NOT_FOUND) return E_FAIL;
|
||
|
} else {
|
||
|
lRegOpenResult = crkSnapinRoot.RecurseDeleteKey(cszNFOExtension);
|
||
|
// It's not really an error to not find a key we were deleting anyhow.
|
||
|
if (lRegOpenResult != ERROR_SUCCESS
|
||
|
&& lRegOpenResult != ERROR_FILE_NOT_FOUND) {
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
crkSnapinRoot.Close();
|
||
|
}
|
||
|
|
||
|
// Remove HKEY_CLASSES_ROOT\MSInfo.Document
|
||
|
lRegOpenResult = crkSnapinRoot.Open(HKEY_CLASSES_ROOT, NULL);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) {
|
||
|
if (lRegOpenResult != ERROR_FILE_NOT_FOUND) return E_FAIL;
|
||
|
} else {
|
||
|
lRegOpenResult = crkSnapinRoot.RecurseDeleteKey(cszOLERegistration);
|
||
|
// It's not really an error to not find a key we were deleting anyhow.
|
||
|
if (lRegOpenResult != ERROR_SUCCESS
|
||
|
&& lRegOpenResult != ERROR_FILE_NOT_FOUND) {
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
crkSnapinRoot.Close();
|
||
|
}
|
||
|
|
||
|
lRegOpenResult = RegOpenMMCSnapinRoot(&crkSnapinRoot);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) {
|
||
|
if (lRegOpenResult != ERROR_FILE_NOT_FOUND) return E_FAIL;
|
||
|
} else {
|
||
|
// Just recursively delete our root. Extensions will be automatically
|
||
|
// deleted as well.
|
||
|
lRegOpenResult = crkSnapinRoot.RecurseDeleteKey(cszClsidMSInfoSnapin);
|
||
|
// It's not really an error to not find a key we were deleting anyhow.
|
||
|
if (lRegOpenResult != ERROR_SUCCESS
|
||
|
&& lRegOpenResult != ERROR_FILE_NOT_FOUND) {
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lRegOpenResult = RegOpenMMCNodeTypeRoot(&crkSnapinRoot);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) {
|
||
|
if (lRegOpenResult != ERROR_FILE_NOT_FOUND) return E_FAIL;
|
||
|
} else {
|
||
|
lRegOpenResult = crkSnapinRoot.RecurseDeleteKey(cszNodeTypeStatic);
|
||
|
|
||
|
ASSERT(lRegOpenResult == ERROR_SUCCESS);
|
||
|
// It's not really an error to not find a key we were deleting anyhow.
|
||
|
if (lRegOpenResult != ERROR_SUCCESS
|
||
|
&& lRegOpenResult != ERROR_FILE_NOT_FOUND) {
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* OpenExtendKeyForNodeType - Return in pcrkExtension the Registry Key for
|
||
|
* HKEY_LOCAL_MACHINE\Software\Microsoft\MMC\NodeTypes\
|
||
|
* cszNodeTypeGuid (GUID string) \Extensions
|
||
|
* If fCreateIfNonextistent is TRUE, the Extensions key (only) is created
|
||
|
* if it doesn't exist.
|
||
|
*
|
||
|
* Return Codes:
|
||
|
* S_OK - All operations succeeded.
|
||
|
* E_FAIL - A critical registry operation failed.
|
||
|
* E_ABORT - The GUID string could not be opened, or
|
||
|
* the Extensions key could not be opened (and
|
||
|
* fCreateIfNonexistent is FALSE).
|
||
|
*
|
||
|
* History: a-jsari 9/18/97 Initial version
|
||
|
*/
|
||
|
static inline HRESULT OpenExtendKeyForNodeType(LPCTSTR cszNodeTypeGuid,
|
||
|
CRegKey *pcrkExtension, BOOL fCreateIfNonexistent = TRUE)
|
||
|
{
|
||
|
CRegKey crkRoot;
|
||
|
CRegKey crkNodeToExtend;
|
||
|
|
||
|
ASSERT(pcrkExtension != NULL);
|
||
|
long lRegOpenResult = RegOpenMMCNodeTypeRoot(&crkRoot);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) return E_FAIL;
|
||
|
// Not finding the proper nodetype is a different kind of error
|
||
|
// than not finding MMC, or not creating a new one.
|
||
|
if (fCreateIfNonexistent) {
|
||
|
lRegOpenResult = crkNodeToExtend.Create(crkRoot, cszNodeTypeGuid);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) return E_FAIL;
|
||
|
lRegOpenResult = pcrkExtension->Create(crkNodeToExtend, cszExtensions);
|
||
|
} else {
|
||
|
lRegOpenResult = crkNodeToExtend.Open(crkRoot, cszNodeTypeGuid);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) return E_ABORT;
|
||
|
lRegOpenResult = pcrkExtension->Open(crkNodeToExtend, cszExtensions);
|
||
|
if (lRegOpenResult == ERROR_FILE_NOT_FOUND) return E_ABORT;
|
||
|
}
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) return E_FAIL;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ExtendNode - Does all registry extension required for the NodeType
|
||
|
* cszNodeTypeGuid.
|
||
|
*
|
||
|
* Return Codes:
|
||
|
* S_OK - Upon successful completion, or if cszNodeTypeGuid can't
|
||
|
* be found.
|
||
|
* E_FAIL - If MMC cannot be found or NodeTypeGuid can't be opened.
|
||
|
*
|
||
|
* History: a-jsari 9/9/97 Initial version
|
||
|
*/
|
||
|
static HRESULT ExtendNode(LPCTSTR cszNodeTypeGuid)
|
||
|
{
|
||
|
CRegKey crkExtension;
|
||
|
CRegKey crkIterator;
|
||
|
CString szResourceLoader;
|
||
|
|
||
|
HRESULT hrOpenExtension = OpenExtendKeyForNodeType(cszNodeTypeGuid,
|
||
|
&crkExtension, TRUE);
|
||
|
// Don't return an error if we can't open the cszNodeTypeGuid
|
||
|
if (hrOpenExtension != S_OK)
|
||
|
return hrOpenExtension == E_ABORT ? S_OK : hrOpenExtension;
|
||
|
|
||
|
// NameSpace
|
||
|
// {GUID} = "System Information Extension"
|
||
|
long lRegOpenResult = crkIterator.Create(crkExtension, cszNameSpace);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) return E_FAIL;
|
||
|
VERIFY(szResourceLoader.LoadString(IDS_EXTENSIONDESCRIPTION));
|
||
|
lRegOpenResult = crkIterator.SetValue(szResourceLoader, cszClsidMSInfoExtension);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) return E_FAIL;
|
||
|
// Task
|
||
|
// {GUID} = "System Information Extension"
|
||
|
lRegOpenResult = crkIterator.Create(crkExtension, cszTask);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) return E_FAIL;
|
||
|
lRegOpenResult = crkIterator.SetValue(szResourceLoader, cszClsidMSInfoExtension);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* HRESULT UnregisterNode - Remove all registry entries for a specific
|
||
|
* Nodetype.
|
||
|
*
|
||
|
* Return Codes:
|
||
|
* S_OK - If all of the essential nodes are found.
|
||
|
* E_FAIL - If any of the path to the keys to remove fail to be found.
|
||
|
*
|
||
|
* History: a-jsari 9/9/97 Initial version.
|
||
|
*/
|
||
|
static HRESULT UnregisterNode(LPCTSTR cszNodeTypeGuid)
|
||
|
{
|
||
|
CRegKey crkExtension;
|
||
|
CRegKey crkIterator;
|
||
|
|
||
|
HRESULT hrOpenExtension = OpenExtendKeyForNodeType(cszNodeTypeGuid,
|
||
|
&crkExtension);
|
||
|
ASSERT(hrOpenExtension == S_OK);
|
||
|
// Don't return an error if we can't open the cszNodeTypeGuid
|
||
|
if (hrOpenExtension != S_OK)
|
||
|
return (hrOpenExtension == E_ABORT) ? S_OK : hrOpenExtension;
|
||
|
long lRegOpenResult = crkIterator.Open(crkExtension, cszNameSpace);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS)
|
||
|
return (lRegOpenResult == ERROR_FILE_NOT_FOUND) ? S_OK : E_FAIL;
|
||
|
lRegOpenResult = crkIterator.DeleteValue(cszClsidMSInfoExtension);
|
||
|
|
||
|
// It's not really an error to not find a key we were deleting anyhow.
|
||
|
if (lRegOpenResult != ERROR_SUCCESS
|
||
|
&& lRegOpenResult != ERROR_FILE_NOT_FOUND) {
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* RegisterExtensionSnapin - Do all registration required for the extension side
|
||
|
* of the snapin.
|
||
|
*
|
||
|
* History: a-jsari 9/9/97 Initial version
|
||
|
*/
|
||
|
static inline HRESULT RegisterExtensionSnapin()
|
||
|
{
|
||
|
const HRESULT hrErrorReturn = E_FAIL;
|
||
|
|
||
|
CRegKey crkRoot;
|
||
|
CRegKey crkClsid;
|
||
|
CRegKey crkIterator;
|
||
|
CString szResourceLoader;
|
||
|
|
||
|
// HKEY_LOCAL_MACHINE\Software\Microsoft\MMC\Snapins
|
||
|
long lRegOpenResult = RegOpenMMCSnapinRoot(&crkRoot);
|
||
|
|
||
|
// FIX: This fail should behave differently (registering the DLL
|
||
|
// w/o MMC registered).
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) return hrErrorReturn;
|
||
|
// {45ac8c63-23e2-11e1-a696-00c04fd58bc3}
|
||
|
lRegOpenResult = crkClsid.Create(crkRoot, cszClsidMSInfoExtension);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) return hrErrorReturn;
|
||
|
// NameString = REG_SZ "System Information Extension"
|
||
|
VERIFY(szResourceLoader.LoadString(IDS_EXTENSIONDESCRIPTION));
|
||
|
lRegOpenResult = crkClsid.SetValue(szResourceLoader, cszNameString);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) return hrErrorReturn;
|
||
|
// Provider = REG_SZ "Microsoft Corporation"
|
||
|
VERIFY(szResourceLoader.LoadString(IDS_COMPANY));
|
||
|
lRegOpenResult = crkClsid.SetValue(szResourceLoader, cszProvider);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) return hrErrorReturn;
|
||
|
// Version = REG_SZ "5.0"
|
||
|
VERIFY(szResourceLoader.LoadString(IDS_VERSION));
|
||
|
lRegOpenResult = crkClsid.SetValue(szResourceLoader, cszVersion);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) return hrErrorReturn;
|
||
|
|
||
|
// Register our about interface CLSID under the "About" value, so when
|
||
|
// we're being added as an extension, our information shows up.
|
||
|
|
||
|
lRegOpenResult = crkClsid.SetValue(cszClsidAboutMSInfo, cszAbout);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS)
|
||
|
return hrErrorReturn;
|
||
|
|
||
|
// NodeTypes
|
||
|
lRegOpenResult = crkIterator.Create(crkClsid, cszNodeTypes);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) return hrErrorReturn;
|
||
|
// {45ac8c66-23e2-11e1-a696-00c04fd58bc3}
|
||
|
CRegKey crkNodeType;
|
||
|
lRegOpenResult = crkNodeType.Create(crkIterator, cszNodeTypeStatic);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) return hrErrorReturn;
|
||
|
|
||
|
// We no longer want to extend the computer management node (138503).
|
||
|
// So we won't make this call to create the extension key. Also, we'll
|
||
|
// delete it if it exists.
|
||
|
//
|
||
|
// HRESULT hrExtend = ExtendNode(cszCompMgrNode);
|
||
|
// ASSERT(hrExtend == S_OK);
|
||
|
// return hrExtend;
|
||
|
|
||
|
CRegKey crkCompmgmtExtension;
|
||
|
if (SUCCEEDED(OpenExtendKeyForNodeType(cszCompMgrNode, &crkCompmgmtExtension, TRUE)))
|
||
|
{
|
||
|
CRegKey crkNameSpace, crkTaskPad;
|
||
|
|
||
|
if (ERROR_SUCCESS == crkNameSpace.Open((HKEY)crkCompmgmtExtension, cszNameSpace))
|
||
|
crkNameSpace.DeleteValue(cszClsidMSInfoExtension);
|
||
|
|
||
|
if (ERROR_SUCCESS == crkTaskPad.Open((HKEY)crkCompmgmtExtension, cszTask))
|
||
|
crkTaskPad.DeleteValue(cszClsidMSInfoExtension);
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* UnregisterExtensionSnapin - Unregister the extension part of the snapin.
|
||
|
*
|
||
|
* History: a-jsari 9/9/97 Initial version
|
||
|
*/
|
||
|
static inline HRESULT UnregisterExtensionSnapin()
|
||
|
{
|
||
|
CRegKey crkSnapinRoot;
|
||
|
|
||
|
long lRegOpenResult = RegOpenMMCSnapinRoot(&crkSnapinRoot);
|
||
|
if (lRegOpenResult != ERROR_SUCCESS) {
|
||
|
if (lRegOpenResult != ERROR_FILE_NOT_FOUND) return E_FAIL;
|
||
|
} else {
|
||
|
// CHECK: Is this appropriate for potential extensions (probably)
|
||
|
lRegOpenResult = crkSnapinRoot.RecurseDeleteKey(cszClsidMSInfoExtension);
|
||
|
|
||
|
ASSERT(lRegOpenResult == ERROR_SUCCESS);
|
||
|
// It's not really an error to not find a key we were deleting anyhow.
|
||
|
if (lRegOpenResult != ERROR_SUCCESS
|
||
|
&& lRegOpenResult != ERROR_FILE_NOT_FOUND) {
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT hrUnregister = UnregisterNode(cszCompMgrNode);
|
||
|
return hrUnregister;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* RegisterPaths - Perform registration for path items
|
||
|
*
|
||
|
* History: a-jsari 12/4/97 Initial version.
|
||
|
*/
|
||
|
static inline HRESULT RegisterPaths()
|
||
|
{
|
||
|
CRegKey crkSnapinRoot;
|
||
|
CRegKey crkProgramFilesKey;
|
||
|
TCHAR szBuffer[MAX_PATH];
|
||
|
CString strPath;
|
||
|
DWORD dwSize;
|
||
|
long lResult;
|
||
|
|
||
|
do {
|
||
|
// Register MSInfo's Windows App Path.
|
||
|
lResult = crkSnapinRoot.Open(HKEY_LOCAL_MACHINE, cszMSInfoKey);
|
||
|
ASSERT(lResult == ERROR_SUCCESS);
|
||
|
if (lResult != ERROR_SUCCESS) break;
|
||
|
dwSize = sizeof(szBuffer);
|
||
|
// Get the Path registry value into szBuffer
|
||
|
lResult = crkSnapinRoot.QueryValue(szBuffer, cszPathValue, &dwSize);
|
||
|
if (lResult != ERROR_SUCCESS) {
|
||
|
// The path can't be read from the registry; register it.
|
||
|
lResult = crkProgramFilesKey.Open(HKEY_LOCAL_MACHINE, cszWindowsCurrentKey);
|
||
|
ASSERT(lResult == ERROR_SUCCESS);
|
||
|
if (lResult != ERROR_SUCCESS) break;
|
||
|
dwSize = sizeof(szBuffer);
|
||
|
lResult = crkProgramFilesKey.QueryValue(szBuffer, cszCommonFilesValue, &dwSize);
|
||
|
ASSERT(lResult == ERROR_SUCCESS);
|
||
|
if (lResult != ERROR_SUCCESS) break;
|
||
|
|
||
|
// Remove the quotes from around the path. Bug #363834.
|
||
|
// strPath = "\"";
|
||
|
strPath = CString(_T(""));
|
||
|
strPath += szBuffer;
|
||
|
strPath += _T("\\");
|
||
|
strPath += cszMSInfoPath;
|
||
|
|
||
|
// Remove the quotes from around the path to mimic the behaviour of MSInfo 4.10
|
||
|
// (so that apps which used this key to launch MSInfo will continue to work). Bug #363834.
|
||
|
|
||
|
if (strPath.Right(1) == CString(_T("\"")))
|
||
|
strPath = strPath.Left(strPath.GetLength() - 1);
|
||
|
|
||
|
// Set the path value: Path = <Path to MSInfo32.exe>
|
||
|
lResult = crkSnapinRoot.SetValue(strPath, cszPathValue);
|
||
|
ASSERT(lResult == ERROR_SUCCESS);
|
||
|
if (lResult != ERROR_SUCCESS) break;
|
||
|
} else {
|
||
|
// Read the path from the previously registered location and set the variable
|
||
|
// equal to it.
|
||
|
strPath = szBuffer;
|
||
|
|
||
|
// Remove the quotes from around the path. Bug #363834.
|
||
|
|
||
|
if (strPath.Left(1) == CString(_T("\"")))
|
||
|
{
|
||
|
strPath = strPath.Right(strPath.GetLength() - 1);
|
||
|
if (strPath.Right(1) == CString(_T("\"")))
|
||
|
strPath = strPath.Left(strPath.GetLength() - 1);
|
||
|
|
||
|
lResult = crkSnapinRoot.SetValue(strPath, cszPathValue);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Bug #363834 - we still want quotes around the string when it's written elsewhere in the registry.
|
||
|
|
||
|
if (strPath.Left(1) != CString(_T("\"")))
|
||
|
strPath = _T("\"") + strPath;
|
||
|
|
||
|
if (strPath.Right(1) != CString(_T("\"")))
|
||
|
strPath += _T("\"");
|
||
|
|
||
|
lResult = crkSnapinRoot.Create(HKEY_LOCAL_MACHINE, cszRunKey);
|
||
|
ASSERT(lResult == ERROR_SUCCESS);
|
||
|
if (lResult != ERROR_SUCCESS) break;
|
||
|
lResult = crkSnapinRoot.SetValue(strPath);
|
||
|
ASSERT(lResult == ERROR_SUCCESS);
|
||
|
if (lResult != ERROR_SUCCESS) break;
|
||
|
int iValue = strPath.ReverseFind((TCHAR)'\\');
|
||
|
strPath = strPath.Left(iValue);
|
||
|
strPath += "\"";
|
||
|
|
||
|
lResult = crkSnapinRoot.SetValue(strPath, cszPathValue);
|
||
|
ASSERT(lResult == ERROR_SUCCESS);
|
||
|
if (lResult != ERROR_SUCCESS) break;
|
||
|
|
||
|
#if 0
|
||
|
// We are now assuming that the path to MSInfo will be registered by some
|
||
|
// outside agent, presumably setup.
|
||
|
// Register the Path in the MSInfo directory
|
||
|
lResult = crkSnapinRoot.Open(HKEY_LOCAL_MACHINE, cszMSInfoKey);
|
||
|
ASSERT(lResult == ERROR_SUCCESS);
|
||
|
if (lResult != ERROR_SUCCESS) break;
|
||
|
// Reuse the saved szPath value.
|
||
|
lResult = crkSnapinRoot.SetValue(szPath, cszPathValue);
|
||
|
ASSERT(lResult == ERROR_SUCCESS);
|
||
|
#endif
|
||
|
} while (FALSE);
|
||
|
return HRESULT_FROM_WIN32(lResult);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* UnregisterPaths - Remove registry entries for path items.
|
||
|
*
|
||
|
* History: a-jsari 12/4/97 Initial version
|
||
|
*/
|
||
|
static inline HRESULT UnregisterPaths()
|
||
|
{
|
||
|
CRegKey crkRootKey;
|
||
|
long lResult;
|
||
|
|
||
|
do {
|
||
|
// Remove the App Path
|
||
|
lResult = crkRootKey.Open(HKEY_LOCAL_MACHINE, cszRunRootKey);
|
||
|
if (lResult != ERROR_SUCCESS) break;
|
||
|
lResult = crkRootKey.DeleteSubKey(cszRunSubKey);
|
||
|
ASSERT(lResult == ERROR_SUCCESS);
|
||
|
if (lResult != ERROR_SUCCESS) break;
|
||
|
|
||
|
// Unregister the MSInfo Key
|
||
|
lResult = crkRootKey.Open(HKEY_LOCAL_MACHINE, cszMSInfoBaseKey);
|
||
|
ASSERT(lResult == ERROR_SUCCESS);
|
||
|
if (lResult != ERROR_SUCCESS) break;
|
||
|
lResult = crkRootKey.DeleteSubKey(cszMSInfoSubKey);
|
||
|
ASSERT(lResult == ERROR_SUCCESS);
|
||
|
} while (FALSE);
|
||
|
return HRESULT_FROM_WIN32(lResult);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* DllRegisterServer - Registers the snapin in
|
||
|
* HKEY_LOCAL_MACHINE\Software\Microsoft\MMC
|
||
|
* HKEY_LOCAL_MACHINE\Software\Classes\MSInfo.*
|
||
|
* HKEY_CLASSES_ROOT\CLSID\{45AC8C6...}
|
||
|
*
|
||
|
* History: a-jsari 9/9/97 Initial version.
|
||
|
*/
|
||
|
STDAPI DllRegisterServer(void)
|
||
|
{
|
||
|
long lToolResult;
|
||
|
if ((lToolResult = CToolList::Register(TRUE)) != ERROR_SUCCESS)
|
||
|
return HRESULT_FROM_WIN32(lToolResult);
|
||
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
||
|
HRESULT hrRegister = RegisterStandaloneSnapin();
|
||
|
if (hrRegister != S_OK) return hrRegister;
|
||
|
hrRegister = RegisterExtensionSnapin();
|
||
|
if (hrRegister != S_OK) return hrRegister;
|
||
|
hrRegister = RegisterPaths();
|
||
|
if (hrRegister != S_OK) return hrRegister;
|
||
|
// Registers object and all interfaces in typelib
|
||
|
#if 0
|
||
|
// This version has been failing
|
||
|
return _Module.RegisterServer(TRUE);
|
||
|
#else
|
||
|
// So use this method.
|
||
|
return _Module.RegisterServer(FALSE);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* DllUnregisterServer - Removes entries from the system registry
|
||
|
*
|
||
|
* History: a-jsari 9/9/97 Initial version.
|
||
|
*/
|
||
|
STDAPI DllUnregisterServer(void)
|
||
|
{
|
||
|
HRESULT hrReturn = S_OK;
|
||
|
long lToolResult;
|
||
|
|
||
|
if ((lToolResult = CToolList::Register(FALSE)) != ERROR_SUCCESS)
|
||
|
hrReturn = HRESULT_FROM_WIN32(lToolResult);
|
||
|
HRESULT hrUnregister = UnregisterStandaloneSnapin();
|
||
|
if (hrUnregister != S_OK) hrReturn = hrUnregister;
|
||
|
hrUnregister = UnregisterExtensionSnapin();
|
||
|
if (hrUnregister != S_OK) hrReturn = hrUnregister;
|
||
|
hrUnregister = UnregisterPaths();
|
||
|
if (hrUnregister != S_OK) hrReturn = hrUnregister;
|
||
|
_Module.UnregisterServer();
|
||
|
return hrReturn;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Implementation for the CMSInfoLog class, used to keep a log of MSInfo
|
||
|
// activities.
|
||
|
//
|
||
|
// This global variable can be used elsewhere in the snap-in to write log
|
||
|
// entries. Only one should be created.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
CMSInfoLog msiLog;
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// The constructor needs to read the logging state information from the
|
||
|
// registry.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
CMSInfoLog::CMSInfoLog()
|
||
|
{
|
||
|
m_pLogFile = NULL;
|
||
|
m_strEndMarker = _T("###"); // see note in OpenLogFile
|
||
|
ReadLoggingStatus();
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// The destructor needs to close the file (if it was ever created and opened).
|
||
|
// Also, this is a good place to put the exit MSInfo log entry.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
CMSInfoLog::~CMSInfoLog()
|
||
|
{
|
||
|
if (this->IsLogging())
|
||
|
this->WriteLog(CMSInfoLog::BASIC, _T("EXIT MSInfo\r\n"));
|
||
|
|
||
|
try
|
||
|
{
|
||
|
if (m_pLogFile)
|
||
|
{
|
||
|
// Advance past the marker we wrote.
|
||
|
|
||
|
m_pLogFile->Seek(m_strEndMarker.GetLength() * sizeof(TCHAR), CFile::current);
|
||
|
|
||
|
// If we aren't at the end of the file, then we've at some point wrapped
|
||
|
// to the beginning and are overwriting entries. To make it so there are
|
||
|
// no incomplete entries, write spaces until the end of the file or until
|
||
|
// we find a '\r' character.
|
||
|
|
||
|
DWORD dwLength = m_pLogFile->GetLength();
|
||
|
DWORD dwPosition = m_pLogFile->GetPosition();
|
||
|
if (dwPosition < dwLength)
|
||
|
{
|
||
|
DWORD dwBytesRead = 0;
|
||
|
TCHAR cRead;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if (m_pLogFile->Read((void *) &cRead, sizeof(TCHAR)) < sizeof(TCHAR))
|
||
|
break;
|
||
|
dwBytesRead += sizeof(TCHAR);
|
||
|
} while (cRead && cRead != _T('\r') && (dwPosition + dwBytesRead) < dwLength);
|
||
|
|
||
|
if (dwBytesRead)
|
||
|
{
|
||
|
m_pLogFile->Seek(dwBytesRead * -1, CFile::current);
|
||
|
|
||
|
// Write the spaces (but don't overwrite the '\r' character).
|
||
|
|
||
|
if (cRead == _T('\0') || cRead == _T('\r'))
|
||
|
dwBytesRead -= sizeof(TCHAR);
|
||
|
WriteSpaces(dwBytesRead / sizeof(TCHAR));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_pLogFile->Close();
|
||
|
delete m_pLogFile;
|
||
|
m_pLogFile = NULL;
|
||
|
}
|
||
|
}
|
||
|
catch (CFileException *e)
|
||
|
{
|
||
|
// Some sort of file error - turn off logging.
|
||
|
|
||
|
m_fLoggingEnabled = FALSE;
|
||
|
m_iLoggingMask = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// These two WriteLog functions are for writing a log entry directly to the
|
||
|
// file. The second (with two string parameters) assumes that the first
|
||
|
// string is a format with a '%s' and the second is the replacement string.
|
||
|
//
|
||
|
// The iType parameter is used to indicate what sort of log entry this is.
|
||
|
// The const int values from the class definition should be used.
|
||
|
//
|
||
|
// If fContinuation is TRUE, then this write is to terminate a log entry which
|
||
|
// spans an operation, and should not have a timestamp added.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CMSInfoLog::WriteLog(int iType, const CString & strMessage, BOOL fContinuation)
|
||
|
{
|
||
|
if (!OpenLogFile())
|
||
|
return FALSE;
|
||
|
|
||
|
if ((m_iLoggingMask & iType) == 0)
|
||
|
return FALSE;
|
||
|
|
||
|
CString strWorking(strMessage);
|
||
|
|
||
|
// If this isn't the continuation of a previous log entry, then
|
||
|
// possibly add a timestamp.
|
||
|
|
||
|
if (!fContinuation && m_fTimestamp)
|
||
|
{
|
||
|
CTime time = CTime::GetCurrentTime();
|
||
|
strWorking = time.Format(_T("%Y-%m-%d %H:%M:%S ")) + strWorking;
|
||
|
}
|
||
|
|
||
|
return WriteLogInternal(strWorking);
|
||
|
}
|
||
|
|
||
|
BOOL CMSInfoLog::WriteLog(int iType, const CString & strFormat, const CString & strReplace1)
|
||
|
{
|
||
|
CString strCombined;
|
||
|
|
||
|
strCombined.Format(strFormat, strReplace1);
|
||
|
return WriteLog(iType, strCombined);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// This function is called each time a log entry is written, to insure that
|
||
|
// the log file is open. If we can't open the file, or shouldn't be logging in
|
||
|
// the first place, this function should return FALSE.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CMSInfoLog::OpenLogFile()
|
||
|
{
|
||
|
if (!m_fLoggingEnabled)
|
||
|
return FALSE;
|
||
|
|
||
|
if (m_pLogFile == NULL)
|
||
|
{
|
||
|
m_pLogFile = new CFile;
|
||
|
if (m_pLogFile == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
if (!m_pLogFile->Open(m_strFilename, CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite))
|
||
|
{
|
||
|
delete m_pLogFile;
|
||
|
m_pLogFile = NULL;
|
||
|
m_fLoggingEnabled = FALSE;
|
||
|
m_iLoggingMask = 0;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Move to the right place in the file. If the file is empty, we're
|
||
|
// already there. If not, look for the end marker (from the last time
|
||
|
// we added log entries). If there is one, we should be positioned over
|
||
|
// its first character. Otherwise, just move to the end of the file.
|
||
|
|
||
|
if (m_pLogFile->GetLength() != 0)
|
||
|
{
|
||
|
// IMPORTANT NOTE: We assume here (for efficiency) that the end
|
||
|
// marker is structured so that we don't need to back up when
|
||
|
// searching the file. For example, no markers of the form "aaab".
|
||
|
|
||
|
TCHAR cRead;
|
||
|
int iMarker = 0;
|
||
|
|
||
|
while (iMarker != m_strEndMarker.GetLength())
|
||
|
{
|
||
|
if (m_pLogFile->Read((void *) &cRead, sizeof(TCHAR)) < sizeof(TCHAR))
|
||
|
break;
|
||
|
|
||
|
if (cRead != m_strEndMarker[iMarker])
|
||
|
iMarker = 0;
|
||
|
|
||
|
if (cRead == m_strEndMarker[iMarker])
|
||
|
iMarker++;
|
||
|
}
|
||
|
|
||
|
if (iMarker == m_strEndMarker.GetLength())
|
||
|
m_pLogFile->Seek(m_strEndMarker.GetLength() * sizeof(TCHAR) * -1, CFile::current);
|
||
|
else
|
||
|
m_pLogFile->SeekToEnd();
|
||
|
}
|
||
|
}
|
||
|
catch (CFileException *e)
|
||
|
{
|
||
|
// Some sort of file error - turn off logging.
|
||
|
|
||
|
m_fLoggingEnabled = FALSE;
|
||
|
m_iLoggingMask = 0;
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// This function reads information about logging (what to log, where to log,
|
||
|
// etc.) out of the registry.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
void CMSInfoLog::ReadLoggingStatus()
|
||
|
{
|
||
|
m_fLoggingEnabled = FALSE;
|
||
|
m_fTimestamp = TRUE;
|
||
|
m_strFilename = _T("");
|
||
|
m_iLoggingMask = 0;
|
||
|
m_dwMaxFileSize = 32 * 1024;
|
||
|
|
||
|
CString strRegkey = CString(cszMSInfoKey) + CString(_T("\\Logging"));
|
||
|
CRegKey regkey;
|
||
|
|
||
|
if (ERROR_SUCCESS == regkey.Open(HKEY_LOCAL_MACHINE, strRegkey, KEY_READ))
|
||
|
{
|
||
|
DWORD dwTemp;
|
||
|
|
||
|
dwTemp = 0;
|
||
|
if (ERROR_SUCCESS == regkey.QueryValue(dwTemp, _T("LogMask")))
|
||
|
m_iLoggingMask = (int) dwTemp;
|
||
|
|
||
|
dwTemp = 0;
|
||
|
if (ERROR_SUCCESS == regkey.QueryValue(dwTemp, _T("LogFileMaxSize")))
|
||
|
m_dwMaxFileSize = dwTemp;
|
||
|
|
||
|
dwTemp = 0;
|
||
|
if (ERROR_SUCCESS == regkey.QueryValue(dwTemp, _T("LogTimestamp")))
|
||
|
m_fTimestamp = (dwTemp) ? TRUE : FALSE;
|
||
|
|
||
|
TCHAR szFilename[MAX_PATH];
|
||
|
dwTemp = MAX_PATH;
|
||
|
if (ERROR_SUCCESS == regkey.QueryValue(szFilename, _T("LogFilename"), &dwTemp))
|
||
|
m_strFilename = szFilename;
|
||
|
|
||
|
regkey.Close();
|
||
|
}
|
||
|
|
||
|
m_fLoggingEnabled = ((m_iLoggingMask != 0) && !m_strFilename.IsEmpty());
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Write a string to the log file. We should be positioned before the end
|
||
|
// marker in the file. Overwrite this, and add the end marker onto the end
|
||
|
// of the string we are writing.
|
||
|
//
|
||
|
// If we are too close to the maximum file size, then fill the rest of the
|
||
|
// file (to that point) with spaces, and wrap to the start of the file.
|
||
|
//
|
||
|
// After we've written the output, back up so that we are positioned over the
|
||
|
// start of the end marker.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CMSInfoLog::WriteLogInternal(const CString & strMessage)
|
||
|
{
|
||
|
CString strTerminated = strMessage + m_strEndMarker;
|
||
|
DWORD dwLength = strTerminated.GetLength() * sizeof(TCHAR);
|
||
|
|
||
|
if (m_pLogFile == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
// If we are too close to the max size of the file, write spaces to that
|
||
|
// size and start from the beginning.
|
||
|
|
||
|
DWORD dwPosition = m_pLogFile->GetPosition();
|
||
|
if (m_dwMaxFileSize && ((dwPosition + dwLength) > m_dwMaxFileSize))
|
||
|
{
|
||
|
WriteSpaces((m_dwMaxFileSize - dwPosition) / sizeof(TCHAR));
|
||
|
m_pLogFile->SeekToBegin();
|
||
|
}
|
||
|
|
||
|
// Write the string to the file.
|
||
|
|
||
|
m_pLogFile->Write((const void *) (LPCTSTR) strTerminated, strTerminated.GetLength() * sizeof(TCHAR));
|
||
|
|
||
|
// Finally, back up over the terminating characters.
|
||
|
|
||
|
m_pLogFile->Seek(m_strEndMarker.GetLength() * sizeof(TCHAR) * -1, CFile::current);
|
||
|
}
|
||
|
catch (CFileException *e)
|
||
|
{
|
||
|
// Some sort of file error - turn off logging.
|
||
|
|
||
|
m_fLoggingEnabled = FALSE;
|
||
|
m_iLoggingMask = 0;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Write the specified number of spaces to the file. (Note, this will already
|
||
|
// be inside an exeption handling block from the caller.)
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
void CMSInfoLog::WriteSpaces(DWORD dwCount)
|
||
|
{
|
||
|
TCHAR * szSpaceBuffer = NULL;
|
||
|
szSpaceBuffer = new TCHAR[dwCount];
|
||
|
if (szSpaceBuffer)
|
||
|
{
|
||
|
_tcsnset(szSpaceBuffer, _T(' '), dwCount);
|
||
|
m_pLogFile->Write((const void *) (LPCTSTR) szSpaceBuffer, dwCount * sizeof(TCHAR));
|
||
|
delete [] szSpaceBuffer;
|
||
|
}
|
||
|
}
|