<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    如鵬網 大學生計算機學習社區

    CowNew開源團隊

    http://www.cownew.com 郵件請聯系 about521 at 163.com

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      363 隨筆 :: 2 文章 :: 808 評論 :: 0 Trackbacks

    公司現在在研發基于.Net中WPF技術的產品,由于要兼容舊有產品,比如一些舊有的Win32程序、第三方的Win32程序等等,還要實現自動登錄這些外部Win32程序,因此必須能夠將這些程序整合到我們的系統中來,讓使用者看起來它們好像是一個程序。

    在MSDN中有專門的章節提到了在WPF中嵌入Win32控件的辦法,那就是使用 HwndHost ,只要把 Win32控件的句柄傳遞給 HwndHost 就可以了。MSDN中的例子演示的都是在同一個進程內創建的 Win32控件,我一開始認為只要通過FindWindow等Win32API得到外部Win32程序的窗口句柄,然后將窗口句柄交給 HwndHost 就可以了。實現核心代碼如下:

             protected   override   HandleRef  BuildWindowCore( HandleRef  hwndParent)

            {

                appProc =  new   Process ();

                appProc.StartInfo.WindowStyle =  ProcessWindowStyle .Hidden;

                appProc.StartInfo.FileName =  @"D:\greeninst\netterm\netterm.exe" ;

                appProc.Start();

                 //等待初始化完成,實現有點土

                 Thread .Sleep(1000);

                hwndHost =  Win32Native .FindWindow( "NetTermClass" null );

                 // 嵌入在HwnHost中的窗口必須要 設置為WS_CHILD風格

                 uint  oldStyle =  Win32Native .GetWindowLong(hwndHost,  Win32Native .GWL_STYLE);

                   Win32Native .SetWindowLong(hwndHost,  Win32Native .GWL_STYLE, (oldStyle |  Win32Native .WS_CHILD));

                 //將netterm的父窗口設置為HwndHost

                 Win32Native .SetParent(hwndHost, hwndParent.Handle);

                 return   new   HandleRef ( this , hwndHost);

            }

    這里啟動的是NetTerm這個外部程序。實踐證明我這種想法是可行的,但是唯一的問題就是雖然 外部Win32程序顯示到WPF程序中來了,但是很奇怪的是嵌入的Win32程序再也無法點擊了,點擊按鈕、輸入按鍵都不起作用,程序好像死了一樣。經過分析,我認為由于通過 SetParent 這個 Win32API 將NetTerm的父窗口設置為了 HwndHost ,這樣 NetTerm就不再有自己獨立的窗口消息循環,而是眼巴巴等著 HwndHost 這個爹給他發 消息。可能由于WPF對于消息循環的處理 不同于以前的Win32程序,導致所有的鼠標點擊、按鍵 消息都不能被傳遞給NetTerm這個兒子,這樣NetTerm就得不到任何消息,所以就像死了一樣。

    解決這個問題的思路是截獲WPF的窗口消息,然后把它通過 SendMessage 這個Win32API 轉發給NetTerm。但是找了半天也沒找到WPF的消息處理的地方,請教同事以后得知WPF根本不像傳統的Win32程序那樣有窗口消息循環,而是自己搞了一套。郁悶了一會兒,突然靈光一現:管它什么WPF不WPF,它本質上還是Win32程序,只不過是一個內部使用了DirectX技術的Win32程序而已,只要是Win32程序一定有辦法拿到它的窗口消息循環。啥辦法呢?對!就是窗口鉤子。使用 SetWindowsHookEx 這個Win32API可以截獲一個窗口所有的 消息循環,這樣只要挑出來發給 HwndHost 的消息,然后把它轉發給 NetTerm窗口就ok了。經過改造以后NetTerm終于活過來了!!!

    解決了最核心的問題就該處理普通問題了,主要問題及對策如下:

    1、隱藏NetTerm的窗口邊框,這樣看起來就感覺不出來NetTerm是一個外部程序了。思路很簡單使用 GetWindowLong 得到窗口原來的風格,然后再附加一個 WS_BORDER 風格就ok了。

    //設置為WS_CHILD風格

                 uint  oldStyle =  Win32Native .GetWindowLong(hwndHost,  Win32Native .GWL_STYLE);

                 //&~WS_BORDER去掉邊框,這樣看起來更像一個內嵌的程序,注意()的作用,改變默認的優先級

                 Win32Native .SetWindowLong(hwndHost,  Win32Native .GWL_STYLE, (oldStyle |  Win32Native .WS_CHILD)&~ Win32Native .WS_BORDER);

    2、隱藏NetTerm在任務欄上的按鈕

    只要找到任務欄的句柄,然后首先向它發送TB_BUTTONCOUNT得到它上邊按鈕的個數,由于NetTerm是剛剛啟動的,可以認為最后一個按鈕就是NetTerm的按鈕,只要向任務欄的句柄發送TB_DELETEBUTTON消息將最后一個按鈕刪掉就ok了。

            private void HideTaskBarButton()

            {

                IntPtr vHandle = Win32Native.FindWindow("Shell_TrayWnd", null);

                vHandle = Win32Native.FindWindowEx(vHandle, IntPtr.Zero,

     "ReBarWindow32", IntPtr.Zero);

                vHandle = Win32Native.FindWindowEx(vHandle, 

    IntPtr.Zero, "MSTaskSwWClass", IntPtr.Zero);

                vHandle = Win32Native.FindWindowEx(vHandle, IntPtr.Zero, 

    "ToolbarWindow32", IntPtr.Zero);

                //得到任務欄中按鈕的數目

                int vCount = Win32Native.SendMessage(new HandleRef(this, vHandle), 

    (uint)Win32Native.TB_BUTTONCOUNT, IntPtr.Zero, IntPtr.Zero).ToInt32();

                

                //認為最后一個按鈕就是被嵌套程序的按鈕,刪除它

                Win32Native.SendMessage(new HandleRef(this, vHandle), 

    Win32Native.TB_DELETEBUTTON, new IntPtr(vCount - 1), IntPtr.Zero);

            }

    這是在WinXP下的處理。好像Win2000、Vista的任務欄的結構是不同的,如果需要運行在這些OS下需要做進一步的改進。

    3、 自動登錄。在NetTerm啟動以后自動登錄到服務器,并且自動輸入用戶名、密碼,并且啟動指定的程序。NetTerm支持在啟動參數中指定要連接的服務器地址,這樣可以解決自動登錄到服務器的問題;使用 SendMessage( handle , Win32Native.WM_CHAR,  ch , IntPtr.Zero) 向NetTerm窗口發送模擬按鍵就可以實現自動鍵入Linux指令的效果。由于Linux指令需要一定的處理的時間,所以每發完一條指令就要Sleep一會兒以防止鍵入指令速度過快。

    運行效果如下:
    主要代碼如下,
    Win32Native .cs是我們寫的一個對Win32API的調用聲明,都是簡單的PInvoke聲明,由于尺寸比較大這里就不貼出來了,大家可以查MSDN自己來聲明。

    =======================================NetTermHost.cs============================

    namespace Client.Pages

    {

        class NetTermHost : HwndHost

        {

            public IntPtr hwndHost;

            private IntPtr hookId = new IntPtr(3);

            private HookProc 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";

                //設置要連接的主機名,這樣啟動以后就立即連接了

                appProc.StartInfo.Arguments = "192.168.88.128";

                appProc.Start();

                //等待初始化完成,實現有點土

                Thread.Sleep(1000);

                hwndHost = Win32Native.FindWindow("NetTermClass", null);

                //設置為WS_CHILD風格

                uint oldStyle = Win32Native.GetWindowLong(hwndHost, Win32Native.GWL_STYLE);

                //&~WS_BORDER去掉邊框,這樣看起來更像一個內嵌的程序,注意()的作用,改變默認的優先級

                Win32Native.SetWindowLong(hwndHost, Win32Native.GWL_STYLE, (oldStyle | Win32Native.WS_CHILD)&~Win32Native.WS_BORDER);

                //將netterm的父窗口設置為HwndHost,爹地我來了

                Win32Native.SetParent(hwndHost, hwndParent.Handle);

         

          //窗口最大化

                Win32Native.ShowWindow(hwndHost.ToInt32(), Win32Native.SW_MAXIMIZE);

          //隱藏netterm在任務欄上的按鈕

                HideTaskBarButton();

          //隱藏netterm的工具欄

                HideNetTermToolBar();

                //由于登錄過程非常長,所以不要在這里等太久,否則界面像死了一樣,所以啟動線程來操作

                ThreadStart ts = new ThreadStart(

                                delegate()

                                {

                    //自動登錄telnet

                                    AutoLogin();

                                }

                            );

                Thread thread = new Thread(ts);

                thread.Start();       

                hookProc = new HookProc(MyHookHandler);

                //設置鉤子,截獲主窗口界面消息循環

                //對當前的窗口,使用IntPtr.Zero

                HookApi.SetWindowsHookEx(hookId.ToInt32(), hookProc, IntPtr.Zero, 

                    HookApi.GetCurrentThreadId());

                return new HandleRef(this, hwndHost);

            }

            private int MyHookHandler(int code, IntPtr wparam, ref MSG msg)

            {

                //如果是當前Host的消息,則將其轉發給netterm程序

                if (msg.hwnd == this.Handle)

                {

                    HandleRef 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.FindWindowEx(vHandle, IntPtr.Zero, "MSTaskSwWClass", IntPtr.Zero);

                vHandle = Win32Native.FindWindowEx(vHandle, IntPtr.Zero, "ToolbarWindow32", IntPtr.Zero);

                //得到任務欄中按鈕的數目

                int vCount = Win32Native.SendMessage(new HandleRef(this, vHandle), (uint)Win32Native.TB_BUTTONCOUNT, IntPtr.Zero, IntPtr.Zero).ToInt32();

                

                //認為最后一個按鈕就是被嵌套程序的按鈕,刪除它

                Win32Native.SendMessage(new HandleRef(this, vHandle), Win32Native.TB_DELETEBUTTON, new IntPtr(vCount - 1), IntPtr.Zero);

            }

            private void HideNetTermToolBar()

            {

                IntPtr toolBarWin = Win32Native.FindWindowEx(hwndHost, IntPtr.Zero, "ToolbarWindow32", IntPtr.Zero);

                Win32Native.ShowWindow(toolBarWin.ToInt32(), 0);

            }

            private void AutoLogin()

            {      

                Thread.Sleep(10000);

          //輸用戶名

                SendString("yzk\n");

                Thread.Sleep(1000);

          //輸密碼

                SendString("123456\n");

                Thread.Sleep(1000);

          //進入目錄

                SendString("cd /mnt/hgfs/NAHA/src/\n");

                Thread.Sleep(1000);

          //運行字符終端

                SendString("python FrontEnd.py\n");

            }

        //模擬按鍵

            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 handleRef = new HandleRef(this, hwndHost);

                //關閉netterm窗口

                //Win32Native.SendMessage(handleRef, Win32Native.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);

                //很黃很暴力,直接殺死

                appProc.Kill();

                //有bug,如果netterm已經連上遠程主機,那么如果不退出就close的話會彈出對話框,這就會造成主程序無法退出

                //幾種策略:殺死netterm、發送模擬鍵點擊“是”按鈕、把netterm釋放出來讓用戶決定、只是demo而已不管它

                //沒有主菜單的bug

                //由于是攔截消息循環搞的,所以有可能有潛在的bug

                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)

      {

        //設置netterm容器為焦點,否則消息不會發給它

        Win32Native.SetFocus(ch.Handle);

      }

    }

    posted on 2008-04-24 12:48 CowNew開源團隊 閱讀(6161) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 精品少妇人妻AV免费久久洗澡 | 毛片免费在线观看网站| 亚洲国产成人a精品不卡在线| 久久亚洲sm情趣捆绑调教| 曰批免费视频播放免费| 可以免费看黄视频的网站| 亚洲国产精品一区二区久久hs | 国产无限免费观看黄网站| 国产小视频在线免费| 国产午夜亚洲精品| 91成人免费在线视频| 亚洲精品一卡2卡3卡三卡四卡| 免费观看男人吊女人视频| 亚洲中文字幕久久精品无码喷水| 国产精品亚洲va在线观看| 免费爱爱的视频太爽了 | 免费又黄又硬又爽大片| 亚洲国产精品无码第一区二区三区 | 久久WWW免费人成人片| 亚洲三级视频在线观看| 亚州免费一级毛片| 亚洲日本香蕉视频| 久久WWW免费人成人片| 嫩草影院在线播放www免费观看| 国产亚洲综合久久系列| 免费女人高潮流视频在线观看| 久久精品视频亚洲| 最近2019中文字幕免费大全5| ww亚洲ww在线观看国产| 日韩精品视频免费网址| 人成午夜免费大片在线观看| 国产裸模视频免费区无码| 久久精品私人影院免费看| CAOPORM国产精品视频免费| 麻豆亚洲AV永久无码精品久久 | 337p日本欧洲亚洲大胆裸体艺术| 免费高清资源黄网站在线观看| 999久久久免费精品播放| 中文在线观看免费网站| 亚洲AV无码国产丝袜在线观看 | 亚洲国产精品成人综合色在线婷婷 |