How can I get at unmanaged globals from C#?
I'm writing a .NET wrapper for an unmanaged DLL. The original DLL is C++ with a C shim that basically just replicates the API in C form, so that language bindings aren't such a pain. I've already written a Python binding for it, so I know what I'm trying to do should work.
The DLL has a number of callbacks exported as global members, viz.:
__declspec(dllexport) exte开发者_Python百科rn int (*some_callback)(int32_t*, uint32_t);
I need to attach a managed function to this pointer, but I can't figure out how to get at non-function resources in an unmanaged library. Unless I'm just blind, DllImport only imports functions.
Is there a C# way to do this, or do I need to write a little shim DLL in C that provides registration functions? I hate that approach, because it just feels inelegant, but if I have to, I have to.
You're right, P/Invoke cannot handle data exports from a DLL. It is however technically possible by obtaining the export directly. This is very ugly and you'll probably regret it some day, but this worked:
Sample C/C++ DLL:
#include "stdafx.h"
typedef int (__stdcall * pfnCallback)(int*, unsigned*);
extern "C" __declspec(dllexport)
pfnCallback some_callback;
pfnCallback some_callback;
static int theCallback(int*, unsigned*) {
return 42;
}
BOOL APIENTRY DllMain( HMODULE hModule, DWORD reason, LPVOID reserved) {
if (reason == DLL_PROCESS_ATTACH) {
some_callback = theCallback;
}
return TRUE;
}
Test C# code:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
class Program {
unsafe static void Main(string[] args) {
IntPtr hMod = LoadLibrary("cpptemp10.dll");
if (hMod == IntPtr.Zero) throw new Win32Exception();
IntPtr export = GetProcAddress(hMod, "some_callback");
if (export == IntPtr.Zero) throw new Win32Exception();
IntPtr callback = Marshal.ReadIntPtr(export);
some_callback dlg = (some_callback)Marshal.GetDelegateForFunctionPointer(callback, typeof(some_callback));
int retval = dlg(null, null);
Console.WriteLine(retval);
Console.ReadLine();
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
unsafe delegate int some_callback(int* arg1, uint* arg2);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadLibrary(string path);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hMod, string name);
}
精彩评论