WPF WIN32 hwndhost WM_MOUSEMOVE WM_MOUSEHOVER - wpf

I have a WPF app with a usercontrol that contains a HwndHost. The HwndHost is created as follows:
hwndHost = CreateWindowEx(0, "static", "",
WS_CHILD | WS_VISIBLE,
0, 0,
hostHeight, hostWidth,
hwndParent.Handle,
(IntPtr)HOST_ID,
IntPtr.Zero,
0);
hwndControl = CreateWindowEx(0, "Static", "",
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN
,
0, 0,
hostHeight, hostWidth,
hwndHost,
(IntPtr)PICTUREBOX_ID,
IntPtr.Zero,
0);
I then hook into the message pump using HwndSourceHook and loads of messages come through.
Except the ones I want i.e. WM_MOUSEMOVE, WM_MOUSEHOVER, WM_LBUTTONDOWN and WM_LBUTTONUP
Also the OnMouseLeftButtonDown event is not fired in the WPF code on the main window or the control, I assume because windows is trapping it and throwing it away.
Anybody know how I can get these to come through, either with or without using the WIN32 window messages?

You need to handle WM_NCHITTEST. Until you do, it won't send you mouse messages.
// C++/CLI implementation of HwndHost.WndProc().
virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, bool% handled) override
{
switch (msg)
{
case WM_NCHITTEST:
{
handled = true;
return IntPtr(HTCLIENT);
}
}
return IntPtr::Zero;
}

It would appear that the Border element in WPF prevents the OnMouseLeftButtonDown being thrown. My temporary solution until I find a better one is to change the WPF border to a WPF button then all mouse events are triggered.
Not ideal for most people but as I am using it to render 3D onto it doesn't matter what is underneath it.

Why don't you register a WndClass and get messages delivered to your own WndProc instead of hooking the message pump? I suspect you'd get much better results.

Related

Win32 C++ ListView HDN_BEGINTRACK not working

I have a ListView whose columns I'd like to prevent being resized. I'm using code similar to this question, however my HDN_BEGINTRACK message isn't recognised.
My code to create the ListView:
HWND Instructions_ListView = CreateWindowEx(LVS_EX_DOUBLEBUFFER |
LVS_EX_FULLROWSELECT, WC_LISTVIEW, L"", WS_CHILD | WS_VISIBLE |
LVS_REPORT | LVS_EDITLABELS, 320, 50, 300, 400, hWnd, NULL, NULL, NULL);
My code to handle the header events follows. WM_NOTIFY is inside of WndProc for the main program window:
case WM_NOTIFY:
{
UINT debugval = (((LPNMHDR)lParam)->code);
switch (((LPNMHDR)lParam)->code)
{
case HDN_BEGINTRACKA:
case HDN_BEGINTRACK:
{
::MessageBox(hWnd, L"RESIZE", L"", MB_OK);
break;
}
}
break;
}
When debugging the value of debugval is 4294966969 when breaking on (what should be) the HDN_BEGINTRACK event.
Absolutely stumped as to why it's not working as intended; any help would be greatly appreciated.
The ListView's header control is a child of the ListView, so the header's WM_NOTIFY notifications will be sent to the ListView itself, not to your parent window. As such, your WndProc will not see them.
To catch WM_NOTIFY (and WM_COMMAND) messages sent by the ListView's internal child controls, you need to subclass the ListView using SetWindowLongPtr(GWL_WNDPROC) or SetWindowSubclass().
FYI, HDN_BEGINTRACKA has a value of 4294966990 (-306, hex 0xFFFFFECE), and HDN_BEGINTRACKW has a value of 4294966970 ( -326, hex 0xFFFFFEBA).
You say you are getting a WM_NOTIFY notification with a code of 4294966969. That is 0xFFFFFEB9 (dec -327), which is the HDN_ENDTRACKW notification.
When using COMCTL32 version 5, applications need to send common controls a CCM_SETVERSION message to take advantage of new functionality and fixes not available in earlier versions. The list view control does not forward all header notifications unless the control version is greater than or equal to 5. The List View control in COMCTL32 version 6 forwards all header notifications without sending the control a CCM_SETVERSION message.
So in your sample after creation of list view please add the below line
SendMessage(Instructions_ListView, CCM_SETVERSION, 5, 0);

