To modernize an older C++/CLI MFC-based application we are trying to replace an old dialog with a new one written in C#/WPF. To host the WPF control inside a CDialog
we have followed this guide describing the procedure for a Win32 host window: Hosting WPF Content in Win32
This works but the textboxes inside the WPF control do not accept/receive any keyboard input despite special keys like [backspace]/[del]/[space].
There is a similar question Non-modal WPF dialog hosted in a Win32 app doesn't receive keyboard events where the only answer advises to use the HwndSource
to implement a message loop within the WPF control's assembly to receive/process the keyboard related messages but its not working.
I implemented it in this way but it doesn't change anything.
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
HwndSource source = (HwndSource)PresentationSource.FromVisual(this);
source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
HwndSource source = HwndSource.FromHwnd(hwnd);
if (source != null)
{
System.Windows.Interop.MSG message = new MSG
{
hwnd = hwnd,
lParam = lParam,
wParam = wParam,
message = msg,
pt_x = 0,
pt_y = 0
};
switch (msg)
{
// WM_KEYDOWN
case 0x0100:
Debug.WriteLine("Received WM_KEYDOWN");
var keyboardSink = (IKeyboardInputSink)source;
keyboardSink.TranslateAccelerator(ref message, Keyboard.Modifiers);
break;
// WM_CHAR
case 0x0102:
Debug.WriteLine("Received WM_CHAR");
var keyboardSink2 = (IKeyboardInputSink)source;
keyboardSink2.TranslateChar(ref message, Keyboard.Modifiers);
break;
}
}
return IntPtr.Zero;
}
However embedding the same WPF control inside a bare win32 window works flawlessly.
Also textboxes inside a modal-dialog which I spawn from the main WPF control receive keyboard inputs as well, so it must be related to the non-modal fashion of the main control.
Here I put a minimal working example to demonstrate the issue: https://github.com/Michaelvsk/WpfHostedInMfc
My MFC knowledge is very basic, so any help is much appreciated.
In your case, the WPF control is hosted as a WS_CHILD
(this is important) of a Win32 dialog box (this is also important), which eats some messages for its own good, as all dialog boxes do.
You can control that if you handle the WM_GETDLGCODE message
Sent to the window procedure associated with a control. By default, the system handles all keyboard input to the control; the system interprets certain types of keyboard input as dialog box navigation keys. To override this default behavior, the control can respond to the WM_GETDLGCODE message to indicate the types of input it wants to process itself.
Something like this:
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
const int WM_GETDLGCODE = 0x0087;
const int DLGC_WANTALLKEYS = 4;
if (msg == WM_GETDLGCODE)
{
handled = true;
return new IntPtr(DLGC_WANTALLKEYS);
}
return IntPtr.Zero;
}