【问题标题】:VB5 dll, how can I invoke the function from C# ( .NET 4.5 )VB5 dll,如何从 C# ( .NET 4.5 ) 调用该函数
【发布时间】:2016-04-14 11:35:44
【问题描述】:

我的问题很简单

VB.dll(VB5.0 我猜)包括这些方法

Private Declare Function ffr_device_find Lib ".\ffr_32.dll" () As Boolean
Private Declare Function ffr_data_transceive_ex Lib ".\ffr_32.dll" (ByVal sp_sdata As String, ByVal sp_rdata As String) As Boolean

在 C# 中......(.NET 4.5)

[DllImport("FFR_32.dll", CallingConvention = CallingConvention.Cdecl)]
extern public static Boolean ffr_device_find();

[DllImport("FFR_32.dll", CallingConvention = CallingConvention.Cdecl)]
extern public static void ffr_data_transceive_ex([Out] string sp_sdata, [Out] string sp_rdata);
// FYI, I tried [Out], out, and ref but to no avail.

第一个效果很好

但是第二个溢出了这个错误。

对 PInvoke 函数“ffr_data_transceive_ex”的调用导致堆栈不平衡。
这可能是因为托管的 PInvoke 签名不匹配 非托管目标签名。检查调用约定和 PInvoke 签名的参数与目标非托管签名匹配。

仅供参考

这是来自 VB 的工作代码...(NOT INNER DLL SOURCES

Dim st As String
Dim rData As String * 40

st = "4401" & "20202020202020202020202020202020"
Text1.Text = st
Cal_BCC
Call ffr_data_transceive_ex(Text1.Text, rData)
Text2.Text = rData

我什至不明白Dim rData As String * 40 是什么意思...当rData0 时它会变成0 吗?当rData1 时变成40? ...

我在 C# 中的 DllImport 方法有什么问题???

【问题讨论】:

  • 你确定ccr_data_transceive_ex的第一个参数是[Out]吗?因为在您提供的示例中,我没有看到它用作输出参数。
  • * 40 在 VB 中使字符串具有 40 的固定预分配长度。在 C# 中尝试:[Out] StringBuilder sp_rdata 其中 sp_rdata 是 new StringBuilder(40),如果是事实,则对 sp_sdata 执行相同操作输出,否则删除输出。 ccr_data_transceive_ex 不是 void 它的 boolean
  • @Peping 它应该使用[Out], ref or out,因为 dll 将参数作为ByVal
  • @AlexK。是的,好点。但我以前试过……voidboolean ( or bool ) 也不起作用。它产生同样的错误。
  • @Peping ByVal 在 VB 中应用于字符串时具有不同的含义。将字符串ByVal 传递给API 函数就是这样做的方法,函数可以更改字符串的内容。它与[In][Out] 无关,这些只是提示marshaler 跳过复制数据。

标签: c# vb.net interop


【解决方案1】:
   [DllImport("FFR_32.dll", CallingConvention = CallingConvention.Cdecl)]

这不是 Cdecl。 Visual Basic 采用默认设置,StdCall。您在第一个函数上侥幸逃脱,因为它不接受任何参数。不是第二个,因为它使堆栈不平衡,调用者和被调用者都将参数从堆栈中弹出,迫使 MDA 介入并告诉你剧烈的事故。

只需完全删除该属性,您就可以在 C# 程序中获得正确的默认值 CallingConvention.StdCall。

   void ffr_data_transceive_ex([Out] string sp_sdata, [Out] string sp_rdata)

您不能使用string,字符串在 .NET 中是不可变的。请改用StringBuilder。请确保其容量足够大,以能够存储函数写入的接收数据。猜测太低会导致堆损坏,这是一个非常难以解决的错误。

也很可能它应该是byte[],您的问题并没有很好地记录返回数据的类型。 VB5 还没有 Byte 类型,因此固定字符串(如 String * 40)是下一个最佳选择。也不适用于 .NET,并非所有可能的字节值都有相应的 Unicode 代码点。仅当您知道该函数仅返回 ASCII 代码时才使用 StringBuilder。

【讨论】:

  • 感谢您的回答以及我应该避免使用CallingConvention 的确切解释。我接受了您的回答,但对于那些可能特别想要针对这种情况的确切解决方案的人,我提出了一个可能进一步支持您的回答的答案。再次感谢您。
【解决方案2】:

我选择 Hans Passant 的上述答案

但是对于那些想要这个案例的精确解决方案的人,我会给你一些额外的信息和一些代码sn-ps。

第一

就像 Hans Passant 所说,CallingConvention 应该被除掉。

第二

就像 Hans Passant 所说,字符串不应该被传递到函数中。更准确地说,第一个参数可以作为string 类型传入。但第二个应该是char[],具有明确的长度。

我对此进行了测试,当长度不同时它会引发另一个错误。

工作代码

extern public static void ffr_data_transceive_ex([Out] string sp_sdata, [Out] char[] sp_rdata);

必要成分

// To pass the second parameter.
// Because the dll returns 40 length characters, this should be specified as length '40'
char[] ForCardHex = new char[40];

// Command is an already defined protocol format, like "200080581028000001"
// , which can be taken as string.
ffr_data_transceive_ex(Command, ForCardHex);

这很有效,它返回ForCardHex 上的预期值。你应该使用char[]。我无法将byte[] 传递到函数中。

感谢所有评论者和回答者。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多