Question

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

Was it helpful?

Solution

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top