IPortableDeviceEventCallback не работает должным образом (странное поведение)

Я хочу получить обратный вызов в моем приложении, когда была сделана фотография на подключенном мобильном телефоне (WPD_EVENT_OBJECT_ADDED).
Я реализовал клиент WPD и IPortableDeviceEventCallback, как показано на Центр разработки Windows.

Теперь моя проблема заключается в том, что метод IPortableDeviceEventCallback :: OnEvent () вызывается только в том случае, если я открыл папку DCIM / Camera на телефоне через проводник Windows и проводник начал создавать миниатюры для изображений. После того, как я сделал это один раз, я получаю каждое событие с телефона, пока не отключу и не подключу его снова. Но если я этого не сделаю, onEvent () никогда не вызывается, за исключением того, что я отключаю телефон.

Протестировано на разных телефонах Android и iOS.
У кого-нибудь есть идея, что происходит?

DeviceEventsCallback::DeviceEventsCallback(MyPortableDevice* parent) : IPortableDeviceEventCallback(), cRef(1)
{
parentDevice = parent;
}

DeviceEventsCallback::~DeviceEventsCallback()
{

}

HRESULT __stdcall DeviceEventsCallback::QueryInterface(const IID& riid, LPVOID* ppvObj)
{
static const QITAB qitab[] = {
QITABENT(DeviceEventsCallback, IPortableDeviceEventCallback),
{ },
};

return QISearch(this, qitab, riid, ppvObj);

//    HRESULT hr = S_OK;
//    if (ppvObj == NULL) {
//        hr = E_INVALIDARG;
//        return hr;
//    }

//    if ((riid == IID_IUnknown) ||
//        (riid == IID_IPortableDeviceEventCallback)) {
//        AddRef();
//        *ppvObj = this;
//    }
//    else {
//        *ppvObj = NULL;
//        hr = E_NOINTERFACE;
//    }
//    return hr;
}

ULONG __stdcall DeviceEventsCallback::AddRef()
{
InterlockedIncrement((long*) &cRef);
return cRef;
}

ULONG __stdcall DeviceEventsCallback::Release()
{
ULONG refCount = cRef - 1;
long ref = InterlockedDecrement(&cRef);

if (ref == 0) {
delete this;
return 0;
}

return refCount;
}

HRESULT __stdcall DeviceEventsCallback::OnEvent(IPortableDeviceValues* pEventParameters)
{
HRESULT hr = S_OK;

if (pEventParameters == NULL) {
hr = E_POINTER;
return hr;
}

// The pEventParameters collection contains information about the event that was
// fired. We'll at least need the EVENT_ID to figure out which event was fired
// and based on that retrieve additional values from the collection

// Display the event that was fired
GUID EventId;

if (EventId == WPD_EVENT_DEVICE_CAPABILITIES_UPDATED) {
return S_OK;
}

if (hr == S_OK) {
hr = pEventParameters->GetGuidValue(WPD_EVENT_PARAMETER_EVENT_ID, &EventId);
}

if (EventId == WPD_EVENT_DEVICE_REMOVED) {
return S_OK;
}

LPWSTR pwszEventId = NULL;

if (hr == S_OK) {
hr = StringFromCLSID(EventId, &pwszEventId);
}

if (pwszEventId != NULL) {
CoTaskMemFree(pwszEventId);
}

// Display the ID of the object that was affected
// We can also obtain WPD_OBJECT_NAME, WPD_OBJECT_PERSISTENT_UNIQUE_ID,
// WPD_OBJECT_PARENT_ID, etc.
LPWSTR pwszObjectId = NULL;

if (hr == S_OK) {
hr = pEventParameters->GetStringValue(WPD_OBJECT_ID, &pwszObjectId);
}

if (parentDevice != nullptr && pwszObjectId != nullptr && EventId == WPD_EVENT_OBJECT_ADDED) {
qDebug() << "invoked method";
QMetaObject::invokeMethod(parentDevice, "onNewFileOnDevice", Qt::DirectConnection, Q_ARG(QString, QString::fromStdWString(pwszObjectId)));
}

if (pwszObjectId != NULL) {
CoTaskMemFree(pwszObjectId);
}

// Note that we intentionally do not call Release on pEventParameters since we
// do not own it

return hr;
}

И в моей реализации MTP я регистрирую свой DeviceEventsCallback () eventNotifier

void MyPortableDevice::registerEventNotification(ComPtr<IPortableDevice> pDevice)
{
HRESULT hr = S_OK;
PWSTR tempEventCookie = nullptr;

if (pwszEventCookie != nullptr || pDevice == nullptr) {
return;
}

eventNotifier = new(std::nothrow) DeviceEventsCallback(this);

if (eventNotifier == nullptr) {
hr = E_OUTOFMEMORY;
}

if (hr == S_OK) {
hr = pDevice->Advise(0, eventNotifier, nullptr, &tempEventCookie);
}

if (hr == S_OK) {
pwszEventCookie = tempEventCookie;
tempEventCookie = nullptr; // relinquish memory to the caller
}
else {
// Free the event registration cookie because some error occurred
CoTaskMemFree(tempEventCookie);
tempEventCookie = nullptr;
}
}

void MyPortableDevice::unregisterEventsNotification(ComPtr<IPortableDevice> pDevice)
{
if (pDevice == nullptr || pwszEventCookie == nullptr) {
return;
}

HRESULT hr = pDevice->Unadvise(pwszEventCookie);

CoTaskMemFree(pwszEventCookie);
pwszEventCookie = nullptr;
}

Моя функция open () выглядит так:

bool MyPortableDevice::open(IPortableDevice** ppDevice)
{
retrieveClientInformation(&clientInformation);
IPortableDevice* pDevice = nullptr;

HRESULT hr = CoCreateInstance(CLSID_PortableDeviceFTM, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevice));

if (SUCCEEDED(hr)) {
wchar_t* wID = new wchar_t[ID.length() + 1];
ID.toWCharArray(wID);
wID[ID.length()] = '\0';

hr = pDevice->Open(wID, clientInformation.Get());

if (hr == E_ACCESSDENIED) {
qDebug() << "Failed to Open the device for Read Write access, will open it for Read-only access instead" << hr;
clientInformation->SetUnsignedIntegerValue(WPD_CLIENT_DESIRED_ACCESS, GENERIC_READ);
hr = pDevice->Open(wID, clientInformation.Get());

readOnly = true;
}
if (SUCCEEDED(hr)) {
// The device successfully opened, obtain an instance of the Device into
// ppDevice so the caller can be returned an opened IPortableDevice.
hr = pDevice->QueryInterface(IID_IPortableDevice, (VOID**)ppDevice);
if (FAILED(hr)) {
qDebug() << "Failed to QueryInterface the opened IPortableDevice";
return  false;
}
}

if (pDevice != nullptr) {
pDevice->Release();
pDevice = nullptr;
}

delete [] wID;
wID = nullptr;

if (clientInformation != nullptr) {
clientInformation.Reset();
clientInformation = nullptr;
}

return true;
}
else {
qDebug() << "! Failed to CoCreateInstance CLSID_PortableDeviceFTM, hr = 0x%lx\n" << hr;
return false;
}
}

0

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]