从非托管 Windows 自定义 DLL 调用托管 .NET 函数。






2.92/5 (11投票s)
2004年4月26日
3分钟阅读

123632

2
它将帮助你从非托管 DLL 函数调用托管函数。
引言
这有可能吗?
是的,这绝对有可能,但你必须记住一件事。你不能从 Win32 进程调用 .NET 函数。除非你外部加载 CLR,否则这永远不可能。因此,在本文中,我们将了解如何在 .NET 进程中,从 Windows 自定义 DLL(例如,用 VC++ 编写的 DLL)调用 .NET 函数。
这有必要吗?
是的,这会有必要。从 .NET 使用 Win32 API 的开发人员,有时需要来自非托管代码的通知传递到 .NET 环境中的托管函数(例如,通知异步调用完成)。那时,他们可以使用这种方法来完成他们的任务。
给出的示例有用吗?
不,我们仅将此代码示例用于演示目的。在此示例中,我们将从托管代码调用非托管代码,并且非托管代码本身再次调用另一个托管代码(你可以使用此技术通知 .NET 环境有关来自非托管代码的异步事件)。
基本思想
通常,我们可以通过两种方法调用函数。第一种是使用函数名称,下一种是通过函数指针。在这里,我们将从另一个(非托管)环境调用函数,因此我们不能直接使用函数名称,因此我们将使用函数指针。第一步是,我们必须将函数指针提供给非托管代码,然后非托管代码将使用此函数指针来调用托管代码。
核心内容在下图中有描述
为了检查这一点,我们将在 VC++ 中创建一个自定义 DLL,并实现两个函数。一个是 SetCallBackPointer
,它接收来自托管代码的函数指针并将其存储在全局变量 pFunction
中。另一个函数 InvokeCallBack
用于使用函数指针 pFunction
调用托管代码。以下是驻留在 DLL 源文件中的代码。
// MyCustomDll.cpp //Global Variable for store the function pointer. typedef VOID (*CALLBACK_FUNCTION )(); CALLBACK_FUNCTION pFunction; void SetCallBackPointer(LPVOID FnAddress); void InvokeCallBack(); //This function receive the address of the CallBack function as //parameter and store it in a global variable to enable other function in // the DLL to call the CallBack Function. void SetCallBackPointer(LPVOID FnAddress) { pFunction = (CALLBACK_FUNCTION)FnAddress; // For demonstration purpose only. In real World we may call // this function in response to a asynchronous message. InvokeCallBack(); } // this function will Invoke the callback function // through the function pointer. void InvokeCallBack() { (pFunction)(); // simply calls the Callback function through pointer. }
然后,我们必须导出 SetCallBackPointer
,使其可以从 DLL 外部调用。
// MyCustomDll.def // LIBRARY MYCUSTOMDLL EXPORTS SetCallBackPointer
好的,现在我们可以构建我们的 DLL 并创建 MyCustomDll.dll。接下来,我们将编写 C# 代码来实现回调函数
// Managed.cs
//
// Our Callback function which will be called by unmanaged code(Form windows dll).
public static void CallbackFunction()
{
MessageBox.Show( “CallBack Function Called by Windows DLL”);
}
我们不能像在 C、C++ 或 VC++ 中那样直接将函数名称作为函数指针给出。幸运的是,我们可以使用委托来实现。(我希望大家都熟悉 .NET 的一个很棒的未来:委托。如果你不熟悉委托,请参考 MSDN。)
让我们声明一个委托并按如下方式实例化它。
// Declaring Delegate for Callback Function
// note that the Delegate prototype and Callback function
// prototype are same.
delegate void CallBackDelegate();
public static CallBackDelegate myDelegate;
接下来,我们必须将我们的回调函数与委托关联起来
// Associating callback function with delegate
myDelegate =new MyDelegate(CallbackFunction);
好的,现在我们的函数指针已准备就绪。下一步是,我们必须将其发送到 DLL。为了将回调函数(即委托)呈现给 DLL,我们必须使用 DllImport
属性声明 SetCallBackPointer
的函数原型。 这是声明
// this function prototype should match our Custom dll’s
// ‘SetCallBackPointer’ functioin prototype.
//
[DllImport("MyCustomDll.dll",CallingConvention=CallingConvention.StdCall)]
private static extern void SetCallBackPointer(CallBackDelegate delegate);
一切都已准备就绪;剩下的就是我们必须调用 SetCallBackPointer
函数。 以下调用将在 MyCustomDll 中调用 SetCallBackPointer
函数,并将 CallBackFunction
函数指针(委托)作为参数
SetCallBackPointer(myDelegate);
是的,我们成功了,CallBackFunction
是从我们的自定义 DLL 调用的。