views:

554

answers:

4

I'm trying to create a message-only window to receive window messages from an MFC library class, within a winforms application.

I've tried subclassing NativeWindow, and in the constructor requesting a window handle like this:

CreateParams cp = new CreateParams();
cp.Parent = (IntPtr)HWND_MESSAGE;
this.CreateHandle(cp);

but I get a Win32Exception thrown with the message "Error creating window handle". How do I create a message-only window from windows forms? Is using NativeWindow the right approach?

A: 

I believe that you'll need to also specify a window class.

arul
what should I set it to? I've tried "Message" and the name of the class, but neither worked. "Message" gives me the same error, and the class name gives me "Window class name is not valid".
Simon
A: 

Try that :

[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

protected override void OnHandleCreated(EventArgs e)
{
    base.OnHandleCreated(e);
    SetParent(this.Handle, HWND_MESSAGE);
}
Thomas Levesque
A: 

Delphi (unmanaged) had a helper routine that did just that. It created a window that you would only use as a target to receive messages (say from a background thread).

You would give it the window procedure method, and it would create the window.

function AllocateHWnd(Method: TWndMethod): HWND;
var
  TempClass: TWndClass;
  ClassRegistered: Boolean;
begin
  UtilWindowClass.hInstance := HInstance;
  ClassRegistered := GetClassInfo(HInstance, UtilWindowClass.lpszClassName,
    TempClass);
  if not ClassRegistered or (TempClass.lpfnWndProc <> @DefWindowProc) then
  begin
    if ClassRegistered then
      Windows.UnregisterClass(UtilWindowClass.lpszClassName, HInstance);
    Windows.RegisterClass(UtilWindowClass);
  end;
  Result := CreateWindowEx(WS_EX_TOOLWINDOW, UtilWindowClass.lpszClassName,
    '', WS_POPUP {!0}, 0, 0, 0, 0, 0, 0, HInstance, nil);
  if Assigned(Method) then
    SetWindowLong(Result, GWL_WNDPROC, Longint(MakeObjectInstance(Method)));
end;

var
  UtilWindowClass: TWndClass = (
    style: 0;
    lpfnWndProc: @DefWindowProc;
    cbClsExtra: 0;
    cbWndExtra: 0;
    hInstance: 0;
    hIcon: 0;
    hCursor: 0;
    hbrBackground: 0;
    lpszMenuName: nil;
    lpszClassName: 'TPUtilWindow');

You'll have to turn it into P/Invoke.

Perhaps .NET already did something similar - but i doubt it. They don't want you using messages and window handles - and so would do everything possible to thwart developers.

Ian Boyd
A: 

I fear that you must derive from a Form, and force the window invisible.

Another approach (in the case the class library is modifiable) is to run a message pump without a window (see Application.Run and Application.AddMessageFilter, or if you prefer pinvokes using PeekMessage & Co).

In this case you can send messages using PostThreadMessage by having the thread id which as run Application.Run, but actually you cannot synch with the application message pump thread because it doesn't wait message acknowledge.

Luca