1
0
mirror of https://github.com/clementine-player/Clementine synced 2025-01-31 11:35:24 +01:00

Get the drive letter for MSC WMDM devices on Windows 7

This commit is contained in:
David Sansome 2010-08-30 19:58:01 +00:00
parent a59025cdec
commit 1dd6ac323e
4 changed files with 112 additions and 113 deletions

View File

@ -41,7 +41,7 @@ pkg_check_modules(LIBMTP libmtp)
if (WIN32)
find_package(ZLIB REQUIRED)
find_library(MSWMDM_LIBRARIES MSWMDM)
find_library(MSWMDM_LIBRARIES mswmdm)
find_library(SAC_SHIM_LIBRARIES sac_shim)
endif (WIN32)

View File

@ -53,91 +53,6 @@
#ifdef Q_OS_WIN32
# include <mswmdm.h>
# include <QUuid>
// Copied from the WMDM SDK 11, it doesn't seem to be included in SDK 9 for
// some reason, even though the devices use it.
typedef enum tagWMDM_FORMATCODE {
WMDM_FORMATCODE_NOTUSED = 0x0000,
WMDM_FORMATCODE_ALLIMAGES = 0xFFFFFFFF,
WMDM_FORMATCODE_UNDEFINED = 0x3000,
WMDM_FORMATCODE_ASSOCIATION = 0x3001,
WMDM_FORMATCODE_SCRIPT = 0x3002,
WMDM_FORMATCODE_EXECUTABLE = 0x3003,
WMDM_FORMATCODE_TEXT = 0x3004,
WMDM_FORMATCODE_HTML = 0x3005,
WMDM_FORMATCODE_DPOF = 0x3006,
WMDM_FORMATCODE_AIFF = 0x3007,
WMDM_FORMATCODE_WAVE = 0x3008,
WMDM_FORMATCODE_MP3 = 0x3009,
WMDM_FORMATCODE_AVI = 0x300A,
WMDM_FORMATCODE_MPEG = 0x300B,
WMDM_FORMATCODE_ASF = 0x300C,
WMDM_FORMATCODE_RESERVED_FIRST = 0x300D,
WMDM_FORMATCODE_RESERVED_LAST = 0x37FF,
WMDM_FORMATCODE_IMAGE_UNDEFINED = 0x3800,
WMDM_FORMATCODE_IMAGE_EXIF = 0x3801,
WMDM_FORMATCODE_IMAGE_TIFFEP = 0x3802,
WMDM_FORMATCODE_IMAGE_FLASHPIX = 0x3803,
WMDM_FORMATCODE_IMAGE_BMP = 0x3804,
WMDM_FORMATCODE_IMAGE_CIFF = 0x3805,
WMDM_FORMATCODE_IMAGE_GIF = 0x3807,
WMDM_FORMATCODE_IMAGE_JFIF = 0x3808,
WMDM_FORMATCODE_IMAGE_PCD = 0x3809,
WMDM_FORMATCODE_IMAGE_PICT = 0x380A,
WMDM_FORMATCODE_IMAGE_PNG = 0x380B,
WMDM_FORMATCODE_IMAGE_TIFF = 0x380D,
WMDM_FORMATCODE_IMAGE_TIFFIT = 0x380E,
WMDM_FORMATCODE_IMAGE_JP2 = 0x380F,
WMDM_FORMATCODE_IMAGE_JPX = 0x3810,
WMDM_FORMATCODE_IMAGE_RESERVED_FIRST = 0x3811,
WMDM_FORMATCODE_IMAGE_RESERVED_LAST = 0x3FFF,
WMDM_FORMATCODE_UNDEFINEDFIRMWARE = 0xB802,
WMDM_FORMATCODE_WINDOWSIMAGEFORMAT = 0xB881,
WMDM_FORMATCODE_UNDEFINEDAUDIO = 0xB900,
WMDM_FORMATCODE_WMA = 0xB901,
WMDM_FORMATCODE_OGG = 0xB902,
WMDM_FORMATCODE_AAC = 0xB903,
WMDM_FORMATCODE_AUDIBLE = 0xB904,
WMDM_FORMATCODE_FLAC = 0xB906,
WMDM_FORMATCODE_UNDEFINEDVIDEO = 0xB980,
WMDM_FORMATCODE_WMV = 0xB981,
WMDM_FORMATCODE_MP4 = 0xB982,
WMDM_FORMATCODE_MP2 = 0xB983,
WMDM_FORMATCODE_UNDEFINEDCOLLECTION = 0xBA00,
WMDM_FORMATCODE_ABSTRACTMULTIMEDIAALBUM = 0xBA01,
WMDM_FORMATCODE_ABSTRACTIMAGEALBUM = 0xBA02,
WMDM_FORMATCODE_ABSTRACTAUDIOALBUM = 0xBA03,
WMDM_FORMATCODE_ABSTRACTVIDEOALBUM = 0xBA04,
WMDM_FORMATCODE_ABSTRACTAUDIOVIDEOPLAYLIST = 0xBA05,
WMDM_FORMATCODE_ABSTRACTCONTACTGROUP = 0xBA06,
WMDM_FORMATCODE_ABSTRACTMESSAGEFOLDER = 0xBA07,
WMDM_FORMATCODE_ABSTRACTCHAPTEREDPRODUCTION = 0xBA08,
WMDM_FORMATCODE_WPLPLAYLIST = 0xBA10,
WMDM_FORMATCODE_M3UPLAYLIST = 0xBA11,
WMDM_FORMATCODE_MPLPLAYLIST = 0xBA12,
WMDM_FORMATCODE_ASXPLAYLIST = 0xBA13,
WMDM_FORMATCODE_PLSPLAYLIST = 0xBA14,
WMDM_FORMATCODE_UNDEFINEDDOCUMENT = 0xBA80,
WMDM_FORMATCODE_ABSTRACTDOCUMENT = 0xBA81,
WMDM_FORMATCODE_XMLDOCUMENT = 0xBA82,
WMDM_FORMATCODE_MICROSOFTWORDDOCUMENT= 0xBA83,
WMDM_FORMATCODE_MHTCOMPILEDHTMLDOCUMENT = 0xBA84,
WMDM_FORMATCODE_MICROSOFTEXCELSPREADSHEET = 0xBA85,
WMDM_FORMATCODE_MICROSOFTPOWERPOINTDOCUMENT = 0xBA86,
WMDM_FORMATCODE_UNDEFINEDMESSAGE = 0xBB00,
WMDM_FORMATCODE_ABSTRACTMESSAGE = 0xBB01,
WMDM_FORMATCODE_UNDEFINEDCONTACT = 0xBB80,
WMDM_FORMATCODE_ABSTRACTCONTACT = 0xBB81,
WMDM_FORMATCODE_VCARD2 = 0xBB82,
WMDM_FORMATCODE_VCARD3 = 0xBB83,
WMDM_FORMATCODE_UNDEFINEDCALENDARITEM = 0xBE00,
WMDM_FORMATCODE_ABSTRACTCALENDARITEM = 0xBE01,
WMDM_FORMATCODE_VCALENDAR1 = 0xBE02,
WMDM_FORMATCODE_VCALENDAR2 = 0xBE03,
WMDM_FORMATCODE_UNDEFINEDWINDOWSEXECUTABLE = 0xBE80,
WMDM_FORMATCODE_MEDIA_CAST = 0xBE81,
WMDM_FORMATCODE_SECTION = 0xBE82
} WMDM_FORMATCODE;
#endif // Q_OS_WIN32
#include <boost/scoped_array.hpp>

