从 C# 代码调用 delphi DLL 函数

发布于 2024-12-23 01:37:22 字数 1497 浏览 0 评论 0原文

我有一个在 Delphi 2007 中编译的 DLL 以及一个在其他 Delphi 项目中使用它的示例。这是代码的一部分:

TErrorCallback = function(Msg:PChar):byte of object;
TSaveEventCallback = function (Line:PChar; HiCode:PChar; LoCode:PChar; MobileNo:PChar):byte of object;

function InitModule(ErrorCallback:TErrorCallback; SaveEventCallback :TSaveEventCallback; MainWindowHandle:THandle; Sock_Event:integer):byte; stdcall; external 'My.dll' name 'InitModule';

function DLLSocketEvent(var msg: TMessage): byte; stdcall; external 'My.dll' name 'DLLSocketEvent';

function InitObjList(Objs: array of PChar; NumObjs: byte; Name: PChar):byte; stdcall; external 'My.dll' name 'InitObjList';

这是我的 C# 模拟:

class Message
{
  unsigned int msg;
  int wParam;
  int lParam;
  int result;
};
delegate byte ErrorCallbackDelegate(string msg);
delegate byte SaveEventCallbackDelegate(string line, string hiCode, string loCode, string mobileNo);

[DllImport("My.dll")]
static extern byte InitModule(ErrorCallbackDelegate errorCallback, SaveEventCallbackDelegate saveEventCallback, IntPtr mainWindowsHandle, Int32 sockEvent);

[DllImport("My.dll")]
static extern byte DllSocketEvent(Message msg);

[DllImport("My.dll")]
static extern byte InitObjList(string[] objs, byte numObjs, string name);

重点是我只尝试了 InitModule 方法,它抛出了一个异常: 对 PInvoke 函数“ProjTest!ProjTest.MyClass::InitModule”的调用使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。

请帮我解决这个问题。我应该如何用 C# 描述这些 DLL 函数?

I have a DLL compiled in Delphi 2007 and an example using it in other Delphi project. Here is a part of code:

TErrorCallback = function(Msg:PChar):byte of object;
TSaveEventCallback = function (Line:PChar; HiCode:PChar; LoCode:PChar; MobileNo:PChar):byte of object;

function InitModule(ErrorCallback:TErrorCallback; SaveEventCallback :TSaveEventCallback; MainWindowHandle:THandle; Sock_Event:integer):byte; stdcall; external 'My.dll' name 'InitModule';

function DLLSocketEvent(var msg: TMessage): byte; stdcall; external 'My.dll' name 'DLLSocketEvent';

function InitObjList(Objs: array of PChar; NumObjs: byte; Name: PChar):byte; stdcall; external 'My.dll' name 'InitObjList';

And here is my C# analog:

class Message
{
  unsigned int msg;
  int wParam;
  int lParam;
  int result;
};
delegate byte ErrorCallbackDelegate(string msg);
delegate byte SaveEventCallbackDelegate(string line, string hiCode, string loCode, string mobileNo);

[DllImport("My.dll")]
static extern byte InitModule(ErrorCallbackDelegate errorCallback, SaveEventCallbackDelegate saveEventCallback, IntPtr mainWindowsHandle, Int32 sockEvent);

[DllImport("My.dll")]
static extern byte DllSocketEvent(Message msg);

[DllImport("My.dll")]
static extern byte InitObjList(string[] objs, byte numObjs, string name);

The point is I've tried only InitModule method and it throwed an exception:
A call to PInvoke function 'ProjTest!ProjTest.MyClass::InitModule' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

Please, help me with this. How should I describe these DLL functions in C#?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

玉环 2024-12-30 01:37:22

您无法从 C# 调用该 DLL。主要问题是两个对象回调。 C# 中没有办法匹配这一点。您将需要修改现有的 DLL 或添加中间适配器 DLL。按照目前的情况,您的 DLL 只能从 Delphi 或 C++ Builder 访问。

如果您可以修改 DLL,那么您需要进行的修改就是删除对象的。如果您需要回调来作用于实例,那么您需要将该实例作为参数传递。然而,C# 委托可以透明地包装所有这些,因此如果您需要从其他语言(例如 Delphi)访问 DLL,则只需将实例作为参数传递。

另一个问题是开放数组参数。从其他语言也不容易访问到这一点。虽然有 技巧,我建议传递对第一个元素的引用而不是开放数组。开放数组是 Delphi 所独有的。

我也不明白为什么你使用 byte 类型来保存数组长度。为此,您应该使用Integer。使用字节没有任何好处,而且只会导致溢出。另外,MainWindowHandle 在 Delphi 中不应该是 THandle。它应该是HWND

我对您的建议是修改 DLL 以具有 C 兼容接口,从而可以从支持该接口的所有语言进行访问。实际上,这将使所有主流编程语言都可以访问它。

You can't call that DLL from C#. The main problem are the two of object callbacks. There's no way in C# to match that. You will need to modify the existing DLL or add an intermediate adapter DLL. As it stands your DLL is only accessible from Delphi or C++ Builder.

If you can modify the DLL then the modification you need to make is to remove the of object. If you need the callback to act on an instance then you will need to pass the instance as a parameter. However, C# delegates can wrap all that up transparently so you would only need to pass the instance as a parameter if you needed the DLL to be accessible from other languages, e.g. Delphi.

The other issue is the open array parameter. That is also not easily accessed from other languages. Although there are tricks, I would recommend passing a reference to the first element rather than an open array. Open arrays are unique to Delphi.

I also do not understand why you are using the byte type to hold array length. You should use Integer for this. There's nothing to gain from using byte and you simply invite overflow. Also, MainWindowHandle should not be THandle in Delphi. It should be HWND.

My recommendation to you would be to modify the DLL to have a C compatible interface and thus be accessible from all languages that support that. In practice this would make it accessible from all mainstream programming languages.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文