如何在C ++ Winapi中获取活动文件浏览器窗口的路径 [英] How to get the path of an active file explorer window in c++ winapi

查看:84
本文介绍了如何在C ++ Winapi中获取活动文件浏览器窗口的路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在摸索如何做到这一点。基本上,我的应用程序需要使用winapi找出c ++中Windows中活动文件浏览器(即前台的文件浏览器)的目录路径。



代替此:

  TCHAR * getWindowDir( ){
TCHAR * windowTitle =新的TCHAR [MAX_PATH];
HWND windowHandle = GetForegroundWindow();
GetWindowText(windowHandle,windowTitle,MAX_PATH);
返回窗口标题;
}

显然返回了窗口标题,但我希望它返回活动目录。 / p>

解决方案

创建 IShellWindows 并使用它来枚举所有当前打开的资源管理器窗口。使用各种相关的界面,您可以以 PIDL 来自 IShellWindows 枚举的每个项目。如果窗口句柄等于 GetForegroundWindow()的结果,则将PIDL转换为路径。



下面,我介绍一些代码以获取有关所有资源管理器窗口的信息。它部分基于 Raymond Chen的代码,但是使用智能指针,可减少代码的脆弱性和简洁性。我还通过异常添加了错误处理。



首先,必需的包含内容和一些实用代码:

  #include< Windows.h> 
#include< shlobj.h>
#include< atlcomcli.h> //对于COM智能指针
#include< vector>
#include< system_error>
#include< memory>

//如果HRESULT指示失败,则引发std :: system_error。
模板<类型名称T>
void ThrowIfFailed(HRESULT hr,T&& msg)
{
if(FAILED(hr))
throw std :: system_error {hr,std :: system_category() ,std :: forward< T(msg)} ;;
}

//删除由Shell分配的PIDL。
struct CoTaskMemDeleter
{
void operator()(ITEMIDLIST * pidl)const {:: CoTaskMemFree(pidl); }
};
// PIDL的智能指针。
使用UniquePidlPtr = std :: unique_ptr< ITEMIDLIST,CoTaskMemDeleter> ;;

现在我们定义一个函数 GetCurrentExplorerFolders()返回有关所有当前打开的Explorer窗口的信息,包括窗口句柄和当前文件夹的 PIDL

  // GetCurrentExplorerFolders()的返回值
struct ExplorerFolderInfo
{
HWND hwnd = nullptr; //资源管理器
的窗口句柄UniquePidlPtr pidl; //指向当前文件夹
的PIDL;

//获取所有当前打开的资源管理器窗口的信息。
//抛出std :: system_error异常以报告错误。
std :: vector< ExplorerFolderInfo> GetCurrentExplorerFolders()
{
CComPtr< IShellWindows> pshWindows;
ThrowIfFailed(
pshWindows.CoCreateInstance(CLSID_ShellWindows),
无法创建IShellWindows实例);

long count = 0;
ThrowIfFailed(
pshWindows-> get_Count(& count),
无法获取shell窗口数);

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

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

CComVariant vi {i};
CComPtr< IDispatch> pDisp;
ThrowIfFailed(
pshWindows-> Item(vi,& pDisp),
无法从IShellWindows获取项目);

if(!pDisp)
//跳过-此shell窗口已注册为NULL IDispatch
Continue;

CComQIPtr< IWebBrowserApp> pApp {pDisp};
if(!pApp)
//此窗口未实现IWebBrowserApp
Continue;

//获取窗口句柄。
pApp-> get_HWND(reinterpret_cast< SHANDLE_PTR *>(& info.hwnd));

CComQIPtr< IServiceProvider> psp {pApp};
if(!psp)
//此窗口未实现IServiceProvider
Continue;

CComPtr< IShellBrowser> pBrowser;
if(FAILED(psp-> QueryService(SID_STopLevelBrowser,& pBrowser)))
//此窗口未提供IShellBrowser
继续;

CComPtr< IShellView> pShellView;
if(FAILED(pBrowser-> QueryActiveShellView(& pShellView)))
//由于某种原因,没有活动的shell视图
Continue;

CComQIPtr< IFolderView> pFolderView {pShellView};
if(!pFolderView)
// shell视图未实现IFolderView
Continue;

//获取最终可以从中查询
//当前文件夹的PIDL的接口。
CComPtr< IPersistFolder2> pFolder;
if(FAILED(pFolderView-> GetFolder(IID_IPersistFolder2,(void **)& pFolder)))
继续;

LPITEMIDLIST pidl = nullptr;
if(SUCCEEDED(pFolder-> GetCurFolder(& pidl)))
{
//通过std :: unique_ptr获得PIDL的所有权。
info.pidl = UniquePidlPtr {pidl};
result.push_back(std :: move(info));
}
}

返回结果;
}

示例显示如何调用 GetCurrentExplorerFolders(),将 PIDL 转换为路径并捕获异常。

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

试试
{
std :: wcout<< L当前打开资源管理器窗口:\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,路径:<<路径<< L \n;
}
}
catch(std :: system_error& e)
{
std :: cout<< 错误:<< e.what()<< \n错误代码:<< e.code()<< \n;
}

:: CoUninitialize();
}

可能的输出:



<当前打开的资源管理器窗口:
hwnd:0x0030058E,路径:C:\Windows
hwnd:0x000C06D4,路径:C: \程序文件


I've been banging my head on the wall of how I can go about doing this. Basically my application needs to figure out the directory path of the active file explorer (ie the file explorer in the foreground) in windows in c++ using the winapi.

Instead of this:

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

Which obviously returns the window title I want it to return the active directory.

解决方案

Create an instance of IShellWindows and use that to enumerate all currently open Explorer windows. Using various related interfaces, you can get the window handle and the current folder in form of a PIDL from each item enumerated by IShellWindows. If the window handle is equal to the result of GetForegroundWindow(), convert the PIDL into a path.

In the following I present some code for getting information about all Explorer windows. It is partially based on code of Raymond Chen but uses smart pointers for less fragile and cleaner code. I've also added error handling via exceptions.

First the required includes and some utility code:

#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 >;

Now we define a function GetCurrentExplorerFolders() to return information about all currently open Explorer windows, including window handle and PIDL of the current folder.

// 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;
}

Example showing how to call GetCurrentExplorerFolders(), convert PIDL into path and catch exceptions.

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();
}

Possible output:

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

这篇关于如何在C ++ Winapi中获取活动文件浏览器窗口的路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