RickStrahl / wwDotnetBridge

.NET Interop for Visual FoxPro made easy
http://west-wind.com/wwDotnetBridge.aspx
73 stars 35 forks source link

.Net 8 Nethost/Hostfxr implementation #30

Open horch004 opened 7 months ago

horch004 commented 7 months ago

Hi Rick,

We use your wwDotnetBridge many years now. Although a bit rewriten over time. It runs very stable in our classic asp application.

I saw you had a newer bridge to the .net core versions. For a normal desktop application it seems to work. But in an asp environment it is crashing. I also found your question (from 2019) on the github issue page of dotnet about the issue. From there I picked up the sample code of microsoft, using the nethost / hostfxr approach, and rewrote it. I only had to add a delegate to your wwDotnetBridge factory class matching the CreatewwDotnetBridgeByRef factory method which is called from the unmanaged code and returns an IDispatch pointer.

So, I have implemented the new functionality, based on the nethost / hostfxr approach, in the ClrHost which I now use in our asp application. It is not crashing anymore and on every request our vfp dll can re-attach to the .net 8 runtime. It is still in an early test phase, but it seems promissing. Our c# assemblies could be upgraded to .net core (VS .Net Upgrade Assistent extension) with little modifications afterwards.

Are you interested in the code? I can also zip the whole project and upload it. You probably have to rewrite some code to fit it in your project. But that's probably piece of cake.

Regards, Wijnand

horch004 commented 7 months ago

Hi Rick,

There might be a trick for you to explore in your implementation. Because VFP loads the dll, it also unloads it when finished. In a classic Asp environment this makes it unstable and when unloaded we cannot attach to the runtime again. My implementation is able to attach, thereby not really suffering of losing the IDispatch handle. Because my implementation needs the path to the module I use GetModuleHandleEx (and GetModuleFileName). I found out that passing GET_MODULE_HANDLE_EX_FLAG_PIN as flag, the module will be prevented from unloading. Even if VFP tries to unload it. This way it seems the static variables are kept alive.

So, you could just make a call the this function with that flag and you might be done. Advice is to keep the IDispatch pointer (CComPtr) as a global static variable and do the AddRef in the C++ code instead of the VFP code (SYS(3097, this.oDotNetBridge)). The AddRef might be unnecessary at all, but just for insurance. At the beginning of CoreClrCreateInstanceFrom just return the IDispatch pointer when not null.

void module_handle_function() { }
HMODULE GetClrHostModuleHandle()
{
    HMODULE hm = NULL;

    void* address = module_handle_function;

    // The GET_MODULE_HANDLE_EX_FLAG_PIN flag seems to prevent VFP of unloading and clearing memory.
    GetModuleHandleEx(
        GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN,
        (LPCSTR)address,
        &hm
    )

    return hm;
}

(removed error handling for clarity)