我是C#/ .net编程新手。
我正在将以下C#结构从WPF代码编组到非托管C ++ DLL中的C ++类。
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct CallbackParams
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string displayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string userName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string sipIdentity;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string sipProxyAddress;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string password;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string sipurl;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string calleeURI;
[MarshalAs(UnmanagedType.U4)]
public UInt32 releaseCallId;
[MarshalAs(UnmanagedType.U4)]
public UInt32 answerCallId;
[MarshalAs(UnmanagedType.U4)]
public UInt32 answerCode;
[MarshalAs(UnmanagedType.U4)]
public UInt32 timeout;
[MarshalAs(UnmanagedType.U4)]
public UInt32 rate_percent;
}
C ++类看起来像这样
typedef struct CallbackParams_s {
char displayName[80];
char userName[80];
char sipIdentity[80];
char sipProxyAddress[80];
char password[80];
char sipurl[80];
char calleeURI[80];
unsigned int releaseCallId;
unsigned int answerCallId;
unsigned int answerCode;
unsigned int timeout;
unsigned int rate_percent;
} CallbackParams;
在C#代码中
public CallbackParams cb;
public int code;
[DllImport("XXXDll.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern int DLLCBFunc1([MarshalAs(UnmanagedType.I4)] int someCode, ref CallbackParams cbParams);
cb.displayName = "XYZ";
... ...
... ...
...Init other fields in struct ....
...
cb.calleeURI = "ABC";
code = 0;
DLLCBFunc1(code, ref cb);
在上面的调用中,cb结构正确地编组到非托管dll。 现在,
cb.calleeURI = "DEF";
code = 1;
DLLCBFunc1(code, ref cb);
当再次调用DLLCBFunc1时,代码参数在非托管dll中正确编组,但cb.calleeURI仍设置为早于“ABC”而不是“DEF”。
我错过了什么?
感谢您的帮助。
EDIT:
Edited to provide more code
C++ code
Class MyClass {
...
...
public:
void SetCBParams(CallbackParams *cb) { cbParams = cb };
private:
CallbackParams *cbParams;
}
MyClass *m_class;
extern "C" __declspec(dllexport) int DLLCBFunc1(int code, CallbackParams *cb)
{
if(code == 0) {
m_class = new MyClass;
}
m_class->setCBParams(cb);
....
..call some func ...
}
答案 0 :(得分:-1)
<强>答案:强>
看看David Heffernan的评论 - 他似乎更有知识,并且花了很多时间在这上面。
之前的尝试:
然后再经过一些搜索,that should answer your exact question。
如果要编组为char *(基本上与char []相同),则需要使用StringBuilder。
请参阅this completely unrelated example that shows the signature from pinvoke.net。
然后,您应该重新创建您的结构,或者将其内部复制/转换(如果在其他地方也使用)以下内容:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct CallbackParams
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public StringBuilder displayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public StringBuilder userName;
}
另外要小心StringBuilder已经自动完成所有编组操作..也不再需要ref了。实际上,使用ref会导致问题。
cb.displayName = "XYZ";
cb.userName = "ABC";
code = 0;
DLLCBFunc1(code, cb);
我不知道如何将字符串分配给stringbuilders ..可能是你必须要做的
cb.displayName = new StringBuilder("XYZ");
修改强>
大卫·赫弗曼指出......我错过了这一点。 :)
所以...在你的情况下,你可能必须将char [80]声明为Byte [80]数组并手动复制字符串的内容,同时确保考虑可能的unicode-&gt; ansi转换。此外,在通话结束后,您需要复制回来。
您可以找到有关执行here on StackOverflow的一些信息。
修改强>
将答案放在顶部。