From 37eb99304470ccdee3917faeb97404f419640568 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 13 Aug 2012 07:31:54 +0530 Subject: [PATCH] WPD: Get information about storage on WPD devices --- .../mtp/windows/device_enumeration.cpp | 122 +++++++++++++++++- src/calibre/devices/mtp/windows/remote.py | 1 + 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/src/calibre/devices/mtp/windows/device_enumeration.cpp b/src/calibre/devices/mtp/windows/device_enumeration.cpp index 43adc35625..3135a50032 100644 --- a/src/calibre/devices/mtp/windows/device_enumeration.cpp +++ b/src/calibre/devices/mtp/windows/device_enumeration.cpp @@ -72,6 +72,119 @@ IPortableDevice *open_device(const wchar_t *pnp_id, IPortableDeviceValues *clien } // }}} +PyObject* get_storage_info(IPortableDevice *device) { + HRESULT hr; + 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; + LPWSTR storage_desc = 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_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++) { + if SUCCEEDED(properties->GetValues(object_ids[i], storage_properties, &values)) { + 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); + 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; + } + PyList_Append(storage, so); + Py_DECREF(so); + } + } + } + } + } + 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; +} + PyObject* get_device_information(IPortableDevice *device) { // {{{ IPortableDeviceContent *content = NULL; IPortableDeviceProperties *properties = NULL; @@ -83,7 +196,7 @@ PyObject* get_device_information(IPortableDevice *device) { // {{{ DWORD num_of_categories, i; LPWSTR temp; ULONG ti; - PyObject *t, *ans = NULL; + PyObject *t, *ans = NULL, *storage = NULL; char *type; Py_BEGIN_ALLOW_THREADS; @@ -216,6 +329,13 @@ PyObject* get_device_information(IPortableDevice *device) { // {{{ } PyDict_SetItemString(ans, "has_storage", t); + if (t == Py_True) { + storage = get_storage_info(device); + if (storage == NULL) goto end; + PyDict_SetItemString(ans, "storage", storage); + + } + end: if (keys != NULL) keys->Release(); if (values != NULL) values->Release(); diff --git a/src/calibre/devices/mtp/windows/remote.py b/src/calibre/devices/mtp/windows/remote.py index cc35e36e64..7c16a87ed1 100644 --- a/src/calibre/devices/mtp/windows/remote.py +++ b/src/calibre/devices/mtp/windows/remote.py @@ -8,6 +8,7 @@ __copyright__ = '2012, Kovid Goyal ' __docformat__ = 'restructuredtext en' import subprocess, sys, os, pprint +pprint def build(mod='wpd'): builder = subprocess.Popen('ssh xp_build ~/build-wpd'.split())