2017-05-06 57 views
1

我一直在我的頭撞在牆上我可以去做這件事。基本上我的應用程序需要找出使用winapi的C++中的窗口中的活動文件瀏覽器(即前景中的文件瀏覽器)的目錄路徑。如何獲得一個活躍的文件資源管理器窗口的路徑在C + + winapi

取而代之的是:

TCHAR* getWindowDir(){ 
TCHAR* windowTitle = new TCHAR[MAX_PATH]; 
HWND windowHandle = GetForegroundWindow(); 
GetWindowText(windowHandle,windowTitle,MAX_PATH); 
return windowTitle; 
} 

這顯然返回窗口標題我想它返回Active Directory中。

+0

也許這線程可以給你一個提示:http://stackoverflow.com/questions/20960316/get-folder-path-from-explorer-window – OnNIX

+0

HTTPS ://en.wikipedia.org/wiki/Dangling_pointer –

+0

停止黑客入侵併使用shell。另外,如果您打算調用Win32函數,請養成檢查錯誤的習慣。在你的危險忽略返回值。 –

回答

4

創建一個IShellWindows的實例並使用它來枚舉所有當前打開的資源管理器窗口。使用各種相關的界面,您可以從IShellWindows列舉的每個項目獲得窗口句柄和當前文件夾,格式爲PIDL。如果窗口句柄等於GetForegroundWindow()的結果,則將PIDL轉換爲路徑。

在下面我介紹一些獲取有關所有資源管理器窗口的信息的代碼。它部分基於code of Raymond Chen,但使用智能指針來實現更脆弱和更簡潔的代碼。我還通過例外添加了錯誤處理。

首先需要的包括和一些實用代碼:

#include <Windows.h> 
#include <shlobj.h> 
#include <atlcomcli.h> // for COM smart pointers 
#include <vector> 
#include <system_error> 
#include <memory> 

// Throw a std::system_error if the HRESULT indicates failure. 
template< typename T > 
void ThrowIfFailed(HRESULT hr, T&& msg) 
{ 
    if(FAILED(hr)) 
     throw std::system_error{ hr, std::system_category(), std::forward<T>(msg) }; 
} 

// Deleter for a PIDL allocated by the shell. 
struct CoTaskMemDeleter 
{ 
    void operator()(ITEMIDLIST* pidl) const { ::CoTaskMemFree(pidl); } 
}; 
// A smart pointer for PIDLs. 
using UniquePidlPtr = std::unique_ptr< ITEMIDLIST, CoTaskMemDeleter >; 

現在我們定義一個函數GetCurrentExplorerFolders()返回當前所有打開的IE窗口,包括窗口句柄和當前文件夾的PIDL信息。

// Return value of GetCurrentExplorerFolders() 
struct ExplorerFolderInfo 
{ 
    HWND hwnd = nullptr; // window handle of explorer 
    UniquePidlPtr pidl; // PIDL that points to current folder 
}; 

// Get information about all currently open explorer windows. 
// Throws std::system_error exception to report errors. 
std::vector<ExplorerFolderInfo> GetCurrentExplorerFolders() 
{ 
    CComPtr<IShellWindows> pshWindows; 
    ThrowIfFailed(
     pshWindows.CoCreateInstance(CLSID_ShellWindows), 
     "Could not create instance of IShellWindows"); 

    long count = 0; 
    ThrowIfFailed(
     pshWindows->get_Count(&count), 
     "Could not get number of shell windows"); 

    std::vector<ExplorerFolderInfo> result; 
    result.reserve(count); 

    for(long i = 0; i < count; ++i) 
    { 
     ExplorerFolderInfo info; 

     CComVariant vi{ i }; 
     CComPtr<IDispatch> pDisp; 
     ThrowIfFailed(
      pshWindows->Item(vi, &pDisp), 
      "Could not get item from IShellWindows"); 

     if(! pDisp) 
      // Skip - this shell window was registered with a NULL IDispatch 
      continue; 

     CComQIPtr<IWebBrowserApp> pApp{ pDisp }; 
     if(! pApp) 
      // This window doesn't implement IWebBrowserApp 
      continue; 

     // Get the window handle. 
     pApp->get_HWND(reinterpret_cast<SHANDLE_PTR*>(&info.hwnd)); 

     CComQIPtr<IServiceProvider> psp{ pApp }; 
     if(! psp) 
      // This window doesn't implement IServiceProvider 
      continue; 

     CComPtr<IShellBrowser> pBrowser; 
     if(FAILED(psp->QueryService(SID_STopLevelBrowser, &pBrowser))) 
      // This window doesn't provide IShellBrowser 
      continue; 

     CComPtr<IShellView> pShellView; 
     if(FAILED(pBrowser->QueryActiveShellView(&pShellView))) 
      // For some reason there is no active shell view 
      continue; 

     CComQIPtr<IFolderView> pFolderView{ pShellView }; 
     if(! pFolderView) 
      // The shell view doesn't implement IFolderView 
      continue; 

     // Get the interface from which we can finally query the PIDL of 
     // the current folder. 
     CComPtr<IPersistFolder2> pFolder; 
     if(FAILED(pFolderView->GetFolder(IID_IPersistFolder2, (void**) &pFolder))) 
      continue; 

     LPITEMIDLIST pidl = nullptr; 
     if(SUCCEEDED(pFolder->GetCurFolder(&pidl))) 
     { 
      // Take ownership of the PIDL via std::unique_ptr. 
      info.pidl = UniquePidlPtr{ pidl }; 
      result.push_back(std::move(info)); 
     } 
    } 

    return result; 
} 

示例展示如何調用GetCurrentExplorerFolders(),轉換成PIDL路徑和捕捉異常。

int main() 
{ 
    ::CoInitialize(nullptr); 

    try 
    { 
     std::wcout << L"Currently open explorer windows:\n"; 
     for(const auto& info : GetCurrentExplorerFolders()) 
     { 
      wchar_t path[ 32767 ]; 
      if(::SHGetPathFromIDListEx(info.pidl.get(), path, ARRAYSIZE(path), 0)) 
       std::wcout << L"hwnd: 0x" << std::hex << info.hwnd << L", path: " << path << L"\n"; 
     } 
    } 
    catch(std::system_error& e) 
    { 
     std::cout << "ERROR: " << e.what() << "\nError code: " << e.code() << "\n"; 
    } 

    ::CoUninitialize(); 
} 

可能的輸出:

Currently open explorer windows: 
hwnd: 0x0030058E, path: C:\Windows 
hwnd: 0x000C06D4, path: C:\Program Files 
+0

這比我預想的要嚴重得多,非常感謝你!奇蹟般有效!我真的瞭解了更多關於COM的文章 –

+0

如果有辦法獲得路徑長度,而不是像32767一樣猜測緩衝區大小,那將是非常棒的。 – raymai97

+0

@ raymai97不幸的是'SHGetPathFromIDListEx'不報告所需的緩衝區大小。但'32767'不是猜測。這是使用「\\?\」前綴時系統支持的最大路徑大小,如[MSDN頁面]上所述(https://msdn.microsoft.com/zh-cn/library/windows/desktop /aa365247(v=vs.85).aspx)。 – zett42

相關問題