2011-04-28 95 views
5

嘿! 我刚开始摆弄pinvoke并遇到问题。我得到了AccessViolationException。首先,有什么方法可以调试或追踪哪个字段导致此错误?唯一写入的是结果结构体。Pinvoke结构编组帮助需要 - System.AccessViolationException

C++的呼叫看起来像:

MyFunc(int var1, _tuchar *var2, _tuchar *var3, _tuchar *var4, MyStruct *Result, 
     _tuchar *var5, _tuchar *var6); 

的C++结构:

typedef struct MyStruct 
{ 
    _tuchar *id; 
    _tuchar *ErrorMessages; 
    int int1; 
    _tuchar language[3]; 
    _tuchar *result; 
    int type; 
    int number; 
    int *type2; 
    _tuchar **blocks; 
} 

C#的结构:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct MyStruct 
{ 
    [MarshalAs(UnmanagedType.LPStr)] 
    public string Id; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst=500)] 
    public char[] ErrorMessages; 

    public int int1; 

    [MarshalAs(UnmanagedType.LPStr)] 
    public string language; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] 
    public char[] result; 

    public int type; 

    public int number; 

    public int type2; 

    [MarshalAs(UnmanagedType.ByValArray)] 
    public string[] blocks; 

C#的方法声明:

[DllImport(MyPath, EntryPoint = "MyEntryPoint", SetLastError = true, 
      CharSet = CharSet.Unicode)] 
internal static extern int MyFunc(int var1, string var2, string var3, 
     string var4, ref MyStruct Result, string var5, string var6); 

C#的召唤:

var result = new MyStruct(); 
MyFunc(0, "var2", "var3", "var4", ref result, "var5", "var6"); 

希望我什么都不会被排除在外。 感谢您的帮助!

+0

“MyFunc”声明在C#中是什么样的? – Justin 2011-04-28 05:18:01

+0

啊我忘了一些东西,谢谢队友^^ – Dashu 2011-04-28 05:21:54

+0

在C++中'int'的大小保证是32位/可以用System.Int32转换吗? System.Int32有一个非常精确的保证 - 即使是跨性别的。 – 2011-04-28 05:47:54

回答

4

Ooooh,man!你已经为你的第一个摆弄经验挑选了一个相当复杂的案例。我建议先做一些简单的事情,然后再转向真正的东西。

首先,CharSet=CharSet.Ansi看起来很可疑。你所有的字符串和字符都是_tuchar,我在那里收集u意味着“Unicode”,不是吗?如果是这样的话,你需要CharSet=CharSet.Unicode

其次,(这是最有可能是罪魁祸首)为什么是ErrorMessages场封送ByValArray?你知道ByVal这里的意思是“按价值”,不是吗?如在,而不是作为参考。你知道C++中的小星号意味着“引用”,不是吗?那么为什么您的参考字段ErrorMessages作为一个按值数组排列?如果你不知道,一个数组通常被认为是在所有内容被传递时“通过值”传递的,而不是仅仅传递一个引用(指针)到存储所有内容的内存位置。在C++结构定义中,指定_tuchar*,意思是“指向某个包含一个或多个_tuchars的内存的引用(指针)”,而在C#中指定[MarshalAs(UnmanagedType.ByValArray, SizeConst=500)],这意味着“500 _tuchars应该在这里,减”。看到引用(指针)通常需要4个字节(或64位机器上的8个字节),而500个unicode字符需要1000个字节,这里显然存在明显的不匹配。

第三第四,同样的观点也适用于resultblocks领域。

第五,则language场正​​好相反的情况:C++代码说“有3个_tuchars这里”,而C#代码表示,“有一个参考(指针)到这里一个字符串”(如果你不“知道,LPStr的意思是‘长指针,字符串’)

最后,你有固定所有这些问题后,我建议你运行你的程序,并打印出通话的结果Marshal.SizeOf(typeof(MyStruct))。在.NET中,这会给你的结构有多大。去C++端打印出sizeof(MyStruct)。这会给你C++认为的大小。

如果他们不同,看看有什么不对。尝试逐个删除字段,直到它们变得相同。这会给你罪魁祸首的领域。与他们合作。

总的来说,我建议你需要更好地理解事情是如何工作的。对于初学者来说,这种情况太复杂了。

祝你好运!

+0

好吧,先生,你是男人:)我非常感谢你的意见。会看看我能否解决这个烂摊子。有一件事我无法真正理解,是C++会写入的字符串......我想如果我发送一个500字符的字符串,那么C++ dll不会写在边界之外。有多大的结果可以限制? – Dashu 2011-04-28 06:09:13

+0

难道是在一个struct中有可写的字符串字段是不可能的吗?或者你知道他们应该如何定义(错误消息和结果)? – Dashu 2011-05-02 16:39:39

0

这是一个位在黑暗中拍摄的,但你有没有试着用MarshalAs(UnmanagedType.LPWStr)装饰字符串参数:

[DllImport(MyPath, EntryPoint = "MyEntryPoint", SetLastError = true, 
    CharSet = CharSet.Unicode)] 
internal static extern int MyFunc(
    int var1, 
    [MarshalAs(UnmanagedType.LPWStr)] 
    string var2, 
    [MarshalAs(UnmanagedType.LPWStr)] 
    string var3, 
    [MarshalAs(UnmanagedType.LPWStr)] 
    string var4, 
    ref MyStruct Result, 
    [MarshalAs(UnmanagedType.LPWStr)] 
    string var5, 
    [MarshalAs(UnmanagedType.LPWStr)] 
    string var6); 

我相信编组选择了弦的BStr_tuchar应扩大到wchar_t默认所以我猜想LPWStr是正确的编组方法(指向宽字符字符串的指针)。


更新:MyStruct各种各样的东西看起来不很正确:

ErrorMessages被标记为ByValArray,所以.NET互操作程序可能是期待MyStruct看起来有点像这样:

typedef struct MyStruct 
{ 
    _tuchar *id; 
    _tuchar ErrorMessages[500]; 
    // Rest of MyStruct 

这可能会导致问题 - result同样的问题。

而且我认为language应该使用ByValArray大小为3

最后blocks或许应该使用LPArray传递是 - ByValArray看起来不正确。

(这是所有主要是凭空猜测顺便说一句 - 我希望这是一个指向你在正确的方向,但我没有有P多少经验/ Invoke的互操作)


另一个更新:MyStruct你声明的字符集是Ansi,但在MyFunc它的Unicode ...是unmanaged DLL与Unicode或Ansi编译?如果它使用Unicode,那么我认为在编组字符串时应该使用LPWStr,而使用Ansi时应该使用LPStr

+0

嗯我会尝试装饰字符串,但这些字符串只能读取,不能写入。我相信问题出现在结果里面,我读过被写入的字符串应该使用stringbuilder,但是你不能在没有得到编组异常的情况下在结构中使用stringbuilder。不知道uni或ansi,有什么方法可以搞清楚吗? – Dashu 2011-04-28 05:41:28

+0

装饰字符串并没有解决这个问题 – Dashu 2011-04-28 05:45:07

+0

@Dashu MyStruct上的一些属性看起来不太正确 - 我更新了我的问题,但被警告我可能不知道我在说什么! :-p – Justin 2011-04-28 05:52:17