今天用WPF程序給一個第三方程序做插件,該程序支持通過菜單擴展的方式集成第三方程序,看起來像是彈出一個對話框。
但是,由於新寫的WPF程序和原程序是沒有任何關系的,一旦原程序重新獲取焦點時,新彈出的WPF程序窗口就會切換到后台,看起來就不像子窗口了。看了一下之前的人們的做法,大多是將新蹦出來的窗口設置為TopMost,但這樣就又引入了改窗口不能切換到后台隱藏的問題。
在網上搜了一下,找到了如下解決方法:http://stackoverflow.com/questions/2599053/how-to-set-win32-window-as-owner-of-wpf-window。具體就是通過WindowInteropHelper將外部窗口設置為Owner。
var helper = new WindowInteropHelper(myWpfChildWindow);
helper->Owner = mainWindowHWND;
這樣做確實解決問題了,但反過來一想,如果要讓外部窗口作為WPF的子窗口,就無法用這個方法了。由於WPF程序本身就是調用的WindowsAPI,肯定WindowsAPI是支持兩個不相干的窗口的父子關系設置的,便在referencesource上看了一下其源碼,用的是如下代碼:
UnsafeNativeMethods.SetWindowLong(new HandleRef(null, CriticalHandle),
NativeMethods.GWL_HWNDPARENT,
_ownerHandle);
也就是說,它調用的是API SetWindowLong:
LONG WINAPI SetWindowLong(
_In_ HWND hWnd,
_In_ int nIndex,
_In_ LONG dwNewLong
);
它有三個參數,第一個參數傳入子窗口Handle, 第二個參數傳入GWL_HWNDPARENT,第三個傳入父窗口Handle。不過,MSDN上同時寫着不建議使用這種方式設置父子關系,而需要用SetParent。我試了一下,用這種方式可以,反而用SetParent不行,既然微軟自己都在用,暫且先用着,后續發現有問題再補充說明。