首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

跨進程修改已開啟檔案對話框的瀏覽路徑

     編輯:VC 教學

問題情境

需控制他人程式 (已顯示) 的「另存新檔」對話框,強制其瀏覽至指定目錄。標準 CFileDialog::m_ofn.lpstrInitialDir 僅對尚未顯示的對話框有效。對於既有視窗,需透過跨進程視窗操作實現。

核心思路:模擬使用者操作

觀察發現:在檔名編輯框輸入目錄路徑並按「儲存」鈕,對話框會切換至該目錄而不關閉。利用此行為,流程如下:

  1. 尋找目標對話框視窗 (FindWindow)。
  2. 列舉子控制項,定位「檔名編輯框」 (Class Edit) 與「儲存按鈕」 (Class Button, 標題「儲存(&S)」)。
  3. 備份編輯框原始內容。
  4. 發送 WM_SETTEXT 將指定路徑寫入編輯框 (不可用 SetWindowText,跨進程失效)。
  5. 發送 WM_LBUTTONDOWN + WM_LBUTTONUP 模擬點擊儲存按鈕。
  6. 還原編輯框原始內容。

關鍵程式碼實作

void ForceSaveDialogPath(const CString& sPath)
{
    // 1. 尋找「另存為」對話框 (標題可能因語系不同需調整)
    CWnd* pWnd = FindWindow(NULL, _T("另存為"));
    if (!pWnd) return;

    CString filename;
    TCHAR BUF[512];
    CWnd* pEdit = NULL;

    // 2. 列舉子視窗
    CWnd* pChild = pWnd->GetWindow(GW_CHILD);
    char* buf = new char[512];

    while (pChild)
    {
        ::GetClassName(pChild->GetSafeHwnd(), buf, 512);
        CString cls(buf); cls.TrimRight();

        if (cls == _T("Edit")) // 檔名編輯框
        {
            pEdit = pChild;
            pChild->SendMessage(WM_GETTEXT, sizeof(BUF)/sizeof(TCHAR), (LPARAM)BUF);
            filename = BUF; // 備份原始檔名
        }
        else if (cls == _T("Button")) // 按鈕
        {
            pChild->SendMessage(WM_GETTEXT, sizeof(BUF)/sizeof(TCHAR), (LPARAM)BUF);
            CString btnText(BUF); btnText.TrimRight();

            if (btnText == _T("儲存(&S)")) // 找到儲存按鈕
            {
                // 3. 寫入目標路徑 (跨進程必須用 WM_SETTEXT)
                lstrcpy(BUF, sPath);
                pEdit->SendMessage(WM_SETTEXT, 0, (LPARAM)BUF);

                // 4. 模擬點擊儲存按鈕
                ::SendMessage(pChild->GetSafeHwnd(), WM_LBUTTONDOWN, 0, 0);
                ::SendMessage(pChild->GetSafeHwnd(), WM_LBUTTONUP, 0, 0);
            }
        }

        pChild = pChild->GetNextWindow();
    }

    // 5. 還原原始檔名
    if (pEdit)
        pEdit->SendMessage(WM_SETTEXT, 0, (LPARAM)(LPCTSTR)filename);

    delete[] buf;
}

關鍵技術點

技術說明
FindWindow依視窗標題尋找目標對話框。注意:標題隨系統語系變化 (如 "Save As"),實際部署需多語系支援。
GetClassName + 列舉子視窗識別編輯框 (Edit) 與按鈕 (Button)。
WM_SETTEXT vs SetWindowText跨進程設定文字 必須 使用 SendMessage(WM_SETTEXT),SetWindowText 內部同樣發送此訊息但可能因安全限制失效。
模擬點擊發送 WM_LBUTTONDOWN/UP 至按鈕視窗,觸發其 BN_CLICKED 通知。
還原檔名避免干擾使用者原本輸入的檔名。

限制與風險

  • 視窗標題/按鈕文字語系相依:需針對目標 OS 語系調整比對字串。
  • UI 自動化脆弱性:對話框版本更新、佈局變更可能導致失效。
  • 安全性限制:UIPI (User Interface Privilege Isolation) 可能阻擋高完整性進程操作低完整性視窗,或反向操作需 ChangeWindowMessageFilterEx。
  • 非標準對話框:自訂檔案對話框 (非系統 Common Dialog) 類別名/結構可能不同。

替代方案

  • 全域鉤子 (WH_CBT/WH_CALLWNDPROC):在對話框 WM_INITDIALOG 時修改 OPENFILENAME 結構,根治源頭但複雜度高。
  • IFileDialog 自訂對話框 (Vista+):若為自家程式,直接使用新版 API 設定 SetFolder。

結語

跨進程操作現有檔案對話框屬於「逆向 UI 自動化」範疇。雖透過 WM_SETTEXT + 模擬點擊可行,但脆弱性高、維護成本大。若為自家開發專案,強烈建議在對話框建立前以正規 API 設定初始目錄;若為第三方程式控制,請評估風險並做好版本相容測試。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved