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.
390 lines
13 KiB
390 lines
13 KiB
/********************************************************************
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
PCH_Module.CPP
|
|
|
|
Abstract:
|
|
WBEM provider class implementation for PCH_Module class
|
|
|
|
Revision History:
|
|
|
|
Ghim-Sim Chua (gschua) 04/27/99
|
|
- Created
|
|
|
|
Jim Martin (a-jammar) 05/20/99
|
|
- Populated data fields.
|
|
|
|
********************************************************************/
|
|
|
|
#include "pchealth.h"
|
|
#include "PCH_Module.h"
|
|
#include <tlhelp32.h>
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// tracing stuff
|
|
|
|
#ifdef THIS_FILE
|
|
#undef THIS_FILE
|
|
#endif
|
|
static char __szTraceSourceFile[] = __FILE__;
|
|
#define THIS_FILE __szTraceSourceFile
|
|
#define TRACE_ID DCID_MODULE
|
|
|
|
CPCH_Module MyPCH_ModuleSet (PROVIDER_NAME_PCH_MODULE, PCH_NAMESPACE) ;
|
|
|
|
// Property names
|
|
//===============
|
|
|
|
const static WCHAR * pAddress = L"Address" ;
|
|
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 * pManufacturer = L"Manufacturer" ;
|
|
const static WCHAR * pName = L"Name" ;
|
|
const static WCHAR * pPartOf = L"PartOf" ;
|
|
const static WCHAR * pPath = L"Path" ;
|
|
const static WCHAR * pSize = L"Size" ;
|
|
const static WCHAR * pType = L"Type" ;
|
|
const static WCHAR * pVersion = L"Version" ;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The CModuleCollection class is used to gather all of the running modules.
|
|
// They can be found from the CIM_ProcessExecutable class, as the Antecedent
|
|
// property, with the following caveat: this enumeration will include
|
|
// duplicate entries of the same file (it will have a copy of a DLL for each
|
|
// time it's been loaded). This class will remove the duplicates, and save
|
|
// a list of filenames which can then be queried.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
class CModuleCollection
|
|
{
|
|
public:
|
|
CModuleCollection();
|
|
~CModuleCollection();
|
|
|
|
HRESULT Create(IEnumWbemClassObject * pEnum);
|
|
BOOL GetInstance(DWORD dwIndex, LPWSTR * pszFile);
|
|
|
|
private:
|
|
struct SModule
|
|
{
|
|
LPWSTR m_szFilename;
|
|
SModule * m_pNext;
|
|
|
|
SModule(LPWSTR szFilename, SModule * pNext) : m_pNext(pNext) { m_szFilename = szFilename; }
|
|
~SModule() { delete m_szFilename; }
|
|
};
|
|
|
|
SModule * m_pList;
|
|
SModule * m_pLastQueriedItem;
|
|
DWORD m_dwLastQueriedIndex;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The constructor and destructor are simple.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
CModuleCollection::CModuleCollection()
|
|
: m_pList(NULL),
|
|
m_pLastQueriedItem(NULL),
|
|
m_dwLastQueriedIndex(0)
|
|
{}
|
|
|
|
CModuleCollection::~CModuleCollection()
|
|
{
|
|
TraceFunctEnter("CModuleCollection::~CModuleCollection");
|
|
|
|
while (m_pList)
|
|
{
|
|
SModule * pNext = m_pList->m_pNext;
|
|
delete m_pList;
|
|
m_pList = pNext;
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The Create method creates the list of module names based on the enumerator
|
|
// passed in (which is assumed to enumerate Antecedents in
|
|
// CIM_ProcessExecutable).
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT CModuleCollection::Create(IEnumWbemClassObject * pEnum)
|
|
{
|
|
TraceFunctEnter("CModuleCollection::Create");
|
|
|
|
HRESULT hRes = S_OK;
|
|
IWbemClassObjectPtr pObj;
|
|
ULONG ulRetVal;
|
|
CComVariant varValue;
|
|
CComBSTR bstrFile("Antecedent");
|
|
|
|
while (WBEM_S_NO_ERROR == pEnum->Next(WBEM_INFINITE, 1, &pObj, &ulRetVal))
|
|
{
|
|
if (FAILED(pObj->Get(bstrFile, 0, &varValue, NULL, NULL)))
|
|
ErrorTrace(TRACE_ID, "Get on Antecedent field failed.");
|
|
else
|
|
{
|
|
// We need to convert the string from a BSTR to a LPCTSTR,
|
|
// and to only include the file part (without the WMI part).
|
|
// So we need to scan through the string until an '=' is
|
|
// found, then use the rest (minus enclosing quote marks)
|
|
// as the file path.
|
|
|
|
CComBSTR ccombstrValue(V_BSTR(&varValue));
|
|
UINT i = 0, uLen = SysStringLen(ccombstrValue);
|
|
|
|
// Scan to the '='.
|
|
|
|
while (i < uLen && ccombstrValue[i] != L'=')
|
|
i++;
|
|
|
|
// Skip over the '=' and any quotes.
|
|
|
|
while (i < uLen && (ccombstrValue[i] == L'=' || ccombstrValue[i] == L'"'))
|
|
i++;
|
|
|
|
// Allocate a character buffer and copy the string, converting it to
|
|
// lower case (to make comparisons faster later on).
|
|
|
|
LPWSTR szFilename = new WCHAR[uLen - i + 1];
|
|
if (!szFilename)
|
|
{
|
|
ErrorTrace(TRACE_ID, "CModuleCollection::Create out of memory");
|
|
throw CHeap_Exception(CHeap_Exception::E_ALLOCATION_ERROR);
|
|
}
|
|
|
|
for (int j = 0; i < uLen; j++, i++)
|
|
szFilename[j] = towlower(ccombstrValue[i]);
|
|
|
|
// Terminate the string - if it ends with a quote, overwrite that with a
|
|
// null character.
|
|
|
|
if (j && szFilename[j - 1] == L'"')
|
|
j -= 1;
|
|
szFilename[j] = L'\0';
|
|
|
|
// Check to see if this module is already in the list of strings.
|
|
|
|
SModule * pScan = m_pList;
|
|
while (pScan)
|
|
{
|
|
if (wcscmp(szFilename, pScan->m_szFilename) == 0)
|
|
break;
|
|
pScan = pScan->m_pNext;
|
|
}
|
|
|
|
if (pScan == NULL)
|
|
{
|
|
// We reached the end of the list without finding a duplicate.
|
|
// Add the new string to the list of modules, which will be responsible for
|
|
// deallocating the string.
|
|
|
|
SModule * pNew = new SModule(szFilename, m_pList);
|
|
if (!pNew)
|
|
{
|
|
delete [] szFilename;
|
|
ErrorTrace(TRACE_ID, "CModuleCollection::Create out of memory");
|
|
throw CHeap_Exception(CHeap_Exception::E_ALLOCATION_ERROR);
|
|
}
|
|
|
|
m_pList = pNew;
|
|
}
|
|
else
|
|
delete [] szFilename;
|
|
}
|
|
}
|
|
|
|
// Set the queried item pointer to the start of the list.
|
|
|
|
m_pLastQueriedItem = m_pList;
|
|
m_dwLastQueriedIndex = 0;
|
|
|
|
TraceFunctLeave();
|
|
return hRes;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Get the instance of module string 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 pszFile to point to the string if
|
|
// it exists, otherwise return FALSE.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BOOL CModuleCollection::GetInstance(DWORD dwIndex, LPWSTR * pszFile)
|
|
{
|
|
TraceFunctEnter("CModuleCollection::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_pList;
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
*pszFile = m_pLastQueriedItem->m_szFilename;
|
|
fResult = TRUE;
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return fResult;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION : CPCH_Module::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.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
typedef HANDLE (*CTH32)(DWORD, DWORD);
|
|
|
|
HRESULT CPCH_Module::EnumerateInstances(MethodContext * pMethodContext, long lFlags)
|
|
{
|
|
TraceFunctEnter("CPCH_Module::EnumerateInstances");
|
|
HRESULT hRes = WBEM_S_NO_ERROR;
|
|
|
|
// Get the date and time
|
|
|
|
SYSTEMTIME stUTCTime;
|
|
GetSystemTime(&stUTCTime);
|
|
|
|
// Create a toolhelp snapshot to get process information. We need to dynamically
|
|
// link to the function, because it might not be present on all platforms.
|
|
|
|
|
|
// The CModuleCollection class gathers a list of module names (which can then
|
|
// be used to retrieve information about each file).
|
|
|
|
CFileVersionInfo fileversioninfo;
|
|
CModuleCollection moduleinfo;
|
|
LPWSTR szFile;
|
|
DWORD dwIndex;
|
|
|
|
CComPtr<IEnumWbemClassObject> pEnum;
|
|
hRes = ExecWQLQuery(&pEnum, CComBSTR("SELECT Antecedent FROM CIM_ProcessExecutable"));
|
|
if (FAILED(hRes))
|
|
goto END;
|
|
|
|
hRes = moduleinfo.Create(pEnum);
|
|
if (FAILED(hRes))
|
|
goto END;
|
|
|
|
// Iterate through all of the module instances.
|
|
|
|
for (dwIndex = 0; moduleinfo.GetInstance(dwIndex, &szFile); dwIndex++)
|
|
{
|
|
if (!szFile)
|
|
continue;
|
|
|
|
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.");
|
|
|
|
// Using the filename, get the CIM_DataFile object.
|
|
|
|
CComPtr<IWbemClassObject> pFileObj;
|
|
CComBSTR ccombstrValue(szFile);
|
|
if (SUCCEEDED(GetCIMDataFile(ccombstrValue, &pFileObj, TRUE)))
|
|
{
|
|
// 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);
|
|
CopyProperty(pFileObj, L"Name", pInstance, pPath);
|
|
CopyProperty(pFileObj, L"EightDotThreeFileName", pInstance, pName);
|
|
CopyProperty(pFileObj, L"Manufacturer", pInstance, pManufacturer);
|
|
}
|
|
|
|
else
|
|
{
|
|
CComBSTR bstr;
|
|
VARIANT var;
|
|
WCHAR *pwsz;
|
|
|
|
// parse the file path to get the name out of it...
|
|
// the name should obviously be the last thing on the path, so
|
|
// search back from the end until we find a '\'. At that point,
|
|
// we've got the filename...
|
|
pwsz = ccombstrValue.m_str + SysStringLen(ccombstrValue.m_str) - 1;
|
|
while(pwsz >= ccombstrValue.m_str)
|
|
{
|
|
if (*pwsz == L'\\')
|
|
{
|
|
pwsz++;
|
|
break;
|
|
}
|
|
pwsz--;
|
|
}
|
|
|
|
bstr = pwsz;
|
|
|
|
VariantInit(&var);
|
|
V_VT(&var) = VT_BSTR;
|
|
V_BSTR(&var) = bstr.m_str;
|
|
if (pInstance->SetVariant(pName, var) == FALSE)
|
|
ErrorTrace(TRACE_ID, "SetVariant on name field failed.");
|
|
}
|
|
|
|
if (SUCCEEDED(fileversioninfo.QueryFile(szFile, TRUE)))
|
|
{
|
|
if (!pInstance->SetCHString(pDescription, fileversioninfo.GetDescription()))
|
|
ErrorTrace(TRACE_ID, "SetCHString on description field failed.");
|
|
|
|
if (!pInstance->SetCHString(pPartOf, fileversioninfo.GetProduct()))
|
|
ErrorTrace(TRACE_ID, "SetCHString on partof field failed.");
|
|
}
|
|
|
|
|
|
hRes = pInstance->Commit();
|
|
if (FAILED(hRes))
|
|
ErrorTrace(TRACE_ID, "Commit on Instance failed.");
|
|
}
|
|
|
|
END:
|
|
TraceFunctLeave();
|
|
return hRes;
|
|
}
|