locked
Passing struct to WriteFile function RRS feed

  • Question

  • Hello all,

    I'm trying to use named pipes to communicate with a c++ app from my c# app.  I'm using the WriteFile function to write to the pipe but I want to write a struct, any idea on what would be the best way to pass such a parameter as the data buffer?  Here is the function:

    [DllImport("kernel32.dll", SetLastError = true)]
          public static extern bool WriteFile(SafeFileHandle hFile, // Handle to file
                                              byte[] lpBuffer, // Data buffer
                                              uint nNumberOfBytesToWrite, // Number of bytes to write
                                              out uint lpNumberOfBytesWritten, // Number of bytes written
                                              [In] ref uint lpOverlapped); // Overlapped buffer );

    Thursday, December 29, 2011 8:42 PM

Answers

All replies

  • what .net version are you using?  If you are using .net 3.5 / + use the NamedPipe classes are suported in BCL.

    http://msdn.microsoft.com/en-us/library/system.io.pipes.aspx

     

    You need to convert the struct to byte array using serialization

    http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/71f48e06-29b0-4ae6-b437-d56714166cc3

     


    --Krishna
    Thursday, December 29, 2011 9:03 PM
  • I'm using .Net 2.0 so I can't use System.IO.Pipes.  I've come up with this from your link but it won't serialize properly.  If I just send a string instead of a struct, the data sends properly.  Can you help with what is wrong with this?

     

       public class CNamedPipeInterface 
       {
          [DllImport("kernel32.dll", SetLastError = true)]
          public static extern SafeFileHandle CreateFile(string pipeName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes,
                                                          uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
    
          [DllImport("kernel32.dll", SetLastError = true)]
          public static extern bool WaitNamedPipe(string name, uint timeout);
    
          [DllImport("kernel32.dll", SetLastError = true)]
          public static extern bool ReadFile(SafeFileHandle hFile, // Handle to file 
                                              byte[] lpBuffer, // Data buffer 
                                              uint nNumberOfBytesToRead, // Number of bytes to read 
                                              out uint lpNumberOfBytesRead, // Number of bytes read 
                                              [In] ref System.Threading.NativeOverlapped lpOverlapped);// Overlapped buffer ); 
    
          [DllImport("kernel32.dll", SetLastError = true)]
          public static extern bool WriteFile(SafeFileHandle hFile, // Handle to file 
                                              byte[] lpBuffer, // Data buffer 
                                              uint nNumberOfBytesToWrite, // Number of bytes to write 
                                              out uint lpNumberOfBytesWritten, // Number of bytes written 
                                              [In] ref System.Threading.NativeOverlapped lpOverlapped); // Overlapped buffer ); 
    
          [DllImport("KERNEL32.DLL", SetLastError = true)]
          public static extern bool SetNamedPipeHandleState(SafeFileHandle hNamedPipe,
                                                             ref int lpMode,
                                                             IntPtr lpMaxCollectionCount,
                                                             IntPtr lpCollectDataTimeout);
       }
    
       public class PipeComm
       {
          private const int MAX_PATH = 260;
          public const string strPIPE_NAME = "\\\\.\\pipe\\namedpipe";
    
          private SafeFileHandle m_hPipe;
    
          [StructLayout(LayoutKind.Sequential,Pack=1)]
          public struct sPIPECMDBLK
          {
             public sPIPECMDBLK(int nIDSize)
             {
                abByteArray = new byte[nIDSize];
                bCommand = 0;
                ui16RetCode = 0;
             }
             public Byte     bCommand;
             public Byte[] abByteArray;
             public ushort ui16RetCode;
          }
          static void main(string[] args)
          {
             m_hPipe = CNamedPipeInterface.CreateFile(strPIPE_NAME, CNamedPipeInterface.GENERIC_READ | CNamedPipeInterface.GENERIC_WRITE, 0, IntPtr.Zero, CNamedPipeInterface.OPEN_ALWAYS, 0, IntPtr.Zero);
    
             if (m_hPipe.IsInvalid)
             {
                int err = Marshal.GetLastWin32Error();
                // ...
             }
             else
             {
                sPIPECMDBLK structPipeCmdBlk = new sPIPECMDBLK(MAX_PATH);
                System.Threading.NativeOverlapped OS = new System.Threading.NativeOverlapped();
                string strData = "some data here";
                System.Text.UnicodeEncoding encoding = new System.Text.UnicodeEncoding();
                structPipeCmdBlk.abByteArray = encoding.GetBytes(strData);
                structPipeCmdBlk.bCommand = 1;
                structPipeCmdBlk.ui16RetCode = 1;
                uint uiNumberBytesWritten = 0;
                IntPtr pntStruct = Marshal.AllocHGlobal(Marshal.SizeOf(structPipeCmdBlk));
                Marshal.StructureToPtr(structPipeCmdBlk, pntStruct, false);
    
                bool fSuccess = CNamedPipeInterface.WriteFile(m_hPipe, encoding.GetBytes(Marshal.PtrToStringAuto(pntStruct)),
                   Convert.ToUInt32(Marshal.SizeOf(structPipeCmdBlk)), out uiNumberBytesWritten, ref OS);
                int err = Marshal.GetLastWin32Error();
                //handle error
    
                Marshal.FreeHGlobal(pntStruct);
             }
          }
       }
    

     

    Also, here is the struct as defined in the server pipe c++ program:

    typedef struct tagPIPECMDBLK
    {
    	unsigned char      bCommand;
    	unsigned char      abByteArray[MAX_PATH]; //MAX_PATH=260
    	unsigned __int16   ui16RetCode;
    } PIPECMDBLK
    Thanks.

    Friday, December 30, 2011 2:37 PM
  • I doubt something wrong with your encoding. Can you try with different encoding other than Unicode whle writing the struct you mentioned, as it had byte array.

    Add additonal attributes on struct

    public struct sPIPECMDBLK
          {
             public sPIPECMDBLK(int nIDSize)
             {
                abByteArray = new byte[nIDSize];
                bCommand = 0;
                ui16RetCode = 0;
             }
             public Byte     bCommand;
    		 [MarshalAs(UnmanageType.ByValArray, SizeConst=8)] 
             public Byte[] abByteArray;
             public ushort ui16RetCode;
          }

     

    try with other encoders instead of Uincode.

    //System.Text.UnicodeEncoding encoding = new System.Text.UnicodeEncoding();



    --Krishna
    • Marked as answer by Paul Zhou Friday, January 6, 2012 6:49 AM
    Tuesday, January 3, 2012 6:48 PM
  • You can refer to the document about WriteFile API when P\Invoke it:

    http://pinvoke.net/default.aspx/kernel32/WriteFile.html

    We always pass the address of the byte array or struct as Intptr to unmanaged code, more information, you can refer to:

    http://www.codeproject.com/KB/vb/Marshaling_Structures.aspx?msg=2199213

    http://www.codeproject.com/KB/cs/UnmanagedArraysInCSharp.aspx


    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    • Marked as answer by Paul Zhou Friday, January 6, 2012 6:49 AM
    Wednesday, January 4, 2012 7:45 AM
  • Hi,

     

    Has your issue been resolved? Would you mind letting us know the result of the suggestions?

     

    Now I will mark an answer, you can mark others that you think to be so useful to your issue.

    If you still have any questions about this issue, please feel free to let me know. We will continue to work with you on this issue.


    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    Friday, January 6, 2012 6:50 AM