mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 10:44:09 -04:00
WPD: Refactor, splitting into multiple translation units
This commit is contained in:
parent
263b648fc0
commit
015ed143be
@ -169,7 +169,14 @@ if iswindows:
|
|||||||
cflags=['/X']
|
cflags=['/X']
|
||||||
),
|
),
|
||||||
Extension('wpd',
|
Extension('wpd',
|
||||||
['calibre/devices/mtp/windows/wpd.cpp'],
|
[
|
||||||
|
'calibre/devices/mtp/windows/utils.cpp',
|
||||||
|
'calibre/devices/mtp/windows/device_enumeration.cpp',
|
||||||
|
'calibre/devices/mtp/windows/wpd.cpp',
|
||||||
|
],
|
||||||
|
headers=[
|
||||||
|
'calibre/devices/mtp/windows/global.h',
|
||||||
|
],
|
||||||
libraries=['ole32', 'portabledeviceguids'],
|
libraries=['ole32', 'portabledeviceguids'],
|
||||||
# needs_ddk=True,
|
# needs_ddk=True,
|
||||||
cflags=['/X']
|
cflags=['/X']
|
||||||
|
195
src/calibre/devices/mtp/windows/device_enumeration.cpp
Normal file
195
src/calibre/devices/mtp/windows/device_enumeration.cpp
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* device_enumeration.cpp
|
||||||
|
* Copyright (C) 2012 Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the MIT license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
namespace wpd {
|
||||||
|
|
||||||
|
IPortableDeviceValues *get_client_information() { // {{{
|
||||||
|
IPortableDeviceValues *client_information;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
ENSURE_WPD(NULL);
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = CoCreateInstance(CLSID_PortableDeviceValues, NULL,
|
||||||
|
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&client_information));
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (FAILED(hr)) { hresult_set_exc("Failed to create IPortableDeviceValues", hr); return NULL; }
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = client_information->SetStringValue(WPD_CLIENT_NAME, client_info.name);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (FAILED(hr)) { hresult_set_exc("Failed to set client name", hr); return NULL; }
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = client_information->SetUnsignedIntegerValue(WPD_CLIENT_MAJOR_VERSION, client_info.major_version);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (FAILED(hr)) { hresult_set_exc("Failed to set major version", hr); return NULL; }
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = client_information->SetUnsignedIntegerValue(WPD_CLIENT_MINOR_VERSION, client_info.minor_version);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (FAILED(hr)) { hresult_set_exc("Failed to set minor version", hr); return NULL; }
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = client_information->SetUnsignedIntegerValue(WPD_CLIENT_REVISION, client_info.revision);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (FAILED(hr)) { hresult_set_exc("Failed to set revision", hr); return NULL; }
|
||||||
|
// Some device drivers need to impersonate the caller in order to function correctly. Since our application does not
|
||||||
|
// need to restrict its identity, specify SECURITY_IMPERSONATION so that we work with all devices.
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = client_information->SetUnsignedIntegerValue(WPD_CLIENT_SECURITY_QUALITY_OF_SERVICE, SECURITY_IMPERSONATION);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (FAILED(hr)) { hresult_set_exc("Failed to set quality of service", hr); return NULL; }
|
||||||
|
return client_information;
|
||||||
|
} // }}}
|
||||||
|
|
||||||
|
IPortableDevice *open_device(const wchar_t *pnp_id, IPortableDeviceValues *client_information) { // {{{
|
||||||
|
IPortableDevice *device = NULL;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = CoCreateInstance(CLSID_PortableDevice, NULL, CLSCTX_INPROC_SERVER,
|
||||||
|
IID_PPV_ARGS(&device));
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if (FAILED(hr)) hresult_set_exc("Failed to create IPortableDevice", hr);
|
||||||
|
else {
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
hr = device->Open(pnp_id, client_information);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
if FAILED(hr) {
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
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;
|
||||||
|
|
||||||
|
} // }}}
|
||||||
|
|
||||||
|
PyObject* get_device_information(IPortableDevice *device) { // {{{
|
||||||
|
IPortableDeviceContent *content = NULL;
|
||||||
|
IPortableDeviceProperties *properties = NULL;
|
||||||
|
IPortableDeviceKeyCollection *keys = NULL;
|
||||||
|
IPortableDeviceValues *values = NULL;
|
||||||
|
HRESULT hr;
|
||||||
|
LPWSTR temp;
|
||||||
|
ULONG ti;
|
||||||
|
PyObject *t, *ans = NULL;
|
||||||
|
char *type;
|
||||||
|
|
||||||
|
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; }
|
||||||
|
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
t = PyString_FromString(type);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (keys != NULL) keys->Release();
|
||||||
|
if (values != NULL) values->Release();
|
||||||
|
if (properties != NULL) properties->Release();
|
||||||
|
if (content != NULL) content->Release();
|
||||||
|
return ans;
|
||||||
|
} // }}}
|
||||||
|
|
||||||
|
} // namespace wpd
|
46
src/calibre/devices/mtp/windows/global.h
Normal file
46
src/calibre/devices/mtp/windows/global.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* global.h
|
||||||
|
* Copyright (C) 2012 Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the MIT license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#define UNICODE
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
#include <Objbase.h>
|
||||||
|
#include <PortableDeviceApi.h>
|
||||||
|
#include <PortableDevice.h>
|
||||||
|
|
||||||
|
#define ENSURE_WPD(retval) \
|
||||||
|
if (portable_device_manager == NULL) { PyErr_SetString(NoWPD, "No WPD service available."); return retval; }
|
||||||
|
|
||||||
|
namespace wpd {
|
||||||
|
|
||||||
|
// Module exception types
|
||||||
|
extern PyObject *WPDError, *NoWPD;
|
||||||
|
|
||||||
|
// The global device manager
|
||||||
|
extern IPortableDeviceManager *portable_device_manager;
|
||||||
|
|
||||||
|
// Application info
|
||||||
|
typedef struct {
|
||||||
|
wchar_t *name;
|
||||||
|
unsigned int major_version;
|
||||||
|
unsigned int minor_version;
|
||||||
|
unsigned int revision;
|
||||||
|
} ClientInfo;
|
||||||
|
extern ClientInfo client_info;
|
||||||
|
|
||||||
|
// Utility functions
|
||||||
|
PyObject *hresult_set_exc(const char *msg, HRESULT hr);
|
||||||
|
wchar_t *unicode_to_wchar(PyObject *o);
|
||||||
|
|
||||||
|
extern IPortableDeviceValues* get_client_information();
|
||||||
|
extern IPortableDevice* open_device(const wchar_t *pnp_id, IPortableDeviceValues *client_information);
|
||||||
|
extern PyObject* get_device_information(IPortableDevice *device);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
45
src/calibre/devices/mtp/windows/utils.cpp
Normal file
45
src/calibre/devices/mtp/windows/utils.cpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* utils.cpp
|
||||||
|
* Copyright (C) 2012 Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the MIT license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
using namespace wpd;
|
||||||
|
|
||||||
|
PyObject *wpd::hresult_set_exc(const char *msg, HRESULT hr) {
|
||||||
|
PyObject *o = NULL, *mess;
|
||||||
|
LPWSTR desc = NULL;
|
||||||
|
|
||||||
|
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&desc, 0, NULL);
|
||||||
|
if (desc == NULL) {
|
||||||
|
o = PyUnicode_FromString("No description available.");
|
||||||
|
} else {
|
||||||
|
o = PyUnicode_FromWideChar(desc, wcslen(desc));
|
||||||
|
LocalFree(desc);
|
||||||
|
}
|
||||||
|
if (o == NULL) return PyErr_NoMemory();
|
||||||
|
mess = PyUnicode_FromFormat("%s: hr=%lu facility=%u error_code=%u description: %U", msg, hr, HRESULT_FACILITY(hr), HRESULT_CODE(hr), o);
|
||||||
|
Py_XDECREF(o);
|
||||||
|
if (mess == NULL) return PyErr_NoMemory();
|
||||||
|
PyErr_SetObject(WPDError, mess);
|
||||||
|
Py_DECREF(mess);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *wpd::unicode_to_wchar(PyObject *o) {
|
||||||
|
wchar_t *buf;
|
||||||
|
Py_ssize_t len;
|
||||||
|
if (!PyUnicode_Check(o)) {PyErr_Format(PyExc_TypeError, "The pnp id must be a unicode object"); return NULL;}
|
||||||
|
len = PyUnicode_GET_SIZE(o);
|
||||||
|
if (len < 1) {PyErr_Format(PyExc_TypeError, "The pnp id must not be empty."); return NULL;}
|
||||||
|
buf = (wchar_t *)calloc(len+2, sizeof(wchar_t));
|
||||||
|
if (buf == NULL) { PyErr_NoMemory(); return NULL; }
|
||||||
|
len = PyUnicode_AsWideChar((PyUnicodeObject*)o, buf, len);
|
||||||
|
if (len == -1) { free(buf); PyErr_Format(PyExc_TypeError, "Invalid pnp id."); return NULL; }
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
@ -5,248 +5,24 @@
|
|||||||
* Distributed under terms of the MIT license.
|
* Distributed under terms of the MIT license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
#define UNICODE
|
using namespace wpd;
|
||||||
#include <Windows.h>
|
|
||||||
#include <Python.h>
|
|
||||||
|
|
||||||
#include <Objbase.h>
|
// Module exception types
|
||||||
#include <PortableDeviceApi.h>
|
PyObject *wpd::WPDError = NULL, *wpd::NoWPD = NULL;
|
||||||
#include <PortableDevice.h>
|
|
||||||
|
|
||||||
// Utility functions {{{
|
// The global device manager
|
||||||
#define ENSURE_WPD(retval) \
|
IPortableDeviceManager *wpd::portable_device_manager = NULL;
|
||||||
if (portable_device_manager == NULL) { PyErr_SetString(NoWPD, "No WPD service available."); return retval; }
|
|
||||||
|
|
||||||
static PyObject *WPDError = NULL, *NoWPD = NULL;
|
// Flag indicating if COM has been initialized
|
||||||
static IPortableDeviceManager *portable_device_manager = NULL;
|
|
||||||
static int _com_initialized = 0;
|
static int _com_initialized = 0;
|
||||||
typedef struct {
|
// Application Info
|
||||||
wchar_t *name;
|
wpd::ClientInfo wpd::client_info = {NULL, 0, 0, 0};
|
||||||
unsigned int major_version;
|
|
||||||
unsigned int minor_version;
|
|
||||||
unsigned int revision;
|
|
||||||
} ClientInfo;
|
|
||||||
static ClientInfo client_info = {NULL, 0, 0, 0};
|
|
||||||
|
|
||||||
static PyObject *hresult_set_exc(const char *msg, HRESULT hr) {
|
extern IPortableDeviceValues* wpd::get_client_information();
|
||||||
PyObject *o = NULL, *mess;
|
extern IPortableDevice* wpd::open_device(const wchar_t *pnp_id, IPortableDeviceValues *client_information);
|
||||||
LPWSTR desc = NULL;
|
extern PyObject* wpd::get_device_information(IPortableDevice *device);
|
||||||
|
|
||||||
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
||||||
NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&desc, 0, NULL);
|
|
||||||
if (desc == NULL) {
|
|
||||||
o = PyUnicode_FromString("No description available.");
|
|
||||||
} else {
|
|
||||||
o = PyUnicode_FromWideChar(desc, wcslen(desc));
|
|
||||||
LocalFree(desc);
|
|
||||||
}
|
|
||||||
if (o == NULL) return PyErr_NoMemory();
|
|
||||||
mess = PyUnicode_FromFormat("%s: hr=%lu facility=%u error_code=%u description: %U", msg, hr, HRESULT_FACILITY(hr), HRESULT_CODE(hr), o);
|
|
||||||
Py_XDECREF(o);
|
|
||||||
if (mess == NULL) return PyErr_NoMemory();
|
|
||||||
PyErr_SetObject(WPDError, mess);
|
|
||||||
Py_DECREF(mess);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static wchar_t *unicode_to_wchar(PyObject *o) {
|
|
||||||
wchar_t *buf;
|
|
||||||
Py_ssize_t len;
|
|
||||||
if (!PyUnicode_Check(o)) {PyErr_Format(PyExc_TypeError, "The pnp id must be a unicode object"); return NULL;}
|
|
||||||
len = PyUnicode_GET_SIZE(o);
|
|
||||||
if (len < 1) {PyErr_Format(PyExc_TypeError, "The pnp id must not be empty."); return NULL;}
|
|
||||||
buf = (wchar_t *)calloc(len+2, sizeof(wchar_t));
|
|
||||||
if (buf == NULL) { PyErr_NoMemory(); return NULL; }
|
|
||||||
len = PyUnicode_AsWideChar((PyUnicodeObject*)o, buf, len);
|
|
||||||
if (len == -1) { free(buf); PyErr_Format(PyExc_TypeError, "Invalid pnp id."); return NULL; }
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
static IPortableDeviceValues *get_client_information() { // {{{
|
|
||||||
IPortableDeviceValues *client_information;
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
ENSURE_WPD(NULL);
|
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
hr = CoCreateInstance(CLSID_PortableDeviceValues, NULL,
|
|
||||||
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&client_information));
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
if (FAILED(hr)) { hresult_set_exc("Failed to create IPortableDeviceValues", hr); return NULL; }
|
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
hr = client_information->SetStringValue(WPD_CLIENT_NAME, client_info.name);
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
if (FAILED(hr)) { hresult_set_exc("Failed to set client name", hr); return NULL; }
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
hr = client_information->SetUnsignedIntegerValue(WPD_CLIENT_MAJOR_VERSION, client_info.major_version);
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
if (FAILED(hr)) { hresult_set_exc("Failed to set major version", hr); return NULL; }
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
hr = client_information->SetUnsignedIntegerValue(WPD_CLIENT_MINOR_VERSION, client_info.minor_version);
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
if (FAILED(hr)) { hresult_set_exc("Failed to set minor version", hr); return NULL; }
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
hr = client_information->SetUnsignedIntegerValue(WPD_CLIENT_REVISION, client_info.revision);
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
if (FAILED(hr)) { hresult_set_exc("Failed to set revision", hr); return NULL; }
|
|
||||||
// Some device drivers need to impersonate the caller in order to function correctly. Since our application does not
|
|
||||||
// need to restrict its identity, specify SECURITY_IMPERSONATION so that we work with all devices.
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
hr = client_information->SetUnsignedIntegerValue(WPD_CLIENT_SECURITY_QUALITY_OF_SERVICE, SECURITY_IMPERSONATION);
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
if (FAILED(hr)) { hresult_set_exc("Failed to set quality of service", hr); return NULL; }
|
|
||||||
return client_information;
|
|
||||||
} // }}}
|
|
||||||
|
|
||||||
static IPortableDevice *open_device(const wchar_t *pnp_id, IPortableDeviceValues *client_information) { // {{{
|
|
||||||
IPortableDevice *device = NULL;
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
hr = CoCreateInstance(CLSID_PortableDevice, NULL, CLSCTX_INPROC_SERVER,
|
|
||||||
IID_PPV_ARGS(&device));
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
if (FAILED(hr)) hresult_set_exc("Failed to create IPortableDevice", hr);
|
|
||||||
else {
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
hr = device->Open(pnp_id, client_information);
|
|
||||||
Py_END_ALLOW_THREADS;
|
|
||||||
if FAILED(hr) {
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
|
||||||
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;
|
|
||||||
|
|
||||||
} // }}}
|
|
||||||
|
|
||||||
static PyObject* get_device_information(IPortableDevice *device) { // {{{
|
|
||||||
IPortableDeviceContent *content = NULL;
|
|
||||||
IPortableDeviceProperties *properties = NULL;
|
|
||||||
IPortableDeviceKeyCollection *keys = NULL;
|
|
||||||
IPortableDeviceValues *values = NULL;
|
|
||||||
HRESULT hr;
|
|
||||||
LPWSTR temp;
|
|
||||||
ULONG ti;
|
|
||||||
PyObject *t, *ans = NULL;
|
|
||||||
char *type;
|
|
||||||
|
|
||||||
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; }
|
|
||||||
|
|
||||||
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";
|
|
||||||
}
|
|
||||||
t = PyString_FromString(type);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
|
||||||
if (keys != NULL) keys->Release();
|
|
||||||
if (values != NULL) values->Release();
|
|
||||||
if (properties != NULL) properties->Release();
|
|
||||||
if (content != NULL) content->Release();
|
|
||||||
return ans;
|
|
||||||
} // }}}
|
|
||||||
|
|
||||||
// }}}
|
|
||||||
|
|
||||||
// Module startup/shutdown {{{
|
// Module startup/shutdown {{{
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
Loading…
x
Reference in New Issue
Block a user