Пример #1
0
PyObject* get_storage_info(IPortableDevice *device) { // {{{
    HRESULT hr, hr2;
    IPortableDeviceContent *content = NULL;
    IEnumPortableDeviceObjectIDs *objects = NULL;
    IPortableDeviceProperties *properties = NULL;
    IPortableDeviceKeyCollection *storage_properties = NULL;
    IPortableDeviceValues *values = NULL;
    PyObject *ans = NULL, *storage = NULL, *so = NULL, *desc = NULL, *soid = NULL;
    DWORD fetched, i;
    PWSTR object_ids[10];
    GUID guid;
    ULONGLONG capacity, free_space, capacity_objects, free_objects;
    ULONG access, storage_type = WPD_STORAGE_TYPE_UNDEFINED;
    LPWSTR storage_desc = NULL, st = NULL;

    storage = PyList_New(0);
    if (storage == NULL) { PyErr_NoMemory(); goto end; }

    Py_BEGIN_ALLOW_THREADS;
    hr = device->Content(&content);
    Py_END_ALLOW_THREADS;
    if (FAILED(hr)) {hresult_set_exc("Failed to get content interface from device", hr); goto end;}

    Py_BEGIN_ALLOW_THREADS;
    hr = content->Properties(&properties);
    Py_END_ALLOW_THREADS;
    if (FAILED(hr)) {hresult_set_exc("Failed to get properties interface", hr); goto end;}

    Py_BEGIN_ALLOW_THREADS;
    hr = CoCreateInstance(CLSID_PortableDeviceKeyCollection, NULL,
            CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&storage_properties));
    Py_END_ALLOW_THREADS;
    if (FAILED(hr)) {hresult_set_exc("Failed to create storage properties collection", hr); goto end;}

    Py_BEGIN_ALLOW_THREADS;
    hr = storage_properties->Add(WPD_OBJECT_CONTENT_TYPE);
    hr = storage_properties->Add(WPD_FUNCTIONAL_OBJECT_CATEGORY);
    hr = storage_properties->Add(WPD_STORAGE_DESCRIPTION);
    hr = storage_properties->Add(WPD_STORAGE_CAPACITY);
    hr = storage_properties->Add(WPD_STORAGE_CAPACITY_IN_OBJECTS);
    hr = storage_properties->Add(WPD_STORAGE_FREE_SPACE_IN_BYTES);
    hr = storage_properties->Add(WPD_STORAGE_FREE_SPACE_IN_OBJECTS);
    hr = storage_properties->Add(WPD_STORAGE_ACCESS_CAPABILITY);
    hr = storage_properties->Add(WPD_STORAGE_FILE_SYSTEM_TYPE);
    hr = storage_properties->Add(WPD_STORAGE_TYPE);
    hr = storage_properties->Add(WPD_OBJECT_NAME);
    Py_END_ALLOW_THREADS;
    if (FAILED(hr)) {hresult_set_exc("Failed to create collection of properties for storage query", hr); goto end; }

    Py_BEGIN_ALLOW_THREADS;
    hr = content->EnumObjects(0, WPD_DEVICE_OBJECT_ID, NULL, &objects);
    Py_END_ALLOW_THREADS;
    if (FAILED(hr)) {hresult_set_exc("Failed to get objects from device", hr); goto end;}

    hr = S_OK;
    while (hr == S_OK) {
        Py_BEGIN_ALLOW_THREADS;
        hr = objects->Next(10, object_ids, &fetched);
        Py_END_ALLOW_THREADS;
        if (SUCCEEDED(hr)) {
            for(i = 0; i < fetched; i++) {
                Py_BEGIN_ALLOW_THREADS;
                hr2 = properties->GetValues(object_ids[i], storage_properties, &values);
                Py_END_ALLOW_THREADS;
                if SUCCEEDED(hr2) {
                    if (
                        SUCCEEDED(values->GetGuidValue(WPD_OBJECT_CONTENT_TYPE, &guid)) && IsEqualGUID(guid, WPD_CONTENT_TYPE_FUNCTIONAL_OBJECT) &&
                        SUCCEEDED(values->GetGuidValue(WPD_FUNCTIONAL_OBJECT_CATEGORY, &guid)) && IsEqualGUID(guid, WPD_FUNCTIONAL_CATEGORY_STORAGE)
                       ) {
                        capacity = 0; capacity_objects = 0; free_space = 0; free_objects = 0;
                        values->GetUnsignedLargeIntegerValue(WPD_STORAGE_CAPACITY, &capacity);
                        values->GetUnsignedLargeIntegerValue(WPD_STORAGE_CAPACITY_IN_OBJECTS, &capacity_objects);
                        values->GetUnsignedLargeIntegerValue(WPD_STORAGE_FREE_SPACE_IN_BYTES, &free_space);
                        values->GetUnsignedLargeIntegerValue(WPD_STORAGE_FREE_SPACE_IN_OBJECTS, &free_objects);
                        values->GetUnsignedIntegerValue(WPD_STORAGE_TYPE, &storage_type);
                        desc = Py_False;
                        if (SUCCEEDED(values->GetUnsignedIntegerValue(WPD_STORAGE_ACCESS_CAPABILITY, &access)) && access == WPD_STORAGE_ACCESS_CAPABILITY_READWRITE) desc = Py_True;
                        soid = PyUnicode_FromWideChar(object_ids[i], wcslen(object_ids[i]));
                        if (soid == NULL) { PyErr_NoMemory(); goto end; }
                        so = Py_BuildValue("{s:K, s:K, s:K, s:K, s:O, s:N}",
                                "capacity", capacity, "capacity_objects", capacity_objects, "free_space", free_space, "free_objects", free_objects, "rw", desc, "id", soid);
                        if (so == NULL) { PyErr_NoMemory(); goto end; }
                        if (SUCCEEDED(values->GetStringValue(WPD_STORAGE_DESCRIPTION, &storage_desc))) {
                                desc = PyUnicode_FromWideChar(storage_desc, wcslen(storage_desc));
                                if (desc != NULL) { PyDict_SetItemString(so, "description", desc); Py_DECREF(desc);}
                                CoTaskMemFree(storage_desc); storage_desc = NULL;
                        }
                        if (SUCCEEDED(values->GetStringValue(WPD_OBJECT_NAME, &storage_desc))) {
                                desc = PyUnicode_FromWideChar(storage_desc, wcslen(storage_desc));
                                if (desc != NULL) { PyDict_SetItemString(so, "name", desc); Py_DECREF(desc);}
                                CoTaskMemFree(storage_desc); storage_desc = NULL;
                        }
                        if (SUCCEEDED(values->GetStringValue(WPD_STORAGE_FILE_SYSTEM_TYPE, &storage_desc))) {
                                desc = PyUnicode_FromWideChar(storage_desc, wcslen(storage_desc));
                                if (desc != NULL) { PyDict_SetItemString(so, "filesystem", desc); Py_DECREF(desc);}
                                CoTaskMemFree(storage_desc); storage_desc = NULL;
                        }
                        switch(storage_type) {
                            case WPD_STORAGE_TYPE_REMOVABLE_RAM:
                                st = L"removable_ram";
                                break;
                            case WPD_STORAGE_TYPE_REMOVABLE_ROM:
                                st = L"removable_rom";
                                break;
                            case WPD_STORAGE_TYPE_FIXED_RAM:
                                st = L"fixed_ram";
                                break;
                            case WPD_STORAGE_TYPE_FIXED_ROM:
                                st = L"fixed_rom";
                                break;
                            default:
                                st = L"unknown_unknown";
                        }
                        desc = PyUnicode_FromWideChar(st, wcslen(st));
                        if (desc != NULL) {PyDict_SetItemString(so, "type", desc); Py_DECREF(desc);}
                        desc = NULL;
                        PyList_Append(storage, so);
                        Py_DECREF(so);
                    }
                }
            }
            for (i = 0; i < fetched; i ++) { CoTaskMemFree(object_ids[i]); object_ids[i] = NULL;}
        }// if(SUCCEEDED(hr))
    }
    ans = storage;

