如何从C#获取非托管全局变量?

时间:2010-09-02 19:14:52

标签: c# interop unmanaged

我正在为非托管DLL编写.NET包装器。原始DLL是带有C shim的C ++,基本上只是以C形式复制API,因此语言绑定不是那么痛苦。我已经为它编写了一个Python绑定,所以我知道我想要做什么应该工作。

DLL有许多回调导出为全局成员,即:

__declspec(dllexport) extern int (*some_callback)(int32_t*, uint32_t);

我需要将一个托管函数附加到此指针,但我无法弄清楚如何获取非托管库中的非函数资源。除非我只是盲目,否则DllImport只会导入函数。

是否有C#方式来执行此操作,或者我是否需要在C中编写一个提供注册功能的小填充DLL?我讨厌这种方法,因为它只是感觉不优雅,但如果必须的话,我必须这样做。

1 个答案:

答案 0 :(得分:3)

你没错,P / Invoke无法处理DLL的数据导出。然而,通过直接获得出口在技术上是可行的。这非常难看,有一天你可能会后悔,但这很有效:

示例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;
}

测试C#代码:

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);

}