Introduction
One of the requirements for a PDA (Personal Digital Assistance) application I was developing was to subclass a window created by a C# application, in an eMbedded VC++ created DLL. The C# application loads the eMbedded VC++ created DLL to perform the recording functionality.
Solution
The GUI for the same was developed using C# (.NET Compact framework), and for the recording functionality, we 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 the waveInOpen
function? We need to somehow pass the window handle to the DLL so that the DLL can subclass the window and the messages can be processed in the DLL itself.
Here is an attempt to solve the above mentioned issue.
First of all, the functions implemented in the DLL are called using DllImport
in the C# application. You need to write the following code to access the functions exported from this DLL (Recorder.dll). I have put all these functions in a class named Wrapper
.
public class Wrapper
{
[DllImport("Recorder.dll", EntryPoint="StartRecording")]
static extern public bool StartRecording ();
[DllImport("Recorder.dll", EntryPoint="StopRecording")]
static extern public bool StopRecording ();
[DllImport("Recorder.dll", EntryPoint="StartPlaying")]
static extern public bool StartPlaying(string sFile);
[DllImport("Recorder.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 window's handle to this function (Please note that this.Handle
is not supported in the .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, coredll.dll, which implements the 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 )
{
switch (unMessage)
{
case <message>:
break;
default:
break;
}
return CallWindowProc ( g_lpfnWndProc, hWnd, unMessage, wParam, lParam );
}
This is your new window procedure in which you can trap any message coming to your C# window.
Do the subclassing whenever the SetWindowHandle
function is called. Here is the code for the same:
bool CRecorder::SetWindowHandle(HWND hWnd)
{
if ( hWnd == NULL )
return false;
m_hParentWnd = hWnd;
g_lpfnWndProc = (WNDPROC) SetWindowLong ( m_hParentWnd,
GWL_WNDPROC, (LONG) RecorderWndProc );
if ( g_lpfnWndProc == NULL )
return false;
return true;
}