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?
I know this is 7.5 years old, but just in case anyone finds this, I thought I would respond. I used Microsoft's TimerNativeWindow code and removed the timer functionality. I ended up using this approach:
public class MyNativeWindow : NativeWindow
{
private readonly string _caption;
private const int WmClose = 0x0010;
[SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
private static readonly HandleRef HwndMessage = new HandleRef(null, new IntPtr(-3));
[DllImport("user32.dll", CharSet = CharSet.Auto)]
[ResourceExposure(ResourceScope.None)]
private static extern IntPtr PostMessage(HandleRef hwnd, int msg, int wparam, int lparam);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
[ResourceExposure(ResourceScope.Process)]
private static extern int GetWindowThreadProcessId(HandleRef hWnd, out int lpdwProcessId);
[DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
[ResourceExposure(ResourceScope.Process)]
private static extern int GetCurrentThreadId();
public MyNativeWindow(string caption)
{
_caption = caption;
}
public bool CreateWindow()
{
if (Handle == IntPtr.Zero)
{
CreateHandle(new CreateParams
{
Style = 0,
ExStyle = 0,
ClassStyle = 0,
Caption = _caption,
Parent = (IntPtr)HwndMessage
});
}
return Handle != IntPtr.Zero;
}
public void DestroyWindow()
{
DestroyWindow(true, IntPtr.Zero);
}
private bool GetInvokeRequired(IntPtr hWnd)
{
if (hWnd == IntPtr.Zero) return false;
int pid;
var hwndThread = GetWindowThreadProcessId(new HandleRef(this, hWnd), out pid);
var currentThread = GetCurrentThreadId();
return (hwndThread != currentThread);
}
private void DestroyWindow(bool destroyHwnd, IntPtr hWnd)
{
if (hWnd == IntPtr.Zero)
{
hWnd = Handle;
}
if (GetInvokeRequired(hWnd))
{
PostMessage(new HandleRef(this, hWnd), WmClose, 0, 0);
return;
}
lock (this)
{
if (destroyHwnd)
{
base.DestroyHandle();
}
}
}
public override void DestroyHandle()
{
DestroyWindow(false, IntPtr.Zero);
base.DestroyHandle();
}
}
Try that :
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
static IntPtr HWND_MESSAGE = new IntPtr(-3);
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
SetParent(this.Handle, HWND_MESSAGE);
}
I believe that you'll need to also specify a window class.
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.
来源:https://stackoverflow.com/questions/935608/how-do-i-create-a-message-only-window-from-windows-forms