WPF中嵌入普通Win32程式的方法
公司現在在研發基於.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
etterm
etterm.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
etterm
etterm.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
");
Thread.Sleep(1000);
//輸密碼
SendString("123456
");
Thread.Sleep(1000);
//進入目錄
SendString("cd /mnt/hgfs/NAHA/src/
");
Thread.Sleep(1000);
//執行字元終端
SendString("python FrontEnd.py
");
}
//模擬按鍵
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);
}
}
在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
etterm
etterm.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
etterm
etterm.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
");
Thread.Sleep(1000);
//輸密碼
SendString("123456
");
Thread.Sleep(1000);
//進入目錄
SendString("cd /mnt/hgfs/NAHA/src/
");
Thread.Sleep(1000);
//執行字元終端
SendString("python FrontEnd.py
");
}
//模擬按鍵
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);
}
}
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12921506/viewspace-259940/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Win32 SDK封閉例項——普通的Windows程式(翻譯) (轉)Win32Windows
- 在WPF中嵌入WebBrowser視覺化頁面Web視覺化
- WPF中嵌入Office編輯器(支援Word、Excel、PPT、Visio等)Excel
- smarty 雙引號中嵌入變數的方法變數
- 在普通的"類庫"專案中新增 WPF 的 Window 物件物件
- WPF和js互動 呼叫窗體中的方法JS
- WPF窗體中嵌入/使用WinForm類/控制元件(基於.NET Core)ORM控制元件
- win32之取畫刷的方法Win32
- 微信小程式掃描普通二維碼開啟小程式的方法微信小程式
- WPF中的命令模式:打造清晰、可重用的程式碼利器模式
- extern "C"的用途—在C++程式碼中嵌入C程式碼C++C程式
- win32的建立視窗程式碼Win32
- 在JavaFX程式中嵌入Swing內容Java
- 把一個JVM嵌入到本地程式中JVM
- 嵌入式開發程式碼中的extern "C" {的作用
- Web應用中的普通java程式獲取資原始檔WebJava
- JSP頁面中嵌入UEditor編輯器方法JS
- WPF中的Popup控制元件控制元件
- C# 獲取程式路徑的幾種方法及其區別【WPF】C#
- 比較簡單的win32 OpenGL 程式Win32
- WPF 程式使用 MediatR
- 手機設定在文章中嵌入程式碼塊
- WPF入門教程系列十八——WPF中的資料繫結(四)
- 普通人眼中的程式設計師 VS 程式設計師眼中的普通人程式設計師
- WPF 穩定的全屏化視窗方法
- Swift-方法排程-類的普通方法底層探究Swift
- 嵌入式linux應用程式移植方法總結Linux
- Win32彙編教程二 Win32彙編程式的結構和語法 (轉)Win32
- WPF中Popup控制元件的使用控制元件
- wpf 中阿里圖示庫的使用阿里
- union 的概念及在嵌入式程式設計中的應用程式設計
- C#中普通快取的使用C#快取
- django中嵌入html的語法DjangoHTML
- 嵌入式開發和普通伺服器開發的前景哪個更好?伺服器
- 痞子衡嵌入式:嵌入式Cortex-M中斷向量表原理及其重定向方法
- 如何在batch指令碼中嵌入python程式碼BAT指令碼Python
- .NET桌面程式(WINFORM或WPF)的部署ORM
- WPF打包獨立執行的程式