One of the requirements for a PDA product was to subclass a window in a dll which is created in a C# application.
GUI for the same was developed using C# and for recording functionality they have a dll created using embedded VC++. Now, the waveform-audio input device sends a notification message to the specified window, but the question was how to get a window handle which is created in C# application so that it can be passed as a parameter for waveInOpen function? We need to somehow pass the window handle to dll so that dll can subclass the window and the messages can be processed in the dll itself.
This is what I did and it seems to be working fine.
First of all the functions implemented in dll are called using dllimport in the C# application. You need to write the following code to access the functions exported from this dll (Recrdr.dll). I have put all these functions in a class named Wrapper.
public class Wrapper
{
[DllImport("Recrdr.dll", EntryPoint="StartRecording")]
static extern public bool StartRecording ();
[DllImport("Recrdr.dll", EntryPoint="StopRecording")]
static extern public bool StopRecording ();
[DllImport("Recrdr.dll", EntryPoint="StartPlaying")]
static extern public bool StartPlaying(string sFile);
[DllImport("Recrdr.dll", EntryPoint="StopPlaying")]
static extern public bool StopPlaying ();
...
...
}
I added one more function in the dll which will accept the window handle of a C# window. I imported the same in the C# application.
[DllImport("Recrdr.dll", EntryPoint="SetParentWnd")]
static extern public bool SetParentWnd(UInt32 hWnd);
Now, I need to pass the windows handle to this function (Please note that this.Handle is not supported in .Net Compact framework). Then how do we do this? Well, again we need to call a windows api for getting the window handle. For that, you need to import the windows dll named coredll.dll which implements GetForegroundWindow function.
This is how you do this.
[DllImport("coredll.dll", EntryPoint="GetForegroundWindow")]
static extern public UInt32 GetForegroundWindow();
This is again added to the Wrapper class which I mentioned earlier.
Call this function from your C# application's form load function to get the foreground window and call the SetParentWnd function of the Recrdr.dll by passing this handle.
UInt32 unHandle = Wrapper.GetForegroundWindow ();
Wrapper.SetParentWnd (unHandle);
Now in your embedded VC++ code, add the following lines of code to trap the message.
LRESULT CALLBACK RecorderWndProc ( HWND hWnd, UINT unMessage, WPARAM wParam, LONG lParam ) // LRESULT CALLBACK
{
switch (unMessage)
{
case <message>:
break;
default:
break;
}
return CallWindowProc ( g_lpfnWndProc, hWnd, unMessage, wParam, lParam ); // Call original window procedure
}
This is your new window procedure in which you can trap any message coming to your C# window.
Do the subclassing whenever SetWindowHandle function is called. Here is the code for the same.
bool CRecorder::SetWindowHandle(HWND hWnd)
{
if ( hWnd == NULL )
return false;
m_hParentWnd = hWnd;
// Do an instance subclassing so that you can trap messages here
// and leave rest of the messages to the main window
g_lpfnWndProc = (WNDPROC) SetWindowLong ( m_hParentWnd, GWL_WNDPROC, (LONG) RecorderWndProc );
if ( g_lpfnWndProc == NULL )
return false;
return true;
}