-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Updated code for refresh_file_explorer.exe. Now getting paths from al…
…l File Explorer windows. #115.
- Loading branch information
1 parent
f8f632a
commit 091e43d
Showing
6 changed files
with
336 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
// https://learn.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-ccomptr-and-ccomqiptr-instances?view=msvc-170 | ||
// https://forums.codeguru.com/showthread.php?345012-Access-violation-using-CComPtr-lt-gt | ||
|
||
#include "file_explorer.h" | ||
#include "user.h" | ||
|
||
#include <objbase.h> | ||
#include <comdef.h> | ||
#include <atlbase.h> | ||
#include <shlobj.h> | ||
#include <exdisp.h> | ||
|
||
#include "rapidassist/undef_windows_macros.h" | ||
#include "rapidassist/unicode.h" | ||
#include "rapidassist/errors.h" | ||
#include "rapidassist/filesystem_utf8.h" | ||
#include "rapidassist/environment_utf8.h" | ||
|
||
bool GetFileExplorerWindowPaths(Utf8FileList& files) | ||
{ | ||
files.clear(); | ||
|
||
CoInitialize(NULL); | ||
|
||
HRESULT hr; | ||
wchar_t szPath[50 * MAX_PATH]; | ||
DWORD size_in_characters = sizeof(szPath) / 2; | ||
|
||
CComPtr<IShellWindows> pShellWindows; | ||
hr = pShellWindows.CoCreateInstance( | ||
CLSID_ShellWindows, | ||
NULL, | ||
CLSCTX_ALL | ||
); | ||
if (FAILED(hr)) | ||
{ | ||
CoUninitialize(); | ||
return false; | ||
} | ||
|
||
// Browse shell windows one by one | ||
bool has_more = true; | ||
VARIANT index; | ||
V_VT(&index) = VT_I4; | ||
V_I4(&index) = 0; | ||
while (has_more) | ||
{ | ||
// Check for a shell window at index | ||
IDispatch* pDisp; | ||
hr = pShellWindows->Item(index, &pDisp); | ||
if (hr == S_FALSE) | ||
{ | ||
has_more = false; | ||
} | ||
else if (hr == S_OK) // Warning, do not check 'hr' with SUCCEEDED() macro since S_FALSE is considered a success. | ||
{ | ||
// Handle IDispatch* graceful destruction | ||
CComPtr<IDispatch> pItem = pDisp; | ||
|
||
// Get IWebBrowserApp from Item | ||
CComPtr<IWebBrowserApp> pWebApp; | ||
hr = pItem->QueryInterface(IID_PPV_ARGS(&pWebApp)); | ||
if (SUCCEEDED(hr)) | ||
{ | ||
// Get IServiceProvider from IWebBrowserApp | ||
CComPtr<IServiceProvider> pServiceProvider; | ||
hr = pWebApp->QueryInterface(IID_PPV_ARGS(&pServiceProvider)); | ||
if (SUCCEEDED(hr)) | ||
{ | ||
// Get IShellBrowser from IServiceProvider | ||
CComPtr<IShellBrowser> pShellBrowser; | ||
hr = pServiceProvider->QueryService(SID_STopLevelBrowser, IID_PPV_ARGS(&pShellBrowser)); | ||
if (SUCCEEDED(hr)) | ||
{ | ||
IShellView* psv; | ||
hr = pShellBrowser->QueryActiveShellView(&psv); | ||
if (SUCCEEDED(hr)) | ||
{ | ||
// Handle IShellView* graceful destruction | ||
CComPtr<IShellView> pShellView = psv; | ||
|
||
// Get IFolderView from IShellView | ||
CComPtr<IFolderView> pFolderView; | ||
hr = pShellView->QueryInterface(IID_PPV_ARGS(&pFolderView)); | ||
if (SUCCEEDED(hr)) | ||
{ | ||
IPersistFolder2* ppf2; | ||
hr = pFolderView->GetFolder(IID_IPersistFolder2, (void**)&ppf2); | ||
if (SUCCEEDED(hr)) | ||
{ | ||
// Handle IPersistFolder2* graceful destruction | ||
CComPtr<IPersistFolder2> pPersistFolder2 = ppf2; | ||
|
||
LPITEMIDLIST pidlFolder; | ||
if (SUCCEEDED(ppf2->GetCurFolder(&pidlFolder))) | ||
{ | ||
szPath[0] = '\0'; | ||
if (SHGetPathFromIDListEx(pidlFolder, szPath, size_in_characters, GPFIDL_DEFAULT)) | ||
{ | ||
// Convert from WIDE to UTF8 | ||
std::string str_utf8 = ra::unicode::UnicodeToUtf8(szPath); | ||
files.push_back(str_utf8); | ||
} | ||
else | ||
{ | ||
//not a directory | ||
} | ||
CoTaskMemFree(pidlFolder); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Next Item | ||
V_I4(&index)++; | ||
} | ||
|
||
CoUninitialize(); | ||
|
||
return true; | ||
} | ||
|
||
bool OpenFileExplorerWindow(const std::string& path) | ||
{ | ||
// Find the absolute path of explorer.exe | ||
std::string explorer_path_utf8 = ra::filesystem::FindFileFromPathsUtf8("explorer.exe"); | ||
if (explorer_path_utf8.empty()) | ||
return false; | ||
std::wstring explorer_path_wide = ra::unicode::Utf8ToUnicode(explorer_path_utf8); | ||
const wchar_t * lpApplicationName = explorer_path_wide.c_str(); | ||
|
||
// Convert the given path to wide string | ||
std::wstring path_wide = ra::unicode::Utf8ToUnicode(path); | ||
|
||
// Build a command line (which is including the path to the executable) | ||
std::wstring command_line; | ||
command_line += explorer_path_wide; | ||
|
||
// Add the given path as an argument | ||
// Wrap the path in double quotes to handle spaces. | ||
// And make a copy of the string for stupid WIN32 api... | ||
command_line += L" "; | ||
command_line += L"\""; | ||
command_line += path_wide; | ||
command_line += L"\""; | ||
wchar_t * lpCommandLine = new wchar_t[command_line.size() + 1]; | ||
StrCpyW(lpCommandLine, command_line.c_str()); | ||
|
||
//launch a new process with the command line | ||
PROCESS_INFORMATION pi = { 0 }; | ||
STARTUPINFOW si = { 0 }; | ||
si.cb = sizeof(STARTUPINFO); | ||
BOOL created = CreateProcessW( | ||
lpApplicationName, // Using module name | ||
lpCommandLine, // Command line | ||
NULL, // Process handle not inheritable | ||
NULL, // Thread handle not inheritable | ||
FALSE, // Set handle inheritance to FALSE | ||
0, // No creation flags | ||
NULL, // Use parent's environment block | ||
NULL, // Use parent's starting directory | ||
&si, // Pointer to STARTUPINFO structure | ||
&pi // Pointer to PROCESS_INFORMATION structure | ||
); | ||
if (created != 0) | ||
{ | ||
//Wait for the application to initialize properly | ||
WaitForInputIdle(pi.hProcess, INFINITE); | ||
|
||
//Extract the program id | ||
DWORD process_id = pi.dwProcessId; | ||
|
||
CloseHandle(pi.hProcess); | ||
CloseHandle(pi.hThread); | ||
|
||
delete[] lpCommandLine; | ||
return true; | ||
} | ||
|
||
delete[] lpCommandLine; | ||
return false; | ||
} | ||
|
||
void TestOpenFolderUnicode() | ||
{ | ||
// Test: | ||
const std::string test_path = "D:\\" "\xCE" "\xA8"; // psi | ||
//const std::string test_path = "C:\\temp"; | ||
bool opened = OpenFileExplorerWindow(test_path); | ||
if (!opened) | ||
{ | ||
ra::errors::errorcode_t error_code = ra::errors::GetLastErrorCode(); | ||
std::string error_desc = ra::errors::GetErrorCodeDescription(error_code); | ||
|
||
std::wstring message; | ||
message += L"Failed to open directory:\n"; | ||
message += ra::unicode::Utf8ToUnicode(test_path); | ||
message += L"\n"; | ||
message += L"\n"; | ||
message += ra::unicode::Utf8ToUnicode(error_desc); | ||
|
||
ShowErrorMessage(message); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
#include <vector> | ||
|
||
typedef std::vector<std::string> Utf8FileList; | ||
|
||
/// <summary> | ||
/// Get the list of paths for all opened File Explorer windows. | ||
/// The paths are returned in utf8 format. | ||
/// </summary> | ||
/// <param name="files">The output file path list in utf8 format.</param> | ||
/// <returns>Returns true when the function has succeeded. Returns false otherwise.</returns> | ||
bool GetFileExplorerWindowPaths(Utf8FileList& files); | ||
|
||
/// <summary> | ||
/// Open File Explorer to the given location. | ||
/// </summary> | ||
/// <param name="path">The path location in utf8 format.</param> | ||
/// <returns>Returns true when the function has succeeded. Returns false otherwise.</returns> | ||
bool OpenFileExplorerWindow(const std::string& path); | ||
|
||
/// <summary> | ||
/// Test to open directory unicode directory `D:\Ψ`. | ||
/// </summary> | ||
void TestOpenFolderUnicode(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,74 +1,35 @@ | ||
#include <windows.h> | ||
#include "file_explorer.h" | ||
#include "user.h" | ||
|
||
const TCHAR g_szClassName[] = L"myWindowClass"; | ||
|
||
// Step 4: the Window Procedure | ||
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) | ||
{ | ||
switch (msg) | ||
{ | ||
case WM_CLOSE: | ||
DestroyWindow(hwnd); | ||
break; | ||
case WM_DESTROY: | ||
PostQuitMessage(0); | ||
break; | ||
default: | ||
return DefWindowProc(hwnd, msg, wParam, lParam); | ||
} | ||
return 0; | ||
} | ||
#include "rapidassist/process_utf8.h" | ||
#include "rapidassist/filesystem_utf8.h" | ||
#include "rapidassist/unicode.h" | ||
#include "rapidassist/errors.h" | ||
|
||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, | ||
LPSTR lpCmdLine, int nCmdShow) | ||
{ | ||
WNDCLASSEX wc; | ||
HWND hwnd; | ||
MSG msg; | ||
|
||
//Step 1: Registering the Window Class | ||
wc.cbSize = sizeof(WNDCLASSEX); | ||
wc.style = 0; | ||
wc.lpfnWndProc = WndProc; | ||
wc.cbClsExtra = 0; | ||
wc.cbWndExtra = 0; | ||
wc.hInstance = hInstance; | ||
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); | ||
wc.hCursor = LoadCursor(NULL, IDC_ARROW); | ||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); | ||
wc.lpszMenuName = NULL; | ||
wc.lpszClassName = g_szClassName; | ||
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); | ||
|
||
if (!RegisterClassEx(&wc)) | ||
// Get prompt confirmation | ||
bool confirmed = GetUserConfirmation(); | ||
if (!confirmed) | ||
return 1; | ||
|
||
TestOpenFolderUnicode(); | ||
return 9; | ||
|
||
// Get all the paths from File Explorer windows | ||
Utf8FileList files; | ||
bool success = GetFileExplorerWindowPaths(files); | ||
if (!success) | ||
{ | ||
MessageBox(NULL, L"Window Registration Failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK); | ||
return 0; | ||
std::wstring message; | ||
message += L"ERROR!\n"; | ||
message += L"Failed getting paths from File Explorer windows."; | ||
ShowErrorMessage(message); | ||
return 2; | ||
} | ||
|
||
// Step 2: Creating the Window | ||
hwnd = CreateWindowEx( | ||
WS_EX_CLIENTEDGE, | ||
g_szClassName, | ||
L"The title of my window", | ||
WS_OVERLAPPEDWINDOW, | ||
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, | ||
NULL, NULL, hInstance, NULL); | ||
|
||
if (hwnd == NULL) | ||
{ | ||
MessageBox(NULL, L"Window Creation Failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK); | ||
return 0; | ||
} | ||
|
||
ShowWindow(hwnd, nCmdShow); | ||
UpdateWindow(hwnd); | ||
|
||
// Step 3: The Message Loop | ||
while (GetMessage(&msg, NULL, 0, 0) > 0) | ||
{ | ||
TranslateMessage(&msg); | ||
DispatchMessage(&msg); | ||
} | ||
return (int)msg.wParam; | ||
return 0; | ||
} |
Oops, something went wrong.