Event handling at calling a third party 32-bit dll from a 64-bit c# WinForms application
See the question and my original answer on StackOverflowHere is a sample with a 64-bit server, implemented as a C# class in a class library project, hosted by Windows' system surrogate: dllhost.
This is the class code (you can compile as 'any cpu', no need to compile as x64):
namespace NetComClassLibrary3
{
// technically, we don't *have to* define an interface, we could do everything using dynamic stuff
// but it's more practical so we can reference this .NET dll from our client
[ComVisible(true)]
[Guid("31dd1263-0002-4071-aa4a-d226a55116bd")]
public interface IMyClass
{
event OnMyEventDelegate OnMyEvent;
object MyMethod();
}
// same remark than above.
// This *must* match the OnMyEvent signature below
[ComVisible(true)]
[Guid("31dd1263-0003-4071-aa4a-d226a55116bd")]
public delegate void OnMyEventDelegate(string text);
// this "event" interface is mandatory
// note from the .NET perspective, no one seems to implement it
// but it's referenced with the ComSourceInterfaces attribute on our COM server (below)
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("31dd1263-0000-4071-aa4a-d226a55116bd")]
public interface IMyEvents
{
// dispids are mandatory here otherwise you'll get a DISP_E_UNKNOWNNAME error
[DispId(1)]
void OnMyEvent(string text);
}
[ComVisible(true)]
[ComSourceInterfaces(typeof(IMyEvents))]
[Guid("31dd1263-0001-4071-aa4a-d226a55116bd")]
public class MyClass : IMyClass
{
public event OnMyEventDelegate OnMyEvent;
public object MyMethod()
{
// we use the current running process to test out stuff
// this should be Windows' default surrogate: dllhost.exe
var process = Process.GetCurrentProcess();
var text = "MyMethod. Bitness: " + IntPtr.Size + " Pid: " + process.Id + " Name: " + process.ProcessName;
Console.WriteLine(text); // should not be displayed when running under dllhost
OnMyEvent?.Invoke("MyEvent. " + text);
return text;
}
}
}
This is how I register it (note I'm targeting the 64bit registry):
%windir%\Microsoft.NET\Framework64\v4.0.30319\regasm.exe NetComClassLibrary3.dll /codebase /tlb
This is a .reg to make sure it will run out-of-process in dllhost.exe (the guid is the COM coclass MyClass' guid):
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\AppID\{31dd1263-0001-4071-aa4a-d226a55116bd}]
"DllSurrogate"=""
[HKEY_CLASSES_ROOT\CLSID\{31dd1263-0001-4071-aa4a-d226a55116bd}]
"AppID"="{31dd1263-0001-4071-aa4a-d226a55116bd}"
And here is the client, compiled as x86:
using System;
using NetComClassLibrary3; // we can reference the .net dll as is
namespace ConsoleApp10
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Bitness: " + IntPtr.Size);
// note we don't use new MyClass() otherwise we may go inprocess
var type = Type.GetTypeFromCLSID(typeof(MyClass).GUID);
var obj = (IMyClass)Activator.CreateInstance(type);
// note I'm using the beloved dynamic keyword here. for some reason obj.OnMyEvent works but locally raises a cast error I've not investigated further...
dynamic d = obj;
d.OnMyEvent += (OnMyEventDelegate)((t) =>
{
Console.WriteLine(t);
});
Console.WriteLine(obj.MyMethod());
}
}
}
When I run it, this is the output:
Bitness: 4 // running as 32-bit
MyEvent. MyMethod. Bitness: 8 Pid: 23780 Name: dllhost // from 64-bit world
MyMethod. Bitness: 8 Pid: 23780 Name: dllhost // from 64-bit world