How does WPF call Win32 programs?
In msdn, a special chapter mentions how to embed Win32 controls in WPF, that is, to use hwndhost, you only need to pass the Win32 control handle to hwndhost. The example in msdn demonstrates the Win32 Control created in the same process. At first, I thought that as long as the windows handle of the external Win32 program is obtained through WIN32API such as findwindow, then, you can hand over the window handle to hwndhost. The core code is as follows:
Protected override handleref buildwindowcore (handleref hwndparent)
{
Appproc = new process ();
Appproc. startinfo. windowstyle = processwindowstyle. hidden;
Appproc. startinfo. filename = @ "D:/greeninst/netterm/netterm.exe ";
Appproc. Start ();
// Wait until the initialization is complete.
Thread. Sleep (1000 );
Hwndhost = win32native. findwindow ("nettermclass", null );
// The window Embedded in hwnhost must be set to ws_child
Uint oldstyle = win32native. getwindowlong (hwndhost, win32native. gwl_style );
Win32native. setwindowlong (hwndhost, win32native. gwl_style, (oldstyle | win32native. ws_child ));
// Set the parent window of netterm to hwndhost
Win32native. setparent (hwndhost, hwndparent. Handle );
Return new handleref (this, hwndhost );
}
Here, the external program netterm is started. Practice has proved that this idea is feasible, but the only problem is that although the external Win32 program is displayed in the WPF program, it is strange that the embedded Win32 program can no longer be clicked, clicking the button or entering the button does not work, and the program seems to be dead. After analysis, I think that because the setparent WIN32API is used to set the parent window of netterm to hwndhost, netterm no longer has its own window message loop, instead, he waited for the father of hwndhost to send a message to him. It may be because the processing of message loops in WPF is different from that in the previous Win32 program. As a result, all mouse clicks and button messages cannot be transmitted to the son of netterm, so that netterm will not receive any messages, so it's like dead.
The solution to this problem is to intercept the window message of WPF and forward it to netterm through the WIN32API sendmessage. However, after half a day, I did not find a place for WPF message processing. After asking my colleagues, I learned that WPF does not have window message loops as traditional Win32 programs do. Instead, I made a set of them myself. After being depressed for a while, the ghost suddenly came to light: it's basically a Win32 program, but it's just a Win32 program that uses DirectX technology internally, as long as the Win32 program has a way to get its window message loop. How can this problem be solved? Yes! Is the window hook. You can use the setwindowshookex WIN32API to intercept all the message loops in a window. In this way, you only need to pick out the message sent to hwndhost and forward it to the netterm window. After the transformation, netterm will finally survive !!!
To solve the most core problem, we should solve the common problem. The main problems and countermeasures are as follows:
1. Hide the window border of netterm, so it seems that netterm is an external program. The idea is simple: Use getwindowlong to get the original style of the window, and then append a ws_border style.
// Set it to ws_child
Uint oldstyle = win32native. getwindowlong (hwndhost, win32native. gwl_style );
//&~ Ws_border removes the border, which looks more like an embedded program. Pay attention to the effect of () and change the default priority.
Win32native. setwindowlong (hwndhost, win32native. gwl_style, (oldstyle | win32native. ws_child )&~ Win32native. ws_border );
2. Hide the netterm button on the taskbar
You only need to find the handle of the taskbar, and then first send tb_buttoncount to it to get the number of buttons above it. Because netterm is just started, you can think that the last button is the netterm button, you only need to send the tb_deletebutton message to the taskbar handle and delete the last button.
Private void hidetaskbarbutton ()
{
Intptr vhandle = win32native. findwindow ("shell_traywnd", null );
Vhandle = win32native. find?wex (vhandle, intptr. Zero,
"Rebarwindow32", intptr. Zero );
Vhandle = win32native. find?wex (vhandle,
Intptr. Zero, "mstaskswwclass", intptr. Zero );
Vhandle = win32native. find?wex (vhandle, intptr. Zero,
"Toolbarwindow32", intptr. Zero );
// Obtain the number of buttons in the taskbar.
Int vcount = win32native. sendmessage (New handleref (this, vhandle ),
(Uint) win32native. tb_buttoncount, intptr. Zero, intptr. Zero). toint32 ();
// Think that the last button is the button of the nested program. Delete it.
Win32native. sendmessage (New handleref (this, vhandle ),
Win32native. tb_deletebutton, new intptr (vcount-1), intptr. Zero );
}
This is the processing in WINXP. It seems that the taskbar structure of Win2000 and Vista is different. If you need to run these OS, you need to make further improvements.
3. Automatic logon. After netterm is started, it automatically logs on to the server, enters the user name and password, and starts the specified program. Netterm supports specifying the server address to be connected in the startup parameter, which can solve the problem of automatically logging on to the server. sendmessage (handle, win32native. wm_char, CH, intptr. zero) sends a simulated button to the netterm window to automatically type Linux commands. Since Linux commands require a certain amount of processing time, sleep is required for a while every time a command is sent to prevent the speed of typing commands from being too fast.