Checking whether the clr requires to be loaded with visual C++

As part of this personal project I am currently working on, I need to  reuse a C# component I wrote a few years back. I think I have blogged about this topic in the past on my old blog, but here I will show you how to check whether the CLR requires to be loaded beforehand, as well as a convenient way to “warm up” .NET code for execution.

////////////////////////////

// Check if CLR is loaded //

////////////////////////////

 

BOOL MyClass::CheckIfClrIsLoaded(const CComPtr<IEnumUnknown>& pEnumerator) {

    ULONG fetched = 0;

    DWORD bufferSize;

    auto retval = FALSE;

    wchar_t buffer[MAX_PATH];

    CComPtr<ICLRRuntimeInfo> pRuntimeInfo;

 

    while (SUCCEEDED(pEnumerator->Next(1, (IUnknown **)&pRuntimeInfo, &fetched)) && fetched > 0) {

        if ((SUCCEEDED(pRuntimeInfo->GetVersionString(buffer, &bufferSize))))

            if (wcscmp(buffer, L"v4.0.30319") == 0) {

                retval = TRUE;

                break;

            }

    }

 

    return retval;

}

 

///////////////////////////////////////////////////////////////////////

// Load, Initialize CLR and load dependant assemblies into AppDomain //

///////////////////////////////////////////////////////////////////////

 

void MyClass::InitializeClr() {

    CoInitialize(NULL);

 

    HANDLE hProcess;

    ExecuteArgs args;

    auto isLoaded = FALSE;

    CComPtr<ICLRMetaHost> pMetaHost;

    CComPtr<ICLRRuntimeInfo> pRuntimeInfo;

    CComPtr<ICLRRuntimeHost> pRuntimeHost;

    CComPtr<IEnumUnknown> pEnumerator;

 

    args.pwzAssemblyPath = L"MyAssembly.dll";

    args.pwzTypeName = L"MyAssembly.MyClass.BusinessRules";

    args.pwzMethodName = L"PreLoadData";

    args.pwzArgument = L"";

    args.pReturnValue = 0;

 

    if ((hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId())) != NULL) {

        if (SUCCEEDED(CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost))) {

            isLoaded = SUCCEEDED(pMetaHost->EnumerateLoadedRuntimes(hProcess, &pEnumerator)) && CheckIfClrIsLoaded(pEnumerator);

            if (!isLoaded &&  SUCCEEDED(pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo))) {

                if (SUCCEEDED(pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost))) {

                    pRuntimeHost->Start();

                    pRuntimeHost->ExecuteInDefaultAppDomain(args.pwzAssemblyPath, args.pwzTypeName,

                        args.pwzMethodName, args.pwzArgument, &args.pReturnValue);

                }

            }

        }

    }

 

    CloseHandle(hProcess);

 

    CoUninitialize();

}

 

.NET provides a few interfaces that enable Visual C++ developer to host and use the CLR from native code applications. In order to improve performance and minimize the load time/first execution of .NET code it’s a good practice to load all of the dependencies (assemblies) required by the target library. As you can see I use smart pointers to do all of this because .NET is COM based and when it’s not done properly one can incur in memory leakage. It’s a good thing we got smart pointers Smile

Like I’ve previously mentioned, I needed to reuse an existing .NET assembly, well, it’s a bit of a shocker to find out the number of reference it loads even when I am not using them Disappointed smile

image

Leave a Reply

Your email address will not be published. Required fields are marked *