Reputation: 402
I have been trying to build a file explorer of my Android phone content that would be optimized to my needs. As FindFirstFile api could not work for MTP devices I had to learn Windows Portable Device Api.
I met alot of obstacles but got most things working:
My only road block now is deleting files. I followed the MSDN sample perfectly but still met into problems. The problem is when I try to delete a file, the file gets deleted but the device hangs and becomes unresponsive. Not even Windows explorer is able to access it at that point. I have to disconnect and reconnect the device. However windows explorer is able to delete files on the device no problem.
This is my code
typedef const wchar_t *string_t;
bool wpd::Device::deleteFile(string_t file_id)
{
PROPVARIANT file ={};
IPortableDevicePropVariantCollection *filesToDelete = newIPortableDevicePropVariantCollection(); // Calls CoCreateInstance
IPortableDeviceContent *devContentMgr;
file.vt = VT_LPWSTR;
file.pwszVal = (LPWSTR)file_id;
filesToDelete->Add(&file);
// IPortableDevice *dev initialized in constructor
dev->Content(&devContentMgr);
HRESULT hr = devContentMgr->Delete(PORTABLE_DEVICE_DELETE_NO_RECURSION,filesToDelete,NULL);
filesToDelete->Release();
devContentMgr->Release();
return SUCCEEDED(hr);
}
Note that I am doing this on Windows Xp.
Upvotes: 3
Views: 421
Reputation: 11
There's an unofficial solution. The method probably Explorer uses itself when working with WPD files.
Its nature was discovered by some Chinese developers and you can find the post on several Chinese platforms, for example here. The post describes how the developers reverse engineered the "good guy" logic (Explorer) using advanced tools like disassembling. This method was also briefly discussed in English/c# as a suggestion to implement it in a media library.
The only existing software that I have at hands using this trick is the extension PortaDev for Far Manager. And here is almost direct quote from the wpd.cpp file
#define CLSID_WPD_NAMESPACE_EXTENSION L"{35786D3C-B075-49B9-88DD-029876E11C01}"
.....
CComPtr<IPortableDevice> _pd_device; ///< Device
CComPtr<IPortableDeviceValues> _pd_values;
....
// Secret ingredient to avoid freeze after first delete operation
hr = _pd_values->SetStringValue(WPD_CLIENT_EVENT_COOKIE, CLSID_WPD_NAMESPACE_EXTENSION);
//
hr = _pd_device->Open(device_id, _pd_values);
The CLSID_WPD_NAMESPACE_EXTENSION constant may be or not be the part of the official API, but its meaningful value might be seen with the following command-line execution (Enter into the Start-Run field)
explorer shell:::{35786D3C-B075-49b9-88DD-029876E11C01}
which should open Portable Devices root node in Explorer probably on any Windows (tested on Windows 7, Windows 10)
The cookie feature that is used here allows registering a unique string that will be passed when notifying about different WPD operations. If you register some (unique) cookie you may detect that a notification about an operation comes from your own code and avoid extra operations (for example, re-scanning). Probably this particular cookie value (CLSID_WPD_NAMESPACE_EXTENSION) is how Explorer uses this feature and by registering it, you pretend that this operation comes from Explorer itself.
Actually, in Windows 10 you even can see the evidence with your own eyes. If you register you handler for IPortableDeviceEventCallback interface and catch the notification after some operation in Explorer, you will find this cookie (IPortableDeviceValues->GetStringValue(WPD_CLIENT_EVENT_COOKIE...).
But I could not detect the presence of the cookie in notifications in Windows 7. So while in Windows 10 there was indirect evidence of Explorer using it, for previous Windows version the evidence was scarce. But I found the steps that showed that this cookie also works in Windows 7, at least for some operations.
First, the steps to trigger the 5-minute freeze in all current MTP clients in Windows 7. The steps below don't require rebooting either for Windows or Android to be reproducible.
These steps were reproducible so several times at least I managed to enforce hanging with different operations in my test programs. After applying the change to the test program and repeating the same steps the hanging was gone.
Upvotes: 1