将固定长度的字符串从 C# 传递到 dll 时获取 AccessViolationException
Getting AccessViolationException when passing a fixed length string from C# to a dll
我有以下 (VB6?) 代码在 VBA 中完美地用于 Excel。我正在使用的 dll (x.dll) 对我来说是 "black box"。我不知道它是用什么写的,是否不受管理。从历史技术的角度来看,我对此知之甚少。我只知道这个特定的函数在从 Excel VBA 调用时有效,而当我从 C# 调用它时我不能同样地让它起作用,我认为我应该能够。 c.b128 的值再次被 dll 使用和更改。
'In VBA for excel the value inside "c.b128" is changed from
'" 1234567890123456789012345678901234567890123456789012345678901234567890123456789 "
'to
'" 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 123456789 "
VBA Excel 代码
Private Type k128
b128 As String * 128
End Type
Private Declare Function dllSpace Lib "x.dll" (aInfo As Long, _
bVec As Long, cQry As k128, dErr As k128) As Long
Function Space() As Long
Dim c As k128
Dim d As k128
c.b128 = Left(" 1234567890123456789012345678901234567890123456789012345678901234567890123456789", 128)
d.b128 = Left("", 128)
Space = dllSpace(-1, -1, c, d)
End Function
我试图在 .NET 中实现相同的功能,但在到达 "return dllSpace(-1, -1, c, d);" 时出现错误
system.accessviolationexception 类型的未处理异常发生在 [...] 试图读取或写入受保护的内存中。其他内存已损坏
我需要将其转换为 .NET,我得到了一个 AccessViolationException。我到处都读到 StringBuilders 保留的内存可供 C# 中的 dll 访问。我试过“ref StringBuilder” 我试过使用 byte[],我试过使用不安全的描述符,我不明白。另外,如果有一种方法可以让我使用 IDE 查看更多内存中发生的事情,那对我也会有帮助。我可以在本地看到我所有的变量并观察 windows,但我看不到也不知道如何查看有关抛出的异常的更多详细信息。我在 Win7 32 位 OS 机器上使用 Visual Studio Express 2013 for Windows Desktop。
这是我的 C# 代码片段
C# 代码片段
[DllImport(@"x.dll")]
private static extern int dllSpace(int aInfo,
int bVec,
StringBuilder cQry,
StringBuilder dErr);
public int StartTheDataSpace()
{
StringBuilder c = new StringBuilder(128);
StringBuilder d = new StringBuilder(128);
c.Append(" 1234567890123456789012345678901234567890123456789012345678901234567890123456789 ");
return dllSpace(-1, -1, c, d);
}
VBA代码清楚地表明,您所拥有的实际上是一个包含固定长度字符串的结构。这意味着 StringBuilder
是错误的类型。您应该改用:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct k128
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string b128;
}
此外,据我了解,VBA 默认使用 ByRef
。所以 C# 声明应该是:
[DllImport(@"x.dll")]
private static extern int dllSpace(
ref int aInfo,
ref int bVec,
ref k128 cQry,
ref k128 dErr
);
现在,碰巧 ref k128
与容量为 128 的 StringBuilder
编组时具有相同的内存布局,因此您可能会发现切换回更方便:
[DllImport(@"x.dll")]
private static extern int dllSpace(
ref int aInfo,
ref int bVec,
StringBuilder cQry,
StringBuilder dErr
);
我有以下 (VB6?) 代码在 VBA 中完美地用于 Excel。我正在使用的 dll (x.dll) 对我来说是 "black box"。我不知道它是用什么写的,是否不受管理。从历史技术的角度来看,我对此知之甚少。我只知道这个特定的函数在从 Excel VBA 调用时有效,而当我从 C# 调用它时我不能同样地让它起作用,我认为我应该能够。 c.b128 的值再次被 dll 使用和更改。
'In VBA for excel the value inside "c.b128" is changed from
'" 1234567890123456789012345678901234567890123456789012345678901234567890123456789 "
'to
'" 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 123456789 "
VBA Excel 代码
Private Type k128
b128 As String * 128
End Type
Private Declare Function dllSpace Lib "x.dll" (aInfo As Long, _
bVec As Long, cQry As k128, dErr As k128) As Long
Function Space() As Long
Dim c As k128
Dim d As k128
c.b128 = Left(" 1234567890123456789012345678901234567890123456789012345678901234567890123456789", 128)
d.b128 = Left("", 128)
Space = dllSpace(-1, -1, c, d)
End Function
我试图在 .NET 中实现相同的功能,但在到达 "return dllSpace(-1, -1, c, d);" 时出现错误 system.accessviolationexception 类型的未处理异常发生在 [...] 试图读取或写入受保护的内存中。其他内存已损坏
我需要将其转换为 .NET,我得到了一个 AccessViolationException。我到处都读到 StringBuilders 保留的内存可供 C# 中的 dll 访问。我试过“ref StringBuilder” 我试过使用 byte[],我试过使用不安全的描述符,我不明白。另外,如果有一种方法可以让我使用 IDE 查看更多内存中发生的事情,那对我也会有帮助。我可以在本地看到我所有的变量并观察 windows,但我看不到也不知道如何查看有关抛出的异常的更多详细信息。我在 Win7 32 位 OS 机器上使用 Visual Studio Express 2013 for Windows Desktop。
这是我的 C# 代码片段
C# 代码片段
[DllImport(@"x.dll")]
private static extern int dllSpace(int aInfo,
int bVec,
StringBuilder cQry,
StringBuilder dErr);
public int StartTheDataSpace()
{
StringBuilder c = new StringBuilder(128);
StringBuilder d = new StringBuilder(128);
c.Append(" 1234567890123456789012345678901234567890123456789012345678901234567890123456789 ");
return dllSpace(-1, -1, c, d);
}
VBA代码清楚地表明,您所拥有的实际上是一个包含固定长度字符串的结构。这意味着 StringBuilder
是错误的类型。您应该改用:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct k128
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string b128;
}
此外,据我了解,VBA 默认使用 ByRef
。所以 C# 声明应该是:
[DllImport(@"x.dll")]
private static extern int dllSpace(
ref int aInfo,
ref int bVec,
ref k128 cQry,
ref k128 dErr
);
现在,碰巧 ref k128
与容量为 128 的 StringBuilder
编组时具有相同的内存布局,因此您可能会发现切换回更方便:
[DllImport(@"x.dll")]
private static extern int dllSpace(
ref int aInfo,
ref int bVec,
StringBuilder cQry,
StringBuilder dErr
);