这已被问了一百万次,但我仍然无法让它工作。所以我问: 我有一个DLL导入(非托管C / C ++代码),我想从C#调用,无法开始工作。我从VB.net移植,代码(工作原理)如下:
Module Module1
Public Declare Function autodetect_SearchAxis Lib "autodetect.dll" (ByVal onusb As Boolean, ByVal searchsubadress As Byte, ByRef portname As String, ByRef devicelocation As String) As Integer
Public AxisCom As String
Public AxisAdress As Byte = 1
Public Dummy As String
Public rc As Integer
Sub Main()
Dummy = Space(1024)
AXISCom = Space(1024)
rc = autodetect_SearchAxis(False, AxisAdress, Dummy, AxisCom)
Debug.WriteLine("rc: " + rc.ToString())
Debug.WriteLine("AxisCom: " + AxisCom.ToString())
End Sub
End Module
我没有自己的C#代码尝试ATM,但我尝试使用SttingBuilder
类的各种版本。如果有人可以帮助我将此代码移植到C#,我会很高兴。提前谢谢!
编辑:
我现在拥有DLL功能的签名:
int _stdcall autodetect_SearchAxis(bool onusb, BYTE searchsubadress, char* &portname, char* &devicelocation)
David Heffernan建议的解决方案部分工作。它正在工作(我没有错误消息),但返回的字符串是垃圾。基本上它是我已经工作的(具有相同的垃圾输出)。我不确定这是否与字符编码有关或什么不是(我没有收到任何错误消息)。希望签名有所帮助。
答案 0 :(得分:1)
基本上应该是:
using System.Diagnostics;
using System.Runtime.InteropServices;
public static class Module1
{
[DllImport("autodetect.dll")]
public static extern int autodetect_SearchAxis(bool onusb, byte searchsubadress, ref string portname, ref string devicelocation);
public static string AxisCom;
public static byte AxisAddress = 1;
public static string Dummy;
public static int rc;
public static void Main()
{
Dummy = new string(' ', 1024);
AxisCom = new string(' ', 1024);
rc = autodetect_SearchAxis(false, AxisAddress, ref Dummy, ref AxisCom);
Debug.WriteLine("rc: " + rc.ToString());
Debug.WriteLine("AxisCom: " + AxisCom.ToString());
}
}
答案 1 :(得分:1)
这不是最好的接口规范。从表面上看,调用者必须分配长度为1024的字符串缓冲区,并相信非托管代码不会超出该范围。更好的接口是让调用者传递缓冲区及其长度,以便非托管代码可以确保它不会超出缓冲区。
但是,假设您无法更改界面,请将其翻译为:
[DllImport("autodetect.dll", CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi)]
public static extern int autodetect_SearchAxis(
bool onusb,
byte searchsubaddress,
StringBuilder portname,
StringBuilder devicelocation
);
您需要声明并分配StringBuilder
个实例:
StringBuilder portname = new StringBuilder(1024);
StringBuilder devicelocation = new StringBuilder(1024);
然后电话看起来像这样:
int retval = autodetect_SearchAxis(onusb, searchsubaddress, portname, devicelocation);
// check retval for errors
然后在两个ToString()
实例上使用StringBuilder
方法读出返回的字符串值。
我必须承认{。{1}}在.net下工作有点不稳定,因为它是旧VB6代码的向后兼容性拐杖。所以我想知道如何编组Declare
参数。它是一个1字节的布尔值,还是一个4字节的布尔值?如本回答所述,它被编组为默认的4字节Windows布尔值bool
。
答案 2 :(得分:0)
我假设给你麻烦的一句话(根据问题的标题)是:
Public Declare Function autodetect_SearchAxis Lib "autodetect.dll" _
( _
ByVal onusb As Boolean, _
ByVal searchsubadress As Byte, _
ByRef portname As String, _
ByRef devicelocation As String _
) As Integer
在C#中,您需要添加引用(在静态类的顶部):
using System.Runtime.InteropServices;
然后你需要制作相同的DLL导入:
[DllImport("autodetect.dll", SetLastError = true)]
public static extern int autodetect_SearchAxis
(
bool onusb,
byte searchsubadress,
[MarshalAs(UnmanagedType.AnsiBStr)] ref string portname,
[MarshalAs(UnmanagedType.AnsiBStr)] ref string devicelocation
);
其余的代码应该非常简单。
要了解详情,请查看: