2011-03-09 156 views
1

在32位程序中,如何獲取打開/保存文件對話框以顯示64位系統的System32文件夾中的文件?32位OpenFileDialog - > 64位System32?

Wow64DisableWow64FsRedirection不起作用,因爲由於某種原因它不適用於對話框,我猜是因爲它在不同的線程上。當然,使用SysNative不起作用,因爲用戶不是。知道什麼內部發生了的,他只是想在電腦上看到的「實際」的文件)


這裏是另一種方式來問這個問題:

是否任何 32位程序瀏覽打開文件對話框中的64位System32文件夾?

+0

當你想在system32文件夾中顯示文件時,不應該在對話框中設置正確的初始文件夾嗎? – GolezTrol 2011-03-09 06:48:49

+0

@GolezTrol:這是一個文本編輯器(以及我製作的類似類型的應用程序),其中*我*不會對用戶選擇的內容有任何偏好,但是如果他想要在'System32'中選擇一些東西,然後他不能。無論如何,這不是一個真正的解決方案,但只是一個解決方法,並不真正起作用。 (謝謝你的建議。) – Mehrdad 2011-03-09 06:50:29

+0

如果你使用C#,爲什麼不爲'AnyCPU編譯而不用擔心呢? – Gabe 2011-03-09 08:32:28

回答

4

我相信這根本不可能。

即使您可以讓對話框顯示這些文件,當它們返回到您的32位進程時,它們的名稱是什麼? Sysnative有點破解,在任何情況下XP 64都不可用。這只是重載system32名稱的結果。

另一個思想實驗。如果可能的話,您需要執行枚舉的線程禁用重定向。由於該線程超出了您的控制範圍,因此必須有發佈選項才能禁用該線程。沒有。如果您要加載DLL,因爲這會導致在32位進程嘗試加載外殼擴展時導致DLL加載失敗,因此您可以禁用外部重定向,因爲您將獲得加載DLL的權限錯誤的

我想你應該寫一個64位的程序,如果你想解決這個限制。

+0

這與禁用重定向後使用標準FindFirstFile API枚舉文件有什麼不同?它會返回文件的真實名稱,很簡單。 .. – Mehrdad 2011-03-09 07:54:06

+0

如果它將system32返回到你的32位進程,那麼當你訪問該文件時,你會被重定向到syswow64。 – 2011-03-09 07:57:41

+0

@David:不,我不會,因爲我會禁用重定向...這就是'Wow64DisableWow64FsRedirection'的全部重點。 – Mehrdad 2011-03-09 07:58:36

1

我對此有一個工作解決方案。這是一種黑客,但它的工作原理。

在我展示解決方案之前的簡短聲明。我主要同意Hefferman。這並不意味着。我實際上並不推薦這樣做的代碼。這是沒有32位文本編輯器,文字處理器(包括32位Office),或正常的應用程序支持。 64位系統上的普通用戶不直接在系統目錄中打開或保存文件。而且,大多數非管理員用戶無論如何都無權觸摸文件。微軟重新定向文件系統的原因非常好,適用於32位應用程序。不要試圖與它戰鬥。

現在解決方案。

訣竅是在DllMain中爲每個DLL_THREAD_ATTACH回調調用Wow64DisableWow64FsRedirection。

首先創建一個簡單的DLL,它只有一個DllMain並導出一些函數:「StartDisableRedirect」和「DisableRedirection」。

bool g_fDisableRedirect = false; 

__declspec(dllexport) 
int DisableRedirection() 
{ 
    void* pVoid = NULL; 
    Wow64DisableWow64FsRedirection(&pVoid); 
    return 0; 
} 


__declspec(dllexport) 
int StartDisableRedirect() 
{ 
    g_fDisableRedirect = true; 
    return 0; 
} 



