none
Passing a native char* via Interop (not a string) RRS feed

  • Question

  • Hello,

    I need to pass wave API audio samples from native to managed code. Wave API is using char* to store their buffers.

    I know that native char corresponds to sbyte in .NET, but I wish I could get a byte[] array instead of sbyte[] on the .NET side, so here is my question:

    When using PINVOKE, does char* correspond to byte[] or sbyte[] on the .NET side? Or, do I have a choice?

    Thank you,

    Evgueni


    Evgueni Tsygankov
    Wednesday, June 4, 2008 1:21 PM

Answers

  • I was mystified by your question, until I looked at the MSDN library article for WAVEHDR.  Whoa, no way a "Pointer to the waveform buffer" is a string.  That's gotta be bytes, LPSTR is only going to work in a non-Unicode environment.  You'll have to fix the SDK mistake.  It's unpleasant because the buffer has a variable size.  Try this:

        [StructLayout(LayoutKind.Sequential)]
        private struct WAVEHDR {
          public IntPtr lpData;
          public uint dwBufferLength;
          public uint dwBytesRecorded;
          public IntPtr dwUser;
          public uint dwFlags;
          public uint dwLoops;
          public IntPtr lpNext;
          public IntPtr reserved;
        }

    Then when you get a WAVEHDR from some API function, you can retrieve the buffer content like this:

          byte[] data = new byte[hdr.dwBufferLength];
          Marshal.Copy(hdr.lpData, data, 0, data.Length);



    Hans Passant.
    • Marked as answer by Popsovy Wednesday, June 4, 2008 9:59 PM
    Wednesday, June 4, 2008 8:48 PM
    Moderator

All replies

  • have a look at Marshal.Copy. You'll need to do something like:

    char* theptr;
    Byte[] theArray;
    Marshal.Copy(new IntPtr(theptr), theArray, 0, length);
    Wednesday, June 4, 2008 1:47 PM
  • Use CharSet=CharSet.Ansi in your P/Invoke declaration.  That will automatically translate System.String to char*
    Hans Passant.
    Wednesday, June 4, 2008 2:56 PM
    Moderator
  •  Thank you for your response, but let me provide more information. The native type in question is 

    1 typedef struct {   
    2     LPSTR      lpData;   
    3     DWORD      dwBufferLength;   
    4     DWORD      dwBytesRecorded;   
    5     DWORD_PTR  dwUser;   
    6     DWORD      dwFlags;   
    7     DWORD      dwLoops;   
    8     struct wavehdr_tag * lpNext;   
    9     DWORD_PTR reserved;   
    10 } WAVEHDR;   
    11  

    On line #2, there is LPSTR lpData declaration. LPSTR is declared in WinNT.h as 
    typedef __nullterminated CHAR *NPSTR, *LPSTR, *PSTR;

    In other words, it's a NULL-terminated array of CHAR.

    if I tried to use the interop to declare/marshal this structure in .NET, what datatype LPSTR would be on the .NET side?

    Thanks



    Evgueni Tsygankov
    Wednesday, June 4, 2008 7:03 PM
  • Like I said, a string:

    using System.Runtime.InteropServices;
    ...

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        private struct WAVEDHR {
          public string lpData;
          public uint dwBufferLength;
          public uint dwBytesRecorded;
          public IntPtr dwUser;
          public uint dwFlags;
          public uint dwLoops;
          public IntPtr lpNext;
          public IntPtr reserved;
        }


    Hans Passant.
    Wednesday, June 4, 2008 7:30 PM
    Moderator
  • Thank you very much, but I have one last question.

    I know that all strings in .NET are in unicode. So, if I then pass that lpData to other parts of the program that expect some kind of a byte array, would I need to do a conversion from unicode? Thanks.
    Evgueni Tsygankov
    Wednesday, June 4, 2008 8:18 PM
  • I was mystified by your question, until I looked at the MSDN library article for WAVEHDR.  Whoa, no way a "Pointer to the waveform buffer" is a string.  That's gotta be bytes, LPSTR is only going to work in a non-Unicode environment.  You'll have to fix the SDK mistake.  It's unpleasant because the buffer has a variable size.  Try this:

        [StructLayout(LayoutKind.Sequential)]
        private struct WAVEHDR {
          public IntPtr lpData;
          public uint dwBufferLength;
          public uint dwBytesRecorded;
          public IntPtr dwUser;
          public uint dwFlags;
          public uint dwLoops;
          public IntPtr lpNext;
          public IntPtr reserved;
        }

    Then when you get a WAVEHDR from some API function, you can retrieve the buffer content like this:

          byte[] data = new byte[hdr.dwBufferLength];
          Marshal.Copy(hdr.lpData, data, 0, data.Length);



    Hans Passant.
    • Marked as answer by Popsovy Wednesday, June 4, 2008 9:59 PM
    Wednesday, June 4, 2008 8:48 PM
    Moderator