0

I am just trying to send packets back and forth between my two apps but my strings aren't getting through in c++. here's what I'm doing in c#

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Size=32)]
public struct Packet
{
    public uint packet_type;
    [MarshalAs(UnmanagedType.LPWStr, SizeConst = 8)]
    public string file_name;
    [MarshalAs(UnmanagedType.LPWStr, SizeConst = 8)]
    public string template_name;
    [MarshalAs(UnmanagedType.LPWStr, SizeConst = 8)]
    public string file_name_list;
    [MarshalAs(UnmanagedType.LPWStr, SizeConst = 8)]
    public string file_buffer;
}
var data = new Packet
{
    packet_type = (uint)action,
    file_name = fileName + Char.MinValue,
    file_name_list = "" + Char.MinValue,
    template_name = "" + Char.MinValue
};
byte[] buffer = new byte[Marshal.SizeOf(typeof(Packet))];
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
Marshal.StructureToPtr(data, handle.AddrOfPinnedObject(), false);
handle.Free();
var bytesSent = _client.Client.Send(buffer);
byte[] buffer = new byte[Marshal.SizeOf(typeof(Packet))];
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
Marshal.StructureToPtr(data, handle.AddrOfPinnedObject(), false);
handle.Free();
var bytesSent = _client.Client.Send(buffer);

and here's what I got in c++

struct Packet {

unsigned int packet_type;
char* file_name;
char* template_name;
char* file_name_list;
char* file_data;

void serialize(char * data) {
    memcpy(data, this, sizeof(Packet));
}

void deserialize(char * data) {
    memcpy(this, data, sizeof(Packet));
}
};

char network_data[MAX_PACKET_SIZE];
recv(curSocket, buffer, MAX_PACKET_SIZE, 0);

The only value that seems to work is the packet_type which is the first one in the struct. that one always comes through. What am I missing?

jacobsgriffith
  • 1,448
  • 13
  • 18

3 Answers3

1

Even though I never tried such approach, I think you cannot simply share data between 2 distinct applications using winsock, then just passing pointer. Memory is protected between both.

You will need to serialize your data to a memory stream. Using the proper classes with Encoding etc. for your strings. Then deserialize it in your C++ app.

Try something like below for your c# application, then do the inverse in your c++, it will work. The other way round would first read the 4 bytes, to tell how much more to read ahead for the string.... the read the string... the proceed to the next one, until an end of file marker is found.

            string myString = "abc";
        byte[] buffer = System.Text.Encoding.UTF8.GetBytes(myString);


        using (MemoryStream ms = new MemoryStream())
        {

            ms.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
            ms.Write(buffer, 0, buffer.Length);

            //... rest of code...
        }
Croc Studio
  • 141
  • 3
  • I tried every other answer and this was the one that I was able to get working. With the exception of changing the encoding to unicode – jacobsgriffith Apr 23 '14 at 17:59
  • Using this method i'm having a problem on the c++ side. If you could help me out on that problem maybe? http://stackoverflow.com/questions/23252334/cannot-properly-memcpy-a-char-array-to-struct – jacobsgriffith Apr 23 '14 at 18:25
  • your question seems answered, and i guess now you resolved all your issues? :) – Croc Studio Apr 23 '14 at 23:22
0

You have several problems:

  1. On C# side the marshal size is you defined as 32 bytes instead of 4 + 2 * 8 * 4 = 68 bytes. It would be better to remove Size field in StructureLayout
  2. In C++ you defined char instead of wchar_t, on the C# side there are Unicode strings
  3. You defined pointers instead of array so:
    • sizeof(Packet) is 20.
    • memcpy copies outside the Packet struct
    • Your code tries to access invalid memory, since it converts string values into pointers.

In C++ Packet should be defined as following:

struct Packet {
    unsigned int packet_type;
    wchar_t file_name[8];
    wchar_t template_name[8];
    wchar_t file_name_list[8];
    wchar_t file_data[8];
    // ...
};
Eugene
  • 2,858
  • 1
  • 26
  • 25
0

The problem is you pass string as pointer. Pointer is only valid in the same process. If your C# is 2.0 or above, change your struct to this:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct Packet
{
    public uint packet_type;
    public fixed char file_name[??];
    public fixed char template_name[??];
    public fixed char file_name_list[??];
    public fixed char file_buffer[??];
}
#pragma pack(push, 1)
struct Packet {
    unsigned int packet_type;
    wchar_t file_name[??];
    wchar_t template_name[??];
    wchar_t file_name_list[??];
    wchar_t file_data[??];

    void serialize(char * data) {
        memcpy(data, this, sizeof(Packet));
    }

    void deserialize(char * data) {
        memcpy(this, data, sizeof(Packet));
    }
};
#pragma pack(pop)

Replace ?? with the size you want, both C# and C++ must be the SAME size. And don't forget to add null character at the end of every string.

UltimaWeapon
  • 2,343
  • 18
  • 19