Receiving Windows Message on C# from managed Dll using p/invoke

5.1k views Asked by At

I have to call some native C functions from C# using p/invoke. So far, I had no problems marshaling the different methods and structures to C#. Where my problem resides is in the fact that many of the methods I have to call are asynchronous, and return their final results to my WinForms application through Windows Messages. For instance, I have a call to a method that has the following signature in C:

HRESULT AsyncOpenSession( LPSTR lpszLogicalName,
          HANDLE hApp,
          LPSTR lpszAppID,
          DWORD dwTraceLevel,
          DWORD dwTimeOut,
          USHORT lphService,
          HWND hWnd,
          DWORD dwSrvcVersionsRequired,
          LPWFSVERSION lpSrvcVersion,
          LPWFSVERSION lpSPIVersion,
          ULONG lpRequestID );

Where lpszAppID expects to receive the NAME of my application (MyApp.exe) and hWnd is a pointer to the WINDOW HANDLE of my application, which I obtain with a call to

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
public static IntPtr GetCurrentWindowHandle()
{
    IntPtr handle = GetForegroundWindow();
    return handle;
}

The imported signature is:

[DllImport("MSXFS.DLL", BestFitMapping = true, CharSet = CharSet.Auto, SetLastError = true)]
private static extern int AsyncOpenSession([MarshalAs(UnmanagedType.LPStr)] string lpszLogicalName,
                                       IntPtr hApp,
                                       [MarshalAs(UnmanagedType.LPStr)] string lpszAppID,
                                       UInt32 dwTraceLevel,
                                       UInt32 dwTimeOut,
                                       out Int32 lphService,
                                       IntPtr hWnd,
                                       UInt32 dwSrvcVersionsRequired,
                                       out WFSVersion lpSrvcVersion,
                                       out WFSVersion lpSPIVersion,
                                       out Int32 lpRequestID); 

I call the method as follows:

Int32 r = AsyncOpenSession(lpszLogicalName,
                               appHanlder,
                               "MyApp.exe",
                               dwTraceLevel,
                               dwTimeOut,
                               out hServ,
                               GetCurrentWindowHandle(),
                               dwSrvcVersionsRequired,
                               out srvcVersion,
                               out spiVersion,
                               out requestID);

Initially, the method call returns a result code that indicates the requested call has been put to the execution queue. Any time after the original call the native Dll completes the execution of the request and send a Windows Message to the application by means of its windows handle and name. The Windows Message code for this method is defined as follows:

#define WM_USER               0x0400
#define OPEN_SESSION_COMPLETE (WM_USER + 1)

More info about Windows Messages here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms644931(v=vs.85).aspx

In my application I have overridden the method WndProc to be able to control the Windows Messages as follows:

protected override void WndProc(ref Message m)
{
    const int wm_user = 0x0400;
    const int OPEN_SESSION_COMPLETE = wm_user + 1;

    switch (m.Msg)
    {
        case OPEN_SESSION_COMPLETE:
        txtEventsState.Text = m.ToString();
        break;
    }
    base.WndProc(ref m);
}

But I never receive a Windows Message with this code. There are no error in logs or event viewer. I know my call to the method succeeded because I do not get any error code and because it is mandatory to have an opened session before calling other methods, and I can call other methods that need a session handler successfully (no error code either).

My imported signature and call to the method is in a class library project that my application is referencing. Am I doing something wrong here? Can anyone give a light on what could be happening? I do not have access to the native code, just to a test application the shows that the Windows Messages are being sent by the native C Dll.

Thank to everybody in advance.

1

There are 1 answers

0
Gabe Thorns On BEST ANSWER

So, here it the deal: GetForegroundWindow() is not retriving the correct Window Handle. It happens that my application has two windows. One is the main form that I use for my test and the other displays all results and logging I am doing. So, the method was actually returning the Handle of the loggin window and not the form windows.

Using this.Handle and passing that value to the native methods made everything work correctly.

Thanks to Hans for pointing this out.