There's no code design going on here. My solution was literally just going through like 100 StackOverflow answers & Microsoft's god-awful documentation to get the 50 lines of code that does what I need it to do.
In fact, this is precisely what I'd hope ChatGPT would be good for. Most of my final code is simply copy-pasted from SO/example repos/official docs. He's the correct function (comments added by me so I'll know wtf this is meant to do when I look at it again in 3 months).
fn get_context_path() -> Result<String, Error> {
unsafe {
// Init COM libraries in this thread
CoInitializeEx(Some(ptr::null()), COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)?;
// CabinetWClass is the Explorer window class
let class = s!("CabinetWClass");
let topmost_explorer = FindWindowA(class, None);
let foreground_window = GetForegroundWindow();
// Breadcrumbs IFF topmost window is an explorer window
if topmost_explorer == foreground_window {
let windows: IShellWindows = CoCreateInstance(&ShellWindows, None, CLSCTX_LOCAL_SERVER)?;
let unk_enum = windows._NewEnum()?;
let enum_variant: IEnumVARIANT = unk_enum.cast::<IEnumVARIANT>()?;
// Iterate through all IShellWindows
loop {
let mut fetched = 0;
let mut var: [VARIANT; 1] = [VARIANT::default(); 1];
let hr = enum_variant.Next(&mut var, &mut fetched);
// No more windows?
if hr == S_FALSE || fetched == 0 {
break;
}
// Not an IDispatch interface?
if var[0].Anonymous.Anonymous.vt != VT_DISPATCH {
continue;
}
// We should be able to turn an IShellWindow into an IShellBrowser
let shell_browser: IShellBrowser = IUnknown_QueryService(
var[0]
.Anonymous
.Anonymous
.Anonymous
.pdispVal
.as_ref()
.unwrap(),
&SID_STopLevelBrowser,
)?;
let shell_window = shell_browser.GetWindow()?;
// NOTE: The window we're matching with is actually the shell's parent
// Given that windows can be tabbed, we want to make sure the parent is the top
if GetParent(shell_window) == topmost_explorer {
let shell_view = shell_browser.QueryActiveShellView()?;
// Do some COM finagling, including a QueryInterface cast,
// until we get the folder path we're looking at
let folder_view: IFolderView = shell_view.cast::<IFolderView>()?;
let folder: IPersistFolder2 = folder_view.GetFolder::<IPersistFolder2>()?;
let curr_folder = folder.GetCurFolder()?;
// NOTE: This fails on non SYSPATH paths (e.g. "Home" or "Recent")
let path = SHGetNameFromIDList(curr_folder, SIGDN_FILESYSPATH)?;
let result = path.to_string()?;
// To figure out what path we're on (e.g. what tab is active), we try to match the
// parent title with the folder
// FIXME: Unless using full paths as titles, we can have ambiguities here
let mut title: [u16; 512] = [0; 512];
let len = GetWindowTextW(topmost_explorer, &mut title);
let title = String::from_utf16_lossy(&title[..len as usize]);
// We found the proper tab (child)
if result.contains(&title) {
// Cleanup COM & return path result
CoUninitialize();
return Ok(result);
// Must be another one (or something went wrong)
} else {
continue;
}
}
}
}
// Cleanup COM & fallback to blank string
CoUninitialize();
return Ok(String::from(""));
}
}