创建一个
IShellWindows
实例,用它来枚举所有当前打开的资源管理器窗口。使用各种相关接口,可以从
IShellWindows
枚举的每个项目中获取窗口句柄和当前文件夹形式的
PIDL
。如果窗口句柄等于
GetForegroundWindow()
的结果,则将 PIDL 转换为路径。
以下是一些关于获取所有资源管理器窗口信息的代码。它部分基于 Raymond Chen 的
代码,但使用智能指针使代码更加健壮和清晰。我还通过异常添加了错误处理。
首先是所需的包含文件和一些实用程序代码:
#include <Windows.h>
#include <shlobj.h>
#include <atlcomcli.h>
#include <atlbase.h>
#include <vector>
#include <system_error>
#include <memory>
#include <iostream>
template< typename T >
void ThrowIfFailed( HRESULT hr, T&& msg )
{
if( FAILED( hr ) )
throw std::system_error{ hr, std::system_category(), std::forward<T>( msg ) };
}
struct CoTaskMemDeleter
{
void operator()( ITEMIDLIST* pidl ) const { ::CoTaskMemFree( pidl ); }
};
using UniquePidlPtr = std::unique_ptr< ITEMIDLIST, CoTaskMemDeleter >;
现在我们定义一个函数
GetCurrentExplorerFolders()
,用于返回所有当前打开的资源管理器窗口的信息,包括窗口句柄和当前文件夹的
PIDL
。
struct ExplorerFolderInfo
;
std::vector< ExplorerFolderInfo > GetCurrentExplorerFolders()
;
CComPtr< IDispatch > pDisp;
ThrowIfFailed(
pshWindows->Item( vi, &pDisp ),
"Could not get item from IShellWindows" );
if( ! pDisp )
continue;
CComQIPtr< IWebBrowserApp > pApp;
if( ! pApp )
continue;
pApp->get_HWND( reinterpret_cast<SHANDLE_PTR*>( &info.hwnd ) );
CComQIPtr< IServiceProvider > psp;
if( ! psp )
continue;
CComPtr< IShellBrowser > pBrowser;
if( FAILED( psp->QueryService( SID_STopLevelBrowser, &pBrowser ) ) )
continue;
CComPtr< IShellView > pShellView;
if( FAILED( pBrowser->QueryActiveShellView( &pShellView ) ) )
continue;
CComQIPtr< IFolderView > pFolderView;
if( ! pFolderView )
continue;
CComPtr< IPersistFolder2 > pFolder;
if( FAILED( pFolderView->GetFolder( IID_IPersistFolder2, (void**) &pFolder ) ) )
continue;
LPITEMIDLIST pidl = nullptr;
if( SUCCEEDED( pFolder->GetCurFolder( &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() )
{
CComHeapPtr<wchar_t> pPath;
if( SUCCEEDED( ::SHGetNameFromIDList( info.pidl.get(), SIGDN_FILESYSPATH, &pPath ) ) )
{
std::wcout << L"hwnd: 0x" << std::hex << info.hwnd
<< L", path: " << static_cast<LPWSTR>( pPath ) << 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