我正在尝试将C#回调函数传递给本机dll。它工作正常,但我找不到一种方法来访问回调方法的父对象。这是一个代码,演示了我想要做的事情:
class MyForm: Form {
public delegate void CallbackDelegate(IntPtr thisPtr);
[DllImport("mylib.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void Test(CallbackDelegate callback);
int Field;
static void Callback(IntPtr thisPtr)
{
// I need to reference class field Field here.
MyForm thisObject = ?MagicMethod?(thisPtr);
thisObject.Field = 10;
}
void CallExternalMethod()
{
Test(Callback);
}
}
我尝试获取this
的指针,但我得到以下异常:“对象包含非原始或非blittable数据。”我应该提一下,父对象是WindowsForms格式。
更新
dll是用Delphi编写的,Test函数的签名如下:
type
TCallback = procedure of object; stdcall;
procedure Test(Callback: TCallback); stdcall;
当我尝试使用以下代码获取指向类的指针时,我收到了上述错误消息:
var ptr = GCHandle.Alloc(this, GCHandleType.Pinned).AddrOfPinnedObject();
答案 0 :(得分:3)
你在想这个。 C#编组将在您的代理周围创建一个thunk。你不能试图这样做。
在Delphi方面写这样:
type
TCallback = procedure; stdcall;
只需删除of object
。
在C#端,您的代表是:
public delegate void CallbackDelegate();
您用于代理的方法如下所示:
void Callback()
{
// an instance method, so *this* is available
}
然后你调用这样的本机代码:
void CallExternalMethod()
{
Test(Callback);
}
所以,让我们把它们放在一起。在Delphi方面,你可以写:
library MyLib;
type
TCallback = procedure; stdcall;
procedure Test(Callback: TCallback); stdcall;
begin
Callback;
end;
exports
Test;
begin
end.
在C#方面:
class MyForm: Form {
public delegate void CallbackDelegate();
[DllImport("mylib.dll")]
public static extern void Test(CallbackDelegate callback);
int Field;
static void Callback()
{
Field = 10;
}
void CallExternalMethod()
{
Field = 0;
Test(Callback);
Debug.Assert(Field == 10);
}
}
答案 1 :(得分:0)
您应该使用System.Runtime.InteropServices.GCHandle
课程its MSDN documentation has examples。它涉及使用其静态方法从C#引用转换为非托管值和从非托管值转换。
我没有快速检查方法,但这样的事情应该有效:
static void Callback(IntPtr thisPtr)
{
MyForm thisObject = (MyForm)GCHandle.FromIntPtr(thisPtr).Target;
thisObject.Field = 10;
}
应该像这样获得IntPtr
:
IntPtr thisPtr = GCHandle.ToIntPtr(GCHandle.Alloc(thisObject)));
PS:请注意,在某些时候,您必须在被叫方或来电者中释放句柄。