Wpf window title bar mouse activity

I'm trying to get event on window title bar (for a standard wpf window).
A simple mouse down event (no matter the button) would be enough.
The idea is that i want to perform action on a custom control (which contain a textbox) when user click outside the control.
For now i'm adding two events handler to the control to help that:
UIElement.IsKeyboardFocusWithinChanged and Window.PreviewMouseDown. It works almost perfectly with this two event, except when user click on the window title bar as none of these two events are being fired...
Any ideas ? Thanks
You can use the following code to check if a window border has been clicked:
private const int WM_NCLBUTTONDOWN = 0x00a1;
// added after window loaded
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));
private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case WM_NCLBUTTONDOWN:
// your action
break;
}
return IntPtr.Zero;
}

WPF MessageBox not working

In my WPF I've tried System.Windows.MessageBox.Show, System.Windows.Forms.MessageBox.Show, and Xceed.Wpf.Toolkit.MessageBox.Show (from the Wpf Toolkit).
Every one of these methods shows the message box exactly how I want it too. The problem is that none of the buttons work. I click OK, I click cancel, I click the X, none of the buttons do anything. And with the toolkit message box I can't move the message box either. The buttons don't depress either. It's as if they're disabled, but I have no idea why.
EDIT: I'm using Prism and MEF to compose the application. Inside my module I have a view that is being displayed in a region in my Shell Window. The view is a UserControl with a button.
<UserControl>
<Grid>
<Button content="click me" Click="Button_OnClick"/>
</Grid>
</UserControl>
In the code behind I have the OnClick method.
private void Button_OnClick(object sender, RoutedEventArgs e)
{
System.Windows.MessageBox.Show("test");
}
The message box gets displayed, I can move it, The 'X' glows on mouse over, but neither the 'X' nor the 'OK' button, do anything.
I can provide more code as needed, I just don't want to have to include my whole application...
FIXED
The main WPF window had a borderless behavior attached to it that was processing windows messages (WndProc) and it wasn't processing the WM_NCACTIVATE message properly.
NOT WORKING:
case UnsafeNativeConstants.WM_NCACTIVATE:
handled = true;
break;
WORKING:
case UnsafeNativeConstants.WM_NCACTIVATE:
retVal = UnsafeNativeMethods.DefWindowProc(hwnd, UnsafeNativeConstants.WM_NCACTIVATE, new IntPtr(1), new IntPtr(-1));
handled = true;
break;
internal static UnsafeNativeMethods
{
[DllImport("user32", CallingConvention = CallingConvention.Winapi)]
public static extern IntPtr DefWindowProc([In] IntPtr hwnd, [In] int msg, [In] IntPtr wParam, [In] IntPtr lParam);
}
Try running your app in the debugger and pausing when the dialog is visible to ensure the message pump/loop is still running and is not deadlocked. That's the only reason I can think of that your UI could be unresponsive.

How to make a multi-line textbox's tab-stop working in win32api application

