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

807 lines
24 KiB
C++

#include "stdinc.h"
#include "fusionbuffer.h"
#include "sxstypes.h"
#include "sxsapi.h"
#ifndef NUMBER_OF
#define NUMBER_OF(x) (sizeof(x)/sizeof(*x))
#endif
class CActivateActCtx
{
HANDLE &m_hActCtx;
ULONG_PTR ulpCookie;
CActivateActCtx(const CActivateActCtx&);
void operator=(const CActivateActCtx&);
public:
CActivateActCtx(HANDLE &hctx) : m_hActCtx(hctx), ulpCookie(0)
{
ActivateActCtx(hctx, &ulpCookie);
}
~CActivateActCtx() {
DeactivateActCtx(0, ulpCookie);
}
};
class CActiveOutputLog
{
protected:
virtual void OutputString(PCWSTR pcwsz, SIZE_T cch) = 0;
WCHAR wchBuffer[4096];
CActiveOutputLog(const CActiveOutputLog&);
void operator=(const CActiveOutputLog&);
CActiveOutputLog() { }
public:
void Output(PCWSTR pcwszText, ...)
{
va_list val;
va_start(val, pcwszText);
this->OutputVa(pcwszText, val);
va_end(val);
}
void OutputVa(PCWSTR pcwszText, va_list val)
{
int iPrinted = _vsnwprintf(wchBuffer, NUMBER_OF(wchBuffer), pcwszText, val);
wchBuffer[iPrinted] = UNICODE_NULL;
OutputString(wchBuffer, iPrinted);
}
void Error(PCWSTR pcwszText, ...)
{
va_list val;
va_start(val, pcwszText);
this->ErrorVa(pcwszText, val);
va_end(val);
}
void ErrorVa(PCWSTR pcwszText, va_list val)
{
int iPrinted = _vsnwprintf(wchBuffer, NUMBER_OF(wchBuffer), pcwszText, val);
wchBuffer[iPrinted] = UNICODE_NULL;
OutputString(wchBuffer, iPrinted);
}
};
class CConsoleOutput : public CActiveOutputLog
{
CConsoleOutput(const CConsoleOutput&);
void operator=(const CConsoleOutput&);
protected:
virtual void OutputString(PCWSTR pcwsz, SIZE_T cch)
{
wprintf(L"%.*ls", cch, pcwsz);
}
public:
CConsoleOutput() { }
};
BOOL GetAssemblyIdentityFromIndex(
HANDLE hActCtx,
ULONG ulRosterIndex,
CBaseStringBuffer &AssemblyName
)
{
SIZE_T cbRequired;
BYTE wchBuffer[512];
SIZE_T cbTarget = sizeof(wchBuffer);
PVOID pvTarget = wchBuffer;
PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION pInformation;
BOOL fSuccess = FALSE;
AssemblyName.Clear();
fSuccess = QueryActCtxW(
0,
hActCtx,
&ulRosterIndex,
AssemblyDetailedInformationInActivationContxt,
pvTarget,
cbTarget,
&cbRequired);
if (!fSuccess && (::GetLastError() == ERROR_INSUFFICIENT_BUFFER))
{
cbTarget = cbRequired;
pvTarget = HeapAlloc(GetProcessHeap(), 0, cbRequired);
fSuccess = QueryActCtxW(
0,
hActCtx,
&ulRosterIndex,
AssemblyDetailedInformationInActivationContext,
pvTarget,
cbTarget,
&cbRequired);
}
if (!fSuccess)
{
goto Exit;
}
//
// Gather the assembly identity out of the thing we got back
//
pInformation = (PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION)pvTarget;
if (!AssemblyName.Win32Assign(
pInformation->lpAssemblyEncodedAssemblyIdentity,
pInformation->ulEncodedAssemblyIdentityLength)) {
goto Exit;
}
Exit:
if (pvTarget && (pvTarget != wchBuffer)) {
HeapFree(GetProcessHeap(), 0, pvTarget);
pvTarget = NULL;
}
return fSuccess;
}
HANDLE
CreateNewActCtx(PCWSTR pcwszManifest)
{
ACTCTXW MyActCtx = {sizeof(MyActCtx)};
MyActCtx.lpSource = pcwszManifest;
return CreateActCtxW(&MyActCtx);
}
BOOL
DisplayComServerRedirect(
HANDLE hActCtx,
PACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION pKeyedData,
CActiveOutputLog &OutputLog
)
{
return TRUE;
}
BOOL
SimpleQueryGuid(
HANDLE hActCtx,
PCWSTR pcwszSectionTitle,
PCWSTR pcwszGuid,
CActiveOutputLog &OutputLog
)
{
ULONG ulSection = _wtol(pcwszSectionTitle);
PCWSTR pcwszValue = pcwszGuid;
GUID GuidValue;
ACTCTX_SECTION_KEYED_DATA KeyedData = {sizeof(KeyedData)};
UNICODE_STRING str = { (USHORT)(wcslen(pcwszValue) * sizeof(WCHAR)), 0, const_cast<PWSTR>(pcwszValue) };
BOOL fSuccess = FALSE;
CActivateActCtx Activator(hActCtx);
if (!NT_SUCCESS(RtlGUIDFromString(&str, &GuidValue))) {
OutputLog.Error(L"Error, '%ls' isn't parseable as a GUID\n", pcwszValue);
SetLastError(ERROR_INVALID_PARAMETER);
goto Exit;
}
if (FindActCtxSectionGuid(0, NULL, ulSection, &GuidValue, &KeyedData)) {
CStringBuffer AssemblyName;
if (!GetAssemblyIdentityFromIndex(hActCtx, KeyedData.ulAssemblyRosterIndex, AssemblyName)) {
AssemblyName.Win32Assign(L"<can't get assembly identity>", NUMBER_OF(L"<can't get assembly identity>") - 1);
}
OutputLog.Output(L"Success, found guid '%ls' in assembly %ld (%ls), data format version %ld",
pcwszValue,
KeyedData.ulAssemblyRosterIndex,
static_cast<PCWSTR>(AssemblyName),
KeyedData.ulDataFormatVersion);
}
else {
const DWORD dwLastError = ::GetLastError();
OutputLog.Error(L"Error 0x%08lx searching for guid '%ls' in section %ld", dwLastError, pcwszValue, ulSection);
goto Exit;
}
fSuccess = TRUE;
Exit:
return fSuccess;
}
BOOL
SimpleQueryString(
HANDLE hActCtx,
PCWSTR pcwszSection,
PCWSTR pcwszString,
CActiveOutputLog &OutputLog
)
{
ULONG ulSection = _wtol(pcwszSection);
CActivateActCtx Activator(hActCtx);
ACTCTX_SECTION_KEYED_DATA KeyedData = {sizeof(KeyedData)};
BOOL fSuccess = FALSE;
if (FindActCtxSectionStringW(0, NULL, ulSection, pcwszString, &KeyedData)) {
CStringBuffer AssemblyName;
if (!GetAssemblyIdentityFromIndex(hActCtx, KeyedData.ulAssemblyRosterIndex, AssemblyName)) {
AssemblyName.Win32Assign(L"<can't get assembly identity>", NUMBER_OF(L"<can't get assembly identity>") - 1);
}
OutputLog.Output(
L"Success, found string '%ls' in assembly %ld (%ls), data format version %ld",
pcwszString,
KeyedData.ulAssemblyRosterIndex,
static_cast<PCWSTR>(AssemblyName),
KeyedData.ulDataFormatVersion);
fSuccess = TRUE;
}
else {
const DWORD dwError = ::GetLastError();
OutputLog.Error(L"Error 0x%08lx finding string '%ls' in section %ld\n", dwError, pcwszString, ulSection);
}
return fSuccess;
}
UNICODE_STRING UnknownAssemblyIdentity = RTL_CONSTANT_STRING(L"<unable to get identity>");
BOOL
LookupClrClass(
HANDLE hActCtx,
PCWSTR pcwszClassName,
CActiveOutputLog &OutputLog
)
{
GUID ParsedGuid;
UNICODE_STRING GuidString;
BOOL fSuccess = FALSE;
ACTCTX_SECTION_KEYED_DATA KeyedData;
PACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION pComServer = NULL;
CActivateActCtx Activator(hActCtx);
RtlInitUnicodeString(&GuidString, pcwszClassName);
//
// If this fails, then we have to look it up in the progid section - it might be
// a progid that's been remapped
//
if (!NT_SUCCESS(RtlGUIDFromString(&GuidString, &ParsedGuid))) {
PACTIVATION_CONTEXT_DATA_COM_PROGID_REDIRECTION pProgId = NULL;
UNICODE_STRING FoundGuidString;
RtlZeroMemory(&KeyedData, sizeof(KeyedData));
KeyedData.cbSize = sizeof(KeyedData);
if (!FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION, pcwszClassName, &KeyedData)) {
OutputLog.Error(L"Error 0x%08lx looking up '%ls' in the progid redirection section\n",
::GetLastError(),
pcwszClassName);
goto Exit;
}
pProgId = (PACTIVATION_CONTEXT_DATA_COM_PROGID_REDIRECTION)KeyedData.lpData;
ParsedGuid = *(GUID*)(((ULONG_PTR)KeyedData.lpSectionBase) + pProgId->ConfiguredClsidOffset);
if (NT_SUCCESS(RtlStringFromGUID(ParsedGuid, &FoundGuidString))) {
OutputLog.Output(L"Converted progid %ls into guid %wZ\n", pcwszClassName, &FoundGuidString);
RtlFreeUnicodeString(&FoundGuidString);
}
}
//
// Now let's go look up the GUID in the COM server redirection table(s)
//
RtlZeroMemory(&KeyedData, sizeof(KeyedData));
KeyedData.cbSize = sizeof(KeyedData);
if (!FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, &ParsedGuid, &KeyedData)) {
const DWORD dwLastError = ::GetLastError();
UNICODE_STRING ReconvertedGuidString;
if (NT_SUCCESS(RtlStringFromGUID(ParsedGuid, &ReconvertedGuidString))) {
OutputLog.Error(L"Error 0x%08lx looking up guid %wZ as a COM server\n", dwLastError, &ReconvertedGuidString);
RtlFreeUnicodeString(&ReconvertedGuidString);
}
else {
OutputLog.Error(L"Error 0x%08lx looking up string %ls as a COM server\n", dwLastError, pcwszClassName);
}
goto Exit;
}
pComServer = (PACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION)KeyedData.lpData;
//
// Say that we found it
//
{
UNICODE_STRING AbsoluteGuid;
RtlStringFromGUID(pComServer->ReferenceClsid, &AbsoluteGuid);
CStringBuffer AssemblyName;
if (!GetAssemblyIdentityFromIndex(hActCtx, KeyedData.ulAssemblyRosterIndex, AssemblyName)) {
AssemblyName.Win32Assign(&UnknownAssemblyIdentity);
}
OutputLog.Output(L"Found GUID %wZ in assembly %ld (%ls)\n",
&AbsoluteGuid,
KeyedData.ulAssemblyRosterIndex,
static_cast<PCWSTR>(AssemblyName));
}
//
// See what we can find about this COM class
//
if (pComServer->ShimDataOffset != 0)
{
UNICODE_STRING usTypeName = {0};
UNICODE_STRING usShimVersion = {0};
PACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_SHIM pShimData = NULL;
pShimData = (PACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_SHIM)(((ULONG_PTR)KeyedData.lpData) + pComServer->ShimDataOffset);
if (pShimData->TypeOffset != 0) {
usTypeName.Length = usTypeName.MaximumLength = (USHORT)pShimData->TypeLength;
usTypeName.Buffer = (PWSTR)(((ULONG_PTR)pShimData) + pShimData->TypeOffset);
}
if (pShimData->ShimVersionOffset != 0) {
usShimVersion.Length = usShimVersion.MaximumLength = (USHORT)pShimData->ShimVersionLength;
usShimVersion.Buffer = (PWSTR)(((ULONG_PTR)pShimData) + pShimData->ShimVersionOffset);
}
OutputLog.Output(L"- Found CLR shim type %ls: Type {%wZ}, version {%wZ}\n",
((pShimData->Type == ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_SHIM_TYPE_OTHER)
? L"other"
: ((pShimData->Type == ACTIVATION_CONTEXT_DATA_COM_SERVER_REDIRECTION_SHIM_TYPE_CLR_CLASS)
? L"clr"
: L"unknown")),
&usTypeName,
&usShimVersion);
}
fSuccess = TRUE;
Exit:
return fSuccess;
}
BOOL
LookupClrSurrogate(
HANDLE hActCtx,
PCWSTR pcwszSurrogateGuid,
CActiveOutputLog &OutputLog
)
{
GUID ParsedGuid;
UNICODE_STRING GuidString;
BOOL fSuccess = FALSE;
ACTCTX_SECTION_KEYED_DATA KeyedData = {sizeof(KeyedData)};
PACTIVATION_CONTEXT_DATA_CLR_SURROGATE pSurrogate = NULL;
CStringBuffer AssemblyIdentity;
UNICODE_STRING usSurrogateName = {0}, usVersionString = {0};
CActivateActCtx Activator(hActCtx);
RtlInitUnicodeString(&GuidString, pcwszSurrogateGuid);
// If this wasn't a guid, then it's an invalid parameter.
if (!NT_SUCCESS(RtlGUIDFromString(&GuidString, &ParsedGuid))) {
SetLastError(ERROR_INVALID_PARAMETER);
goto Exit;
}
if (!FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES, &ParsedGuid, &KeyedData)) {
OutputLog.Error(L"Error 0x%08lx looking for clr surrogate '%ls'\n", ::GetLastError(), pcwszSurrogateGuid);
goto Exit;
}
if (!GetAssemblyIdentityFromIndex(hActCtx, KeyedData.ulAssemblyRosterIndex, AssemblyIdentity)) {
AssemblyIdentity.Win32Assign(&UnknownAssemblyIdentity);
}
pSurrogate = (PACTIVATION_CONTEXT_DATA_CLR_SURROGATE)KeyedData.lpData;
if (pSurrogate->VersionOffset != 0) {
usVersionString.Length = usVersionString.MaximumLength = (USHORT)pSurrogate->VersionLength;
usVersionString.Buffer = (PWSTR)(((ULONG_PTR)pSurrogate) + pSurrogate->VersionOffset);
}
if (pSurrogate->TypeNameOffset != 0) {
usSurrogateName.Length = usSurrogateName.MaximumLength = (USHORT)pSurrogate->TypeNameLength;
usSurrogateName.Buffer = (PWSTR)(((ULONG_PTR)pSurrogate) + pSurrogate->TypeNameOffset);
}
OutputLog.Output(
L"Found surrogate {%wZ} (version {%wZ}) from assembly %ld (%ls)",
&usSurrogateName,
&usVersionString,
KeyedData.ulAssemblyRosterIndex,
static_cast<PCWSTR>(AssemblyIdentity));
fSuccess = TRUE;
Exit:
return fSuccess;
}
BOOL
SimpleLookupSurrogate(
HANDLE hActCtx,
PCWSTR pcwszGuid,
CActiveOutputLog &OutputLog
)
{
GUID ParsedGuid;
BOOL fSuccess = FALSE;
UNICODE_STRING OriginalGuid;
PFN_SXS_FIND_CLR_SURROGATE_INFO pfnLookup = NULL;
HMODULE hm = NULL;
DWORD dwSearchFlags = SXS_FIND_CLR_SURROGATE_USE_ACTCTX | SXS_FIND_CLR_SURROGATE_GET_ALL;
PVOID pvSearchData = NULL;
BYTE bStackBuffer[256];
SIZE_T cbBuffer = sizeof(bStackBuffer);
PVOID pvBuffer = bStackBuffer;
SIZE_T cbRequired;
PCSXS_CLR_SURROGATE_INFORMATION pSurrogateInfo = NULL;
//
// This has to be a GUID
//
RtlInitUnicodeString(&OriginalGuid, pcwszGuid);
if (NT_SUCCESS(RtlGUIDFromString(&OriginalGuid, &ParsedGuid))) {
pvSearchData = (PVOID)&ParsedGuid;
}
else {
OutputLog.Error(L"Error, %ls isn't a GUID\n", pcwszGuid);
SetLastError(ERROR_INVALID_PARAMETER);
goto Exit;
}
//
// Load sxs.dll and the function to call
//
if (NULL == (hm = LoadLibraryW(L"sxs.dll")))
goto Exit;
if (NULL == (pfnLookup = (PFN_SXS_FIND_CLR_SURROGATE_INFO)GetProcAddress(hm, SXS_FIND_CLR_SURROGATE_INFO)))
goto Exit;
fSuccess = pfnLookup(dwSearchFlags, &ParsedGuid, hActCtx, pvBuffer, cbBuffer, &cbRequired);
if (!fSuccess) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
OutputLog.Error(L"Error 0x%08lx looking up %ls\n", GetLastError(), pcwszGuid);
goto Exit;
}
if (NULL == (pvBuffer = HeapAlloc(GetProcessHeap(), 0, cbRequired))) {
OutputLog.Error(L"Failed allocating %ul bytes\n", cbRequired);
goto Exit;
}
cbBuffer = cbRequired;
if (!pfnLookup(dwSearchFlags, &ParsedGuid, hActCtx, pvBuffer, cbBuffer, &cbRequired)) {
OutputLog.Error(L"Error 0x%08lx in second lookup.\n", GetLastError());
goto Exit;
}
}
pSurrogateInfo = (PCSXS_CLR_SURROGATE_INFORMATION)pvBuffer;
OutputLog.Output(
L"Found CLR surrogate for %ls:\n\t- Assembly %ls\n\t- Typename %ls\n\t- Runtime %ls\n\t",
pcwszGuid,
pSurrogateInfo->pcwszImplementingAssembly,
pSurrogateInfo->pcwszSurrogateType,
pSurrogateInfo->pcwszRuntimeVersion);
fSuccess = TRUE;
Exit:
if (pvBuffer && (pvBuffer != bStackBuffer)) {
const DWORD dwLastError = GetLastError();
HeapFree(GetProcessHeap(), 0, pvBuffer);
pvBuffer = NULL;
SetLastError(dwLastError);
}
return fSuccess;
}
BOOL
SimpleLookupGuid(
HANDLE hActCtx,
PCWSTR pcwszGuid,
CActiveOutputLog &OutputLog
)
{
GUID ParsedGuid;
BOOL fSuccess = FALSE;
UNICODE_STRING OriginalGuid;
PFN_SXS_LOOKUP_CLR_GUID pfnLookup = NULL;
HMODULE hm = NULL;
DWORD dwSearchFlags = SXS_LOOKUP_CLR_GUID_FIND_ANY | SXS_LOOKUP_CLR_GUID_USE_ACTCTX;
PVOID pvSearchData = NULL;
BYTE bStackBuffer[256];
SIZE_T cbBuffer = sizeof(bStackBuffer);
PVOID pvBuffer = bStackBuffer;
SIZE_T cbRequired;
PCSXS_GUID_INFORMATION_CLR pGuidInfo = NULL;
//
// This has to be a GUID
//
RtlInitUnicodeString(&OriginalGuid, pcwszGuid);
if (NT_SUCCESS(RtlGUIDFromString(&OriginalGuid, &ParsedGuid))) {
pvSearchData = (PVOID)&ParsedGuid;
}
else {
OutputLog.Error(L"Error, %ls isn't a GUID\n", pcwszGuid);
SetLastError(ERROR_INVALID_PARAMETER);
goto Exit;
}
//
// Load sxs.dll and the function to call
//
if (NULL == (hm = LoadLibraryW(L"sxs.dll")))
goto Exit;
if (NULL == (pfnLookup = (PFN_SXS_LOOKUP_CLR_GUID)GetProcAddress(hm, SXS_LOOKUP_CLR_GUID)))
goto Exit;
fSuccess = pfnLookup(dwSearchFlags, &ParsedGuid, hActCtx, pvBuffer, cbBuffer, &cbRequired);
if (!fSuccess) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
OutputLog.Error(L"Error 0x%08lx looking up %ls\n", GetLastError(), pcwszGuid);
goto Exit;
}
if (NULL == (pvBuffer = HeapAlloc(GetProcessHeap(), 0, cbRequired))) {
OutputLog.Error(L"Failed allocating %ul bytes\n", cbRequired);
goto Exit;
}
cbBuffer = cbRequired;
if (!pfnLookup(dwSearchFlags, &ParsedGuid, hActCtx, pvBuffer, cbBuffer, &cbRequired)) {
OutputLog.Error(L"Error 0x%08lx in second lookup.\n", GetLastError());
goto Exit;
}
}
pGuidInfo = (PCSXS_GUID_INFORMATION_CLR)pvBuffer;
OutputLog.Output(
L"Found CLR entry for %ls:\n\t- Thing is a %ls\n\t- Assembly %ls\n\t- Typename %ls\n\t- Runtime %ls\n\t",
pcwszGuid,
((pGuidInfo->dwFlags & SXS_GUID_INFORMATION_CLR_FLAG_IS_SURROGATE)
? L"surrogate"
: ((pGuidInfo->dwFlags & SXS_GUID_INFORMATION_CLR_FLAG_IS_CLASS)
? L"class"
: L"unknown thing?")),
pGuidInfo->pcwszAssemblyIdentity,
pGuidInfo->pcwszTypeName,
pGuidInfo->pcwszRuntimeVersion);
fSuccess = TRUE;
Exit:
if (pvBuffer && (pvBuffer != bStackBuffer)) {
const DWORD dwLastError = GetLastError();
HeapFree(GetProcessHeap(), 0, pvBuffer);
pvBuffer = NULL;
SetLastError(dwLastError);
}
return fSuccess;
}
BOOL
SimpleLookupClass(
HANDLE hActCtx,
PCWSTR pcwszGuid,
CActiveOutputLog &OutputLog
)
{
GUID ParsedGuid;
BOOL fSuccess = FALSE;
UNICODE_STRING OriginalGuid;
PFN_SXS_FIND_CLR_CLASS_INFO pfnLookup = NULL;
HMODULE hm = NULL;
DWORD dwSearchFlags = SXS_FIND_CLR_CLASS_ACTIVATE_ACTCTX | SXS_FIND_CLR_CLASS_GET_ALL;
PVOID pvSearchData = NULL;
BYTE bStackBuffer[256];
SIZE_T cbBuffer = sizeof(bStackBuffer);
PVOID pvBuffer = bStackBuffer;
SIZE_T cbRequired;
PCSXS_CLR_CLASS_INFORMATION pClassInfo = NULL;
//
// Determine whether or not we're searching for a GUID or a progid
//
RtlInitUnicodeString(&OriginalGuid, pcwszGuid);
if (NT_SUCCESS(RtlGUIDFromString(&OriginalGuid, &ParsedGuid))) {
dwSearchFlags |= SXS_FIND_CLR_CLASS_SEARCH_GUID;
pvSearchData = (PVOID)&ParsedGuid;
}
else {
dwSearchFlags |= SXS_FIND_CLR_CLASS_SEARCH_PROGID;
pvSearchData = (PVOID)pcwszGuid;
}
//
// Load sxs.dll and the function to call
//
if (NULL == (hm = LoadLibraryW(L"sxs.dll")))
goto Exit;
if (NULL == (pfnLookup = (PFN_SXS_FIND_CLR_CLASS_INFO)GetProcAddress(hm, SXS_FIND_CLR_CLASS_INFO)))
goto Exit;
fSuccess = pfnLookup(dwSearchFlags, pvSearchData, hActCtx, pvBuffer, cbBuffer, &cbRequired);
if (!fSuccess) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
OutputLog.Error(L"Error 0x%08lx looking up %ls\n", GetLastError(), pcwszGuid);
goto Exit;
}
if (NULL == (pvBuffer = HeapAlloc(GetProcessHeap(), 0, cbRequired))) {
OutputLog.Error(L"Failed allocating %ul bytes\n", cbRequired);
goto Exit;
}
cbBuffer = cbRequired;
if (!pfnLookup(dwSearchFlags, pvSearchData, hActCtx, pvBuffer, cbBuffer, &cbRequired)) {
OutputLog.Error(L"Error 0x%08lx in second lookup.\n", GetLastError());
goto Exit;
}
}
pClassInfo = (PCSXS_CLR_CLASS_INFORMATION)pvBuffer;
OutputLog.Output(
L"Found CLR class for %ls:\n\t- Assembly %ls\n\t- Typename %ls\n\t- Progid %ls\n\t- Runtime %ls\n\t",
pcwszGuid,
pClassInfo->pcwszImplementingAssembly,
pClassInfo->pcwszTypeName,
pClassInfo->pcwszProgId,
pClassInfo->pcwszRuntimeVersion);
fSuccess = TRUE;
Exit:
if (pvBuffer && (pvBuffer != bStackBuffer)) {
const DWORD dwLastError = GetLastError();
HeapFree(GetProcessHeap(), 0, pvBuffer);
pvBuffer = NULL;
SetLastError(dwLastError);
}
return fSuccess;
}
int __cdecl wmain(INT argc, WCHAR** argv)
{
HANDLE hActCtx = INVALID_HANDLE_VALUE;
GUID uid = GUID_NULL;
INT i = 0;
CStringBuffer ManifestFileName;
CConsoleOutput ConsoleOutput;
CActiveOutputLog &OutputLog = ConsoleOutput;
bool fVerboseDumping = false;
for (i = 1; i < argc; i++)
{
if (lstrcmpiW(argv[i], L"-manifest") == 0) {
OutputLog.Output(L"Loading manifest %ls\n", argv[i+1]);
if (hActCtx != INVALID_HANDLE_VALUE) {
ReleaseActCtx(hActCtx);
hActCtx = INVALID_HANDLE_VALUE;
}
hActCtx = CreateNewActCtx(argv[++i]);
}
else if (lstrcmpiW(argv[i], L"-verbose") == 0) {
fVerboseDumping = true;
}
//
// Just look for a guid
//
else if (lstrcmpiW(argv[i], L"-querystring") == 0) {
if (!SimpleQueryString(hActCtx, argv[i+1], argv[i+2], OutputLog))
return GetLastError();
i += 2;
}
//
// Let's look just for a guid in a section
//
else if (lstrcmpiW(argv[i], L"-queryguid") == 0) {
if (!SimpleQueryGuid(hActCtx, argv[i+1], argv[i+2], OutputLog))
return GetLastError();
}
//
// Specifically find out about a CLR class
//
else if (lstrcmpiW(argv[i], L"-clrclass") == 0) {
if (!LookupClrClass(hActCtx, argv[i+1], OutputLog))
return GetLastError();
i++;
}
//
// Look for a surrogate, print some reasonable information about it
//
else if (lstrcmpiW(argv[i], L"-clrsurrogate") == 0) {
if (!LookupClrSurrogate(hActCtx, argv[i+1], OutputLog))
return GetLastError();
i++;
}
//
// Use the simple query for a clr class
//
else if (lstrcmpiW(argv[i], L"-simpleclass") == 0) {
if (!SimpleLookupClass(hActCtx, argv[i+1], OutputLog))
return GetLastError();
i++;
}
//
// Simple query for a clr surrogate
//
else if (lstrcmpiW(argv[i], L"-simplesurrogate") == 0) {
if (!SimpleLookupSurrogate(hActCtx, argv[i+1], OutputLog))
return GetLastError();
i++;
}
//
// Simple query for a clr guid of either type
//
else if (lstrcmpiW(argv[i], L"-simpleguid") == 0) {
if (!SimpleLookupGuid(hActCtx, argv[i+1], OutputLog))
return GetLastError();
i++;
}
}
if (hActCtx != INVALID_HANDLE_VALUE)
{
ReleaseActCtx(hActCtx);
hActCtx = INVALID_HANDLE_VALUE;
}
return ERROR_SUCCESS;
}