Search code examples
c#winapipinvoke

Win32 API waveInGetErrorText declaration into C#


Need to call

MMRESULT waveInGetErrorText(
   MMRESULT mmrError,
   LPTSTR   pszText,
   UINT     cchText
);

From C# code. Didn't find the declaration at PINVOKE.net. The description of the func is here

MMRESULT is just an uint value. 0 - no error.. any other value up to 20 - are errors.

Tried lot of patterns. Always get back an empty string.

[DllImport("Winmm", EntryPoint = "waveInGetErrorText")]
public static extern uint waveInGetErrorText(uint mmrError, IntPtr pszText, uint cchText);

When call.

uint r = 12 // for example return value is 12
uint szErrorMessage = 128;
string errorMessage = new string(' ', (int) szErrorMessage);
IntPtr strPtr = Marshal.StringToBSTR(errorMessage);

r = waveInGetErrorText(r, strPtr, szErrorMessage);

The return string is always empty reserved 128 bytes of spaces. Tried ref and out without success..

Pls, any idea why?


Solution

  • Your definiton of:

    public static extern uint waveInGetErrorText(uint mmrError, 
                                                 IntPtr pszText, 
                                                 uint cchText);
    

    ...isn't enough to tell .NET that IntPtr pszText is outputting anything. By default all paramaters are decorated with [in] marshal attributes by the compiler. So your above definiton is equivalent to:

    public static extern uint waveInGetErrorText([in] uint mmrError, 
                                                 [in] IntPtr pszText, 
                                                 [in] uint cchText);
    

    Now if you had a definition like:

    int CountRecords (out int numErrors)

    ...the compiler turns that into:

    int CountRecords ([out] out int numErrors)

    ...I believe. Regardless, the out (either form) tells the compiler to expect something from the p-invoke. Because you did not specify out or [out], nothing is passed back into the parameter after completion of the call.

    Now you could use out string but StringBuilder is easer. Some types like StringBuilder are recogised by .NET as "hey, for this parameter I expect something in return". The out is optional.

    Change your definition to:

    [DllImport("Winmm", EntryPoint = "waveInGetErrorText")]
    public static extern uint waveInGetErrorText(uint mmrError, StringBuilder text, uint cchText);
    

    I believe you should be calling it like so:

    uint r = 12 // for example return value is 12
    StringBuilder data = new StringBuilder(255);
    r = waveInGetErrorText(r, data, data.Capacity);
    

    Tell me more