Translating C# structure to C++
-
I have a structure in C# which is read using a BinaryReader like so:
binaryReader.ReadInt32();
binaryReader.ReadInt32();
binaryReader.ReadString();
binaryReader.ReadString();I need to be able to send this structure from a C++ app, I have managed to send across the two ints and I realise that the strings have a length marker in front of them but I cannot get it to send the string. I am currently using a struct like this:
struct MyData
{
int val1;
int val2;
int strLength1;
LPCTSTR string1;
int strLength2;
LPCTSTR string2;
};This send the ints fine but I get 2 0 length strings. What am I doing wrong?
-
I have a structure in C# which is read using a BinaryReader like so:
binaryReader.ReadInt32();
binaryReader.ReadInt32();
binaryReader.ReadString();
binaryReader.ReadString();I need to be able to send this structure from a C++ app, I have managed to send across the two ints and I realise that the strings have a length marker in front of them but I cannot get it to send the string. I am currently using a struct like this:
struct MyData
{
int val1;
int val2;
int strLength1;
LPCTSTR string1;
int strLength2;
LPCTSTR string2;
};This send the ints fine but I get 2 0 length strings. What am I doing wrong?
One way that works AFAIK is using fixed-length strings, put them in length+chararray on the C/C++ side and in length+array on the managed side, using some Marshal attribute to indicate that the array data has to be there, not just a reference. It is something like
[MarshalAs(UnmanagedType.ByValArray, SizeConst=16)]
BTW: as always, be wary of different character types. :)Luc Pattyn [Forum Guidelines] [My Articles]
Voting for dummies? No thanks. X|
-
I have a structure in C# which is read using a BinaryReader like so:
binaryReader.ReadInt32();
binaryReader.ReadInt32();
binaryReader.ReadString();
binaryReader.ReadString();I need to be able to send this structure from a C++ app, I have managed to send across the two ints and I realise that the strings have a length marker in front of them but I cannot get it to send the string. I am currently using a struct like this:
struct MyData
{
int val1;
int val2;
int strLength1;
LPCTSTR string1;
int strLength2;
LPCTSTR string2;
};This send the ints fine but I get 2 0 length strings. What am I doing wrong?
At a guess I'd day you need two
short
s for your string lengths or possibly even twoBYTE
s. If C# strings are a development of BSTRs then I doubt the string lengths will be as much as the 4 bytes you get with anint
. 4GB long strings are really not what MS want to be supporting I guess. The other thing is you need the character data itself effectively in the structure rather than pointers to the characters (LPCTSTR). You want something like this.struct MyData { int val1; int val2; unsigned short strLength1; TCHAR string1[strLength1]; unsigned short strLength2; TCHAR string2[strLength2]; };
but of course you can't do that directly as strLength1 and strLength2 are not known at compile time. This means you're likely going to have to use some form of serialization/deserilaization rather then just passing a structure unless you can use fixed length strings."The secret of happiness is freedom, and the secret of freedom, courage." Thucydides (B.C. 460-400)
-
At a guess I'd day you need two
short
s for your string lengths or possibly even twoBYTE
s. If C# strings are a development of BSTRs then I doubt the string lengths will be as much as the 4 bytes you get with anint
. 4GB long strings are really not what MS want to be supporting I guess. The other thing is you need the character data itself effectively in the structure rather than pointers to the characters (LPCTSTR). You want something like this.struct MyData { int val1; int val2; unsigned short strLength1; TCHAR string1[strLength1]; unsigned short strLength2; TCHAR string2[strLength2]; };
but of course you can't do that directly as strLength1 and strLength2 are not known at compile time. This means you're likely going to have to use some form of serialization/deserilaization rather then just passing a structure unless you can use fixed length strings."The secret of happiness is freedom, and the secret of freedom, courage." Thucydides (B.C. 460-400)
Thanks, I thought I would end up doing some serialization. I have checked the BinaryWriter documentation and it states
This method first writes the length of the string as a four-byte unsigned integer, and then writes that many characters to the stream. This method writes a length-prefixed string to this stream using the BinaryWriter instance's current Encoding.
So it seems it does need a 4-bytes uint to prefix the length. So my next question is how would I create a byte array containing the strings and the lengths? (C++ is not my strong point!), I know how to create the array using malloc and copy the strings in but not the ints.
-
Thanks, I thought I would end up doing some serialization. I have checked the BinaryWriter documentation and it states
This method first writes the length of the string as a four-byte unsigned integer, and then writes that many characters to the stream. This method writes a length-prefixed string to this stream using the BinaryWriter instance's current Encoding.
So it seems it does need a 4-bytes uint to prefix the length. So my next question is how would I create a byte array containing the strings and the lengths? (C++ is not my strong point!), I know how to create the array using malloc and copy the strings in but not the ints.
Yep, I'd say a malloc, or more properly, BYTE* pBuffer = new BYTE[uBufferSize]; is the way to go. Once you've got your buffer you write the strings in by casting a copy of pBuffer + n to a TCHAR* and copy your ints in by casting pBuffer + n to an int* and setting its value.
int* pFirstInt = reinterpret_cast<int*>(pBuffer + 0); *pFirstInt = nValue; int* pSecondInt = reinterpret_cast<int*>(pBuffer + 4); *SecondInt = nValue2;
It's not pretty but then this sort of stuff seldom is. You could create some struct types and cast to those. Up to you really. There are almost certainly fancier ways to do this with operator << overloading and stl string stream modifiers but I wouldn't go there unless you've got a lot of complex data to transfer and you know your stl."The secret of happiness is freedom, and the secret of freedom, courage." Thucydides (B.C. 460-400)
-
Yep, I'd say a malloc, or more properly, BYTE* pBuffer = new BYTE[uBufferSize]; is the way to go. Once you've got your buffer you write the strings in by casting a copy of pBuffer + n to a TCHAR* and copy your ints in by casting pBuffer + n to an int* and setting its value.
int* pFirstInt = reinterpret_cast<int*>(pBuffer + 0); *pFirstInt = nValue; int* pSecondInt = reinterpret_cast<int*>(pBuffer + 4); *SecondInt = nValue2;
It's not pretty but then this sort of stuff seldom is. You could create some struct types and cast to those. Up to you really. There are almost certainly fancier ways to do this with operator << overloading and stl string stream modifiers but I wouldn't go there unless you've got a lot of complex data to transfer and you know your stl."The secret of happiness is freedom, and the secret of freedom, courage." Thucydides (B.C. 460-400)
Thanks for the tip, that worked for the ints perfectly but still not getting the strings. My code now is:
int* pFirstValue = reinterpret_cast<int*>(pBuffer + 0); // First integer
int* pSecondValue = reinterpret_cast<int*>(pBuffer + 4); // Second integer
unsigned int* pStringLength1 = reinterpret_cast(pBuffer + 8); // First string length marker
unsigned int* pStringLength2 = reinterpret_cast(pBuffer + 12 + (sizeof(WCHAR) * firststring)); // Second string length marker*pFirstValue = 1;
*pSecondValue = 2;
*pStringLength1 = strlen(firststring);
*pStringLength2 = strlen(secondstring);strcpy((char*)(pBuffer + 12), firststring);
strcpy((char*)(pBuffer + 16 + (sizeof(WCHAR) * firststring)), secondstring);That appears to me to be correct but as I've said before, C++ is not my strong point. Does that look correct?
-
Thanks for the tip, that worked for the ints perfectly but still not getting the strings. My code now is:
int* pFirstValue = reinterpret_cast<int*>(pBuffer + 0); // First integer
int* pSecondValue = reinterpret_cast<int*>(pBuffer + 4); // Second integer
unsigned int* pStringLength1 = reinterpret_cast(pBuffer + 8); // First string length marker
unsigned int* pStringLength2 = reinterpret_cast(pBuffer + 12 + (sizeof(WCHAR) * firststring)); // Second string length marker*pFirstValue = 1;
*pSecondValue = 2;
*pStringLength1 = strlen(firststring);
*pStringLength2 = strlen(secondstring);strcpy((char*)(pBuffer + 12), firststring);
strcpy((char*)(pBuffer + 16 + (sizeof(WCHAR) * firststring)), secondstring);That appears to me to be correct but as I've said before, C++ is not my strong point. Does that look correct?
This won't solve your marshaling problem, but: You can't use strcpy, or TCHAR. All your strings are wchar_t in C# so you should be using only wide character functions and types. Mark
Mark Salsbery Microsoft MVP - Visual C++ :java: