mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Use RAII for get_storage_info()
This commit is contained in:
parent
014f7fe82a
commit
d7150a4b86
@ -45,13 +45,13 @@ IPortableDeviceValues *get_client_information() { // {{{
|
||||
return client_information.Detach();
|
||||
} // }}}
|
||||
|
||||
IPortableDevice *open_device(const wchar_t *pnp_id, CComPtr<IPortableDeviceValues> &client_information) { // {{{
|
||||
IPortableDevice *device = NULL;
|
||||
IPortableDevice*
|
||||
open_device(const wchar_t *pnp_id, CComPtr<IPortableDeviceValues> &client_information) { // {{{
|
||||
CComPtr<IPortableDevice> device;
|
||||
HRESULT hr;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
hr = CoCreateInstance(CLSID_PortableDevice, NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_PPV_ARGS(&device));
|
||||
hr = device.CoCreateInstance(CLSID_PortableDevice, NULL, CLSCTX_INPROC_SERVER);
|
||||
Py_END_ALLOW_THREADS;
|
||||
if (FAILED(hr)) { hresult_set_exc("Failed to create IPortableDevice", hr); device = NULL; }
|
||||
else {
|
||||
@ -60,82 +60,80 @@ IPortableDevice *open_device(const wchar_t *pnp_id, CComPtr<IPortableDeviceValue
|
||||
Py_END_ALLOW_THREADS;
|
||||
if FAILED(hr) {
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
device->Release();
|
||||
device.Release();
|
||||
Py_END_ALLOW_THREADS;
|
||||
device = NULL;
|
||||
hresult_set_exc((hr == E_ACCESSDENIED) ? "Read/write access to device is denied": "Failed to open device", hr);
|
||||
}
|
||||
}
|
||||
|
||||
return device;
|
||||
return device.Detach();
|
||||
|
||||
} // }}}
|
||||
|
||||
PyObject* get_storage_info(IPortableDevice *device) { // {{{
|
||||
static 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;
|
||||
CComPtr<IPortableDeviceContent> content = NULL;
|
||||
CComPtr<IEnumPortableDeviceObjectIDs> objects = NULL;
|
||||
CComPtr<IPortableDeviceProperties> properties = NULL;
|
||||
CComPtr<IPortableDeviceKeyCollection> storage_properties = 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; }
|
||||
pyobject_raii storage(PyList_New(0));
|
||||
if (!storage) return NULL;
|
||||
|
||||
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;}
|
||||
if (FAILED(hr)) {hresult_set_exc("Failed to get content interface from device", hr); return NULL;}
|
||||
|
||||
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;}
|
||||
if (FAILED(hr)) {hresult_set_exc("Failed to get properties interface", hr); return NULL;}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
hr = CoCreateInstance(CLSID_PortableDeviceKeyCollection, NULL,
|
||||
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&storage_properties));
|
||||
hr = storage_properties.CoCreateInstance(CLSID_PortableDeviceKeyCollection, NULL, CLSCTX_INPROC_SERVER);
|
||||
Py_END_ALLOW_THREADS;
|
||||
if (FAILED(hr)) {hresult_set_exc("Failed to create storage properties collection", hr); goto end;}
|
||||
if (FAILED(hr)) {hresult_set_exc("Failed to create storage properties collection", hr); return NULL;}
|
||||
|
||||
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; }
|
||||
#define A(what) hr = storage_properties->Add(what); if (FAILED(hr)) { hresult_set_exc("Failed to add storage property " #what " for storage query", hr); return NULL; }
|
||||
A(WPD_OBJECT_CONTENT_TYPE);
|
||||
A(WPD_FUNCTIONAL_OBJECT_CATEGORY);
|
||||
A(WPD_STORAGE_DESCRIPTION);
|
||||
A(WPD_STORAGE_CAPACITY);
|
||||
A(WPD_STORAGE_CAPACITY_IN_OBJECTS);
|
||||
A(WPD_STORAGE_FREE_SPACE_IN_BYTES);
|
||||
A(WPD_STORAGE_FREE_SPACE_IN_OBJECTS);
|
||||
A(WPD_STORAGE_ACCESS_CAPABILITY);
|
||||
A(WPD_STORAGE_FILE_SYSTEM_TYPE);
|
||||
A(WPD_STORAGE_TYPE);
|
||||
A(WPD_OBJECT_NAME);
|
||||
#undef A
|
||||
|
||||
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;}
|
||||
if (FAILED(hr)) {hresult_set_exc("Failed to get objects from device", hr); return NULL;}
|
||||
|
||||
hr = S_OK;
|
||||
while (hr == S_OK) {
|
||||
wchar_t* object_ids[16] = {0};
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
hr = objects->Next(10, object_ids, &fetched);
|
||||
hr = objects->Next(arraysz(object_ids), object_ids, &fetched);
|
||||
Py_END_ALLOW_THREADS;
|
||||
if (SUCCEEDED(hr)) {
|
||||
com_wchar_raii cleanup[arraysz(object_ids)];
|
||||
for (i = 0; i < arraysz(object_ids); i++) { cleanup[i].set_ptr(object_ids[i]); };
|
||||
for(i = 0; i < fetched; i++) {
|
||||
CComPtr<IPortableDeviceValues> values;
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
hr2 = properties->GetValues(object_ids[i], storage_properties, &values);
|
||||
Py_END_ALLOW_THREADS;
|
||||
if SUCCEEDED(hr2) {
|
||||
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)
|
||||
@ -146,28 +144,23 @@ PyObject* get_storage_info(IPortableDevice *device) { // {{{
|
||||
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;
|
||||
}
|
||||
PyObject *paccess = Py_False;
|
||||
if (SUCCEEDED(values->GetUnsignedIntegerValue(WPD_STORAGE_ACCESS_CAPABILITY, &access)) && access == WPD_STORAGE_ACCESS_CAPABILITY_READWRITE) paccess = Py_True;
|
||||
pyobject_raii soid(PyUnicode_FromWideChar(object_ids[i], -1));
|
||||
if (!soid) return NULL;
|
||||
pyobject_raii so(Py_BuildValue("{s:K, s:K, s:K, s:K, s:O, s:O}",
|
||||
"capacity", capacity, "capacity_objects", capacity_objects, "free_space", free_space, "free_objects", free_objects, "rw", paccess, "id", soid.ptr()));
|
||||
if (!so) return NULL;
|
||||
#define A(which, key) { com_wchar_raii buf; if (SUCCEEDED(values->GetStringValue(which, buf.address()))) { \
|
||||
pyobject_raii d(PyUnicode_FromWideChar(buf.ptr(), -1)); \
|
||||
if (d) PyDict_SetItemString(so.ptr(), key, d.ptr()); \
|
||||
else PyErr_Clear(); \
|
||||
}}
|
||||
A(WPD_STORAGE_DESCRIPTION, "description");
|
||||
A(WPD_OBJECT_NAME, "name");
|
||||
A(WPD_STORAGE_FILE_SYSTEM_TYPE, "filesystem");
|
||||
#undef A
|
||||
const wchar_t *st;
|
||||
switch(storage_type) {
|
||||
case WPD_STORAGE_TYPE_REMOVABLE_RAM:
|
||||
st = L"removable_ram";
|
||||
@ -184,26 +177,15 @@ PyObject* get_storage_info(IPortableDevice *device) { // {{{
|
||||
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);
|
||||
pyobject_raii dt(PyUnicode_FromWideChar(st, -1));
|
||||
if (dt) PyDict_SetItemString(so.ptr(), "type", dt.ptr());
|
||||
if (PyList_Append(storage.ptr(), so.ptr()) != 0) return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
return storage.detach();
|
||||
} // }}}
|
||||
|
||||
PyObject*
|
||||
@ -219,7 +201,7 @@ get_device_information(CComPtr<IPortableDevice> &device, IPortableDeviceProperti
|
||||
DWORD num_of_categories, i;
|
||||
LPWSTR temp;
|
||||
ULONG ti;
|
||||
PyObject *t, *ans = NULL, *storage = NULL;
|
||||
PyObject *t, *ans = NULL;
|
||||
const char *type = NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
@ -286,6 +268,7 @@ get_device_information(CComPtr<IPortableDevice> &device, IPortableDeviceProperti
|
||||
// }
|
||||
|
||||
if (SUCCEEDED(values->GetUnsignedIntegerValue(WPD_DEVICE_TYPE, &ti))) {
|
||||
type = "unknown";
|
||||
switch (ti) {
|
||||
case WPD_DEVICE_TYPE_CAMERA:
|
||||
type = "camera"; break;
|
||||
@ -299,8 +282,8 @@ get_device_information(CComPtr<IPortableDevice> &device, IPortableDeviceProperti
|
||||
type = "personal information manager"; break;
|
||||
case WPD_DEVICE_TYPE_AUDIO_RECORDER:
|
||||
type = "audio recorder"; break;
|
||||
default:
|
||||
type = "unknown";
|
||||
case WPD_DEVICE_TYPE_GENERIC:
|
||||
break;
|
||||
}
|
||||
t = PyUnicode_FromString(type);
|
||||
if (t != NULL) {
|
||||
@ -353,20 +336,19 @@ get_device_information(CComPtr<IPortableDevice> &device, IPortableDeviceProperti
|
||||
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);
|
||||
|
||||
pyobject_raii storage(get_storage_info(device));
|
||||
if (!storage) {
|
||||
pyobject_raii exc_type, exc_value, exc_tb;
|
||||
PyErr_Fetch(exc_type.address(), exc_value.address(), exc_tb.address());
|
||||
if (exc_type) {
|
||||
PyErr_NormalizeException(exc_type.address(), exc_value.address(), exc_tb.address());
|
||||
PyDict_SetItemString(ans, "storage_error", exc_value.ptr());
|
||||
} else {
|
||||
PyDict_SetItemString(ans, "storage_error", PyUnicode_FromString("get_storage_info() failed without an error set"));
|
||||
}
|
||||
} else {
|
||||
PyDict_SetItemString(ans, "storage", storage.ptr());
|
||||
}
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
|
@ -45,7 +45,9 @@ class wchar_raii {
|
||||
}
|
||||
|
||||
wchar_t *ptr() { return handle; }
|
||||
wchar_t *detach() { wchar_t *ans = handle; handle = NULL; return ans; }
|
||||
void set_ptr(wchar_t *val) { handle = val; }
|
||||
wchar_t **address() { return &handle; }
|
||||
explicit operator bool() const { return handle != NULL; }
|
||||
};
|
||||
|
||||
@ -67,6 +69,8 @@ class com_wchar_raii {
|
||||
}
|
||||
|
||||
wchar_t *ptr() { return handle; }
|
||||
void set_ptr(wchar_t *val) { handle = val; }
|
||||
wchar_t *detach() { wchar_t *ans = handle; handle = NULL; return ans; }
|
||||
wchar_t **address() { return &handle; }
|
||||
explicit operator bool() const { return handle != NULL; }
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user