2025-04-27 07:49:33 -04:00

741 lines
21 KiB
C++

// VSAEvent.cpp
#include "precomp.h"
#include "VSAProv.h"
#include "VSAEvent.h"
#include "Buffer.h"
#include <list>
#include <wstlallc.h>
#define INVALID_INDEX 0xFFFFFFFF
// ***DO NOT*** move these around!!! The order has to match the order of the
// VSA property indexes we get back from event buffers.
LPCWSTR szStandardParams[] =
{
// Default params
L"SourceMachine", // 0
L"SourceProcessId", // 1
L"SourceThreadId", // 2
L"SourceComponent", // 3
L"SourceSession", // 4
L"TargetMachine", // 5
L"TargetProcessId", // 6
L"TargetThreadId", // 7
L"TargetComponent", // 8
L"TargetSession", // 9
L"SecurityIdentity", // 10
L"CausalityId", // 11
L"SourceProcessName", // 12
L"TargetProcessName", // 13
// No default params
L"SourceHandle", // 14
L"TargetHandle", // 15
L"Arguments", // 16
L"ReturnValue", // 17
L"Exception", // 18
L"CorrelationId", // 19
// Params specific to WMI classes
L"GenericParamNames", // 20
L"GenericParamValues", // 21
L"ProviderGUID", // 22
};
// Taken from the above table
#define GEN_NAMES_INDEX 20
#define GEN_VALUES_INDEX 21
#define PROVIDER_GUID_INDEX 22
CIMTYPE typesStandardParams[] =
{
// Default params
CIM_STRING, // L"SourceMachine", // 0
CIM_UINT32, // L"SourceProcessId", // 1
CIM_UINT32, // L"SourceThreadId", // 2
CIM_STRING, // L"SourceComponent", // 3
CIM_STRING, // L"SourceSession", // 4
CIM_STRING, // L"TargetMachine", // 5
CIM_UINT32, // L"TargetProcessId", // 6
CIM_UINT32, // L"TargetThreadId", // 7
CIM_STRING, // L"TargetComponent", // 8
CIM_STRING, // L"TargetSession", // 9
CIM_STRING, // L"SecurityIdentity", // 10
CIM_STRING, // L"CausalityId", // 11
CIM_STRING, // L"SourceProcessName", // 12
CIM_STRING, // L"TargetProcessName", // 13
// No default params
CIM_STRING, // L"SourceHandle", // 14
CIM_STRING, // L"TargetHandle", // 15
CIM_STRING, // L"Arguments", // 16
CIM_STRING, // L"ReturnValue", // 17
CIM_STRING, // L"Exception", // 18
CIM_STRING, // L"CorrelationId", // 19
CIM_STRING, //L"GenericParamNames", // 20
CIM_STRING, //L"GenericParamValues", // 21
CIM_STRING, //L"ProviderGUID", // 22
};
#define NUM_STANDARD_PARAMS (sizeof(typesStandardParams)/sizeof(typesStandardParams[0]))
#define STANDARD_BASE_BEGIN 0x6c736d61
#define STANDARD_BASE_END 0x6c736d74
static GUID guidStandardBase = {0x6c736d61,0xbcbf,0x11d0,{0x8a,0x23,0x00,0xaa,0x00,0xb5,0x8e,0x10}};
LPCWSTR szStandardClassNames[] =
{
L"MSFT_AppProfCall",
L"MSFT_AppProfReturn",
L"MSFT_AppProfComponentStart",
L"MSFT_AppProfComponentStop",
L"MSFT_AppProfCallData",
L"MSFT_AppProfEnter",
L"MSFT_AppProfEnterData",
L"MSFT_AppProfLeaveNormal",
L"MSFT_AppProfLeaveException",
L"MSFT_AppProfLeaveData",
L"MSFT_AppProfReturnData",
L"MSFT_AppProfReturnNormal",
L"MSFT_AppProfReturnException",
L"MSFT_AppProfQuerySend",
L"MSFT_AppProfQueryEnter",
L"MSFT_AppProfQueryLeave",
L"MSFT_AppProfQueryResult",
L"MSFT_AppProfTransactionStart",
L"MSFT_AppProfTransactionCommit",
L"MSFT_AppProfTransactionRollback",
};
//#define USE_WMI
BOOL CVSAEvent::InitFromGUID(IWbemServices *pSvc, GUID *pGUID)
{
WCHAR szGUID[100] = L"";
WCHAR szClassName[256] = L"";
BOOL bRet = FALSE;
StringFromGUID2(*pGUID, szGUID, COUNTOF(szGUID));
// See if it's one of the standard GUIDs.
if (!memcmp((DWORD*) &pGUID->Data2, &guidStandardBase.Data2,
sizeof(DWORD) * 3) &&
pGUID->Data1 >= STANDARD_BASE_BEGIN && pGUID->Data1 <= STANDARD_BASE_END)
{
wcscpy(szClassName, szStandardClassNames[pGUID->Data1 -
STANDARD_BASE_BEGIN]);
}
else
// Try to get it from WMI.
#ifdef USE_WMI
// TODO: This is currently broken, due to a bug in the core. Enable once we
// figure out what's wrong with the core.
{
LPWSTR szPath = new WCHAR[wcslen(szGUID) + 100];
if (szPath)
{
IWbemClassObjectPtr pObj;
swprintf(
szPath,
L"select * from MSFT_AppProfEventSetting where ClassName=\"%s\"",
szGUID);
IEnumWbemClassObjectPtr pEnum;
DWORD nCount = 0;
if (SUCCEEDED(
pSvc->ExecQuery(
_bstr_t(L"WQL"),
_bstr_t(szPath),
WBEM_FLAG_FORWARD_ONLY,
NULL,
&pEnum)) &&
SUCCEEDED(pEnum->Next(WBEM_INFINITE, 1, &pObj, &nCount)) && nCount)
{
_variant_t vClass;
if (SUCCEEDED(pObj->Get(L"WmiClassName", 0, &vClass, NULL, NULL)) &&
vClass.vt == VT_BSTR)
wcscpy(szClassName, V_BSTR(&vClass));
}
}
delete szPath;
}
#else
{
HKEY hKey;
// Try to get it from the registry.
char szEventKey[256];
sprintf(
szEventKey,
"SOFTWARE\\Microsoft\\VisualStudio\\Analyzer\\Events\\%S",
szGUID);
if (RegOpenKeyExA(
HKEY_LOCAL_MACHINE,
szEventKey,
0,
KEY_READ,
&hKey) == 0)
{
char szTempClassName[100] = "";
DWORD dwSize = sizeof(szTempClassName);
if (RegQueryValueExA(
hKey,
"WmiClassName", // To get an ANSI version.
NULL,
NULL,
(LPBYTE) &szTempClassName,
&dwSize) == 0)
{
mbstowcs(szClassName, szTempClassName, strlen(szTempClassName) + 1);
}
RegCloseKey(hKey);
}
}
#endif // #ifdef USE_WMI
// If we weren't able to find the class name, we'll have to use
// the generic class.
if (!*szClassName)
wcscpy(szClassName, GENERIC_VSA_EVENT);
if (Init(
pSvc,
szClassName,
szStandardParams,
NUM_STANDARD_PARAMS,
FAILED_PROP_IGNORE))
{
// Set this property only for the generic event. All other
// events can get this out of the UUID.
if (!_wcsicmp(GENERIC_VSA_EVENT, szClassName))
{
_variant_t vUUID = szGUID;
m_pObj->Put(L"EventGUID", 0, &vUUID, NULL);
}
// We clone off a copy into m_pObjBase. After every indicate
// we'll use this copy to clone a new blank copy into m_pObj.
if (SUCCEEDED(m_pObj->Clone(&m_pObjBase)))
bRet = TRUE;
}
return bRet;
}
#define DWORD_ALIGNED(x) (((x) + 3) & ~3)
HRESULT VSADataToCIMData(VSAParameterType typeVSA, LPBYTE pData,
CIMTYPE type, _variant_t &var, DWORD dwAccessIndex)
{
VSAParameterType typeVSABase = (VSAParameterType) (typeVSA & 0xF0000);
HRESULT hr = S_OK;
// If we're not using an IWbemObjectAccess handle, we'll need to convert
// 64-bit values to strings since IWbemClassObject::Put only accepts
// strings for 64-bit properties.
if (dwAccessIndex == INVALID_INDEX && type == CIM_UINT64)
type = CIM_STRING;
switch(type)
{
case CIM_UINT64:
var.vt = VT_I8;
switch(typeVSABase)
{
case cVSAParameterValueUnicodeString:
{
WCHAR *szBad;
*(DWORD64*) &var.iVal =
(DWORD64) wcstoul((LPCWSTR) pData, &szBad, 0);
break;
}
case cVSAParameterValueANSIString:
{
char *szBad;
*(DWORD64*) &var.iVal =
(DWORD64) strtoul((LPCSTR) pData, &szBad, 0);
break;
}
case cVSAParameterValueDWORD:
*(DWORD64*) &var.iVal = *(long*) pData;
break;
// No other conversions supported.
// TODO: Should we add one for byte arrays or GUIDs?
default:
hr = WBEM_E_FAILED;
}
break;
case CIM_STRING:
switch(typeVSABase)
{
case cVSAParameterValueUnicodeString:
var = (LPCWSTR) pData;
break;
case cVSAParameterValueANSIString:
var = (LPCSTR) pData;
break;
case cVSAParameterValueGUID:
{
WCHAR szGUID[100];
StringFromGUID2(*(GUID*) pData, szGUID, COUNTOF(szGUID));
var = szGUID;
break;
}
case cVSAParameterValueDWORD:
{
WCHAR szValue[100];
swprintf(szValue, _T("%u"), *(DWORD*) pData);
var = szValue;
break;
}
// No other conversions supported.
// TODO: Should we add one for byte arrays?
default:
hr = WBEM_E_FAILED;
}
break;
case CIM_SINT32:
case CIM_UINT32:
switch(typeVSABase)
{
case cVSAParameterValueUnicodeString:
{
WCHAR *szBad;
var = (long) wcstoul((LPCWSTR) pData, &szBad, 0);
break;
}
case cVSAParameterValueANSIString:
{
char *szBad;
var = (long) strtoul((LPCSTR) pData, &szBad, 0);
break;
}
case cVSAParameterValueDWORD:
var = *(long*) pData;
break;
// No other conversions supported.
// TODO: Should we add one for byte arrays or GUIDs?
default:
hr = WBEM_E_FAILED;
}
break;
case CIM_UINT8 | CIM_FLAG_ARRAY:
switch(typeVSABase)
{
case cVSAParameterValueBYTEArray:
{
SAFEARRAYBOUND bound;
var.vt = VT_UI1 | VT_ARRAY;
bound.lLbound = 0;
bound.cElements = typeVSA & 0xFFFF;
var.parray = SafeArrayCreate(VT_UI1, 1, &bound);
if (var.parray)
memcpy(var.parray->pvData, pData, typeVSA & 0xFFFF);
else
hr = WBEM_E_OUT_OF_MEMORY;
break;
}
// No other conversions supported.
default:
hr = WBEM_E_FAILED;
}
break;
// No other conversions supported.
default:
hr = WBEM_E_FAILED;
break;
}
return hr;
}
DWORD CVSAEvent::GetVSADataLength(LPBYTE pBuffer, VSAParameterType typeVSA)
{
VSAParameterType typeVSABase = (VSAParameterType) (typeVSA & 0xF0000);
DWORD dwRet = 0;
// Move the buffer past the current data.
switch(typeVSABase)
{
case cVSAParameterValueUnicodeString:
dwRet = (wcslen((LPCWSTR) pBuffer) + 1) * sizeof(WCHAR);
break;
case cVSAParameterValueANSIString:
dwRet = strlen((LPCSTR) pBuffer) + 1;
break;
case cVSAParameterValueGUID:
dwRet = sizeof(GUID);
break;
case cVSAParameterValueBYTEArray:
dwRet = typeVSA & 0xFFFF;
break;
case cVSAParameterValueDWORD:
dwRet = sizeof(DWORD);
break;
}
return dwRet;
}
DWORD CVSAEvent::GetCIMDataLength(VARIANT *pVar, CIMTYPE type)
{
DWORD dwRet = 0;
// Move the buffer past the current data.
switch(type)
{
case CIM_STRING:
dwRet = (wcslen(V_BSTR(pVar)) + 1) * sizeof(WCHAR);
break;
case CIM_UINT32:
case CIM_SINT32:
dwRet = sizeof(DWORD);
break;
case CIM_UINT64:
case CIM_SINT64:
dwRet = sizeof(DWORD64);
break;
case CIM_UINT8 | CIM_FLAG_ARRAY:
dwRet = pVar->parray->rgsabound[0].cElements;
break;
}
return dwRet;
}
typedef std::list<_bstr_t, wbem_allocator<_bstr_t> > CBstrList;
typedef CBstrList::iterator CBstrListIterator;
BOOL CVSAEvent::AreTypesEquivalent(CIMTYPE type, VSAParameterType typeVSA)
{
BOOL bRet;
bRet =
(type == CIM_STRING && typeVSA == cVSAParameterValueUnicodeString) ||
((type == CIM_UINT32 || type == CIM_SINT32) &&
typeVSA == cVSAParameterValueDWORD) ||
(type == (CIM_UINT8 | CIM_FLAG_ARRAY) &&
typeVSA == cVSAParameterValueBYTEArray);
return bRet;
}
HRESULT CVSAEvent::SetViaBuffer(LPCWSTR szProviderGuid, LPBYTE pBuffer)
{
VSA_EVENT_HEADER *pHeader = (VSA_EVENT_HEADER*) pBuffer;
LPBYTE pEnd = pBuffer + pHeader->dwSize;
CBuffer bufferGenNames,
bufferGenValues;
DWORD nGenValues = 0;
// Get past the header.
pBuffer += sizeof(VSA_EVENT_HEADER);
while (pBuffer < pEnd)
{
VSA_EVENT_FIELD *pField = (VSA_EVENT_FIELD*) pBuffer;
LPCWSTR szFieldName = NULL;
DWORD dwIndex = INVALID_INDEX;
CIMTYPE type;
BOOL bGeneric = FALSE;
DWORD dwDataLen;
BOOL bAlreadySet = FALSE;
// Is this a standard field?
if ((pField->dwType & 0x80000000) == 0)
{
dwIndex = pField->dwIndex;
// Normalize the index to a zero-based value if it's in the
// non-default range.
if (dwIndex >= 0x4000)
dwIndex = dwIndex - 0x4000 + cVSAStandardParameterDefaultLast + 1;
// Get pBuffer to point at the data.
pBuffer = ((LPBYTE) &pField->dwIndex) + sizeof(DWORD);
// Get the length of the data.
dwDataLen = GetVSADataLength(pBuffer, (VSAParameterType) pField->dwType);
// If we find a valid IWbemObjectAccess handle, we'll use it,
// otherwise we'll have to use our generic array.
if (m_pProps[dwIndex].m_lHandle)
{
type = typesStandardParams[dwIndex];
if (AreTypesEquivalent(type, (VSAParameterType) pField->dwType))
{
WriteData(dwIndex, pBuffer, dwDataLen);
bAlreadySet = TRUE;
}
}
else
{
// This is for the case where a standard parameter was used,
// but this event class doesn't have that standard parameter.
// So, it has to go into the generic property arrays.
type = CIM_STRING;
bGeneric = TRUE;
szFieldName = szStandardParams[dwIndex];
}
}
else
// Must be a string field.
{
HRESULT hr;
szFieldName = pField->szName;
// Get past the field name so pBuffer points at the data.
pBuffer =
(LPBYTE) DWORD_ALIGNED((DWORD_PTR) (szFieldName + wcslen(szFieldName) + 1));
// Get the length of the data.
dwDataLen = GetVSADataLength(pBuffer, (VSAParameterType) pField->dwType);
// See if this property has a corresponding CIM property and get
// its type.
hr =
m_pObj->Get(
szFieldName,
0,
NULL,
&type,
NULL);
// If the property wasn't found we'll use our generic array.
if (FAILED(hr))
{
type = CIM_STRING;
bGeneric = TRUE;
}
}
// Make sure we haven't already set the data using the index.
if (!bAlreadySet)
{
// Convert the VSA data to the proper CIM type.
_variant_t varData;
if (SUCCEEDED(VSADataToCIMData(
(VSAParameterType) pField->dwType,
pBuffer,
type,
varData,
dwIndex)))
{
if (bGeneric)
{
//listParamNames.push_back(szFieldName);
//listParamValues.push_back(V_BSTR(&varData));
bufferGenNames.Write(szFieldName);
bufferGenValues.Write(V_BSTR(&varData));
nGenValues++;
}
else if (dwIndex != INVALID_INDEX)
{
DWORD dwDataLen = GetCIMDataLength(&varData, type);
WriteData(
dwIndex,
type == CIM_STRING ? varData.bstrVal : (BSTR) &varData.iVal,
dwDataLen);
}
else if (szFieldName)
{
m_pObj->Put(
szFieldName,
0,
&varData,
NULL);
}
}
// So the _variant_t destructor doesn't freak out.
if (varData.vt == VT_I8)
varData.vt = VT_I4;
}
pBuffer += DWORD_ALIGNED(dwDataLen);
}
#define GUID_STR_LEN 39 * sizeof(WCHAR)
// Add the provider GUID.
WriteData(
PROVIDER_GUID_INDEX,
(LPVOID) szProviderGuid,
GUID_STR_LEN);
// Now add the generic properties, if any were found.
if (nGenValues)
{
WriteNonPackedArrayData(
GEN_NAMES_INDEX,
bufferGenNames.m_pBuffer,
nGenValues,
bufferGenNames.GetUsedSize());
WriteNonPackedArrayData(
GEN_VALUES_INDEX,
bufferGenValues.m_pBuffer,
nGenValues,
bufferGenValues.GetUsedSize());
/*
// Create the safe array.
SAFEARRAYBOUND bound;
VARIANT var;
var.vt = VT_BSTR | VT_ARRAY;
bound.lLbound = 0;
bound.cElements = listParamNames.size();
var.parray = SafeArrayCreate(VT_BSTR, 1, &bound);
if (var.parray)
{
// Set the names.
BSTR *pNames = (BSTR*) var.parray->pvData;
for (CBstrListIterator name = listParamNames.begin();
name != listParamNames.end();
name++)
{
*pNames = *name;
pNames++;
}
m_pObj->Put(
L"GenericParamNames",
0,
&var,
NULL);
// Set the values.
BSTR *pValues = (BSTR*) var.parray->pvData;
for (CBstrListIterator value = listParamValues.begin();
value != listParamValues.end();
value++)
{
*pValues = (*value).copy();
pValues++;
}
m_pObj->Put(
L"GenericParamValues",
0,
&var,
NULL);
// Get rid of the safe array.
SafeArrayDestroy(var.parray);
}
*/
}
_variant_t vVal;
m_pObj->Get(
L"BlobParam",
0,
&vVal,
NULL,
NULL);
return S_OK;
}
HRESULT CVSAEvent::Indicate(IWbemObjectSink *pSink)
{
HRESULT hr = pSink->Indicate(1, &m_pObj);
Reset();
return hr;
}
HRESULT CVSAEvent::Reset()
{
HRESULT hr = m_pObjBase->Clone(&m_pObj);
if (SUCCEEDED(hr))
hr =
m_pObj->QueryInterface(
IID_IWbemObjectAccess,
(LPVOID*) &m_pObjAccess);
return hr;
}