Leaked source code of windows server 2003
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

/********************************************************************
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;
}