BOOL APIENTRY DllMain(HMODULE hModule, 
         DWORD ul_reason_for_call, 
         LPVOID lpReserved 
        ) 
{ 
    switch (ul_reason_for_call) 
    { 
    case DLL_PROCESS_ATTACH: 
    case DLL_THREAD_ATTACH: 
     { 
      void* pVoid = NULL; 

      if (g_fDisableRedirect) 
      { 
       DisableRedirection(); 
      } 
      break; 
     } 

    case DLL_THREAD_DETACH: 
    case DLL_PROCESS_DETACH: 
     break; 
    } 
    return TRUE; 
} 

讓您的二進制文件(EXE或DLL)直接與此DLL鏈接。然後,在調用GetOpenFileName之前,調用StartDisableRedirect(使後續線程不重定向)和DisableRedirect(用於當前線程)。

我故意做了一個「Start」函數,使得所有的DLL(包括系統DLL)都在鉤子實際開始處理線程之前被加載。我不想假設實現Wow64Disable的DLL會在我的DLL之前加載。從DllMain調用代碼時,必須非常小心(閱讀:不應該)。

extern int StartDisableRedirect(); 
extern int DisableRedirection(); 


void OnFile(HWND hwndParent) 
{ 

    StartDisableRedirect(); 

    DisableRedirection(); 


    OPENFILENAME ofn = {}; 
    WCHAR szFile[MAX_PATH*2] = {}; 

    ofn.lStructSize = sizeof(ofn); 
    ofn.hwndOwner = hwndParent; 
    ofn.lpstrFilter = L"All Files\0*.*\0\0"; 
    ofn.nFilterIndex = 1; 
    ofn.lpstrFile = szFile; 
    ofn.nMaxFile = ARRAYSIZE(szFile); 
    ofn.Flags = OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST; 

    ::GetOpenFileName(&ofn); 

} 
+0

哇,真好! o__o所以......這是如何處理系統DLL在不同線程中延遲加載的情況(這種情況在第一次加載對話框時似乎幾乎發生)? – Mehrdad 2011-03-09 09:36:50

+0

@Mehrdad它不會。外殼擴展將會殺死這個。 – 2011-03-09 09:39:41

+0

@David:我當時並沒有真正在談論shell擴展,我只是在討論* regular * DLLs,比如'Ole32.dll',它們是windows的正常組成部分,並且在每一種情況下都會延遲加載。我很好奇這是如何處理的,因爲@selbie顯然說它是有效的。 :) – Mehrdad 2011-03-09 09:42:38

0

這是安裝程序的常見問題。人們希望爲32位和64位系統提供一個安裝程序可執行文件,這意味着它必須是32位。然而,32位安裝程序無法將64位可執行文件放在正確的位置。解決方案as described by Raymond Chen將有一個單獨的64位安裝程序,它可以在64位機器上由32位版本調用。

您將創建一個64位程序,其任務是以您的應用程序窗口作爲所有者打開一個通用對話框。在64位系統上,您只需創建打開對話框的進程,並將傳遞給GetOpenFileName或其他參數的參數傳遞給它。你可以聽stdout上的文件名或使用其他IPC機制。請記住在打開返回的文件時使用Wow64DisableWow64FsRedirection!在另一個進程中運行UI似乎很笨重,但它對用戶來說是無縫的,許多Web瀏覽器在不同的進程中運行不同的標籤或插件。

如果你細使用Vista或更高,則可以使用IFileDialog接口,這將允許您添加一個「地方」爲SysNative目錄。這樣,您的用戶仍然可以在需要時訪問這些文件。甚至可能有一種簡單的方法來重定向事物,以便當有人點擊System32目錄時,您將它們帶到SysNative

+0

跨進程的東西不適合我,但有趣的想法'IFileDialog'。 – Mehrdad 2011-03-09 10:26:22

+0

@Mehrdad:當你說它不起作用時,你的意思是你不能使用解決方案,或者它實際上失敗了? – Gabe 2011-03-09 10:46:33

+0

我的意思是前者。 :\感謝您的想法,但。 – Mehrdad 2011-03-09 11:00:38