Call a function in a C DLL from VB: Access Violation
我正在尝试调用如下所示的 Dll 函数(在 C/C Dll 中):
1 | __declspec(dllexport) void execute(char** ReturnMsg, char* serverAddress, char* commandLine) |
VB\\'wrapper\\' 函数如下所示:
1 2 3 4 5 | <DllImport("TPClient.dll", EntryPoint:="execute", CallingConvention:=CallingConvention.Cdecl, CharSet:=CharSet.Auto, ExactSpelling:=True)> _ Public Shared Sub tg_execute(<Out()> <MarshalAs(UnmanagedType.LPStr)> ByRef returnString As System.Text.StringBuilder, _ <MarshalAs(UnmanagedType.LPStr)> ByVal serverAddress As String, _ <MarshalAs(UnmanagedType.LPStr)> ByVal commandLine As String) End Sub |
参数为:
returnString:我需要从函数中取回的字符串,发送命令的结果;
serverAddress:字符串,仅输入(IP 或 DNS 名称);和
commandLine:字符串,仅输入(任何命令)
为了调用该函数,我创建了一个具有足够容量的 StringBuilder 对象以用作 returnString 变量:
1 2 3 | Dim returnString As New System.Text.StringBuilder(128) tg_execute(returnString, TextBox_serverName.Text.Trim, TextBox_Command.Text.Trim) |
当我运行代码时,我确实在 returnString 中得到了预期的字符串(正如我在调试器中看到的那样),但是我也得到了一个 AccessViolationException。因此,当我在 commandLine 中使用命令 "uname -r" 时,我会在 returnString 中得到例如 "2.6.30.8-x86"。但是由于内存错误,代码挂起。
现在我对 VB 和 P/Invoke 不太熟悉,我不得不反复试验才能将参数传递给 DLL(我也在编写和调试)。这也是我最终使用"MarshalAs(UnmanagedType.LPStr)"属性的方式。但是现在我不知道为什么会出现这些内存错误。
我使用 IntPtr 参数进行了一些其他尝试,但我也无法使其正常工作并放弃了这种方法,因为我的理解应该自动处理编组(正确吗?)。
非常感谢任何帮助。
返回值
这里实际上没有足够的信息来知道如何调用这个函数。缺少的是知道哪一方负责解除分配字符串。它可能是任何一方,我将假设 C 代码会这样做,可能是通过静态分配的字符串,例如常量。
现在,我没有使用 VB p/invoke 的经验,所以我希望你不介意我给你一个 C# 版本。我希望你可以很容易地翻译。
1 2 3 4 | [DllImport("TPClient.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi, EntryPoint="execute", ExactSpelling=true)] private static void tg_execute(out IntPtr returnString, string serverAddress, string commandLine) |
你这样调用函数:
1 2 3 | IntPtr returnStringPtr; tg_execute(out returnStringPtr, serverAddress, commandLine); string returnString = Marshal.PtrToStringAnsi(returnStringPtr); |
请注意,您的字符集在问题中不正确。您必须使用 Ansi,因为本机代码使用
现在,如果本机代码希望调用者释放内存,那么本机代码必须导出一个函数来执行此操作。如果是这种情况,那么您可以将其称为按值传递