C# C++/你能让这种情况变得容易些吗?

C# C++/你能让这种情况变得容易些吗?,c#,c++-cli,pinvoke,wrapper,C#,C++ Cli,Pinvoke,Wrapper,我有一个库的一小部分,我想为它编写一个.NET包装器。目前,我正在使用P/Invoke,但由于我没有库的源代码或大量的C知识,所以我在封送方面遇到了困难。到目前为止(有点),它还可以工作,但感觉像是一个黑客 C签名 typedef struct { unsigned short sAddress[MAX_ADDRESS_CHAR_LENGTH + 1]; unsigned short sCallback[MAX_CALLBACK_CHAR_LENGTH + 1]; u

我有一个库的一小部分,我想为它编写一个.NET包装器。目前,我正在使用P/Invoke,但由于我没有库的源代码或大量的C知识,所以我在封送方面遇到了困难。到目前为止(有点),它还可以工作,但感觉像是一个黑客

C签名

typedef struct
{
    unsigned short  sAddress[MAX_ADDRESS_CHAR_LENGTH + 1];
    unsigned short  sCallback[MAX_CALLBACK_CHAR_LENGTH + 1];
    unsigned short  sMessage[(MAX_MESSAGE_CHAR_LENGTH + 1) ];
    unsigned short  sSmscAddress[MAX_ADDRESS_CHAR_LENGTH+1];
    unsigned short  sSubject[MAX_SUBJECT_CHAR_LENGTH + 1];
    unsigned char   msgLength;        
    unsigned char   pduType;
    unsigned short  msgRef;
    unsigned char   msgSequence;
    unsigned char   msgTotal;
    EMsgPriority    nPriority;
    struct tm       tTime;
    EncodingType    encoding;
    unsigned char   bReceipt;
    unsigned long   dwDataMask;
    struct tm       tValidity;
    unsigned char   nValidityType;
    unsigned char   bRelativeValidityFlag;
    unsigned char   isDeliveryAck;
} SMS_MSG_DATA;

unsigned short SmsEncodeMessage( SMS_MSG_DATA* sms_msg, unsigned char* msg_buf,
    unsigned short* msg_buf_len );
C#p/Invoke

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SMS_MSG_DATA {
    [MarshalAs(UnmanagedType.ByValTStr,
        SizeConst=SmsEncoding.MAX_ADDRESS_CHAR_LENGTH+1)]
    public string sAddress;

    [MarshalAs(UnmanagedType.ByValTStr,
        SizeConst=SmsEncoding.MAX_CALLBACK_CHAR_LENGTH+1)]
    public string sCallback;

    [MarshalAs(UnmanagedType.ByValTStr,
        SizeConst=SmsEncoding.MAX_MESSAGE_CHAR_LENGTH+1)]
    public string sMessage;

    [MarshalAs(UnmanagedType.ByValTStr,
        SizeConst=SmsEncoding.MAX_ADDRESS_CHAR_LENGTH+1)]
    public string sSmscAddress;

    [MarshalAs(UnmanagedType.ByValTStr,
        SizeConst=SmsEncoding.MAX_SUBJECT_CHAR_LENGTH+1)]
    public string sSubject;

    public byte msgLength;
    public byte pduType;
    public ushort msgRef;
    public byte msgSequence;
    public byte msgTotal;
    public EMsgPriority nPriority;
    public tm tTime;
    public EncodingType encoding;
    public byte bReceipt;
    public long dwDataMask;
    public tm tValidity;
    public byte nValidityType;
    public byte bRelativeValidityFlag;
    public byte isDeliveryAck;
}

[DllImport(Constants.LIB_SMSENCODE)]
public static extern ErrorCode SmsEncodeMessage(ref SMS_MSG_DATA sms_msg,
    byte[] msg_buf, ref short msg_buf_len);
本质上,它的作用是获取
SMS_MSG_DATA
struct并将其输出为
MSG_buf
字节数组中的二进制格式。
msg_buf_len
的初始值是字节数组的大小,但编码完成后,它被设置为实际填充的字节数


C++/CLI包装器如何使此过程更简单、更干净?

C++/CLI可以使此过程更简单,因为您不必编写PInvoke定义。相反,您可以直接使用原始的原生
SMS\u MSG\u DATA
结构。您可以自由编写外观更好的包装器结构,该结构在内部转换为
SMS\u MSG\u DATA
。此包装器结构不需要任何难看的PInvoke声明,并且可以更符合托管准则。

这是完全合理的p/Invoke代码,不过您应该确保您没有传递Unicode(检查您的结构定义),因为所有本机声明似乎都采用ANSI字符串


在这里,C++/CLI并没有给您带来太多帮助—它让您的生活更轻松的地方是,您需要编写一些本机代码块,并简化C#部分的接口。这里唯一可以做的事情是,如果在C端你真的只关心1-2个参数,你可以让C++/CLI DLL为你填充其余的参数,而不用担心C端有那么多丑陋的代码

它可以通过删除属性声明使它更干净,但不要期望太多……在这种情况下,我仍然需要知道哪些托管类型可以转换为
SMS\u MSG\u DATA
struct中的非托管类型,对吗?我现在遇到的问题是,struct声明不完全正确,因此数据未正确封送,导致Encode方法阻塞了某些字段。@David:区别在于,在C++/CLI中,您将自己进行转换(通过强制转换和/或
Encoder
等).I最初在结构上没有
CharSet.Unicode
,但是Encode方法没有正确编码字符串。不过,当我将它改为Unicode时,它工作得很好。我不知道他的原生声明是如何接受ANSI字符串的。例如,
unsigned short sAddress[…]
-注意这里的
short
-在我看来非常像UTF-16字符串!(无法编辑此内容,因此添加新内容)-是的,您的问题肯定是这些字符串的编组。您将它们声明为Unicode,因此它是空间的2倍,因此您将覆盖结构的其余部分。1字符Unicode=2字符ANSI。唯一的选项是ANSI、Auto、None和Unicode。ANSI在编码时工作得很好,但是当我稍后用另一种方法解码它时,字符串变成空的。Unicode被正确地解码为原始字符串。@Pavel-Hmmm,我想你可能是对的,我习惯于将它们视为wchar_t的@David:现在是我破解WinDbg的时候了-在本机函数上设置一个断点,并检查传递给它的结构/参数。当然,如果您不知道WinDbg,这可能太棘手了:(可能附加一个本机VS调试器?(即,只需运行应用程序,然后从DLL的VS项目中“附加”)