在传递给本机dll的c#回调中访问托管对象
我试图将一个C#回调函数传递给一个本机dll。它工作正常,但我找不到访问回调方法的父对象的方法。下面的代码演示了我要做的事情:在传递给本机dll的c#回调中访问托管对象,c#,delphi,pinvoke,C#,Delphi,Pinvoke,我试图将一个C#回调函数传递给一个本机dll。它工作正常,但我找不到访问回调方法的父对象的方法。下面的代码演示了我要做的事情: class MyForm: Form { public delegate void CallbackDelegate(IntPtr thisPtr); [DllImport("mylib.dll", CallingConvention = CallingConvention.StdCall)] public static extern void Test(
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编写的,测试函数的签名如下:
type
TCallback = procedure of object; stdcall;
procedure Test(Callback: TCallback); stdcall;
当我试图用以下代码获取指向类的指针时,我收到了上述错误消息:
var ptr = GCHandle.Alloc(this, GCHandleType.Pinned).AddrOfPinnedObject();
您应该使用
System.Runtime.InteropServices.GCHandle
类。它涉及使用其静态方法从C#引用到非托管值以及从非托管值转换
我没有快速检查的方法,但类似的方法应该可以:
应按如下方式获取IntPtr
:
IntPtr thisPtr = GCHandle.ToIntPtr(GCHandle.Alloc(thisObject)));
type
TCallback = procedure; stdcall;
void Callback()
{
// an instance method, so *this* is available
}
void CallExternalMethod()
{
Test(Callback);
}
PS:请注意,在某些情况下,您必须释放被调用方或调用方中的句柄。您应该使用
System.Runtime.InteropServices.GCHandle
类。它涉及使用其静态方法从C#引用到非托管值以及从非托管值转换
我没有快速检查的方法,但类似的方法应该可以:
应按如下方式获取IntPtr
:
IntPtr thisPtr = GCHandle.ToIntPtr(GCHandle.Alloc(thisObject)));
type
TCallback = procedure; stdcall;
void Callback()
{
// an instance method, so *this* is available
}
void CallExternalMethod()
{
Test(Callback);
}
PS:请注意,在某些时候,您必须释放被调用方或调用方中的句柄。您考虑得太多了。C#编组将在您的代理周围产生一个响声。您不得试图这样做 在Delphi端,这样写:
IntPtr thisPtr = GCHandle.ToIntPtr(GCHandle.Alloc(thisObject)));
type
TCallback = procedure; stdcall;
void Callback()
{
// an instance method, so *this* is available
}
void CallExternalMethod()
{
Test(Callback);
}
只需删除对象的
在C方,您的代表是:
public delegate void CallbackDelegate();
用于代理的方法如下所示:
IntPtr thisPtr = GCHandle.ToIntPtr(GCHandle.Alloc(thisObject)));
type
TCallback = procedure; stdcall;
void Callback()
{
// an instance method, so *this* is available
}
void CallExternalMethod()
{
Test(Callback);
}
然后调用本机代码,如下所示:
IntPtr thisPtr = GCHandle.ToIntPtr(GCHandle.Alloc(thisObject)));
type
TCallback = procedure; stdcall;
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#端:
你想得太多了。C#编组将在您的代理周围产生一个响声。您不得试图这样做
在Delphi端,这样写:
IntPtr thisPtr = GCHandle.ToIntPtr(GCHandle.Alloc(thisObject)));
type
TCallback = procedure; stdcall;
void Callback()
{
// an instance method, so *this* is available
}
void CallExternalMethod()
{
Test(Callback);
}
只需删除对象的
在C方,您的代表是:
public delegate void CallbackDelegate();
用于代理的方法如下所示:
IntPtr thisPtr = GCHandle.ToIntPtr(GCHandle.Alloc(thisObject)));
type
TCallback = procedure; stdcall;
void Callback()
{
// an instance method, so *this* is available
}
void CallExternalMethod()
{
Test(Callback);
}
然后调用本机代码,如下所示:
IntPtr thisPtr = GCHandle.ToIntPtr(GCHandle.Alloc(thisObject)));
type
TCallback = procedure; stdcall;
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#端:
mylib.dll中的本机测试方法是如何声明的?我不是要定义,只是要方法的签名。你能提供更多的代码吗?@David Heffernan我实际上是在编代码,而不是复制原始代码以避免不相关的细节。我想我写了所有相关的代码。缺少什么?我有一些p/invoke interop到Delphi的经验。和回调。但我完全不知道你想做什么。我希望看到一个完整的程序来演示这个错误。p/invoke部分工作得非常好。我不知道如何从静态回调方法引用MyForm实例的字段。当我尝试使用GCHandle.Alloc(这个,GCHandleType.pinted)
获取指向MyForm实例的指针时,会引发异常。但我不确定这是否是做我想做的事情的正确方法。我已经更新了代码。您在mylib.dll中的本机测试方法是如何声明的?我不是要定义,只是要方法的签名。你能提供更多的代码吗?@David Heffernan我实际上是在编代码,而不是复制原始代码以避免不相关的细节。我想我写了所有相关的代码。缺少什么?我有一些p/invoke interop到Delphi的经验。和回调。但我完全不知道你想做什么。我希望看到一个完整的程序来演示这个错误。p/invoke部分工作得非常好。我不知道如何从静态回调方法引用MyForm实例的字段。当我尝试使用GCHandle.Alloc(这个,GCHandleType.pinted)
获取指向MyForm实例的指针时,会引发异常。但我不确定这是否是做我想做的事情的正确方法。我已经更新了代码。我已经更新了我的问题。您能提供执行此操作的代码吗?我试图使用这个类,但没有成功。@Max我没有快速的方法来测试它是否有效,但这只是一般的想法。这就是我正在做的,只是我使用了GCHandleType.pinted
参数。我认为不允许将未固定的指针传递给本机代码。您的主要问题是使用addrofPindedObject
而不是ToIntPtr
。GCHandle
不是一个原始指针,它更像是一个cookie,用于重建托管指针(并在对象上维护一个“人工”引用,因此它不是GC的)。我已经更新了我的问题。您能提供执行此操作的代码吗?我试图使用这个类,但没有成功。@Max我没有快速的方法来测试它是否有效,但这只是一般的想法。这就是我正在做的,只是我使用了GCHandleType.pinted
参数。我认为不允许将未固定的指针传递给本机代码。您的主要问题是使用addrofPindedObject
而不是ToIntPtr
。GCHandle
不是一个原始指针,它更像是一个cookie,用于重建托管指针(并在对象上维护一个“人工”引用,因此它不是GC的)。哇!这真的很奇怪。所以这个ptr就像一个虚拟参数。非常感谢你!这确实有效。您需要删除两侧的thisPtr。让马歇尔帮你敲打它。关于这个话题,这里还有一个问题:我忘了提到的一件事是,我不能从delphi declarion中删除对象的,因为它也被用于其他部分。但是你的编辑前解决方案很好,这是个问题。