View File

@ -14,13 +14,15 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#define _WIN32_WINNT 0x0501
#include "wmdmlister.h"
#include "wmdmthread.h"
#include "core/utilities.h"
#include <icomponentauthenticate.h>
#include <objbase.h>
#include <mswmdm_i.c>
#include <winbase.h>
#include <boost/bind.hpp>
#include <boost/scoped_array.hpp>
@ -29,6 +31,9 @@
#include <QStringList>
#include <QtDebug>
const QUuid WmdmLister::kDeviceProtocolMsc(
0xa4d2c26c, 0xa881, 0x44bb, 0xbd, 0x5d, 0x1f, 0x70, 0x3c, 0x71, 0xf7, 0xa9);
QString WmdmLister::CanonicalNameToId(const QString& canonical_name) {
return "wmdm/" + canonical_name;
}
@ -139,14 +144,23 @@ WmdmLister::DeviceInfo WmdmLister::ReadDeviceInfo(IWMDMDevice2* device) {
const int max_size = 512;
wchar_t buf[max_size];
device->GetName(buf, max_size);
ret.name_ = QString::fromWCharArray(buf);
ret.name_ = QString::fromWCharArray(buf).trimmed();
device->GetManufacturer(buf, max_size);
ret.manufacturer_ = QString::fromWCharArray(buf);
ret.manufacturer_ = QString::fromWCharArray(buf).trimmed();
device->GetCanonicalName(buf, max_size);
ret.canonical_name_ = QString::fromWCharArray(buf).toLower();
// Upgrade to a device3
IWMDMDevice3* device3 = NULL;
device->QueryInterface(IID_IWMDMDevice3, (void**)&device3);
// Get the device protocol so we can figure out whether the device is MSC
PROPVARIANT protocol;
device3->GetProperty(g_wszWMDMDeviceProtocol, &protocol);
device3->Release();
// Get the type and check whether it has storage
DWORD type = 0;
device->GetType(&type);
@ -180,34 +194,99 @@ WmdmLister::DeviceInfo WmdmLister::ReadDeviceInfo(IWMDMDevice2* device) {
// There doesn't seem to be a way to get the drive letter of MSC devices, so
// try parsing the device's name to extract it.
QRegExp drive_letter("\\(([A-Z]:)\\)$");
if (drive_letter.indexIn(ret.name_) != -1) {
// Sanity check to make sure there really is a drive there
ScopedWCharArray path(drive_letter.cap(1) + "\\");
ScopedWCharArray name(QString(MAX_PATH + 1, '\0'));
ScopedWCharArray type(QString(MAX_PATH + 1, '\0'));
DWORD serial = 0;
if (!GetVolumeInformationW(
path,
name, MAX_PATH,
&serial,
NULL, // max component length
NULL, // flags
type, MAX_PATH // fat or ntfs
)) {
qWarning() << "Error getting volume information for" << drive_letter.cap(1);
} else {
ret.mount_point_ = drive_letter.cap(1) + "/";
ret.fs_name_ = name.ToString();
ret.fs_type_ = type.ToString();
ret.fs_serial_ = serial;
}
}
if (QUuid(*protocol.puuid) == kDeviceProtocolMsc)
GuessDriveLetter(&ret);
return ret;
}
void WmdmLister::GuessDriveLetter(DeviceInfo* info) {
// Windows XP puts the drive letter in brackets at the end of the name
QRegExp drive_letter("\\(([A-Z]:)\\)$");
if (drive_letter.indexIn(info->name_) != -1) {
CheckDriveLetter(info, drive_letter.cap(1));
return;
}
// Windows 7 sometimes has the drive letter as the whole name
drive_letter = QRegExp("^([A-Z]:)\\\\$");
if (drive_letter.indexIn(info->name_) != -1) {
CheckDriveLetter(info, drive_letter.cap(1));
return;
}
// Otherwise Windows 7 uses the drive's DOS label as its whole name.
// Let's enumerate all the volumes on the system and find one with that
// label, then get its drive letter. Yay!
wchar_t volume_name[MAX_PATH + 1];
HANDLE handle = FindFirstVolumeW(volume_name, MAX_PATH);
forever {
// QueryDosDeviceW doesn't allow a trailing backslash, so remove it.
int length = wcslen(volume_name);
volume_name[length - 1] = L'\0';
wchar_t device_name[MAX_PATH + 1];
QueryDosDeviceW(&volume_name[4], device_name, MAX_PATH);
volume_name[length - 1] = L'\\';
// Don't do cd-roms or floppies
if (QString::fromWCharArray(device_name).contains("HarddiskVolume")) {
wchar_t volume_path[MAX_PATH + 1];
DWORD volume_path_length = MAX_PATH;
GetVolumePathNamesForVolumeNameW(
volume_name, volume_path, volume_path_length, &volume_path_length);
if (wcslen(volume_path) == 3) {
ScopedWCharArray name(QString(MAX_PATH + 1, '\0'));
ScopedWCharArray type(QString(MAX_PATH + 1, '\0'));
DWORD serial = 0;
if (!GetVolumeInformationW(volume_path, name, MAX_PATH,
&serial, NULL, NULL, type, MAX_PATH)) {
qWarning() << "Error getting volume information for" <<
QString::fromWCharArray(volume_path);
} else {
if (name.ToString() == info->name_ && name.characters() != 0) {
// We found it!
CheckDriveLetter(info, QString::fromWCharArray(volume_path));
break;
}
}
}
}
if (!FindNextVolumeW(handle, volume_name, MAX_PATH))
break;
}
FindVolumeClose(handle);
}
void WmdmLister::CheckDriveLetter(DeviceInfo* info, const QString& drive) {
// Sanity check to make sure there really is a drive there
ScopedWCharArray path(drive.endsWith('\\') ? drive : (drive + "\\"));
ScopedWCharArray name(QString(MAX_PATH + 1, '\0'));
ScopedWCharArray type(QString(MAX_PATH + 1, '\0'));
DWORD serial = 0;
if (!GetVolumeInformationW(
path,
name, MAX_PATH,
&serial,
NULL, // max component length
NULL, // flags
type, MAX_PATH // fat or ntfs
)) {
qWarning() << "Error getting volume information for" << drive;
} else {
info->mount_point_ = drive + "/";
info->fs_name_ = name.ToString();
info->fs_type_ = type.ToString();
info->fs_serial_ = serial;
}
}
QStringList WmdmLister::DeviceUniqueIDs() {
QMutexLocker l(&mutex_);
return devices_.keys();

View File

@ -22,6 +22,7 @@
#include <QMap>
#include <QMutex>
#include <QPixmap>
#include <QUuid>
#include <boost/scoped_ptr.hpp>
@ -98,12 +99,16 @@ private:
int fs_serial_;
};
static const QUuid kDeviceProtocolMsc;
DeviceInfo ReadDeviceInfo(IWMDMDevice2* device);
template <typename T>
T LockAndGetDeviceInfo(const QString& id, T DeviceInfo::*field);
void UpdateFreeSpace(DeviceInfo* info);
void GuessDriveLetter(DeviceInfo* info);
void CheckDriveLetter(DeviceInfo* info, const QString& drive);
static QString CanonicalNameToId(const QString& canonical_name);
void WMDMDeviceAdded(const QString& canonical_name);