Remove all the soruce for WMDM devices. Fixes issue 3748
This commit is contained in:
parent
f245f7ed82
commit
eb20fb5945
@ -83,7 +83,6 @@ pkg_check_modules(TAGLIB REQUIRED taglib>=1.6)
|
|||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
find_package(ZLIB REQUIRED)
|
find_package(ZLIB REQUIRED)
|
||||||
find_library(MSWMDM_LIBRARIES mswmdm)
|
|
||||||
find_library(QTSPARKLE_LIBRARIES qtsparkle)
|
find_library(QTSPARKLE_LIBRARIES qtsparkle)
|
||||||
endif (WIN32)
|
endif (WIN32)
|
||||||
|
|
||||||
|
38
dist/windows/clementine.nsi.in
vendored
38
dist/windows/clementine.nsi.in
vendored
@ -9,9 +9,6 @@
|
|||||||
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
|
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
|
||||||
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES\Clementine"
|
!define PRODUCT_INSTALL_DIR "$PROGRAMFILES\Clementine"
|
||||||
|
|
||||||
!define WMDM_DIST_URL "http://clementine-player.googlecode.com/files/wmdmdist.exe"
|
|
||||||
!define WMF_DIST_URL "http://clementine-player.googlecode.com/files/wmfdist.exe"
|
|
||||||
|
|
||||||
; Set Application Capabilities info
|
; Set Application Capabilities info
|
||||||
!define CAPABILITIES_NAME "Clementine"
|
!define CAPABILITIES_NAME "Clementine"
|
||||||
!define CAPABILITIES_LOCAL_NAME "Clementine"
|
!define CAPABILITIES_LOCAL_NAME "Clementine"
|
||||||
@ -911,41 +908,6 @@ Section "Uninstaller"
|
|||||||
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
|
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Windows Media Device Manager"
|
|
||||||
GetDllVersion "$SYSDIR\mswmdm.dll" $R8 $R9
|
|
||||||
IntOp $R7 $R8 / 0x00010000
|
|
||||||
IntCmp $R7 9 end downloadwmf end # Major version >= 9
|
|
||||||
|
|
||||||
downloadwmf:
|
|
||||||
StrCpy $1 "wmfdist.exe"
|
|
||||||
NSISdl::download ${WMF_DIST_URL} "$TEMP\$1"
|
|
||||||
Pop $R0
|
|
||||||
StrCmp $R0 "success" downloadwmdm
|
|
||||||
MessageBox MB_OK|MB_ICONSTOP "Error while downloading $1."
|
|
||||||
Quit
|
|
||||||
|
|
||||||
downloadwmdm:
|
|
||||||
StrCpy $1 "wmdmdist.exe"
|
|
||||||
NSISdl::download ${WMDM_DIST_URL} "$TEMP\$1"
|
|
||||||
Pop $R0
|
|
||||||
StrCmp $R0 "success" install
|
|
||||||
MessageBox MB_OK|MB_ICONSTOP "Error while downloading $1."
|
|
||||||
Quit
|
|
||||||
|
|
||||||
install:
|
|
||||||
DetailPrint "Installing the Windows Media Format 9 redistributable"
|
|
||||||
ExecWait "$TEMP\wmfdist.exe /Q"
|
|
||||||
|
|
||||||
DetailPrint "Installing the Windows Media Device Manager 9 redistributable"
|
|
||||||
ExecWait "$TEMP\wmdmdist.exe /Q"
|
|
||||||
|
|
||||||
Delete "$TEMP\wmfdist.exe"
|
|
||||||
Delete "$TEMP\wmdmdist.exe"
|
|
||||||
|
|
||||||
end:
|
|
||||||
DetailPrint "WMDM redistributable installed"
|
|
||||||
SectionEnd
|
|
||||||
|
|
||||||
Section "Uninstall"
|
Section "Uninstall"
|
||||||
; Kill clementine.exe if it's running
|
; Kill clementine.exe if it's running
|
||||||
; This calling convention is retarded...
|
; This calling convention is retarded...
|
||||||
|
@ -1045,20 +1045,6 @@ optional_source(HAVE_LIBMTP
|
|||||||
devices/mtploader.h
|
devices/mtploader.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# Windows media lister
|
|
||||||
optional_source(WIN32
|
|
||||||
SOURCES
|
|
||||||
devices/wmdmdevice.cpp
|
|
||||||
devices/wmdmlister.cpp
|
|
||||||
devices/wmdmloader.cpp
|
|
||||||
devices/wmdmprogress.cpp
|
|
||||||
devices/wmdmthread.cpp
|
|
||||||
HEADERS
|
|
||||||
devices/wmdmdevice.h
|
|
||||||
devices/wmdmlister.h
|
|
||||||
devices/wmdmloader.h
|
|
||||||
)
|
|
||||||
|
|
||||||
# Moodbar support
|
# Moodbar support
|
||||||
optional_source(HAVE_MOODBAR
|
optional_source(HAVE_MOODBAR
|
||||||
SOURCES
|
SOURCES
|
||||||
@ -1297,7 +1283,6 @@ endif(HAVE_STATIC_SQLITE)
|
|||||||
if (WIN32)
|
if (WIN32)
|
||||||
target_link_libraries(clementine_lib
|
target_link_libraries(clementine_lib
|
||||||
${ZLIB_LIBRARIES}
|
${ZLIB_LIBRARIES}
|
||||||
${MSWMDM_LIBRARIES}
|
|
||||||
${QTSPARKLE_LIBRARIES}
|
${QTSPARKLE_LIBRARIES}
|
||||||
tinysvcmdns
|
tinysvcmdns
|
||||||
qtwin
|
qtwin
|
||||||
|
@ -40,11 +40,6 @@
|
|||||||
|
|
||||||
#include <id3v1genres.h>
|
#include <id3v1genres.h>
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
|
||||||
# include <mswmdm.h>
|
|
||||||
# include <QUuid>
|
|
||||||
#endif // Q_OS_WIN32
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBGPOD
|
#ifdef HAVE_LIBGPOD
|
||||||
# include <gpod/itdb.h>
|
# include <gpod/itdb.h>
|
||||||
#endif
|
#endif
|
||||||
@ -726,233 +721,6 @@ void Song::InitFromLastFM(const lastfm::Track& track) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_WIN32)
|
|
||||||
static void AddWmdmItem(IWMDMMetaData* metadata, const wchar_t* name,
|
|
||||||
const QVariant& value) {
|
|
||||||
switch (value.type()) {
|
|
||||||
case QVariant::Int:
|
|
||||||
case QVariant::UInt: {
|
|
||||||
DWORD data = value.toUInt();
|
|
||||||
metadata->AddItem(WMDM_TYPE_DWORD, name, (BYTE*)&data, sizeof(data));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case QVariant::String: {
|
|
||||||
ScopedWCharArray data(value.toString());
|
|
||||||
metadata->AddItem(WMDM_TYPE_STRING, name, (BYTE*)data.get(), data.bytes());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case QVariant::ByteArray: {
|
|
||||||
QByteArray data = value.toByteArray();
|
|
||||||
metadata->AddItem(WMDM_TYPE_BINARY, name, (BYTE*)data.constData(), data.size());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case QVariant::Bool: {
|
|
||||||
int data = value.toBool();
|
|
||||||
metadata->AddItem(WMDM_TYPE_BOOL, name, (BYTE*)&data, sizeof(data));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case QVariant::LongLong:
|
|
||||||
case QVariant::ULongLong: {
|
|
||||||
quint64 data = value.toULongLong();
|
|
||||||
metadata->AddItem(WMDM_TYPE_QWORD, name, (BYTE*)&data, sizeof(data));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
qLog(Warning) << "Type" << value.type() << "not handled";
|
|
||||||
Q_ASSERT(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static QVariant ReadWmdmValue(int type, uchar* data, uint length) {
|
|
||||||
switch (type) {
|
|
||||||
case WMDM_TYPE_DWORD:
|
|
||||||
return QVariant::fromValue(uint(*reinterpret_cast<DWORD*>(data)));
|
|
||||||
case WMDM_TYPE_WORD:
|
|
||||||
return QVariant::fromValue(uint(*reinterpret_cast<WORD*>(data)));
|
|
||||||
case WMDM_TYPE_QWORD:
|
|
||||||
return QVariant::fromValue(qulonglong(*reinterpret_cast<quint64*>(data)));
|
|
||||||
case WMDM_TYPE_STRING:
|
|
||||||
return QString::fromWCharArray(reinterpret_cast<wchar_t*>(data), length/2);
|
|
||||||
case WMDM_TYPE_BINARY:
|
|
||||||
return QByteArray(reinterpret_cast<char*>(data), length);
|
|
||||||
case WMDM_TYPE_BOOL:
|
|
||||||
return bool(*reinterpret_cast<int*>(data));
|
|
||||||
case WMDM_TYPE_GUID:
|
|
||||||
return QUuid(*reinterpret_cast<GUID*>(data)).toString();
|
|
||||||
}
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Song::InitFromWmdm(IWMDMMetaData* metadata) {
|
|
||||||
bool non_consumable = false;
|
|
||||||
int format = 0;
|
|
||||||
|
|
||||||
// How much metadata is there?
|
|
||||||
uint count = 0;
|
|
||||||
metadata->GetItemCount(&count);
|
|
||||||
|
|
||||||
for (int i=0 ; i<count ; ++i) {
|
|
||||||
// Get this metadata item
|
|
||||||
wchar_t* name = NULL;
|
|
||||||
WMDM_TAG_DATATYPE type;
|
|
||||||
BYTE* value = NULL;
|
|
||||||
uint length = 0;
|
|
||||||
|
|
||||||
metadata->QueryByIndex(i, &name, &type, &value, &length);
|
|
||||||
|
|
||||||
QVariant item_value = ReadWmdmValue(type, value, length);
|
|
||||||
|
|
||||||
// Store it in the song if it's something we recognise
|
|
||||||
if (wcscmp(name, g_wszWMDMTitle) == 0)
|
|
||||||
d->title_ = item_value.toString();
|
|
||||||
|
|
||||||
else if (wcscmp(name, g_wszWMDMAuthor) == 0)
|
|
||||||
d->artist_ = item_value.toString();
|
|
||||||
|
|
||||||
else if (wcscmp(name, g_wszWMDMDescription) == 0)
|
|
||||||
d->comment_ = item_value.toString();
|
|
||||||
|
|
||||||
else if (wcscmp(name, g_wszWMDMAlbumTitle) == 0)
|
|
||||||
d->album_ = item_value.toString();
|
|
||||||
|
|
||||||
else if (wcscmp(name, g_wszWMDMTrack) == 0)
|
|
||||||
d->track_ = item_value.toInt();
|
|
||||||
|
|
||||||
else if (wcscmp(name, g_wszWMDMGenre) == 0)
|
|
||||||
d->genre_ = item_value.toString();
|
|
||||||
|
|
||||||
else if (wcscmp(name, g_wszWMDMYear) == 0)
|
|
||||||
d->year_ = item_value.toInt();
|
|
||||||
|
|
||||||
else if (wcscmp(name, g_wszWMDMComposer) == 0)
|
|
||||||
d->composer_ = item_value.toString();
|
|
||||||
|
|
||||||
else if (wcscmp(name, g_wszWMDMBitrate) == 0)
|
|
||||||
d->bitrate_ = item_value.toInt();
|
|
||||||
|
|
||||||
else if (wcscmp(name, g_wszWMDMFileName) == 0)
|
|
||||||
d->url_ = QUrl::fromLocalFile(item_value.toString());
|
|
||||||
|
|
||||||
else if (wcscmp(name, g_wszWMDMDuration) == 0)
|
|
||||||
set_length_nanosec(item_value.toULongLong() * 1e2);
|
|
||||||
|
|
||||||
else if (wcscmp(name, L"WMDM/FileSize") == 0)
|
|
||||||
d->filesize_ = item_value.toULongLong();
|
|
||||||
|
|
||||||
else if (wcscmp(name, L"WMDM/NonConsumable") == 0)
|
|
||||||
non_consumable = item_value.toBool();
|
|
||||||
|
|
||||||
else if (wcscmp(name, L"WMDM/FormatCode") == 0)
|
|
||||||
format = item_value.toInt();
|
|
||||||
|
|
||||||
CoTaskMemFree(name);
|
|
||||||
CoTaskMemFree(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decide if this is music or not
|
|
||||||
if (count == 0 || non_consumable)
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (format) {
|
|
||||||
case WMDM_FORMATCODE_AIFF:
|
|
||||||
d->filetype_ = Song::Type_Aiff;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMDM_FORMATCODE_WAVE:
|
|
||||||
d->filetype_ = Song::Type_Wav;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMDM_FORMATCODE_MP2:
|
|
||||||
case WMDM_FORMATCODE_MP3:
|
|
||||||
case WMDM_FORMATCODE_MPEG:
|
|
||||||
d->filetype_ = Song::Type_Mpeg;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMDM_FORMATCODE_WMA:
|
|
||||||
case WMDM_FORMATCODE_ASF:
|
|
||||||
d->filetype_ = Song::Type_Asf;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMDM_FORMATCODE_OGG:
|
|
||||||
d->filetype_ = Song::Type_OggVorbis;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMDM_FORMATCODE_AAC:
|
|
||||||
case WMDM_FORMATCODE_MP4:
|
|
||||||
d->filetype_ = Song::Type_Mp4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMDM_FORMATCODE_FLAC:
|
|
||||||
d->filetype_ = Song::Type_Flac;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMDM_FORMATCODE_AUDIBLE:
|
|
||||||
case WMDM_FORMATCODE_UNDEFINEDAUDIO:
|
|
||||||
d->filetype_ = Song::Type_Unknown;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMDM_FORMATCODE_UNDEFINED:
|
|
||||||
// WMDM doesn't know what type of file it is, so we start guessing - first
|
|
||||||
// check if any of the music metadata fields were defined. If they were,
|
|
||||||
// there's a fairly good chance the file was music.
|
|
||||||
if (!d->title_.isEmpty() || !d->artist_.isEmpty() ||
|
|
||||||
!d->album_.isEmpty() || !d->comment_.isEmpty() ||
|
|
||||||
!d->genre_.isEmpty() || d->track_ != -1 || d->year_ != -1 ||
|
|
||||||
length_nanosec() != -1) {
|
|
||||||
d->filetype_ = Song::Type_Unknown;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a final guess based on the file extension
|
|
||||||
{
|
|
||||||
QString ext = d->url_.path().section('.', -1, -1).toLower();
|
|
||||||
if (ext == "mp3" || ext == "wma" || ext == "flac" || ext == "ogg" ||
|
|
||||||
ext == "spx" || ext == "mp4" || ext == "aac" || ext == "m4a")
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return; // It's not music
|
|
||||||
}
|
|
||||||
|
|
||||||
d->valid_ = true;
|
|
||||||
d->mtime_ = 0;
|
|
||||||
d->ctime_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Song::ToWmdm(IWMDMMetaData* metadata) const {
|
|
||||||
AddWmdmItem(metadata, g_wszWMDMTitle, d->title_);
|
|
||||||
AddWmdmItem(metadata, g_wszWMDMAuthor, d->artist_);
|
|
||||||
AddWmdmItem(metadata, g_wszWMDMDescription, d->comment_);
|
|
||||||
AddWmdmItem(metadata, g_wszWMDMAlbumTitle, d->album_);
|
|
||||||
AddWmdmItem(metadata, g_wszWMDMTrack, d->track_);
|
|
||||||
AddWmdmItem(metadata, g_wszWMDMGenre, d->genre_);
|
|
||||||
AddWmdmItem(metadata, g_wszWMDMYear, QString::number(d->year_));
|
|
||||||
AddWmdmItem(metadata, g_wszWMDMComposer, d->composer_);
|
|
||||||
AddWmdmItem(metadata, g_wszWMDMBitrate, d->bitrate_);
|
|
||||||
AddWmdmItem(metadata, g_wszWMDMFileName, d->basefilename_);
|
|
||||||
AddWmdmItem(metadata, g_wszWMDMDuration, qint64(length_nanosec() / 1e2));
|
|
||||||
AddWmdmItem(metadata, L"WMDM/FileSize", d->filesize_);
|
|
||||||
|
|
||||||
WMDM_FORMATCODE format;
|
|
||||||
switch (d->filetype_) {
|
|
||||||
case Type_Aiff: format = WMDM_FORMATCODE_AIFF; break;
|
|
||||||
case Type_Wav: format = WMDM_FORMATCODE_WAVE; break;
|
|
||||||
case Type_Mpeg: format = WMDM_FORMATCODE_MP3; break;
|
|
||||||
case Type_Asf: format = WMDM_FORMATCODE_ASF; break;
|
|
||||||
case Type_OggFlac:
|
|
||||||
case Type_OggSpeex:
|
|
||||||
case Type_OggVorbis: format = WMDM_FORMATCODE_OGG; break;
|
|
||||||
case Type_Mp4: format = WMDM_FORMATCODE_MP4; break;
|
|
||||||
case Type_Flac: format = WMDM_FORMATCODE_FLAC; break;
|
|
||||||
default: format = WMDM_FORMATCODE_UNDEFINEDAUDIO; break;
|
|
||||||
}
|
|
||||||
AddWmdmItem(metadata, L"WMDM/FormatCode", format);
|
|
||||||
}
|
|
||||||
#endif // Q_OS_WIN32
|
|
||||||
|
|
||||||
void Song::MergeFromSimpleMetaBundle(const Engine::SimpleMetaBundle &bundle) {
|
void Song::MergeFromSimpleMetaBundle(const Engine::SimpleMetaBundle &bundle) {
|
||||||
if (d->init_from_file_ || d->url_.scheme() == "file") {
|
if (d->init_from_file_ || d->url_.scheme() == "file") {
|
||||||
// This Song was already loaded using taglib. Our tags are probably better
|
// This Song was already loaded using taglib. Our tags are probably better
|
||||||
|
@ -44,10 +44,6 @@ class QUrl;
|
|||||||
struct LIBMTP_track_struct;
|
struct LIBMTP_track_struct;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_WIN32)
|
|
||||||
struct IWMDMMetaData;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBLASTFM
|
#ifdef HAVE_LIBLASTFM
|
||||||
namespace lastfm {
|
namespace lastfm {
|
||||||
class Track;
|
class Track;
|
||||||
@ -126,11 +122,6 @@ class Song {
|
|||||||
void ToMTP(LIBMTP_track_struct* track) const;
|
void ToMTP(LIBMTP_track_struct* track) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_WIN32)
|
|
||||||
void InitFromWmdm(IWMDMMetaData* metadata);
|
|
||||||
void ToWmdm(IWMDMMetaData* metadata) const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Copies important statistics from the other song to this one, overwriting
|
// Copies important statistics from the other song to this one, overwriting
|
||||||
// any data that already exists. Useful when you want updated tags from disk
|
// any data that already exists. Useful when you want updated tags from disk
|
||||||
// but you want to keep user stats.
|
// but you want to keep user stats.
|
||||||
|
@ -50,10 +50,6 @@
|
|||||||
#ifdef Q_OS_DARWIN
|
#ifdef Q_OS_DARWIN
|
||||||
# include "macdevicelister.h"
|
# include "macdevicelister.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_WIN32
|
|
||||||
# include "wmdmlister.h"
|
|
||||||
# include "wmdmdevice.h"
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_LIBGPOD
|
#ifdef HAVE_LIBGPOD
|
||||||
# include "gpoddevice.h"
|
# include "gpoddevice.h"
|
||||||
#endif
|
#endif
|
||||||
@ -202,10 +198,6 @@ DeviceManager::DeviceManager(Application* app, QObject *parent)
|
|||||||
#ifdef Q_OS_DARWIN
|
#ifdef Q_OS_DARWIN
|
||||||
AddLister(new MacDeviceLister);
|
AddLister(new MacDeviceLister);
|
||||||
#endif
|
#endif
|
||||||
#if defined(Q_OS_WIN32)
|
|
||||||
AddLister(new WmdmLister);
|
|
||||||
AddDeviceClass<WmdmDevice>();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
AddDeviceClass<FilesystemDevice>();
|
AddDeviceClass<FilesystemDevice>();
|
||||||
|
|
||||||
|
@ -1,292 +0,0 @@
|
|||||||
/* This file is part of Clementine.
|
|
||||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Clementine is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "devicemanager.h"
|
|
||||||
#include "wmdmdevice.h"
|
|
||||||
#include "wmdmlister.h"
|
|
||||||
#include "wmdmloader.h"
|
|
||||||
#include "wmdmprogress.h"
|
|
||||||
#include "wmdmthread.h"
|
|
||||||
#include "core/application.h"
|
|
||||||
#include "core/logging.h"
|
|
||||||
#include "core/utilities.h"
|
|
||||||
#include "library/librarybackend.h"
|
|
||||||
#include "library/librarymodel.h"
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QThread>
|
|
||||||
|
|
||||||
#include <boost/scoped_array.hpp>
|
|
||||||
|
|
||||||
#include <mswmdm.h>
|
|
||||||
|
|
||||||
WmdmDevice::WmdmDevice(const QUrl& url, DeviceLister* lister,
|
|
||||||
const QString& unique_id, DeviceManager* manager,
|
|
||||||
Application* app,
|
|
||||||
int database_id, bool first_time)
|
|
||||||
: ConnectedDevice(url, lister, unique_id, manager, app, database_id, first_time),
|
|
||||||
loader_thread_(new QThread(this)),
|
|
||||||
loader_(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
WmdmDevice::~WmdmDevice() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmDevice::Init() {
|
|
||||||
InitBackendDirectory("/", first_time_, false);
|
|
||||||
model_->Init();
|
|
||||||
|
|
||||||
loader_ = new WmdmLoader(app_->task_manager(), backend_, shared_from_this());
|
|
||||||
loader_->moveToThread(loader_thread_);
|
|
||||||
|
|
||||||
connect(loader_, SIGNAL(Error(QString)), SIGNAL(Error(QString)));
|
|
||||||
connect(loader_, SIGNAL(TaskStarted(int)), SIGNAL(TaskStarted(int)));
|
|
||||||
connect(loader_, SIGNAL(LoadFinished()), SLOT(LoadFinished()));
|
|
||||||
connect(loader_thread_, SIGNAL(started()), loader_, SLOT(LoadDatabase()));
|
|
||||||
loader_thread_->start();
|
|
||||||
|
|
||||||
db_busy_.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmDevice::LoadFinished() {
|
|
||||||
loader_->deleteLater();
|
|
||||||
loader_ = NULL;
|
|
||||||
|
|
||||||
db_busy_.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WmdmDevice::StartCopy(QList<Song::FileType>* supported_types) {
|
|
||||||
// Ensure only one "organise files" can be active at any one time
|
|
||||||
db_busy_.lock();
|
|
||||||
|
|
||||||
// This initialises COM and gets a connection to the device
|
|
||||||
thread_.reset(new WmdmThread);
|
|
||||||
if (!thread_->manager())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Find a place to put the files. We default to the root folder for now, but
|
|
||||||
// could look for a "Music" folder in the future?
|
|
||||||
WmdmLister* wmdm_lister = static_cast<WmdmLister*>(lister());
|
|
||||||
QString canonical_name = wmdm_lister->DeviceCanonicalName(unique_id());
|
|
||||||
IWMDMStorage* destination = thread_->GetRootStorage(canonical_name);
|
|
||||||
|
|
||||||
// Get the control interface
|
|
||||||
destination->QueryInterface(IID_IWMDMStorageControl3, (void**)&storage_control_);
|
|
||||||
|
|
||||||
// Get the storage3 interface for CreateEmptyMetadataObject later
|
|
||||||
destination->QueryInterface(IID_IWMDMStorage3, (void**)&storage_);
|
|
||||||
|
|
||||||
destination->Release();
|
|
||||||
|
|
||||||
// Did the caller want a list of supported filetypes?
|
|
||||||
if (supported_types) {
|
|
||||||
IWMDMDevice* device = thread_->GetDeviceByCanonicalName(canonical_name);
|
|
||||||
if (!GetSupportedFiletypes(supported_types, device)) {
|
|
||||||
device->Release();
|
|
||||||
FinishCopy(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
device->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WmdmDevice::CopyToStorage(const CopyJob& job) {
|
|
||||||
if (!storage_control_ || !storage_)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Create the song metadata
|
|
||||||
IWMDMMetaData* metadata_iface = NULL;
|
|
||||||
storage_->CreateEmptyMetadataObject(&metadata_iface);
|
|
||||||
job.metadata_.ToWmdm(metadata_iface);
|
|
||||||
|
|
||||||
// Convert the filenames to wchars
|
|
||||||
ScopedWCharArray source_filename(QDir::toNativeSeparators(job.source_));
|
|
||||||
ScopedWCharArray dest_filename(job.metadata_.basefilename());
|
|
||||||
|
|
||||||
// Create the progress object
|
|
||||||
WmdmProgress progress(job.progress_);
|
|
||||||
|
|
||||||
// Copy the file
|
|
||||||
IWMDMStorage* new_storage = NULL;
|
|
||||||
if (storage_control_->Insert3(
|
|
||||||
WMDM_MODE_BLOCK | WMDM_STORAGECONTROL_INSERTINTO |
|
|
||||||
WMDM_FILE_CREATE_OVERWRITE | WMDM_CONTENT_FILE,
|
|
||||||
WMDM_FILE_ATTR_FOLDER,
|
|
||||||
source_filename,
|
|
||||||
dest_filename,
|
|
||||||
NULL, // operation
|
|
||||||
&progress, // progress
|
|
||||||
metadata_iface,
|
|
||||||
NULL, // data
|
|
||||||
&new_storage)) {
|
|
||||||
qLog(Warning) << "Couldn't copy file to WMDM device";
|
|
||||||
metadata_iface->Release();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
metadata_iface->Release();
|
|
||||||
|
|
||||||
if (!new_storage)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Get the metadata from the newly copied file
|
|
||||||
IWMDMStorage3* new_storage3 = NULL;
|
|
||||||
IWMDMMetaData* new_metadata = NULL;
|
|
||||||
|
|
||||||
new_storage->QueryInterface(IID_IWMDMStorage3, (void**)&new_storage3);
|
|
||||||
new_storage3->GetMetadata(&new_metadata);
|
|
||||||
|
|
||||||
new_storage->Release();
|
|
||||||
new_storage3->Release();
|
|
||||||
|
|
||||||
if (!new_metadata)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Add it to our LibraryModel
|
|
||||||
Song new_song;
|
|
||||||
new_song.InitFromWmdm(new_metadata);
|
|
||||||
new_song.set_directory_id(1);
|
|
||||||
songs_to_add_ << new_song;
|
|
||||||
|
|
||||||
new_metadata->Release();
|
|
||||||
|
|
||||||
// Remove the original if requested
|
|
||||||
if (job.remove_original_) {
|
|
||||||
if (!QFile::remove(job.source_))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmDevice::FinishCopy(bool success) {
|
|
||||||
if (success) {
|
|
||||||
if (!songs_to_add_.isEmpty())
|
|
||||||
backend_->AddOrUpdateSongs(songs_to_add_);
|
|
||||||
if (!songs_to_remove_.isEmpty())
|
|
||||||
backend_->DeleteSongs(songs_to_remove_);
|
|
||||||
}
|
|
||||||
|
|
||||||
songs_to_add_.clear();
|
|
||||||
songs_to_remove_.clear();
|
|
||||||
|
|
||||||
storage_->Release();
|
|
||||||
storage_control_->Release();
|
|
||||||
thread_.reset();
|
|
||||||
|
|
||||||
db_busy_.unlock();
|
|
||||||
|
|
||||||
ConnectedDevice::FinishCopy(success);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmDevice::StartDelete() {
|
|
||||||
StartCopy(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WmdmDevice::DeleteFromStorage(const DeleteJob& job) {
|
|
||||||
// Walk down the tree until we've found the file
|
|
||||||
IWMDMStorage3* storage = storage_;
|
|
||||||
storage->AddRef();
|
|
||||||
|
|
||||||
const QStringList path_components =
|
|
||||||
job.metadata_.url().path().split('/', QString::SkipEmptyParts);
|
|
||||||
foreach (const QString& path_component, path_components) {
|
|
||||||
ScopedWCharArray path_component_wchar(path_component);
|
|
||||||
|
|
||||||
IWMDMStorage* next_storage = NULL;
|
|
||||||
if (storage->GetStorage(path_component_wchar, &next_storage)) {
|
|
||||||
// Couldn't find it
|
|
||||||
storage->Release();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
storage->Release();
|
|
||||||
|
|
||||||
next_storage->QueryInterface(IID_IWMDMStorage3, (void**)&storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a control interface on it
|
|
||||||
IWMDMStorageControl3* control = NULL;
|
|
||||||
storage->QueryInterface(IID_IWMDMStorageControl3, (void**)&control);
|
|
||||||
storage->Release();
|
|
||||||
|
|
||||||
// Delete it
|
|
||||||
WmdmProgress progress;
|
|
||||||
if (control->Delete(WMDM_MODE_BLOCK, &progress)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove it from our library model
|
|
||||||
songs_to_remove_ << job.metadata_;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmDevice::FinishDelete(bool success) {
|
|
||||||
FinishCopy(success);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WmdmDevice::GetSupportedFiletypes(QList<Song::FileType>* ret, IWMDMDevice* device) {
|
|
||||||
// Get a list of supported formats
|
|
||||||
uint32_t format_count = 0;
|
|
||||||
uint32_t mime_count = 0;
|
|
||||||
_WAVEFORMATEX* formats;
|
|
||||||
wchar_t** mime_types;
|
|
||||||
|
|
||||||
if (device->GetFormatSupport(
|
|
||||||
&formats, &format_count, &mime_types, &mime_count)) {
|
|
||||||
qLog(Warning) << "Unable to get a list of supported formats for device";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find known mime types
|
|
||||||
for (int i=0 ; i<mime_count ; ++i) {
|
|
||||||
QString type = QString::fromWCharArray(mime_types[i]);
|
|
||||||
if (type == "audio/mp3" || type == "audio/mpeg")
|
|
||||||
*ret << Song::Type_Mpeg;
|
|
||||||
else if (type == "audio/x-ms-wma")
|
|
||||||
*ret << Song::Type_Asf;
|
|
||||||
else if (type == "audio/wav")
|
|
||||||
*ret << Song::Type_Wav;
|
|
||||||
else if (type == "audio/mp4")
|
|
||||||
*ret << Song::Type_Mp4;
|
|
||||||
else if (type == "audio/ogg" || type == "audio/vorbis")
|
|
||||||
*ret << Song::Type_OggVorbis;
|
|
||||||
}
|
|
||||||
|
|
||||||
CoTaskMemFree(formats);
|
|
||||||
CoTaskMemFree(mime_types);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WmdmDevice::GetSupportedFiletypes(QList<Song::FileType>* ret) {
|
|
||||||
QMutexLocker l(&db_busy_);
|
|
||||||
|
|
||||||
WmdmThread thread;
|
|
||||||
|
|
||||||
// Get the device
|
|
||||||
WmdmLister* wmdm_lister = static_cast<WmdmLister*>(lister());
|
|
||||||
QString canonical_name = wmdm_lister->DeviceCanonicalName(unique_id());
|
|
||||||
IWMDMDevice* device = thread.GetDeviceByCanonicalName(canonical_name);
|
|
||||||
|
|
||||||
bool success = GetSupportedFiletypes(ret, device);
|
|
||||||
device->Release();
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
/* This file is part of Clementine.
|
|
||||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Clementine is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WMDMDEVICE_H
|
|
||||||
#define WMDMDEVICE_H
|
|
||||||
|
|
||||||
#include "connecteddevice.h"
|
|
||||||
|
|
||||||
#include <boost/scoped_ptr.hpp>
|
|
||||||
|
|
||||||
class WmdmLoader;
|
|
||||||
class WmdmThread;
|
|
||||||
|
|
||||||
struct IWMDMDevice;
|
|
||||||
struct IWMDMStorage3;
|
|
||||||
struct IWMDMStorageControl3;
|
|
||||||
|
|
||||||
class WmdmDevice : public ConnectedDevice {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
Q_INVOKABLE WmdmDevice(const QUrl& url, DeviceLister* lister,
|
|
||||||
const QString& unique_id, DeviceManager* manager,
|
|
||||||
Application* app,
|
|
||||||
int database_id, bool first_time);
|
|
||||||
~WmdmDevice();
|
|
||||||
|
|
||||||
static QStringList url_schemes() { return QStringList() << "wmdm"; }
|
|
||||||
|
|
||||||
void Init();
|
|
||||||
|
|
||||||
bool GetSupportedFiletypes(QList<Song::FileType>* ret);
|
|
||||||
|
|
||||||
bool StartCopy(QList<Song::FileType>* supported_types);
|
|
||||||
bool CopyToStorage(const CopyJob& job);
|
|
||||||
void FinishCopy(bool success);
|
|
||||||
|
|
||||||
void StartDelete();
|
|
||||||
bool DeleteFromStorage(const DeleteJob& job);
|
|
||||||
void FinishDelete(bool success);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void LoadFinished();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool GetSupportedFiletypes(QList<Song::FileType>* ret, IWMDMDevice* device);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QThread* loader_thread_;
|
|
||||||
WmdmLoader* loader_;
|
|
||||||
|
|
||||||
QMutex db_busy_;
|
|
||||||
SongList songs_to_add_;
|
|
||||||
SongList songs_to_remove_;
|
|
||||||
|
|
||||||
boost::scoped_ptr<WmdmThread> thread_;
|
|
||||||
IWMDMStorage3* storage_;
|
|
||||||
IWMDMStorageControl3* storage_control_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // WMDMDEVICE_H
|
|
@ -1,528 +0,0 @@
|
|||||||
/* This file is part of Clementine.
|
|
||||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Clementine is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define _WIN32_WINNT 0x0501
|
|
||||||
|
|
||||||
#include "wmdmlister.h"
|
|
||||||
#include "wmdmthread.h"
|
|
||||||
#include "core/logging.h"
|
|
||||||
#include "core/utilities.h"
|
|
||||||
|
|
||||||
#include <objbase.h>
|
|
||||||
#include <mswmdm_i.c>
|
|
||||||
#include <winbase.h>
|
|
||||||
|
|
||||||
#include <boost/bind.hpp>
|
|
||||||
#include <boost/scoped_array.hpp>
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QPixmap>
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WmdmLister::DeviceInfo::unique_id() const {
|
|
||||||
return WmdmLister::CanonicalNameToId(canonical_name_);
|
|
||||||
}
|
|
||||||
|
|
||||||
WmdmLister::WmdmLister()
|
|
||||||
: notification_cookie_(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
WmdmLister::~WmdmLister() {
|
|
||||||
Q_ASSERT(!thread_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmLister::Init() {
|
|
||||||
qLog(Debug) << "Starting";
|
|
||||||
|
|
||||||
thread_.reset(new WmdmThread);
|
|
||||||
if (!thread_->manager())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Register for notifications
|
|
||||||
qLog(Debug) << "Obtaining CP container";
|
|
||||||
IConnectionPointContainer* cp_container = NULL;
|
|
||||||
thread_->manager()->QueryInterface(IID_IConnectionPointContainer, (void**)&cp_container);
|
|
||||||
|
|
||||||
qLog(Debug) << "Obtaining CP";
|
|
||||||
IConnectionPoint* cp = NULL;
|
|
||||||
cp_container->FindConnectionPoint(IID_IWMDMNotification, &cp);
|
|
||||||
|
|
||||||
qLog(Debug) << "Registering for notifications";
|
|
||||||
cp->Advise(this, ¬ification_cookie_);
|
|
||||||
|
|
||||||
cp->Release();
|
|
||||||
cp_container->Release();
|
|
||||||
|
|
||||||
// Fetch the initial list of devices
|
|
||||||
qLog(Debug) << "Fetching device list";
|
|
||||||
IWMDMEnumDevice* device_it = NULL;
|
|
||||||
if (thread_->manager()->EnumDevices2(&device_it)) {
|
|
||||||
qLog(Warning) << "Error querying WMDM devices";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate through the devices
|
|
||||||
QMap<QString, DeviceInfo> devices;
|
|
||||||
forever {
|
|
||||||
IWMDMDevice* device = NULL;
|
|
||||||
IWMDMDevice2* device2 = NULL;
|
|
||||||
ULONG fetched = 0;
|
|
||||||
if (device_it->Next(1, &device, &fetched) || fetched != 1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
qLog(Debug) << "Querying device";
|
|
||||||
if (device->QueryInterface(IID_IWMDMDevice2, (void**)&device2)) {
|
|
||||||
qLog(Warning) << "Error getting IWMDMDevice2 from device";
|
|
||||||
device->Release();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
device->Release();
|
|
||||||
|
|
||||||
DeviceInfo info = ReadDeviceInfo(device2);
|
|
||||||
if (info.is_suitable_)
|
|
||||||
devices[info.unique_id()] = info;
|
|
||||||
else
|
|
||||||
device2->Release();
|
|
||||||
}
|
|
||||||
device_it->Release();
|
|
||||||
|
|
||||||
// Update the internal cache
|
|
||||||
qLog(Debug) << "Updating device cache";
|
|
||||||
{
|
|
||||||
QMutexLocker l(&mutex_);
|
|
||||||
devices_ = devices;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify about the changes
|
|
||||||
foreach (const QString& id, devices.keys()) {
|
|
||||||
emit DeviceAdded(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
qLog(Debug) << "Startup complete";
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmLister::ReallyShutdown() {
|
|
||||||
// Unregister for notifications
|
|
||||||
IConnectionPointContainer* cp_container;
|
|
||||||
thread_->manager()->QueryInterface(IID_IConnectionPointContainer, (void**)&cp_container);
|
|
||||||
|
|
||||||
IConnectionPoint* cp;
|
|
||||||
cp_container->FindConnectionPoint(IID_IWMDMNotification, &cp);
|
|
||||||
|
|
||||||
cp->Release();
|
|
||||||
cp_container->Release();
|
|
||||||
|
|
||||||
thread_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmLister::ShutDown() {
|
|
||||||
// COM shutdown must be done in the original thread.
|
|
||||||
metaObject()->invokeMethod(this, "ReallyShutdown", Qt::BlockingQueuedConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
WmdmLister::DeviceInfo WmdmLister::ReadDeviceInfo(IWMDMDevice2* device) {
|
|
||||||
qLog(Debug) << "Reading device info";
|
|
||||||
|
|
||||||
DeviceInfo ret;
|
|
||||||
ret.device_ = device;
|
|
||||||
|
|
||||||
// Get text strings
|
|
||||||
const int max_size = 512;
|
|
||||||
wchar_t buf[max_size];
|
|
||||||
device->GetName(buf, max_size);
|
|
||||||
ret.name_ = QString::fromWCharArray(buf).trimmed();
|
|
||||||
|
|
||||||
device->GetManufacturer(buf, max_size);
|
|
||||||
ret.manufacturer_ = QString::fromWCharArray(buf).trimmed();
|
|
||||||
|
|
||||||
device->GetCanonicalName(buf, max_size);
|
|
||||||
ret.canonical_name_ = QString::fromWCharArray(buf).toLower();
|
|
||||||
|
|
||||||
qLog(Debug) << "Read device strings:" << ret.name_ << ret.manufacturer_ << ret.canonical_name_;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
if (device3) {
|
|
||||||
device3->GetProperty(g_wszWMDMDeviceProtocol, &protocol);
|
|
||||||
device3->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the type and check whether it has storage
|
|
||||||
DWORD type = 0;
|
|
||||||
device->GetType(&type);
|
|
||||||
if (type & WMDM_DEVICE_TYPE_STORAGE)
|
|
||||||
ret.is_suitable_ = true;
|
|
||||||
|
|
||||||
// Get the icon
|
|
||||||
HICON icon;
|
|
||||||
if (device->GetDeviceIcon((ULONG*)&icon) == S_OK) {
|
|
||||||
// Extra check for whether the icon is valid (see issue 1417)
|
|
||||||
|
|
||||||
ICONINFO iconinfo;
|
|
||||||
if (GetIconInfo(icon, &iconinfo)) {
|
|
||||||
ret.icon_ = QPixmap::fromWinHICON(icon);
|
|
||||||
DestroyIcon(icon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the main (first) storage for the device
|
|
||||||
IWMDMEnumStorage* storage_it = NULL;
|
|
||||||
if (device->EnumStorage(&storage_it) == S_OK && storage_it) {
|
|
||||||
ULONG storage_fetched = 0;
|
|
||||||
IWMDMStorage* storage;
|
|
||||||
|
|
||||||
if (storage_it->Next(1, &storage, &storage_fetched) == S_OK) {
|
|
||||||
if (storage->QueryInterface(IID_IWMDMStorage2, (void**)&ret.storage_)) {
|
|
||||||
qLog(Warning) << "Error getting IWMDMStorage2 from storage";
|
|
||||||
} else {
|
|
||||||
// Get free space information
|
|
||||||
UpdateFreeSpace(&ret);
|
|
||||||
}
|
|
||||||
storage->Release();
|
|
||||||
}
|
|
||||||
storage_it->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
if (!device3 || QUuid(*protocol.puuid) == kDeviceProtocolMsc)
|
|
||||||
GuessDriveLetter(&ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmLister::GuessDriveLetter(DeviceInfo* info) {
|
|
||||||
qLog(Debug) << "Guessing drive letter for" << info->name_;
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
qLog(Debug) << "Looks like an XP drive" << drive_letter.cap(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) {
|
|
||||||
qLog(Debug) << "Looks like a win7 drive" << drive_letter.cap(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)) {
|
|
||||||
qLog(Warning) << "Error getting volume information for" <<
|
|
||||||
QString::fromWCharArray(volume_path);
|
|
||||||
} else {
|
|
||||||
if (name.ToString() == info->name_ && name.characters() != 0) {
|
|
||||||
// We found it!
|
|
||||||
qLog(Debug) << "Looks like a win7 drive name" << QString::fromWCharArray(volume_path);
|
|
||||||
if (CheckDriveLetter(info, QString::fromWCharArray(volume_path))) {
|
|
||||||
info->device_name_ = QString::fromWCharArray(device_name);
|
|
||||||
info->volume_name_ = QString::fromWCharArray(volume_name);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!FindNextVolumeW(handle, volume_name, MAX_PATH))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
FindVolumeClose(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool 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
|
|
||||||
)) {
|
|
||||||
qLog(Warning) << "Error getting volume information for" << drive;
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
qLog(Debug) << "Validated drive letter" << drive;
|
|
||||||
info->mount_point_ = path.ToString();
|
|
||||||
info->fs_name_ = name.ToString();
|
|
||||||
info->fs_type_ = type.ToString();
|
|
||||||
info->fs_serial_ = serial;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList WmdmLister::DeviceUniqueIDs() {
|
|
||||||
QMutexLocker l(&mutex_);
|
|
||||||
return devices_.keys();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantList WmdmLister::DeviceIcons(const QString& id) {
|
|
||||||
QPixmap pixmap = LockAndGetDeviceInfo(id, &DeviceInfo::icon_);
|
|
||||||
|
|
||||||
if (pixmap.isNull())
|
|
||||||
return QVariantList();
|
|
||||||
return QVariantList() << pixmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WmdmLister::DeviceManufacturer(const QString& id) {
|
|
||||||
return LockAndGetDeviceInfo(id, &DeviceInfo::manufacturer_);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WmdmLister::DeviceModel(const QString& id) {
|
|
||||||
return LockAndGetDeviceInfo(id, &DeviceInfo::name_);
|
|
||||||
}
|
|
||||||
|
|
||||||
quint64 WmdmLister::DeviceCapacity(const QString& id) {
|
|
||||||
return LockAndGetDeviceInfo(id, &DeviceInfo::total_bytes_);
|
|
||||||
}
|
|
||||||
|
|
||||||
quint64 WmdmLister::DeviceFreeSpace(const QString& id) {
|
|
||||||
return LockAndGetDeviceInfo(id, &DeviceInfo::free_bytes_);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantMap WmdmLister::DeviceHardwareInfo(const QString& id) {
|
|
||||||
QVariantMap ret;
|
|
||||||
|
|
||||||
QMutexLocker l(&mutex_);
|
|
||||||
if (!devices_.contains(id))
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
const DeviceInfo& info = devices_[id];
|
|
||||||
|
|
||||||
ret[tr("Drive letter")] = QDir::toNativeSeparators(info.mount_point_);
|
|
||||||
ret[tr("Filesystem type")] = info.fs_type_;
|
|
||||||
ret[tr("Filesystem name")] = info.fs_name_;
|
|
||||||
ret[tr("Device name")] = info.device_name_;
|
|
||||||
ret[tr("Volume name")] = info.volume_name_;
|
|
||||||
|
|
||||||
if (info.fs_serial_ != 0)
|
|
||||||
ret[tr("Filesystem serial number")] = info.fs_serial_;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WmdmLister::MakeFriendlyName(const QString& id) {
|
|
||||||
QMutexLocker l(&mutex_);
|
|
||||||
if (!devices_.contains(id))
|
|
||||||
return QString();
|
|
||||||
|
|
||||||
const DeviceInfo& info = devices_[id];
|
|
||||||
if (info.manufacturer_.isEmpty() || info.manufacturer_ == "Unknown")
|
|
||||||
return info.name_;
|
|
||||||
|
|
||||||
return info.manufacturer_ + " " + info.name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QUrl> WmdmLister::MakeDeviceUrls(const QString& id) {
|
|
||||||
QList<QUrl> ret;
|
|
||||||
|
|
||||||
QString mount_point = LockAndGetDeviceInfo(id, &DeviceInfo::mount_point_);
|
|
||||||
if (!mount_point.isEmpty()) {
|
|
||||||
ret << MakeUrlFromLocalPath(mount_point);
|
|
||||||
}
|
|
||||||
|
|
||||||
QUrl wmdm_url;
|
|
||||||
wmdm_url.setScheme("wmdm");
|
|
||||||
wmdm_url.setPath(id);
|
|
||||||
ret << wmdm_url;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmLister::UnmountDevice(const QString& id) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmLister::UpdateDeviceFreeSpace(const QString& id) {
|
|
||||||
// This needs to be done in the lister's thread where we already have COM
|
|
||||||
// initialised
|
|
||||||
metaObject()->invokeMethod(this, "DoUpdateDriveFreeSpace",
|
|
||||||
Qt::BlockingQueuedConnection, Q_ARG(QString, id));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmLister::DoUpdateDriveFreeSpace(const QString& id) {
|
|
||||||
{
|
|
||||||
QMutexLocker l(&mutex_);
|
|
||||||
if (!devices_.contains(id))
|
|
||||||
return;
|
|
||||||
|
|
||||||
UpdateFreeSpace(&devices_[id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit DeviceChanged(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
qint64 GetSpaceValue(
|
|
||||||
IWMDMStorageGlobals* globals,
|
|
||||||
LONG (IWMDMStorageGlobals::*f)(DWORD*,DWORD*)) {
|
|
||||||
DWORD low, high;
|
|
||||||
((globals)->*(f))(&low, &high);
|
|
||||||
|
|
||||||
return (qint64)high << 32 | (qint64)low;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmLister::UpdateFreeSpace(DeviceInfo* info) {
|
|
||||||
IWMDMStorageGlobals* globals;
|
|
||||||
info->storage_->GetStorageGlobals(&globals);
|
|
||||||
|
|
||||||
DWORD low, high;
|
|
||||||
|
|
||||||
globals->GetTotalSize(&low, &high);
|
|
||||||
info->total_bytes_ = (qint64)high << 32 | (qint64)low;
|
|
||||||
|
|
||||||
globals->GetTotalFree(&low, &high);
|
|
||||||
info->free_bytes_ = (qint64)high << 32 | (qint64)low;
|
|
||||||
|
|
||||||
globals->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT WmdmLister::WMDMMessage(DWORD message_type, LPCWSTR name) {
|
|
||||||
qLog(Debug) << "WMDM message" << message_type << name;
|
|
||||||
|
|
||||||
QString canonical_name = QString::fromWCharArray(name).toLower();
|
|
||||||
|
|
||||||
switch (message_type) {
|
|
||||||
case WMDM_MSG_DEVICE_ARRIVAL: WMDMDeviceAdded(canonical_name); break;
|
|
||||||
case WMDM_MSG_DEVICE_REMOVAL: WMDMDeviceRemoved(canonical_name); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmLister::WMDMDeviceAdded(const QString& canonical_name) {
|
|
||||||
ScopedWCharArray name(canonical_name);
|
|
||||||
|
|
||||||
IWMDMDevice* device = NULL;
|
|
||||||
if (thread_->manager()->GetDeviceFromCanonicalName(name, &device)) {
|
|
||||||
qLog(Warning) << "Error in GetDeviceFromCanonicalName for" << canonical_name;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IWMDMDevice2* device2 = NULL;
|
|
||||||
if (device->QueryInterface(IID_IWMDMDevice2, (void**) &device2)) {
|
|
||||||
qLog(Warning) << "Error getting IWMDMDevice2 from device";
|
|
||||||
device->Release();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
device->Release();
|
|
||||||
|
|
||||||
DeviceInfo info = ReadDeviceInfo(device2);
|
|
||||||
if (info.is_suitable_) {
|
|
||||||
QString id = info.unique_id();
|
|
||||||
{
|
|
||||||
QMutexLocker l(&mutex_);
|
|
||||||
devices_[id] = info;
|
|
||||||
}
|
|
||||||
emit DeviceAdded(id);
|
|
||||||
} else {
|
|
||||||
device2->Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmLister::WMDMDeviceRemoved(const QString& canonical_name) {
|
|
||||||
QString id = CanonicalNameToId(canonical_name);
|
|
||||||
{
|
|
||||||
QMutexLocker l(&mutex_);
|
|
||||||
if (!devices_.contains(id))
|
|
||||||
return;
|
|
||||||
|
|
||||||
devices_[id].device_->Release();
|
|
||||||
devices_[id].storage_->Release();
|
|
||||||
|
|
||||||
devices_.remove(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit DeviceRemoved(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
LONG WmdmLister::QueryInterface(REFIID riid, void** object) {
|
|
||||||
*object = 0;
|
|
||||||
|
|
||||||
if (riid == IID_IUnknown)
|
|
||||||
*object = (IUnknown*) this;
|
|
||||||
else if (riid == IID_IWMDMNotification)
|
|
||||||
*object = (IWMDMNotification*) this;
|
|
||||||
else
|
|
||||||
return E_NOINTERFACE;
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG WmdmLister::AddRef() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG WmdmLister::Release() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WmdmLister::DeviceCanonicalName(const QString& id) {
|
|
||||||
return LockAndGetDeviceInfo(id, &DeviceInfo::canonical_name_);
|
|
||||||
}
|
|
||||||
|
|
@ -1,141 +0,0 @@
|
|||||||
/* This file is part of Clementine.
|
|
||||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Clementine is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WMDMLISTER_H
|
|
||||||
#define WMDMLISTER_H
|
|
||||||
|
|
||||||
#include "devicelister.h"
|
|
||||||
|
|
||||||
#include <QMap>
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QPixmap>
|
|
||||||
#include <QUuid>
|
|
||||||
|
|
||||||
#include <boost/scoped_ptr.hpp>
|
|
||||||
|
|
||||||
#include <mswmdm.h>
|
|
||||||
#include <sac_shim.h>
|
|
||||||
#undef LoadIcon
|
|
||||||
|
|
||||||
class WmdmThread;
|
|
||||||
|
|
||||||
class WmdmLister : public DeviceLister, public IWMDMNotification {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
WmdmLister();
|
|
||||||
~WmdmLister();
|
|
||||||
|
|
||||||
// DeviceLister
|
|
||||||
virtual void Init();
|
|
||||||
|
|
||||||
virtual QStringList DeviceUniqueIDs();
|
|
||||||
virtual QVariantList DeviceIcons(const QString& id);
|
|
||||||
virtual QString DeviceManufacturer(const QString& id);
|
|
||||||
virtual QString DeviceModel(const QString& id);
|
|
||||||
virtual quint64 DeviceCapacity(const QString& id);
|
|
||||||
virtual quint64 DeviceFreeSpace(const QString& id);
|
|
||||||
virtual QVariantMap DeviceHardwareInfo(const QString& id);
|
|
||||||
virtual QString MakeFriendlyName(const QString& id);
|
|
||||||
virtual QList<QUrl> MakeDeviceUrls(const QString& id);
|
|
||||||
virtual void UnmountDevice(const QString& id);
|
|
||||||
|
|
||||||
// IWMDMNotification
|
|
||||||
// The __stdcall is *really* important
|
|
||||||
virtual HRESULT __stdcall WMDMMessage(DWORD message_type, LPCWSTR name);
|
|
||||||
virtual LONG __stdcall QueryInterface(const IID& riid, void** object);
|
|
||||||
virtual ULONG __stdcall AddRef();
|
|
||||||
virtual ULONG __stdcall Release();
|
|
||||||
|
|
||||||
// Called by WmdmLister
|
|
||||||
QString DeviceCanonicalName(const QString& id);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
virtual void UpdateDeviceFreeSpace(const QString& id);
|
|
||||||
virtual void ShutDown();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
virtual void DoUpdateDriveFreeSpace(const QString& id);
|
|
||||||
virtual void ReallyShutdown();
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct DeviceInfo {
|
|
||||||
DeviceInfo() : device_(NULL), storage_(NULL), is_suitable_(false),
|
|
||||||
total_bytes_(0), free_bytes_(0) {}
|
|
||||||
|
|
||||||
QString unique_id() const;
|
|
||||||
|
|
||||||
IWMDMDevice2* device_;
|
|
||||||
IWMDMStorage2* storage_;
|
|
||||||
|
|
||||||
bool is_suitable_;
|
|
||||||
|
|
||||||
QString name_;
|
|
||||||
QString manufacturer_;
|
|
||||||
QString canonical_name_;
|
|
||||||
|
|
||||||
QPixmap icon_;
|
|
||||||
|
|
||||||
quint64 total_bytes_;
|
|
||||||
quint64 free_bytes_;
|
|
||||||
|
|
||||||
// Only valid for filesystem devices
|
|
||||||
QString mount_point_;
|
|
||||||
QString fs_name_;
|
|
||||||
QString fs_type_;
|
|
||||||
int fs_serial_;
|
|
||||||
|
|
||||||
// Information we get by querying win7-style FS devices
|
|
||||||
QString device_name_;
|
|
||||||
QString volume_name_;
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
bool CheckDriveLetter(DeviceInfo* info, const QString& drive);
|
|
||||||
|
|
||||||
static QString CanonicalNameToId(const QString& canonical_name);
|
|
||||||
void WMDMDeviceAdded(const QString& canonical_name);
|
|
||||||
void WMDMDeviceRemoved(const QString& canonical_name);
|
|
||||||
|
|
||||||
private:
|
|
||||||
boost::scoped_ptr<WmdmThread> thread_;
|
|
||||||
|
|
||||||
SacHandle sac_;
|
|
||||||
DWORD notification_cookie_;
|
|
||||||
|
|
||||||
QMutex mutex_;
|
|
||||||
QMap<QString, DeviceInfo> devices_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T WmdmLister::LockAndGetDeviceInfo(const QString& id, T DeviceInfo::*field) {
|
|
||||||
QMutexLocker l(&mutex_);
|
|
||||||
if (!devices_.contains(id))
|
|
||||||
return T();
|
|
||||||
|
|
||||||
return devices_[id].*field;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // WMDMLISTER_H
|
|
@ -1,133 +0,0 @@
|
|||||||
/* This file is part of Clementine.
|
|
||||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Clementine is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "devicelister.h"
|
|
||||||
#include "wmdmdevice.h"
|
|
||||||
#include "wmdmlister.h"
|
|
||||||
#include "wmdmloader.h"
|
|
||||||
#include "wmdmthread.h"
|
|
||||||
#include "core/taskmanager.h"
|
|
||||||
#include "library/librarybackend.h"
|
|
||||||
|
|
||||||
#include <boost/scoped_array.hpp>
|
|
||||||
|
|
||||||
#include <cwchar>
|
|
||||||
#include <mswmdm.h>
|
|
||||||
|
|
||||||
#include <QUuid>
|
|
||||||
|
|
||||||
WmdmLoader::WmdmLoader(TaskManager* task_manager, LibraryBackend* backend,
|
|
||||||
boost::shared_ptr<ConnectedDevice> device)
|
|
||||||
: QObject(NULL),
|
|
||||||
device_(device),
|
|
||||||
task_manager_(task_manager),
|
|
||||||
backend_(backend)
|
|
||||||
{
|
|
||||||
original_thread_ = thread();
|
|
||||||
}
|
|
||||||
|
|
||||||
WmdmLoader::~WmdmLoader() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmLoader::LoadDatabase() {
|
|
||||||
int task_id = task_manager_->StartTask(tr("Loading Windows Media device"));
|
|
||||||
emit TaskStarted(task_id);
|
|
||||||
|
|
||||||
boost::scoped_ptr<WmdmThread> thread(new WmdmThread);
|
|
||||||
|
|
||||||
// Get the device's canonical name
|
|
||||||
boost::shared_ptr<WmdmDevice> connected_device =
|
|
||||||
boost::static_pointer_cast<WmdmDevice>(device_);
|
|
||||||
WmdmLister* lister = static_cast<WmdmLister*>(connected_device->lister());
|
|
||||||
QString canonical_name = lister->DeviceCanonicalName(connected_device->unique_id());
|
|
||||||
|
|
||||||
IWMDMStorage* storage = thread->GetRootStorage(canonical_name);
|
|
||||||
QStringList path_components;
|
|
||||||
RecursiveExploreStorage(storage, &path_components);
|
|
||||||
storage->Release();
|
|
||||||
|
|
||||||
thread.reset();
|
|
||||||
|
|
||||||
// Need to remove all the existing songs in the database first
|
|
||||||
backend_->DeleteSongs(backend_->FindSongsInDirectory(1));
|
|
||||||
|
|
||||||
// Add the songs we've just loaded
|
|
||||||
backend_->AddOrUpdateSongs(songs_);
|
|
||||||
|
|
||||||
task_manager_->SetTaskFinished(task_id);
|
|
||||||
emit LoadFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmLoader::RecursiveExploreStorage(IWMDMStorage* parent, QStringList* path_components) {
|
|
||||||
IWMDMEnumStorage* child_it = NULL;
|
|
||||||
parent->EnumStorage(&child_it);
|
|
||||||
|
|
||||||
IWMDMStorage* child = NULL;
|
|
||||||
ULONG num_retreived = 0;
|
|
||||||
while (child_it->Next(1, &child, &num_retreived) == S_OK && num_retreived == 1) {
|
|
||||||
const int kMaxLen = 255;
|
|
||||||
wchar_t name[kMaxLen];
|
|
||||||
child->GetName(name, kMaxLen);
|
|
||||||
|
|
||||||
DWORD attributes = 0;
|
|
||||||
_WAVEFORMATEX audio_format;
|
|
||||||
child->GetAttributes(&attributes, &audio_format);
|
|
||||||
|
|
||||||
path_components->append(QString::fromWCharArray(name));
|
|
||||||
if (attributes & WMDM_FILE_ATTR_FILE) {
|
|
||||||
LoadFile(child, path_components);
|
|
||||||
} else if (attributes & WMDM_FILE_ATTR_FOLDER) {
|
|
||||||
RecursiveExploreStorage(child, path_components);
|
|
||||||
}
|
|
||||||
path_components->removeLast();
|
|
||||||
|
|
||||||
child->Release();
|
|
||||||
}
|
|
||||||
child_it->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WmdmLoader::LoadFile(IWMDMStorage* file, const QStringList* path_components) {
|
|
||||||
// Convert to a IWMDMStorage3 so we can get metadata
|
|
||||||
IWMDMStorage3* storage3 = NULL;
|
|
||||||
if (file->QueryInterface(IID_IWMDMStorage3, (void**) &storage3))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Get the metadata interface
|
|
||||||
IWMDMMetaData* metadata = NULL;
|
|
||||||
if (storage3->GetMetadata(&metadata)) {
|
|
||||||
storage3->Release();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
storage3->Release();
|
|
||||||
|
|
||||||
QUrl url;
|
|
||||||
url.setScheme("wmdm");
|
|
||||||
url.setPath(path_components->join("/"));
|
|
||||||
|
|
||||||
// Store the metadata in here
|
|
||||||
Song song;
|
|
||||||
song.InitFromWmdm(metadata);
|
|
||||||
song.set_directory_id(1);
|
|
||||||
song.set_url(url);
|
|
||||||
|
|
||||||
metadata->Release();
|
|
||||||
|
|
||||||
if (song.is_valid())
|
|
||||||
songs_ << song;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
|||||||
/* This file is part of Clementine.
|
|
||||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Clementine is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WMDMLOADER_H
|
|
||||||
#define WMDMLOADER_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
|
||||||
|
|
||||||
#include "core/song.h"
|
|
||||||
|
|
||||||
class ConnectedDevice;
|
|
||||||
class LibraryBackend;
|
|
||||||
class TaskManager;
|
|
||||||
|
|
||||||
struct IWMDMStorage;
|
|
||||||
|
|
||||||
class WmdmLoader : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
WmdmLoader(TaskManager* task_manager, LibraryBackend* backend,
|
|
||||||
boost::shared_ptr<ConnectedDevice> device);
|
|
||||||
~WmdmLoader();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void LoadDatabase();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void Error(const QString& message);
|
|
||||||
void TaskStarted(int task_id);
|
|
||||||
void LoadFinished();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RecursiveExploreStorage(IWMDMStorage* parent, QStringList* path_components);
|
|
||||||
void LoadFile(IWMDMStorage* file, const QStringList* path_components);
|
|
||||||
|
|
||||||
private:
|
|
||||||
boost::shared_ptr<ConnectedDevice> device_;
|
|
||||||
QThread* original_thread_;
|
|
||||||
|
|
||||||
TaskManager* task_manager_;
|
|
||||||
LibraryBackend* backend_;
|
|
||||||
|
|
||||||
SongList songs_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // WMDMLOADER_H
|
|
@ -1,82 +0,0 @@
|
|||||||
/* This file is part of Clementine.
|
|
||||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Clementine is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "wmdmprogress.h"
|
|
||||||
|
|
||||||
#include <QtDebug>
|
|
||||||
|
|
||||||
WmdmProgress::WmdmProgress(const MusicStorage::ProgressFunction& f)
|
|
||||||
: f_(f),
|
|
||||||
estimated_(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
LONG WmdmProgress::QueryInterface(const IID& riid, void** object) {
|
|
||||||
*object = 0;
|
|
||||||
|
|
||||||
if (riid == IID_IUnknown)
|
|
||||||
*object = (IUnknown*) this;
|
|
||||||
else if (riid == IID_IWMDMProgress)
|
|
||||||
*object = (IWMDMProgress*) this;
|
|
||||||
else if (riid == IID_IWMDMProgress2)
|
|
||||||
*object = (IWMDMProgress2*) this;
|
|
||||||
else if (riid == IID_IWMDMProgress3)
|
|
||||||
*object = (IWMDMProgress3*) this;
|
|
||||||
else
|
|
||||||
return E_NOINTERFACE;
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG WmdmProgress::AddRef() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ULONG WmdmProgress::Release() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT WmdmProgress::Begin(DWORD estimated_ticks) {
|
|
||||||
return Begin3(EVENT_WMDM_CONTENT_TRANSFER, estimated_ticks, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT WmdmProgress::End() {
|
|
||||||
return End3(EVENT_WMDM_CONTENT_TRANSFER, S_OK, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT WmdmProgress::Progress(DWORD transpired_ticks) {
|
|
||||||
return Progress3(EVENT_WMDM_CONTENT_TRANSFER, transpired_ticks, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT WmdmProgress::End2(HRESULT completion_code) {
|
|
||||||
return End3(EVENT_WMDM_CONTENT_TRANSFER, completion_code, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT WmdmProgress::Begin3(GUID, DWORD estimated_ticks, OPAQUECOMMAND*) {
|
|
||||||
estimated_ = estimated_ticks;
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT WmdmProgress::End3(GUID, HRESULT, OPAQUECOMMAND*) {
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT WmdmProgress::Progress3(GUID, DWORD transpired_ticks, OPAQUECOMMAND*) {
|
|
||||||
if (estimated_ != 0)
|
|
||||||
f_(float(transpired_ticks) / estimated_);
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
/* This file is part of Clementine.
|
|
||||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Clementine is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WMDMPROGRESS_H
|
|
||||||
#define WMDMPROGRESS_H
|
|
||||||
|
|
||||||
#include <mswmdm.h>
|
|
||||||
|
|
||||||
#include "core/musicstorage.h"
|
|
||||||
|
|
||||||
class WmdmProgress : public IWMDMProgress3 {
|
|
||||||
public:
|
|
||||||
WmdmProgress(const MusicStorage::ProgressFunction& f =
|
|
||||||
MusicStorage::ProgressFunction());
|
|
||||||
|
|
||||||
// IUnknown
|
|
||||||
// The __stdcall is *really* important
|
|
||||||
virtual LONG __stdcall QueryInterface(const IID& riid, void** object);
|
|
||||||
virtual ULONG __stdcall AddRef();
|
|
||||||
virtual ULONG __stdcall Release();
|
|
||||||
|
|
||||||
// IWMDMProgress
|
|
||||||
virtual HRESULT __stdcall Begin(DWORD estimated_ticks);
|
|
||||||
virtual HRESULT __stdcall End();
|
|
||||||
virtual HRESULT __stdcall Progress(DWORD transpired_ticks);
|
|
||||||
|
|
||||||
// IWMDMProgress2
|
|
||||||
virtual HRESULT __stdcall End2(HRESULT completion_code);
|
|
||||||
|
|
||||||
// IWMDMProgress3
|
|
||||||
virtual HRESULT __stdcall Begin3(GUID event_id, DWORD estimated_ticks,
|
|
||||||
OPAQUECOMMAND* context);
|
|
||||||
virtual HRESULT __stdcall End3(GUID event_id, HRESULT completion_code,
|
|
||||||
OPAQUECOMMAND* context);
|
|
||||||
virtual HRESULT __stdcall Progress3(GUID event_id, DWORD transpired_ticks,
|
|
||||||
OPAQUECOMMAND* context);
|
|
||||||
|
|
||||||
private:
|
|
||||||
MusicStorage::ProgressFunction f_;
|
|
||||||
|
|
||||||
DWORD estimated_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // WMDMPROGRESS_H
|
|
@ -1,157 +0,0 @@
|
|||||||
/* This file is part of Clementine.
|
|
||||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Clementine is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "wmdmthread.h"
|
|
||||||
#include "core/logging.h"
|
|
||||||
#include "core/utilities.h"
|
|
||||||
|
|
||||||
#include <mswmdm.h>
|
|
||||||
|
|
||||||
#include <boost/scoped_array.hpp>
|
|
||||||
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QLibrary>
|
|
||||||
#include <QMutexLocker>
|
|
||||||
#include <QtDebug>
|
|
||||||
|
|
||||||
BYTE abPVK[] = {0x00};
|
|
||||||
BYTE abCert[] = {0x00};
|
|
||||||
|
|
||||||
bool WmdmThread::sIsLoaded = false;
|
|
||||||
|
|
||||||
decltype(&CSecureChannelClient_New) WmdmThread::_CSecureChannelClient_New;
|
|
||||||
decltype(&CSecureChannelClient_Free) WmdmThread::_CSecureChannelClient_Free;
|
|
||||||
decltype(&CSecureChannelClient_SetCertificate) WmdmThread::_CSecureChannelClient_SetCertificate;
|
|
||||||
decltype(&CSecureChannelClient_SetInterface) WmdmThread::_CSecureChannelClient_SetInterface;
|
|
||||||
decltype(&CSecureChannelClient_Authenticate) WmdmThread::_CSecureChannelClient_Authenticate;
|
|
||||||
|
|
||||||
|
|
||||||
WmdmThread::WmdmThread()
|
|
||||||
: device_manager_(NULL),
|
|
||||||
sac_(NULL)
|
|
||||||
{
|
|
||||||
if (!sIsLoaded) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Initialise COM
|
|
||||||
CoInitialize(0);
|
|
||||||
|
|
||||||
// Authenticate with WMDM
|
|
||||||
IComponentAuthenticate* auth;
|
|
||||||
if (CoCreateInstance(CLSID_MediaDevMgr, NULL, CLSCTX_ALL,
|
|
||||||
IID_IComponentAuthenticate, (void**) &auth)) {
|
|
||||||
qLog(Warning) << "Error creating the IComponentAuthenticate interface";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sac_ = _CSecureChannelClient_New();
|
|
||||||
if (_CSecureChannelClient_SetCertificate(
|
|
||||||
sac_, SAC_CERT_V1, abCert, sizeof(abCert), abPVK, sizeof(abPVK))) {
|
|
||||||
qLog(Warning) << "Error setting SAC certificate";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_CSecureChannelClient_SetInterface(sac_, auth);
|
|
||||||
if (_CSecureChannelClient_Authenticate(sac_, SAC_PROTOCOL_V1)) {
|
|
||||||
qLog(Warning) << "Error authenticating with SAC";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the device manager
|
|
||||||
if (auth->QueryInterface(IID_IWMDeviceManager2, (void**)&device_manager_)) {
|
|
||||||
qLog(Warning) << "Error creating WMDM device manager";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WmdmThread::~WmdmThread() {
|
|
||||||
if (device_manager_) {
|
|
||||||
// Release the device manager
|
|
||||||
device_manager_->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sac_) {
|
|
||||||
// SAC
|
|
||||||
_CSecureChannelClient_Free(sac_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uninitialise COM
|
|
||||||
CoUninitialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T Resolve(QLibrary* library, const char* name) {
|
|
||||||
return reinterpret_cast<T>(library->resolve(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
bool WmdmThread::StaticInit() {
|
|
||||||
if (!sIsLoaded) {
|
|
||||||
QLibrary library(QCoreApplication::applicationDirPath() + "/sac_shim.dll");
|
|
||||||
if (!library.load()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_CSecureChannelClient_New = Resolve<decltype(_CSecureChannelClient_New)>(
|
|
||||||
&library, "CSecureChannelClient_New");
|
|
||||||
_CSecureChannelClient_Free = Resolve<decltype(_CSecureChannelClient_Free)>(
|
|
||||||
&library, "CSecureChannelClient_Free");
|
|
||||||
_CSecureChannelClient_SetCertificate = Resolve<decltype(_CSecureChannelClient_SetCertificate)>(
|
|
||||||
&library, "CSecureChannelClient_SetCertificate");
|
|
||||||
_CSecureChannelClient_SetInterface = Resolve<decltype(_CSecureChannelClient_SetInterface)>(
|
|
||||||
&library, "CSecureChannelClient_SetInterface");
|
|
||||||
if (_CSecureChannelClient_New &&
|
|
||||||
_CSecureChannelClient_Free &&
|
|
||||||
_CSecureChannelClient_SetCertificate &&
|
|
||||||
_CSecureChannelClient_SetInterface) {
|
|
||||||
sIsLoaded = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
IWMDMDevice* WmdmThread::GetDeviceByCanonicalName(const QString& device_name) {
|
|
||||||
ScopedWCharArray name(device_name);
|
|
||||||
|
|
||||||
IWMDMDevice* device = NULL;
|
|
||||||
if (device_manager_->GetDeviceFromCanonicalName(name, &device)) {
|
|
||||||
qLog(Warning) << "Error in GetDeviceFromCanonicalName for" << device_name;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return device;
|
|
||||||
}
|
|
||||||
|
|
||||||
IWMDMStorage* WmdmThread::GetRootStorage(const QString& device_name) {
|
|
||||||
IWMDMDevice* device = GetDeviceByCanonicalName(device_name);
|
|
||||||
|
|
||||||
IWMDMEnumStorage* storage_it = NULL;
|
|
||||||
device->EnumStorage(&storage_it);
|
|
||||||
|
|
||||||
ULONG storage_fetched = 0;
|
|
||||||
IWMDMStorage* storage = NULL;
|
|
||||||
storage_it->Next(1, &storage, &storage_fetched);
|
|
||||||
|
|
||||||
storage_it->Release();
|
|
||||||
device->Release();
|
|
||||||
|
|
||||||
return storage;
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
/* This file is part of Clementine.
|
|
||||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Clementine is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WMDMTHREAD_H
|
|
||||||
#define WMDMTHREAD_H
|
|
||||||
|
|
||||||
#include <QMutex>
|
|
||||||
#include <QtGlobal>
|
|
||||||
|
|
||||||
#include <sac_shim.h>
|
|
||||||
|
|
||||||
struct IWMDeviceManager2;
|
|
||||||
struct IWMDMDevice;
|
|
||||||
struct IWMDMStorage;
|
|
||||||
|
|
||||||
class WmdmThread {
|
|
||||||
public:
|
|
||||||
WmdmThread();
|
|
||||||
~WmdmThread();
|
|
||||||
|
|
||||||
IWMDeviceManager2* manager() const { return device_manager_; }
|
|
||||||
|
|
||||||
IWMDMDevice* GetDeviceByCanonicalName(const QString& device_name);
|
|
||||||
IWMDMStorage* GetRootStorage(const QString& device_name);
|
|
||||||
|
|
||||||
static bool StaticInit();
|
|
||||||
private:
|
|
||||||
|
|
||||||
Q_DISABLE_COPY(WmdmThread);
|
|
||||||
|
|
||||||
IWMDeviceManager2* device_manager_;
|
|
||||||
SacHandle sac_;
|
|
||||||
|
|
||||||
static decltype(&CSecureChannelClient_New) _CSecureChannelClient_New;
|
|
||||||
static decltype(&CSecureChannelClient_Free) _CSecureChannelClient_Free;
|
|
||||||
static decltype(&CSecureChannelClient_SetCertificate) _CSecureChannelClient_SetCertificate;
|
|
||||||
static decltype(&CSecureChannelClient_SetInterface) _CSecureChannelClient_SetInterface;
|
|
||||||
static decltype(&CSecureChannelClient_Authenticate) _CSecureChannelClient_Authenticate;
|
|
||||||
|
|
||||||
static bool sIsLoaded;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // WMDMTHREAD_H
|
|
@ -101,7 +101,6 @@ using boost::scoped_ptr;
|
|||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
# include <qtsparkle/Updater>
|
# include <qtsparkle/Updater>
|
||||||
# include "devices/wmdmthread.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Load sqlite plugin on windows and mac.
|
// Load sqlite plugin on windows and mac.
|
||||||
@ -447,12 +446,6 @@ int main(int argc, char *argv[]) {
|
|||||||
mpris::Mpris mpris(&app);
|
mpris::Mpris mpris(&app);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
|
||||||
if (!WmdmThread::StaticInit()) {
|
|
||||||
qLog(Warning) << "Failed to initialise SAC shim";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Window
|
// Window
|
||||||
MainWindow w(&app, tray_icon.get(), &osd);
|
MainWindow w(&app, tray_icon.get(), &osd);
|
||||||
#ifdef Q_OS_DARWIN
|
#ifdef Q_OS_DARWIN
|
||||||
|
Loading…
x
Reference in New Issue
Block a user