简体   繁体   English

我该如何从C#中获得不受管理的全局变量?

[英]How can I get at unmanaged globals from C#?

I'm writing a .NET wrapper for an unmanaged DLL. 我正在为非托管DLL编写.NET包装器。 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. 原始的DLL是带有C填充程序的C ++,该填充程序基本上只是以C形式复制API,因此语言绑定并不是那么麻烦。 I've already written a Python binding for it, so I know what I'm trying to do should work. 我已经为它编写了Python绑定,所以我知道我想做的应该可行。

The DLL has a number of callbacks exported as global members, viz.: DLL具有许多作为全局成员导出的回调,即:

__declspec(dllexport) extern 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. 除非我只是盲目,否则DllImport仅导入函数。

Is there a C# way to do this, or do I need to write a little shim DLL in C that provides registration functions? 有C#方式可以做到这一点,还是我需要在C中编写一个提供注册功能的小垫片DLL? 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. 没错,P / Invoke无法处理从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: 示例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: 测试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);

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM