Mimick C++ nested structs with union in C# - c#

I know this question has been asked many times before, and I've tried to read through all the previous questions without much luck.
I am trying to convert the following C++ struct to C#, for use with socket communication.
enum class packet_type
{
read_mem,
get_base_addr,
get_pid,
completed
};
struct copy_mem
{
unsigned int dest_process_id;
unsigned long long dest_address;
unsigned int src_process_id;
unsigned long long src_address;
unsigned int size;
};
struct get_base_addr
{
unsigned int process_id;
};
struct get_pid
{
size_t len;
wchar_t name[256];
};
struct completed
{
unsigned long long result;
};
struct PacketHeader
{
//uint32_t magic;
packet_type type;
};
struct Packet
{
PacketHeader header;
union
{
copy_mem copy_memory;
get_base_addr get_base_address;
get_pid get_pid;
completed completed;
} data;
};
And this is my current C# implementation
public enum PacketType
{
read_mem = 0,
get_base_addr = 1,
get_pid = 2,
completed = 3
}
[StructLayout(LayoutKind.Sequential)]
public struct PacketHeader
{
public PacketType type;
}
[StructLayout(LayoutKind.Sequential)]
public struct get_base_addr
{
uint process_id;
};
[StructLayout(LayoutKind.Sequential)]
public struct get_pid
{
public ulong len;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string name;
}
[StructLayout(LayoutKind.Sequential)]
public struct copy_mem
{
public uint dest_process_id;
public ulong dest_address;
public uint src_process_id;
public ulong src_address;
public uint size;
}
[StructLayout(LayoutKind.Sequential)]
public struct completed
{
public ulong result;
};
[StructLayout(LayoutKind.Explicit, Pack = 0, CharSet = CharSet.Unicode)]
public struct Packet
{
[FieldOffset(0)] //
public PacketHeader header;
[FieldOffset(4)]
public copy_mem CopyMem; //28
[FieldOffset(32)]
public get_base_addr GetBaseAddress;
[FieldOffset(36)]
public get_pid GetPid;
[FieldOffset(300)]
public completed Completed;
}
I am then using this method to convert the struct to a byte array for the socket transmission:
public static byte[] RawSerialize(T item)
{
int rawSize = Marshal.SizeOf(typeof(T));
IntPtr buffer = Marshal.AllocHGlobal(rawSize);
var a = Marshal.SizeOf(item);
var b = Marshal.SizeOf(buffer);
Marshal.StructureToPtr(item, buffer, false);
byte[] rawData = new byte[rawSize];
Marshal.Copy(buffer, rawData, 0, rawSize);
Marshal.FreeHGlobal(buffer);
return rawData;
}
The issue is that var a = Marshal.SizeOf(item); reports a size of 312, but the actual struct should be 528 bytes when I do sizeof(Packet) in C++

Your assumptions seem to be wrong. First of all, the wchar_t type may have different lengths on different machines. On mine, an x64 Linux box, it's 4 byte - that alone makes get_pid a 1032 byte sized struct. You might be interested in using a char16_t or char32_t type instead (see e.g. here).
Since the union in Packet overlaps all fields, this also makes Packet a 1040 byte-sized struct: 4 bytes for PacketHeader, 1032 bytes for get_pid - which is the "longest" struct in there by far - and 4 bytes for padding. Padding, sadly, is platform specific.
To get rid of padding from the C/C++ compiler, you'd need to use attributes such as GCC's __attribute__ ((packed)) or Visual C++'s #pragma pack(1) (see e.g. this SO answer).
Careful though, the field offsets in C# are wrong as well: Except for the header, all field offsets in Packet have to be [FieldOffset(4)] - since in C++ it's a union that starts at byte 4 (assuming zero padding).
For portability, also be aware that an unsigned long long is platform specific as well and that the only guarantee for it is to be at least 64 bit long. If you need exactly 64 bit, you may want to use uint64_t instead (see e.g. here).
Here's the code I used to determine sizes (Linux x64, GCC 9.3):
int main() {
std::cout << "packet_type: " << sizeof(packet_type) << std::endl;
std::cout << "copy_mem: " << sizeof(copy_mem) << std::endl;
std::cout << "get_base_addr: " << sizeof(get_base_addr) << std::endl;
std::cout << "get_pid: " << sizeof(get_pid) << std::endl;
std::cout << "completed: " << sizeof(completed) << std::endl;
std::cout << "PacketHeader: " << sizeof(PacketHeader) << std::endl;
std::cout << "Packet: " << sizeof(Packet) << std::endl;
std::cout << "wchar_t: " << sizeof(wchar_t) << std::endl;
return 0;
}
With padding (default structs):
packet_type: 4
copy_mem: 40
get_base_addr: 4
get_pid: 1032
completed: 8
PacketHeader: 4
Packet: 1040
wchar_t: 4
No padding (__attribute__ ((packed))):
packet_type: 4
copy_mem: 28
get_base_addr: 4
get_pid: 1032
completed: 8
PacketHeader: 4
Packet: 1036
wchar_t: 4
As was pointed out in the comments, setting the Packet struct's GetPid field to [FieldAlign(4)] will result in the following runtime error:
Unhandled exception. System.TypeLoadException: Could not load type 'Packet' from assembly 'StructSize, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 4 that is incorrectly aligned or overlapped by a non-object field.
One way to work around this is to define the get_pid struct like so:
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public unsafe struct get_pid
{
public ulong len;
public fixed byte name[256];
}
This is still assuming that the name string is 128 characters long, each of which is a 2-byte Unicode. In doing so, the name property is now of type byte*. To get back the string, the following two methods should work:
public static unsafe string GetName(get_pid gp) =>
new string((sbyte*) gp.name, 0, 256, Encoding.Unicode);
public static unsafe string GetName(get_pid gp) =>
Marshal.PtrToStringUni(new IntPtr(gp.name), 256);

Related

How to write a C++ wrapper of managed C# dll having ref string as its parameter

I am writing wrappers using C++/CLR. The managed C# class has a function signature as below
//C#
int WriteToInstrument(string command, ref string response, int stage);
I have to write a C++ wrapper to this function in something like the following signature
//C++
int WriteToInstrumentWrap(const char * command, char * response, int stage);
My question is: how can I handle the conversion from "ref string" in C# to char* in C++? Or how can I handle the situation that requires to take a ref string from C# that can be used in C/C++? Many thanks in advance.
I'll add some examples of code I've written this morning. In general, when speaking of returning objects (in the broad meaning where even a char* string is an object), the big questions in C/C++ are:
Who allocates the memory
How many elements are needed
How is the memory allocated (which allocator is used)
And as a corollary, how the memory must be freed
One last optional question is if the memory must be really freed: a method could return a pointer to an internal object that has a lifetime equal to the lifetime of the program and that mustn't be freed. For example:
const char* Message()
{
return "OK";
}
You mustn't free the memory returned by Message()!
This questions get even more complex when you are writing a library (a dll) that will be used by other programs: the malloc and the new that are used in a dll can be different/distinct from the malloc and the new used by the main program (or by another dll), so that you shouldn't free with your (main program) free the memory that is malloc(ed) by a dll.
There are three possible solutions to this particular problem:
Use a shared allocator, for example one given by the OS. Windows gives LocalAlloc and CoTaskMemAlloc. They are even accessible from .NET (Marshal.AllocHGlobal and Marshal.AllocCoTaskMem). In this way the main application can free the memory allocated by the dll
The API of your dll has a Free() method that must be used to free the memory allocated by the dll
The API of your dll has some methods like SetAllocator(void *(*allocator)(size_t)) and SetFree(void (*free)(void*)), so methods that store a function pointer, that the main application can use to set the allocator and free to be used by the dll, so that they are shared between the main application and the dll. The dll will use those allocators. Note that SetAllocator(malloc); SetFree(free) if done by the main application is perfectly legal: now the dll will use the main application's malloc, and not the dll's malloc!
Shortcut used in some example I'll give: the method has as a parameter the allocator (a function pointer) that will then be used
As an important sidenote: we are in 2018. It is at least 15 years that you should have forgotten of char* for strings in C for Windows. Use wchar_t. Always.
And finally some code :-)
Now... given (C# code):
int WriteToInstrument(string command, ref string response, int stage)
{
response = "The quick brown fox jumps over the lazy dog";
return 0;
}
Simple method that calls WriteToInstrument and then copies the response result to an ansi string (char*). The buffer is allocated by the caller, and is of size length. After the method is executed, length contains the number of characters used (including the terminating \0). The response is always \0 terminated. The problem here is that the response could get truncated and/or the caller could allocate a buffer too much big (that won't really protect it from the truncation problem, if it is unlucky :-) ). I'll repeat myself here: using char* for strings in 2018 is ancient technology.
// Utility method to copy a unicode string to a fixed size buffer
size_t Utf16ToAnsi(const wchar_t *wstr, char *str, size_t length)
{
if (length == 0)
{
return 0;
}
// This whole piece of code can be moved to a method
size_t length2 = WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, (int)length, nullptr, nullptr);
// WideCharToMultiByte will try to write up to *length characters, but
// if the buffer is too much small, it will return 0,
// **and the tring won't be 0-terminated**
if (length2 != 0)
{
return length2;
}
// Buffer too much small
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
// We add a terminating 0
str[length - 1] = 0;
return length;
}
// Big bad error, shouldn't happen. Return 0 but terminate the string
str[0] = 0;
return 0;
}
Example of use:
char response[16];
size_t length = sizeof(response) / sizeof(char); // useless / sizeof(char) == / 1 by definition
WriteToInstrumentWrap1("cmd1", response, &length, 1);
std::cout << "fixed buffer char[]: " << response << ", used length: " << length << std::endl;
or (using std::vector<>/std::array<>)
//Alternative: std::array<char, 16> response;
std::vector<char> response(16);
size_t length = response.size();
WriteToInstrumentWrap1("cmd1", response.data(), &length, 1);
std::cout << "fixed buffer vector<char>: " << response.data() << ", used length: " << length << std::endl;
Simple method that calls WriteToInstrument and then copies the response result to an unicode string (wchar_t*). The buffer is allocated by the caller, and is of size length. After the method is executed, length contains the number of characters used (including the terminating \0). The response is always \0 terminated.
// in input length is the size of response, in output the number of characters (not bytes!) written to response
// (INCLUDING THE \0!). The string is always correctly terminated.
int WriteToInstrumentWrap2(const wchar_t *command, wchar_t *response, size_t *length, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
*length = (size_t)str2->Length < *length ? str2->Length : *length - 1;
memcpy(response, pch, *length * sizeof(wchar_t));
response[*length] = '\0';
*length++;
return res;
}
Example of use:
wchar_t response[16];
size_t length = sizeof(response) / sizeof(wchar_t);
WriteToInstrumentWrap2(L"cmd1", response, &length, 1);
std::wcout << L"fixed buffer wchar_t[]: " << response << L", used length: " << length << std::endl;
or (using std::vector<>/std::array<char, 16>)
//Alternative: std::array<wchar_t, 16> response;
std::vector<wchar_t> response(16);
size_t length = response.size();
WriteToInstrumentWrap2(L"cmd1", response.data(), &length, 1);
std::wcout << L"fixed buffer vector<wchar_t>: " << response.data() << ", used length: " << length << std::endl;
All the next examples will use char instead of wchar_t. It is quite easy to convert them. I'll repeat myself here: using char* for strings in 2018 is ancient technology. It is like using ArrayList instead of List<>
Simple method that calls WriteToInstrument, allocates the response buffer using CoTaskMemAlloc and copies the result to an ansi string (char*). The caller must CoTaskMemFree the allocated memory. The response is always \0 terminated.
// Memory allocated with CoTaskMemAlloc. Remember to CoTaskMemFree!
int WriteToInstrumentWrap3(const char *command, char **response, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
// length includes the terminating \0
size_t length = WideCharToMultiByte(CP_ACP, 0, pch, -1, nullptr, 0, nullptr, nullptr);
*response = (char*)CoTaskMemAlloc(length * sizeof(char));
WideCharToMultiByte(CP_ACP, 0, pch, -1, *response, length, nullptr, nullptr);
return res;
}
Example of use:
char *response;
WriteToInstrumentWrap3("cmd1", &response, 1);
std::cout << "CoTaskMemFree char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Must free with CoTaskMemFree!
CoTaskMemFree(response);
Simple method that calls WriteToInstrument, allocates the response buffer using a "private" "library" allocator and copies the result to an ansi string (char*). The caller must use the library deallocator MyLibraryFree to free the allocated memory. The response is always \0 terminated.
// Free method used by users of the library
void MyLibraryFree(void *p)
{
free(p);
}
// The memory is allocated through a proprietary allocator of the library. Use MyLibraryFree() to free it.
int WriteToInstrumentWrap4(const char *command, char **response, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
// length includes the terminating \0
size_t length = WideCharToMultiByte(CP_ACP, 0, pch, -1, nullptr, 0, nullptr, nullptr);
*response = (char*)malloc(length);
WideCharToMultiByte(CP_ACP, 0, pch, -1, *response, length, nullptr, nullptr);
return res;
}
Example of use:
char *response;
WriteToInstrumentWrap4("cmd1", &response, 1);
std::cout << "Simple MyLibraryFree char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Must free with the MyLibraryFree() method
MyLibraryFree(response);
Simple method that calls WriteToInstrument, allocates the response buffer using a settable (through the SetLibraryAllocator/SetLibraryFree methods) allocator (there is a default that is used if no special allocator is selected) and copies the result to an ansi string (char*). The caller must use the library deallocator LibraryFree (that uses the allocator selected by SetLibraryFree) to free the allocated memory or if it has setted a different allocator, it can directly use that deallocator. The response is always \0 terminated.
void *(*libraryAllocator)(size_t length) = malloc;
void (*libraryFree)(void *p) = free;
// Free method used by library
void SetLibraryAllocator(void *(*allocator)(size_t length))
{
libraryAllocator = allocator;
}
// Free method used by library
void SetLibraryFree(void (*free)(void *p))
{
libraryFree = free;
}
// Free method used by library
void LibraryFree(void *p)
{
libraryFree(p);
}
// The memory is allocated through the allocator specified by SetLibraryAllocator (default the malloc of the dll)
// You can use LibraryFree to free it, or change the SetLibraryAllocator and the SetLibraryFree with an allocator
// of your choosing and then use your free.
int WriteToInstrumentWrap5(const char *command, char **response, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
// length includes the terminating \0
size_t length = WideCharToMultiByte(CP_ACP, 0, pch, -1, nullptr, 0, nullptr, nullptr);
*response = (char*)libraryAllocator(length);
WideCharToMultiByte(CP_ACP, 0, pch, -1, *response, length, nullptr, nullptr);
return res;
}
Example of use:
void* MyLocalAlloc(size_t size)
{
return LocalAlloc(0, size);
}
void MyLocalFree(void *p)
{
LocalFree(p);
}
and then:
// Using the main program malloc/free
SetLibraryAllocator(malloc);
SetLibraryFree(free);
char *response;
WriteToInstrumentWrap5("cmd1", &response, 1);
std::cout << "SetLibraryAllocator(malloc) char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Here I'm using the main program free, because the allocator has been set to malloc
free(response);
or
// Using the Windows LocalAlloc/LocalFree. Note that we need to use an intermediate method to call them because
// they have a different signature (stdcall instead of cdecl and an additional parameter for LocalAlloc)
SetLibraryAllocator(MyLocalAlloc);
SetLibraryFree(MyLocalFree);
char *response;
WriteToInstrumentWrap5("cmd1", &response, 1);
std::cout << "SetLibraryAllocator(LocalAlloc) char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Here I'm using diretly the Windows API LocalFree
LocalFree(response);
More complex method that calls WriteToInstrument but has as a parameter an allocator that will be used to allocate the response buffer. There is an addition parameter par that will be passed to the allocator. The method then will copy the result as an ansi string (char*). The caller must free the memory using a specific deallocator based on the allocator used. The response is always \0 terminated.
// allocator is a function that will be used for allocating the memory. par will be passed as a parameter to allocator(length, par)
// the length of allocator is in number of elements, *not in bytes!*
int WriteToInstrumentWrap6(const char *command, char **response, char *(*allocator)(size_t length, void *par), void *par, int stage)
{
auto str1 = gcnew String(command);
String ^str2 = nullptr;
int res = WriteToInstrument(str1, str2, 5);
pin_ptr<const Char> ppchar = PtrToStringChars(str2);
const wchar_t *pch = const_cast<wchar_t*>(ppchar);
// length includes the terminating \0
size_t length = WideCharToMultiByte(CP_ACP, 0, pch, -1, nullptr, 0, nullptr, nullptr);
*response = allocator(length, par);
WideCharToMultiByte(CP_ACP, 0, pch, -1, *response, length, nullptr, nullptr);
return res;
}
Examples of use (multiple allocator showed: vector<>, malloc, new[], unique_ptr<>):
Note the use of the par parameter.
template<typename T>
T* vector_allocator(size_t length, void *par)
{
std::vector<T> *pvector = static_cast<std::vector<T>*>(par);
pvector->resize(length);
return pvector->data();
}
template<typename T>
T* malloc_allocator(size_t length, void *par)
{
return (T*)malloc(length * sizeof(T));
}
template<typename T>
T* new_allocator(size_t length, void *par)
{
return new T[length];
}
template<typename T>
T* uniqueptr_allocator(size_t length, void *par)
{
std::unique_ptr<T[]> *pp = static_cast<std::unique_ptr<T[]>*>(par);
pp->reset(new T[length]);
return pp->get();
}
and then (note the fact that sometimes one of the parameter passed to WriteToInstrumentWrap6 is useless because we already have a pointer to the buffer):
{
std::vector<char> response;
char *useless;
WriteToInstrumentWrap6("cmd1", &useless, vector_allocator<char>, &response, 1);
std::cout << "vector char: " << response.data() << ", used length: " << response.size() << std::endl;
// The memory is automatically freed by std::vector<>
}
{
char *response;
WriteToInstrumentWrap6("cmd1", &response, malloc_allocator<char>, nullptr, 1);
std::cout << "malloc char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Must free with free
free(response);
}
{
char *response;
WriteToInstrumentWrap6("cmd1", &response, new_allocator<char>, nullptr, 1);
std::cout << "new[] char: " << response << ", used length: " << strlen(response) + 1 << std::endl;
// Must free with delete[]
delete[] response;
}
{
std::unique_ptr<char[]> response;
char *useless;
WriteToInstrumentWrap6("cmd1", &useless, uniqueptr_allocator<char>, &response, 1);
std::cout << "unique_ptr<> char: " << response.get() << ", used length: " << strlen(response.get()) + 1 << std::endl;
// The memory is automatically freed by std::unique_ptr<>
}
In a high level overflow, you need C++/CLI (C++ that is using managed .NET code)
OK, you take a handle of type System::String (.NET) and get it's length property. Use that value to allocate a new buffer of size + 2 chars using malloc and memset to zero it out. lock the string, copy its contents and unlock it again.
There is a conversion operator to go from System::String ^ to MFC's CString, if that helps. It will make the code a single liner
Yes. But again,
CString unmanaged = CString(System::String ^) does all that for you.

Creating a managed structure for data

Last night I was working on cleaning up some code I found that was a port of an old game I used to play. One of the tricks I used to clean up data was to get rid of the home-brew DataOffsetAttribute that was made for a struct and just make it a plain jane struct and then I can (later) convert it to something a little more useful. Kind of like a person would do with a DataLayer. This worked really good for fixed sized data from a file. Using this method I was about to convert between the two "data types".
public static byte[] ToByteArray<T>(this T dataStructure) where T : struct
{
int size = Marshal.SizeOf(dataStructure);
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(dataStructure, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
return arr;
}
public static T MarshalAs<T>(this byte[] rawDataStructure) where T : struct
{
var type = typeof(T);
int size = Marshal.SizeOf(type);
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(rawDataStructure, 0, ptr, size);
T structure = (T)Marshal.PtrToStructure(ptr, type);
Marshal.FreeHGlobal(ptr);
return structure;
}
So then I started to wonder if this would work on another project I worked on a long time ago where the data was variable. Here is what I was hoping my data structure would look like
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct RfidReaderResponse
{
public byte PreambleA;
public byte PreambleB;
public byte Length;
public byte LengthLRC;
public ushort ReaderId;
public byte CommandId;
public byte ErrorCode;
public byte[] Data;
public byte LRC;
}
I would probably combine the preamble bytes into a ushort and check if it is a specific value... but that is a different discussion. I have 3 known good responses that I used for testing back in the day. I put those into linqpad as well as my hopeful datastructure. So here is what I am currently using for testing
void Main()
{
var readerResponses = new string[]
{
//data is null because of error EC
"AA-BB-05-05-02-39-0C-EC-21",
//data is 44-00
"AA-BB-07-07-02-39-0C-00-44-00-8B",
//data is 44-00-20-04-13-5E-1A-A4-33-80
"AA-BB-0F-0F-02-39-10-00-44-00-20-04-13-5E-1A-A4-33-80-FB",
};
readerResponses
.Select(x=> x.ToByteArray().MarshalAs<RfidReaderResponse>())
.Dump();
}
now if I comment out the last two fields of the struct I get back what I expect for the first part of the response, but I am just lost on how to get back the data portion. I would prefer to have it as I have it with some magical attribute that the Marshaler understands but so far I can't figure it out. I have tried
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct RfidReaderResponse
{
public byte PreambleA;
public byte PreambleB;
public byte Length;
public byte LengthLRC;
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)]
public IntPtr Data;
}
and
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct RfidReaderResponse
{
public byte PreambleA;
public byte PreambleB;
public byte Length;
public byte LengthLRC;
public ushort ReaderId;
public byte CommandId;
public byte ErrorCode;
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_I1)]
public byte[] Data;
public byte LRC;
}
after a few hours of research. Both of which didn't work stating that my method couldn't make a size for my structure. So I dunno. What am I doing wrong?
EDIT
forgot the method for converting hex strings to byte arrays
public static byte[] ToByteArray(this string hexString)
{
hexString = System.Text.RegularExpressions.Regex.Replace(hexString, "[^0-9A-F.]", "").ToUpper();
if (hexString.Length % 2 == 1)
throw new Exception("The binary key cannot have an odd number of digits");
byte[] arr = new byte[hexString.Length >> 1];
for (int i = 0; i < hexString.Length >> 1; ++i)
{
arr[i] = (byte)((GetHexVal(hexString[i << 1]) << 4) + (GetHexVal(hexString[(i << 1) + 1])));
}
return arr;
}
private static int GetHexVal(char hex)
{
int val = (int)hex;
return val - (val < 58 ? 48 : 55);
}

