IPortableDeviceEventCallback无法正常工作(奇怪的行为)

时间:2018-03-07 15:15:39

标签: c++ winapi usb wpd

我希望在连接的手机上的照片被拍摄时在我的应用程序中收到回调(WPD_EVENT_OBJECT_ADDED)。 我实现了一个WPD客户端和IPortableDeviceEventCallback,如Windows Dev Center所示。

现在我的问题是只有在我通过Windows资源管理器打开手机上的DCIM / Camera文件夹并且资源管理器开始为图像创建缩略图时才会调用IPortableDeviceEventCallback :: OnEvent()方法。在我做了一次之后,我从手机接收了所有事件,直到我解除并重新连接它。但如果我不这样做,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 个答案:

没有答案