Embedded common Win32 program in WPF

Source: Internet
Author: User
The company is currently developing based on. net, because it is compatible with old products, such as some old Win32 programs and third-party Win32 programs, it is also necessary to automatically log on to these external Win32 programs, therefore, we must be able to integrate these programs into our systems so that users can see them as a program.

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.


The running effect is as follows:


The main code is as follows: win32native. CS is a simple call statement for WIN32API. It is a simple pinvoke statement. It is not posted here because of its large size. You can check msdn to declare it.

================================================== Nettermhost. CS ================================

Namespace client. Pages

{

Class nettermhost: hwndhost

{

Public intptr hwndhost;


Private intptr hookid = new intptr (3 );


Private hookproc;


Private process appproc;


Protected override handleref buildwindowcore (handleref hwndparent)

{

Appproc = new process ();

Appproc. startinfo. windowstyle = processwindowstyle. hidden;

Appproc. startinfo. filename = @ "D:/greeninst/netterm/netterm.exe ";

// Set the host name to be connected, so that the connection will be established immediately after startup.

Appproc. startinfo. Arguments = "192.168.88.128 ";

Appproc. Start ();


// Wait until the initialization is complete.

Thread. Sleep (1000 );


Hwndhost = win32native. findwindow ("nettermclass", null );


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


// Set the parent window of netterm to hwndhost.

Win32native. setparent (hwndhost, hwndparent. Handle );



// Maximize the window

Win32native. showwindow (hwndhost. toint32 (), win32native. sw_maximize );


// Hide the netterm button on the taskbar

Hidetaskbarbutton ();

// Hide the netterm Toolbar

Hidenettermtoolbar ();


// Because the login process is very long, do not wait too long here; otherwise, the interface is like dead, so start the thread to operate

Threadstart Ts = new threadstart (

Delegate ()

{

// Automatically log on to telnet

Autologin ();

}

);

Thread thread = new thread (TS );

Thread. Start ();


Hookproc = new hookproc (myhookhandler );


// Set the hook to intercept the message loop in the main window.

// Use intptr. Zero for the current window

Hookapi. setwindowshookex (hookid. toint32 (), hookproc, intptr. Zero,

Hookapi. getcurrentthreadid ());


Return new handleref (this, hwndhost );

}


Private int myhookhandler (INT code, intptr wparam, ref MSG)

{

// If it is the message of the current host, it will be forwarded to the netterm Program

If (msg. hwnd = This. Handle)

{

Handleref = new handleref (this, hwndhost );

Win32native. sendmessage (handleref, (uint) MSG. Message, MSG. wparam, MSG. lparam );

}


Int nexthook = hookapi. callnexthookex (hookid, code, wparam, ref MSG );

Return nexthook;

}


Private void hidetaskbarbutton ()

{

Intptr vhandle = win32native. findwindow ("shell_traywnd", null );

Vhandle = win32native. findwindowex (vhandle, intptr. Zero, "rebarwindow32", intptr. Zero );

Vhandle = win32native. find+wex (vhandle, intptr. Zero, "mstaskswwclass", intptr. Zero );

Vhandle = win32native. findwindowex (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 );

}


Private void hidenettermtoolbar ()

{

Intptr toolbarwin = win32native. find1_wex (hwndhost, intptr. Zero, "toolbarwindow32", intptr. Zero );

Win32native. showwindow (toolbarwin. toint32 (), 0 );

}


Private void autologin ()

{

Thread. Sleep (10000 );

// Enter the user name

Sendstring ("yzk/N ");

Thread. Sleep (1000 );

// Enter the password

Sendstring ("123456/N ");

Thread. Sleep (1000 );

// Enter the Directory

Sendstring ("CD/mnt/HGFS/Naha/src/N ");

Thread. Sleep (1000 );

// Run character Terminal

Sendstring ("Python frontend. py/N ");

}


// Simulate the button

Private void sendstring (string S)

{

Foreach (char C in S)

{

Win32native. sendmessage (New handleref (this, hwndhost), win32native. wm_char, new intptr (C), intptr. Zero );

}

}


Protected override void destroywindowcore (handleref hwnd)

{

Handleref = new handleref (this, hwndhost );

// Close the netterm window

// Win32native. sendmessage (handleref, win32native. wm_close, intptr. Zero, intptr. Zero );


// Very pornographic and violent, directly killing

Appproc. Kill ();


// There is a bug. If netterm is already connected to a remote host, the close dialog box will pop up if it is not exited. This will cause the main program to be unable to exit.

// Several Policies: Kill netterm, send the analog key, click the "yes" button, release netterm, and let the user decide. It's just a demo.

// No Main Menu bug

// Potential bugs may occur due to the interception of message loops.


Win32native. destroywindow (hwnd. Handle );

Hookapi. unhookwindowshookex (hookid );

}

}

}



==================================== Tradenettermhost. CS ============================================== ====

Public partial class tradenettermhost: usercontrol

{

Private nettermhost ch;

Public tradenettermhost ()

{

Win32native. initcommoncontrols ();

Initializecomponent ();

Ch = new nettermhost ();

This. win32hosterborder. Child = CH;


Loaded + = new routedeventhandler (tradenettermhost_loaded );

}


Void tradenettermhost_loaded (Object sender, routedeventargs E)

{

// Set the netterm container as the focus, otherwise the message will not be sent to it

Win32native. setfocus (ch. Handle );

}

}

To be honest, please note the power from cool (www. aspcool. com ).

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.