Why does the storage size of a char seem to change?

If I do
char c = 'A';
byte[] b = BitConverter.GetBytes(c);
Length of b is 2.
However, if I have the following struct for interop purposes
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MyStruct
{
int i;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
char[] c;
public int TheInt
{
get { return i; }
set { i = value; }
}
public string TheString
{
get { return new string(c); }
set { c = value.ToCharArray(); }
}
}
then do
MyStruct m = new MyStruct();
m.TheInt = 10;
m.TheString = "Balloons";
int mSize = Marshal.SizeOf(m);
mSize is 12, not 20 as I expected.
MSDN says char storage is 2 bytes.
The first example supports this.
Am I doing something wrong with my struct?
Am I missing something?
Because you are are marshaling, and by default, a char will get marshalled to an ANSI char instead of a Unicode char. So "balloon" is 8 characters, which is 8 bytes when ANSI encoded, plus 4 bytes for your int, which is 12.
If you want the size to be 20 for marshalling, change your StructLayout and set the ChatSet to Unicode:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
Now you will have your struct size as 20.
MSDN says char storage is 2 bytes.
That is true when we are talking about a CLR char, but not in the context of marshalling.
char is 2 bytes or 16-bit Unicode character (U +0000 to U +ffff)
char [] is a pointer type
int is 4 bytes
hence, about marshalling, I would pick vcsjones' answer.

