snowcrash09
snowcrash09

Reputation: 4814

Using unmanaged code to check for presence of .net runtime

I want to create a mixed managed/unmanaged DLL that can be loaded by rundll32, and which checks for the presence of the .Net runtime library before attempting to run any managed code, thusly:

using namespace System;

void SomeManagedCode()
{
    Diagnostics::Debug::WriteLine("Hello managed code!");
}

#pragma managed(push,off)

bool isRuntimeInstalled()
{
    // check for runtime using some *unmanaged* code

    return true;
}

extern "C" __declspec(dllexport) void _stdcall RunDllEntryPoint(
            HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
{
    if (isRuntimeInstalled())
    {
        SomeManagedCode();
    }
    else
    {
        OutputDebugString(L".net framework not installed");
    }
}

#pragma managed(pop)

To achieve this, I tried to /DELAYLOAD the CLR (mscoree.dll etc) so that it is only loaded when SomeManagedCode() is called and not before. However, the CLR is still loaded even before RunDllEntryPoint() is called (I can see mscoree.dll in the list of loaded modules). I believe this is because the compiler is linking in code which calls _CorDllMain(), which must force the runtime to load before my own entrypoint is called.

I know there are ways I could repackage this to make it work e.g. split the managed code into a separate DLL, but I'm interested if there's any way to make the above work code in a single DLL.

Is it possible to truly delay-load the CLR dlls, and if so, how?

Upvotes: 2

Views: 275

Answers (1)

Bryce Wagner
Bryce Wagner

Reputation: 1511

Could it be the existence of the function call "SomeManagedCode()" in your RunDllEntryPoint that's triggering it? Would it fix things by adding a layer of indirection?

#pragma managed
void SomeManagedCode()
{
    Diagnostics::Debug::WriteLine("Hello managed code!");
}
#pragma unmanaged
void CallSomeManagedCode()
{
    SomeManagedCode();
}
extern "C" __declspec(dllexport) void _stdcall RunDllEntryPoint(
        HWND hWnd, HINSTANCE hInst, LPSTR lpszCmdLine, int nCmdShow)
{
    if (isRuntimeInstalled())
    {
        CallSomeManagedCode();
    }
    else
    {
        OutputDebugString(L".net framework not installed");
    }
}

I was in a similar situation, trying to prevent .NET from loading from the wrong thread, and by adding layers of indirection, i.e. never directly call any managed code or managed classes from the native entry point, I was able to push off the .NET loading until later (in my case, until I could do it from a different thread).

Upvotes: 0

Related Questions