PyObject* get_device_information(IPortableDevice *device, IPortableDevicePropertiesBulk **pb) { // {{{ IPortableDeviceContent *content = NULL; IPortableDeviceProperties *properties = NULL; IPortableDevicePropertiesBulk *properties_bulk = NULL; IPortableDeviceKeyCollection *keys = NULL; IPortableDeviceValues *values = NULL; IPortableDeviceCapabilities *capabilities = NULL; IPortableDevicePropVariantCollection *categories = NULL; HRESULT hr; DWORD num_of_categories, i; LPWSTR temp; ULONG ti; PyObject *t, *ans = NULL, *storage = NULL; const char *type = NULL; Py_BEGIN_ALLOW_THREADS; hr = CoCreateInstance(CLSID_PortableDeviceKeyCollection, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&keys)); Py_END_ALLOW_THREADS; if (FAILED(hr)) {hresult_set_exc("Failed to create IPortableDeviceKeyCollection", hr); goto end;} Py_BEGIN_ALLOW_THREADS; hr = keys->Add(WPD_DEVICE_PROTOCOL); // Despite the MSDN documentation, this does not exist in PortableDevice.h // hr = keys->Add(WPD_DEVICE_TRANSPORT); hr = keys->Add(WPD_DEVICE_FRIENDLY_NAME); hr = keys->Add(WPD_DEVICE_MANUFACTURER); hr = keys->Add(WPD_DEVICE_MODEL); hr = keys->Add(WPD_DEVICE_SERIAL_NUMBER); hr = keys->Add(WPD_DEVICE_FIRMWARE_VERSION); hr = keys->Add(WPD_DEVICE_TYPE); Py_END_ALLOW_THREADS; if (FAILED(hr)) {hresult_set_exc("Failed to add keys to IPortableDeviceKeyCollection", hr); goto end;} Py_BEGIN_ALLOW_THREADS; hr = device->Content(&content); Py_END_ALLOW_THREADS; if (FAILED(hr)) {hresult_set_exc("Failed to get IPortableDeviceContent", hr); goto end; } Py_BEGIN_ALLOW_THREADS; hr = content->Properties(&properties); Py_END_ALLOW_THREADS; if (FAILED(hr)) {hresult_set_exc("Failed to get IPortableDeviceProperties", hr); goto end; } Py_BEGIN_ALLOW_THREADS; hr = properties->GetValues(WPD_DEVICE_OBJECT_ID, keys, &values); Py_END_ALLOW_THREADS; if(FAILED(hr)) {hresult_set_exc("Failed to get device info", hr); goto end; } Py_BEGIN_ALLOW_THREADS; hr = device->Capabilities(&capabilities); Py_END_ALLOW_THREADS; if(FAILED(hr)) {hresult_set_exc("Failed to get device capabilities", hr); goto end; } Py_BEGIN_ALLOW_THREADS; hr = capabilities->GetFunctionalCategories(&categories); Py_END_ALLOW_THREADS; if(FAILED(hr)) {hresult_set_exc("Failed to get device functional categories", hr); goto end; } Py_BEGIN_ALLOW_THREADS; hr = categories->GetCount(&num_of_categories); Py_END_ALLOW_THREADS; if(FAILED(hr)) {hresult_set_exc("Failed to get device functional categories number", hr); goto end; } ans = PyDict_New(); if (ans == NULL) {PyErr_NoMemory(); goto end;} if (SUCCEEDED(values->GetStringValue(WPD_DEVICE_PROTOCOL, &temp))) { t = PyUnicode_FromWideChar(temp, wcslen(temp)); if (t != NULL) {PyDict_SetItemString(ans, "protocol", t); Py_DECREF(t);} CoTaskMemFree(temp); } // if (SUCCEEDED(values->GetUnsignedIntegerValue(WPD_DEVICE_TRANSPORT, &ti))) { // PyDict_SetItemString(ans, "isusb", (ti == WPD_DEVICE_TRANSPORT_USB) ? Py_True : Py_False); // t = PyLong_FromUnsignedLong(ti); // } if (SUCCEEDED(values->GetUnsignedIntegerValue(WPD_DEVICE_TYPE, &ti))) { switch (ti) { case WPD_DEVICE_TYPE_CAMERA: type = "camera"; break; case WPD_DEVICE_TYPE_MEDIA_PLAYER: type = "media player"; break; case WPD_DEVICE_TYPE_PHONE: type = "phone"; break; case WPD_DEVICE_TYPE_VIDEO: type = "video"; break; case WPD_DEVICE_TYPE_PERSONAL_INFORMATION_MANAGER: type = "personal information manager"; break; case WPD_DEVICE_TYPE_AUDIO_RECORDER: type = "audio recorder"; break; default: type = "unknown"; } #if PY_MAJOR_VERSION >= 3 t = PyUnicode_FromString(type); #else t = PyString_FromString(type); #endif if (t != NULL) { PyDict_SetItemString(ans, "type", t); Py_DECREF(t); } } if (SUCCEEDED(values->GetStringValue(WPD_DEVICE_FRIENDLY_NAME, &temp))) { t = PyUnicode_FromWideChar(temp, wcslen(temp)); if (t != NULL) {PyDict_SetItemString(ans, "friendly_name", t); Py_DECREF(t);} CoTaskMemFree(temp); } if (SUCCEEDED(values->GetStringValue(WPD_DEVICE_MANUFACTURER, &temp))) { t = PyUnicode_FromWideChar(temp, wcslen(temp)); if (t != NULL) {PyDict_SetItemString(ans, "manufacturer_name", t); Py_DECREF(t);} CoTaskMemFree(temp); } if (SUCCEEDED(values->GetStringValue(WPD_DEVICE_MODEL, &temp))) { t = PyUnicode_FromWideChar(temp, wcslen(temp)); if (t != NULL) {PyDict_SetItemString(ans, "model_name", t); Py_DECREF(t);} CoTaskMemFree(temp); } if (SUCCEEDED(values->GetStringValue(WPD_DEVICE_SERIAL_NUMBER, &temp))) { t = PyUnicode_FromWideChar(temp, wcslen(temp)); if (t != NULL) {PyDict_SetItemString(ans, "serial_number", t); Py_DECREF(t);} CoTaskMemFree(temp); } if (SUCCEEDED(values->GetStringValue(WPD_DEVICE_FIRMWARE_VERSION, &temp))) { t = PyUnicode_FromWideChar(temp, wcslen(temp)); if (t != NULL) {PyDict_SetItemString(ans, "device_version", t); Py_DECREF(t);} CoTaskMemFree(temp); } t = Py_False; for (i = 0; i < num_of_categories; i++) { PROPVARIANT pv; PropVariantInit(&pv); if (SUCCEEDED(categories->GetAt(i, &pv)) && pv.puuid != NULL) { if (IsEqualGUID(WPD_FUNCTIONAL_CATEGORY_STORAGE, *pv.puuid)) { t = Py_True; } } PropVariantClear(&pv); if (t == Py_True) break; } PyDict_SetItemString(ans, "has_storage", t); if (t == Py_True) { storage = get_storage_info(device); if (storage == NULL) { PyObject *exc_type, *exc_value, *exc_tb; PyErr_Fetch(&exc_type, &exc_value, &exc_tb); if (exc_type != NULL && exc_value != NULL) { PyErr_NormalizeException(&exc_type, &exc_value, &exc_tb); PyDict_SetItemString(ans, "storage_error", exc_value); Py_DECREF(exc_value); exc_value = NULL; } Py_XDECREF(exc_type); Py_XDECREF(exc_value); Py_XDECREF(exc_tb); goto end; } PyDict_SetItemString(ans, "storage", storage); } Py_BEGIN_ALLOW_THREADS; hr = properties->QueryInterface(IID_PPV_ARGS(&properties_bulk)); Py_END_ALLOW_THREADS; PyDict_SetItemString(ans, "has_bulk_properties", (FAILED(hr)) ? Py_False: Py_True); if (pb != NULL) *pb = (SUCCEEDED(hr)) ? properties_bulk : NULL; end: if (keys != NULL) keys->Release(); if (values != NULL) values->Release(); if (properties != NULL) properties->Release(); if (properties_bulk != NULL && pb == NULL) properties_bulk->Release(); if (content != NULL) content->Release(); if (capabilities != NULL) capabilities->Release(); if (categories != NULL) categories->Release(); return ans; } // }}}