#include "common.h" #include "clr.h" BOOL clr::InitializeCommonLanguageRuntime(PCLR_CONTEXT pClrContext, mscorlib::_AppDomain** ppAppDomain) { BOOL bResult = FALSE; HRESULT hr; ICLRMetaHost* pMetaHost = NULL; ICLRRuntimeInfo* pRuntimeInfo = NULL; ICorRuntimeHost* pRuntimeHost = NULL; IUnknown* pAppDomainThunk = NULL; BOOL bIsLoadable; mscorlib::_AppDomain* pAppDomain = NULL; hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, reinterpret_cast(&pMetaHost)); EXIT_ON_HRESULT_ERROR(L"CLRCreateInstance", hr); hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, reinterpret_cast(&pRuntimeInfo)); EXIT_ON_HRESULT_ERROR(L"IMetaHost->GetRuntime", hr); hr = pRuntimeInfo->IsLoadable(&bIsLoadable); EXIT_ON_HRESULT_ERROR(L"IRuntimeInfo->IsLoadable", hr); hr = pRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_ICorRuntimeHost, reinterpret_cast(&pRuntimeHost)); EXIT_ON_HRESULT_ERROR(L"IRuntimeInfo->GetInterface", hr); hr = pRuntimeHost->Start(); EXIT_ON_HRESULT_ERROR(L"IRuntimeHost->Start", hr); hr = pRuntimeHost->CreateDomain(APP_DOMAIN, nullptr, &pAppDomainThunk); EXIT_ON_HRESULT_ERROR(L"IRuntimeHost->CreateDomain", hr); hr = pAppDomainThunk->QueryInterface(IID_PPV_ARGS(&pAppDomain)); EXIT_ON_HRESULT_ERROR(L"IAppDomainThunk->QueryInterface", hr); pClrContext->pMetaHost = pMetaHost; pClrContext->pRuntimeInfo = pRuntimeInfo; pClrContext->pRuntimeHost = pRuntimeHost; pClrContext->pAppDomainThunk = pAppDomainThunk; *ppAppDomain = pAppDomain; bResult = TRUE; exit: if (!bResult && pAppDomain) pAppDomain->Release(); if (!bResult && pAppDomainThunk) pAppDomainThunk->Release(); if (!bResult && pRuntimeHost) pRuntimeHost->Release(); if (!bResult && pRuntimeInfo) pRuntimeInfo->Release(); if (!bResult && pMetaHost) pMetaHost->Release(); return bResult; } void clr::DestroyCommonLanguageRuntime(PCLR_CONTEXT pClrContext, mscorlib::_AppDomain* pAppDomain) { if (pAppDomain) pAppDomain->Release(); if (pClrContext->pAppDomainThunk) pClrContext->pAppDomainThunk->Release(); if (pClrContext->pRuntimeHost) pClrContext->pRuntimeHost->Release(); if (pClrContext->pRuntimeInfo) pClrContext->pRuntimeInfo->Release(); if (pClrContext->pMetaHost) pClrContext->pMetaHost->Release(); } BOOL clr::FindAssemblyPath(LPCWSTR pwszAssemblyName, LPWSTR* ppwszAssemblyPath) { BOOL bResult = FALSE; WIN32_FIND_DATA ffd = { 0 }; LPCWSTR pwszAssemblyFolderPath = L"C:\\Windows\\Microsoft.NET\\assembly\\GAC_MSIL"; LPWSTR pwszSearchPath = NULL; LPWSTR pwszAssemblyPath = NULL; HANDLE hFind = NULL; HANDLE hAssemblyFile = NULL; pwszSearchPath = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH * sizeof(*pwszSearchPath)); EXIT_ON_WIN32_ERROR(L"HeapAlloc", pwszSearchPath == NULL); pwszAssemblyPath = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH * sizeof(*pwszAssemblyPath)); EXIT_ON_WIN32_ERROR(L"HeapAlloc", pwszAssemblyPath == NULL); swprintf_s(pwszSearchPath, MAX_PATH, L"%ws\\%ws\\*", pwszAssemblyFolderPath, pwszAssemblyName); hFind = FindFirstFileW(pwszSearchPath, &ffd); EXIT_ON_WIN32_ERROR(L"FindFirstFileW", hFind == INVALID_HANDLE_VALUE); do { if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { swprintf_s(pwszAssemblyPath, MAX_PATH, L"%ws\\%ws\\%ws\\%ws.dll", pwszAssemblyFolderPath, pwszAssemblyName, ffd.cFileName, pwszAssemblyName); hAssemblyFile = CreateFileW(pwszAssemblyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hAssemblyFile != INVALID_HANDLE_VALUE) { bResult = TRUE; CloseHandle(hAssemblyFile); break; } } } while (FindNextFileW(hFind, &ffd) != 0); if (!bResult) goto exit; *ppwszAssemblyPath = pwszAssemblyPath; exit: if (hFind && hFind != INVALID_HANDLE_VALUE) FindClose(hFind); if (!bResult && pwszAssemblyPath) HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, pwszAssemblyPath); if (pwszSearchPath) HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, pwszSearchPath); return bResult; } BOOL clr::GetAssembly(mscorlib::_AppDomain* pAppDomain, LPCWSTR pwszAssemblyName, mscorlib::_Assembly** ppAssembly) { BOOL bResult = FALSE; HRESULT hr; LONG lAssembliesLowerBound, lAssembliesUpperBound; LONG lTargetAssemblyNameLength, lCurrentAssemblyNameLength, lAssemblyNameIndex; BSTR bstrAssemblyFullName; SAFEARRAY* pLoadedAssembliesArray = NULL; mscorlib::_Assembly** ppLoadedAssemblies = NULL; lTargetAssemblyNameLength = (LONG)wcslen(pwszAssemblyName); hr = pAppDomain->GetAssemblies(&pLoadedAssembliesArray); EXIT_ON_HRESULT_ERROR(L"AppDomain->GetAssemblies", hr); SafeArrayGetLBound(pLoadedAssembliesArray, 1, &lAssembliesLowerBound); SafeArrayGetUBound(pLoadedAssembliesArray, 1, &lAssembliesUpperBound); hr = SafeArrayAccessData(pLoadedAssembliesArray, (void**)&ppLoadedAssemblies); EXIT_ON_HRESULT_ERROR(L"SafeArrayAccessData", hr); for (int i = 0; i < lAssembliesUpperBound - lAssembliesLowerBound + 1; i++) { bstrAssemblyFullName = NULL; hr = ppLoadedAssemblies[i]->get_FullName(&bstrAssemblyFullName); if (SUCCEEDED(hr)) { // // If the target assembly name is 'Some.Assembly.Name', check whether // the current assembly's full name starts with 'Some.Assembly.Name,'. // As an example, the full name of the 'System.Management.Automation' // assembly would be something like: // System.Management.Automation, Version=3.0.0.0, Culture=neutral, // PublicKeyToken=31bf3856ad364e35 // lCurrentAssemblyNameLength = (LONG)wcslen(bstrAssemblyFullName); if (lCurrentAssemblyNameLength > lTargetAssemblyNameLength) { for (lAssemblyNameIndex = 0; lAssemblyNameIndex < lTargetAssemblyNameLength; lAssemblyNameIndex++) { if (pwszAssemblyName[lAssemblyNameIndex] != bstrAssemblyFullName[lAssemblyNameIndex]) break; } if (lAssemblyNameIndex == lTargetAssemblyNameLength) { if (bstrAssemblyFullName[lAssemblyNameIndex] == L',') { bResult = TRUE; *ppAssembly = ppLoadedAssemblies[i]; break; } } } SysFreeString(bstrAssemblyFullName); } } exit: if (pLoadedAssembliesArray) SafeArrayDestroy(pLoadedAssembliesArray); return bResult; } BOOL clr::LoadAssembly(mscorlib::_AppDomain* pAppDomain, LPCWSTR pwszAssemblyName, mscorlib::_Assembly** ppAssembly) { BOOL bResult = FALSE; HRESULT hr; DWORD dwBytesRead; HANDLE hAssemblyFile = NULL; LPWSTR pwszAssemblyPath = NULL; LARGE_INTEGER liAssemblyFileSize = { 0 }; SAFEARRAYBOUND sab = { 0 }; SAFEARRAY* pSafeAssembly = NULL; mscorlib::_Assembly* pAssembly = NULL; // Check if assembly is already loaded if (!clr::GetAssembly(pAppDomain, pwszAssemblyName, &pAssembly)) { if (!clr::FindAssemblyPath(pwszAssemblyName, &pwszAssemblyPath)) goto exit; hAssemblyFile = CreateFileW(pwszAssemblyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); EXIT_ON_WIN32_ERROR(L"CreateFileW", hAssemblyFile == INVALID_HANDLE_VALUE); EXIT_ON_WIN32_ERROR(L"GetFileSizeEx", GetFileSizeEx(hAssemblyFile, &liAssemblyFileSize) == FALSE); sab = { (ULONG)liAssemblyFileSize.QuadPart, 0 }; pSafeAssembly = SafeArrayCreate(VT_UI1, 1, &sab); EXIT_ON_WIN32_ERROR(L"ReadFile", ReadFile(hAssemblyFile, pSafeAssembly->pvData, (DWORD)liAssemblyFileSize.QuadPart, &dwBytesRead, NULL) == FALSE); hr = pAppDomain->Load_3(pSafeAssembly, &pAssembly); EXIT_ON_HRESULT_ERROR(L"AppDomain->Load_3", hr); } *ppAssembly = pAssembly; bResult = TRUE; exit: if (pSafeAssembly) SafeArrayDestroy(pSafeAssembly); if (hAssemblyFile && hAssemblyFile != INVALID_HANDLE_VALUE) CloseHandle(hAssemblyFile); if (pwszAssemblyPath) HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, pwszAssemblyPath); return bResult; } BOOL clr::CreateInstance(mscorlib::_AppDomain* pAppDomain, LPCWSTR pwszAssemblyName, LPCWSTR pwszClassName, VARIANT* pvtInstance) { BOOL bResult = FALSE; HRESULT hr; BSTR bstrClassName = SysAllocString(pwszClassName); VARIANT vtInstance = { 0 }; mscorlib::_Assembly* pAssembly = NULL; if (!clr::LoadAssembly(pAppDomain, pwszAssemblyName, &pAssembly)) goto exit; hr = pAssembly->CreateInstance(bstrClassName, &vtInstance); EXIT_ON_HRESULT_ERROR(L"Assembly->CreateInstance", hr); memcpy_s(pvtInstance, sizeof(*pvtInstance), &vtInstance, sizeof(vtInstance)); bResult = TRUE; exit: if (bstrClassName) SysFreeString(bstrClassName); if (pAssembly) pAssembly->Release(); return bResult; } BOOL clr::GetType(mscorlib::_AppDomain* pAppDomain, LPCWSTR pwszAssemblyName, LPCWSTR pwszTypeFullName, mscorlib::_Type** ppType) { HRESULT hr; BOOL bResult = FALSE; BSTR bstrTypeFullName = SysAllocString(pwszTypeFullName); mscorlib::_Assembly* pAssembly = NULL; mscorlib::_Type* pType = NULL; if (!clr::LoadAssembly(pAppDomain, pwszAssemblyName, &pAssembly)) goto exit; hr = pAssembly->GetType_2(bstrTypeFullName, &pType); EXIT_ON_HRESULT_ERROR(L"Assembly->GetType_2", hr); EXIT_ON_NULL_POINTER(pwszTypeFullName, pType); *ppType = pType; bResult = TRUE; exit: if (bstrTypeFullName) SysFreeString(bstrTypeFullName); if (pAssembly) pAssembly->Release(); return bResult; } BOOL clr::GetProperty(mscorlib::_Type* pType, mscorlib::BindingFlags bindingFlags, LPCWSTR pwszPropertyName, mscorlib::_PropertyInfo** ppPropertyInfo) { HRESULT hr; BOOL bResult = FALSE; BSTR bstrPropertyName = SysAllocString(pwszPropertyName); mscorlib::_PropertyInfo* pPropertyInfo = NULL; hr = pType->GetProperty(bstrPropertyName, bindingFlags, &pPropertyInfo); EXIT_ON_HRESULT_ERROR(L"Type->GetProperty", hr); EXIT_ON_NULL_POINTER(pwszPropertyName, pPropertyInfo); *ppPropertyInfo = pPropertyInfo; bResult = TRUE; exit: if (bstrPropertyName) SysFreeString(bstrPropertyName); return bResult; } BOOL clr::GetPropertyValue(mscorlib::_Type* pType, mscorlib::BindingFlags bindingFlags, VARIANT vtObject, LPCWSTR pwszPropertyName, VARIANT* pvtPropertyValue) { BOOL bResult = FALSE; HRESULT hr; VARIANT vtPropertyValue = { 0 }; mscorlib::_PropertyInfo* pPropertyInfo = NULL; if (!clr::GetProperty(pType, bindingFlags, pwszPropertyName, &pPropertyInfo)) goto exit; hr = pPropertyInfo->GetValue(vtObject, NULL, &vtPropertyValue); EXIT_ON_HRESULT_ERROR(L"PropertyInfo->GetValue", hr); memcpy_s(pvtPropertyValue, sizeof(*pvtPropertyValue), &vtPropertyValue, sizeof(vtPropertyValue)); bResult = TRUE; exit: if (pPropertyInfo) pPropertyInfo->Release(); return bResult; } BOOL clr::GetField(mscorlib::_Type* pType, mscorlib::BindingFlags bindingFlags, LPCWSTR pwszFieldName, mscorlib::_FieldInfo** ppFieldInfo) { HRESULT hr; BOOL bResult = FALSE; BSTR bstrFieldName = SysAllocString(pwszFieldName); mscorlib::_FieldInfo* pFieldInfo = NULL; hr = pType->GetField(bstrFieldName, bindingFlags, &pFieldInfo); EXIT_ON_HRESULT_ERROR(L"Type->GetField", hr); EXIT_ON_NULL_POINTER(pwszFieldName, pFieldInfo); *ppFieldInfo = pFieldInfo; bResult = TRUE; exit: if (bstrFieldName) SysFreeString(bstrFieldName); return bResult; } BOOL clr::GetFieldValue(mscorlib::_Type* pType, mscorlib::BindingFlags bindingFlags, VARIANT vtObject, LPCWSTR pwszFieldName, VARIANT* pvtFieldValue) { BOOL bResult = FALSE; HRESULT hr; VARIANT vtValue = { 0 }; mscorlib::_FieldInfo* pFieldInfo = NULL; if (!clr::GetField(pType, bindingFlags, pwszFieldName, &pFieldInfo)) goto exit; hr = pFieldInfo->GetValue(vtObject, &vtValue); EXIT_ON_HRESULT_ERROR(L"FieldInfo->GetValue", hr); memcpy_s(pvtFieldValue, sizeof(*pvtFieldValue), &vtValue, sizeof(vtValue)); bResult = TRUE; exit: if (pFieldInfo) pFieldInfo->Release(); return bResult; } BOOL clr::GetMethod(mscorlib::_Type* pType, mscorlib::BindingFlags bindingFlags, LPCWSTR pwszMethodName, LONG lNbArg, mscorlib::_MethodInfo** ppMethodInfo) { HRESULT hr; BOOL bResult = FALSE; SAFEARRAY* pMethods = NULL; mscorlib::_MethodInfo* pMethodInfo; hr = pType->GetMethods(bindingFlags, &pMethods); EXIT_ON_HRESULT_ERROR(L"Type->GetMethods", hr); if (!clr::FindMethodInArray(pMethods, pwszMethodName, lNbArg, &pMethodInfo)) goto exit; *ppMethodInfo = pMethodInfo; bResult = TRUE; exit: if (pMethods) SafeArrayDestroy(pMethods); return bResult; } BOOL clr::InvokeMethod(mscorlib::_MethodInfo* pMethodInfo, VARIANT vtObject, SAFEARRAY* pParameters, VARIANT* pvtResult) { HRESULT hr; BOOL bResult = FALSE; hr = pMethodInfo->Invoke_3(vtObject, pParameters, pvtResult); EXIT_ON_HRESULT_ERROR(L"MethodInfo->Invoke_3", hr); bResult = TRUE; exit: return bResult; } BOOL clr::FindMethodInArray(SAFEARRAY* pMethods, LPCWSTR pwszMethodName, LONG lNbArgs, mscorlib::_MethodInfo** ppMethodInfo) { BOOL bResult = FALSE; HRESULT hr; LONG lMethodsLowerBound, lMethodsUpperBound; LONG lParametersLowerBound, lParametersUpperBound; BSTR bstrMethodName; SAFEARRAY* pParameters = NULL; mscorlib::_MethodInfo** ppMethods = NULL; mscorlib::_MethodInfo* pTargetMethodInfo = NULL; SafeArrayGetLBound(pMethods, 1, &lMethodsLowerBound); SafeArrayGetUBound(pMethods, 1, &lMethodsUpperBound); hr = SafeArrayAccessData(pMethods, (void**)&ppMethods); EXIT_ON_HRESULT_ERROR(L"SafeArrayAccessData", hr); for (int i = 0; i < lMethodsUpperBound - lMethodsLowerBound + 1; i++) { bstrMethodName = NULL; hr = ppMethods[i]->get_name(&bstrMethodName); if (SUCCEEDED(hr)) { if (_wcsicmp(bstrMethodName, pwszMethodName) == 0) { hr = ppMethods[i]->GetParameters(&pParameters); if (SUCCEEDED(hr)) { SafeArrayGetLBound(pParameters, 1, &lParametersLowerBound); SafeArrayGetUBound(pParameters, 1, &lParametersUpperBound); if (lParametersUpperBound - lParametersLowerBound + 1 == lNbArgs) { pTargetMethodInfo = ppMethods[i]; break; } SafeArrayDestroy(pParameters); } } SysFreeString(bstrMethodName); } } if (!pTargetMethodInfo) { PRINT_ERROR("Could not find a method named '%ws' with %d arguments.\n", pwszMethodName, lNbArgs); goto exit; } bResult = TRUE; *ppMethodInfo = pTargetMethodInfo; exit: return bResult; } BOOL clr::PrepareMethod(mscorlib::_AppDomain* pAppDomain, VARIANT* pvtMethodHandle) { BOOL bResult = FALSE; LONG lArgumentIndex; SAFEARRAY* pPrepareMethodArguments = NULL; VARIANT vtEmpty = { 0 }; VARIANT vtResult = { 0 }; mscorlib::_Type* pRuntimeHelpersType = NULL; mscorlib::_MethodInfo* pPrepareMethod = NULL; if (!clr::GetType(pAppDomain, ASSEMBLY_NAME_SYSTEM_RUNTIME, L"System.Runtime.CompilerServices.RuntimeHelpers", &pRuntimeHelpersType)) goto exit; if (!clr::GetMethod(pRuntimeHelpersType, static_cast(BINDING_FLAGS_PUBLIC_STATIC), L"PrepareMethod", 1, &pPrepareMethod)) goto exit; pPrepareMethodArguments = SafeArrayCreateVector(VT_VARIANT, 0, 1); lArgumentIndex = 0; SafeArrayPutElement(pPrepareMethodArguments, &lArgumentIndex, pvtMethodHandle); if (!clr::InvokeMethod(pPrepareMethod, vtEmpty, pPrepareMethodArguments, &vtResult)) goto exit; bResult = TRUE; exit: if (pPrepareMethodArguments) SafeArrayDestroy(pPrepareMethodArguments); if (pPrepareMethod) pPrepareMethod->Release(); if (pRuntimeHelpersType) pRuntimeHelpersType->Release(); VariantClear(&vtResult); return bResult; } BOOL clr::GetFunctionPointer(mscorlib::_AppDomain* pAppDomain, VARIANT* pvtMethodHandle, PULONG_PTR pFunctionPointer) { BOOL bResult = FALSE; VARIANT vtFunctionPointer = { 0 }; mscorlib::_Type* pRuntimeMethodHandleType = NULL; mscorlib::_MethodInfo* pGetFunctionPointerInfo = NULL; if (!clr::GetType(pAppDomain, ASSEMBLY_NAME_SYSTEM_RUNTIME, L"System.RuntimeMethodHandle", &pRuntimeMethodHandleType)) goto exit; if (!clr::GetMethod(pRuntimeMethodHandleType, static_cast(BINDING_FLAGS_PUBLIC_INSTANCE), L"GetFunctionPointer", 0, &pGetFunctionPointerInfo)) goto exit; if (!clr::InvokeMethod(pGetFunctionPointerInfo, *pvtMethodHandle, NULL, &vtFunctionPointer)) goto exit; *pFunctionPointer = vtFunctionPointer.ullVal; bResult = TRUE; exit: if (pGetFunctionPointerInfo) pGetFunctionPointerInfo->Release(); if (pRuntimeMethodHandleType) pRuntimeMethodHandleType->Release(); return bResult; } BOOL clr::GetJustInTimeMethodAddress(mscorlib::_AppDomain* pAppDomain, LPCWSTR pwszAssemblyName, LPCWSTR pwszClassName, LPCWSTR pwszMethodName, DWORD dwNbArgs, PULONG_PTR pMethodAddress) { BOOL bResult = FALSE; VARIANT vtMethodHandlePtr = { 0 }; VARIANT vtMethodHandleVal = { 0 }; mscorlib::_Type* pType = NULL; mscorlib::_Type* pMethodInfoType = NULL; mscorlib::_MethodInfo* pTargetMethodInfo = NULL; // Here, we include as many binding flags as we can so that we can list // ALL the methods of the target class. mscorlib::BindingFlags flags = static_cast( mscorlib::BindingFlags::BindingFlags_Instance | mscorlib::BindingFlags::BindingFlags_Static | mscorlib::BindingFlags::BindingFlags_Public | mscorlib::BindingFlags::BindingFlags_NonPublic | mscorlib::BindingFlags::BindingFlags_DeclaredOnly ); if (!clr::GetType(pAppDomain, pwszAssemblyName, pwszClassName, &pType)) goto exit; if (!clr::GetMethod(pType, flags, pwszMethodName, dwNbArgs, &pTargetMethodInfo)) goto exit; // // The method for obtaining the MethodHandle from the MethodInfo object is // taken from this article. // // Credit: // - https://www.outflank.nl/blog/2024/02/01/unmanaged-dotnet-patching/ // if (!clr::GetType(pAppDomain, ASSEMBLY_NAME_SYSTEM_REFLECTION, L"System.Reflection.MethodInfo", &pMethodInfoType)) goto exit; vtMethodHandlePtr.vt = VT_UNKNOWN; vtMethodHandlePtr.punkVal = pTargetMethodInfo; if (!clr::GetPropertyValue(pMethodInfoType, static_cast(BINDING_FLAGS_PUBLIC_INSTANCE), vtMethodHandlePtr, L"MethodHandle", &vtMethodHandleVal)) goto exit; // // Next, we can invoke 'RuntimeHelpers.PrepareMethod' to make sure the target // method is JIT-compiled, and finally get its effective address. // // Credit: // - https://github.com/calebstewart/bypass-clm // - https://www.mdsec.co.uk/2020/08/massaging-your-clr-preventing-environment-exit-in-in-process-net-assemblies/ // if (!PrepareMethod(pAppDomain, &vtMethodHandleVal)) goto exit; if (!GetFunctionPointer(pAppDomain, &vtMethodHandleVal, pMethodAddress)) goto exit; bResult = TRUE; exit: if (pTargetMethodInfo) pTargetMethodInfo->Release(); if (pType) pType->Release(); if (pMethodInfoType) pMethodInfoType->Release(); VariantClear(&vtMethodHandleVal); VariantClear(&vtMethodHandlePtr); return bResult; } BOOL dotnet::System_Object_GetType(mscorlib::_AppDomain* pAppDomain, VARIANT vtObject, VARIANT* pvtObjectType) { BOOL bResult = FALSE; VARIANT vtGetTypeResult = { 0 }; mscorlib::_Type* pObjectType = NULL; mscorlib::_MethodInfo* pGetTypeMethodInfo = NULL; if (!clr::GetType(pAppDomain, ASSEMBLY_NAME_SYSTEM_RUNTIME, L"System.Object", &pObjectType)) goto exit; if (!clr::GetMethod(pObjectType, static_cast(BINDING_FLAGS_PUBLIC_INSTANCE), L"GetType", 0, &pGetTypeMethodInfo)) goto exit; if (!clr::InvokeMethod(pGetTypeMethodInfo, vtObject, NULL, &vtGetTypeResult)) goto exit; memcpy_s(pvtObjectType, sizeof(*pvtObjectType), &vtGetTypeResult, sizeof(vtGetTypeResult)); bResult = TRUE; exit: if (pGetTypeMethodInfo) pGetTypeMethodInfo->Release(); if (pObjectType) pObjectType->Release(); return bResult; } BOOL dotnet::System_Type_GetProperty(mscorlib::_AppDomain* pAppDomain, VARIANT vtTypeObject, LPCWSTR pwszPropertyName, VARIANT* pvtPropertyInfo) { BOOL bResult = FALSE; LONG lArgumentIndex; VARIANT vtPropertyName = { 0 }; VARIANT vtPropertyInfo = { 0 }; SAFEARRAY* pGetPropertyArguments = NULL; mscorlib::_Type* pTypeType = NULL; mscorlib::_MethodInfo* pGetPropertyMethodInfo = NULL; if (!clr::GetType(pAppDomain, ASSEMBLY_NAME_SYSTEM_RUNTIME, L"System.Type", &pTypeType)) goto exit; if (!clr::GetMethod(pTypeType, static_cast(BINDING_FLAGS_PUBLIC_INSTANCE), L"GetProperty", 1, &pGetPropertyMethodInfo)) goto exit; InitVariantFromString(pwszPropertyName, &vtPropertyName); pGetPropertyArguments = SafeArrayCreateVector(VT_VARIANT, 0, 1); lArgumentIndex = 0; SafeArrayPutElement(pGetPropertyArguments, &lArgumentIndex, &vtPropertyName); if (!clr::InvokeMethod(pGetPropertyMethodInfo, vtTypeObject, pGetPropertyArguments, &vtPropertyInfo)) goto exit; memcpy_s(pvtPropertyInfo, sizeof(*pvtPropertyInfo), &vtPropertyInfo, sizeof(vtPropertyInfo)); bResult = TRUE; exit: if (pGetPropertyArguments) SafeArrayDestroy(pGetPropertyArguments); if (pGetPropertyMethodInfo) pGetPropertyMethodInfo->Release(); if (pTypeType) pTypeType->Release(); VariantClear(&vtPropertyName); return bResult; } BOOL dotnet::System_Reflection_PropertyInfo_GetValue(mscorlib::_AppDomain* pAppDomain, VARIANT vtPropertyInfo, VARIANT vtObject, SAFEARRAY* pIndex, VARIANT* pvtValue) { BOOL bResult = FALSE; LONG lNbArguments; LONG lArgumentIndex; VARIANT vtIndexArray = { 0 }; VARIANT vtValue = { 0 }; SAFEARRAY* pGetValueArguments = NULL; mscorlib::_Type* pPropertyInfoType = NULL; mscorlib::_MethodInfo* pGetValueMethodInfo = NULL; lNbArguments = pIndex != NULL ? 2 : 1; if (!clr::GetType(pAppDomain, ASSEMBLY_NAME_SYSTEM_REFLECTION, L"System.Reflection.PropertyInfo", &pPropertyInfoType)) goto exit; if (!clr::GetMethod(pPropertyInfoType, static_cast(BINDING_FLAGS_PUBLIC_INSTANCE), L"GetValue", lNbArguments, &pGetValueMethodInfo)) goto exit; pGetValueArguments = SafeArrayCreateVector(VT_VARIANT, 0, lNbArguments); lArgumentIndex = 0; SafeArrayPutElement(pGetValueArguments, &lArgumentIndex, &vtObject); if (pIndex != NULL) { vtIndexArray.vt = VT_ARRAY | VT_VARIANT; vtIndexArray.parray = pIndex; lArgumentIndex = 1; SafeArrayPutElement(pGetValueArguments, &lArgumentIndex, &vtIndexArray); } if (!clr::InvokeMethod(pGetValueMethodInfo, vtPropertyInfo, pGetValueArguments, &vtValue)) goto exit; memcpy_s(pvtValue, sizeof(*pvtValue), &vtValue, sizeof(vtValue)); bResult = TRUE; exit: if (pGetValueArguments) SafeArrayDestroy(pGetValueArguments); if (pGetValueMethodInfo) pGetValueMethodInfo->Release(); if (pPropertyInfoType) pPropertyInfoType->Release(); return bResult; } BOOL dotnet::System_Reflection_PropertyInfo_GetValue(mscorlib::_AppDomain* pAppDomain, VARIANT vtPropertyInfo, VARIANT vtObject, VARIANT* pvtValue) { return dotnet::System_Reflection_PropertyInfo_GetValue(pAppDomain, vtPropertyInfo, vtObject, NULL, pvtValue); }