从 VB.NET 转换为 C# - 未正确返回值
Converted From VB.NET to C# - Not Returning Values Correctly
原来的VB.net,运行完美:
Declare Function HolderName Lib "myCard.dll" (ByVal buf As String) As Integer
Declare Function Photo Lib "myCard.dll" (ByRef photo As Byte) As Integer
...
buff = Space(200) : res = HolderName(buff)
ShowMsg("HolderName():" & IIf(res = 0, "OK:" & Trim(buff), "FAIL"))
photobuf = New Byte(4096) {}
res = Photo(photobuf(0))
ShowMsg("Photo():" & IIf(res = 0, "OK", "FAIL"))
If res = 0 Then
Dim ms As New MemoryStream(photobuf)
picImage.Image = Image.FromStream(ms)
End If
转换后的代码现在在 C# 中(使用 http://converter.telerik.com/)
using System.Runtime.InteropServices;
...
[DllImport("myCard.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern int HolderName(String dBuff);
[DllImport("myCard.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern int Photo(ref byte photo);
//...
buff = new String(' ', 200);
res = HolderName(buff);
// buff remains UNALTERED!
ShowMsg("HolderName():" + (res == 0 ? "OK:" + Strings.Trim(buff) : "FAIL"));
photobuf = new byte[4096];
res = Photo(ref photobuf[0]);
ShowMsg("Photo():" + (res == 0 ? "OK" : "FAIL"));
// photobuf successfully receives the data bytes from Photo function
if (res == 0)
{
MemoryStream ms = new MemoryStream(photobuf);
picImage.Image = Image.FromStream(ms);
}
问题是 buff
保持不变,即使 HolderName
函数实际上 returns 一些值(使用 USB 监视器观看)。为什么会发生这种情况,我该如何解决?
看起来这段代码是从 VB6 开始的。它 可以 在该语言中工作,但今天遇到了严重的麻烦。两个 [DllImport] 声明都是错误的。
您让本机 HolderName() 函数修改字符串的内容。这是非法的,.NET 中的字符串是不可变的。您 必须 将参数声明为 StringBuilder。并在拨打电话之前将其容量设置得足够高。请注意这是一个有风险的功能,您不能告诉它避免写入超出分配的容量。
当它破坏 GC 堆时,调试起来非常麻烦。
Photo() 的问题在于它的参数 实际上 byte[],没有引用。倾向于偶然工作,一种非常常见的事故。但最大的问题是 pinvoke 编组器不知道数组需要固定。当垃圾收集器在 Photo() 为 运行 时运行时,它会抖动地垫并将数组移动到其他地方。 Photo() 不知道并继续使用旧地址。
当它破坏 GC 堆时,调试起来非常麻烦。
否则,没有什么奇怪的理由可以在 VB.NET 中工作,但不能在 C# 中工作。我怀疑框架更改是更好的解释。但一个必要的起点当然是消除错误,这种腐败问题很难推理。
最后,我回答了我自己的问题。 StringBuilder 就是答案!这是代码...
[DllImport("mykaddll.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern int HolderName([Out] StringBuilder dBuff);
//....
StringBuilder sbBuff = new StringBuilder(200);
res = HolderName(sbBuff);
buf = sbBuff.ToString().Trim();
ShowMsg("HolderName():" + (res == 0 ? "OK:" + buf : "FAIL"));
原来的VB.net,运行完美:
Declare Function HolderName Lib "myCard.dll" (ByVal buf As String) As Integer
Declare Function Photo Lib "myCard.dll" (ByRef photo As Byte) As Integer
...
buff = Space(200) : res = HolderName(buff)
ShowMsg("HolderName():" & IIf(res = 0, "OK:" & Trim(buff), "FAIL"))
photobuf = New Byte(4096) {}
res = Photo(photobuf(0))
ShowMsg("Photo():" & IIf(res = 0, "OK", "FAIL"))
If res = 0 Then
Dim ms As New MemoryStream(photobuf)
picImage.Image = Image.FromStream(ms)
End If
转换后的代码现在在 C# 中(使用 http://converter.telerik.com/)
using System.Runtime.InteropServices;
...
[DllImport("myCard.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern int HolderName(String dBuff);
[DllImport("myCard.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern int Photo(ref byte photo);
//...
buff = new String(' ', 200);
res = HolderName(buff);
// buff remains UNALTERED!
ShowMsg("HolderName():" + (res == 0 ? "OK:" + Strings.Trim(buff) : "FAIL"));
photobuf = new byte[4096];
res = Photo(ref photobuf[0]);
ShowMsg("Photo():" + (res == 0 ? "OK" : "FAIL"));
// photobuf successfully receives the data bytes from Photo function
if (res == 0)
{
MemoryStream ms = new MemoryStream(photobuf);
picImage.Image = Image.FromStream(ms);
}
问题是 buff
保持不变,即使 HolderName
函数实际上 returns 一些值(使用 USB 监视器观看)。为什么会发生这种情况,我该如何解决?
看起来这段代码是从 VB6 开始的。它 可以 在该语言中工作,但今天遇到了严重的麻烦。两个 [DllImport] 声明都是错误的。
您让本机 HolderName() 函数修改字符串的内容。这是非法的,.NET 中的字符串是不可变的。您 必须 将参数声明为 StringBuilder。并在拨打电话之前将其容量设置得足够高。请注意这是一个有风险的功能,您不能告诉它避免写入超出分配的容量。
当它破坏 GC 堆时,调试起来非常麻烦。
Photo() 的问题在于它的参数 实际上 byte[],没有引用。倾向于偶然工作,一种非常常见的事故。但最大的问题是 pinvoke 编组器不知道数组需要固定。当垃圾收集器在 Photo() 为 运行 时运行时,它会抖动地垫并将数组移动到其他地方。 Photo() 不知道并继续使用旧地址。
当它破坏 GC 堆时,调试起来非常麻烦。
否则,没有什么奇怪的理由可以在 VB.NET 中工作,但不能在 C# 中工作。我怀疑框架更改是更好的解释。但一个必要的起点当然是消除错误,这种腐败问题很难推理。
最后,我回答了我自己的问题。 StringBuilder 就是答案!这是代码...
[DllImport("mykaddll.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern int HolderName([Out] StringBuilder dBuff);
//....
StringBuilder sbBuff = new StringBuilder(200);
res = HolderName(sbBuff);
buf = sbBuff.ToString().Trim();
ShowMsg("HolderName():" + (res == 0 ? "OK:" + buf : "FAIL"));