簡體   English   中英

啟動另一個應用程序作為彈出窗口

[英]launch another application as popup window

我有一個MFC應用程序,它會作為彈出窗口啟動其他(通用窗口,黑盒)應用程序,並等待其完成。 父母與孩子之間不需要溝通/互動,應避免。 僅需要“子應用程序表現為父應用程序的模式對話框”。 正確的方法是什么?

可以在以下位置看到“啟動另一個應用程序作為窗口”的示例: 將應用程序激活為另一個應用程序的窗口/彈出窗口,從而導致http://www.codeproject.com/Articles/18724/Hosting-exe-applications-進入一個對話 (這不是我想要的,我想要模式彈出行為)

為簡單起見,我們可以假設啟動和啟動的應用程序都具有單個“堆棧”窗口(一個帶有模態對話框的主窗口可以具有自己的模態對話框)。

我當前的偽代碼(為簡單起見,省略了錯誤處理和回調函數)

//get the current MFC dialog of launcher program we are launching the other app from
parentWnd = AfxGetMainWnd()->GetActiveWindow(); 
parentHwnd = parentWnd->GetSafeHwnd(); //HWND

// launch child and retrieve basic info from PROCESSINFO structure
CreateProcess(childExecutable); // => childProcessHandle, childProcessId 

//get the "main" window of child application
EnumWindows(EnumProc_That_Retrieves_TopLevelWindow_With_childProcessId); // => childHwnd

//link the child window as popup
SetWindowLong(childHwnd, GW_OWNER, parentHwnd);

//disable input into parent window
parentWnd->EnableWindow(FALSE);

//remove taskbar entry for child
SetWindowLong(child, GWL_EXSTYLE, GetWindowLong(child, GWL_EXSTYLE)&~WS_APPWINDOW);

//now keep waiting for the child process termination and process parent messages (e.g. WM_PAINT)
while (MsgWaitForMultipleObjects(childProcessHandle and process QS_ALLINPUT) {
   while (PeekMessage(PM_NOREMOVE)) AfxGetApp()->PumpMessage();
}

//re-enable input into parent window
parentWnd->EnableWindow(TRUE);

現在,我較小的問題是前景視覺樣式(例如,前景=藍色標題欄與背景=灰色標題欄)和鍵盤輸入焦點行為:

1)最初刪除子級WS_APPWINDOW樣式將從子級應用程序中刪除前景視覺和輸入焦點。 在這一點上,沒有應用程序具有焦點。

2)當用戶單擊任何父應用程序窗口時,將切換子前景的視覺樣式。 鍵盤焦點保留在子應用程序中。 示例:子應用具有前景+焦點->第一次單擊父項->子失去前景,保持焦點->單擊父項第二次->子項獲得前景,保持焦點->等等。

預期的行為(“常規” MFC彈出窗口會執行的操作):子應用程序具有前景+焦點->單擊父項->子標題欄短暫閃爍並保留前景+焦點子應用程序沒有前景+焦點->單擊父項->子標題欄獲得前景和鍵盤焦點

現在這是最嚴重的問題 :3)我遇到了一個MFC應用程序,當單獨啟動該應用程序時,用戶可以打開“模式對話框堆棧” A-> B-> C-> D-> E,Windows的所有權完全匹配(E由D擁有,D由C擁有,等等)。 但是,如果我從MFC應用程序(M)中打開它,則所有權看起來就像M-> A-> B-> C,D,E(C,D,E都由B擁有,B由A擁有,A擁有通過我的應用窗口M)。 這會導致“沒有支持的堆棧” http://blogs.msdn.com/b/oldnewthing/archive/2005/02/24/379635.aspx問題。 當我刪除SetWindowLong(childHwnd, GW_OWNER, parentHwnd)時,此行為消失了SetWindowLong(childHwnd, GW_OWNER, parentHwnd)因此弄亂所有權可能會觸發子應用程序的有害行為,但是如果沒有這樣做,我似乎無法保證模式對話框的前提是“一個位於另一個之上” 。

因此,還有一個大問題:執行此任務並避免出現我所描述的問題的正確方法是什么?

編輯

到目前為止的解決方案

我們必須避免像@mfc所建議的那樣弄亂所有者擁有的結構,因此,任務基本上是以另一種方式為我們的父子對重新實現窗口管理器的這一方面。 我已經使用Windows Hooks建立了解決方案的原型。 但是,完成它似乎相當復雜且乏味,因此我決定采用另一種原始方法(截止日期,截止日期)。 為了舉例,我將描述兩者的基本思想。

掛鈎解決方案

免責聲明:只有父焦點掛鈎已被確認可以正常工作,其余都是理論上的努力。 也許有一個更清潔/更輕量級的實現,可能會在實際的Windows窗口管理器實現中獲得啟發(記住整個要點是避免設置GW_OWNER,該功能對於窗口管理器來說很好用,但是會破壞子黑盒應用程序的行為)。

  • 在子程序運行時(間歇地)無窗口的情況下,將一些“子程序運行時忽略輸入”添加到父消息循環中
  • 創建共享內存和結構以為每次調用保留[parentPid,parentHwnd,childPid]
  • 為[父非擁有窗口的列表,它們的UI線程,子鈎子]創建DLL實例內存
  • 將系統范圍內的鈎子鏈接到WH_CBT-> HCBT_CREATEWND,如果childPid匹配,則在列表中注冊窗口,僅為該子線程注冊另一個鈎子HCBT_ACTIVATE(如果尚未存在)
  • 將系統范圍內的鈎子連接到WH_CBT-> HCBT_DESTROYWND,如果childPid匹配,則取消注冊列表中的窗口,如果這是給定線程的最后一個窗口,則取消注冊HCBT_ACTIVATE鈎子,如果這是子應用程序的最后一個窗口,則取消鈎子父級HCBT_ACTIVATE鈎子並聚焦父級
  • 父線程HCBT_ACTIVATE掛鈎會阻止獲得焦點,而是使用EnumWindows來聚焦子應用程序。
  • 如果目標是父對象,則子線程HCBT_ACTIVATE掛鈎可防止焦點丟失,以Z順序將父對象保持在子對象下方
  • 創建掛起的子進程並僅在掛鈎到位時恢復
  • 記得到處解鈎

原始方法

基本上在先前解決方案的第一點上應用了焦點開關,當單擊父對象時,它會在子對象之間來回閃爍,從而在子對象上閃爍。

  • 對於子應用程序運行時的父消息循環中的“忽略子項運行時忽略輸入”(丟棄各種按鍵,單擊等消息),請使用EnumWindows代替子應用程序。

更改不屬於您的其他窗口的父/子關系非常棘手且容易出錯。 如果啟動器程序與啟動的程序沒有通信,並且主要目的是避免與啟動器有任何UI,則可以使用ShowWindow(SW_HIDE)在成功啟動輔助程序后簡單地隱藏啟動器。 在隱藏模式下,它將繼續監視啟動的程序,並在輔助程序終止時取消隱藏自身。

嘗試使用API​​函數“ ShellExecute()”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM