2017-05-06 93 views
1

私はこれをどうやってやっていくことができようとしているのですか?基本的に私のアプリケーションでは、winapiを使ってC++のウィンドウでアクティブファイルエクスプローラ(フォアグラウンドのファイルエクスプローラ)のディレクトリパスを調べる必要があります。これに代えてC++ winapiでアクティブなファイルエクスプローラウィンドウのパスを取得するには


明らかに私はそれがアクティブディレクトリを返すようにしたいウィンドウのタイトルを返し

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

+0

はたぶん、このスレッドがあなたにヒントを与えることができます。http://stackoverflow.com/questions/20960316/get-folder-path-from-explorer-window – OnNIX

+0

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

+0

ハッキングを止めてシェルを使用します。また、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 >; 

今、私たちは、ウィンドウハンドルと、現在のフォルダのPIDL含めて現在開いているすべてのエクスプローラウィンドウに関する情報を返すために機能GetCurrentExplorerFolders()を定義します。 PIDLパスとキャッチ例外に変換、GetCurrentExplorerFolders()を呼び出す方法を示す

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

例。

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/en-us/library/windows/desktop)に記載されているように、 "\\?\"プレフィックスを使用するとシステムがサポートするパスの最大サイズです/aa365247(v=vs.85).aspx)。 – zett42

関連する問題