Opening Folder in New Tab of Existing Shell Window
See the question and my original answer on StackOverflowThe first solution is to use the official UI Automation API.
Microsoft UI Automation is an accessibility framework that enables Windows applications to provide and consume programmatic information about user interfaces (UIs). It provides programmatic access to most UI elements on the desktop. It enables assistive technology products, such as screen readers, to provide information about the UI to end users and to manipulate the UI by means other than standard input. UI Automation also allows automated test scripts to interact with the UI.
This code opens a c:\temp
folder (or select one already opened) and adds a new tab to the Explorer window:
int main()
{
CoInitialize(nullptr);
// get a pidl for a given folder
LPITEMIDLIST pidl;
if (SUCCEEDED(SHParseDisplayName(L"c:\\temp", nullptr, &pidl, 0, nullptr)))
{
// open the folder (or activate an already matching opened one)
SHOpenFolderAndSelectItems(pidl, 1, (LPCITEMIDLIST*)&pidl, 0);
// find window that displays this pidl
IShellWindows* windows;
if (SUCCEEDED(CoCreateInstance(CLSID_ShellWindows, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&windows))))
{
// build buffer from pidl
VARIANT url;
VariantInit(&url);
if (SUCCEEDED(InitVariantFromBuffer(pidl, ILGetSize(pidl), &url))) // propvarutil.h
{
long hwnd = 0;
IDispatch* disp;
VARIANT empty;
VariantInit(&empty);
windows->FindWindowSW(&url, &empty, SWC_BROWSER, &hwnd, 0, &disp);
VariantClear(&url);
VariantClear(&empty); // useless but we always pair calls
if (disp) // should be null but we never know...
{
disp->Release();
}
if (hwnd)
{
//needs UIAutomationCore.h & UIAutomationClient.h
IUIAutomation* automation;
if (SUCCEEDED(CoCreateInstance(CLSID_CUIAutomation8, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&automation)))) // or CLSID_CUIAutomation
{
// get UIA element from handle
IUIAutomationElement* window;
automation->ElementFromHandle((UIA_HWND)(INT_PTR)hwnd, &window);
if (window)
{
// window's class should be 'ShellTabWindowClass'
// create inconditional "true" condition
IUIAutomationCondition* trueCondition;
automation->CreateTrueCondition(&trueCondition);
if (trueCondition)
{
// create a tree walker to determine window's parent
IUIAutomationTreeWalker* walker;
automation->CreateTreeWalker(trueCondition, &walker);
if (walker)
{
IUIAutomationElement* parent;
walker->GetParentElement(window, &parent);
if (parent)
{
// create a condition to find the first button with AutomationId property set to AddButton
VARIANT v;
V_VT(&v) = VT_BSTR;
V_BSTR(&v) = SysAllocString(L"AddButton");
IUIAutomationCondition* condition;
automation->CreatePropertyCondition(UIA_AutomationIdPropertyId, v, &condition);
VariantClear(&v);
if (condition)
{
IUIAutomationElement* button;
// search button
parent->FindFirst(TreeScope_Subtree, condition, &button);
if (button)
{
// a button implements the "Invoke" pattern
IUnknown* unk;
button->GetCurrentPattern(UIA_InvokePatternId, &unk);
if (unk)
{
IUIAutomationInvokePattern* pattern;
unk->QueryInterface(&pattern);
if (pattern)
{
// press the button
pattern->Invoke();
pattern->Release();
}
unk->Release();
}
button->Release();
}
condition->Release();
}
parent->Release();
}
walker->Release();
}
trueCondition->Release();
}
}
automation->Release();
}
CoUninitialize();
}
}
windows->Release();
}
CoTaskMemFree(pidl);
}
CoUninitialize();
return 0;
}
To be able to program UIA you generally first analyse the window's structure for example using the Inspect tool from Windows SDK or the newer Accessibility Insights to understand what actions you should execute. Here's an inspect screenshot on hightlighted Explorer's "Add new tab" button that tells us this button has an Automation Id property set to "AddButton":
PS: Sometimes, it's less obvious as Automation Id is not always set.
Another solution is to use the undocumented Explorer's WM_COMMAND
0xA21B (41499) which directly asks Explorer to open a new tab. So, with the previous example code, you can simply replace all UIA code by this, after you got ahold on the ShellTabWindowClass
window:
...
if (hwnd)
{
// window's class should be 'ShellTabWindowClass'
// ask to open a new tab
SendMessage((HWND)(INT_PTR)hwnd, WM_COMMAND, 0xA21B, 0);
}
...
Once you have opened a new tab, it's seen as a new window (view), so you can (re)start using CLSID_ShellWindows
again and navigate this new view to any folder using something like what I have done here https://stackoverflow.com/a/78272475/403671 with Navigate2
call.