I want to programmatically ask explorer to refresh MTP folder contents (Android device) and display the existing files (simulating F5 on the folder). if it was a standard path with drive letter, I can refresh using:
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH, FolderPath, NULL);
However, MTP folder doesn't have a drive letter path that I can use. how can I ask explorer to refresh such folder, or alternatively ask explorer to refresh all open folder windows?
Here is some sample code that scans all opened Windows Explorer views and refresh all views that currently display a portable device Shell Item (using WPD properties), you can adapt it to filter the exact view(s) you want to target:
#include <windows.h>
#include <stdio.h>
#include <atlbase.h>
#include <shobjidl_core.h>
#include <shlobj_core.h>
#include <ShlGuid.h>
#include <PortableDevice.h>
#include <propvarutil.h>
int main()
{
CoInitialize(nullptr);
{
// get Shell windows' list
CComPtr<IShellWindows> windows;
ATLASSERT(SUCCEEDED(windows.CoCreateInstance(CLSID_ShellWindows)));
// browse all opened views, pick the path or display name that you need
long count = 0;
windows->get_Count(&count);
for (auto i = 0; i < count; i++)
{
CComPtr<IDispatch> disp;
ATLASSERT(SUCCEEDED(windows->Item(CComVariant(i), &disp)));
// get the PIDL from the underlying IShellView
CComPtr<IPersistIDList> idlist;
ATLASSERT(SUCCEEDED(IUnknown_QueryService(disp, SID_SFolderView, IID_PPV_ARGS(&idlist))));
CComHeapPtr<ITEMIDLIST> pidl;
ATLASSERT(SUCCEEDED(idlist->GetIDList(&pidl)));
// get this as an IShellItem, easier to work with
CComPtr<IShellItem2> item;
ATLASSERT(SUCCEEDED(SHCreateItemFromIDList(pidl, IID_PPV_ARGS(&item))));
CComHeapPtr<wchar_t> displayName;
ATLASSERT(SUCCEEDED(item->GetDisplayName(SIGDN::SIGDN_DESKTOPABSOLUTEEDITING, &displayName)));
wprintf(L"display name:%s\n", displayName.m_pData);
CComHeapPtr<wchar_t> path;
ATLASSERT(SUCCEEDED(item->GetDisplayName(SIGDN::SIGDN_DESKTOPABSOLUTEPARSING, &path)));
wprintf(L"path:%s\n", path.m_pData);
// if you want to make sure it's a WPD object, you can get a WPD property
// for example WPD_OBJECT_NAME (should be the same as SIGDN_NORMALDISPLAY)
PROPVARIANT pv;
PropVariantInit(&pv);
ATLASSERT(SUCCEEDED(item->GetProperty(WPD_OBJECT_NAME, &pv))); // PortableDevice.h
// here we refresh all WPD views
auto isWpd = pv.vt != VT_EMPTY;
CComHeapPtr<wchar_t> name;
ATLASSERT(SUCCEEDED(PropVariantToStringAlloc(pv, &name))); // propvarutil.h
wprintf(L"WPD name:%s\n", name.m_pData);
PropVariantClear(&pv);
if (isWpd)
{
// ask for refresh
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, pidl, NULL);
}
}
}
CoUninitialize();
}