Mix WinForms and WinAPI controls - winforms

Is it possible to mix WinAPI control creation and WinForms functionality?
Such a code won't work.
HWND hWndButton = CreateWindowEx(NULL,
"BUTTON",
"OK",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
50,
220,
100,
24,
(HWND)Handle.ToInt32(),
(HMENU)101,
GetModuleHandle(NULL),
NULL);
System::Windows::Forms::Control^ control =
System::Windows::Forms::Control::FromHandle(System::IntPtr(hWndButton));
Controls->Add(control);
I need to do this in order to add in a WinForms application some C++ Win32 API written controls by other company.
thx

You can override CreateParams property from Control class to specify desired class name. See this blog post for detailed explanations.

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);

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;
}

What is the use of Type.InvokeMember

Iam working in a WPF Application and in one place I had to use this piece of code to get the reference to a VirtualizingStackPanel.
Following is the piece of code,
VirtualizingStackPanel vsp = (VirtualizingStackPanel)obj.InvokeMember("_itemsHost", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic, null, content, null);
vsp.SetVerticalOffset(_SomeSelectedIndex);
Can someone explain what exactly this lines do and what are those binding flags ?

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.

WPF WIN32 hwndhost WM_MOUSEMOVE WM_MOUSEHOVER

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.

Resources