将字符串从非托管 dll 返回到 C#
我很抱歉在这里问这个问题,因为我确信它必须在“外面”得到回答,但我已经在这个问题上坚持了几个月了,而且我找到的解决方案都不适合我。
我有以下有效的 VB 代码:
Declare Function DeviceSendRead Lib "unmanaged.dll" (ByVal sCommand As String, ByVal sReply As String, ByVal sError As String, ByVal Timeout As Double) As Integer
Dim err As Integer
Dim outstr As String
Dim readstr As String
Dim errstr As String
outstr = txtSend.Text
readstr = Space(4000)
errstr = Space(100)
Timeout = 10
err = DeviceSendRead(outstr, readstr, errstr, Timeout)
并且我正在尝试在 C# 项目中实现它。我能找到的最好的等价物是:
[DllImport("unmanaged.dll")] public static extern int DeviceSendRead(String outstr, StringBuilder readstr, StringBuilder errstr, double Timeout);
int err;
StringBuilder readstr = new StringBuilder(4000);
StringBuilder errstr = new StringBuilder(100);
err = DeviceSendRead(txtSend.Text, readstr, errstr, 10);
但是,当我运行它时,应用程序冻结,我必须强制退出它。通过尝试 ref 和 out,我偶尔会设法让它崩溃而不是冻结,但我取得的唯一“进步”是将 dll 函数调用替换为:
DeviceSendRead(txtSend.Text, null, null, 10);
这可以防止崩溃,但当然什么也不做(我可以检测到)。因此,我假设传递两个返回字符串参数的方式导致了问题。如果有人可以建议我可能做错了什么,我会很高兴听到。谢谢。
I'm sorry to ask this here since I'm sure it must be answered "out there", but I've been stuck on this for several months now, and none of the solutions I've found have worked for me.
I have the following VB code that works:
Declare Function DeviceSendRead Lib "unmanaged.dll" (ByVal sCommand As String, ByVal sReply As String, ByVal sError As String, ByVal Timeout As Double) As Integer
Dim err As Integer
Dim outstr As String
Dim readstr As String
Dim errstr As String
outstr = txtSend.Text
readstr = Space(4000)
errstr = Space(100)
Timeout = 10
err = DeviceSendRead(outstr, readstr, errstr, Timeout)
and I am trying to implement it in a C# project. The best equivalent I have been able to find is:
[DllImport("unmanaged.dll")] public static extern int DeviceSendRead(String outstr, StringBuilder readstr, StringBuilder errstr, double Timeout);
int err;
StringBuilder readstr = new StringBuilder(4000);
StringBuilder errstr = new StringBuilder(100);
err = DeviceSendRead(txtSend.Text, readstr, errstr, 10);
However, when I run this, the application freezes and I must force quit it. By experimenting with ref and out, I have occasionally managed to make it crash rather than freeze, but the only "progress" I have achieved is to replace the dll function call with:
DeviceSendRead(txtSend.Text, null, null, 10);
This prevents the crash, but of course does nothing (that I can detect). I'm therefore assuming that it's the manner of passing the two return string parameters that is causing the problem. If anyone can suggest what I might be doing wrong, I'd be very happy to hear it. Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我已经找到了答案,为了完整起见,我将在这里记录下来,并衷心感谢所有为我指明正确方向的人。
根据其他地方的这篇文章,使用.NET类似 VB 代码的 Reflector 建议需要使用
string
类型代替我的StringBuilder
,正如 Alex Mendez、JamieSee 和 Austin Salonen 在此建议的那样,以及显式的封送处理,如 Nanhidin 建议的那样,但使用非托管类型VBByRefStr
而不是AnsiBStr
。难题的最后一个关键是需要使用 ref 关键字通过引用传递字符串参数。我可以确认这是有效的,因此我的最终工作 C# 代码是:
我希望这对面临类似问题的其他人有用。
I have reached an answer, which I will record here for completeness, with grateful thanks to all those who pointed me in the right direction.
According to this post elsewhere, the use of .NET Reflector on similar VB code suggests the need to use the
string
type in place of myStringBuilder
, as suggested here by Alex Mendez, JamieSee and Austin Salonen, together with explicit marshaling, as suggested by Nanhydrin, but utilising the unmanaged typeVBByRefStr
rather thanAnsiBStr
. The final key to the puzzle is that the string parameter then needs to be passed by reference using theref
keyword.I can confirm that this works, and that my final working C# code is therefore:
I hope this is useful to others facing a similar issue.
试试这个:
Try this:
尝试将其作为等效项:
Try this as an equivalent:
字符串的默认编组
默认编组行为
您可能需要在 dllimport 声明中更加具体,并且添加一些 MarshalAs 属性,如果您有关于被调用函数期望的字符串类型(Ansi、Unicode、null 终止等)的更多详细信息,那么这会有所帮助。
事实上,它期望以空结尾的字符串也许可以解释为什么它挂起而不是出错。
您可能还需要使用参数属性 [In, Out] 明确声明您的参数是输入、输出或两者。
Default Marshalling for strings
Default Marshalling behaviour
You may need to be more specific in your dllimport declaration and add in some MarshalAs attributes, if you have more details on what type of strings the called function is expecting (Ansi, Unicode, null terminated, etc.) then that would help.
In fact it expecting null terminated strings could perhaps explain why it's hanging rather than erroring out.
You might also need to explicitly state that your parameters are input, output, or both by using the parameter attributes [In, Out].
您不能在此处封送 StringBuilder。编组 StringBuilder 需要遵循一些规则(请参阅 CLR 由内而外:托管和托管之间的编组非托管代码):
规则3在这里似乎并没有得到满足。
You cannot marshal a StringBuilder here. There are some rules to follow for marshalling StringBuilder (see CLR Inside Out: Marshaling between Managed and Unmanaged Code):
Rule 3 doesn't seem like it is satisied here.