Reputation: 36279
I have a little piece of a library that I would like to write a .NET wrapper for. At the moment, I'm using P/Invoke, but since I don't have the library's source code or a whole lot of C knowledge, I'm having a difficult time with marshaling. It works so far (sort of), but it feels like a hack.
C Signatures
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);
Essentially, what this does is takes the SMS_MSG_DATA
struct and outputs it to a binary format in the msg_buf
byte array. The initial value of msg_buf_len
is the size of the byte array, but when the encoding completes, it is set to the number of bytes actually filled.
How can a C++/CLI wrapper make this process any easier and cleaner?
Upvotes: 0
Views: 367
Reputation: 74702
This is perfectly reasonable P/Invoke code, though you should make sure that you are not passing Unicode around (check your struct defn.), because all your native declarations seem to take ANSI strings.
C++/CLI doesn't really help you too much here - the place where it makes your life easier is when you want to write some blocks of native code, and make the interface to the C# part simpler. The only thing you could do here, is if on the C# side you really only cared about 1-2 params, you could have the C++/CLI DLL fill out the rest for you and not worry about as much ugly code on the C# side
Upvotes: 1
Reputation: 755587
C++/CLI can make this easier because you don't have to write a PInvoke definition. Instead you can just use the original native SMS_MSG_DATA
structure directly. You are free to write a better looking wrapper structure which is internally converted to SMS_MSG_DATA
. This wrapper structure need not have any ugly PInvoke declaration and can be much more in lines with managed guidelines.
Upvotes: 0