C# structure include byte array and long value

This is My Code to user a long variable with it bytes, but when program runs, Exception Happens and show these:
An unhandled exception of type 'System.TypeLoadException' occurred in Test.exe
Additional information: Could not load type 'Test.MyU32' from assembly 'Test,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an
object field at offset 0 that is incorrectly aligned or overlapped by a non-object
field.
[StructLayout(LayoutKind.Explicit)]
public struct MyU32
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] Bytes;
[FieldOffset(0)]
public long Value;
}
Please help me how to handle it!
Your code case doesn't work because you're overlapping a reference and a value type(a 64 bit int). You can overlap different value types and different references, but you can't mix them.
But even when they work, such low level hacks are usually a bad idea in C#. I recommend using properties which do the transformation instead of low level unions.
Perhaps what you actually want is:
internal static class ByteIntegerConverter
{
public static UInt32 LoadLittleEndian32(byte[] buf, int offset)
{
return
(UInt32)(buf[offset + 0])
| (((UInt32)(buf[offset + 1])) << 8)
| (((UInt32)(buf[offset + 2])) << 16)
| (((UInt32)(buf[offset + 3])) << 24);
}
public static void StoreLittleEndian32(byte[] buf, int offset, UInt32 value)
{
buf[offset + 0] = (byte)value;
buf[offset + 1] = (byte)(value >> 8);
buf[offset + 2] = (byte)(value >> 16);
buf[offset + 3] = (byte)(value >> 24);
}
}
UInt32 value = ByteIntegerConverter.LoadLittleEndian32(buf, offset);
// do something with `value`
ByteIntegerConverter.StoreLittleEndian32(buf, offset, value);
This always uses little endian regardless of the computer's native endianness. If you want native endainness you could check with BitConverter.IsLittleEndian and use different shift constants if it is big endian.
I'm not perfectly sure, but I think the problem is caused by the overlap between a value type and a reference type. It should be possible to overlap only value types. Because if it was possible to overlap value types & reference types, you could change the reference directly. For obvious safety reason, it's not possible.
As byte[] is a reference type (as all arrays in .NET). You can't have Value overlapping Bytes.
If you are used to C, your structure (without the explicit layout) would be "similar" to:
struct MyU32
{
byte* Bytes;
long Value;
}
but it is not similar to:
struct MyU32
{
byte Bytes[4];
long Value;
}
I solve my problem
Tanx to All bodies that put time on it.
public struct MyU32
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] Bytes;
public uint Value
{
get { return ((uint)Bytes[0] + Bytes[1] << 8 + Bytes[2] << 16 + Bytes[3] << 24); }
set
{
Bytes[0] = (byte)(value & 0xFF);
Bytes[1] = (byte)(value>>8 & 0xFF);
Bytes[2] = (byte)(value>>16 & 0xFF);
Bytes[3] = (byte)(value>>24 & 0xFF);
}
}
}

