diff --git a/setup/build_environment.py b/setup/build_environment.py index 136976b251..58d2006ee7 100644 --- a/setup/build_environment.py +++ b/setup/build_environment.py @@ -17,7 +17,7 @@ OSX_SDK = '/Developer/SDKs/MacOSX10.5.sdk' os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.5' -NMAKE = RC = msvc = MT = win_inc = win_lib = win_ddk = None +NMAKE = RC = msvc = MT = win_inc = win_lib = win_ddk = win_ddk_lib_dirs = None if iswindows: from distutils import msvc9compiler msvc = msvc9compiler.MSVCCompiler() @@ -26,7 +26,8 @@ if iswindows: RC = msvc.find_exe('rc.exe') SDK = os.environ.get('WINSDK', r'C:\Program Files\Microsoft SDKs\Windows\v6.0A') DDK = os.environ.get('WINDDK', r'Q:\WinDDK\7600.16385.0') - win_ddk = [DDK+'\\inc\\'+x for x in ('api',)] + win_ddk = [DDK+'\\inc\\'+x for x in ('atl71',)] + win_ddk_lib_dirs = [DDK+'\\lib\\ATL\\i386'] win_inc = os.environ['include'].split(';') win_lib = os.environ['lib'].split(';') for p in win_inc: diff --git a/setup/extensions.py b/setup/extensions.py index 964d4d9839..bc6e41089e 100644 --- a/setup/extensions.py +++ b/setup/extensions.py @@ -17,7 +17,7 @@ from setup.build_environment import (fc_inc, fc_lib, chmlib_inc_dirs, fc_error, podofo_inc, podofo_lib, podofo_error, pyqt, OSX_SDK, NMAKE, QMAKE, msvc, MT, win_inc, win_lib, win_ddk, magick_inc_dirs, magick_lib_dirs, magick_libs, chmlib_lib_dirs, sqlite_inc_dirs, icu_inc_dirs, - icu_lib_dirs) + icu_lib_dirs, win_ddk_lib_dirs) MT isunix = islinux or isosx or isbsd @@ -162,11 +162,19 @@ extensions = [ if iswindows: - extensions.append(Extension('winutil', + extensions.extend([ + Extension('winutil', ['calibre/utils/windows/winutil.c'], libraries=['shell32', 'setupapi', 'wininet'], cflags=['/X'] - )) + ), + Extension('wpd', + ['calibre/devices/mtp/windows/wpd.cpp'], + libraries=['ole32', 'portabledeviceguids'], + # needs_ddk=True, + cflags=['/X'] + ), + ]) if isosx: extensions.append(Extension('usbobserver', @@ -325,8 +333,8 @@ class Build(Command): obj_dir = self.j(self.obj_dir, ext.name) if ext.needs_ddk: ddk_flags = ['-I'+x for x in win_ddk] - i = [i for i in range(len(cflags)) if 'VC\\INCLUDE' in cflags[i]][0] - cflags[i+1:i+2] = ddk_flags + cflags.extend(ddk_flags) + ldflags.extend(['/LIBPATH:'+x for x in win_ddk_lib_dirs]) if not os.path.exists(obj_dir): os.makedirs(obj_dir) for src in ext.sources: diff --git a/src/calibre/constants.py b/src/calibre/constants.py index 63119c5363..77a2bae615 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -90,7 +90,7 @@ class Plugins(collections.Mapping): 'speedup', ] if iswindows: - plugins.append('winutil') + plugins.extend(['winutil', 'wpd']) if isosx: plugins.append('usbobserver') if islinux: diff --git a/src/calibre/devices/mtp/windows/wpd.cpp b/src/calibre/devices/mtp/windows/wpd.cpp new file mode 100644 index 0000000000..f4029e7061 --- /dev/null +++ b/src/calibre/devices/mtp/windows/wpd.cpp @@ -0,0 +1,85 @@ +/* + * mtp.c + * Copyright (C) 2012 Kovid Goyal + * + * Distributed under terms of the MIT license. + */ + + +#define UNICODE +#include +#include + +#include +#include + +static int _com_initialized = 0; +static PyObject *WPDError; +static IPortableDeviceManager *portable_device_manager = NULL; + +static PyObject * +wpd_init(PyObject *self, PyObject *args) { + HRESULT hr; + + if (!_com_initialized) { + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + if (SUCCEEDED(hr)) _com_initialized = 1; + else {PyErr_SetString(WPDError, "Failed to initialize COM"); return NULL;} + } + + if (portable_device_manager == NULL) { + hr = CoCreateInstance(CLSID_PortableDeviceManager, NULL, + CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&portable_device_manager)); + + if (FAILED(hr)) { + PyErr_SetString(WPDError, (hr == REGDB_E_CLASSNOTREG) ? + "This computer is not running the Windows Portable Device framework. You may need to install Windows Media Player 11 or newer." : + "Failed to create the WPD device manager interface"); + return NULL; + } + } + + Py_RETURN_NONE; +} + +static PyObject * +wpd_uninit(PyObject *self, PyObject *args) { + if (_com_initialized) { + CoUninitialize(); + _com_initialized = 0; + } + + if (portable_device_manager != NULL) { + portable_device_manager->Release(); + portable_device_manager = NULL; + } + + Py_RETURN_NONE; +} + +static PyMethodDef wpd_methods[] = { + {"init", wpd_init, METH_VARARGS, + "init()\n\n Initializes this module. Call this method *only* in the thread in which you intend to use this module. Also remember to call uninit before the thread exits." + }, + + {"uninit", wpd_uninit, METH_VARARGS, + "uninit()\n\n Uninitialize this module. Must be called in the same thread as init(). Do not use any function/objects from this module after uninit has been called." + }, + + {NULL, NULL, 0, NULL} +}; + + +PyMODINIT_FUNC +initwpd(void) { + PyObject *m; + + m = Py_InitModule3("wpd", wpd_methods, "Interface to the WPD windows service."); + if (m == NULL) return; + + WPDError = PyErr_NewException("wpd.WPDError", NULL, NULL); + if (WPDError == NULL) return; + +} + +