I have a win32api application written in c here. All controls in main window are created manually like this:
hEditSource = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", NULL,
WS_VISIBLE | WS_CHILD | WS_TABSTOP | ES_MULTILINE | ES_READONLY,
someLeft, someTop, someWidth, someHeight,
hWndMain, NULL, hInst, NULL);
At first I didn't apply IsDialogMessage test in main message loop so all controls' tab stop won't work. Now I have it done, every control are OK except the multi-line textbox above. Indeed nothing happens when press tab in it. No focus moving, no tab charactor inserting(it will discard read-only style afterwards).
Other textboxes are all single-line ones, looks like this:
editSearch = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", NULL,
WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL | WS_TABSTOP,
someLeft, someTop, someWidth, someHeight,
hWndMain, NULL, hInst, NULL);
It seems sth related to multiple line style is the cause. But in C# winform, it is very easy to create a multi-line edit with working tab-stop (it is the default behavior of a textbox, whether it is multi-line). I have tried to use spy++, to find if there is any clue in window style. However, 2 textboxes' window style are indentical if the only difference is the "Accept Tab" property.
Rightnow I cannot find another way to locate the root cause. Does anyone have a clue? Any help will be appreciated.
The behaviour of the IsDialogMessage is influenced by how the controls respond to WM_GETDLGCODE. As documented, for a multi-line edit control the following is returned by the default window procedure:
DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS | DLGC_WANTALLKEYS
The inclusion of DLGC_WANTALLKEYS stops IsDialogMessage from responding to TAB and moving the focus to the next control. So, you will need to subclass your multi-line edit control and remove that flag. The sub-classed window procedure might look like this:
LRESULT CALLBACK MultiLineEditWndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam)
{
LRESULT res = CallWindowProc(wpOld, hWnd, message, wParam, lParam);
switch (message)
{
case WM_GETDLGCODE:
res &= ~DLGC_WANTALLKEYS;
}
return res;
}

WPF - remove system menu icon from modal window, but not main app window

I'm trying to do (in WPF):
Have an .exe file that displays the system menu icon (the icon in the upper left of the window) like normal
Not have this icon show up in modal windows called by this app
I tried the solution here:
Removing Icon from a WPF window
And this worked. There's a downloadable sample of the same thing at:
http://blogs.msdn.com/b/wpfsdk/archive/2007/08/02/a-wpf-window-without-an-window-icon-the-thing-you-click-to-get-the-system-menu.aspx
However, it stops working if I add an .ico file to the .exe's project properties (Properties -> Application -> Icon and Manifest). You can try this with the downloadable sample.
It seems that the icon from the .exe is used in the modal windows too (which we have in .dll files) even if the properties of that .dll says "default icon". It must get passed down from the .exe. So, is there a way to show the icon on the main window, but not on a child window?
Possibly, an easier way of asking this is: Is it possible to remove the icon even though there's an .ico file specifies in the project's properties?
The only thing I've found to work is to set the WindowStye of the modal window to "ToolWindow". This gives me almost what I want: no icon and the "Close" button ("x" in upper right) is still there. Yet, the x is super small. Is this the best there is?
Thanks for any help.
I had this same problem. It appears that WS_EX_DLGMODALFRAME only removes the icon when the WPF window's native Win32 window does not have an icon associated with it. WPF (conveniently) uses the application's icon as the default icon for all windows without an explicitly set icon. Normally, that doesn't cause any problems and saves us the trouble of manually setting the application's icon on each window; however, it causes a problem for us when we try to remove the icon.
Since the problem is that WPF automatically sets the window's icon for us, we can send WM_SETICON to the Win32 window to reset its icon when we are applying WS_EX_DLGMODALFRAME.
const int WM_SETICON = 0x0080;
const int ICON_SMALL = 0;
const int ICON_BIG = 1;
[DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr SendMessage(
IntPtr hWnd,
int msg,
IntPtr wParam,
IntPtr lParam);
Code to remove the icon:
IntPtr hWnd = new WindowInteropHelper(window).Handle;
int currentStyle = NativeMethods.GetWindowLongPtr(hWnd, GWL_EXSTYLE);
SetWindowLongPtr(
hWnd,
GWL_EXSTYLE,
currentStyle | WS_EX_DLGMODALFRAME);
// reset the icon, both calls important
SendMessage(hWnd, WM_SETICON, (IntPtr)ICON_SMALL, IntPtr.Zero);
SendMessage(hWnd, WM_SETICON, (IntPtr)ICON_BIG, IntPtr.Zero);
SetWindowPos(hWnd, IntPtr.Zero, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
Edit: Oh, and it looks like this works only when the app is run outside of Visual Studio.

Resources