創建一個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
也許這線程可以給你一個提示:http://stackoverflow.com/questions/20960316/get-folder-path-from-explorer-window – OnNIX
HTTPS ://en.wikipedia.org/wiki/Dangling_pointer –
停止黑客入侵併使用shell。另外,如果您打算調用Win32函數,請養成檢查錯誤的習慣。在你的危險忽略返回值。 –