Reading Named Pipe Data sent from a VC++ 6.0 dll into embeded structures in c#

I have an old client side application that is writing to named pipes using a VC 6.0 dll, and I have been asked to write an C# application to read the named pipe and process the request. I am able to receive the data in a byte array, but can't get the data in the pipe to match with the structures i have defined in C#.
old C struct
typedef struct
{
WORD WtYPE;
AB objEmbededStruct1;
BB objEmbededStruct2;
char szString[13];
union
{
char szString1[25];
char szSTring2[45];
char szString3[134];
}
BOOL bExist;
} myStruct1;
typedef struct
{
char szThisString1[2];
int iFlag1;
char szThisString2[11];
}AB;
typedef struct
{
HANDLE hEvents[2];
DWORD dw;
int ithisFlag;
}BB;
I have tried parsing the byte array, but the data is not where I expect it to be. For instance, the first string in the first embedded structure (AB) starts at byte[4] as opposed to byte[2] since a word maps to an unsigned int16. Then the first integer in the AB struct starts at byte[8] as opposed to byte[6]. So, is there a more efficient way to retrieve the data from the pipe and put it into the structure, or is parsing by bytes the correct way? If parsing the bytes is how it should be done, then what am I missing when trying to map where the data should be?
Thanks
after a suggestion from LU RD, i was able to put this solution together:
definition of VC 6 structs:
typedef struct
{
WORD WtYPE;
AB objEmbededStruct1;
BB objEmbededStruct2;
char szString[13];
union
{
char szString1[25];
char szSTring2[45];
char szString3[134];
}
BOOL bExist;
} myStruct1;
typedef struct
{
char szThisString1[2];
int iFlag1;
char szThisString2[11];
}AB;
typedef struct
{
HANDLE hEvents[2];
DWORD dw;
int ithisFlag;
}BB;
I needed to the using statement to the c# code:
using System.Runtime.InteropServices;
The struct definition in c# looks like this:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct RM_CLIENT_DATA
{
public UInt16 wtype;
AB objEmbededStruct1;
BB objEmbededStruct2;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)]
char[] szString;
public Data objMyUnion //this is the structure substituted for the union
public int bExist;
}
//Union struct
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct Data
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = FILE_NAME_LENGTH + 1)]
[FieldOffset(0)]
public char[] szString1
[MarshalAs(UnmanagedType.ByValArray, SizeConst = DOCS_LEN + 1)]
[FieldOffset(0)]
public char[] szString2;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 134)]
[FieldOffset(0)]
public char[] szString3;
}
[structLayout(LayoutKind.Sequential, charset = charSet.Ansi)]
public struct AB
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
char[] szThisString1;
int IFlag1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
char[] szThisString2;
}
[structLayout(LayoutKind.Sequential, charset = charSet.Ansi)]
public struct BB
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public UInt32[] hEvents;
public UInt32 dw;
public int ithisFlag;
}
the code to pull the stream from the named pipe into the struct looks like this:
const int BUFFER_SIZE=4096;
byte[] typeData = new byte[BUFFER_SIZE];
int iMaxData = ioStream.Read(typeData, 0, BUFFER_SIZE);
GCHandle objHandle = new GCHandle();
iMaxData = ioStream.Read(typeData, 0, BUFFER_SIZE); //read the stream
try
{
objHandle = GCHandle.Alloc(typeData, GCHandleType.Pinned);
objData = (RM_CLIENT_DATA)Marshal.PtrToStructure(objHandle.
AddrOfPinnedObject(),typeof(RM_CLIENT_DATA));
}
catch (Exception ex)
{
ErrorCode = -6;
ErrorMessage = string.Format("ReadMessageToGenericStruct: Error: {0}
attempting to move data into RM_CLIENT_DATA struct.", ex.Message);
return bResult;
}
finally
{
objHandle.Free();
}
to use the char[]'s in the structure, I used:
string myWorkString = new string( objData.szString);
to return the data to the pipe -- I reversed the process:
//get the size of the filled structure
int iStructSize = Marshal.SizeOf(objData);
//allocate the byte array to write the structure into
byte[] outBuffer = new byte[ iStructSize];
//create the GCHandle variable
GCHanlde objHandle = new GCHandle();
try{
//allocate a handle for the byte array
objHandle = GCHandle.Alloc(outBuffer, GCHandleType.Pinned);
//move your data to the byte array
Marshal.StructureToPtr( objData, objHandle.AddrOfPinnedObject(), false);
}
catch (Execeptiion ex)
{
//write error message here
}
finally
{
//free the handle
objHandle.Free();
}
//write the byte array to the stream
try
{
ioStream.Write(outBuffer, 0, iStructSize);
}
catch (Exception ex)
{
//write error message here
}
ioStream.Flush();
ioStream.Close();
the following link was a big help, thanks to that author as well!
Mastering c# structs

Categories

Resources