end:
    if (content != NULL) content->Release();
    if (objects != NULL) objects->Release();
    if (properties != NULL) properties->Release();
    if (storage_properties != NULL) storage_properties->Release();
    if (values != NULL) values->Release();
    return ans;
} // }}}
Пример #2
0
void Parse_MTP::mtp_get_metadata(PCWSTR object_id, IPortableDeviceContent *pdc, bool clear)
{
    IPortableDeviceValues *pdv;
    IPortableDeviceKeyCollection *pdkc;
    IPortableDeviceProperties *pdp = NULL;
    HRESULT hr;
    scrob_entry new_entry;
    LPWSTR album = NULL;
    LPWSTR artist = NULL;
    LPWSTR name = NULL;
    ULONG usecount;
    ULONG skipcount;
    ULONG tracknum;
    ULONGLONG duration;
    PROPVARIANT date;

    new_entry.length = 0;

    hr = CoCreateInstance(CLSID_PortableDeviceValues, NULL, CLSCTX_INPROC_SERVER,
                          IID_IPortableDeviceValues, (VOID**)&pdv);
    if (FAILED(hr))
    {
        emit add_log(LOG_ERROR, QString("mtp_get_metadata: Failed to create IPortableDeviceValues: %1")
                .arg(hr, 0, 16));
        return;
    }

    hr = CoCreateInstance(CLSID_PortableDeviceKeyCollection, NULL, CLSCTX_INPROC_SERVER,
                          IID_IPortableDeviceKeyCollection, (VOID**)&pdkc);
    if (FAILED(hr))
    {
        emit add_log(LOG_ERROR, QString("mtp_get_metadata: Failed to create IPortableDeviceKeyCollection: %1")
                .arg(hr, 0, 16));
        return;
    }

    hr = pdc->Properties(&pdp);
    if (FAILED(hr))
    {
        emit add_log(LOG_ERROR, QString("mtp_get_metadata: Failed to get properties from IPortableDeviceContent: %1")
                .arg(hr, 0, 16));
        goto mtp_get_metadata_cleanup;
    }

    hr = pdkc->Add(WPD_MEDIA_USE_COUNT);          //VT_UI4
    hr = pdkc->Add(WPD_MEDIA_SKIP_COUNT);         //VT_UI4
    hr = pdkc->Add(WPD_MEDIA_LAST_ACCESSED_TIME); //VT_DATE
    hr = pdkc->Add(WPD_MUSIC_ALBUM);              //VT_LPWSTR
    hr = pdkc->Add(WPD_MUSIC_TRACK);              //VT_UI4
    hr = pdkc->Add(WPD_MEDIA_DURATION);           //VT_UI8, in milliseconds
    hr = pdkc->Add(WPD_OBJECT_NAME);              //VT_LPWSTR
    hr = pdkc->Add(WPD_MEDIA_ARTIST);             //VT_LPWSTR
    if (FAILED(hr))
    {
        emit add_log(LOG_ERROR, QString("mtp_get_metadata: Failed to add to IPortableDeviceKeyCollection: %1")
                .arg(hr, 0, 16));
        goto mtp_get_metadata_cleanup;
    }

    hr = pdp->GetValues(object_id, pdkc, &pdv);
    if (FAILED(hr))
    {
        emit add_log(LOG_ERROR, QString("mtp_get_metadata: Failed to get values from IPortableDeviceProperties: %1")
                .arg(hr, 0, 16));
        goto mtp_get_metadata_cleanup;
    }

    hr = pdv->GetStringValue(WPD_MUSIC_ALBUM, &album);
    if (SUCCEEDED(hr))
        new_entry.album = QString::fromStdWString(album);

    hr = pdv->GetStringValue(WPD_MEDIA_ARTIST, &artist);
    if (SUCCEEDED(hr))
        new_entry.artist = QString::fromStdWString(artist);

    hr = pdv->GetStringValue(WPD_OBJECT_NAME, &name);
    if (SUCCEEDED(hr))
        new_entry.title = QString::fromStdWString(name);

    hr = pdv->GetUnsignedIntegerValue(WPD_MEDIA_USE_COUNT, &usecount);
    hr = pdv->GetUnsignedIntegerValue(WPD_MEDIA_SKIP_COUNT, &skipcount);

    hr = pdv->GetUnsignedIntegerValue(WPD_MUSIC_TRACK, &tracknum);
    if (SUCCEEDED(hr))
        new_entry.tracknum = tracknum;

    hr = pdv->GetUnsignedLargeIntegerValue(WPD_MEDIA_DURATION, &duration);
    if (SUCCEEDED(hr))
        new_entry.length = duration/1000;

    hr = pdv->GetValue(WPD_MEDIA_LAST_ACCESSED_TIME, &date);
    if (SUCCEEDED(hr))
    {
        SYSTEMTIME st;
        VariantTimeToSystemTime(date.date, &st);
        PropVariantClear(&date);
        QDate d = QDate(st.wYear, st.wMonth, st.wDay);
        QTime t = QTime(st.wHour, st.wMinute, st.wSecond);
        new_entry.when = QDateTime(d, t).toTime_t() - tz_offset;

        // Not all MTP devices provide a valid result for
        // WPD_MEDIA_LAST_ACCESSED_TIME, so sanity check it

        // are we within (+/-) 30 days?
        long offset = new_entry.when - QDateTime::currentDateTime().toTime_t();
        if (abs(offset) > 2592000)
            new_entry.when = 0;
    }

    emit add_log(LOG_TRACE, 
        QString("%1 : %2 : %3 : %4 : %5 : %6 : %7")
        .arg(new_entry.artist)
        .arg(new_entry.title)
        .arg(new_entry.album)
        .arg(new_entry.tracknum)
        .arg(new_entry.length)
        .arg(usecount)
        .arg(skipcount)
        );

    tracks++;

    if (usecount > 0 
        && new_entry.artist.length() 
        && new_entry.title.length())
    {
        if (clear)
        {
            IPortableDeviceValues *pdv_clear = NULL;
            hr = pdv->Clear();
            hr = pdv->SetUnsignedIntegerValue(WPD_MEDIA_USE_COUNT, 0);
            hr = pdp->SetValues(object_id, pdv, &pdv_clear);
            if (SUCCEEDED(hr))
            {
                if (pdv_clear != NULL)
                    pdv_clear->Clear();
                    pdv_clear = NULL;
            }
        }
        else
        {
            playcounts++;
            new_entry.played = 'L';

            for (ULONG i = 0; i < usecount; i++)
            {
                entries++;

                // Only use the last playcount for one instance
                // we'll recalc the rest afterwards
                // via Scrobble::check_timestamps()
                if (i > 1)
                    new_entry.when = 0;
                
                emit entry(new_entry);
            }
        }
    }

mtp_get_metadata_cleanup:
    if (album)
        CoTaskMemFree(album);
    if (artist)
        CoTaskMemFree(artist);
    if (name)
        CoTaskMemFree(name);
    if (pdp)
    {
        pdp->Release();
        pdp = NULL;
    }
    if (pdv)
    {
        pdv->Release();
        pdv = NULL;
    }
}