You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
548 lines
19 KiB
548 lines
19 KiB
/********************************************************************
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
PCH_OLERegistration.CPP
|
|
|
|
Abstract:
|
|
WBEM provider class implementation for PCH_OLERegistration class
|
|
|
|
Revision History:
|
|
|
|
Ghim-Sim Chua (gschua) 04/27/99
|
|
- Created
|
|
|
|
Jim Martin (a-jammar) 05/14/99
|
|
- Gathering data.
|
|
|
|
********************************************************************/
|
|
|
|
#include "pchealth.h"
|
|
#include "PCH_OLERegistration.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// tracing stuff
|
|
|
|
#ifdef THIS_FILE
|
|
#undef THIS_FILE
|
|
#endif
|
|
static char __szTraceSourceFile[] = __FILE__;
|
|
#define THIS_FILE __szTraceSourceFile
|
|
#define TRACE_ID DCID_OLEREGISTRATION
|
|
|
|
CPCH_OLERegistration MyPCH_OLERegistrationSet (PROVIDER_NAME_PCH_OLEREGISTRATION, PCH_NAMESPACE) ;
|
|
|
|
// Property names
|
|
//===============
|
|
const static WCHAR * pCategory = L"Category" ;
|
|
const static WCHAR * pTimeStamp = L"TimeStamp" ;
|
|
const static WCHAR * pChange = L"Change" ;
|
|
const static WCHAR * pDate = L"Date" ;
|
|
const static WCHAR * pDescription = L"Description" ;
|
|
const static WCHAR * pObject = L"Object" ;
|
|
const static WCHAR * pProgramFile = L"ProgramFile" ;
|
|
const static WCHAR * pSize = L"Size" ;
|
|
const static WCHAR * pVersion = L"Version" ;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The COLERegItem class encapsulates a single OLE Registration item, and is
|
|
// used to build a linked list of items. Note that the constructor is private,
|
|
// since the only way one of these is created is by the friend class
|
|
// COLEItemCollection.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#define CATEGORY_LEN 9
|
|
#define DESCRIPTION_LEN 128
|
|
#define OBJECT_LEN 128
|
|
#define PROGRAM_LEN MAX_PATH
|
|
|
|
class COLEItemCollection;
|
|
class COLERegItem
|
|
{
|
|
friend class COLEItemCollection;
|
|
private:
|
|
TCHAR m_szCategory[CATEGORY_LEN];
|
|
TCHAR m_szDescription[DESCRIPTION_LEN];
|
|
TCHAR m_szObject[OBJECT_LEN];
|
|
TCHAR m_szProgramFile[PROGRAM_LEN];
|
|
|
|
public:
|
|
LPCTSTR GetCategory() { return m_szCategory; };
|
|
LPCTSTR GetDescription() { return m_szDescription; };
|
|
LPCTSTR GetObject() { return m_szObject; };
|
|
LPCTSTR GetProgramFile() { return m_szProgramFile; };
|
|
|
|
private:
|
|
COLERegItem();
|
|
|
|
COLERegItem * m_pNext;
|
|
};
|
|
|
|
COLERegItem::COLERegItem()
|
|
{
|
|
m_szCategory[0] = _T('\0');
|
|
m_szDescription[0] = _T('\0');
|
|
m_szObject[0] = _T('\0');
|
|
m_szProgramFile[0] = _T('\0');
|
|
m_pNext = NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The COLEItemCollection class is used to gather all of the OLE Registration
|
|
// items (from the registry and INI file) when the object is constructed. The
|
|
// object is then used to iterate all of the items, returning COLERegItem
|
|
// pointers for each item found.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
class COLEItemCollection
|
|
{
|
|
public:
|
|
COLEItemCollection();
|
|
~COLEItemCollection();
|
|
|
|
BOOL GetInstance(DWORD dwIndex, COLERegItem ** ppoleitem);
|
|
|
|
private:
|
|
BOOL UpdateFromRegistry();
|
|
BOOL UpdateFromINIFile();
|
|
BOOL AddOLERegItem(LPCSTR szCategory, LPCSTR szDescription, LPCSTR szObject, LPCSTR szProgramFile);
|
|
|
|
COLERegItem * m_pItemList;
|
|
COLERegItem * m_pLastQueriedItem;
|
|
DWORD m_dwLastQueriedIndex;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Build the internal list of OLE registration items. This is done by looking
|
|
// in the registry and in the INI file. Also set the m_pLastQueriedItem pointer
|
|
// to the first item in the list (this cached pointer is used to improve
|
|
// indexed lookup speed for iterated indices).
|
|
//
|
|
// The destructor just deletes the list.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
COLEItemCollection::COLEItemCollection() : m_pItemList(NULL), m_dwLastQueriedIndex(0)
|
|
{
|
|
TraceFunctEnter("COLEItemCollection::COLEItemCollection");
|
|
|
|
// If UpdateFromRegistry fails, it would be because there isn't enough memory
|
|
// to create more list items, so don't bother calling UpdateFromINIFile.
|
|
|
|
if (UpdateFromRegistry())
|
|
UpdateFromINIFile();
|
|
|
|
m_pLastQueriedItem = m_pItemList;
|
|
|
|
TraceFunctLeave();
|
|
}
|
|
|
|
COLEItemCollection::~COLEItemCollection()
|
|
{
|
|
TraceFunctEnter("COLEItemCollection::~COLEItemCollection");
|
|
|
|
while (m_pItemList)
|
|
{
|
|
COLERegItem * pNext = m_pItemList->m_pNext;
|
|
delete m_pItemList;
|
|
m_pItemList = pNext;
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Get the instance of COLERegItem referenced by the index. This is stored
|
|
// internally as a linked list, but we'll cache a pointer for the last
|
|
// referenced dwIndex to improve performance if the dwIndex is iterated
|
|
// sequentially. Return TRUE and set ppoleitem to point to the instance if
|
|
// it exists, otherwise return FALSE.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BOOL COLEItemCollection::GetInstance(DWORD dwIndex, COLERegItem ** ppoleitem)
|
|
{
|
|
TraceFunctEnter("COLEItemCollection::GetInstance");
|
|
|
|
// If the call is for an index less than the last queried index (which
|
|
// should be rare), we need to scan from the start of the list.
|
|
|
|
if (dwIndex < m_dwLastQueriedIndex)
|
|
{
|
|
m_dwLastQueriedIndex = 0;
|
|
m_pLastQueriedItem = m_pItemList;
|
|
}
|
|
|
|
// Scan through the list by (dwIndex - m_dwLastQueriedIndex) items.
|
|
|
|
while (dwIndex > m_dwLastQueriedIndex && m_pLastQueriedItem)
|
|
{
|
|
m_pLastQueriedItem = m_pLastQueriedItem->m_pNext;
|
|
m_dwLastQueriedIndex += 1;
|
|
}
|
|
|
|
BOOL fResult = FALSE;
|
|
if (m_pLastQueriedItem)
|
|
{
|
|
*ppoleitem = m_pLastQueriedItem;
|
|
fResult = TRUE;
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return fResult;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Insert a new item in the COLERegItem linked list.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BOOL COLEItemCollection::AddOLERegItem(LPCSTR szCategory, LPCSTR szDescription, LPCSTR szObject, LPCSTR szProgramFile)
|
|
{
|
|
TraceFunctEnter("COLEItemCollection::AddOLERegItem");
|
|
|
|
BOOL fReturn = FALSE;
|
|
COLERegItem * pNewNode = new COLERegItem;
|
|
|
|
if (pNewNode)
|
|
{
|
|
_tcsncpy(pNewNode->m_szCategory, szCategory, CATEGORY_LEN);
|
|
_tcsncpy(pNewNode->m_szDescription, szDescription, DESCRIPTION_LEN);
|
|
_tcsncpy(pNewNode->m_szObject, szObject, OBJECT_LEN);
|
|
_tcsncpy(pNewNode->m_szProgramFile, szProgramFile, PROGRAM_LEN);
|
|
|
|
pNewNode->m_pNext = m_pItemList;
|
|
m_pItemList = pNewNode;
|
|
fReturn = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ErrorTrace(TRACE_ID, "COLEItemCollection::AddOLERegItem out of memory.");
|
|
throw CHeap_Exception(CHeap_Exception::E_ALLOCATION_ERROR);
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return fReturn;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// This method retrieves OLE object information from the registry and adds
|
|
// it to the list of objects. Note - this code is essentially lifted from the
|
|
// source code for the OLE Registration OCX in MSInfo 4.10.
|
|
//
|
|
// Changes were made to remove MFC dependencies.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BOOL COLEItemCollection::UpdateFromRegistry()
|
|
{
|
|
TraceFunctEnter("COLEItemCollection::UpdateFromRegistry");
|
|
BOOL fReturn = TRUE;
|
|
|
|
// Fill in the information for the array of items. We do this by
|
|
// looking in the registry under the HKEY_CLASSES_ROOT key and
|
|
// enumerating all of the subkeys there.
|
|
|
|
TCHAR szCLSID[MAX_PATH];
|
|
TCHAR szObjectKey[OBJECT_LEN];
|
|
TCHAR szServer[PROGRAM_LEN];
|
|
TCHAR szTemp[MAX_PATH];
|
|
TCHAR szDescription[DESCRIPTION_LEN];
|
|
DWORD dwSize, dwType;
|
|
FILETIME filetime;
|
|
HKEY hkeyObject, hkeyServer, hkeyTest, hkeyCLSID, hkeySearch;
|
|
BOOL bInsertInList;
|
|
|
|
for (DWORD dwIndex = 0; TRUE; dwIndex++)
|
|
{
|
|
dwSize = OBJECT_LEN;
|
|
if (RegEnumKeyEx(HKEY_CLASSES_ROOT, dwIndex, szObjectKey, &dwSize, NULL, NULL, NULL, &filetime) != ERROR_SUCCESS)
|
|
break;
|
|
|
|
// Open the key for this object (we'll be using it a lot).
|
|
|
|
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CLASSES_ROOT, szObjectKey, 0, KEY_READ, &hkeyObject))
|
|
continue;
|
|
|
|
// Now we need to figure out if this subkey refers to an OLE object which
|
|
// we want to put into the list. Our first test is to see if there is
|
|
// a "NotInsertable" key under it. If there is, we skip this object.
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(hkeyObject, _T("NotInsertable"), 0, KEY_READ, &hkeyTest))
|
|
{
|
|
RegCloseKey(hkeyTest);
|
|
continue;
|
|
}
|
|
|
|
// The next test is to look for a CLSID. If there isn't one, then we
|
|
// will skip this object.
|
|
|
|
if (ERROR_SUCCESS != RegOpenKeyEx(hkeyObject, _T("CLSID"), 0, KEY_READ, &hkeyCLSID))
|
|
{
|
|
RegCloseKey(hkeyObject);
|
|
continue;
|
|
}
|
|
|
|
dwSize = MAX_PATH * sizeof(TCHAR);
|
|
if (ERROR_SUCCESS != RegQueryValueEx(hkeyCLSID, _T(""), NULL, &dwType, (LPBYTE) szCLSID, &dwSize))
|
|
{
|
|
RegCloseKey(hkeyObject);
|
|
RegCloseKey(hkeyCLSID);
|
|
continue;
|
|
}
|
|
RegCloseKey(hkeyCLSID);
|
|
|
|
// The next check is for a subkey called "protocol\StdFileEditing\server".
|
|
// If it is present, then this object should be inserted into the list.
|
|
|
|
bInsertInList = FALSE;
|
|
strcpy(szTemp, szObjectKey);
|
|
strcat(szTemp, "\\protocol\\StdFileEditing\\server");
|
|
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, szTemp, 0, KEY_READ, &hkeyServer) == ERROR_SUCCESS)
|
|
{
|
|
// Get the name of the server.
|
|
|
|
dwSize = MAX_PATH * sizeof(TCHAR);
|
|
if (RegQueryValueEx(hkeyServer, "", NULL, &dwType, (LPBYTE) szServer, &dwSize) != ERROR_SUCCESS || szServer[0] == '\0')
|
|
{
|
|
RegCloseKey(hkeyObject);
|
|
RegCloseKey(hkeyServer);
|
|
continue;
|
|
}
|
|
|
|
bInsertInList = TRUE;
|
|
RegCloseKey(hkeyServer);
|
|
}
|
|
|
|
// There's still another chance for this little fella to make it into the
|
|
// list. If the object is insertable (i.e. it has an "Insertable" key) and
|
|
// it a server can be found under HKEY_CLASSES_ROOT\CLSID\<clsid> key, then
|
|
// it makes it into the list.
|
|
|
|
if (!bInsertInList)
|
|
{
|
|
// First, make sure the object is insertable.
|
|
|
|
if (RegOpenKeyEx(hkeyObject, "Insertable", 0, KEY_READ, &hkeyTest) == ERROR_SUCCESS)
|
|
{
|
|
// There are four places to look for a server. We'll check for 32-bit
|
|
// servers first. When we've found one, use that server name and
|
|
// stop the search.
|
|
|
|
TCHAR * aszServerKeys[] = { _T("LocalServer32"), _T("InProcServer32"), _T("LocalServer"), _T("InProcServer"), _T("")};
|
|
for (int iServer = 0; *aszServerKeys[iServer] && !bInsertInList; iServer++)
|
|
{
|
|
_tcscpy(szTemp, _T("CLSID\\"));
|
|
_tcscat(szTemp, szCLSID);
|
|
_tcscat(szTemp, _T("\\"));
|
|
_tcscat(szTemp, aszServerKeys[iServer]);
|
|
|
|
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, szTemp, 0, KEY_READ, &hkeySearch) == ERROR_SUCCESS)
|
|
{
|
|
dwSize = PROGRAM_LEN * sizeof(TCHAR);
|
|
if (RegQueryValueEx(hkeySearch, _T(""), NULL, &dwType, (LPBYTE) szServer, &dwSize) == ERROR_SUCCESS && szServer[0] != '\0')
|
|
bInsertInList = TRUE;
|
|
RegCloseKey(hkeySearch);
|
|
}
|
|
}
|
|
}
|
|
RegCloseKey(hkeyTest);
|
|
}
|
|
|
|
if (bInsertInList)
|
|
{
|
|
// Get the description of the object. This can be found under the
|
|
// objects key as the default value.
|
|
|
|
dwSize = DESCRIPTION_LEN * sizeof(TCHAR);
|
|
if (ERROR_SUCCESS != RegQueryValueEx(hkeyObject, "", NULL, &dwType, (LPBYTE) szDescription, &dwSize))
|
|
szDescription[0] = _T('\0');
|
|
|
|
// Create a new OLE registration item entry. This might throw a memory exception,
|
|
// so close the hkeyObject handle first.
|
|
|
|
RegCloseKey(hkeyObject);
|
|
if (!AddOLERegItem(_T("REGISTRY"), szDescription, szObjectKey, szServer))
|
|
{
|
|
fReturn = FALSE;
|
|
goto END;
|
|
}
|
|
}
|
|
else
|
|
RegCloseKey(hkeyObject);
|
|
}
|
|
|
|
END:
|
|
TraceFunctLeave();
|
|
return fReturn;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// This method retrieves OLE object information from the INI file(s) and adds
|
|
// it to the list of objects. Note - this code is essentially lifted from the
|
|
// source code for the OLE Registration OCX in MSInfo 4.10.
|
|
//
|
|
// Changes were made to remove MFC dependencies.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BOOL COLEItemCollection::UpdateFromINIFile()
|
|
{
|
|
TraceFunctEnter("COLEItemCollection::UpdateFromINIFile");
|
|
|
|
TCHAR szProgram[PROGRAM_LEN];
|
|
TCHAR szDescription[DESCRIPTION_LEN];
|
|
LPTSTR szBuffer;
|
|
LPTSTR szEntry;
|
|
LPTSTR szScan;
|
|
TCHAR szData[MAX_PATH * 2];
|
|
BOOL fReturn = TRUE;
|
|
int i;
|
|
|
|
szBuffer = new TCHAR[2048];
|
|
if (szBuffer == NULL)
|
|
throw CHeap_Exception(CHeap_Exception::E_ALLOCATION_ERROR);
|
|
|
|
if (GetProfileString(_T("embedding"), NULL, _T("\0\0"), szBuffer, 2048) <= 2)
|
|
{
|
|
fReturn = FALSE;
|
|
goto END;
|
|
}
|
|
|
|
szEntry = szBuffer;
|
|
while (*szEntry != 0)
|
|
{
|
|
if (GetProfileString(_T("embedding"), szEntry, _T("\0\0"), szData, MAX_PATH * 2) > 1)
|
|
{
|
|
// Parse out the components of the string we retrieved. The string
|
|
// should be formed as "primary desc, registry desc, program, format".
|
|
|
|
szScan = szData;
|
|
|
|
i = _tcscspn(szScan, _T(","));
|
|
_tcsncpy(szDescription, szScan, (i < DESCRIPTION_LEN - 1) ? i : DESCRIPTION_LEN - 1);
|
|
szDescription[(i < DESCRIPTION_LEN - 1) ? i : DESCRIPTION_LEN - 1] = _T('\0');
|
|
szScan += i + 1;
|
|
|
|
szScan += _tcscspn(szScan, _T(",")) + 1; // skip registry
|
|
|
|
i = _tcscspn(szScan, _T(","));
|
|
_tcsncpy(szProgram, szScan, (i < PROGRAM_LEN - 1) ? i : PROGRAM_LEN - 1);
|
|
szProgram[(i < PROGRAM_LEN - 1) ? i : PROGRAM_LEN - 1] = _T('\0');
|
|
szScan += i + 1;
|
|
|
|
// Create a new OLE registration item entry. This might throw an exception.
|
|
|
|
try
|
|
{
|
|
if (!AddOLERegItem(_T("INIFILE"), szDescription, szEntry, szProgram))
|
|
{
|
|
fReturn = FALSE;
|
|
goto END;
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
if (szBuffer)
|
|
delete [] szBuffer;
|
|
throw;
|
|
}
|
|
}
|
|
szEntry += lstrlen(szEntry) + 1;
|
|
}
|
|
|
|
END:
|
|
if (szBuffer)
|
|
delete [] szBuffer;
|
|
TraceFunctLeave();
|
|
return fReturn;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION : CPCH_OLERegistration::EnumerateInstances
|
|
*
|
|
* DESCRIPTION : Returns all the instances of this class.
|
|
*
|
|
* INPUTS : A pointer to the MethodContext for communication with WinMgmt.
|
|
* A long that contains the flags described in
|
|
* IWbemServices::CreateInstanceEnumAsync. Note that the following
|
|
* flags are handled by (and filtered out by) WinMgmt:
|
|
* WBEM_FLAG_DEEP
|
|
* WBEM_FLAG_SHALLOW
|
|
* WBEM_FLAG_RETURN_IMMEDIATELY
|
|
* WBEM_FLAG_FORWARD_ONLY
|
|
* WBEM_FLAG_BIDIRECTIONAL
|
|
*
|
|
* RETURNS : WBEM_S_NO_ERROR if successful
|
|
*
|
|
* COMMENTS : TO DO: All instances on the machine should be returned here.
|
|
* If there are no instances, return WBEM_S_NO_ERROR.
|
|
* It is not an error to have no instances.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
HRESULT CPCH_OLERegistration::EnumerateInstances(MethodContext * pMethodContext, long lFlags)
|
|
{
|
|
TraceFunctEnter("CPCH_OLERegistration::EnumerateInstances");
|
|
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
// Get the date and time
|
|
|
|
SYSTEMTIME stUTCTime;
|
|
GetSystemTime(&stUTCTime);
|
|
|
|
// The COLEItemCollection class gathers data about the OLE registration objects when it's
|
|
// constructed. We can get info for each individual object using it's GetInstance
|
|
// pointer, which gives us a pointer to a COLERegItem object.
|
|
|
|
COLEItemCollection olereginfo;
|
|
COLERegItem * poleitem;
|
|
|
|
for (DWORD dwIndex = 0; olereginfo.GetInstance(dwIndex, &poleitem); dwIndex++)
|
|
{
|
|
CInstancePtr pInstance(CreateNewInstance(pMethodContext), false);
|
|
|
|
// Set the change and timestamp fields to "Snapshot" and the current time.
|
|
|
|
if (!pInstance->SetDateTime(pTimeStamp, WBEMTime(stUTCTime)))
|
|
ErrorTrace(TRACE_ID, "SetDateTime on Timestamp field failed.");
|
|
|
|
if (!pInstance->SetCHString(pChange, L"Snapshot"))
|
|
ErrorTrace(TRACE_ID, "SetCHString on Change field failed.");
|
|
|
|
// Set each of the other fields to the values we found when we retrieved
|
|
// the OLE objects from the registry and INI files.
|
|
|
|
if (!pInstance->SetCHString(pCategory, poleitem->GetCategory()))
|
|
ErrorTrace(TRACE_ID, "SetCHString on Category field failed.");
|
|
|
|
if (!pInstance->SetCHString(pDescription, poleitem->GetDescription()))
|
|
ErrorTrace(TRACE_ID, "SetCHString on Description field failed.");
|
|
|
|
if (!pInstance->SetCHString(pProgramFile, poleitem->GetProgramFile()))
|
|
ErrorTrace(TRACE_ID, "SetCHString on ProgramFile field failed.");
|
|
|
|
if (!pInstance->SetCHString(pObject, poleitem->GetObject()))
|
|
ErrorTrace(TRACE_ID, "SetCHString on Object field failed.");
|
|
|
|
LPCSTR szFile = poleitem->GetProgramFile();
|
|
if (szFile && szFile[0])
|
|
{
|
|
CComPtr<IWbemClassObject> pFileObj;
|
|
CComBSTR ccombstrValue(szFile);
|
|
if (SUCCEEDED(GetCIMDataFile(ccombstrValue, &pFileObj)))
|
|
{
|
|
// Using the CIM_DataFile object, copy over the appropriate properties.
|
|
|
|
CopyProperty(pFileObj, L"Version", pInstance, pVersion);
|
|
CopyProperty(pFileObj, L"FileSize", pInstance, pSize);
|
|
CopyProperty(pFileObj, L"CreationDate", pInstance, pDate);
|
|
}
|
|
}
|
|
|
|
hRes = pInstance->Commit();
|
|
if (FAILED(hRes))
|
|
ErrorTrace(TRACE_ID, "Commit on Instance failed.");
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return hRes;
|
|
}
|