aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Portable
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Plugins/Portable')
-rw-r--r--Src/Plugins/Portable/pmp_activesync/ASDevice.cpp798
-rw-r--r--Src/Plugins/Portable/pmp_activesync/ASDevice.h172
-rw-r--r--Src/Plugins/Portable/pmp_activesync/activesync/Inc/IRAPIStream.h286
-rw-r--r--Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapi.h118
-rw-r--r--Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapi2.h3090
-rw-r--r--Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapitypes.h445
-rw-r--r--Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapitypes2.h248
-rw-r--r--Src/Plugins/Portable/pmp_activesync/activesync/Lib/rapiuuid.libbin0 -> 4964 bytes
-rw-r--r--Src/Plugins/Portable/pmp_activesync/main.cpp220
-rw-r--r--Src/Plugins/Portable/pmp_activesync/pmp_activesync.rc116
-rw-r--r--Src/Plugins/Portable/pmp_activesync/pmp_activesync.sln18
-rw-r--r--Src/Plugins/Portable/pmp_activesync/pmp_activesync.vcxproj357
-rw-r--r--Src/Plugins/Portable/pmp_activesync/pmp_activesync.vcxproj.filters51
-rw-r--r--Src/Plugins/Portable/pmp_activesync/resource.h31
-rw-r--r--Src/Plugins/Portable/pmp_activesync/resources/activeSyncIcon.pngbin0 -> 246 bytes
-rw-r--r--Src/Plugins/Portable/pmp_activesync/version.rc239
-rw-r--r--Src/Plugins/Portable/pmp_android/albumart.cpp58
-rw-r--r--Src/Plugins/Portable/pmp_android/androiddevice.cpp1869
-rw-r--r--Src/Plugins/Portable/pmp_android/androiddevice.h240
-rw-r--r--Src/Plugins/Portable/pmp_android/androidplaylist.cpp134
-rw-r--r--Src/Plugins/Portable/pmp_android/androidplaylist.h49
-rw-r--r--Src/Plugins/Portable/pmp_android/androidplaylistsaver.cpp74
-rw-r--r--Src/Plugins/Portable/pmp_android/androidplaylistsaver.h33
-rw-r--r--Src/Plugins/Portable/pmp_android/api.cpp64
-rw-r--r--Src/Plugins/Portable/pmp_android/api.h34
-rw-r--r--Src/Plugins/Portable/pmp_android/deviceprovider.cpp343
-rw-r--r--Src/Plugins/Portable/pmp_android/deviceprovider.h50
-rw-r--r--Src/Plugins/Portable/pmp_android/eject.cpp138
-rw-r--r--Src/Plugins/Portable/pmp_android/filecopy.cpp67
-rw-r--r--Src/Plugins/Portable/pmp_android/main.cpp601
-rw-r--r--Src/Plugins/Portable/pmp_android/pmp_android.rc209
-rw-r--r--Src/Plugins/Portable/pmp_android/pmp_android.sln130
-rw-r--r--Src/Plugins/Portable/pmp_android/pmp_android.vcxproj332
-rw-r--r--Src/Plugins/Portable/pmp_android/pmp_android.vcxproj.filters91
-rw-r--r--Src/Plugins/Portable/pmp_android/resource.h75
-rw-r--r--Src/Plugins/Portable/pmp_android/resources/androidIcon.pngbin0 -> 197 bytes
-rw-r--r--Src/Plugins/Portable/pmp_android/resources/generic_android.pngbin0 -> 5721 bytes
-rw-r--r--Src/Plugins/Portable/pmp_android/utils.cpp334
-rw-r--r--Src/Plugins/Portable/pmp_android/version.rc239
-rw-r--r--Src/Plugins/Portable/pmp_ipod/SysInfoXML.cpp149
-rw-r--r--Src/Plugins/Portable/pmp_ipod/api.h30
-rw-r--r--Src/Plugins/Portable/pmp_ipod/deviceprovider.cpp343
-rw-r--r--Src/Plugins/Portable/pmp_ipod/deviceprovider.h50
-rw-r--r--Src/Plugins/Portable/pmp_ipod/eject.cpp357
-rw-r--r--Src/Plugins/Portable/pmp_ipod/filecopy.cpp69
-rw-r--r--Src/Plugins/Portable/pmp_ipod/hash58.cpp154
-rw-r--r--Src/Plugins/Portable/pmp_ipod/hash58.h1
-rw-r--r--Src/Plugins/Portable/pmp_ipod/iPodArtworkDB.cpp914
-rw-r--r--Src/Plugins/Portable/pmp_ipod/iPodArtworkDB.h232
-rw-r--r--Src/Plugins/Portable/pmp_ipod/iPodDB.cpp4807
-rw-r--r--Src/Plugins/Portable/pmp_ipod/iPodDB.h1256
-rw-r--r--Src/Plugins/Portable/pmp_ipod/iPodDevice.cpp1795
-rw-r--r--Src/Plugins/Portable/pmp_ipod/iPodDevice.h142
-rw-r--r--Src/Plugins/Portable/pmp_ipod/iPodInfo.cpp1040
-rw-r--r--Src/Plugins/Portable/pmp_ipod/iPodInfo.h97
-rw-r--r--Src/Plugins/Portable/pmp_ipod/iPodSD.cpp523
-rw-r--r--Src/Plugins/Portable/pmp_ipod/iPodSD.h78
-rw-r--r--Src/Plugins/Portable/pmp_ipod/main.cpp336
-rw-r--r--Src/Plugins/Portable/pmp_ipod/pmp_ipod.rc194
-rw-r--r--Src/Plugins/Portable/pmp_ipod/pmp_ipod.sln75
-rw-r--r--Src/Plugins/Portable/pmp_ipod/pmp_ipod.vcxproj355
-rw-r--r--Src/Plugins/Portable/pmp_ipod/pmp_ipod.vcxproj.filters113
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resource.h71
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_classic.pngbin0 -> 3464 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_classic_16.pngbin0 -> 199 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_1g.pngbin0 -> 1991 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_1g_16.pngbin0 -> 192 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_2g.pngbin0 -> 1861 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_2g_16.pngbin0 -> 195 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_3g.pngbin0 -> 2128 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_3g_16.pngbin0 -> 186 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_4g.pngbin0 -> 2513 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_4g_16.pngbin0 -> 193 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_5g.pngbin0 -> 1939 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_5g_16.pngbin0 -> 187 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_1g.pngbin0 -> 1781 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_1g_16.pngbin0 -> 182 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_2g.pngbin0 -> 1117 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_2g_16.pngbin0 -> 230 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_3g.pngbin0 -> 1345 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_3g_16.pngbin0 -> 119 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_4g.pngbin0 -> 1964 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_4g_16.pngbin0 -> 233 bytes
-rw-r--r--Src/Plugins/Portable/pmp_ipod/sha1.c240
-rw-r--r--Src/Plugins/Portable/pmp_ipod/sha1.h9
-rw-r--r--Src/Plugins/Portable/pmp_ipod/version.rc239
-rw-r--r--Src/Plugins/Portable/pmp_ipod/yail.cpp114
-rw-r--r--Src/Plugins/Portable/pmp_ipod/yail.h25
-rw-r--r--Src/Plugins/Portable/pmp_njb/NJBDevice.cpp714
-rw-r--r--Src/Plugins/Portable/pmp_njb/NJBDevice.h168
-rw-r--r--Src/Plugins/Portable/pmp_njb/NOMAD DAP PC SDK v3_5.pdfbin0 -> 1469440 bytes
-rw-r--r--Src/Plugins/Portable/pmp_njb/Nmsdk.h922
-rw-r--r--Src/Plugins/Portable/pmp_njb/ctnmjb2.dllbin0 -> 126976 bytes
-rw-r--r--Src/Plugins/Portable/pmp_njb/main.cpp181
-rw-r--r--Src/Plugins/Portable/pmp_njb/pmp_njb.rc109
-rw-r--r--Src/Plugins/Portable/pmp_njb/pmp_njb.sln30
-rw-r--r--Src/Plugins/Portable/pmp_njb/pmp_njb.vcxproj315
-rw-r--r--Src/Plugins/Portable/pmp_njb/pmp_njb.vcxproj.filters61
-rw-r--r--Src/Plugins/Portable/pmp_njb/resource.h23
-rw-r--r--Src/Plugins/Portable/pmp_njb/resources/zenIcon.pngbin0 -> 238 bytes
-rw-r--r--Src/Plugins/Portable/pmp_njb/version.rc239
-rw-r--r--Src/Plugins/Portable/pmp_p4s/Cert.zipbin0 -> 6499 bytes
-rw-r--r--Src/Plugins/Portable/pmp_p4s/MTP Error Codes.txt41
-rw-r--r--Src/Plugins/Portable/pmp_p4s/MyProgress.cpp95
-rw-r--r--Src/Plugins/Portable/pmp_p4s/MyProgress.h35
-rw-r--r--Src/Plugins/Portable/pmp_p4s/P4SDevice.cpp2185
-rw-r--r--Src/Plugins/Portable/pmp_p4s/P4SDevice.h243
-rw-r--r--Src/Plugins/Portable/pmp_p4s/WMDRMDeviceApp.h502
-rw-r--r--Src/Plugins/Portable/pmp_p4s/WMDRMDeviceApp_i.c93
-rw-r--r--Src/Plugins/Portable/pmp_p4s/deviceprovider.cpp285
-rw-r--r--Src/Plugins/Portable/pmp_p4s/deviceprovider.h49
-rw-r--r--Src/Plugins/Portable/pmp_p4s/key-sub-523.c531
-rw-r--r--Src/Plugins/Portable/pmp_p4s/main.cpp571
-rw-r--r--Src/Plugins/Portable/pmp_p4s/mssachlp.libbin0 -> 3800538 bytes
-rw-r--r--Src/Plugins/Portable/pmp_p4s/mswmdm.h9913
-rw-r--r--Src/Plugins/Portable/pmp_p4s/mswmdm_i.c269
-rw-r--r--Src/Plugins/Portable/pmp_p4s/pmp_p4s.rc91
-rw-r--r--Src/Plugins/Portable/pmp_p4s/pmp_p4s.vcxproj434
-rw-r--r--Src/Plugins/Portable/pmp_p4s/pmp_p4s.vcxproj.filters93
-rw-r--r--Src/Plugins/Portable/pmp_p4s/resource1.h31
-rw-r--r--Src/Plugins/Portable/pmp_p4s/resources/creativeZenIcon.pngbin0 -> 238 bytes
-rw-r--r--Src/Plugins/Portable/pmp_p4s/resources/nokiaIcon.pngbin0 -> 226 bytes
-rw-r--r--Src/Plugins/Portable/pmp_p4s/sac.h26
-rw-r--r--Src/Plugins/Portable/pmp_p4s/scclient.h73
-rw-r--r--Src/Plugins/Portable/pmp_p4s/sehupd.libbin0 -> 37298 bytes
-rw-r--r--Src/Plugins/Portable/pmp_p4s/version.rc239
-rw-r--r--Src/Plugins/Portable/pmp_p4s/wmdm.chmbin0 -> 857488 bytes
-rw-r--r--Src/Plugins/Portable/pmp_usb/albumart.cpp58
-rw-r--r--Src/Plugins/Portable/pmp_usb/api.cpp64
-rw-r--r--Src/Plugins/Portable/pmp_usb/api.h34
-rw-r--r--Src/Plugins/Portable/pmp_usb/deviceprovider.cpp343
-rw-r--r--Src/Plugins/Portable/pmp_usb/deviceprovider.h51
-rw-r--r--Src/Plugins/Portable/pmp_usb/eject.cpp135
-rw-r--r--Src/Plugins/Portable/pmp_usb/filecopy.cpp67
-rw-r--r--Src/Plugins/Portable/pmp_usb/main.cpp547
-rw-r--r--Src/Plugins/Portable/pmp_usb/pmp_usb2.rc209
-rw-r--r--Src/Plugins/Portable/pmp_usb/pmp_usb2.sln129
-rw-r--r--Src/Plugins/Portable/pmp_usb/pmp_usb2.vcxproj340
-rw-r--r--Src/Plugins/Portable/pmp_usb/pmp_usb2.vcxproj.filters89
-rw-r--r--Src/Plugins/Portable/pmp_usb/resource.h75
-rw-r--r--Src/Plugins/Portable/pmp_usb/resources/pspIcon.pngbin0 -> 216 bytes
-rw-r--r--Src/Plugins/Portable/pmp_usb/resources/usbIcon.pngbin0 -> 200 bytes
-rw-r--r--Src/Plugins/Portable/pmp_usb/usbdevice.cpp1913
-rw-r--r--Src/Plugins/Portable/pmp_usb/usbdevice.h242
-rw-r--r--Src/Plugins/Portable/pmp_usb/usbplaylist.cpp33
-rw-r--r--Src/Plugins/Portable/pmp_usb/usbplaylist.h35
-rw-r--r--Src/Plugins/Portable/pmp_usb/usbplaylistsaver.cpp74
-rw-r--r--Src/Plugins/Portable/pmp_usb/usbplaylistsaver.h31
-rw-r--r--Src/Plugins/Portable/pmp_usb/utils.cpp355
-rw-r--r--Src/Plugins/Portable/pmp_usb/version.rc239
-rw-r--r--Src/Plugins/Portable/pmp_wifi/ConnectActivity.cpp53
-rw-r--r--Src/Plugins/Portable/pmp_wifi/ConnectActivity.h16
-rw-r--r--Src/Plugins/Portable/pmp_wifi/InfoDownloader.cpp201
-rw-r--r--Src/Plugins/Portable/pmp_wifi/InfoDownloader.h51
-rw-r--r--Src/Plugins/Portable/pmp_wifi/ListenServer.cpp147
-rw-r--r--Src/Plugins/Portable/pmp_wifi/Pair.cpp87
-rw-r--r--Src/Plugins/Portable/pmp_wifi/Pair.h25
-rw-r--r--Src/Plugins/Portable/pmp_wifi/PlaylistSync.cpp150
-rw-r--r--Src/Plugins/Portable/pmp_wifi/PlaylistSync.h9
-rw-r--r--Src/Plugins/Portable/pmp_wifi/RenameDownloader.cpp39
-rw-r--r--Src/Plugins/Portable/pmp_wifi/RenameDownloader.h3
-rw-r--r--Src/Plugins/Portable/pmp_wifi/SongDownloader.cpp88
-rw-r--r--Src/Plugins/Portable/pmp_wifi/SongDownloader.h24
-rw-r--r--Src/Plugins/Portable/pmp_wifi/SongListDownloader.cpp178
-rw-r--r--Src/Plugins/Portable/pmp_wifi/SongListDownloader.h58
-rw-r--r--Src/Plugins/Portable/pmp_wifi/WifiDevice.cpp269
-rw-r--r--Src/Plugins/Portable/pmp_wifi/WifiDevice.h64
-rw-r--r--Src/Plugins/Portable/pmp_wifi/WifiPlaylist.cpp104
-rw-r--r--Src/Plugins/Portable/pmp_wifi/WifiPlaylist.h36
-rw-r--r--Src/Plugins/Portable/pmp_wifi/XMLString.cpp49
-rw-r--r--Src/Plugins/Portable/pmp_wifi/XMLString.h28
-rw-r--r--Src/Plugins/Portable/pmp_wifi/api.cpp72
-rw-r--r--Src/Plugins/Portable/pmp_wifi/api.h44
-rw-r--r--Src/Plugins/Portable/pmp_wifi/device.cpp797
-rw-r--r--Src/Plugins/Portable/pmp_wifi/device.h127
-rw-r--r--Src/Plugins/Portable/pmp_wifi/images.cpp72
-rw-r--r--Src/Plugins/Portable/pmp_wifi/images.h5
-rw-r--r--Src/Plugins/Portable/pmp_wifi/main.cpp263
-rw-r--r--Src/Plugins/Portable/pmp_wifi/main.h30
-rw-r--r--Src/Plugins/Portable/pmp_wifi/modelInfo.cpp168
-rw-r--r--Src/Plugins/Portable/pmp_wifi/modelInfo.h22
-rw-r--r--Src/Plugins/Portable/pmp_wifi/pmp_wifi.rc126
-rw-r--r--Src/Plugins/Portable/pmp_wifi/pmp_wifi.sln83
-rw-r--r--Src/Plugins/Portable/pmp_wifi/pmp_wifi.vcxproj341
-rw-r--r--Src/Plugins/Portable/pmp_wifi/pmp_wifi.vcxproj.filters214
-rw-r--r--Src/Plugins/Portable/pmp_wifi/post.cpp518
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resource.h65
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/attach.pngbin0 -> 788 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/attach16.pngbin0 -> 239 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/generic_android.pngbin0 -> 5721 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/generic_drive_wifi_16.pngbin0 -> 242 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/htc_desire_passion_bravo.pngbin0 -> 4177 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/htc_desire_passion_bravo_16.pngbin0 -> 162 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/htc_evo_4g.pngbin0 -> 2305 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/htc_evo_4g_16.pngbin0 -> 159 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/htc_hd2.pngbin0 -> 1861 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/htc_hd2_16.pngbin0 -> 162 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/htc_incredible.pngbin0 -> 2484 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/htc_incredible_16.pngbin0 -> 182 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/htc_nexus_one_16.pngbin0 -> 164 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/motorola_droid.pngbin0 -> 2662 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/motorola_droid_16.pngbin0 -> 156 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/motorola_droid_x.pngbin0 -> 2319 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/motorola_droid_x_16.pngbin0 -> 169 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/nexus_one.pngbin0 -> 4053 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/resources/wifi.pngbin0 -> 599 bytes
-rw-r--r--Src/Plugins/Portable/pmp_wifi/version.rc239
207 files changed, 52250 insertions, 0 deletions
diff --git a/Src/Plugins/Portable/pmp_activesync/ASDevice.cpp b/Src/Plugins/Portable/pmp_activesync/ASDevice.cpp
new file mode 100644
index 00000000..42d6ccfd
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/ASDevice.cpp
@@ -0,0 +1,798 @@
+#include "ASDevice.h"
+#include <vector>
+
+static void removebadchars(wchar_t *s) {
+ while (s && *s)
+ {
+ if (*s == L'?' || *s == L'/' || *s == L'\\' || *s == L':' || *s == L'*' || *s == L'\"' || *s == L'<' || *s == L'>' || *s == L'|')
+ *s = L'_';
+ s = CharNextW(s);
+ }
+}
+
+Playlist::Playlist(const wchar_t * path, LPCE_FIND_DATA f) {
+ _snwprintf(fn,MAX_PATH,L"%s\\%s",path,f->cFileName);
+ wchar_t * ext = wcsrchr(f->cFileName,L'.');
+ if(ext) *ext=0;
+ lstrcpyn(name,f->cFileName,fieldlen);
+}
+
+Playlist::Playlist(const wchar_t * name0) {
+ lstrcpyn(name,name0,fieldlen);
+ fn[0]=0;
+}
+
+#define ASSIGNLARGE(r,h,l) {ULARGE_INTEGER li; li.HighPart = h; li.LowPart = l; r=li.QuadPart;}
+
+Song::Song(const wchar_t * path0, LPCE_FIND_DATA f, bool video) : track(-1), video(video) {
+ artist[0]=album[0]=title[0]=fn[0]=0;
+
+ ASSIGNLARGE(size,f->nFileSizeHigh,f->nFileSizeLow);
+ // first, fill in artist and album
+ wchar_t *path = _wcsdup(path0);
+ wchar_t *a = wcsrchr(path,L'\\');
+ if(a && a-1 != path) {
+ lstrcpyn(album,a+1,fieldlen);
+ *a=0;
+ a = wcsrchr(path,L'\\');
+ if(a && a-1 != path) lstrcpyn(artist,a+1,fieldlen);
+ }
+ // now parse out the title
+ _snwprintf(fn,MAX_PATH,L"%s\\%s",path0,f->cFileName);
+ wchar_t * ext = wcsrchr(f->cFileName,L'.');
+ if(ext) *ext=0;
+ wchar_t * p = f->cFileName;
+ if(memcmp(artist,p,wcslen(artist)*sizeof(wchar_t))==0) p+=wcslen(artist);
+ while(p && *p && (*p==L'.' || *p==L'_' || *p==L'-' || *p==L' ')) p++;
+ track = wcstoul(p,&p,10);
+ while(p && *p && (*p==L'.' || *p==L'_' || *p==L'-' || *p==L' ')) p++;
+ lstrcpyn(title,p,fieldlen);
+ if(title[0]==0) lstrcpyn(title,f->cFileName,fieldlen);
+ free(path);
+}
+
+Song::Song() : video(false) {}
+
+void ASDevice::Find(const wchar_t * path) {
+ wchar_t fpath[MAX_PATH] = {0};
+ wsprintf(fpath,L"%s\\*",path);
+ CE_FIND_DATA f = {0};
+ HANDLE h = pISession->CeFindFirstFile(fpath,&f);
+ if(h == INVALID_HANDLE_VALUE) return;
+ do {
+ if(f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ wchar_t path2[MAX_PATH] = {0};
+ wsprintf(path2,L"%s\\%s",path,f.cFileName);
+ Find(path2);
+ }
+ else FoundFile(path,&f);
+ } while(pISession->CeFindNextFile(h,&f));
+ pISession->CeFindClose(h);
+}
+
+void ASDevice::FoundFile(const wchar_t * path, LPCE_FIND_DATA f) {
+ wchar_t * ext = wcsrchr(f->cFileName,L'.');
+ if(!_wcsicmp(ext,L".mp3") || !_wcsicmp(ext,L".wma"))
+ playlists[0]->songs.push_back(new Song(path,f,false));
+ if(!_wcsicmp(ext,L".avi") || !_wcsicmp(ext,L".wmv") || !_wcsicmp(ext,L".asf") || !_wcsicmp(ext,L".mpg") || !_wcsicmp(ext,L".mpeg"))
+ playlists[0]->songs.push_back(new Song(path,f,true));
+ else if(!_wcsicmp(ext,L".asx"))
+ playlists.push_back(new Playlist(path,f));
+}
+
+void fixTagsForXML(wchar_t* dest, const wchar_t *cstr, const int len)
+{
+ int tindex = 0;
+ wchar_t *temp = (wchar_t*)calloc(len, sizeof(wchar_t));
+ for(int i=0;i<len && tindex<len;i++)
+ {
+ switch(cstr[i])
+ {
+ case(L'&'):
+ if(tindex < len-5)
+ {
+ temp[tindex++] = '&';
+ temp[tindex++] = 'a';
+ temp[tindex++] = 'm';
+ temp[tindex++] = 'p';
+ temp[tindex] = ';';
+ }
+ else temp[tindex] = ' '; //no room
+ break;
+ case(L'<'):
+ {
+ if(tindex < len-4)
+ {
+ temp[tindex++] = '&';
+ temp[tindex++] = 'l';
+ temp[tindex++] = 't';
+ temp[tindex] = ';';
+ }
+ else temp[tindex] = ' '; //no room
+ break;
+ }
+ case(L'>'):
+ {
+ if(tindex < len-4)
+ {
+ temp[tindex++] = '&';
+ temp[tindex++] = 'g';
+ temp[tindex++] = 't';
+ temp[tindex] = ';';
+ }
+ else temp[tindex] = ' '; //no room
+ break;
+ }
+ case(L'\"'):
+ {
+ if(tindex < len-4)
+ {
+ temp[tindex++] = '&';
+ temp[tindex++] = 'q';
+ temp[tindex++] = 'u';
+ temp[tindex++] = 'o';
+ temp[tindex++] = 't';
+ temp[tindex] = ';';
+ }
+ else temp[tindex] = ' '; //no room
+ break;
+ }
+ case(L'\''):
+ {
+ if(tindex < len-4)
+ {
+ temp[tindex++] = '&';
+ temp[tindex++] = 'a';
+ temp[tindex++] = 'p';
+ temp[tindex++] = 'o';
+ temp[tindex++] = 's';
+ temp[tindex] = ';';
+ }
+ else temp[tindex] = ' '; //no room
+ break;
+ }
+ default:
+ {
+ temp[tindex] = cstr[i];
+ break;
+ }
+ }
+ if(cstr[i] == 0) break;
+ tindex++;
+ }
+ wcsncpy(dest, temp, len);
+ free(temp);
+}
+
+void ASDevice::WritePlaylist(Playlist * pl) {
+#define CePutws(x,h) pISession->CeWriteFile(h,x,(DWORD)wcslen(x)*sizeof(wchar_t),&w,NULL)
+#define CePuts(x,h) pISession->CeWriteFile(h,x,(DWORD)strlen(x)*sizeof(char),&w,NULL)
+ HANDLE h = pISession->CeCreateFile(pl->fn,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,TRUNCATE_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
+ if(h == INVALID_HANDLE_VALUE) return;
+ std::vector<Song*> *songs = &pl->songs;
+ int l=(int)songs->size();
+ DWORD w;
+ CePuts("<asx version=\"3.0\">\r\n",h);
+ for(int j=0; j<l; j++) {
+ CePuts("<entry><ref href=\"",h);
+ wchar_t safe[fieldlen*2] = {0};
+ fixTagsForXML(safe,songs->at(j)->fn,sizeof(safe)/sizeof(wchar_t));
+ AutoChar fn(safe);
+ CePuts(fn,h);
+ CePuts("\"/></entry>\r\n",h);
+ }
+ CePuts("</asx>",h);
+ pISession->CeCloseHandle(h);
+#undef CePutws
+#undef CePuts
+}
+
+struct mplSearch { bool operator()(Song*& a,Song*& b) { return _wcsicmp(a->fn,b->fn)<0; } };
+struct mplSearch2 { bool operator()(Song*& a,Song* b) { return _wcsicmp(a->fn,b->fn)<0; } };
+
+waServiceFactory *parserFactory;
+
+class plread : public ifc_xmlreadercallback {
+public:
+ Playlist * pl;
+ Playlist * mpl;
+ plread(Playlist * pl,Playlist * mpl) : pl(pl),mpl(mpl) {}
+ void StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) {
+ if(!wcscmp(xmlpath,L"ASX\fENTRY\fREF")) {
+ const wchar_t* path = params->getItemValue(L"HREF");
+ int l= (int)mpl->songs.size();
+ Song s;
+ lstrcpyn(s.fn,path,MAX_PATH);
+ std::vector<Song*>::iterator p = std::lower_bound(mpl->songs.begin(),mpl->songs.end(),&s,mplSearch2());
+ int f = (int)(p - mpl->songs.begin());
+ if(f >= 0 && f < (int)mpl->songs.size()) {
+ Song * found = mpl->songs[f];
+ if(!_wcsicmp(found->fn,s.fn)) pl->songs.push_back(found);
+ }
+ }
+ }
+ RECVS_DISPATCH;
+};
+
+#define CBCLASS plread
+START_DISPATCH;
+VCB(ONSTARTELEMENT, StartTag)
+END_DISPATCH;
+#undef CBCLASS
+
+void ASDevice::ReadPlaylist(Playlist * pl) {
+ if(!parserFactory) return;
+ obj_xml * parser = (obj_xml *)parserFactory->getInterface();
+ if(!parser) return;
+ HANDLE h = pISession->CeCreateFile(pl->fn,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
+ if(h == INVALID_HANDLE_VALUE) { parserFactory->releaseInterface(parser); return; }
+
+ plread cb(pl,playlists[0]);
+ parser->xmlreader_open();
+ parser->xmlreader_registerCallback(L"ASX\fENTRY\f*",&cb);
+
+ for(;;) {
+ char buf[32768] = {0};
+ DWORD read = 0;
+ pISession->CeReadFile(h,buf,sizeof(buf),&read,NULL);
+ if(read == 0) break;
+ parser->xmlreader_feed(buf,read);
+ }
+
+ parserFactory->releaseInterface(parser);
+ pISession->CeCloseHandle(h);
+}
+
+static void findStorageCard(IRAPISession *pISession,wchar_t *storageCard) {
+ ULARGE_INTEGER fa={0},rootTotal={0},ft={0};
+ pISession->CeGetDiskFreeSpaceEx(L"\\",&fa,&rootTotal,&ft);
+
+ wchar_t *fpath = L"\\*";
+ CE_FIND_DATA f;
+ HANDLE h = pISession->CeFindFirstFile(fpath,&f);
+ if(h == INVALID_HANDLE_VALUE) return;
+ do {
+ if(f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY/* && wcscmp(f.cFileName,L"Storage Card")*/) {
+ ULARGE_INTEGER folderTotal={0};
+ wchar_t path[MAX_PATH] = L"\\";
+ wcscat(path,f.cFileName);
+ pISession->CeGetDiskFreeSpaceEx(path,&fa,&folderTotal,&ft);
+ if(folderTotal.QuadPart > rootTotal.QuadPart) {
+ rootTotal = folderTotal;
+ wcsncpy(storageCard,path,MAX_PATH);
+ }
+ }
+ } while(pISession->CeFindNextFile(h,&f));
+ pISession->CeFindClose(h);
+}
+
+ASDevice::ASDevice(IRAPIDevice *pIDevice,IRAPISession *pISession) : pIDevice(pIDevice), pISession(pISession), transferQueueSize(0) {
+ pIDevice->AddRef();
+ pIDevice->GetDeviceInfo(&devInfo);
+
+ pmpDeviceLoading load={this,0};
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)&load,PMP_IPC_DEVICELOADING);
+ if(load.UpdateCaption) {
+ wchar_t buf[200]=L"";
+ wsprintf(buf,WASABI_API_LNGSTRINGW(IDS_LOADING),devInfo.bstrName);
+ load.UpdateCaption(buf,load.context);
+ }
+
+ //find where playlists and music are stored...
+ wchar_t storageCard[MAX_PATH]=L"";
+ findStorageCard(pISession,storageCard);
+ wsprintf(musicFolder,L"%s\\Music",storageCard);
+ wsprintf(videoFolder,L"%s\\My Documents\\My Videos",storageCard);
+ wsprintf(playlistFolder,L"%s\\Playlists",storageCard);
+ wcsncpy(playlistFormat,L".asx",16);
+ // default values found. Fill in real values
+ {
+ wchar_t inifile[MAX_PATH] = {0};
+ const char * iniDirectory = (const char*)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETINIDIRECTORY);
+ wchar_t name[256] = {0};
+ lstrcpyn(name,devInfo.bstrName,256);
+ removebadchars(name);
+ wsprintf(inifile,L"%s\\Plugins\\ml\\ml_pmp_device_%s.ini",(wchar_t*)AutoWide(iniDirectory),name);
+ wchar_t * def = _wcsdup(musicFolder);
+ GetPrivateProfileString(L"pmp_activesync",L"musicfolder",def,musicFolder,MAX_PATH,inifile);
+ free(def); def = _wcsdup(videoFolder);
+ GetPrivateProfileString(L"pmp_activesync",L"videofolder",def,videoFolder,MAX_PATH,inifile);
+ free(def); def = _wcsdup(playlistFolder);
+ GetPrivateProfileString(L"pmp_activesync",L"playlistfolder",def,playlistFolder,MAX_PATH,inifile);
+ free(def);
+ }
+
+ playlists.push_back(new Playlist(devInfo.bstrName));
+
+ Find(musicFolder);
+ Find(videoFolder);
+ Find(playlistFolder);
+
+ std::sort(playlists[0]->songs.begin(),playlists[0]->songs.end(),mplSearch());
+ parserFactory = plugin.service->service_getServiceByGuid(obj_xmlGUID);
+
+ for(unsigned int i=1; i<playlists.size(); i++)
+ ReadPlaylist(playlists[i]);
+
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICECONNECTED);
+ transcoder = (Transcoder*)SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_GET_TRANSCODER);
+
+ transcoder->AddAcceptableFormat(L"mp3");
+ transcoder->AddAcceptableFormat(L"wma");
+ transcoder->AddAcceptableFormat(L"wmv");
+ transcoder->AddAcceptableFormat(L"avi");
+ transcoder->AddAcceptableFormat(L"asf");
+ transcoder->AddAcceptableFormat(L"mpeg");
+ transcoder->AddAcceptableFormat(L"mpg");
+}
+
+ASDevice::~ASDevice()
+{
+ Playlist *mpl = playlists[ 0 ];
+ unsigned int l = (unsigned int)mpl->songs.size();
+ for ( unsigned int i = 0; i < l; i++ )
+ {
+ delete mpl->songs[ i ];
+ }
+ for ( unsigned int j = 0; j < playlists.size(); j++ )
+ {
+ delete playlists[ j ];
+ }
+ for ( int k = 0; k < devices.size(); k++ )
+ {
+ if ( devices[ k ] == this )
+ {
+ devices.erase( devices.begin() + k );
+ k--;
+ }
+ }
+ pIDevice->Release();
+ pISession->Release();
+ SysFreeString( devInfo.bstrName );
+ SysFreeString( devInfo.bstrPlatform );
+ SendMessage( plugin.hwndPortablesParent, WM_PMP_IPC, (WPARAM)transcoder, PMP_IPC_RELEASE_TRANSCODER );
+}
+
+__int64 ASDevice::getDeviceCapacityAvailable() {
+ if(devInfo.dwOsVersionMajor >= 5) {
+ ULARGE_INTEGER fa={0},t={0},ft={0};
+ pISession->CeGetDiskFreeSpaceEx(musicFolder,&fa,&t,&ft);
+ return fa.QuadPart;
+ } else {
+ STORE_INFORMATION s;
+ pISession->CeGetStoreInformation(&s);
+ return s.dwFreeSize;
+ }
+}
+
+__int64 ASDevice::getDeviceCapacityTotal() {
+ if(devInfo.dwOsVersionMajor >= 5) {
+ ULARGE_INTEGER fa={0},t={0},ft={0};
+ pISession->CeGetDiskFreeSpaceEx(musicFolder,&fa,&t,&ft);
+ return t.QuadPart;
+ } else {
+ STORE_INFORMATION s;
+ pISession->CeGetStoreInformation(&s);
+ return s.dwStoreSize;
+ }
+}
+
+void ASDevice::Eject() {
+ ejectedDevice *e = (ejectedDevice *)calloc(1, sizeof(ejectedDevice));
+ e->id = devInfo.DeviceId;
+ e->marked = true;
+ ejected.push_back(e);
+ Close();
+}
+
+void ASDevice::Close() {
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
+ delete this;
+}
+
+int ASDevice::transferTrackToDevice(const itemRecordW * track,void * callbackContext,void (*callback)(void * callbackContext, wchar_t * status),songid_t * songid,int * killswitch) {
+ wchar_t ext[10]={0};
+ wchar_t file[2048]={0};
+ wcsncpy(file,track->filename,2048);
+ {wchar_t * e = wcsrchr(file,L'.'); if(e) wcsncpy(ext,e+1,10);}
+
+ bool deletefile = false;
+ if(transcoder->ShouldTranscode(file)) {
+ wchar_t newfile[MAX_PATH] = {0};
+ transcoder->CanTranscode(file,ext);
+ transcoder->GetTempFilePath(ext,newfile);
+ if(transcoder->TranscodeFile(file,newfile,killswitch,callback,callbackContext)) return -1;
+ wcsncpy(file,newfile,2048);
+ deletefile=true;
+ }
+
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_TRANSFERRING));
+
+ bool video = !_wcsicmp(ext,L"wmv") || !_wcsicmp(ext,L"avi");
+
+ int len = (int)(wcslen(musicFolder)+wcslen(track->artist)+wcslen(track->album)+wcslen(track->title)+100);
+ wchar_t *path = (wchar_t*)calloc(len, sizeof(wchar_t));
+ wchar_t *artist = _wcsdup(track->artist);
+ wchar_t *album = _wcsdup(track->album);
+ wchar_t *title = _wcsdup(track->title);
+ removebadchars(artist);
+ removebadchars(album);
+ removebadchars(title);
+ if(video) {
+ wcsncpy(path,videoFolder,len);
+ pISession->CeCreateDirectory(path,NULL);
+ wsprintf(path+wcslen(path),L"\\%s - %s.%s",artist,title,ext);
+ } else {
+ wcsncpy(path,musicFolder,len);
+ pISession->CeCreateDirectory(path,NULL);
+ wcscat(path,L"\\");
+ wcscat(path,artist);
+ pISession->CeCreateDirectory(path,NULL);
+ wcscat(path,L"\\");
+ wcscat(path,album);
+ pISession->CeCreateDirectory(path,NULL);
+ wsprintf(path+wcslen(path),L"\\%02d - %s.%s",track->track,title,ext);
+ }
+ free(artist); free(album); free(title);
+
+ FILE *f = _wfopen(file,L"rb");
+ if(!f) { callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_CANNOT_OPEN_LOCAL_FILE)); return -1; }
+ HANDLE h = pISession->CeCreateFile(path,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
+ if(h == INVALID_HANDLE_VALUE) {
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_CANNOT_OPEN_FILE_ON_DEVICE));
+ fclose(f);
+ return -1;
+ }
+
+ fseek(f,0,2);
+ int error=0;
+ int size = ftell(f);
+ int pc = size/100;
+ fseek(f,0,0);
+ int written=0,lastupdate=0;
+ for(;;) {
+ char buf[32768] = {0};
+ int l = (int)fread(buf,1,sizeof(buf),f);
+ if(!l) break;
+ DWORD wl=0;
+ pISession->CeWriteFile(h,buf,l,&wl,NULL);
+ if(wl != l) {
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_ERROR_WRITING_FILE));
+ error=1;
+ break;
+ }
+ written += l;
+ if(written - lastupdate > pc) {
+ lastupdate = written;
+ wchar_t buf[100] = {0};
+ wsprintf(buf,WASABI_API_LNGSTRINGW(IDS_TRANSFERRING_PERCENT),written/(size/100));
+ callback(callbackContext,buf);
+ }
+ }
+
+ fclose(f);
+ pISession->CeCloseHandle(h);
+ if(deletefile) _wunlink(file);
+ if(!error) {
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_DONE));
+ Song * s = new Song;
+ lstrcpyn(s->fn,path,MAX_PATH);
+ lstrcpyn(s->album,track->album,fieldlen);
+ lstrcpyn(s->artist,track->artist,fieldlen);
+ lstrcpyn(s->title,track->title,fieldlen);
+ s->track = track->track;
+ s->size = size;
+ s->video = video;
+ *songid = (songid_t)s;
+ }
+ free(path);
+ return error?-1:0;
+}
+
+static __int64 fileSize(wchar_t * filename)
+{
+ WIN32_FIND_DATA f={0};
+ HANDLE h = FindFirstFileW(filename,&f);
+ if(h == INVALID_HANDLE_VALUE) return -1;
+ FindClose(h);
+ ULARGE_INTEGER i;
+ i.HighPart = f.nFileSizeHigh;
+ i.LowPart = f.nFileSizeLow;
+ return i.QuadPart;
+}
+
+static bool extentionSupported(wchar_t * ext) {
+ if(!ext) return false;
+ bool supported=false;
+ if(!_wcsicmp(ext,L".mp3") || !_wcsicmp(ext,L".wma")) supported=true;
+ if(!_wcsicmp(ext,L".avi") || !_wcsicmp(ext,L".wmv")) supported=true;
+ return supported;
+}
+
+int ASDevice::trackAddedToTransferQueue(const itemRecordW * track) {
+ __int64 s = getTrackSizeOnDevice(track);
+ if(!s) return -2;
+ __int64 avail = getDeviceCapacityAvailable();
+ __int64 cmp = transferQueueSize;
+ cmp += s;
+ if(cmp > avail) return -1;
+ else {
+ transferQueueSize += s;
+ return 0;
+ }
+}
+
+void ASDevice::trackRemovedFromTransferQueue(const itemRecordW * track) {
+ transferQueueSize -= getTrackSizeOnDevice(track);
+}
+
+__int64 ASDevice::getTrackSizeOnDevice(const itemRecordW * track) {
+ if(transcoder->ShouldTranscode(track->filename)) {
+ int k = transcoder->CanTranscode(track->filename);
+ if(k != -1 && k != 0) return k;
+ }
+ wchar_t * ext = wcsrchr(track->filename,L'.');
+ if(!extentionSupported(ext)) return 0;
+ return fileSize(track->filename);
+}
+
+void ASDevice::deleteTrack(songid_t songid) {
+ Song * song = (Song*)songid;
+ if(!pISession->CeDeleteFile(song->fn)) return;
+ for(unsigned int i=0; i<playlists.size(); i++)
+ {
+ unsigned int l = (unsigned int)playlists[i]->songs.size();
+ for(int j=0; j<l; j++)
+ {
+ if(playlists[i]->songs[j] == song)
+ {
+ playlists[i]->songs.erase(playlists[i]->songs.begin() + j);
+ j--;
+ l--;
+ playlists[i]->dirty=true;
+ }
+ }
+ }
+ delete song;
+}
+
+void ASDevice::commitChanges() {
+ for(unsigned int i=1; i<playlists.size(); i++) if(playlists[i]->dirty) { WritePlaylist(playlists[i]); playlists[i]->dirty=false; }
+}
+
+int ASDevice::getPlaylistCount() { return (int)playlists.size(); }
+void ASDevice::getPlaylistName(int playlistnumber, wchar_t * buf, int len) { lstrcpyn(buf,playlists[playlistnumber]->name,len); }
+int ASDevice::getPlaylistLength(int playlistnumber) { return (int)playlists[playlistnumber]->songs.size(); }
+songid_t ASDevice::getPlaylistTrack(int playlistnumber,int songnum) { return (songid_t)playlists[playlistnumber]->songs[songnum]; }
+
+void ASDevice::setPlaylistName(int playlistnumber, const wchar_t * buf) {
+ Playlist * pl = playlists[playlistnumber];
+ lstrcpyn(pl->name,buf,fieldlen);
+ wchar_t * oldname = _wcsdup(pl->fn);
+ wchar_t * name = _wcsdup(buf);
+ removebadchars(name);
+ wsprintf(pl->fn,L"%s\\%s.%s",playlistFolder,name,playlistFormat);
+ free(name);
+ pISession->CeMoveFile(oldname,pl->fn);
+ free(oldname);
+}
+
+void ASDevice::playlistSwapItems(int playlistnumber, int posA, int posB) {
+ std::vector<Song*> &songs = playlists[playlistnumber]->songs;
+ Song * a = songs[posA];
+ Song * b = songs[posB];
+ songs[posA] = b;
+ songs[posB] = a;
+ playlists[playlistnumber]->dirty=true;
+}
+
+#define CMPFIELDS(x) { int v = lstrcmpi(a->x,b->x); if(v) return v<0; }
+#define CMPINTFIELDS(x) { int v = a->x-b->x; if(v) return v<0; }
+
+typedef struct PlaylistItemSort {
+ int use_by;
+ bool operator()(Song*& a,Song*& b) {
+ int x;
+ for (x = 0; x < 4; x ++)
+ {
+ if (use_by == SORTBY_TITLE) // title -> artist -> album -> disc -> track
+ {
+ CMPFIELDS(title);
+ use_by=SORTBY_ARTIST;
+ }
+ else if (use_by == SORTBY_ARTIST) // artist -> album -> disc -> track -> title
+ {
+ CMPFIELDS(artist);
+ use_by=SORTBY_ALBUM;
+ }
+ else if (use_by == SORTBY_ALBUM) // album -> disc -> track -> title -> artist
+ {
+ CMPFIELDS(album);
+ use_by=SORTBY_TRACKNUM;
+ }
+ else if (use_by == SORTBY_TRACKNUM) // track -> title -> artist -> album -> disc
+ {
+ CMPINTFIELDS(track);
+ use_by=SORTBY_TITLE;
+ }
+ else break; // no sort order?
+ }
+ return false;
+ }
+} PlaylistItemSort;
+#undef CMPFIELDS
+#undef CMPINTFIELDS
+
+void ASDevice::sortPlaylist(int playlistnumber, int sortBy) {
+ PlaylistItemSort sort;
+ sort.use_by = sortBy;
+ std::sort(playlists[playlistnumber]->songs.begin(),playlists[playlistnumber]->songs.end(),sort);
+ playlists[playlistnumber]->dirty=true;
+}
+
+void ASDevice::addTrackToPlaylist(int playlistnumber, songid_t songid){
+ playlists[playlistnumber]->songs.push_back((Song*)songid);
+ playlists[playlistnumber]->dirty=true;
+}
+
+void ASDevice::removeTrackFromPlaylist(int playlistnumber, int songnum) {
+ playlists[playlistnumber]->songs.erase(playlists[playlistnumber]->songs.begin() + songnum);
+ playlists[playlistnumber]->dirty=true;
+}
+
+void ASDevice::deletePlaylist(int playlistnumber) {
+ pISession->CeDeleteFile(playlists[playlistnumber]->fn);
+ delete playlists[playlistnumber];
+ playlists.erase(playlists.begin() + playlistnumber);
+}
+
+int ASDevice::newPlaylist(const wchar_t * name0) {
+ pISession->CeCreateDirectory(playlistFolder,NULL);
+ Playlist* pl = new Playlist(name0);
+ wchar_t * name = _wcsdup(name0);
+ removebadchars(name);
+ wsprintf(pl->fn,L"%s\\%s.%s",playlistFolder,name,playlistFormat);
+ free(name);
+ pl->dirty=true;
+ playlists.push_back(pl);
+ return (int)playlists.size()-1;
+}
+
+void ASDevice::getTrackArtist(songid_t songid, wchar_t * buf, int len) { lstrcpyn(buf,((Song*)songid)->artist,len); }
+void ASDevice::getTrackAlbum(songid_t songid, wchar_t * buf, int len) { lstrcpyn(buf,((Song*)songid)->album,len); }
+void ASDevice::getTrackTitle(songid_t songid, wchar_t * buf, int len) { lstrcpyn(buf,((Song*)songid)->title,len); }
+int ASDevice::getTrackTrackNum(songid_t songid) { return ((Song*)songid)->track; }
+__int64 ASDevice::getTrackSize(songid_t songid) { return ((Song*)songid)->size; }
+void ASDevice::getTrackExtraInfo(songid_t songid, const wchar_t * field, wchar_t * buf, int len) {
+ if(!wcscmp(field,FIELD_EXTENSION)) {
+ Song * s = (Song *)songid;
+ wchar_t * ext = wcsrchr(s->fn,L'.');
+ if(ext) { ext++; lstrcpyn(buf,ext,len); }
+ }
+}
+
+int ASDevice::copyToHardDrive(songid_t song,wchar_t * path,void * callbackContext,void (*callback)(void * callbackContext, wchar_t * status),int * killswitch) {
+ Song * s = (Song*)song;
+ wchar_t * ext = wcsrchr(s->fn,L'.');
+ if(ext && wcslen(ext)<10) wcscat(path,ext);
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_TRANSFERRING));
+ FILE * f = _wfopen(path,L"wb");
+ if(!f) {
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_CANNOT_OPEN_DESTINATION));
+ return -1;
+ }
+
+ HANDLE h = pISession->CeCreateFile(s->fn,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
+ if(h == INVALID_HANDLE_VALUE) {
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_CANNOT_OPEN_FILE_ON_DEVICE));
+ fclose(f);
+ return -1;
+ }
+
+ int error=0;
+ int pc = (int)(s->size/100);
+ int written=0,lastupdate=0;
+ for(;;) {
+ char buf[32768] = {0};
+ DWORD read=0;
+ pISession->CeReadFile(h,buf,sizeof(buf),&read,NULL);
+ if(!read) break;
+ int wr = (int)fwrite(buf,1,read,f);
+ if(wr != read) {
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_ERROR_WRITING_FILE));
+ error=1;
+ break;
+ }
+ written += read;
+ if(written - lastupdate > pc) {
+ lastupdate = written;
+ wchar_t buf[100] = {0};
+ wsprintf(buf,WASABI_API_LNGSTRINGW(IDS_TRANSFERRING),written/(s->size/100));
+ callback(callbackContext,buf);
+ }
+ }
+
+ pISession->CeCloseHandle(h);
+ fclose(f);
+ if(!error) {
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_DONE));
+ return 0;
+ } else return -1;
+}
+
+static BOOL CALLBACK config_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+
+intptr_t ASDevice::extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4) {
+ switch(param1) {
+ case DEVICE_SET_ICON:
+ {
+ MLTREEIMAGE * i = (MLTREEIMAGE*)param2;
+ i->hinst = plugin.hDllInstance;
+ i->resourceId = IDR_ACTIVESYNC_ICON;
+ }
+ break;
+ case DEVICE_SUPPORTED_METADATA: return 0x8f;
+ case DEVICE_DOES_NOT_SUPPORT_EDITING_METADATA: return 1;
+ case DEVICE_GET_PREFS_DIALOG:
+ if(param3 == 0) {
+ pref_tab * p = (pref_tab *)param2;
+ p->hinst = WASABI_API_LNG_HINST;
+ p->dlg_proc = (DLGPROC)config_dialogProc;
+ p->res_id = IDD_CONFIG;
+ lstrcpyn(p->title,WASABI_API_LNGSTRINGW(IDS_ADVANCED),100);
+ }
+ break;
+ case DEVICE_SUPPORTS_VIDEO:
+ return 1;
+ }
+ return 0;
+}
+
+static BOOL CALLBACK config_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
+ static ASDevice * dev;
+ switch(uMsg) {
+ case WM_INITDIALOG:
+ {
+ prefsParam* p = (prefsParam*)lParam;
+ dev = (ASDevice*)p->dev;
+ p->config_tab_init(hwndDlg,p->parent);
+ SetDlgItemText(hwndDlg,IDC_FOLDER_MUSIC,dev->musicFolder);
+ SetDlgItemText(hwndDlg,IDC_FOLDER_VIDEO,dev->videoFolder);
+ SetDlgItemText(hwndDlg,IDC_FOLDER_PLAYLIST,dev->playlistFolder);
+ }
+ break;
+ case WM_DESTROY:
+ {
+ GetDlgItemText(hwndDlg,IDC_FOLDER_MUSIC,dev->musicFolder,MAX_PATH);
+ GetDlgItemText(hwndDlg,IDC_FOLDER_VIDEO,dev->videoFolder,MAX_PATH);
+ GetDlgItemText(hwndDlg,IDC_FOLDER_PLAYLIST,dev->playlistFolder,MAX_PATH);
+ wchar_t *inifile = (wchar_t*)SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)dev,PMP_IPC_GET_INI_FILE);
+#if 1
+ wchar_t inifil[MAX_PATH] = {0};
+ if(!inifile) {
+ inifile=inifil;
+ const char * iniDirectory = (const char*)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETINIDIRECTORY);
+ wchar_t name[256] = {0};
+ lstrcpyn(name,dev->devInfo.bstrName,256);
+ removebadchars(name);
+ wsprintf(inifile,L"%s\\Plugins\\ml\\ml_pmp_device_%s.ini",(wchar_t*)AutoWide(iniDirectory),name);
+ }
+#endif
+ if(inifile) {
+ WritePrivateProfileString(L"pmp_activesync",L"musicfolder",dev->musicFolder,inifile);
+ WritePrivateProfileString(L"pmp_activesync",L"videofolder",dev->videoFolder,inifile);
+ WritePrivateProfileString(L"pmp_activesync",L"playlistfolder",dev->playlistFolder,inifile);
+ }
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_RESCAN:
+ config_dialogProc(hwndDlg,WM_DESTROY,0,0);
+ dev->Close();
+ break;
+ }
+ break;
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_activesync/ASDevice.h b/Src/Plugins/Portable/pmp_activesync/ASDevice.h
new file mode 100644
index 00000000..c1fa7584
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/ASDevice.h
@@ -0,0 +1,172 @@
+#define _WIN32_DCOM
+
+#include <winsock2.h>
+#include <windows.h>
+#include <windowsx.h>
+#include <rapi2.h>
+#include <shlobj.h>
+//#include <vector>
+#include <algorithm>
+
+#include <vector>
+
+#include "../Winamp/wa_ipc.h"
+#include "../Plugins/General/gen_ml/ml.h"
+#include "../Plugins/Library/ml_pmp/pmp.h"
+#include "../Plugins/Library/ml_pmp/transcoder.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+
+#include <api/service/waservicefactory.h>
+#include "../playlist/ifc_playlistloader.h"
+#include "../xml/ifc_xmlreadercallback.h"
+#include "../xml/obj_xml.h"
+#include "../xml/api__xml.h"
+#include "../Agave/Language/api_language.h"
+
+#include "resource.h"
+
+typedef struct {
+ RAPIDEVICEID id;
+ bool marked;
+} ejectedDevice;
+
+extern PMPDevicePlugin plugin;
+extern std::vector<ejectedDevice*> ejected;
+
+#define fieldlen 128
+
+class Song {
+public:
+ wchar_t artist[fieldlen],album[fieldlen],title[fieldlen];
+ wchar_t fn[MAX_PATH];
+ int track;
+ __int64 size;
+ bool video;
+ Song(const wchar_t * path, LPCE_FIND_DATA f, bool video);
+ Song();
+};
+
+class Playlist {
+public:
+ std::vector<Song*> songs;
+ wchar_t name[fieldlen];
+ wchar_t fn[MAX_PATH];
+ bool dirty;
+ Playlist(const wchar_t * path, LPCE_FIND_DATA f);
+ Playlist(const wchar_t * name);
+};
+
+class ASDevice : public Device {
+public:
+
+ wchar_t musicFolder[MAX_PATH];
+ wchar_t videoFolder[MAX_PATH];
+ wchar_t playlistFolder[MAX_PATH];
+ wchar_t playlistFormat[16];
+
+ IRAPIDevice *pIDevice;
+ IRAPISession *pISession;
+
+ Transcoder * transcoder;
+ RAPI_DEVICEINFO devInfo;
+ __int64 transferQueueSize;
+ std::vector<Playlist*> playlists;
+ void Find(const wchar_t * dir);
+ void FoundFile(const wchar_t * path, LPCE_FIND_DATA f);
+
+ void WritePlaylist(Playlist * pl);
+ void ReadPlaylist(Playlist * pl);
+
+ ASDevice(IRAPIDevice *pIDevice,IRAPISession *pISession);
+ ~ASDevice();
+
+ virtual __int64 getDeviceCapacityAvailable(); // in bytes
+ virtual __int64 getDeviceCapacityTotal(); // in bytes
+
+ virtual void Eject();
+ virtual void Close(); // save any changes, and call PMP_IPC_DEVICEDISCONNECTED AND delete this;
+
+
+ // return 0 for success, -1 for failed or cancelled
+ virtual int transferTrackToDevice(const itemRecordW * track, // the track to transfer
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
+ songid_t * songid, // fill in the songid when you are finished
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ );
+ virtual int trackAddedToTransferQueue(const itemRecordW * track); // return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
+ virtual void trackRemovedFromTransferQueue(const itemRecordW * track);
+
+ // return the amount of space that will be taken up on the device by the track (once it has been tranferred)
+ // or 0 for incompatable. This is usually the filesize, unless you are transcoding. An estimate is acceptable.
+ virtual __int64 getTrackSizeOnDevice(const itemRecordW * track);
+
+ virtual void deleteTrack(songid_t songid); // physically remove from device. Be sure to remove it from all the playlists!
+
+ virtual void commitChanges(); // optional. Will be called at a good time to save changes
+
+ virtual int getPlaylistCount(); // always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
+ // PlaylistName(0) should return the name of the device.
+ virtual void getPlaylistName(int playlistnumber, wchar_t * buf, int len);
+ virtual int getPlaylistLength(int playlistnumber);
+ virtual songid_t getPlaylistTrack(int playlistnumber,int songnum); // returns a songid
+
+ virtual void setPlaylistName(int playlistnumber, const wchar_t * buf); // with playlistnumber==0, set the name of the device.
+ virtual void playlistSwapItems(int playlistnumber, int posA, int posB); // swap the songs at position posA and posB
+ virtual void sortPlaylist(int playlistnumber, int sortBy);
+ virtual void addTrackToPlaylist(int playlistnumber, songid_t songid); // adds songid to the end of the playlist
+ virtual void removeTrackFromPlaylist(int playlistnumber, int songnum); //where songnum is the position of the track in the playlist
+
+ virtual void deletePlaylist(int playlistnumber);
+ virtual int newPlaylist(const wchar_t * name); // create empty playlist, returns playlistnumber. -1 for failed.
+
+ virtual void getTrackArtist(songid_t songid, wchar_t * buf, int len);
+ virtual void getTrackAlbum(songid_t songid, wchar_t * buf, int len);
+ virtual void getTrackTitle(songid_t songid, wchar_t * buf, int len);
+ virtual int getTrackTrackNum(songid_t songid);
+ virtual int getTrackDiscNum(songid_t songid){return -1;}
+ virtual void getTrackGenre(songid_t songid, wchar_t * buf, int len){buf[0]=0;}
+ virtual int getTrackYear(songid_t songid){return -1;}
+ virtual __int64 getTrackSize(songid_t songid); // in bytes
+ virtual int getTrackLength(songid_t songid){return -1;} // in millisecs
+ virtual int getTrackBitrate(songid_t songid){return -1;} // in kbps
+ virtual int getTrackPlayCount(songid_t songid){return 0;}
+ virtual int getTrackRating(songid_t songid){return 0;} //0-5
+ virtual __time64_t getTrackLastPlayed(songid_t songid){return 0;} // in unix time format
+ virtual __time64_t getTrackLastUpdated(songid_t songid){return 0;} // in unix time format
+ virtual int getTrackType(songid_t songid) { return ((Song *)songid)->video?1:0; }
+ virtual void getTrackExtraInfo(songid_t songid, const wchar_t * field, wchar_t * buf, int len); //optional
+
+ // feel free to ignore any you don't support
+ virtual void setTrackArtist(songid_t songid, const wchar_t * value){}
+ virtual void setTrackAlbum(songid_t songid, const wchar_t * value){}
+ virtual void setTrackTitle(songid_t songid, const wchar_t * value){}
+ virtual void setTrackTrackNum(songid_t songid, int value){}
+ virtual void setTrackDiscNum(songid_t songid, int value){}
+ virtual void setTrackGenre(songid_t songid, const wchar_t * value){}
+ virtual void setTrackYear(songid_t songid, int year){}
+ virtual void setTrackPlayCount(songid_t songid, int value){}
+ virtual void setTrackRating(songid_t songid, int value){}
+ virtual void setTrackLastPlayed(songid_t songid, __time64_t value){} // in unix time format
+ virtual void setTrackLastUpdated(songid_t songid, __time64_t value){} // in unix time format
+ virtual void setTrackExtraInfo(songid_t songid, const wchar_t * field, const wchar_t * value) {}; //optional
+
+ virtual bool playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue){return false;} // return false if unsupported
+
+ virtual intptr_t extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4);
+
+ // new methods as of PMPHDR_VER 0x002
+ virtual bool copyToHardDriveSupported() {return true;}
+
+ virtual __int64 songSizeOnHardDrive(songid_t song) {return getTrackSize(song);} // how big a song will be when copied back. Return -1 for not supported.
+
+ virtual int copyToHardDrive(songid_t song, // the song to copy
+ wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ ); // -1 for failed/not supported. 0 for success.
+};
+
+extern std::vector<ASDevice*> devices;
diff --git a/Src/Plugins/Portable/pmp_activesync/activesync/Inc/IRAPIStream.h b/Src/Plugins/Portable/pmp_activesync/activesync/Inc/IRAPIStream.h
new file mode 100644
index 00000000..c1004fa1
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/activesync/Inc/IRAPIStream.h
@@ -0,0 +1,286 @@
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 6.00.0361 */
+/* at Fri Sep 17 22:09:50 2004
+ */
+/* Compiler settings for ..\IRAPIStream.idl:
+ Oicf, W1, Zp8, env=Win32 (32b run)
+ protocol : dce , ms_ext, c_ext, robust
+ error checks: allocation ref bounds_check enum stub_data
+ VC __declspec() decoration level:
+ __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+ DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+//@@MIDL_FILE_HEADING( )
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __IRAPIStream_h__
+#define __IRAPIStream_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __IRAPIStream_FWD_DEFINED__
+#define __IRAPIStream_FWD_DEFINED__
+typedef interface IRAPIStream IRAPIStream;
+#endif /* __IRAPIStream_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "oaidl.h"
+#include "ocidl.h"
+#include "rapitypes.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+void * __RPC_USER MIDL_user_allocate(size_t);
+void __RPC_USER MIDL_user_free( void * );
+
+#ifndef __IRAPIStream_INTERFACE_DEFINED__
+#define __IRAPIStream_INTERFACE_DEFINED__
+
+/* interface IRAPIStream */
+/* [object][uuid] */
+
+
+EXTERN_C const IID IID_IRAPIStream;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("449FE623-24B0-454b-A889-129BB05DDBED")
+ IRAPIStream : public IStream
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetRapiStat(
+ /* [in] */ RAPISTREAMFLAG Flag,
+ /* [in] */ DWORD dwValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRapiStat(
+ /* [in] */ RAPISTREAMFLAG Flag,
+ /* [out] */ DWORD *pdwValue) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IRAPIStreamVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IRAPIStream * This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IRAPIStream * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IRAPIStream * This);
+
+ /* [local] */ HRESULT ( STDMETHODCALLTYPE *Read )(
+ IRAPIStream * This,
+ /* [length_is][size_is][out] */ void *pv,
+ /* [in] */ ULONG cb,
+ /* [out] */ ULONG *pcbRead);
+
+ /* [local] */ HRESULT ( STDMETHODCALLTYPE *Write )(
+ IRAPIStream * This,
+ /* [size_is][in] */ const void *pv,
+ /* [in] */ ULONG cb,
+ /* [out] */ ULONG *pcbWritten);
+
+ /* [local] */ HRESULT ( STDMETHODCALLTYPE *Seek )(
+ IRAPIStream * This,
+ /* [in] */ LARGE_INTEGER dlibMove,
+ /* [in] */ DWORD dwOrigin,
+ /* [out] */ ULARGE_INTEGER *plibNewPosition);
+
+ HRESULT ( STDMETHODCALLTYPE *SetSize )(
+ IRAPIStream * This,
+ /* [in] */ ULARGE_INTEGER libNewSize);
+
+ /* [local] */ HRESULT ( STDMETHODCALLTYPE *CopyTo )(
+ IRAPIStream * This,
+ /* [unique][in] */ IStream *pstm,
+ /* [in] */ ULARGE_INTEGER cb,
+ /* [out] */ ULARGE_INTEGER *pcbRead,
+ /* [out] */ ULARGE_INTEGER *pcbWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *Commit )(
+ IRAPIStream * This,
+ /* [in] */ DWORD grfCommitFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *Revert )(
+ IRAPIStream * This);
+
+ HRESULT ( STDMETHODCALLTYPE *LockRegion )(
+ IRAPIStream * This,
+ /* [in] */ ULARGE_INTEGER libOffset,
+ /* [in] */ ULARGE_INTEGER cb,
+ /* [in] */ DWORD dwLockType);
+
+ HRESULT ( STDMETHODCALLTYPE *UnlockRegion )(
+ IRAPIStream * This,
+ /* [in] */ ULARGE_INTEGER libOffset,
+ /* [in] */ ULARGE_INTEGER cb,
+ /* [in] */ DWORD dwLockType);
+
+ HRESULT ( STDMETHODCALLTYPE *Stat )(
+ IRAPIStream * This,
+ /* [out] */ STATSTG *pstatstg,
+ /* [in] */ DWORD grfStatFlag);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ IRAPIStream * This,
+ /* [out] */ IStream **ppstm);
+
+ HRESULT ( STDMETHODCALLTYPE *SetRapiStat )(
+ IRAPIStream * This,
+ /* [in] */ RAPISTREAMFLAG Flag,
+ /* [in] */ DWORD dwValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRapiStat )(
+ IRAPIStream * This,
+ /* [in] */ RAPISTREAMFLAG Flag,
+ /* [out] */ DWORD *pdwValue);
+
+ END_INTERFACE
+ } IRAPIStreamVtbl;
+
+ interface IRAPIStream
+ {
+ CONST_VTBL struct IRAPIStreamVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IRAPIStream_QueryInterface(This,riid,ppvObject) \
+ (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define IRAPIStream_AddRef(This) \
+ (This)->lpVtbl -> AddRef(This)
+
+#define IRAPIStream_Release(This) \
+ (This)->lpVtbl -> Release(This)
+
+
+#define IRAPIStream_Read(This,pv,cb,pcbRead) \
+ (This)->lpVtbl -> Read(This,pv,cb,pcbRead)
+
+#define IRAPIStream_Write(This,pv,cb,pcbWritten) \
+ (This)->lpVtbl -> Write(This,pv,cb,pcbWritten)
+
+
+#define IRAPIStream_Seek(This,dlibMove,dwOrigin,plibNewPosition) \
+ (This)->lpVtbl -> Seek(This,dlibMove,dwOrigin,plibNewPosition)
+
+#define IRAPIStream_SetSize(This,libNewSize) \
+ (This)->lpVtbl -> SetSize(This,libNewSize)
+
+#define IRAPIStream_CopyTo(This,pstm,cb,pcbRead,pcbWritten) \
+ (This)->lpVtbl -> CopyTo(This,pstm,cb,pcbRead,pcbWritten)
+
+#define IRAPIStream_Commit(This,grfCommitFlags) \
+ (This)->lpVtbl -> Commit(This,grfCommitFlags)
+
+#define IRAPIStream_Revert(This) \
+ (This)->lpVtbl -> Revert(This)
+
+#define IRAPIStream_LockRegion(This,libOffset,cb,dwLockType) \
+ (This)->lpVtbl -> LockRegion(This,libOffset,cb,dwLockType)
+
+#define IRAPIStream_UnlockRegion(This,libOffset,cb,dwLockType) \
+ (This)->lpVtbl -> UnlockRegion(This,libOffset,cb,dwLockType)
+
+#define IRAPIStream_Stat(This,pstatstg,grfStatFlag) \
+ (This)->lpVtbl -> Stat(This,pstatstg,grfStatFlag)
+
+#define IRAPIStream_Clone(This,ppstm) \
+ (This)->lpVtbl -> Clone(This,ppstm)
+
+
+#define IRAPIStream_SetRapiStat(This,Flag,dwValue) \
+ (This)->lpVtbl -> SetRapiStat(This,Flag,dwValue)
+
+#define IRAPIStream_GetRapiStat(This,Flag,pdwValue) \
+ (This)->lpVtbl -> GetRapiStat(This,Flag,pdwValue)
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+HRESULT STDMETHODCALLTYPE IRAPIStream_SetRapiStat_Proxy(
+ IRAPIStream * This,
+ /* [in] */ RAPISTREAMFLAG Flag,
+ /* [in] */ DWORD dwValue);
+
+
+void __RPC_STUB IRAPIStream_SetRapiStat_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPIStream_GetRapiStat_Proxy(
+ IRAPIStream * This,
+ /* [in] */ RAPISTREAMFLAG Flag,
+ /* [out] */ DWORD *pdwValue);
+
+
+void __RPC_STUB IRAPIStream_GetRapiStat_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+
+#endif /* __IRAPIStream_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapi.h b/Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapi.h
new file mode 100644
index 00000000..18e47dbd
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapi.h
@@ -0,0 +1,118 @@
+// --------------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+// Module:
+//
+// rapi.h
+//
+// Purpose:
+//
+// Master include file for Windows CE Remote API
+//
+// --------------------------------------------------------------------------
+
+#ifndef RAPI_H
+#define RAPI_H
+
+#include <windows.h>
+
+#include "rapitypes.h"
+#include "irapistream.h"
+
+#ifndef UNDER_CE
+
+STDAPI CeRapiInitEx(RAPIINIT*);
+STDAPI CeRapiInit();
+STDAPI CeRapiUninit();
+STDAPI CeRapiGetError(void);
+STDAPI CeRapiFreeBuffer(LPVOID);
+STDAPI_( HRESULT ) CeRapiInvoke(LPCWSTR, LPCWSTR,DWORD,BYTE *, DWORD *,BYTE **, IRAPIStream **,DWORD);
+
+STDAPI_(CEOID) CeCreateDatabase (LPWSTR, DWORD, WORD, SORTORDERSPEC*);
+STDAPI_(BOOL ) CeDeleteDatabase (CEOID);
+STDAPI_(BOOL ) CeDeleteRecord (HANDLE, CEOID);
+STDAPI_(HANDLE) CeFindFirstDatabase (DWORD);
+STDAPI_(CEOID) CeFindNextDatabase (HANDLE);
+STDAPI_(BOOL ) CeOidGetInfo (CEOID, CEOIDINFO*);
+STDAPI_(HANDLE) CeOpenDatabase (PCEOID, LPWSTR, CEPROPID, DWORD, HWND);
+STDAPI_(CEOID) CeReadRecordProps (HANDLE, DWORD, LPWORD, CEPROPID*, LPBYTE*, LPDWORD);
+STDAPI_(CEOID) CeSeekDatabase (HANDLE, DWORD, DWORD, LPDWORD);
+STDAPI_(BOOL ) CeSetDatabaseInfo (CEOID, CEDBASEINFO*);
+STDAPI_(HANDLE) CeFindFirstFile (LPCWSTR, LPCE_FIND_DATA);
+STDAPI_(BOOL ) CeFindNextFile (HANDLE, LPCE_FIND_DATA);
+STDAPI_(BOOL ) CeFindClose (HANDLE);
+STDAPI_(DWORD ) CeGetFileAttributes (LPCWSTR);
+STDAPI_(BOOL ) CeSetFileAttributes (LPCWSTR, DWORD);
+STDAPI_(HANDLE) CeCreateFile (LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
+STDAPI_(BOOL ) CeReadFile (HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
+STDAPI_(BOOL ) CeWriteFile (HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED);
+STDAPI_(BOOL ) CeCloseHandle (HANDLE);
+STDAPI_(BOOL ) CeFindAllFiles (LPCWSTR, DWORD, LPDWORD, LPLPCE_FIND_DATA);
+STDAPI_(BOOL ) CeFindAllDatabases (DWORD, WORD, LPWORD, LPLPCEDB_FIND_DATA);
+STDAPI_(DWORD ) CeGetLastError (void);
+STDAPI_(DWORD ) CeSetFilePointer (HANDLE, LONG, PLONG, DWORD);
+STDAPI_(BOOL ) CeSetEndOfFile (HANDLE);
+STDAPI_(BOOL ) CeCreateDirectory (LPCWSTR, LPSECURITY_ATTRIBUTES);
+STDAPI_(BOOL ) CeRemoveDirectory (LPCWSTR);
+STDAPI_(BOOL ) CeCreateProcess (LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPWSTR, LPSTARTUPINFO, LPPROCESS_INFORMATION);
+STDAPI_(BOOL ) CeMoveFile (LPCWSTR, LPCWSTR);
+STDAPI_(BOOL ) CeCopyFile (LPCWSTR, LPCWSTR, BOOL);
+STDAPI_(BOOL ) CeDeleteFile (LPCWSTR);
+STDAPI_(DWORD ) CeGetFileSize (HANDLE, LPDWORD);
+STDAPI_(LONG ) CeRegOpenKeyEx (HKEY, LPCWSTR, DWORD, REGSAM, PHKEY);
+STDAPI_(LONG ) CeRegEnumKeyEx (HKEY, DWORD, LPWSTR, LPDWORD, LPDWORD, LPWSTR, LPDWORD, PFILETIME);
+STDAPI_(LONG ) CeRegCreateKeyEx (HKEY, LPCWSTR, DWORD, LPWSTR, DWORD, REGSAM, LPSECURITY_ATTRIBUTES, PHKEY, LPDWORD);
+STDAPI_(LONG ) CeRegCloseKey (HKEY);
+STDAPI_(LONG ) CeRegDeleteKey (HKEY, LPCWSTR);
+STDAPI_(LONG ) CeRegEnumValue (HKEY, DWORD, LPWSTR, LPDWORD, LPDWORD, LPDWORD, LPBYTE, LPDWORD);
+STDAPI_(LONG ) CeRegDeleteValue (HKEY, LPCWSTR);
+STDAPI_(LONG ) CeRegQueryInfoKey (HKEY, LPWSTR, LPDWORD, LPDWORD, LPDWORD, LPDWORD, LPDWORD, LPDWORD, LPDWORD, LPDWORD, LPDWORD, PFILETIME);
+STDAPI_(LONG ) CeRegQueryValueEx (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD);
+STDAPI_(LONG ) CeRegSetValueEx (HKEY, LPCWSTR, DWORD, DWORD, LPBYTE, DWORD);
+STDAPI_(BOOL ) CeGetStoreInformation(LPSTORE_INFORMATION);
+STDAPI_(INT ) CeGetSystemMetrics (INT);
+STDAPI_(INT ) CeGetDesktopDeviceCaps(INT);
+STDAPI_(VOID ) CeGetSystemInfo (LPSYSTEM_INFO);
+STDAPI_(DWORD ) CeSHCreateShortcut (LPWSTR, LPWSTR);
+STDAPI_(BOOL ) CeSHGetShortcutTarget(LPWSTR, LPWSTR, INT);
+STDAPI_(BOOL ) CeCheckPassword (LPWSTR);
+STDAPI_(BOOL ) CeGetFileTime (HANDLE, LPFILETIME, LPFILETIME, LPFILETIME);
+STDAPI_(BOOL ) CeSetFileTime (HANDLE, LPFILETIME, LPFILETIME, LPFILETIME);
+STDAPI_(BOOL ) CeGetVersionEx (LPCEOSVERSIONINFO);
+STDAPI_(HWND ) CeGetWindow (HWND, UINT);
+STDAPI_(LONG ) CeGetWindowLong (HWND, int);
+STDAPI_(int ) CeGetWindowText (HWND, LPWSTR, int);
+STDAPI_(int ) CeGetClassName (HWND, LPWSTR, int);
+STDAPI_(VOID ) CeGlobalMemoryStatus (LPMEMORYSTATUS);
+STDAPI_(BOOL ) CeGetSystemPowerStatusEx(PSYSTEM_POWER_STATUS_EX, BOOL);
+STDAPI_(DWORD ) CeGetTempPath (DWORD, LPWSTR);
+STDAPI_(DWORD ) CeGetSpecialFolderPath(int, DWORD, LPWSTR);
+STDAPI_(HANDLE) CeFindFirstDatabaseEx (PCEGUID, DWORD);
+STDAPI_(CEOID ) CeFindNextDatabaseEx (HANDLE, PCEGUID);
+STDAPI_(CEOID ) CeCreateDatabaseEx (PCEGUID, CEDBASEINFO*);
+STDAPI_(BOOL ) CeSetDatabaseInfoEx (PCEGUID, CEOID, CEDBASEINFO*);
+STDAPI_(HANDLE) CeOpenDatabaseEx (PCEGUID, PCEOID, LPWSTR, CEPROPID, DWORD, CENOTIFYREQUEST *);
+STDAPI_(BOOL ) CeDeleteDatabaseEx (PCEGUID, CEOID);
+STDAPI_(CEOID ) CeReadRecordPropsEx (HANDLE, DWORD, LPWORD, CEPROPID*, LPBYTE*, LPDWORD, HANDLE);
+STDAPI_(CEOID ) CeWriteRecordProps (HANDLE, CEOID, WORD, CEPROPVAL*);
+STDAPI_(BOOL ) CeMountDBVol (PCEGUID, LPWSTR, DWORD);
+STDAPI_(BOOL ) CeUnmountDBVol (PCEGUID);
+STDAPI_(BOOL ) CeFlushDBVol (PCEGUID);
+STDAPI_(BOOL ) CeEnumDBVolumes (PCEGUID, LPWSTR, DWORD);
+STDAPI_(BOOL ) CeOidGetInfoEx (PCEGUID, CEOID, CEOIDINFO*);
+STDAPI CeSyncStart (LPCWSTR);
+STDAPI CeSyncStop ();
+STDAPI_(BOOL ) CeQueryInstructionSet (DWORD, LPDWORD);
+STDAPI_(BOOL ) CeGetDiskFreeSpaceEx (LPCWSTR, ULARGE_INTEGER *, ULARGE_INTEGER *, ULARGE_INTEGER *);
+#endif // #ifndef UNDER_CE
+
+#ifndef NO_APIMAP
+#include <ceapimap.h>
+#endif
+
+#ifdef CONN_INTERNAL
+#include <prapi.h> // internal defines
+#endif
+
+#endif // #ifndef RAPI_H
diff --git a/Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapi2.h b/Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapi2.h
new file mode 100644
index 00000000..6d930758
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapi2.h
@@ -0,0 +1,3090 @@
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 6.00.0361 */
+/* at Fri Apr 22 19:21:11 2005
+ */
+/* Compiler settings for .\RAPI2.idl:
+ Oicf, W1, Zp8, env=Win32 (32b run)
+ protocol : dce , ms_ext, c_ext, robust
+ error checks: allocation ref bounds_check enum stub_data
+ VC __declspec() decoration level:
+ __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+ DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+//@@MIDL_FILE_HEADING( )
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __RAPI2_h__
+#define __RAPI2_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __IRAPISession_FWD_DEFINED__
+#define __IRAPISession_FWD_DEFINED__
+typedef interface IRAPISession IRAPISession;
+#endif /* __IRAPISession_FWD_DEFINED__ */
+
+
+#ifndef __IRAPIDevice_FWD_DEFINED__
+#define __IRAPIDevice_FWD_DEFINED__
+typedef interface IRAPIDevice IRAPIDevice;
+#endif /* __IRAPIDevice_FWD_DEFINED__ */
+
+
+#ifndef __IRAPIEnumDevices_FWD_DEFINED__
+#define __IRAPIEnumDevices_FWD_DEFINED__
+typedef interface IRAPIEnumDevices IRAPIEnumDevices;
+#endif /* __IRAPIEnumDevices_FWD_DEFINED__ */
+
+
+#ifndef __IRAPISink_FWD_DEFINED__
+#define __IRAPISink_FWD_DEFINED__
+typedef interface IRAPISink IRAPISink;
+#endif /* __IRAPISink_FWD_DEFINED__ */
+
+
+#ifndef __IRAPIDesktop_FWD_DEFINED__
+#define __IRAPIDesktop_FWD_DEFINED__
+typedef interface IRAPIDesktop IRAPIDesktop;
+#endif /* __IRAPIDesktop_FWD_DEFINED__ */
+
+
+#ifndef __RAPI_FWD_DEFINED__
+#define __RAPI_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class RAPI RAPI;
+#else
+typedef struct RAPI RAPI;
+#endif /* __cplusplus */
+
+#endif /* __RAPI_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "oaidl.h"
+#include "ocidl.h"
+#include "rapitypes.h"
+#include "rapitypes2.h"
+#include "irapistream.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+void * __RPC_USER MIDL_user_allocate(size_t);
+void __RPC_USER MIDL_user_free( void * );
+
+/* interface __MIDL_itf_RAPI2_0000 */
+/* [local] */
+
+#define NO_APIMAP 1
+#include "rapi.h"
+#ifndef UNDER_CE
+
+
+extern RPC_IF_HANDLE __MIDL_itf_RAPI2_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_RAPI2_0000_v0_0_s_ifspec;
+
+#ifndef __IRAPISession_INTERFACE_DEFINED__
+#define __IRAPISession_INTERFACE_DEFINED__
+
+/* interface IRAPISession */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IRAPISession;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("76a78b7d-8e54-4c06-ac38-459e6a1ab5e3")
+ IRAPISession : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CeRapiInit( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CeRapiUninit( void) = 0;
+
+ virtual DWORD STDMETHODCALLTYPE CeGetLastError( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CeRapiGetError( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CeRapiFreeBuffer(
+ void *Buffer) = 0;
+
+ virtual HANDLE STDMETHODCALLTYPE CeFindFirstFile(
+ LPCWSTR FileName,
+ LPCE_FIND_DATA FindData) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeFindNextFile(
+ HANDLE FoundFile,
+ LPCE_FIND_DATA FindData) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeFindClose(
+ HANDLE FoundFile) = 0;
+
+ virtual DWORD STDMETHODCALLTYPE CeGetFileAttributes(
+ LPCWSTR FileName) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeSetFileAttributes(
+ LPCWSTR FileName,
+ DWORD FileAttrib) = 0;
+
+ virtual HANDLE STDMETHODCALLTYPE CeCreateFile(
+ LPCWSTR lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDistribution,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeReadFile(
+ HANDLE hFile,
+ LPVOID lpBuffer,
+ DWORD nNumberOfBytesToRead,
+ LPDWORD lpNumberOfBytesRead,
+ LPOVERLAPPED lpOverlapped) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeWriteFile(
+ HANDLE hFile,
+ LPCVOID lpBuffer,
+ DWORD nNumberOfBytesToWrite,
+ LPDWORD lpNumberOfBytesWritten,
+ LPOVERLAPPED lpOverlapped) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeCloseHandle(
+ HANDLE hObject) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeFindAllFiles(
+ LPCWSTR Path,
+ DWORD Flags,
+ LPDWORD pFoundCount,
+ LPLPCE_FIND_DATA ppFindDataArray) = 0;
+
+ virtual HANDLE STDMETHODCALLTYPE CeFindFirstDatabase(
+ DWORD dwDbaseType) = 0;
+
+ virtual CEOID STDMETHODCALLTYPE CeFindNextDatabase(
+ HANDLE hEnum) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeOidGetInfo(
+ CEOID oid,
+ CEOIDINFO *oidInfo) = 0;
+
+ virtual CEOID STDMETHODCALLTYPE CeCreateDatabase(
+ LPWSTR lpszName,
+ DWORD dwDbaseType,
+ WORD cNumSortOrder,
+ SORTORDERSPEC *rgSortSpecs) = 0;
+
+ virtual HANDLE STDMETHODCALLTYPE CeOpenDatabase(
+ PCEOID poid,
+ LPWSTR lpszName,
+ CEPROPID propid,
+ DWORD dwFlags,
+ HWND hwndNotify) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeDeleteDatabase(
+ CEOID oidDbase) = 0;
+
+ virtual CEOID STDMETHODCALLTYPE CeReadRecordProps(
+ HANDLE hDbase,
+ DWORD dwFlags,
+ LPWORD lpcPropID,
+ CEPROPID *rgPropID,
+ LPBYTE *lplpBuffer,
+ LPDWORD lpcbBuffer) = 0;
+
+ virtual CEOID STDMETHODCALLTYPE CeWriteRecordProps(
+ HANDLE hDbase,
+ CEOID oidRecord,
+ WORD cPropID,
+ CEPROPVAL *rgPropVal) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeDeleteRecord(
+ HANDLE hDatabase,
+ CEOID oidRecord) = 0;
+
+ virtual CEOID STDMETHODCALLTYPE CeSeekDatabase(
+ HANDLE hDatabase,
+ DWORD dwSeekType,
+ DWORD dwValue,
+ LPDWORD lpdwIndex) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeSetDatabaseInfo(
+ CEOID oidDbase,
+ CEDBASEINFO *pNewInfo) = 0;
+
+ virtual DWORD STDMETHODCALLTYPE CeSetFilePointer(
+ HANDLE hFile,
+ LONG lDistanceToMove,
+ PLONG lpDistanceToMoveHigh,
+ DWORD dwMoveMethod) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeSetEndOfFile(
+ HANDLE hFile) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeCreateDirectory(
+ LPCWSTR lpPathName,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeRemoveDirectory(
+ LPCWSTR lpPathName) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeCreateProcess(
+ LPCWSTR lpszImageName,
+ LPCWSTR lpszCmdLine,
+ LPSECURITY_ATTRIBUTES lpsaProcess,
+ LPSECURITY_ATTRIBUTES lpsaThread,
+ BOOL fInheritHandles,
+ DWORD fdwCreate,
+ LPVOID lpvEnvironment,
+ LPWSTR lpszCurDir,
+ LPSTARTUPINFOW lpsiStartInfo,
+ LPPROCESS_INFORMATION lppiProcInfo) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeMoveFile(
+ LPCWSTR lpExistingFileName,
+ LPCWSTR lpNewFileName) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeCopyFile(
+ LPCWSTR lpExistingFileName,
+ LPCWSTR lpNewFileName,
+ BOOL bFailIfExists) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeDeleteFile(
+ LPCWSTR FileName) = 0;
+
+ virtual DWORD STDMETHODCALLTYPE CeGetFileSize(
+ HANDLE hFile,
+ LPDWORD lpFileSizeHigh) = 0;
+
+ virtual LONG STDMETHODCALLTYPE CeRegOpenKeyEx(
+ HKEY hKey,
+ LPCWSTR lpszSubKey,
+ DWORD dwReserved,
+ REGSAM samDesired,
+ PHKEY phkResult) = 0;
+
+ virtual LONG STDMETHODCALLTYPE CeRegEnumKeyEx(
+ HKEY hKey,
+ DWORD dwIndex,
+ LPWSTR lpName,
+ LPDWORD lpcbName,
+ LPDWORD lpReserved,
+ LPWSTR lpClass,
+ LPDWORD lpcbClass,
+ PFILETIME lpftLastWriteTime) = 0;
+
+ virtual LONG STDMETHODCALLTYPE CeRegCreateKeyEx(
+ HKEY hKey,
+ LPCWSTR lpszSubKey,
+ DWORD dwReserved,
+ LPWSTR lpszClass,
+ DWORD fdwOptions,
+ REGSAM samDesired,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ PHKEY phkResult,
+ LPDWORD lpdwDisposition) = 0;
+
+ virtual LONG STDMETHODCALLTYPE CeRegCloseKey(
+ HKEY hKey) = 0;
+
+ virtual LONG STDMETHODCALLTYPE CeRegDeleteKey(
+ HKEY hKey,
+ LPCWSTR lpszSubKey) = 0;
+
+ virtual LONG STDMETHODCALLTYPE CeRegEnumValue(
+ HKEY hKey,
+ DWORD dwIndex,
+ LPWSTR lpszValueName,
+ LPDWORD lpcbValueName,
+ LPDWORD lpReserved,
+ LPDWORD lpType,
+ LPBYTE lpData,
+ LPDWORD lpcbData) = 0;
+
+ virtual LONG STDMETHODCALLTYPE CeRegDeleteValue(
+ HKEY hKey,
+ LPCWSTR lpszValueName) = 0;
+
+ virtual LONG STDMETHODCALLTYPE CeRegQueryInfoKey(
+ HKEY hKey,
+ LPWSTR lpClass,
+ LPDWORD lpcbClass,
+ LPDWORD lpReserved,
+ LPDWORD lpcSubKeys,
+ LPDWORD lpcbMaxSubKeyLen,
+ LPDWORD lpcbMaxClassLen,
+ LPDWORD lpcValues,
+ LPDWORD lpcbMaxValueNameLen,
+ LPDWORD lpcbMaxValueLen,
+ LPDWORD lpcbSecurityDescriptor,
+ PFILETIME lpftLastWriteTime) = 0;
+
+ virtual LONG STDMETHODCALLTYPE CeRegQueryValueEx(
+ HKEY hKey,
+ LPCWSTR lpValueName,
+ LPDWORD lpReserved,
+ LPDWORD lpType,
+ LPBYTE lpData,
+ LPDWORD lpcbData) = 0;
+
+ virtual LONG STDMETHODCALLTYPE CeRegSetValueEx(
+ HKEY hKey,
+ LPCWSTR lpValueName,
+ DWORD Reserved,
+ DWORD dwType,
+ BYTE *lpData,
+ DWORD cbData) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeGetStoreInformation(
+ LPSTORE_INFORMATION lpsi) = 0;
+
+ virtual INT STDMETHODCALLTYPE CeGetSystemMetrics(
+ INT nIndex) = 0;
+
+ virtual INT STDMETHODCALLTYPE CeGetDesktopDeviceCaps(
+ INT nIndex) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeFindAllDatabases(
+ DWORD DbaseType,
+ WORD Flags,
+ LPWORD cFindData,
+ LPLPCEDB_FIND_DATA ppFindData) = 0;
+
+ virtual void STDMETHODCALLTYPE CeGetSystemInfo(
+ LPSYSTEM_INFO lpSystemInfo) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeSHCreateShortcut(
+ LPWSTR lpszShortcut,
+ LPWSTR lpszTarget) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeSHGetShortcutTarget(
+ LPWSTR lpszShortcut,
+ LPWSTR lpszTarget,
+ int cbMax) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeCheckPassword(
+ LPWSTR lpszPassword) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeGetFileTime(
+ HANDLE hFile,
+ LPFILETIME lpCreationTime,
+ LPFILETIME lpLastAccessTime,
+ LPFILETIME lpLastWriteTime) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeSetFileTime(
+ HANDLE hFile,
+ FILETIME *lpCreationTime,
+ FILETIME *lpLastAccessTime,
+ FILETIME *lpLastWriteTime) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeGetVersionEx(
+ LPCEOSVERSIONINFO lpVersionInformation) = 0;
+
+ virtual HWND STDMETHODCALLTYPE CeGetWindow(
+ HWND hWnd,
+ UINT uCmd) = 0;
+
+ virtual LONG STDMETHODCALLTYPE CeGetWindowLong(
+ HWND hWnd,
+ int nIndex) = 0;
+
+ virtual INT STDMETHODCALLTYPE CeGetWindowText(
+ HWND hWnd,
+ LPWSTR lpString,
+ int nMaxCount) = 0;
+
+ virtual INT STDMETHODCALLTYPE CeGetClassName(
+ HWND hWnd,
+ LPWSTR lpClassName,
+ int nMaxCount) = 0;
+
+ virtual void STDMETHODCALLTYPE CeGlobalMemoryStatus(
+ LPMEMORYSTATUS lpmst) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeGetSystemPowerStatusEx(
+ PSYSTEM_POWER_STATUS_EX pstatus,
+ BOOL fUpdate) = 0;
+
+ virtual DWORD STDMETHODCALLTYPE CeGetTempPath(
+ DWORD nBufferLength,
+ LPWSTR lpBuffer) = 0;
+
+ virtual DWORD STDMETHODCALLTYPE CeGetSpecialFolderPath(
+ int nFolder,
+ DWORD nBufferLength,
+ LPWSTR lpBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CeRapiInvoke(
+ LPCWSTR pDllPath,
+ LPCWSTR pFunctionName,
+ DWORD cbInput,
+ BYTE *pInput,
+ DWORD *pcbOutput,
+ BYTE **ppOutput,
+ IRAPIStream **ppIRAPIStream,
+ DWORD dwReserved) = 0;
+
+ virtual HANDLE STDMETHODCALLTYPE CeFindFirstDatabaseEx(
+ PCEGUID pguid,
+ DWORD dwDbaseType) = 0;
+
+ virtual CEOID STDMETHODCALLTYPE CeFindNextDatabaseEx(
+ HANDLE hEnum,
+ PCEGUID pguid) = 0;
+
+ virtual CEOID STDMETHODCALLTYPE CeCreateDatabaseEx(
+ PCEGUID pceguid,
+ CEDBASEINFO *lpCEDBInfo) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeSetDatabaseInfoEx(
+ PCEGUID pceguid,
+ CEOID oidDbase,
+ CEDBASEINFO *pNewInfo) = 0;
+
+ virtual HANDLE STDMETHODCALLTYPE CeOpenDatabaseEx(
+ PCEGUID pceguid,
+ PCEOID poid,
+ LPWSTR lpszName,
+ CEPROPID propid,
+ DWORD dwFlags,
+ CENOTIFYREQUEST *pReq) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeDeleteDatabaseEx(
+ PCEGUID pceguid,
+ CEOID oidDbase) = 0;
+
+ virtual CEOID STDMETHODCALLTYPE CeReadRecordPropsEx(
+ HANDLE hDbase,
+ DWORD dwFlags,
+ LPWORD lpcPropID,
+ CEPROPID *rgPropID,
+ LPBYTE *lplpBuffer,
+ LPDWORD lpcbBuffer,
+ HANDLE hHeap) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeMountDBVol(
+ PCEGUID pceguid,
+ LPWSTR lpszDBVol,
+ DWORD dwFlags) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeUnmountDBVol(
+ PCEGUID pceguid) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeFlushDBVol(
+ PCEGUID pceguid) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeEnumDBVolumes(
+ PCEGUID pceguid,
+ LPWSTR lpBuf,
+ DWORD dwNumChars) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeOidGetInfoEx(
+ PCEGUID pceguid,
+ CEOID oid,
+ CEOIDINFO *oidInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CeSyncStart(
+ LPCWSTR szCommand) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CeSyncStop( void) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeQueryInstructionSet(
+ DWORD dwInstructionSet,
+ LPDWORD lpdwCurrentInstructionSet) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE CeGetDiskFreeSpaceEx(
+ LPCWSTR lpDirectoryName,
+ ULARGE_INTEGER *lpFreeBytesAvailableToCaller,
+ ULARGE_INTEGER *lpTotalNumberOfBytes,
+ ULARGE_INTEGER *lpTotalNumberOfFreeBytes) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IRAPISessionVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IRAPISession * This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IRAPISession * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IRAPISession * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CeRapiInit )(
+ IRAPISession * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CeRapiUninit )(
+ IRAPISession * This);
+
+ DWORD ( STDMETHODCALLTYPE *CeGetLastError )(
+ IRAPISession * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CeRapiGetError )(
+ IRAPISession * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CeRapiFreeBuffer )(
+ IRAPISession * This,
+ void *Buffer);
+
+ HANDLE ( STDMETHODCALLTYPE *CeFindFirstFile )(
+ IRAPISession * This,
+ LPCWSTR FileName,
+ LPCE_FIND_DATA FindData);
+
+ BOOL ( STDMETHODCALLTYPE *CeFindNextFile )(
+ IRAPISession * This,
+ HANDLE FoundFile,
+ LPCE_FIND_DATA FindData);
+
+ BOOL ( STDMETHODCALLTYPE *CeFindClose )(
+ IRAPISession * This,
+ HANDLE FoundFile);
+
+ DWORD ( STDMETHODCALLTYPE *CeGetFileAttributes )(
+ IRAPISession * This,
+ LPCWSTR FileName);
+
+ BOOL ( STDMETHODCALLTYPE *CeSetFileAttributes )(
+ IRAPISession * This,
+ LPCWSTR FileName,
+ DWORD FileAttrib);
+
+ HANDLE ( STDMETHODCALLTYPE *CeCreateFile )(
+ IRAPISession * This,
+ LPCWSTR lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDistribution,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile);
+
+ BOOL ( STDMETHODCALLTYPE *CeReadFile )(
+ IRAPISession * This,
+ HANDLE hFile,
+ LPVOID lpBuffer,
+ DWORD nNumberOfBytesToRead,
+ LPDWORD lpNumberOfBytesRead,
+ LPOVERLAPPED lpOverlapped);
+
+ BOOL ( STDMETHODCALLTYPE *CeWriteFile )(
+ IRAPISession * This,
+ HANDLE hFile,
+ LPCVOID lpBuffer,
+ DWORD nNumberOfBytesToWrite,
+ LPDWORD lpNumberOfBytesWritten,
+ LPOVERLAPPED lpOverlapped);
+
+ BOOL ( STDMETHODCALLTYPE *CeCloseHandle )(
+ IRAPISession * This,
+ HANDLE hObject);
+
+ BOOL ( STDMETHODCALLTYPE *CeFindAllFiles )(
+ IRAPISession * This,
+ LPCWSTR Path,
+ DWORD Flags,
+ LPDWORD pFoundCount,
+ LPLPCE_FIND_DATA ppFindDataArray);
+
+ HANDLE ( STDMETHODCALLTYPE *CeFindFirstDatabase )(
+ IRAPISession * This,
+ DWORD dwDbaseType);
+
+ CEOID ( STDMETHODCALLTYPE *CeFindNextDatabase )(
+ IRAPISession * This,
+ HANDLE hEnum);
+
+ BOOL ( STDMETHODCALLTYPE *CeOidGetInfo )(
+ IRAPISession * This,
+ CEOID oid,
+ CEOIDINFO *oidInfo);
+
+ CEOID ( STDMETHODCALLTYPE *CeCreateDatabase )(
+ IRAPISession * This,
+ LPWSTR lpszName,
+ DWORD dwDbaseType,
+ WORD cNumSortOrder,
+ SORTORDERSPEC *rgSortSpecs);
+
+ HANDLE ( STDMETHODCALLTYPE *CeOpenDatabase )(
+ IRAPISession * This,
+ PCEOID poid,
+ LPWSTR lpszName,
+ CEPROPID propid,
+ DWORD dwFlags,
+ HWND hwndNotify);
+
+ BOOL ( STDMETHODCALLTYPE *CeDeleteDatabase )(
+ IRAPISession * This,
+ CEOID oidDbase);
+
+ CEOID ( STDMETHODCALLTYPE *CeReadRecordProps )(
+ IRAPISession * This,
+ HANDLE hDbase,
+ DWORD dwFlags,
+ LPWORD lpcPropID,
+ CEPROPID *rgPropID,
+ LPBYTE *lplpBuffer,
+ LPDWORD lpcbBuffer);
+
+ CEOID ( STDMETHODCALLTYPE *CeWriteRecordProps )(
+ IRAPISession * This,
+ HANDLE hDbase,
+ CEOID oidRecord,
+ WORD cPropID,
+ CEPROPVAL *rgPropVal);
+
+ BOOL ( STDMETHODCALLTYPE *CeDeleteRecord )(
+ IRAPISession * This,
+ HANDLE hDatabase,
+ CEOID oidRecord);
+
+ CEOID ( STDMETHODCALLTYPE *CeSeekDatabase )(
+ IRAPISession * This,
+ HANDLE hDatabase,
+ DWORD dwSeekType,
+ DWORD dwValue,
+ LPDWORD lpdwIndex);
+
+ BOOL ( STDMETHODCALLTYPE *CeSetDatabaseInfo )(
+ IRAPISession * This,
+ CEOID oidDbase,
+ CEDBASEINFO *pNewInfo);
+
+ DWORD ( STDMETHODCALLTYPE *CeSetFilePointer )(
+ IRAPISession * This,
+ HANDLE hFile,
+ LONG lDistanceToMove,
+ PLONG lpDistanceToMoveHigh,
+ DWORD dwMoveMethod);
+
+ BOOL ( STDMETHODCALLTYPE *CeSetEndOfFile )(
+ IRAPISession * This,
+ HANDLE hFile);
+
+ BOOL ( STDMETHODCALLTYPE *CeCreateDirectory )(
+ IRAPISession * This,
+ LPCWSTR lpPathName,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes);
+
+ BOOL ( STDMETHODCALLTYPE *CeRemoveDirectory )(
+ IRAPISession * This,
+ LPCWSTR lpPathName);
+
+ BOOL ( STDMETHODCALLTYPE *CeCreateProcess )(
+ IRAPISession * This,
+ LPCWSTR lpszImageName,
+ LPCWSTR lpszCmdLine,
+ LPSECURITY_ATTRIBUTES lpsaProcess,
+ LPSECURITY_ATTRIBUTES lpsaThread,
+ BOOL fInheritHandles,
+ DWORD fdwCreate,
+ LPVOID lpvEnvironment,
+ LPWSTR lpszCurDir,
+ LPSTARTUPINFOW lpsiStartInfo,
+ LPPROCESS_INFORMATION lppiProcInfo);
+
+ BOOL ( STDMETHODCALLTYPE *CeMoveFile )(
+ IRAPISession * This,
+ LPCWSTR lpExistingFileName,
+ LPCWSTR lpNewFileName);
+
+ BOOL ( STDMETHODCALLTYPE *CeCopyFile )(
+ IRAPISession * This,
+ LPCWSTR lpExistingFileName,
+ LPCWSTR lpNewFileName,
+ BOOL bFailIfExists);
+
+ BOOL ( STDMETHODCALLTYPE *CeDeleteFile )(
+ IRAPISession * This,
+ LPCWSTR FileName);
+
+ DWORD ( STDMETHODCALLTYPE *CeGetFileSize )(
+ IRAPISession * This,
+ HANDLE hFile,
+ LPDWORD lpFileSizeHigh);
+
+ LONG ( STDMETHODCALLTYPE *CeRegOpenKeyEx )(
+ IRAPISession * This,
+ HKEY hKey,
+ LPCWSTR lpszSubKey,
+ DWORD dwReserved,
+ REGSAM samDesired,
+ PHKEY phkResult);
+
+ LONG ( STDMETHODCALLTYPE *CeRegEnumKeyEx )(
+ IRAPISession * This,
+ HKEY hKey,
+ DWORD dwIndex,
+ LPWSTR lpName,
+ LPDWORD lpcbName,
+ LPDWORD lpReserved,
+ LPWSTR lpClass,
+ LPDWORD lpcbClass,
+ PFILETIME lpftLastWriteTime);
+
+ LONG ( STDMETHODCALLTYPE *CeRegCreateKeyEx )(
+ IRAPISession * This,
+ HKEY hKey,
+ LPCWSTR lpszSubKey,
+ DWORD dwReserved,
+ LPWSTR lpszClass,
+ DWORD fdwOptions,
+ REGSAM samDesired,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ PHKEY phkResult,
+ LPDWORD lpdwDisposition);
+
+ LONG ( STDMETHODCALLTYPE *CeRegCloseKey )(
+ IRAPISession * This,
+ HKEY hKey);
+
+ LONG ( STDMETHODCALLTYPE *CeRegDeleteKey )(
+ IRAPISession * This,
+ HKEY hKey,
+ LPCWSTR lpszSubKey);
+
+ LONG ( STDMETHODCALLTYPE *CeRegEnumValue )(
+ IRAPISession * This,
+ HKEY hKey,
+ DWORD dwIndex,
+ LPWSTR lpszValueName,
+ LPDWORD lpcbValueName,
+ LPDWORD lpReserved,
+ LPDWORD lpType,
+ LPBYTE lpData,
+ LPDWORD lpcbData);
+
+ LONG ( STDMETHODCALLTYPE *CeRegDeleteValue )(
+ IRAPISession * This,
+ HKEY hKey,
+ LPCWSTR lpszValueName);
+
+ LONG ( STDMETHODCALLTYPE *CeRegQueryInfoKey )(
+ IRAPISession * This,
+ HKEY hKey,
+ LPWSTR lpClass,
+ LPDWORD lpcbClass,
+ LPDWORD lpReserved,
+ LPDWORD lpcSubKeys,
+ LPDWORD lpcbMaxSubKeyLen,
+ LPDWORD lpcbMaxClassLen,
+ LPDWORD lpcValues,
+ LPDWORD lpcbMaxValueNameLen,
+ LPDWORD lpcbMaxValueLen,
+ LPDWORD lpcbSecurityDescriptor,
+ PFILETIME lpftLastWriteTime);
+
+ LONG ( STDMETHODCALLTYPE *CeRegQueryValueEx )(
+ IRAPISession * This,
+ HKEY hKey,
+ LPCWSTR lpValueName,
+ LPDWORD lpReserved,
+ LPDWORD lpType,
+ LPBYTE lpData,
+ LPDWORD lpcbData);
+
+ LONG ( STDMETHODCALLTYPE *CeRegSetValueEx )(
+ IRAPISession * This,
+ HKEY hKey,
+ LPCWSTR lpValueName,
+ DWORD Reserved,
+ DWORD dwType,
+ BYTE *lpData,
+ DWORD cbData);
+
+ BOOL ( STDMETHODCALLTYPE *CeGetStoreInformation )(
+ IRAPISession * This,
+ LPSTORE_INFORMATION lpsi);
+
+ INT ( STDMETHODCALLTYPE *CeGetSystemMetrics )(
+ IRAPISession * This,
+ INT nIndex);
+
+ INT ( STDMETHODCALLTYPE *CeGetDesktopDeviceCaps )(
+ IRAPISession * This,
+ INT nIndex);
+
+ BOOL ( STDMETHODCALLTYPE *CeFindAllDatabases )(
+ IRAPISession * This,
+ DWORD DbaseType,
+ WORD Flags,
+ LPWORD cFindData,
+ LPLPCEDB_FIND_DATA ppFindData);
+
+ void ( STDMETHODCALLTYPE *CeGetSystemInfo )(
+ IRAPISession * This,
+ LPSYSTEM_INFO lpSystemInfo);
+
+ BOOL ( STDMETHODCALLTYPE *CeSHCreateShortcut )(
+ IRAPISession * This,
+ LPWSTR lpszShortcut,
+ LPWSTR lpszTarget);
+
+ BOOL ( STDMETHODCALLTYPE *CeSHGetShortcutTarget )(
+ IRAPISession * This,
+ LPWSTR lpszShortcut,
+ LPWSTR lpszTarget,
+ int cbMax);
+
+ BOOL ( STDMETHODCALLTYPE *CeCheckPassword )(
+ IRAPISession * This,
+ LPWSTR lpszPassword);
+
+ BOOL ( STDMETHODCALLTYPE *CeGetFileTime )(
+ IRAPISession * This,
+ HANDLE hFile,
+ LPFILETIME lpCreationTime,
+ LPFILETIME lpLastAccessTime,
+ LPFILETIME lpLastWriteTime);
+
+ BOOL ( STDMETHODCALLTYPE *CeSetFileTime )(
+ IRAPISession * This,
+ HANDLE hFile,
+ FILETIME *lpCreationTime,
+ FILETIME *lpLastAccessTime,
+ FILETIME *lpLastWriteTime);
+
+ BOOL ( STDMETHODCALLTYPE *CeGetVersionEx )(
+ IRAPISession * This,
+ LPCEOSVERSIONINFO lpVersionInformation);
+
+ HWND ( STDMETHODCALLTYPE *CeGetWindow )(
+ IRAPISession * This,
+ HWND hWnd,
+ UINT uCmd);
+
+ LONG ( STDMETHODCALLTYPE *CeGetWindowLong )(
+ IRAPISession * This,
+ HWND hWnd,
+ int nIndex);
+
+ INT ( STDMETHODCALLTYPE *CeGetWindowText )(
+ IRAPISession * This,
+ HWND hWnd,
+ LPWSTR lpString,
+ int nMaxCount);
+
+ INT ( STDMETHODCALLTYPE *CeGetClassName )(
+ IRAPISession * This,
+ HWND hWnd,
+ LPWSTR lpClassName,
+ int nMaxCount);
+
+ void ( STDMETHODCALLTYPE *CeGlobalMemoryStatus )(
+ IRAPISession * This,
+ LPMEMORYSTATUS lpmst);
+
+ BOOL ( STDMETHODCALLTYPE *CeGetSystemPowerStatusEx )(
+ IRAPISession * This,
+ PSYSTEM_POWER_STATUS_EX pstatus,
+ BOOL fUpdate);
+
+ DWORD ( STDMETHODCALLTYPE *CeGetTempPath )(
+ IRAPISession * This,
+ DWORD nBufferLength,
+ LPWSTR lpBuffer);
+
+ DWORD ( STDMETHODCALLTYPE *CeGetSpecialFolderPath )(
+ IRAPISession * This,
+ int nFolder,
+ DWORD nBufferLength,
+ LPWSTR lpBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *CeRapiInvoke )(
+ IRAPISession * This,
+ LPCWSTR pDllPath,
+ LPCWSTR pFunctionName,
+ DWORD cbInput,
+ BYTE *pInput,
+ DWORD *pcbOutput,
+ BYTE **ppOutput,
+ IRAPIStream **ppIRAPIStream,
+ DWORD dwReserved);
+
+ HANDLE ( STDMETHODCALLTYPE *CeFindFirstDatabaseEx )(
+ IRAPISession * This,
+ PCEGUID pguid,
+ DWORD dwDbaseType);
+
+ CEOID ( STDMETHODCALLTYPE *CeFindNextDatabaseEx )(
+ IRAPISession * This,
+ HANDLE hEnum,
+ PCEGUID pguid);
+
+ CEOID ( STDMETHODCALLTYPE *CeCreateDatabaseEx )(
+ IRAPISession * This,
+ PCEGUID pceguid,
+ CEDBASEINFO *lpCEDBInfo);
+
+ BOOL ( STDMETHODCALLTYPE *CeSetDatabaseInfoEx )(
+ IRAPISession * This,
+ PCEGUID pceguid,
+ CEOID oidDbase,
+ CEDBASEINFO *pNewInfo);
+
+ HANDLE ( STDMETHODCALLTYPE *CeOpenDatabaseEx )(
+ IRAPISession * This,
+ PCEGUID pceguid,
+ PCEOID poid,
+ LPWSTR lpszName,
+ CEPROPID propid,
+ DWORD dwFlags,
+ CENOTIFYREQUEST *pReq);
+
+ BOOL ( STDMETHODCALLTYPE *CeDeleteDatabaseEx )(
+ IRAPISession * This,
+ PCEGUID pceguid,
+ CEOID oidDbase);
+
+ CEOID ( STDMETHODCALLTYPE *CeReadRecordPropsEx )(
+ IRAPISession * This,
+ HANDLE hDbase,
+ DWORD dwFlags,
+ LPWORD lpcPropID,
+ CEPROPID *rgPropID,
+ LPBYTE *lplpBuffer,
+ LPDWORD lpcbBuffer,
+ HANDLE hHeap);
+
+ BOOL ( STDMETHODCALLTYPE *CeMountDBVol )(
+ IRAPISession * This,
+ PCEGUID pceguid,
+ LPWSTR lpszDBVol,
+ DWORD dwFlags);
+
+ BOOL ( STDMETHODCALLTYPE *CeUnmountDBVol )(
+ IRAPISession * This,
+ PCEGUID pceguid);
+
+ BOOL ( STDMETHODCALLTYPE *CeFlushDBVol )(
+ IRAPISession * This,
+ PCEGUID pceguid);
+
+ BOOL ( STDMETHODCALLTYPE *CeEnumDBVolumes )(
+ IRAPISession * This,
+ PCEGUID pceguid,
+ LPWSTR lpBuf,
+ DWORD dwNumChars);
+
+ BOOL ( STDMETHODCALLTYPE *CeOidGetInfoEx )(
+ IRAPISession * This,
+ PCEGUID pceguid,
+ CEOID oid,
+ CEOIDINFO *oidInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *CeSyncStart )(
+ IRAPISession * This,
+ LPCWSTR szCommand);
+
+ HRESULT ( STDMETHODCALLTYPE *CeSyncStop )(
+ IRAPISession * This);
+
+ BOOL ( STDMETHODCALLTYPE *CeQueryInstructionSet )(
+ IRAPISession * This,
+ DWORD dwInstructionSet,
+ LPDWORD lpdwCurrentInstructionSet);
+
+ BOOL ( STDMETHODCALLTYPE *CeGetDiskFreeSpaceEx )(
+ IRAPISession * This,
+ LPCWSTR lpDirectoryName,
+ ULARGE_INTEGER *lpFreeBytesAvailableToCaller,
+ ULARGE_INTEGER *lpTotalNumberOfBytes,
+ ULARGE_INTEGER *lpTotalNumberOfFreeBytes);
+
+ END_INTERFACE
+ } IRAPISessionVtbl;
+
+ interface IRAPISession
+ {
+ CONST_VTBL struct IRAPISessionVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IRAPISession_QueryInterface(This,riid,ppvObject) \
+ (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define IRAPISession_AddRef(This) \
+ (This)->lpVtbl -> AddRef(This)
+
+#define IRAPISession_Release(This) \
+ (This)->lpVtbl -> Release(This)
+
+
+#define IRAPISession_CeRapiInit(This) \
+ (This)->lpVtbl -> CeRapiInit(This)
+
+#define IRAPISession_CeRapiUninit(This) \
+ (This)->lpVtbl -> CeRapiUninit(This)
+
+#define IRAPISession_CeGetLastError(This) \
+ (This)->lpVtbl -> CeGetLastError(This)
+
+#define IRAPISession_CeRapiGetError(This) \
+ (This)->lpVtbl -> CeRapiGetError(This)
+
+#define IRAPISession_CeRapiFreeBuffer(This,Buffer) \
+ (This)->lpVtbl -> CeRapiFreeBuffer(This,Buffer)
+
+#define IRAPISession_CeFindFirstFile(This,FileName,FindData) \
+ (This)->lpVtbl -> CeFindFirstFile(This,FileName,FindData)
+
+#define IRAPISession_CeFindNextFile(This,FoundFile,FindData) \
+ (This)->lpVtbl -> CeFindNextFile(This,FoundFile,FindData)
+
+#define IRAPISession_CeFindClose(This,FoundFile) \
+ (This)->lpVtbl -> CeFindClose(This,FoundFile)
+
+#define IRAPISession_CeGetFileAttributes(This,FileName) \
+ (This)->lpVtbl -> CeGetFileAttributes(This,FileName)
+
+#define IRAPISession_CeSetFileAttributes(This,FileName,FileAttrib) \
+ (This)->lpVtbl -> CeSetFileAttributes(This,FileName,FileAttrib)
+
+#define IRAPISession_CeCreateFile(This,lpFileName,dwDesiredAccess,dwShareMode,lpSecurityAttributes,dwCreationDistribution,dwFlagsAndAttributes,hTemplateFile) \
+ (This)->lpVtbl -> CeCreateFile(This,lpFileName,dwDesiredAccess,dwShareMode,lpSecurityAttributes,dwCreationDistribution,dwFlagsAndAttributes,hTemplateFile)
+
+#define IRAPISession_CeReadFile(This,hFile,lpBuffer,nNumberOfBytesToRead,lpNumberOfBytesRead,lpOverlapped) \
+ (This)->lpVtbl -> CeReadFile(This,hFile,lpBuffer,nNumberOfBytesToRead,lpNumberOfBytesRead,lpOverlapped)
+
+#define IRAPISession_CeWriteFile(This,hFile,lpBuffer,nNumberOfBytesToWrite,lpNumberOfBytesWritten,lpOverlapped) \
+ (This)->lpVtbl -> CeWriteFile(This,hFile,lpBuffer,nNumberOfBytesToWrite,lpNumberOfBytesWritten,lpOverlapped)
+
+#define IRAPISession_CeCloseHandle(This,hObject) \
+ (This)->lpVtbl -> CeCloseHandle(This,hObject)
+
+#define IRAPISession_CeFindAllFiles(This,Path,Flags,pFoundCount,ppFindDataArray) \
+ (This)->lpVtbl -> CeFindAllFiles(This,Path,Flags,pFoundCount,ppFindDataArray)
+
+#define IRAPISession_CeFindFirstDatabase(This,dwDbaseType) \
+ (This)->lpVtbl -> CeFindFirstDatabase(This,dwDbaseType)
+
+#define IRAPISession_CeFindNextDatabase(This,hEnum) \
+ (This)->lpVtbl -> CeFindNextDatabase(This,hEnum)
+
+#define IRAPISession_CeOidGetInfo(This,oid,oidInfo) \
+ (This)->lpVtbl -> CeOidGetInfo(This,oid,oidInfo)
+
+#define IRAPISession_CeCreateDatabase(This,lpszName,dwDbaseType,cNumSortOrder,rgSortSpecs) \
+ (This)->lpVtbl -> CeCreateDatabase(This,lpszName,dwDbaseType,cNumSortOrder,rgSortSpecs)
+
+#define IRAPISession_CeOpenDatabase(This,poid,lpszName,propid,dwFlags,hwndNotify) \
+ (This)->lpVtbl -> CeOpenDatabase(This,poid,lpszName,propid,dwFlags,hwndNotify)
+
+#define IRAPISession_CeDeleteDatabase(This,oidDbase) \
+ (This)->lpVtbl -> CeDeleteDatabase(This,oidDbase)
+
+#define IRAPISession_CeReadRecordProps(This,hDbase,dwFlags,lpcPropID,rgPropID,lplpBuffer,lpcbBuffer) \
+ (This)->lpVtbl -> CeReadRecordProps(This,hDbase,dwFlags,lpcPropID,rgPropID,lplpBuffer,lpcbBuffer)
+
+#define IRAPISession_CeWriteRecordProps(This,hDbase,oidRecord,cPropID,rgPropVal) \
+ (This)->lpVtbl -> CeWriteRecordProps(This,hDbase,oidRecord,cPropID,rgPropVal)
+
+#define IRAPISession_CeDeleteRecord(This,hDatabase,oidRecord) \
+ (This)->lpVtbl -> CeDeleteRecord(This,hDatabase,oidRecord)
+
+#define IRAPISession_CeSeekDatabase(This,hDatabase,dwSeekType,dwValue,lpdwIndex) \
+ (This)->lpVtbl -> CeSeekDatabase(This,hDatabase,dwSeekType,dwValue,lpdwIndex)
+
+#define IRAPISession_CeSetDatabaseInfo(This,oidDbase,pNewInfo) \
+ (This)->lpVtbl -> CeSetDatabaseInfo(This,oidDbase,pNewInfo)
+
+#define IRAPISession_CeSetFilePointer(This,hFile,lDistanceToMove,lpDistanceToMoveHigh,dwMoveMethod) \
+ (This)->lpVtbl -> CeSetFilePointer(This,hFile,lDistanceToMove,lpDistanceToMoveHigh,dwMoveMethod)
+
+#define IRAPISession_CeSetEndOfFile(This,hFile) \
+ (This)->lpVtbl -> CeSetEndOfFile(This,hFile)
+
+#define IRAPISession_CeCreateDirectory(This,lpPathName,lpSecurityAttributes) \
+ (This)->lpVtbl -> CeCreateDirectory(This,lpPathName,lpSecurityAttributes)
+
+#define IRAPISession_CeRemoveDirectory(This,lpPathName) \
+ (This)->lpVtbl -> CeRemoveDirectory(This,lpPathName)
+
+#define IRAPISession_CeCreateProcess(This,lpszImageName,lpszCmdLine,lpsaProcess,lpsaThread,fInheritHandles,fdwCreate,lpvEnvironment,lpszCurDir,lpsiStartInfo,lppiProcInfo) \
+ (This)->lpVtbl -> CeCreateProcess(This,lpszImageName,lpszCmdLine,lpsaProcess,lpsaThread,fInheritHandles,fdwCreate,lpvEnvironment,lpszCurDir,lpsiStartInfo,lppiProcInfo)
+
+#define IRAPISession_CeMoveFile(This,lpExistingFileName,lpNewFileName) \
+ (This)->lpVtbl -> CeMoveFile(This,lpExistingFileName,lpNewFileName)
+
+#define IRAPISession_CeCopyFile(This,lpExistingFileName,lpNewFileName,bFailIfExists) \
+ (This)->lpVtbl -> CeCopyFile(This,lpExistingFileName,lpNewFileName,bFailIfExists)
+
+#define IRAPISession_CeDeleteFile(This,FileName) \
+ (This)->lpVtbl -> CeDeleteFile(This,FileName)
+
+#define IRAPISession_CeGetFileSize(This,hFile,lpFileSizeHigh) \
+ (This)->lpVtbl -> CeGetFileSize(This,hFile,lpFileSizeHigh)
+
+#define IRAPISession_CeRegOpenKeyEx(This,hKey,lpszSubKey,dwReserved,samDesired,phkResult) \
+ (This)->lpVtbl -> CeRegOpenKeyEx(This,hKey,lpszSubKey,dwReserved,samDesired,phkResult)
+
+#define IRAPISession_CeRegEnumKeyEx(This,hKey,dwIndex,lpName,lpcbName,lpReserved,lpClass,lpcbClass,lpftLastWriteTime) \
+ (This)->lpVtbl -> CeRegEnumKeyEx(This,hKey,dwIndex,lpName,lpcbName,lpReserved,lpClass,lpcbClass,lpftLastWriteTime)
+
+#define IRAPISession_CeRegCreateKeyEx(This,hKey,lpszSubKey,dwReserved,lpszClass,fdwOptions,samDesired,lpSecurityAttributes,phkResult,lpdwDisposition) \
+ (This)->lpVtbl -> CeRegCreateKeyEx(This,hKey,lpszSubKey,dwReserved,lpszClass,fdwOptions,samDesired,lpSecurityAttributes,phkResult,lpdwDisposition)
+
+#define IRAPISession_CeRegCloseKey(This,hKey) \
+ (This)->lpVtbl -> CeRegCloseKey(This,hKey)
+
+#define IRAPISession_CeRegDeleteKey(This,hKey,lpszSubKey) \
+ (This)->lpVtbl -> CeRegDeleteKey(This,hKey,lpszSubKey)
+
+#define IRAPISession_CeRegEnumValue(This,hKey,dwIndex,lpszValueName,lpcbValueName,lpReserved,lpType,lpData,lpcbData) \
+ (This)->lpVtbl -> CeRegEnumValue(This,hKey,dwIndex,lpszValueName,lpcbValueName,lpReserved,lpType,lpData,lpcbData)
+
+#define IRAPISession_CeRegDeleteValue(This,hKey,lpszValueName) \
+ (This)->lpVtbl -> CeRegDeleteValue(This,hKey,lpszValueName)
+
+#define IRAPISession_CeRegQueryInfoKey(This,hKey,lpClass,lpcbClass,lpReserved,lpcSubKeys,lpcbMaxSubKeyLen,lpcbMaxClassLen,lpcValues,lpcbMaxValueNameLen,lpcbMaxValueLen,lpcbSecurityDescriptor,lpftLastWriteTime) \
+ (This)->lpVtbl -> CeRegQueryInfoKey(This,hKey,lpClass,lpcbClass,lpReserved,lpcSubKeys,lpcbMaxSubKeyLen,lpcbMaxClassLen,lpcValues,lpcbMaxValueNameLen,lpcbMaxValueLen,lpcbSecurityDescriptor,lpftLastWriteTime)
+
+#define IRAPISession_CeRegQueryValueEx(This,hKey,lpValueName,lpReserved,lpType,lpData,lpcbData) \
+ (This)->lpVtbl -> CeRegQueryValueEx(This,hKey,lpValueName,lpReserved,lpType,lpData,lpcbData)
+
+#define IRAPISession_CeRegSetValueEx(This,hKey,lpValueName,Reserved,dwType,lpData,cbData) \
+ (This)->lpVtbl -> CeRegSetValueEx(This,hKey,lpValueName,Reserved,dwType,lpData,cbData)
+
+#define IRAPISession_CeGetStoreInformation(This,lpsi) \
+ (This)->lpVtbl -> CeGetStoreInformation(This,lpsi)
+
+#define IRAPISession_CeGetSystemMetrics(This,nIndex) \
+ (This)->lpVtbl -> CeGetSystemMetrics(This,nIndex)
+
+#define IRAPISession_CeGetDesktopDeviceCaps(This,nIndex) \
+ (This)->lpVtbl -> CeGetDesktopDeviceCaps(This,nIndex)
+
+#define IRAPISession_CeFindAllDatabases(This,DbaseType,Flags,cFindData,ppFindData) \
+ (This)->lpVtbl -> CeFindAllDatabases(This,DbaseType,Flags,cFindData,ppFindData)
+
+#define IRAPISession_CeGetSystemInfo(This,lpSystemInfo) \
+ (This)->lpVtbl -> CeGetSystemInfo(This,lpSystemInfo)
+
+#define IRAPISession_CeSHCreateShortcut(This,lpszShortcut,lpszTarget) \
+ (This)->lpVtbl -> CeSHCreateShortcut(This,lpszShortcut,lpszTarget)
+
+#define IRAPISession_CeSHGetShortcutTarget(This,lpszShortcut,lpszTarget,cbMax) \
+ (This)->lpVtbl -> CeSHGetShortcutTarget(This,lpszShortcut,lpszTarget,cbMax)
+
+#define IRAPISession_CeCheckPassword(This,lpszPassword) \
+ (This)->lpVtbl -> CeCheckPassword(This,lpszPassword)
+
+#define IRAPISession_CeGetFileTime(This,hFile,lpCreationTime,lpLastAccessTime,lpLastWriteTime) \
+ (This)->lpVtbl -> CeGetFileTime(This,hFile,lpCreationTime,lpLastAccessTime,lpLastWriteTime)
+
+#define IRAPISession_CeSetFileTime(This,hFile,lpCreationTime,lpLastAccessTime,lpLastWriteTime) \
+ (This)->lpVtbl -> CeSetFileTime(This,hFile,lpCreationTime,lpLastAccessTime,lpLastWriteTime)
+
+#define IRAPISession_CeGetVersionEx(This,lpVersionInformation) \
+ (This)->lpVtbl -> CeGetVersionEx(This,lpVersionInformation)
+
+#define IRAPISession_CeGetWindow(This,hWnd,uCmd) \
+ (This)->lpVtbl -> CeGetWindow(This,hWnd,uCmd)
+
+#define IRAPISession_CeGetWindowLong(This,hWnd,nIndex) \
+ (This)->lpVtbl -> CeGetWindowLong(This,hWnd,nIndex)
+
+#define IRAPISession_CeGetWindowText(This,hWnd,lpString,nMaxCount) \
+ (This)->lpVtbl -> CeGetWindowText(This,hWnd,lpString,nMaxCount)
+
+#define IRAPISession_CeGetClassName(This,hWnd,lpClassName,nMaxCount) \
+ (This)->lpVtbl -> CeGetClassName(This,hWnd,lpClassName,nMaxCount)
+
+#define IRAPISession_CeGlobalMemoryStatus(This,lpmst) \
+ (This)->lpVtbl -> CeGlobalMemoryStatus(This,lpmst)
+
+#define IRAPISession_CeGetSystemPowerStatusEx(This,pstatus,fUpdate) \
+ (This)->lpVtbl -> CeGetSystemPowerStatusEx(This,pstatus,fUpdate)
+
+#define IRAPISession_CeGetTempPath(This,nBufferLength,lpBuffer) \
+ (This)->lpVtbl -> CeGetTempPath(This,nBufferLength,lpBuffer)
+
+#define IRAPISession_CeGetSpecialFolderPath(This,nFolder,nBufferLength,lpBuffer) \
+ (This)->lpVtbl -> CeGetSpecialFolderPath(This,nFolder,nBufferLength,lpBuffer)
+
+#define IRAPISession_CeRapiInvoke(This,pDllPath,pFunctionName,cbInput,pInput,pcbOutput,ppOutput,ppIRAPIStream,dwReserved) \
+ (This)->lpVtbl -> CeRapiInvoke(This,pDllPath,pFunctionName,cbInput,pInput,pcbOutput,ppOutput,ppIRAPIStream,dwReserved)
+
+#define IRAPISession_CeFindFirstDatabaseEx(This,pguid,dwDbaseType) \
+ (This)->lpVtbl -> CeFindFirstDatabaseEx(This,pguid,dwDbaseType)
+
+#define IRAPISession_CeFindNextDatabaseEx(This,hEnum,pguid) \
+ (This)->lpVtbl -> CeFindNextDatabaseEx(This,hEnum,pguid)
+
+#define IRAPISession_CeCreateDatabaseEx(This,pceguid,lpCEDBInfo) \
+ (This)->lpVtbl -> CeCreateDatabaseEx(This,pceguid,lpCEDBInfo)
+
+#define IRAPISession_CeSetDatabaseInfoEx(This,pceguid,oidDbase,pNewInfo) \
+ (This)->lpVtbl -> CeSetDatabaseInfoEx(This,pceguid,oidDbase,pNewInfo)
+
+#define IRAPISession_CeOpenDatabaseEx(This,pceguid,poid,lpszName,propid,dwFlags,pReq) \
+ (This)->lpVtbl -> CeOpenDatabaseEx(This,pceguid,poid,lpszName,propid,dwFlags,pReq)
+
+#define IRAPISession_CeDeleteDatabaseEx(This,pceguid,oidDbase) \
+ (This)->lpVtbl -> CeDeleteDatabaseEx(This,pceguid,oidDbase)
+
+#define IRAPISession_CeReadRecordPropsEx(This,hDbase,dwFlags,lpcPropID,rgPropID,lplpBuffer,lpcbBuffer,hHeap) \
+ (This)->lpVtbl -> CeReadRecordPropsEx(This,hDbase,dwFlags,lpcPropID,rgPropID,lplpBuffer,lpcbBuffer,hHeap)
+
+#define IRAPISession_CeMountDBVol(This,pceguid,lpszDBVol,dwFlags) \
+ (This)->lpVtbl -> CeMountDBVol(This,pceguid,lpszDBVol,dwFlags)
+
+#define IRAPISession_CeUnmountDBVol(This,pceguid) \
+ (This)->lpVtbl -> CeUnmountDBVol(This,pceguid)
+
+#define IRAPISession_CeFlushDBVol(This,pceguid) \
+ (This)->lpVtbl -> CeFlushDBVol(This,pceguid)
+
+#define IRAPISession_CeEnumDBVolumes(This,pceguid,lpBuf,dwNumChars) \
+ (This)->lpVtbl -> CeEnumDBVolumes(This,pceguid,lpBuf,dwNumChars)
+
+#define IRAPISession_CeOidGetInfoEx(This,pceguid,oid,oidInfo) \
+ (This)->lpVtbl -> CeOidGetInfoEx(This,pceguid,oid,oidInfo)
+
+#define IRAPISession_CeSyncStart(This,szCommand) \
+ (This)->lpVtbl -> CeSyncStart(This,szCommand)
+
+#define IRAPISession_CeSyncStop(This) \
+ (This)->lpVtbl -> CeSyncStop(This)
+
+#define IRAPISession_CeQueryInstructionSet(This,dwInstructionSet,lpdwCurrentInstructionSet) \
+ (This)->lpVtbl -> CeQueryInstructionSet(This,dwInstructionSet,lpdwCurrentInstructionSet)
+
+#define IRAPISession_CeGetDiskFreeSpaceEx(This,lpDirectoryName,lpFreeBytesAvailableToCaller,lpTotalNumberOfBytes,lpTotalNumberOfFreeBytes) \
+ (This)->lpVtbl -> CeGetDiskFreeSpaceEx(This,lpDirectoryName,lpFreeBytesAvailableToCaller,lpTotalNumberOfBytes,lpTotalNumberOfFreeBytes)
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+HRESULT STDMETHODCALLTYPE IRAPISession_CeRapiInit_Proxy(
+ IRAPISession * This);
+
+
+void __RPC_STUB IRAPISession_CeRapiInit_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPISession_CeRapiUninit_Proxy(
+ IRAPISession * This);
+
+
+void __RPC_STUB IRAPISession_CeRapiUninit_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+DWORD STDMETHODCALLTYPE IRAPISession_CeGetLastError_Proxy(
+ IRAPISession * This);
+
+
+void __RPC_STUB IRAPISession_CeGetLastError_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPISession_CeRapiGetError_Proxy(
+ IRAPISession * This);
+
+
+void __RPC_STUB IRAPISession_CeRapiGetError_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPISession_CeRapiFreeBuffer_Proxy(
+ IRAPISession * This,
+ void *Buffer);
+
+
+void __RPC_STUB IRAPISession_CeRapiFreeBuffer_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HANDLE STDMETHODCALLTYPE IRAPISession_CeFindFirstFile_Proxy(
+ IRAPISession * This,
+ LPCWSTR FileName,
+ LPCE_FIND_DATA FindData);
+
+
+void __RPC_STUB IRAPISession_CeFindFirstFile_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeFindNextFile_Proxy(
+ IRAPISession * This,
+ HANDLE FoundFile,
+ LPCE_FIND_DATA FindData);
+
+
+void __RPC_STUB IRAPISession_CeFindNextFile_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeFindClose_Proxy(
+ IRAPISession * This,
+ HANDLE FoundFile);
+
+
+void __RPC_STUB IRAPISession_CeFindClose_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+DWORD STDMETHODCALLTYPE IRAPISession_CeGetFileAttributes_Proxy(
+ IRAPISession * This,
+ LPCWSTR FileName);
+
+
+void __RPC_STUB IRAPISession_CeGetFileAttributes_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeSetFileAttributes_Proxy(
+ IRAPISession * This,
+ LPCWSTR FileName,
+ DWORD FileAttrib);
+
+
+void __RPC_STUB IRAPISession_CeSetFileAttributes_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HANDLE STDMETHODCALLTYPE IRAPISession_CeCreateFile_Proxy(
+ IRAPISession * This,
+ LPCWSTR lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDistribution,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile);
+
+
+void __RPC_STUB IRAPISession_CeCreateFile_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeReadFile_Proxy(
+ IRAPISession * This,
+ HANDLE hFile,
+ LPVOID lpBuffer,
+ DWORD nNumberOfBytesToRead,
+ LPDWORD lpNumberOfBytesRead,
+ LPOVERLAPPED lpOverlapped);
+
+
+void __RPC_STUB IRAPISession_CeReadFile_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeWriteFile_Proxy(
+ IRAPISession * This,
+ HANDLE hFile,
+ LPCVOID lpBuffer,
+ DWORD nNumberOfBytesToWrite,
+ LPDWORD lpNumberOfBytesWritten,
+ LPOVERLAPPED lpOverlapped);
+
+
+void __RPC_STUB IRAPISession_CeWriteFile_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeCloseHandle_Proxy(
+ IRAPISession * This,
+ HANDLE hObject);
+
+
+void __RPC_STUB IRAPISession_CeCloseHandle_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeFindAllFiles_Proxy(
+ IRAPISession * This,
+ LPCWSTR Path,
+ DWORD Flags,
+ LPDWORD pFoundCount,
+ LPLPCE_FIND_DATA ppFindDataArray);
+
+
+void __RPC_STUB IRAPISession_CeFindAllFiles_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HANDLE STDMETHODCALLTYPE IRAPISession_CeFindFirstDatabase_Proxy(
+ IRAPISession * This,
+ DWORD dwDbaseType);
+
+
+void __RPC_STUB IRAPISession_CeFindFirstDatabase_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+CEOID STDMETHODCALLTYPE IRAPISession_CeFindNextDatabase_Proxy(
+ IRAPISession * This,
+ HANDLE hEnum);
+
+
+void __RPC_STUB IRAPISession_CeFindNextDatabase_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeOidGetInfo_Proxy(
+ IRAPISession * This,
+ CEOID oid,
+ CEOIDINFO *oidInfo);
+
+
+void __RPC_STUB IRAPISession_CeOidGetInfo_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+CEOID STDMETHODCALLTYPE IRAPISession_CeCreateDatabase_Proxy(
+ IRAPISession * This,
+ LPWSTR lpszName,
+ DWORD dwDbaseType,
+ WORD cNumSortOrder,
+ SORTORDERSPEC *rgSortSpecs);
+
+
+void __RPC_STUB IRAPISession_CeCreateDatabase_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HANDLE STDMETHODCALLTYPE IRAPISession_CeOpenDatabase_Proxy(
+ IRAPISession * This,
+ PCEOID poid,
+ LPWSTR lpszName,
+ CEPROPID propid,
+ DWORD dwFlags,
+ HWND hwndNotify);
+
+
+void __RPC_STUB IRAPISession_CeOpenDatabase_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeDeleteDatabase_Proxy(
+ IRAPISession * This,
+ CEOID oidDbase);
+
+
+void __RPC_STUB IRAPISession_CeDeleteDatabase_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+CEOID STDMETHODCALLTYPE IRAPISession_CeReadRecordProps_Proxy(
+ IRAPISession * This,
+ HANDLE hDbase,
+ DWORD dwFlags,
+ LPWORD lpcPropID,
+ CEPROPID *rgPropID,
+ LPBYTE *lplpBuffer,
+ LPDWORD lpcbBuffer);
+
+
+void __RPC_STUB IRAPISession_CeReadRecordProps_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+CEOID STDMETHODCALLTYPE IRAPISession_CeWriteRecordProps_Proxy(
+ IRAPISession * This,
+ HANDLE hDbase,
+ CEOID oidRecord,
+ WORD cPropID,
+ CEPROPVAL *rgPropVal);
+
+
+void __RPC_STUB IRAPISession_CeWriteRecordProps_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeDeleteRecord_Proxy(
+ IRAPISession * This,
+ HANDLE hDatabase,
+ CEOID oidRecord);
+
+
+void __RPC_STUB IRAPISession_CeDeleteRecord_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+CEOID STDMETHODCALLTYPE IRAPISession_CeSeekDatabase_Proxy(
+ IRAPISession * This,
+ HANDLE hDatabase,
+ DWORD dwSeekType,
+ DWORD dwValue,
+ LPDWORD lpdwIndex);
+
+
+void __RPC_STUB IRAPISession_CeSeekDatabase_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeSetDatabaseInfo_Proxy(
+ IRAPISession * This,
+ CEOID oidDbase,
+ CEDBASEINFO *pNewInfo);
+
+
+void __RPC_STUB IRAPISession_CeSetDatabaseInfo_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+DWORD STDMETHODCALLTYPE IRAPISession_CeSetFilePointer_Proxy(
+ IRAPISession * This,
+ HANDLE hFile,
+ LONG lDistanceToMove,
+ PLONG lpDistanceToMoveHigh,
+ DWORD dwMoveMethod);
+
+
+void __RPC_STUB IRAPISession_CeSetFilePointer_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeSetEndOfFile_Proxy(
+ IRAPISession * This,
+ HANDLE hFile);
+
+
+void __RPC_STUB IRAPISession_CeSetEndOfFile_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeCreateDirectory_Proxy(
+ IRAPISession * This,
+ LPCWSTR lpPathName,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes);
+
+
+void __RPC_STUB IRAPISession_CeCreateDirectory_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeRemoveDirectory_Proxy(
+ IRAPISession * This,
+ LPCWSTR lpPathName);
+
+
+void __RPC_STUB IRAPISession_CeRemoveDirectory_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeCreateProcess_Proxy(
+ IRAPISession * This,
+ LPCWSTR lpszImageName,
+ LPCWSTR lpszCmdLine,
+ LPSECURITY_ATTRIBUTES lpsaProcess,
+ LPSECURITY_ATTRIBUTES lpsaThread,
+ BOOL fInheritHandles,
+ DWORD fdwCreate,
+ LPVOID lpvEnvironment,
+ LPWSTR lpszCurDir,
+ LPSTARTUPINFOW lpsiStartInfo,
+ LPPROCESS_INFORMATION lppiProcInfo);
+
+
+void __RPC_STUB IRAPISession_CeCreateProcess_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeMoveFile_Proxy(
+ IRAPISession * This,
+ LPCWSTR lpExistingFileName,
+ LPCWSTR lpNewFileName);
+
+
+void __RPC_STUB IRAPISession_CeMoveFile_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeCopyFile_Proxy(
+ IRAPISession * This,
+ LPCWSTR lpExistingFileName,
+ LPCWSTR lpNewFileName,
+ BOOL bFailIfExists);
+
+
+void __RPC_STUB IRAPISession_CeCopyFile_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeDeleteFile_Proxy(
+ IRAPISession * This,
+ LPCWSTR FileName);
+
+
+void __RPC_STUB IRAPISession_CeDeleteFile_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+DWORD STDMETHODCALLTYPE IRAPISession_CeGetFileSize_Proxy(
+ IRAPISession * This,
+ HANDLE hFile,
+ LPDWORD lpFileSizeHigh);
+
+
+void __RPC_STUB IRAPISession_CeGetFileSize_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+LONG STDMETHODCALLTYPE IRAPISession_CeRegOpenKeyEx_Proxy(
+ IRAPISession * This,
+ HKEY hKey,
+ LPCWSTR lpszSubKey,
+ DWORD dwReserved,
+ REGSAM samDesired,
+ PHKEY phkResult);
+
+
+void __RPC_STUB IRAPISession_CeRegOpenKeyEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+LONG STDMETHODCALLTYPE IRAPISession_CeRegEnumKeyEx_Proxy(
+ IRAPISession * This,
+ HKEY hKey,
+ DWORD dwIndex,
+ LPWSTR lpName,
+ LPDWORD lpcbName,
+ LPDWORD lpReserved,
+ LPWSTR lpClass,
+ LPDWORD lpcbClass,
+ PFILETIME lpftLastWriteTime);
+
+
+void __RPC_STUB IRAPISession_CeRegEnumKeyEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+LONG STDMETHODCALLTYPE IRAPISession_CeRegCreateKeyEx_Proxy(
+ IRAPISession * This,
+ HKEY hKey,
+ LPCWSTR lpszSubKey,
+ DWORD dwReserved,
+ LPWSTR lpszClass,
+ DWORD fdwOptions,
+ REGSAM samDesired,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ PHKEY phkResult,
+ LPDWORD lpdwDisposition);
+
+
+void __RPC_STUB IRAPISession_CeRegCreateKeyEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+LONG STDMETHODCALLTYPE IRAPISession_CeRegCloseKey_Proxy(
+ IRAPISession * This,
+ HKEY hKey);
+
+
+void __RPC_STUB IRAPISession_CeRegCloseKey_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+LONG STDMETHODCALLTYPE IRAPISession_CeRegDeleteKey_Proxy(
+ IRAPISession * This,
+ HKEY hKey,
+ LPCWSTR lpszSubKey);
+
+
+void __RPC_STUB IRAPISession_CeRegDeleteKey_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+LONG STDMETHODCALLTYPE IRAPISession_CeRegEnumValue_Proxy(
+ IRAPISession * This,
+ HKEY hKey,
+ DWORD dwIndex,
+ LPWSTR lpszValueName,
+ LPDWORD lpcbValueName,
+ LPDWORD lpReserved,
+ LPDWORD lpType,
+ LPBYTE lpData,
+ LPDWORD lpcbData);
+
+
+void __RPC_STUB IRAPISession_CeRegEnumValue_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+LONG STDMETHODCALLTYPE IRAPISession_CeRegDeleteValue_Proxy(
+ IRAPISession * This,
+ HKEY hKey,
+ LPCWSTR lpszValueName);
+
+
+void __RPC_STUB IRAPISession_CeRegDeleteValue_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+LONG STDMETHODCALLTYPE IRAPISession_CeRegQueryInfoKey_Proxy(
+ IRAPISession * This,
+ HKEY hKey,
+ LPWSTR lpClass,
+ LPDWORD lpcbClass,
+ LPDWORD lpReserved,
+ LPDWORD lpcSubKeys,
+ LPDWORD lpcbMaxSubKeyLen,
+ LPDWORD lpcbMaxClassLen,
+ LPDWORD lpcValues,
+ LPDWORD lpcbMaxValueNameLen,
+ LPDWORD lpcbMaxValueLen,
+ LPDWORD lpcbSecurityDescriptor,
+ PFILETIME lpftLastWriteTime);
+
+
+void __RPC_STUB IRAPISession_CeRegQueryInfoKey_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+LONG STDMETHODCALLTYPE IRAPISession_CeRegQueryValueEx_Proxy(
+ IRAPISession * This,
+ HKEY hKey,
+ LPCWSTR lpValueName,
+ LPDWORD lpReserved,
+ LPDWORD lpType,
+ LPBYTE lpData,
+ LPDWORD lpcbData);
+
+
+void __RPC_STUB IRAPISession_CeRegQueryValueEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+LONG STDMETHODCALLTYPE IRAPISession_CeRegSetValueEx_Proxy(
+ IRAPISession * This,
+ HKEY hKey,
+ LPCWSTR lpValueName,
+ DWORD Reserved,
+ DWORD dwType,
+ BYTE *lpData,
+ DWORD cbData);
+
+
+void __RPC_STUB IRAPISession_CeRegSetValueEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeGetStoreInformation_Proxy(
+ IRAPISession * This,
+ LPSTORE_INFORMATION lpsi);
+
+
+void __RPC_STUB IRAPISession_CeGetStoreInformation_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+INT STDMETHODCALLTYPE IRAPISession_CeGetSystemMetrics_Proxy(
+ IRAPISession * This,
+ INT nIndex);
+
+
+void __RPC_STUB IRAPISession_CeGetSystemMetrics_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+INT STDMETHODCALLTYPE IRAPISession_CeGetDesktopDeviceCaps_Proxy(
+ IRAPISession * This,
+ INT nIndex);
+
+
+void __RPC_STUB IRAPISession_CeGetDesktopDeviceCaps_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeFindAllDatabases_Proxy(
+ IRAPISession * This,
+ DWORD DbaseType,
+ WORD Flags,
+ LPWORD cFindData,
+ LPLPCEDB_FIND_DATA ppFindData);
+
+
+void __RPC_STUB IRAPISession_CeFindAllDatabases_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+void STDMETHODCALLTYPE IRAPISession_CeGetSystemInfo_Proxy(
+ IRAPISession * This,
+ LPSYSTEM_INFO lpSystemInfo);
+
+
+void __RPC_STUB IRAPISession_CeGetSystemInfo_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeSHCreateShortcut_Proxy(
+ IRAPISession * This,
+ LPWSTR lpszShortcut,
+ LPWSTR lpszTarget);
+
+
+void __RPC_STUB IRAPISession_CeSHCreateShortcut_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeSHGetShortcutTarget_Proxy(
+ IRAPISession * This,
+ LPWSTR lpszShortcut,
+ LPWSTR lpszTarget,
+ int cbMax);
+
+
+void __RPC_STUB IRAPISession_CeSHGetShortcutTarget_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeCheckPassword_Proxy(
+ IRAPISession * This,
+ LPWSTR lpszPassword);
+
+
+void __RPC_STUB IRAPISession_CeCheckPassword_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeGetFileTime_Proxy(
+ IRAPISession * This,
+ HANDLE hFile,
+ LPFILETIME lpCreationTime,
+ LPFILETIME lpLastAccessTime,
+ LPFILETIME lpLastWriteTime);
+
+
+void __RPC_STUB IRAPISession_CeGetFileTime_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeSetFileTime_Proxy(
+ IRAPISession * This,
+ HANDLE hFile,
+ FILETIME *lpCreationTime,
+ FILETIME *lpLastAccessTime,
+ FILETIME *lpLastWriteTime);
+
+
+void __RPC_STUB IRAPISession_CeSetFileTime_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeGetVersionEx_Proxy(
+ IRAPISession * This,
+ LPCEOSVERSIONINFO lpVersionInformation);
+
+
+void __RPC_STUB IRAPISession_CeGetVersionEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HWND STDMETHODCALLTYPE IRAPISession_CeGetWindow_Proxy(
+ IRAPISession * This,
+ HWND hWnd,
+ UINT uCmd);
+
+
+void __RPC_STUB IRAPISession_CeGetWindow_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+LONG STDMETHODCALLTYPE IRAPISession_CeGetWindowLong_Proxy(
+ IRAPISession * This,
+ HWND hWnd,
+ int nIndex);
+
+
+void __RPC_STUB IRAPISession_CeGetWindowLong_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+INT STDMETHODCALLTYPE IRAPISession_CeGetWindowText_Proxy(
+ IRAPISession * This,
+ HWND hWnd,
+ LPWSTR lpString,
+ int nMaxCount);
+
+
+void __RPC_STUB IRAPISession_CeGetWindowText_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+INT STDMETHODCALLTYPE IRAPISession_CeGetClassName_Proxy(
+ IRAPISession * This,
+ HWND hWnd,
+ LPWSTR lpClassName,
+ int nMaxCount);
+
+
+void __RPC_STUB IRAPISession_CeGetClassName_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+void STDMETHODCALLTYPE IRAPISession_CeGlobalMemoryStatus_Proxy(
+ IRAPISession * This,
+ LPMEMORYSTATUS lpmst);
+
+
+void __RPC_STUB IRAPISession_CeGlobalMemoryStatus_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeGetSystemPowerStatusEx_Proxy(
+ IRAPISession * This,
+ PSYSTEM_POWER_STATUS_EX pstatus,
+ BOOL fUpdate);
+
+
+void __RPC_STUB IRAPISession_CeGetSystemPowerStatusEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+DWORD STDMETHODCALLTYPE IRAPISession_CeGetTempPath_Proxy(
+ IRAPISession * This,
+ DWORD nBufferLength,
+ LPWSTR lpBuffer);
+
+
+void __RPC_STUB IRAPISession_CeGetTempPath_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+DWORD STDMETHODCALLTYPE IRAPISession_CeGetSpecialFolderPath_Proxy(
+ IRAPISession * This,
+ int nFolder,
+ DWORD nBufferLength,
+ LPWSTR lpBuffer);
+
+
+void __RPC_STUB IRAPISession_CeGetSpecialFolderPath_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPISession_CeRapiInvoke_Proxy(
+ IRAPISession * This,
+ LPCWSTR pDllPath,
+ LPCWSTR pFunctionName,
+ DWORD cbInput,
+ BYTE *pInput,
+ DWORD *pcbOutput,
+ BYTE **ppOutput,
+ IRAPIStream **ppIRAPIStream,
+ DWORD dwReserved);
+
+
+void __RPC_STUB IRAPISession_CeRapiInvoke_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HANDLE STDMETHODCALLTYPE IRAPISession_CeFindFirstDatabaseEx_Proxy(
+ IRAPISession * This,
+ PCEGUID pguid,
+ DWORD dwDbaseType);
+
+
+void __RPC_STUB IRAPISession_CeFindFirstDatabaseEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+CEOID STDMETHODCALLTYPE IRAPISession_CeFindNextDatabaseEx_Proxy(
+ IRAPISession * This,
+ HANDLE hEnum,
+ PCEGUID pguid);
+
+
+void __RPC_STUB IRAPISession_CeFindNextDatabaseEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+CEOID STDMETHODCALLTYPE IRAPISession_CeCreateDatabaseEx_Proxy(
+ IRAPISession * This,
+ PCEGUID pceguid,
+ CEDBASEINFO *lpCEDBInfo);
+
+
+void __RPC_STUB IRAPISession_CeCreateDatabaseEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeSetDatabaseInfoEx_Proxy(
+ IRAPISession * This,
+ PCEGUID pceguid,
+ CEOID oidDbase,
+ CEDBASEINFO *pNewInfo);
+
+
+void __RPC_STUB IRAPISession_CeSetDatabaseInfoEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HANDLE STDMETHODCALLTYPE IRAPISession_CeOpenDatabaseEx_Proxy(
+ IRAPISession * This,
+ PCEGUID pceguid,
+ PCEOID poid,
+ LPWSTR lpszName,
+ CEPROPID propid,
+ DWORD dwFlags,
+ CENOTIFYREQUEST *pReq);
+
+
+void __RPC_STUB IRAPISession_CeOpenDatabaseEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeDeleteDatabaseEx_Proxy(
+ IRAPISession * This,
+ PCEGUID pceguid,
+ CEOID oidDbase);
+
+
+void __RPC_STUB IRAPISession_CeDeleteDatabaseEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+CEOID STDMETHODCALLTYPE IRAPISession_CeReadRecordPropsEx_Proxy(
+ IRAPISession * This,
+ HANDLE hDbase,
+ DWORD dwFlags,
+ LPWORD lpcPropID,
+ CEPROPID *rgPropID,
+ LPBYTE *lplpBuffer,
+ LPDWORD lpcbBuffer,
+ HANDLE hHeap);
+
+
+void __RPC_STUB IRAPISession_CeReadRecordPropsEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeMountDBVol_Proxy(
+ IRAPISession * This,
+ PCEGUID pceguid,
+ LPWSTR lpszDBVol,
+ DWORD dwFlags);
+
+
+void __RPC_STUB IRAPISession_CeMountDBVol_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeUnmountDBVol_Proxy(
+ IRAPISession * This,
+ PCEGUID pceguid);
+
+
+void __RPC_STUB IRAPISession_CeUnmountDBVol_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeFlushDBVol_Proxy(
+ IRAPISession * This,
+ PCEGUID pceguid);
+
+
+void __RPC_STUB IRAPISession_CeFlushDBVol_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeEnumDBVolumes_Proxy(
+ IRAPISession * This,
+ PCEGUID pceguid,
+ LPWSTR lpBuf,
+ DWORD dwNumChars);
+
+
+void __RPC_STUB IRAPISession_CeEnumDBVolumes_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeOidGetInfoEx_Proxy(
+ IRAPISession * This,
+ PCEGUID pceguid,
+ CEOID oid,
+ CEOIDINFO *oidInfo);
+
+
+void __RPC_STUB IRAPISession_CeOidGetInfoEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPISession_CeSyncStart_Proxy(
+ IRAPISession * This,
+ LPCWSTR szCommand);
+
+
+void __RPC_STUB IRAPISession_CeSyncStart_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPISession_CeSyncStop_Proxy(
+ IRAPISession * This);
+
+
+void __RPC_STUB IRAPISession_CeSyncStop_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeQueryInstructionSet_Proxy(
+ IRAPISession * This,
+ DWORD dwInstructionSet,
+ LPDWORD lpdwCurrentInstructionSet);
+
+
+void __RPC_STUB IRAPISession_CeQueryInstructionSet_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+BOOL STDMETHODCALLTYPE IRAPISession_CeGetDiskFreeSpaceEx_Proxy(
+ IRAPISession * This,
+ LPCWSTR lpDirectoryName,
+ ULARGE_INTEGER *lpFreeBytesAvailableToCaller,
+ ULARGE_INTEGER *lpTotalNumberOfBytes,
+ ULARGE_INTEGER *lpTotalNumberOfFreeBytes);
+
+
+void __RPC_STUB IRAPISession_CeGetDiskFreeSpaceEx_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+
+#endif /* __IRAPISession_INTERFACE_DEFINED__ */
+
+
+#ifndef __IRAPIDevice_INTERFACE_DEFINED__
+#define __IRAPIDevice_INTERFACE_DEFINED__
+
+/* interface IRAPIDevice */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IRAPIDevice;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("8a0f1632-3905-4ca4-aea4-7e094ecbb9a7")
+ IRAPIDevice : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetConnectStat(
+ /* [out] */ RAPI_DEVICESTATUS *pStat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceInfo(
+ /* [out] */ RAPI_DEVICEINFO *pDevInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetConnectionInfo(
+ /* [out] */ RAPI_CONNECTIONINFO *pConnInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateSession(
+ /* [out] */ IRAPISession **ppISession) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IRAPIDeviceVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IRAPIDevice * This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IRAPIDevice * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IRAPIDevice * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetConnectStat )(
+ IRAPIDevice * This,
+ /* [out] */ RAPI_DEVICESTATUS *pStat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceInfo )(
+ IRAPIDevice * This,
+ /* [out] */ RAPI_DEVICEINFO *pDevInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetConnectionInfo )(
+ IRAPIDevice * This,
+ /* [out] */ RAPI_CONNECTIONINFO *pConnInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateSession )(
+ IRAPIDevice * This,
+ /* [out] */ IRAPISession **ppISession);
+
+ END_INTERFACE
+ } IRAPIDeviceVtbl;
+
+ interface IRAPIDevice
+ {
+ CONST_VTBL struct IRAPIDeviceVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IRAPIDevice_QueryInterface(This,riid,ppvObject) \
+ (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define IRAPIDevice_AddRef(This) \
+ (This)->lpVtbl -> AddRef(This)
+
+#define IRAPIDevice_Release(This) \
+ (This)->lpVtbl -> Release(This)
+
+
+#define IRAPIDevice_GetConnectStat(This,pStat) \
+ (This)->lpVtbl -> GetConnectStat(This,pStat)
+
+#define IRAPIDevice_GetDeviceInfo(This,pDevInfo) \
+ (This)->lpVtbl -> GetDeviceInfo(This,pDevInfo)
+
+#define IRAPIDevice_GetConnectionInfo(This,pConnInfo) \
+ (This)->lpVtbl -> GetConnectionInfo(This,pConnInfo)
+
+#define IRAPIDevice_CreateSession(This,ppISession) \
+ (This)->lpVtbl -> CreateSession(This,ppISession)
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+HRESULT STDMETHODCALLTYPE IRAPIDevice_GetConnectStat_Proxy(
+ IRAPIDevice * This,
+ /* [out] */ RAPI_DEVICESTATUS *pStat);
+
+
+void __RPC_STUB IRAPIDevice_GetConnectStat_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPIDevice_GetDeviceInfo_Proxy(
+ IRAPIDevice * This,
+ /* [out] */ RAPI_DEVICEINFO *pDevInfo);
+
+
+void __RPC_STUB IRAPIDevice_GetDeviceInfo_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPIDevice_GetConnectionInfo_Proxy(
+ IRAPIDevice * This,
+ /* [out] */ RAPI_CONNECTIONINFO *pConnInfo);
+
+
+void __RPC_STUB IRAPIDevice_GetConnectionInfo_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPIDevice_CreateSession_Proxy(
+ IRAPIDevice * This,
+ /* [out] */ IRAPISession **ppISession);
+
+
+void __RPC_STUB IRAPIDevice_CreateSession_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+
+#endif /* __IRAPIDevice_INTERFACE_DEFINED__ */
+
+
+#ifndef __IRAPIEnumDevices_INTERFACE_DEFINED__
+#define __IRAPIEnumDevices_INTERFACE_DEFINED__
+
+/* interface IRAPIEnumDevices */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IRAPIEnumDevices;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("357a557c-b03f-4240-90d8-c6c71c659bf1")
+ IRAPIEnumDevices : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [out] */ IRAPIDevice **ppIDevice) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ ULONG cElt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ IRAPIEnumDevices **ppIEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCount(
+ /* [out] */ ULONG *pcElt) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IRAPIEnumDevicesVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IRAPIEnumDevices * This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IRAPIEnumDevices * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IRAPIEnumDevices * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IRAPIEnumDevices * This,
+ /* [out] */ IRAPIDevice **ppIDevice);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ IRAPIEnumDevices * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ IRAPIEnumDevices * This,
+ /* [in] */ ULONG cElt);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ IRAPIEnumDevices * This,
+ /* [out] */ IRAPIEnumDevices **ppIEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ IRAPIEnumDevices * This,
+ /* [out] */ ULONG *pcElt);
+
+ END_INTERFACE
+ } IRAPIEnumDevicesVtbl;
+
+ interface IRAPIEnumDevices
+ {
+ CONST_VTBL struct IRAPIEnumDevicesVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IRAPIEnumDevices_QueryInterface(This,riid,ppvObject) \
+ (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define IRAPIEnumDevices_AddRef(This) \
+ (This)->lpVtbl -> AddRef(This)
+
+#define IRAPIEnumDevices_Release(This) \
+ (This)->lpVtbl -> Release(This)
+
+
+#define IRAPIEnumDevices_Next(This,ppIDevice) \
+ (This)->lpVtbl -> Next(This,ppIDevice)
+
+#define IRAPIEnumDevices_Reset(This) \
+ (This)->lpVtbl -> Reset(This)
+
+#define IRAPIEnumDevices_Skip(This,cElt) \
+ (This)->lpVtbl -> Skip(This,cElt)
+
+#define IRAPIEnumDevices_Clone(This,ppIEnum) \
+ (This)->lpVtbl -> Clone(This,ppIEnum)
+
+#define IRAPIEnumDevices_GetCount(This,pcElt) \
+ (This)->lpVtbl -> GetCount(This,pcElt)
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+HRESULT STDMETHODCALLTYPE IRAPIEnumDevices_Next_Proxy(
+ IRAPIEnumDevices * This,
+ /* [out] */ IRAPIDevice **ppIDevice);
+
+
+void __RPC_STUB IRAPIEnumDevices_Next_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPIEnumDevices_Reset_Proxy(
+ IRAPIEnumDevices * This);
+
+
+void __RPC_STUB IRAPIEnumDevices_Reset_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPIEnumDevices_Skip_Proxy(
+ IRAPIEnumDevices * This,
+ /* [in] */ ULONG cElt);
+
+
+void __RPC_STUB IRAPIEnumDevices_Skip_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPIEnumDevices_Clone_Proxy(
+ IRAPIEnumDevices * This,
+ /* [out] */ IRAPIEnumDevices **ppIEnum);
+
+
+void __RPC_STUB IRAPIEnumDevices_Clone_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPIEnumDevices_GetCount_Proxy(
+ IRAPIEnumDevices * This,
+ /* [out] */ ULONG *pcElt);
+
+
+void __RPC_STUB IRAPIEnumDevices_GetCount_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+
+#endif /* __IRAPIEnumDevices_INTERFACE_DEFINED__ */
+
+
+#ifndef __IRAPISink_INTERFACE_DEFINED__
+#define __IRAPISink_INTERFACE_DEFINED__
+
+/* interface IRAPISink */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IRAPISink;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("b4fd053e-4810-46db-889b-20e638e334f0")
+ IRAPISink : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE OnDeviceConnected(
+ /* [in] */ IRAPIDevice *pIDevice) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OnDeviceDisconnected(
+ /* [in] */ IRAPIDevice *pIDevice) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IRAPISinkVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IRAPISink * This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IRAPISink * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IRAPISink * This);
+
+ HRESULT ( STDMETHODCALLTYPE *OnDeviceConnected )(
+ IRAPISink * This,
+ /* [in] */ IRAPIDevice *pIDevice);
+
+ HRESULT ( STDMETHODCALLTYPE *OnDeviceDisconnected )(
+ IRAPISink * This,
+ /* [in] */ IRAPIDevice *pIDevice);
+
+ END_INTERFACE
+ } IRAPISinkVtbl;
+
+ interface IRAPISink
+ {
+ CONST_VTBL struct IRAPISinkVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IRAPISink_QueryInterface(This,riid,ppvObject) \
+ (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define IRAPISink_AddRef(This) \
+ (This)->lpVtbl -> AddRef(This)
+
+#define IRAPISink_Release(This) \
+ (This)->lpVtbl -> Release(This)
+
+
+#define IRAPISink_OnDeviceConnected(This,pIDevice) \
+ (This)->lpVtbl -> OnDeviceConnected(This,pIDevice)
+
+#define IRAPISink_OnDeviceDisconnected(This,pIDevice) \
+ (This)->lpVtbl -> OnDeviceDisconnected(This,pIDevice)
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+HRESULT STDMETHODCALLTYPE IRAPISink_OnDeviceConnected_Proxy(
+ IRAPISink * This,
+ /* [in] */ IRAPIDevice *pIDevice);
+
+
+void __RPC_STUB IRAPISink_OnDeviceConnected_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPISink_OnDeviceDisconnected_Proxy(
+ IRAPISink * This,
+ /* [in] */ IRAPIDevice *pIDevice);
+
+
+void __RPC_STUB IRAPISink_OnDeviceDisconnected_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+
+#endif /* __IRAPISink_INTERFACE_DEFINED__ */
+
+
+#ifndef __IRAPIDesktop_INTERFACE_DEFINED__
+#define __IRAPIDesktop_INTERFACE_DEFINED__
+
+/* interface IRAPIDesktop */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IRAPIDesktop;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("dcbeb807-14d0-4cbd-926c-b991f4fd1b91")
+ IRAPIDesktop : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE FindDevice(
+ /* [in] */ RAPIDEVICEID *pDeviceID,
+ /* [in] */ RAPI_GETDEVICEOPCODE opFlags,
+ /* [out] */ IRAPIDevice **ppIDevice) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumDevices(
+ /* [out] */ IRAPIEnumDevices **ppIEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Advise(
+ /* [in] */ IRAPISink *pISink,
+ /* [out] */ DWORD_PTR *pdwContext) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UnAdvise(
+ /* [in] */ DWORD_PTR dwContext) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IRAPIDesktopVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IRAPIDesktop * This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IRAPIDesktop * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IRAPIDesktop * This);
+
+ HRESULT ( STDMETHODCALLTYPE *FindDevice )(
+ IRAPIDesktop * This,
+ /* [in] */ RAPIDEVICEID *pDeviceID,
+ /* [in] */ RAPI_GETDEVICEOPCODE opFlags,
+ /* [out] */ IRAPIDevice **ppIDevice);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumDevices )(
+ IRAPIDesktop * This,
+ /* [out] */ IRAPIEnumDevices **ppIEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *Advise )(
+ IRAPIDesktop * This,
+ /* [in] */ IRAPISink *pISink,
+ /* [out] */ DWORD_PTR *pdwContext);
+
+ HRESULT ( STDMETHODCALLTYPE *UnAdvise )(
+ IRAPIDesktop * This,
+ /* [in] */ DWORD_PTR dwContext);
+
+ END_INTERFACE
+ } IRAPIDesktopVtbl;
+
+ interface IRAPIDesktop
+ {
+ CONST_VTBL struct IRAPIDesktopVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IRAPIDesktop_QueryInterface(This,riid,ppvObject) \
+ (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define IRAPIDesktop_AddRef(This) \
+ (This)->lpVtbl -> AddRef(This)
+
+#define IRAPIDesktop_Release(This) \
+ (This)->lpVtbl -> Release(This)
+
+
+#define IRAPIDesktop_FindDevice(This,pDeviceID,opFlags,ppIDevice) \
+ (This)->lpVtbl -> FindDevice(This,pDeviceID,opFlags,ppIDevice)
+
+#define IRAPIDesktop_EnumDevices(This,ppIEnum) \
+ (This)->lpVtbl -> EnumDevices(This,ppIEnum)
+
+#define IRAPIDesktop_Advise(This,pISink,pdwContext) \
+ (This)->lpVtbl -> Advise(This,pISink,pdwContext)
+
+#define IRAPIDesktop_UnAdvise(This,dwContext) \
+ (This)->lpVtbl -> UnAdvise(This,dwContext)
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+HRESULT STDMETHODCALLTYPE IRAPIDesktop_FindDevice_Proxy(
+ IRAPIDesktop * This,
+ /* [in] */ RAPIDEVICEID *pDeviceID,
+ /* [in] */ RAPI_GETDEVICEOPCODE opFlags,
+ /* [out] */ IRAPIDevice **ppIDevice);
+
+
+void __RPC_STUB IRAPIDesktop_FindDevice_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPIDesktop_EnumDevices_Proxy(
+ IRAPIDesktop * This,
+ /* [out] */ IRAPIEnumDevices **ppIEnum);
+
+
+void __RPC_STUB IRAPIDesktop_EnumDevices_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPIDesktop_Advise_Proxy(
+ IRAPIDesktop * This,
+ /* [in] */ IRAPISink *pISink,
+ /* [out] */ DWORD_PTR *pdwContext);
+
+
+void __RPC_STUB IRAPIDesktop_Advise_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IRAPIDesktop_UnAdvise_Proxy(
+ IRAPIDesktop * This,
+ /* [in] */ DWORD_PTR dwContext);
+
+
+void __RPC_STUB IRAPIDesktop_UnAdvise_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+
+#endif /* __IRAPIDesktop_INTERFACE_DEFINED__ */
+
+
+
+#ifndef __RAPILib_LIBRARY_DEFINED__
+#define __RAPILib_LIBRARY_DEFINED__
+
+/* library RAPILib */
+/* [helpstring][version][uuid] */
+
+
+EXTERN_C const IID LIBID_RAPILib;
+
+EXTERN_C const CLSID CLSID_RAPI;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("35440327-1517-4B72-865E-3FFE8E97002F")
+RAPI;
+#endif
+#endif /* __RAPILib_LIBRARY_DEFINED__ */
+
+/* interface __MIDL_itf_RAPI2_0268 */
+/* [local] */
+
+#endif
+
+
+extern RPC_IF_HANDLE __MIDL_itf_RAPI2_0268_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_RAPI2_0268_v0_0_s_ifspec;
+
+/* Additional Prototypes for ALL interfaces */
+
+unsigned long __RPC_USER BSTR_UserSize( unsigned long *, unsigned long , BSTR * );
+unsigned char * __RPC_USER BSTR_UserMarshal( unsigned long *, unsigned char *, BSTR * );
+unsigned char * __RPC_USER BSTR_UserUnmarshal(unsigned long *, unsigned char *, BSTR * );
+void __RPC_USER BSTR_UserFree( unsigned long *, BSTR * );
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapitypes.h b/Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapitypes.h
new file mode 100644
index 00000000..6a2f0b45
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapitypes.h
@@ -0,0 +1,445 @@
+// *************************************************************************
+// rapitypes.h
+//
+// Copyright 2002 Microsoft Corporation, All Rights Reserved
+//
+// Typedefs common to public and private RAPI idl.
+//
+// ***************************************************************************
+
+#pragma once
+
+#ifdef MIDL_ONLY
+
+typedef BYTE far * LPBYTE;
+#define STDAPICALLTYPE __stdcall
+#endif // MIDL_ONLY
+
+//
+// The Windows CE WIN32_FIND_DATA structure differs from the
+// Windows WIN32_FIND_DATA stucture so we copy the Windows CE
+// definition to here so that both sides match.
+//
+#define MAX_PATH 260
+
+typedef struct CE_FIND_DATA
+{
+ DWORD dwFileAttributes;
+ FILETIME ftCreationTime;
+ FILETIME ftLastAccessTime;
+ FILETIME ftLastWriteTime;
+ DWORD nFileSizeHigh;
+ DWORD nFileSizeLow;
+ DWORD dwOID;
+ WCHAR cFileName[MAX_PATH];
+} CE_FIND_DATA;
+
+typedef CE_FIND_DATA* LPCE_FIND_DATA;
+
+typedef CE_FIND_DATA** LPLPCE_FIND_DATA;
+
+//
+// These are flags for CeFindAllFiles
+//
+#define FAF_ATTRIBUTES ((DWORD) 0x01)
+#define FAF_CREATION_TIME ((DWORD) 0x02)
+#define FAF_LASTACCESS_TIME ((DWORD) 0x04)
+#define FAF_LASTWRITE_TIME ((DWORD) 0x08)
+#define FAF_SIZE_HIGH ((DWORD) 0x10)
+#define FAF_SIZE_LOW ((DWORD) 0x20)
+#define FAF_OID ((DWORD) 0x40)
+#define FAF_NAME ((DWORD) 0x80)
+#define FAF_FLAG_COUNT ((UINT) 8)
+#define FAF_ATTRIB_CHILDREN ((DWORD) 0x01000)
+#define FAF_ATTRIB_NO_HIDDEN ((DWORD) 0x02000)
+#define FAF_FOLDERS_ONLY ((DWORD) 0x04000)
+#define FAF_NO_HIDDEN_SYS_ROMMODULES ((DWORD) 0x08000)
+#define FAF_GETTARGET ((DWORD) 0x10000)
+
+#define FAD_OID ((WORD) 0x01)
+#define FAD_FLAGS ((WORD) 0x02)
+#define FAD_NAME ((WORD) 0x04)
+#define FAD_TYPE ((WORD) 0x08)
+#define FAD_NUM_RECORDS ((WORD) 0x10)
+#define FAD_NUM_SORT_ORDER ((WORD) 0x20)
+#define FAD_SIZE ((WORD) 0x40)
+#define FAD_LAST_MODIFIED ((WORD) 0x80)
+#define FAD_SORT_SPECS ((WORD) 0x100)
+#define FAD_FLAG_COUNT ((UINT) 9)
+
+#ifndef FILE_ATTRIBUTE_INROM
+#define FILE_ATTRIBUTE_INROM 0x00000040
+#endif
+#ifndef FILE_ATTRIBUTE_ROMSTATICREF
+#define FILE_ATTRIBUTE_ROMSTATICREF 0x00001000
+#endif
+#ifndef FILE_ATTRIBUTE_ROMMODULE
+#define FILE_ATTRIBUTE_ROMMODULE 0x00002000
+#endif
+
+//
+// The following is not a standard Windows CE File Attribute.
+//
+#ifndef FILE_ATTRIBUTE_HAS_CHILDREN
+#define FILE_ATTRIBUTE_HAS_CHILDREN 0x00010000
+#endif
+#ifndef FILE_ATTRIBUTE_SHORTCUT
+#define FILE_ATTRIBUTE_SHORTCUT 0x00020000
+#endif
+
+typedef enum RAPISTREAMFLAG
+{
+ STREAM_TIMEOUT_READ
+} RAPISTREAMFLAG;
+
+// forward define
+#ifdef MIDL_ONLY
+interface IRAPIStream;
+#else
+typedef struct IRAPIStream IRAPIStream;
+#endif
+
+// RAPI extension on Windows CE (e.g., MyFunctionFOO) called via CeRapiInvoke should be declared as:
+// EXTERN_C RAPIEXT MyFunctionFOO;
+typedef HRESULT (STDAPICALLTYPE RAPIEXT)(
+ DWORD cbInput, // [IN]
+ BYTE * pInput, // [IN]
+ DWORD * pcbOutput, // [OUT]
+ BYTE ** ppOutput, // [OUT]
+ IRAPIStream * pIRAPIStream // [IN]
+ );
+
+//
+// The following definitions are for the client side only,
+// because they are already defined on Windows CE.
+//
+#ifndef UNDER_CE
+
+#include <stddef.h>
+
+typedef struct STORE_INFORMATION
+{
+ DWORD dwStoreSize;
+ DWORD dwFreeSize;
+} STORE_INFORMATION;
+
+
+typedef STORE_INFORMATION * LPSTORE_INFORMATION;
+
+typedef DWORD CEPROPID;
+
+typedef CEPROPID * PCEPROPID;
+
+#define TypeFromPropID(propid) LOWORD(propid)
+
+typedef DWORD CEOID;
+
+typedef CEOID *PCEOID;
+
+typedef struct CEGUID
+{
+ DWORD Data1;
+ DWORD Data2;
+ DWORD Data3;
+ DWORD Data4;
+} CEGUID;
+
+typedef CEGUID * PCEGUID;
+
+typedef struct CENOTIFICATION {
+ DWORD dwSize;
+ DWORD dwParam;
+ UINT uType;
+ CEGUID guid;
+ CEOID oid;
+ CEOID oidParent;
+} CENOTIFICATION;
+
+#define CEDB_EXNOTIFICATION 0x00000001
+
+typedef struct CENOTIFYREQUEST {
+ DWORD dwSize;
+ HWND hwnd;
+ DWORD dwFlags;
+ HANDLE hHeap;
+ DWORD dwParam;
+} CENOTIFYREQUEST;
+
+typedef CENOTIFYREQUEST * PCENOTIFYREQUEST;
+
+typedef struct CEFILEINFO
+{
+ DWORD dwAttributes;
+ CEOID oidParent;
+ WCHAR szFileName[MAX_PATH];
+ FILETIME ftLastChanged;
+ DWORD dwLength;
+} CEFILEINFO;
+
+typedef struct CEDIRINFO {
+ DWORD dwAttributes;
+ CEOID oidParent;
+ WCHAR szDirName[MAX_PATH];
+} CEDIRINFO;
+
+typedef struct CERECORDINFO {
+ CEOID oidParent;
+} CERECORDINFO;
+
+#define CEDB_SORT_DESCENDING 0x00000001
+#define CEDB_SORT_CASEINSENSITIVE 0x00000002
+#define CEDB_SORT_UNKNOWNFIRST 0x00000004
+#define CEDB_SORT_GENERICORDER 0x00000008
+
+typedef struct SORTORDERSPEC {
+ CEPROPID propid;
+ DWORD dwFlags;
+} SORTORDERSPEC;
+
+#define CEDB_MAXDBASENAMELEN 32
+#define CEDB_MAXDBASENAMELEN 32
+#define CEDB_MAXSORTORDER 4
+#define CEDB_MAXSORTORDER 4
+
+#define CEDB_VALIDNAME 0x0001
+#define CEDB_VALIDTYPE 0x0002
+#define CEDB_VALIDSORTSPEC 0x0004
+#define CEDB_VALIDMODTIME 0x0008
+#define CEDB_VALIDDBFLAGS 0x0010
+#define CEDB_VALIDCREATE (CEDB_VALIDNAME|CEDB_VALIDTYPE|CEDB_VALIDSORTSPEC|CEDB_VALIDDBFLAGS)
+
+#define CEDB_NOCOMPRESS 0x00010000
+
+typedef struct CEDBASEINFO
+{
+ DWORD dwFlags;
+ WCHAR szDbaseName[CEDB_MAXDBASENAMELEN];
+ DWORD dwDbaseType;
+ WORD wNumRecords;
+ WORD wNumSortOrder;
+ DWORD dwSize;
+ FILETIME ftLastModified;
+ SORTORDERSPEC rgSortSpecs[CEDB_MAXSORTORDER];
+} CEDBASEINFO;
+
+typedef struct CEDB_FIND_DATA {
+ CEOID OidDb;
+ CEDBASEINFO DbInfo;
+} CEDB_FIND_DATA;
+
+
+typedef CEDB_FIND_DATA * LPCEDB_FIND_DATA;
+
+typedef CEDB_FIND_DATA ** LPLPCEDB_FIND_DATA;
+
+#define OBJTYPE_INVALID 0
+#define OBJTYPE_FILE 1
+#define OBJTYPE_DIRECTORY 2
+#define OBJTYPE_DATABASE 3
+#define OBJTYPE_RECORD 4
+
+typedef struct CEOIDINFO
+{
+ WORD wObjType;
+ WORD wPad;
+ union
+ {
+ CEFILEINFO infFile;
+ CEDIRINFO infDirectory;
+ CEDBASEINFO infDatabase;
+ CERECORDINFO infRecord;
+ };
+} CEOIDINFO;
+
+#define CEDB_AUTOINCREMENT 0x00000001
+
+#define CEDB_SEEK_CEOID 0x00000001
+#define CEDB_SEEK_BEGINNING 0x00000002
+#define CEDB_SEEK_END 0x00000004
+#define CEDB_SEEK_CURRENT 0x00000008
+#define CEDB_SEEK_VALUESMALLER 0x00000010
+#define CEDB_SEEK_VALUEFIRSTEQUAL 0x00000020
+#define CEDB_SEEK_VALUEGREATER 0x00000040
+#define CEDB_SEEK_VALUENEXTEQUAL 0x00000080
+
+typedef struct CEBLOB{
+ DWORD dwCount;
+ LPBYTE lpb;
+} CEBLOB;
+
+#define CEVT_I2 2
+#define CEVT_UI2 18
+#define CEVT_I4 3
+#define CEVT_UI4 19
+#define CEVT_FILETIME 64
+#define CEVT_LPWSTR 31
+#define CEVT_BLOB 65
+#define CEVT_BOOL 11
+#define CEVT_R8 5
+
+typedef union CEVALUNION {
+ short iVal;
+ USHORT uiVal;
+ long lVal;
+ ULONG ulVal;
+ FILETIME filetime;
+ LPWSTR lpwstr;
+ CEBLOB blob;
+ BOOL boolVal;
+ double dblVal;
+} CEVALUNION;
+
+#define CEDB_PROPNOTFOUND 0x0100
+#define CEDB_PROPDELETE 0x0200
+
+typedef struct CEPROPVAL {
+ CEPROPID propid;
+ WORD wLenData;
+ WORD wFlags;
+ CEVALUNION val;
+} CEPROPVAL;
+
+typedef CEPROPVAL * PCEPROPVAL;
+
+
+#define CEDB_MAXDATABLOCKSIZE 4092
+#define CEDB_MAXPROPDATASIZE (CEDB_MAXDATABLOCKSIZE*16)
+#define CEDB_MAXRECORDSIZE (128*1024)
+
+#define CEDB_ALLOWREALLOC 0x00000001
+
+#define CREATE_SYSTEMGUID(pguid) (memset((pguid), 0, sizeof(CEGUID)))
+#define CREATE_INVALIDGUID(pguid) (memset((pguid), -1, sizeof(CEGUID)))
+
+#define CHECK_SYSTEMGUID(pguid) !((pguid)->Data1|(pguid)->Data2|(pguid)->Data3|(pguid)->Data4)
+#define CHECK_INVALIDGUID(pguid) !~((pguid)->Data1&(pguid)->Data2&(pguid)->Data3&(pguid)->Data4)
+
+#define SYSMEM_CHANGED 0
+#define SYSMEM_MUSTREBOOT 1
+#define SYSMEM_REBOOTPENDING 2
+#define SYSMEM_FAILED 3
+
+typedef struct CEOSVERSIONINFO {
+ DWORD dwOSVersionInfoSize;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ DWORD dwBuildNumber;
+ DWORD dwPlatformId;
+ WCHAR szCSDVersion[ 128 ];
+} CEOSVERSIONINFO;
+
+typedef CEOSVERSIONINFO * LPCEOSVERSIONINFO;
+
+#define AC_LINE_OFFLINE 0x00
+#define AC_LINE_ONLINE 0x01
+#define AC_LINE_BACKUP_POWER 0x02
+#define AC_LINE_UNKNOWN 0xFF
+
+#define BATTERY_FLAG_HIGH 0x01
+#define BATTERY_FLAG_LOW 0x02
+#define BATTERY_FLAG_CRITICAL 0x04
+#define BATTERY_FLAG_CHARGING 0x08
+#define BATTERY_FLAG_NO_BATTERY 0x80
+#define BATTERY_FLAG_UNKNOWN 0xFF
+
+#define BATTERY_PERCENTAGE_UNKNOWN 0xFF
+
+#define BATTERY_LIFE_UNKNOWN 0xFFFFFFFF
+
+typedef struct SYSTEM_POWER_STATUS_EX{
+ BYTE ACLineStatus;
+ BYTE BatteryFlag;
+ BYTE BatteryLifePercent;
+ BYTE Reserved1;
+ DWORD BatteryLifeTime;
+ DWORD BatteryFullLifeTime;
+ BYTE Reserved2;
+ BYTE BackupBatteryFlag;
+ BYTE BackupBatteryLifePercent;
+ BYTE Reserved3;
+ DWORD BackupBatteryLifeTime;
+ DWORD BackupBatteryFullLifeTime;
+} SYSTEM_POWER_STATUS_EX;
+
+typedef SYSTEM_POWER_STATUS_EX * PSYSTEM_POWER_STATUS_EX;
+
+typedef SYSTEM_POWER_STATUS_EX * LPSYSTEM_POWER_STATUS_EX;
+
+
+//
+// MessageId: CERAPI_E_ALREADYINITIALIZED
+//
+// CeRapiInit(Ex) has already been successfully called
+//
+#define CERAPI_E_ALREADYINITIALIZED 0x80041001
+
+typedef struct RAPIINIT
+{
+ DWORD cbSize;
+ HANDLE heRapiInit;
+ HRESULT hrRapiInit;
+} RAPIINIT;
+
+//
+// Instruction set definitions for CeQueryInstructionSet()
+//
+// PROCESSOR_ARCHITECTURE_x are already defined in desktop winnt.h
+// Here we include the CE specific definitions from CE winnt.h
+//
+#define PROCESSOR_INSTRUCTION_CODE(arch, core, feature) \
+ ((arch) << 24 | (core) << 16 | (feature))
+#define PROCESSOR_X86_32BIT_CORE 1
+
+#define PROCESSOR_MIPS16_CORE 1
+#define PROCESSOR_MIPSII_CORE 2
+#define PROCESSOR_MIPSIV_CORE 3
+
+#define PROCESSOR_HITACHI_SH3_CORE 1
+#define PROCESSOR_HITACHI_SH4_CORE 2
+
+#define PROCESSOR_ARM_V4_CORE 1
+#define PROCESSOR_ARM_V4I_CORE 2
+#define PROCESSOR_ARM_V4T_CORE 3
+
+#define PROCESSOR_FEATURE_NOFP 0
+#define PROCESSOR_FEATURE_FP 1
+#define PROCESSOR_FEATURE_DSP PROCESSOR_FEATURE_FP
+
+#define PROCESSOR_QUERY_INSTRUCTION PROCESSOR_INSTRUCTION_CODE(0,0,0)
+
+#define PROCESSOR_X86_32BIT_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_INTEL, PROCESSOR_X86_32BIT_CORE, PROCESSOR_FEATURE_FP)
+
+#define PROCESSOR_MIPS_MIPS16_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_MIPS, PROCESSOR_MIPS16_CORE, PROCESSOR_FEATURE_NOFP)
+#define PROCESSOR_MIPS_MIPSII_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_MIPS, PROCESSOR_MIPSII_CORE, PROCESSOR_FEATURE_NOFP)
+#define PROCESSOR_MIPS_MIPSIIFP_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_MIPS, PROCESSOR_MIPSII_CORE, PROCESSOR_FEATURE_FP)
+#define PROCESSOR_MIPS_MIPSIV_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_MIPS, PROCESSOR_MIPSIV_CORE, PROCESSOR_FEATURE_NOFP)
+#define PROCESSOR_MIPS_MIPSIVFP_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_MIPS, PROCESSOR_MIPSIV_CORE, PROCESSOR_FEATURE_FP)
+
+#define PROCESSOR_HITACHI_SH3_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_SHX, PROCESSOR_HITACHI_SH3_CORE, PROCESSOR_FEATURE_NOFP)
+#define PROCESSOR_HITACHI_SH3DSP_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_SHX, PROCESSOR_HITACHI_SH3_CORE, PROCESSOR_FEATURE_DSP)
+#define PROCESSOR_HITACHI_SH4_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_SHX, PROCESSOR_HITACHI_SH4_CORE, PROCESSOR_FEATURE_FP)
+
+#define PROCESSOR_ARM_V4_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_ARM, PROCESSOR_ARM_V4_CORE, PROCESSOR_FEATURE_NOFP)
+#define PROCESSOR_ARM_V4FP_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_ARM, PROCESSOR_ARM_V4_CORE, PROCESSOR_FEATURE_FP)
+#define PROCESSOR_ARM_V4I_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_ARM, PROCESSOR_ARM_V4I_CORE, PROCESSOR_FEATURE_NOFP)
+#define PROCESSOR_ARM_V4IFP_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_ARM, PROCESSOR_ARM_V4I_CORE, PROCESSOR_FEATURE_FP)
+#define PROCESSOR_ARM_V4T_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_ARM, PROCESSOR_ARM_V4T_CORE, PROCESSOR_FEATURE_NOFP)
+#define PROCESSOR_ARM_V4TFP_INSTRUCTION \
+ PROCESSOR_INSTRUCTION_CODE(PROCESSOR_ARCHITECTURE_ARM, PROCESSOR_ARM_V4T_CORE, PROCESSOR_FEATURE_FP)
+
+
+#endif // !UNDER_CE
diff --git a/Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapitypes2.h b/Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapitypes2.h
new file mode 100644
index 00000000..aa429fbc
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/activesync/Inc/rapitypes2.h
@@ -0,0 +1,248 @@
+// ***************************************************************************
+// rapitypes2.h
+//
+// Copyright 2003 Microsoft Corporation, All Rights Reserved
+//
+// Types needed for RAPI2.
+//
+// ***************************************************************************
+
+#pragma once
+
+#ifdef MIDL_ONLY
+
+#include <basetsd.h>
+
+typedef struct OVERLAPPED {
+ ULONG_PTR Internal;
+ ULONG_PTR InternalHigh;
+ union UNION_OFFSET_POINTER{
+ struct OFFSET{
+ DWORD Offset;
+ DWORD OffsetHigh;
+ } OFFSET;
+
+ PVOID Pointer;
+ } UNION_OFFSET_POINTER;
+
+ HANDLE hEvent;
+} OVERLAPPED;
+
+typedef OVERLAPPED * LPOVERLAPPED;
+
+#define CONST const
+typedef CONST void far *LPCVOID;
+typedef LONG *PLONG;
+
+typedef struct STARTUPINFOA {
+ DWORD cb;
+ LPSTR lpReserved;
+ LPSTR lpDesktop;
+ LPSTR lpTitle;
+ DWORD dwX;
+ DWORD dwY;
+ DWORD dwXSize;
+ DWORD dwYSize;
+ DWORD dwXCountChars;
+ DWORD dwYCountChars;
+ DWORD dwFillAttribute;
+ DWORD dwFlags;
+ WORD wShowWindow;
+ WORD cbReserved2;
+ LPBYTE lpReserved2;
+ HANDLE hStdInput;
+ HANDLE hStdOutput;
+ HANDLE hStdError;
+} STARTUPINFOA;
+
+typedef STARTUPINFOA * LPSTARTUPINFOA;
+
+typedef struct STARTUPINFOW {
+ DWORD cb;
+ LPWSTR lpReserved;
+ LPWSTR lpDesktop;
+ LPWSTR lpTitle;
+ DWORD dwX;
+ DWORD dwY;
+ DWORD dwXSize;
+ DWORD dwYSize;
+ DWORD dwXCountChars;
+ DWORD dwYCountChars;
+ DWORD dwFillAttribute;
+ DWORD dwFlags;
+ WORD wShowWindow;
+ WORD cbReserved2;
+ LPBYTE lpReserved2;
+ HANDLE hStdInput;
+ HANDLE hStdOutput;
+ HANDLE hStdError;
+} STARTUPINFOW;
+
+typedef STARTUPINFOW * LPSTARTUPINFOW;
+
+#ifdef UNICODE
+typedef STARTUPINFOW STARTUPINFO;
+typedef LPSTARTUPINFOW LPSTARTUPINFO;
+#else
+typedef STARTUPINFOA STARTUPINFO;
+typedef LPSTARTUPINFOA LPSTARTUPINFO;
+#endif // UNICODE
+
+typedef struct PROCESS_INFORMATION {
+ HANDLE hProcess;
+ HANDLE hThread;
+ DWORD dwProcessId;
+ DWORD dwThreadId;
+} PROCESS_INFORMATION;
+
+typedef PROCESS_INFORMATION * PPROCESS_INFORMATION;
+typedef PROCESS_INFORMATION * LPPROCESS_INFORMATION;
+
+typedef DWORD ACCESS_MASK;
+typedef ACCESS_MASK REGSAM;
+typedef HKEY *PHKEY;
+
+typedef struct SYSTEM_INFO {
+ union UNION_OEMID_PROCESSOR_INFO{
+ DWORD dwOemId; // Obsolete field...do not use
+ struct PROCESSOR_INFO{
+ WORD wProcessorArchitecture;
+ WORD wReserved;
+ } PROCESSOR_INFO;
+ } UNION_OEMID_PROCESSOR_INFO;
+ DWORD dwPageSize;
+ LPVOID lpMinimumApplicationAddress;
+ LPVOID lpMaximumApplicationAddress;
+ DWORD_PTR dwActiveProcessorMask;
+ DWORD dwNumberOfProcessors;
+ DWORD dwProcessorType;
+ DWORD dwAllocationGranularity;
+ WORD wProcessorLevel;
+ WORD wProcessorRevision;
+} SYSTEM_INFO;
+typedef SYSTEM_INFO * LPSYSTEM_INFO;
+
+
+typedef struct MEMORYSTATUS {
+ DWORD dwLength;
+ DWORD dwMemoryLoad;
+ SIZE_T dwTotalPhys;
+ SIZE_T dwAvailPhys;
+ SIZE_T dwTotalPageFile;
+ SIZE_T dwAvailPageFile;
+ SIZE_T dwTotalVirtual;
+ SIZE_T dwAvailVirtual;
+} MEMORYSTATUS;
+
+typedef MEMORYSTATUS * LPMEMORYSTATUS;
+
+#define _SS_MAXSIZE 128 // Maximum size.
+#define _SS_ALIGNSIZE (sizeof(__int64)) // Desired alignment.
+#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof (short))
+#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (short) + _SS_PAD1SIZE \
+ + _SS_ALIGNSIZE))
+/*
+typedef struct sockaddr_storage {
+ short ss_family; // Address family.
+ char __ss_pad1[_SS_PAD1SIZE]; // 6 byte pad, this is to make
+ // implementation specific pad up to
+ // alignment field that follows explicit
+ // in the data structure.
+ __int64 __ss_align; // Field to force desired structure.
+ char __ss_pad2[_SS_PAD2SIZE]; // 112 byte pad to achieve desired size;
+ // _SS_MAXSIZE value minus size of
+ // ss_family, __ss_pad1, and
+ // __ss_align fields is 112.
+} sockaddr_storage ;
+
+typedef struct sockaddr_storage SOCKADDR_STORAGE;
+*/
+#endif // MIDL_ONLY
+
+// end gross struct copy hack (everything after this is previously hacked from CE stuff that doesn't exist on desktop, so leave it as is).
+
+//
+// DEVICEID structure
+//
+typedef GUID RAPIDEVICEID;
+#define RAPIDEVICEID_BACKCOMPAT GUID_NULL // device id for older devices
+
+#ifndef UNDER_CE
+
+// this is defined in CE's pwinuser.h, so we only want it for desktop
+typedef struct {
+ DWORD dwMajor;
+ DWORD dwMinor;
+} PLATFORMVERSION;
+
+#endif
+
+//
+// struct to hold additional platforms and their versions.
+//
+#define MAX_SUB_PLATFORMS 6
+
+typedef struct RAPI_DEVICE_PLATFORM
+{
+ BSTR bstrName;
+ DWORD dwMajor;
+ DWORD dwMinor;
+} RAPI_DEVICE_PLATFORM;
+
+//
+// RAPI_DEVICEINFO
+//
+typedef struct RAPI_DEVICEINFO
+{
+ RAPIDEVICEID DeviceId;
+ DWORD dwOsVersionMajor;
+ DWORD dwOsVersionMinor;
+ BSTR bstrName;
+ BSTR bstrPlatform;
+} RAPI_DEVICEINFO;
+
+#define FreeDeviceInfoData(pDevInfo) \
+ do \
+ { \
+ SysFreeString((pDevInfo)->bstrName); \
+ SysFreeString((pDevInfo)->bstrPlatform); \
+ } while (0,0)
+
+#ifndef MIDL_ONLY
+#include "winsock2.h"
+#endif
+
+//
+// RAPI_DEVICESTATUS
+//
+typedef enum RAPI_DEVICESTATUS
+{
+ RAPI_DEVICE_DISCONNECTED = 0,
+ RAPI_DEVICE_CONNECTED = 1,
+} RAPI_DEVICESTATUS;
+
+//
+// op codes for IRAPIDesktop funcs
+//
+typedef enum RAPI_GETDEVICEOPCODE
+{
+ RAPI_GETDEVICE_NONBLOCKING,
+ RAPI_GETDEVICE_BLOCKING
+} RAPI_GETDEVICEOPCODE;
+
+//
+// Connected type codes
+//
+typedef enum RAPI_CONNECTIONTYPE
+{
+ RAPI_CONNECTION_USB = 0,
+ RAPI_CONNECTION_IR = 1,
+ RAPI_CONNECTION_SERIAL = 2,
+ RAPI_CONNECTION_NETWORK = 3,
+} RAPI_CONNECTIONTYPE;
+
+typedef struct RAPI_CONNECTIONINFO {
+ SOCKADDR_STORAGE ipaddr;
+ SOCKADDR_STORAGE hostIpaddr;
+ RAPI_CONNECTIONTYPE connectionType;
+} RAPI_CONNECTIONINFO;
diff --git a/Src/Plugins/Portable/pmp_activesync/activesync/Lib/rapiuuid.lib b/Src/Plugins/Portable/pmp_activesync/activesync/Lib/rapiuuid.lib
new file mode 100644
index 00000000..8b60d9af
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/activesync/Lib/rapiuuid.lib
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_activesync/main.cpp b/Src/Plugins/Portable/pmp_activesync/main.cpp
new file mode 100644
index 00000000..a1408050
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/main.cpp
@@ -0,0 +1,220 @@
+//#define PLUGIN_NAME "Nullsoft ActiveSync Plug-in"
+#define PLUGIN_VERSION L"0.25"
+
+#include "ASDevice.h"
+
+int init();
+void quit();
+intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3);
+
+extern PMPDevicePlugin plugin = {PMPHDR_VER,0,init,quit,MessageProc};
+
+static HANDLE killEvent=0, hThread=0;
+static DWORD WINAPI ThreadFunc(LPVOID lpParam);
+
+IRAPIDesktop *pIRapiDesktop = NULL;
+
+// wasabi based services for localisation support
+api_language *WASABI_API_LNG = 0;
+HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
+
+std::vector<ASDevice*> devices;
+
+std::vector<ejectedDevice*> ejected;
+static RAPIDEVICEID lastDevId;
+
+
+class MyRAPISink : public IRAPISink {
+public:
+ virtual HRESULT STDMETHODCALLTYPE OnDeviceConnected(IRAPIDevice *pIDevice) {
+ RAPI_DEVICEINFO devInfo;
+ if(!SUCCEEDED(pIDevice->GetDeviceInfo(&devInfo))) return S_OK;
+ SysFreeString(devInfo.bstrName);
+ SysFreeString(devInfo.bstrPlatform);
+
+ EnterCriticalSection(&cs);
+
+ lastDevId = devInfo.DeviceId;
+ for(unsigned int i=0; i<ejected.size(); i++) {
+ if(devInfo.DeviceId == ejected[i]->id) {
+ ejected[i]->marked=true;
+ LeaveCriticalSection(&cs);
+ return S_OK;
+ }
+ }
+
+ for(unsigned int i=0; i<devices.size(); i++) {
+ if(devInfo.DeviceId == devices[i]->devInfo.DeviceId || devices[i]->pIDevice == pIDevice) {
+ LeaveCriticalSection(&cs);
+ return S_OK;
+ }
+ }
+
+ IRAPISession *pISession = NULL;
+ if (SUCCEEDED(pIDevice->CreateSession(&pISession))) {
+ if (SUCCEEDED(pISession->CeRapiInit())) devices.push_back(new ASDevice(pIDevice,pISession));
+ else pISession->Release();
+ }
+
+ LeaveCriticalSection(&cs);
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE OnDeviceDisconnected(IRAPIDevice *pIDevice) {
+ EnterCriticalSection(&cs);
+ RAPI_DEVICEINFO devInfo;
+ if(!SUCCEEDED(pIDevice->GetDeviceInfo(&devInfo))) return S_OK;
+ for(unsigned int i=0; i<devices.size(); i++) {
+ if(devInfo.DeviceId == devices[i]->devInfo.DeviceId || devices[i]->pIDevice == pIDevice) {
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)devices[i],PMP_IPC_DEVICEDISCONNECTED);
+ delete devices[i];
+ }
+ }
+ SysFreeString(devInfo.bstrName);
+ SysFreeString(devInfo.bstrPlatform);
+ LeaveCriticalSection(&cs);
+ return S_OK;
+ }
+
+ DWORD RAPISinkContext;
+ CRITICAL_SECTION cs;
+ ULONG refs;
+ MyRAPISink() {refs=1; InitializeCriticalSection(&cs);}
+ ~MyRAPISink() { DeleteCriticalSection(&cs); }
+ #define IMPLEMENTS(ifc) if (riid == IID_ ## ifc) { ++refs; *ppvObject = static_cast<ifc *>(this); return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,void __RPC_FAR *__RPC_FAR *ppvObject) {
+ IMPLEMENTS(IRAPISink);
+ IMPLEMENTS(IUnknown);
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+ virtual ULONG STDMETHODCALLTYPE AddRef() { return ++refs; }
+ virtual ULONG STDMETHODCALLTYPE Release() { int x = --refs; if(!x) delete this; return x; }
+ #undef IMPLEMENTS
+};
+
+MyRAPISink *pMyRapiSink=NULL;
+
+int init() {
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ HRESULT hr = CoCreateInstance(CLSID_RAPI,NULL,CLSCTX_INPROC_SERVER,IID_IRAPIDesktop,(void**)&pIRapiDesktop);
+ if(!SUCCEEDED(hr) || !pIRapiDesktop) return -1; // no activesync on this computer!
+
+ // loader so that we can get the localisation service api for use
+ waServiceFactory *sf = plugin.service->service_getServiceByGuid(languageApiGUID);
+ if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
+
+ // need to have this initialised before we try to do anything with localisation features
+ WASABI_API_START_LANG(plugin.hDllInstance,PmpACTIVESYNCLangGUID);
+
+ static wchar_t szDescription[256];
+ swprintf(szDescription, ARRAYSIZE(szDescription),
+ WASABI_API_LNGSTRINGW(IDS_NULLSOFT_ACTIVESYNC_PLUGIN), PLUGIN_VERSION);
+ plugin.description = szDescription;
+
+ killEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
+ DWORD dwThreadId;
+ hThread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &dwThreadId);
+
+ return 0;
+}
+
+static void enumDevices() {
+ // find all the currently connected devices
+ IRAPIEnumDevices* pIRapiEnumDevices = NULL;
+ HRESULT hr = pIRapiDesktop->EnumDevices(&pIRapiEnumDevices);
+
+ for (unsigned int i = 0; i < ejected.size(); i++) ejected[i]->marked = false;
+
+ while (SUCCEEDED(hr) && pIRapiEnumDevices) {
+ IRAPIDevice* pIRapiDevice = NULL;
+ hr = pIRapiEnumDevices->Next(&pIRapiDevice);
+ if (SUCCEEDED(hr) && pIRapiDevice) {
+ pMyRapiSink->OnDeviceConnected(pIRapiDevice);
+ pIRapiDevice->Release();
+ }
+ else {
+ pIRapiEnumDevices->Release();
+ pIRapiEnumDevices = NULL;
+ }
+ }
+
+ //for (unsigned int i = 0; i < ejected.size(); i++)
+ //{
+ // if (!ejected[i]->marked)
+ // {
+ // free(ejected[i]);
+ // ejected.eraseindex(i);
+ // }
+ //}
+ auto it = ejected.begin();
+ while (it != ejected.end())
+ {
+ ejectedDevice* dev = *it;
+ if (!dev->marked)
+ {
+ free(dev);
+ it = ejected.erase(it);
+ }
+ else
+ {
+ it++;
+ }
+ }
+}
+
+static void init2() {
+ // set up device connection/disconnection notifications
+ pMyRapiSink = new MyRAPISink();
+ pIRapiDesktop->Advise(pMyRapiSink,(DWORD_PTR*)&pMyRapiSink->RAPISinkContext);
+
+ // find currently attached devices
+ enumDevices();
+}
+
+void quit() {
+ SetEvent(killEvent);
+ if (hThread) {
+ for(;;) {
+ int val = WaitForSingleObjectEx(hThread,15000,TRUE);
+ if(val == WAIT_OBJECT_0) { CloseHandle(hThread); break; }
+ else if(val == WAIT_TIMEOUT) { TerminateThread(hThread, 0); break; }
+ else continue;
+ }
+ }
+ CloseHandle(killEvent);
+
+ pIRapiDesktop->UnAdvise(pMyRapiSink->RAPISinkContext);
+ pIRapiDesktop->Release();
+ pMyRapiSink->Release();
+ CoUninitialize();
+ for(unsigned int i=0; i<ejected.size(); i++) free(ejected[i]);
+}
+
+static DWORD WINAPI ThreadFunc(LPVOID lpParam) {
+ CoInitializeEx(0,COINIT_MULTITHREADED);
+ init2();
+ while (WaitForSingleObjectEx(killEvent,5000,TRUE) != WAIT_OBJECT_0) {
+ // FUCKO: For some reason I'm not getting the device connected notifications, so lets just enum for devices on a regular basis.
+ enumDevices();
+ }
+ CoUninitialize();
+ return 0;
+}
+
+intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3) {
+ if (msg == PMP_NO_CONFIG)
+ return TRUE;
+
+ return FALSE;
+}
+
+extern "C" {
+ __declspec( dllexport ) PMPDevicePlugin * winampGetPMPDevicePlugin(){return &plugin;}
+ __declspec( dllexport ) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) {
+ int i = (int)devices.size();
+ while(i-- > 0) devices[i]->Close();
+ return PMP_PLUGIN_UNINSTALL_NOW;
+ }
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_activesync/pmp_activesync.rc b/Src/Plugins/Portable/pmp_activesync/pmp_activesync.rc
new file mode 100644
index 00000000..a74b7178
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/pmp_activesync.rc
@@ -0,0 +1,116 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""version.rc2""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RCDATA
+//
+
+IDR_ACTIVESYNC_ICON RCDATA ".\\resources\\activeSyncIcon.png"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_CONFIG DIALOGEX 0, 0, 264, 226
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Folders",IDC_STATIC,4,3,255,83
+ LTEXT "Music Folder",IDC_STATIC,8,16,40,8
+ EDITTEXT IDC_FOLDER_MUSIC,56,14,197,14,ES_AUTOHSCROLL
+ LTEXT "Video Folder",IDC_STATIC,8,32,40,8
+ EDITTEXT IDC_FOLDER_VIDEO,56,30,197,14,ES_AUTOHSCROLL
+ LTEXT "Playlist Folder",IDC_STATIC,8,49,45,8
+ EDITTEXT IDC_FOLDER_PLAYLIST,56,46,197,14,ES_AUTOHSCROLL
+ PUSHBUTTON "Rescan folders",IDC_RESCAN,7,66,56,14
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_NULLSOFT_ACTIVESYNC_PLUGIN "Nullsoft ActiveSync Plug-in v%s"
+ 65535 "{B81F32B8-4AA4-4eba-8798-95F13812F638}"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_LOADING "Loading %s..."
+ IDS_TRANSFERRING "Transferring..."
+ IDS_CANNOT_OPEN_LOCAL_FILE "Cannot open local file"
+ IDS_CANNOT_OPEN_FILE_ON_DEVICE "Cannot open file on device"
+ IDS_ERROR_WRITING_FILE "Error writing to file"
+ IDS_TRANSFERRING_PERCENT "Transferring %d%%"
+ IDS_DONE "Done"
+ IDS_CANNOT_OPEN_DESTINATION "Cannot open destination file"
+ IDS_ADVANCED "Advanced"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc2"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/Plugins/Portable/pmp_activesync/pmp_activesync.sln b/Src/Plugins/Portable/pmp_activesync/pmp_activesync.sln
new file mode 100644
index 00000000..f8e22711
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/pmp_activesync.sln
@@ -0,0 +1,18 @@
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmp_activesync", "pmp_activesync.vcproj", "{60D71BB7-D741-444E-99ED-7249A716B99F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {60D71BB7-D741-444E-99ED-7249A716B99F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {60D71BB7-D741-444E-99ED-7249A716B99F}.Release|Win32.ActiveCfg = Release|Win32
+ {60D71BB7-D741-444E-99ED-7249A716B99F}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Src/Plugins/Portable/pmp_activesync/pmp_activesync.vcxproj b/Src/Plugins/Portable/pmp_activesync/pmp_activesync.vcxproj
new file mode 100644
index 00000000..9100716b
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/pmp_activesync.vcxproj
@@ -0,0 +1,357 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>17.0</VCProjectVersion>
+ <ProjectGuid>{60D71BB7-D741-444E-99ED-7249A716B99F}</ProjectGuid>
+ <RootNamespace>pmp_activesync</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>17.0.32505.173</_ProjectFileVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <LinkIncremental>false</LinkIncremental>
+ <GenerateManifest>true</GenerateManifest>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <GenerateManifest>true</GenerateManifest>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg">
+ <VcpkgEnabled>false</VcpkgEnabled>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>$(IntDir)$(TargetName).tlb</TypeLibraryName>
+ <HeaderFileName />
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\..\replicant;activesync\Inc;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_WINDOWS;_USRDLL;ML_ex_EXPORTS;WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <IgnoreStandardIncludePath>false</IgnoreStandardIncludePath>
+ <StringPooling>true</StringPooling>
+ <MinimalRebuild>false</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader />
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>rapiuuid.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalLibraryDirectories>activesync\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapExports>false</MapExports>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention />
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <IgnoreSpecificDefaultLibraries>libc.lib;msvcprt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)*.dll ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+xcopy /Y /D $(IntDir)*.pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TypeLibraryName>$(IntDir)$(TargetName).tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\..\replicant;activesync\Inc;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_WINDOWS;_USRDLL;ML_ex_EXPORTS;WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <IgnoreStandardIncludePath>false</IgnoreStandardIncludePath>
+ <StringPooling>true</StringPooling>
+ <MinimalRebuild>false</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>rapiuuid.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalLibraryDirectories>activesync\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapExports>false</MapExports>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <IgnoreSpecificDefaultLibraries>libc.lib;msvcprt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)*.dll ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+xcopy /Y /D $(IntDir)*.pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>$(IntDir)$(TargetName).tlb</TypeLibraryName>
+ <HeaderFileName />
+ </Midl>
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\..\replicant;activesync\Inc;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_WINDOWS;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <IgnoreStandardIncludePath>false</IgnoreStandardIncludePath>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <PrecompiledHeader />
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>rapiuuid.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalLibraryDirectories>activesync\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <IgnoreSpecificDefaultLibraries>libc.lib;msvcprt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TypeLibraryName>$(IntDir)$(TargetName).tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\..\replicant;activesync\Inc;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_WINDOWS;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <IgnoreStandardIncludePath>false</IgnoreStandardIncludePath>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>rapiuuid.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalLibraryDirectories>activesync\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <IgnoreSpecificDefaultLibraries>libc.lib;msvcprt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp" />
+ <ClCompile Include="ASDevice.cpp" />
+ <ClCompile Include="main.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\General\gen_ml\ml.h" />
+ <ClInclude Include="..\..\Library\ml_pmp\pmp.h" />
+ <ClInclude Include="ASDevice.h" />
+ <ClInclude Include="resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="resources\activeSyncIcon.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="pmp_activesync.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
+ <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_activesync/pmp_activesync.vcxproj.filters b/Src/Plugins/Portable/pmp_activesync/pmp_activesync.vcxproj.filters
new file mode 100644
index 00000000..7627405a
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/pmp_activesync.vcxproj.filters
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{b35076f0-5e1b-4df9-baa4-ef63b5b1e046}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{5ed7e868-d2e1-4274-890e-0f94583196e2}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl</Extensions>
+ </Filter>
+ <Filter Include="resources">
+ <UniqueIdentifier>{194593b8-f700-465e-aa6d-b982a8271c7e}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="ASDevice.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="ASDevice.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\General\gen_ml\ml.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Library\ml_pmp\pmp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="resources\activeSyncIcon.png">
+ <Filter>resources</Filter>
+ </Image>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="pmp_activesync.rc">
+ <Filter>resources</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_activesync/resource.h b/Src/Plugins/Portable/pmp_activesync/resource.h
new file mode 100644
index 00000000..e54c6a67
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/resource.h
@@ -0,0 +1,31 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by pmp_activesync.rc
+//
+#define IDS_LOADING 1
+#define IDS_TRANSFERRING 2
+#define IDS_CANNOT_OPEN_LOCAL_FILE 3
+#define IDS_CANNOT_OPEN_FILE_ON_DEVICE 4
+#define IDS_ERROR_WRITING_FILE 5
+#define IDS_TRANSFERRING_PERCENT 6
+#define IDS_DONE 7
+#define IDS_CANNOT_OPEN_DESTINATION 8
+#define IDS_ADVANCED 9
+#define IDR_ACTIVESYNC_ICON 101
+#define IDD_CONFIG 102
+#define IDC_FOLDER_MUSIC 1001
+#define IDC_FOLDER_PLAYLIST 1002
+#define IDC_FOLDER_VIDEO 1003
+#define IDC_RESCAN 1004
+#define IDS_NULLSOFT_ACTIVESYNC_PLUGIN 65534
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 106
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1005
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/Plugins/Portable/pmp_activesync/resources/activeSyncIcon.png b/Src/Plugins/Portable/pmp_activesync/resources/activeSyncIcon.png
new file mode 100644
index 00000000..ec7a5ab2
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/resources/activeSyncIcon.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_activesync/version.rc2 b/Src/Plugins/Portable/pmp_activesync/version.rc2
new file mode 100644
index 00000000..353480c4
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_activesync/version.rc2
@@ -0,0 +1,39 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#include "../../../Winamp/buildType.h"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,25,0,0
+ PRODUCTVERSION WINAMP_PRODUCTVER
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Winamp SA"
+ VALUE "FileDescription", "Winamp Portable Device Plug-in"
+ VALUE "FileVersion", "0,25,0,0"
+ VALUE "InternalName", "Nullsoft ActiveSync"
+ VALUE "LegalCopyright", "Copyright © 2006-2023 Winamp SA"
+ VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
+ VALUE "OriginalFilename", "pmp_activesync.dll"
+ VALUE "ProductName", "Winamp"
+ VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/Src/Plugins/Portable/pmp_android/albumart.cpp b/Src/Plugins/Portable/pmp_android/albumart.cpp
new file mode 100644
index 00000000..7d3a26a7
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/albumart.cpp
@@ -0,0 +1,58 @@
+#include "../../Library/ml_pmp/pmp.h"
+#include "api.h"
+#include "../agave/albumart/svc_albumartprovider.h"
+#include <api/service/waservicefactory.h>
+
+extern PMPDevicePlugin plugin;
+
+static svc_albumArtProvider *FindProvider(const wchar_t *filename, int providerType, waServiceFactory **factory)
+{
+ FOURCC albumartprovider = svc_albumArtProvider::getServiceType();
+ int n = (int)plugin.service->service_getNumServices(albumartprovider);
+ for (int i=0; i<n; i++)
+ {
+ waServiceFactory *sf = plugin.service->service_enumService(albumartprovider,i);
+ if (sf)
+ {
+ svc_albumArtProvider * provider = (svc_albumArtProvider*)sf->getInterface();
+ if (provider)
+ {
+ if (provider->ProviderType() == providerType && provider->IsMine(filename))
+ {
+ *factory = sf;
+ return provider;
+ }
+ sf->releaseInterface(provider);
+ }
+ }
+ }
+ return NULL;
+}
+
+void CopyAlbumArt(const wchar_t *source, const wchar_t *destination)
+{
+ size_t datalen = 0;
+ void *data = 0;
+ wchar_t *mimeType = 0;
+ waServiceFactory *destinationFactory = 0;
+ svc_albumArtProvider *destinationProvider = FindProvider(destination, ALBUMARTPROVIDER_TYPE_EMBEDDED, &destinationFactory);
+ if (destinationFactory)
+ {
+ /* First, look to see if there's already embedded album art */
+ if (destinationProvider->GetAlbumArtData(destination, L"cover", &data, &datalen, &mimeType) == ALBUMARTPROVIDER_SUCCESS && data && datalen)
+ {
+ destinationFactory->releaseInterface(destinationProvider);
+ WASABI_API_MEMMGR->sysFree(data);
+ WASABI_API_MEMMGR->sysFree(mimeType);
+ return;
+ }
+ else if (AGAVE_API_ALBUMART->GetAlbumArtData(source, L"cover", &data, &datalen, &mimeType) == ALBUMART_SUCCESS && data && datalen)
+ {
+ destinationProvider->SetAlbumArtData(destination, L"cover", data, datalen, mimeType);
+ WASABI_API_MEMMGR->sysFree(data);
+ WASABI_API_MEMMGR->sysFree(mimeType);
+
+ destinationFactory->releaseInterface(destinationProvider);
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_android/androiddevice.cpp b/Src/Plugins/Portable/pmp_android/androiddevice.cpp
new file mode 100644
index 00000000..6ea4e04c
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/androiddevice.cpp
@@ -0,0 +1,1869 @@
+#include "androiddevice.h"
+#include "resource.h"
+#include "androidplaylist.h"
+#include "androidplaylistsaver.h"
+#include "api.h"
+#include "../winamp/wa_ipc.h"
+#include <tataki/bitmap/bitmap.h>
+#include <tataki/canvas/bltcanvas.h>
+#include <shlobj.h>
+#include <strsafe.h>
+#include <shlwapi.h>
+
+// from main.cpp
+extern PMPDevicePlugin plugin;
+extern std::vector<AndroidDevice*> devices;
+extern bool loading_devices[26];
+
+// from utils.cpp
+extern BOOL RecursiveCreateDirectory(wchar_t* buf);
+extern bool supportedFormat(wchar_t * file, wchar_t * supportedFormats);
+extern DeviceType detectDeviceType(wchar_t drive);
+extern __int64 fileSize(wchar_t * filename);
+extern void removebadchars(wchar_t *s);
+extern wchar_t * fixReplacementVars(wchar_t *str, int str_size, Device * dev, songid_t song);
+static INT_PTR CALLBACK prefs_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+int CopyFile(const wchar_t *infile, const wchar_t *outfile, void * callbackContext, void (*callback)(void * callbackContext, wchar_t * status), int * killswitch);
+extern BOOL EjectVolume(TCHAR cDriveLetter);
+
+static int connected_drives[26] = {0, };
+// from albumart.cpp
+void CopyAlbumArt(const wchar_t *source, const wchar_t *destination);
+
+// called from ml_pmp
+__int64 AndroidDevice::getDeviceCapacityAvailable() // in bytes
+{
+ ULARGE_INTEGER tfree={0,}, total={0,}, freeb={0,};
+ wchar_t path[4]=L"x:\\";
+ path[0]=drive;
+ GetDiskFreeSpaceEx(path, &tfree, &total, &freeb);
+ return freeb.QuadPart;
+}
+
+// called from ml_pmp
+__int64 AndroidDevice::getDeviceCapacityTotal()
+{
+ // in bytes
+ ULARGE_INTEGER tfree={0,}, total={0,}, freeb={0,};
+ wchar_t path[4]=L"x:\\";
+ path[0]=drive;
+ GetDiskFreeSpaceEx(path, &tfree, &total, &freeb);
+ return total.QuadPart;
+}
+
+// called from ml_pmp
+void AndroidDevice::Eject()
+{
+ // if you ejected successfully, you MUST call PMP_IPC_DEVICEDISCONNECTED and delete this
+ for(size_t i=0; i < devices.size(); i++)
+ {
+ AndroidDevice *device = devices.at(i);
+ if (device == this)
+ {
+ if (EjectVolume(drive))
+ {
+ devices.erase(devices.begin() + i);
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
+ delete this;
+ }
+ else
+ {
+ wchar_t titleStr[128] = {0};
+ MessageBox(plugin.hwndLibraryParent,WASABI_API_LNGSTRINGW(IDS_FAILED_TO_EJECT_DRIVE), WASABI_API_LNGSTRINGW_BUF(IDS_ERROR,titleStr,128),0);
+ }
+
+ break;
+ }
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::Close()
+{
+ // save any changes, and call PMP_IPC_DEVICEDISCONNECTED AND delete this
+ for (size_t i=0; i < devices.size(); i++)
+ {
+ if (((AndroidDevice*)devices.at(i)) == this)
+ {
+ devices.erase(devices.begin() + i);
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
+ delete this;
+ break;
+ }
+ }
+}
+
+// called from ml_pmp
+// return 0 for success, -1 for failed or cancelled
+int AndroidDevice::transferTrackToDevice(const itemRecordW * track, // the track to transfer
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void *callbackContext, wchar_t *status), // call this every so often so the GUI can be updated. Including when finished!
+ songid_t * songid, // fill in the songid when you are finished
+ int * killswitch) // if this gets set to anything other than zero, the transfer has been cancelled by the user
+{
+ wchar_t fn[MAX_PATH] = L"X:\\";
+ lstrcpyn(fn, songFormat, MAX_PATH);
+ fn[0] = drive;
+ wchar_t * src = track->filename;
+ wchar_t ext[10] = {0};
+ wchar_t *e = wcsrchr(src,L'.');
+ if (e) lstrcpyn(ext, e, 10);
+
+ bool transcodefile = false;
+ if (transcoder && transcoder->ShouldTranscode(src))
+ {
+ int r = transcoder->CanTranscode(src, ext);
+ if (r != 0 && r != -1) transcodefile = true;
+ }
+
+ AndroidSong *s = new AndroidSong();
+ lstrcpyn(s->filename, src, MAX_PATH); //this will get written over, but for now we have this so that the user can keep the old filename
+
+ fillMetaData(s); // TODO: benski> used cached info inside track (itemRecordW) if available
+ fixReplacementVars(fn, MAX_PATH, this, (songid_t)s);
+
+ StringCchCat(fn, MAX_PATH, ext); //place extension
+ StringCchCopy(s->filename, MAX_PATH, fn);
+
+ wchar_t * dir = wcsrchr(fn,L'\\');
+ wchar_t * dir2 = wcsrchr(fn,L'/');
+ wchar_t slash;
+ if (dir2 > dir)
+ {
+ dir = dir2;
+ slash=L'/';
+ }
+ else slash = L'\\';
+ if (dir) *dir = 0;
+ RecursiveCreateDirectory(fn);
+ if (dir) *dir = slash;
+ int r;
+ if (transcodefile)
+ {
+ r = transcoder->TranscodeFile(src, fn, killswitch, callback, callbackContext);
+ }
+ else
+ {
+ r = CopyFile(src, fn, callbackContext, callback, killswitch);
+ }
+
+ if (r == 0)
+ {
+ // TODO: benski> do we need to update any fields from the transcoded filed?
+ CopyAlbumArt(src, fn);
+ writeRecordToDB(s);
+ callback(callbackContext, WASABI_API_LNGSTRINGW(IDS_DONE));
+ *songid = (songid_t)s;
+ }
+ else
+ {
+ callback(callbackContext, WASABI_API_LNGSTRINGW(IDS_TRANSFER_FAILED));
+ delete s;
+ }
+ return r;
+}
+
+// called from ml_pmp
+int AndroidDevice::trackAddedToTransferQueue(const itemRecordW *track)
+{
+ // return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
+ __int64 k = getTrackSizeOnDevice(track);
+ if (!k) return -2;
+ __int64 l = (__int64)k;
+ __int64 avail = getDeviceCapacityAvailable();
+ __int64 cmp = transferQueueLength;
+ cmp += l;
+ if (cmp > avail) return -1;
+ else
+ {
+ transferQueueLength += l;
+ return 0;
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::trackRemovedFromTransferQueue(const itemRecordW *track)
+{
+ transferQueueLength -= (__int64)getTrackSizeOnDevice(track);
+}
+
+// called from ml_pmp
+// return the amount of space that will be taken up on the device by the track (once it has been tranferred)
+// or 0 for incompatable. This is usually the filesize, unless you are transcoding. An estimate is acceptable.
+__int64 AndroidDevice::getTrackSizeOnDevice(const itemRecordW *track)
+{
+ if (transcoder)
+ {
+ if (transcoder->ShouldTranscode(track->filename))
+ {
+ int k = transcoder->CanTranscode(track->filename);
+ if (k != -1 && k != 0) return k;
+ return 0;
+ }
+ else return fileSize(track->filename);
+ }
+ else
+ {
+ if (!supportedFormat(track->filename,supportedFormats)) return 0;
+ return fileSize(track->filename);
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::deleteTrack( songid_t songid )
+{
+ // physically remove from device. Be sure to remove it from all the playlists!
+ AndroidSong *s = (AndroidSong *)songid;
+
+ //errno == 2 is ENOENT
+ if ( !_wunlink( s->filename ) || errno == 2 ) //will continue delete if file was deleted successfully or file path does not exist in the first place (errno==2)
+ {
+ for ( size_t i = 0; i < androidPlaylists.size(); i++ )
+ {
+ AndroidPlaylist *pl = androidPlaylists.at( i );
+ pl->RemoveSong( s );
+ }
+
+ if ( purgeFolders[ 0 ] == '1' )
+ {
+ RemoveDirectory( s->filename );
+ }
+
+ delete s;
+ }
+ else
+ {
+ char titleStr[ 32 ] = { 0 };
+ MessageBoxA( plugin.hwndLibraryParent, WASABI_API_LNGSTRING( IDS_TRACK_IN_USE ), WASABI_API_LNGSTRING_BUF( IDS_ERROR, titleStr, 32 ), 0 );
+ }
+}
+
+// called from ml_pmp
+// optional. Will be called at a good time to save changes
+void AndroidDevice::commitChanges()
+{
+ Nullsoft::Utility::AutoLock lock(dbcs);
+ if (deviceTable && androidPlaylists.size() && androidPlaylists[0]->dirty)
+ {
+ NDE_Table_Sync(deviceTable);
+ androidPlaylists[0]->dirty=false;
+ }
+
+ for (size_t i=1;i<androidPlaylists.size();i++)
+ {
+ AndroidPlaylist *pl = androidPlaylists[i];
+ if (pl->dirty)
+ {
+ // Lets delete the current playlist file
+ _wunlink(pl->filename);
+
+ AndroidPlaylistSaver playlistSaver(pl->filename, L"autosaved", pl);
+ playlistSaver.Save();
+ pl->dirty = false;
+ }
+ }
+
+}
+
+// called from ml_pmp
+int AndroidDevice::getPlaylistCount()
+{
+ // always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
+ return (int)androidPlaylists.size();
+}
+
+// called from ml_pmp
+// PlaylistName(0) should return the name of the device.
+void AndroidDevice::getPlaylistName(int playlistnumber, wchar_t *buf, int len)
+{
+ wchar_t * pathName = androidPlaylists.at(playlistnumber)->filename;
+ if (playlistnumber != 0)
+ {
+ if (pathName[0])
+ {
+ wchar_t * playlistName = PathFindFileNameW(pathName);
+ lstrcpyn(buf,playlistName,len);
+ PathRemoveExtension(buf);
+ }
+ }
+ else //playlist number = 0 -> this is the device
+ {
+ if (pathName[0])
+ {
+ //if we have a custom device name
+ lstrcpyn(buf,pathName,len);
+ }
+ else
+ {
+ WASABI_API_LNGSTRINGW_BUF(IDS_ANDROID_DRIVE_X,buf,len);
+ wchar_t * x = wcsrchr(buf,L'X');
+ if (x) *x = drive;
+ }
+ }
+}
+
+// called from ml_pmp
+int AndroidDevice::getPlaylistLength(int playlistnumber)
+{
+ return (int)androidPlaylists.at(playlistnumber)->size();
+}
+
+// called from ml_pmp
+songid_t AndroidDevice::getPlaylistTrack(int playlistnumber,int songnum)
+{
+ // returns a songid
+ return (songid_t) androidPlaylists.at(playlistnumber)->at(songnum);
+}
+
+// called from ml_pmp
+void AndroidDevice::setPlaylistName(int playlistnumber, const wchar_t *buf)
+{
+ // with playlistnumber==0, set the name of the device.
+ AndroidPlaylist * pl = androidPlaylists.at(playlistnumber);
+ if (playlistnumber==0)
+ {
+ WritePrivateProfileString(L"pmp_android",L"customName",buf,iniFile);
+ lstrcpyn(pl->filename,buf,sizeof(pl->filename)/sizeof(wchar_t));
+ }
+ else
+ {
+ wchar_t currentFilename[MAX_PATH] = {0};
+ lstrcpynW(currentFilename, pl->filename, MAX_PATH);
+
+ wchar_t * newFilename = const_cast<wchar_t *>(buf);
+ if (wcslen(buf) >= MAX_PATH-1) newFilename[MAX_PATH-1]=0;
+ while (newFilename && *newFilename && *newFilename == L'.') newFilename++;
+ removebadchars(newFilename);
+ StringCchPrintf(pl->filename,MAX_PATH,L"%s\\%s.m3u",pldir,newFilename);
+ pl->filename[0]=drive;
+ MoveFile(currentFilename, pl->filename);
+
+ pl->dirty=true;
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::playlistSwapItems(int playlistnumber, int posA, int posB)
+{
+ // swap the songs at position posA and posB
+ AndroidPlaylist * pl = (AndroidPlaylist*)androidPlaylists.at(playlistnumber);
+ pl->swap(posA, posB);
+}
+
+// called from ml_pmp
+void AndroidDevice::sortPlaylist(int playlistnumber, int sortBy)
+{
+ // TODO: implement
+}
+
+// called from ml_pmp
+void AndroidDevice::addTrackToPlaylist(int playlistnumber, songid_t songid)
+{
+ // adds songid to the end of the playlist
+ AndroidSong* song = (AndroidSong *) songid;
+ AndroidPlaylist * pl = (AndroidPlaylist*)androidPlaylists.at(playlistnumber);
+ pl->push_back(song);
+}
+
+// called from ml_pmp
+void AndroidDevice::removeTrackFromPlaylist(int playlistnumber, int songnum)
+{
+ //where songnum is the position of the track in the playlist
+ AndroidPlaylist * pl = (AndroidPlaylist*)androidPlaylists.at(playlistnumber);
+ pl->eraseAt(songnum);
+
+}
+
+// called from ml_pmp
+void AndroidDevice::deletePlaylist(int playlistnumber)
+{
+ AndroidPlaylist * pl = (AndroidPlaylist*)androidPlaylists.at(playlistnumber);
+ _wunlink(pl->filename);
+ androidPlaylists.erase(androidPlaylists.begin() + playlistnumber);
+ delete pl;
+}
+
+// called from ml_pmp
+int AndroidDevice::newPlaylist(const wchar_t *name)
+{
+ wchar_t plname[MAX_PATH] = {0};
+ StringCchCopy(plname, MAX_PATH, name);
+ removebadchars(plname);
+
+
+ // create empty playlist, returns playlistnumber. -1 for failed.
+ for (std::vector<AndroidPlaylist*>::iterator itr=androidPlaylists.begin();itr!=androidPlaylists.end();itr++)
+ {
+ AndroidPlaylist *p = *itr;
+ if (!_wcsicmp(p->playlistName, plname))
+ return -1;
+ }
+
+ wchar_t buff[MAX_PATH] = {0};
+ StringCchPrintf(buff, MAX_PATH, L"%s\\%s.m3u",pldir,plname);
+
+ AndroidPlaylist * pl = new AndroidPlaylist(*this, buff, false);
+ pl->filename[0]=drive;
+
+ //Lets save the playlist right away
+ AndroidPlaylistSaver playlistSaver(pl->filename, L"autosaved", pl);
+ playlistSaver.Save();
+
+ androidPlaylists.push_back(pl);
+ return (int)androidPlaylists.size()-1;
+}
+
+// called from ml_pmp
+void AndroidDevice::getTrackArtist(songid_t songid, wchar_t *buf, int len)
+{
+ AndroidSong* song = (AndroidSong*)songid;
+ if (!song) return;
+
+ buf[0] = L'\0';
+ StringCchCopy(buf, len, song->artist);
+}
+
+// called from ml_pmp
+void AndroidDevice::getTrackAlbum(songid_t songid, wchar_t *buf, int len)
+{
+ AndroidSong* song = (AndroidSong*)songid;
+ if (!song) return;
+
+ buf[0] = L'\0';
+ StringCchCopy(buf, len, song->album);
+}
+
+// called from ml_pmp
+void AndroidDevice::getTrackTitle(songid_t songid, wchar_t *buf, int len)
+{
+ AndroidSong* song = (AndroidSong*)songid;
+ if (!song) return;
+
+ StringCchCopy(buf, len, song->title);
+}
+
+// called from ml_pmp
+int AndroidDevice::getTrackTrackNum(songid_t songid)
+{
+ AndroidSong* song = (AndroidSong*)songid;
+ if (!song) return 0;
+
+ return song->track;
+}
+
+// called from ml_pmp
+int AndroidDevice::getTrackDiscNum(songid_t songid)
+{
+ AndroidSong* song = (AndroidSong*)songid;
+ if (!song) return 0;
+
+ return song->discnum;
+}
+
+// called from ml_pmp
+void AndroidDevice::getTrackGenre(songid_t songid, wchar_t * buf, int len)
+{
+ AndroidSong* song = (AndroidSong*)songid;
+ if (!song) return;
+
+ StringCchCopy(buf, len, song->genre);
+}
+
+// called from ml_pmp
+int AndroidDevice::getTrackYear(songid_t songid)
+{
+ AndroidSong* song = (AndroidSong*)songid;
+ if (!song) return 0;
+
+ return song->year;
+}
+
+// called from ml_pmp
+__int64 AndroidDevice::getTrackSize(songid_t songid)
+{
+ // in bytes
+ AndroidSong* song = (AndroidSong*)songid;
+ if (!song) return 0;
+
+ return song->size;
+}
+
+// called from ml_pmp
+int AndroidDevice::getTrackLength(songid_t songid)
+{
+ // in millisecs
+ AndroidSong* song = (AndroidSong*)songid;
+ if (!song) return 0;
+
+ return song->length;
+}
+
+// called from ml_pmp
+int AndroidDevice::getTrackBitrate(songid_t songid)
+{
+ // in kbps
+ AndroidSong* song = (AndroidSong*)songid;
+ if (!song) return 0;
+
+ return song->bitrate;
+}
+
+// called from ml_pmp
+int AndroidDevice::getTrackPlayCount(songid_t songid)
+{
+ AndroidSong* song = (AndroidSong*)songid;
+ if (!song) return 0;
+
+ return song->playcount;
+}
+
+// called from ml_pmp
+int AndroidDevice::getTrackRating(songid_t songid)
+{
+ //0-5
+ // TODO: implement
+ return 0;
+}
+
+// called from ml_pmp
+__time64_t AndroidDevice::getTrackLastPlayed(songid_t songid)
+{
+ // in unix time format
+ // TODO: implement
+ return 0;
+}
+
+// called from ml_pmp
+__time64_t AndroidDevice::getTrackLastUpdated(songid_t songid)
+{
+ // in unix time format
+ // TODO: implement
+ return 0;
+}
+
+// called from ml_pmp
+void AndroidDevice::getTrackAlbumArtist(songid_t songid, wchar_t *buf, int len)
+{
+ AndroidSong* song = (AndroidSong*)songid;
+ if (!song) return;
+
+ StringCchCopy(buf, len, song->albumartist);
+}
+
+// called from ml_pmp
+void AndroidDevice::getTrackPublisher(songid_t songid, wchar_t *buf, int len)
+{
+ AndroidSong* song = (AndroidSong*)songid;
+ if (!song) return;
+
+ StringCchCopy(buf, len, song->publisher);
+}
+
+// called from ml_pmp
+void AndroidDevice::getTrackComposer(songid_t songid, wchar_t *buf, int len)
+{
+ AndroidSong* song = (AndroidSong*)songid;
+ if (!song) return;
+
+ StringCchCopy(buf, len, song->composer);
+}
+
+// called from ml_pmp
+int AndroidDevice::getTrackType(songid_t songid)
+{
+ // TODO: implement
+ return 0;
+}
+
+// called from ml_pmp
+void AndroidDevice::getTrackExtraInfo(songid_t songid, const wchar_t *field, wchar_t *buf, int len)
+{
+ // TODO: implement
+ //optional
+}
+
+// called from ml_pmp
+// feel free to ignore any you don't support
+void AndroidDevice::setTrackArtist(songid_t songid, const wchar_t *value)
+{
+ AndroidSong *song = (AndroidSong *) songid;
+ if (song)
+ {
+ updateTrackField(song, DEVICEVIEW_COL_ARTIST, value, FIELD_STRING);
+ StringCchCopy(song->artist, FIELD_LENGTH, value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"artist", value);
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::setTrackAlbum(songid_t songid, const wchar_t *value)
+{
+ AndroidSong *song = (AndroidSong *) songid;
+ if (song)
+ {
+ updateTrackField(song, DEVICEVIEW_COL_ALBUM, value, FIELD_STRING);
+ StringCchCopy(song->album, FIELD_LENGTH, value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"album", value);
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::setTrackTitle(songid_t songid, const wchar_t *value)
+{
+ AndroidSong *song = (AndroidSong *) songid;
+ if (song)
+ {
+ updateTrackField(song, DEVICEVIEW_COL_TITLE, value, FIELD_STRING);
+ StringCchCopy(song->title, FIELD_LENGTH, value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"title", value);
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::setTrackTrackNum(songid_t songid, int value)
+{
+ AndroidSong *song = (AndroidSong *) songid;
+
+ if (song)
+ {
+ wchar_t track[FIELD_LENGTH] = {0};
+ updateTrackField(song, DEVICEVIEW_COL_TRACK, &value, FIELD_INTEGER);
+ song->track = value;
+ StringCchPrintf(track, FIELD_LENGTH, L"%d", value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"track", track);
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::setTrackDiscNum(songid_t songid, int value)
+{
+ AndroidSong *song = (AndroidSong *) songid;
+
+ if (song)
+ {
+ wchar_t discNum[FIELD_LENGTH] = {0};
+ updateTrackField(song, DEVICEVIEW_COL_DISC_NUMBER, &value, FIELD_INTEGER);
+ song->discnum = value;
+ StringCchPrintf(discNum, FIELD_LENGTH, L"%d", value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"disc", discNum);
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::setTrackGenre(songid_t songid, const wchar_t *value)
+{
+ AndroidSong *song = (AndroidSong *) songid;
+ if (song)
+ {
+ updateTrackField(song, DEVICEVIEW_COL_GENRE, value, FIELD_STRING);
+ StringCchCopy(song->genre, FIELD_LENGTH, value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"genre", value);
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::setTrackYear(songid_t songid, int year)
+{
+ AndroidSong *song = (AndroidSong *) songid;
+
+ if (song)
+ {
+ wchar_t yearStr[FIELD_LENGTH] = {0};
+ updateTrackField(song, DEVICEVIEW_COL_YEAR, &year, FIELD_INTEGER);
+ song->year = year;
+ StringCchPrintf(yearStr, FIELD_LENGTH, L"%d", year);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"year", yearStr);
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::setTrackPlayCount(songid_t songid, int value)
+{
+ AndroidSong *song = (AndroidSong *) songid;
+
+ if (song)
+ {
+ wchar_t playCount[FIELD_LENGTH] = {0};
+ updateTrackField(song, DEVICEVIEW_COL_PLAY_COUNT, &value, FIELD_INTEGER);
+ song->playcount = value;
+ StringCchPrintf(playCount, FIELD_LENGTH, L"%d", value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"playcount", playCount);
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::setTrackRating(songid_t songid, int value)
+{
+ AndroidSong *song = (AndroidSong *) songid;
+
+ if (song)
+ {
+ wchar_t rating[FIELD_LENGTH] = {0};
+ updateTrackField(song, DEVICEVIEW_COL_PLAY_COUNT, &value, FIELD_INTEGER);
+ song->playcount = value;
+ StringCchPrintf(rating, FIELD_LENGTH, L"%d", value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"rating", rating);
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::setTrackLastPlayed(songid_t songid, __time64_t value)
+{
+ // TODO: implement
+
+} // in unix time format
+
+// called from ml_pmp
+void AndroidDevice::setTrackLastUpdated(songid_t songid, __time64_t value)
+{
+ // TODO: implement
+
+} // in unix time format
+
+// called from ml_pmp
+void AndroidDevice::setTrackAlbumArtist(songid_t songid, const wchar_t *value)
+{
+ AndroidSong *song = (AndroidSong *) songid;
+ if (song)
+ {
+ updateTrackField(song, DEVICEVIEW_COL_ALBUM_ARTIST, value, FIELD_STRING);
+ StringCchCopy(song->albumartist, FIELD_LENGTH, value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"albumartist", value);
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::setTrackPublisher(songid_t songid, const wchar_t *value)
+{
+ AndroidSong *song = (AndroidSong *) songid;
+ if (song)
+ {
+ updateTrackField(song, DEVICEVIEW_COL_PUBLISHER, value, FIELD_STRING);
+ StringCchCopy(song->publisher, FIELD_LENGTH, value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"publisher", value);
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::setTrackComposer(songid_t songid, const wchar_t *value)
+{
+ AndroidSong *song = (AndroidSong *) songid;
+ if (song)
+ {
+ updateTrackField(song, DEVICEVIEW_COL_COMPOSER, value, FIELD_STRING);
+ StringCchCopy(song->composer, FIELD_LENGTH, value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"composer", value);
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::setTrackExtraInfo(songid_t songid, const wchar_t *field, const wchar_t *value)
+{
+ // TODO: implement
+
+} //optional
+
+// called from ml_pmp
+bool AndroidDevice::playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue)
+{
+ // return false if unsupported
+ if (!enqueue) //clear playlist
+ {
+ SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_DELETE);
+ }
+
+ for (int i=0; i<listLength; i++)
+ {
+ AndroidSong *curSong = (AndroidSong*)songidList[i];
+
+ if (curSong)
+ {
+ enqueueFileWithMetaStructW s={0};
+ s.filename = _wcsdup(curSong->filename);
+ s.title = _wcsdup( curSong->title );
+ s.ext = NULL;
+ s.length = curSong->length/1000;
+
+ SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
+ }
+ else
+ {
+ char titleStr[32] = {0};
+ MessageBoxA(plugin.hwndWinampParent,WASABI_API_LNGSTRING(IDS_CANNOT_OPEN_FILE),
+ WASABI_API_LNGSTRING_BUF(IDS_ERROR,titleStr,32),0);
+ }
+ }
+
+ if (!enqueue)
+ {
+ //play item startPlaybackAt
+ SendMessage(plugin.hwndWinampParent,WM_WA_IPC,startPlaybackAt,IPC_SETPLAYLISTPOS);
+ SendMessage(plugin.hwndWinampParent,WM_COMMAND,40047,0); //stop
+ SendMessage(plugin.hwndWinampParent,WM_COMMAND,40045,0); //play
+ }
+ return true;
+}
+
+static const intptr_t encoder_blacklist[] =
+{
+ mmioFOURCC('W','M','A',' '),
+ mmioFOURCC('A','A','C','H'),
+ mmioFOURCC('A','A','C','P'),
+ mmioFOURCC('A','A','C','r'),
+ mmioFOURCC('F','L','A','C'),
+ mmioFOURCC('M','P','2',' '),
+ mmioFOURCC('A','D','T','S'),
+};
+
+// called from ml_pmp
+intptr_t AndroidDevice::extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4)
+{
+ switch (param1)
+ {
+ case DEVICE_SET_ICON:
+ {
+ MLTREEIMAGE * i = (MLTREEIMAGE*)param2;
+ i->hinst = plugin.hDllInstance;
+ i->resourceId = IDR_ANDROID_ICON;
+ }
+ break;
+
+ case DEVICE_SUPPORTED_METADATA:
+ {
+ intptr_t supported = SUPPORTS_ARTIST | SUPPORTS_ALBUM | SUPPORTS_TITLE | SUPPORTS_TRACKNUM | SUPPORTS_DISCNUM | SUPPORTS_GENRE |
+ SUPPORTS_YEAR | SUPPORTS_SIZE | SUPPORTS_LENGTH | SUPPORTS_BITRATE | SUPPORTS_LASTUPDATED | SUPPORTS_ALBUMARTIST |
+ SUPPORTS_COMPOSER | SUPPORTS_PUBLISHER | SUPPORTS_ALBUMART;
+ return supported;
+ }
+ break;
+
+ case DEVICE_CAN_RENAME_DEVICE:
+ return 1;
+
+ case DEVICE_GET_INI_FILE:
+ StringCchCopy((wchar_t*)param2, MAX_PATH, iniFile);
+ break;
+ case DEVICE_GET_PREFS_DIALOG:
+ if (param3 == 0)
+ {
+ pref_tab * p = (pref_tab *)param2;
+ p->hinst = WASABI_API_LNG_HINST;
+ p->dlg_proc = prefs_dialogProc;
+ p->res_id = IDD_CONFIG;
+ WASABI_API_LNGSTRINGW_BUF(IDS_ADVANCED,p->title,100);
+ }
+ break;
+ case DEVICE_DONE_SETTING:
+ {
+ AndroidSong * song = (AndroidSong *) param2;
+ AGAVE_API_METADATA->WriteExtendedFileInfo(song->filename);
+ return true;
+ }
+ break;
+ case DEVICE_VETO_ENCODER:
+ {
+ for (size_t i=0;i<sizeof(encoder_blacklist)/sizeof(*encoder_blacklist);i++)
+ {
+ // TODO: check device info XML for aacPlus support
+ if (param2 == encoder_blacklist[i])
+ return 1;
+ }
+ }
+ return 0;
+ case DEVICE_GET_ICON:
+ {
+ if (param2 <= 16 && param3 <= 16)
+ {
+ // TODO: get the name of the DLL at load time
+ StringCchPrintfW((wchar_t *)param4, 260, L"res://%s/PNG/#%u", L"pmp_android.dll", IDR_ANDROID_ICON);
+ }
+ else
+ {
+ // TODO: get the name of the DLL at load time
+ StringCchPrintfW((wchar_t *)param4, 260, L"res://%s/PNG/#%u", L"pmp_android.dll", IDB_ANDROID_160);
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+// called from ml_pmp
+bool AndroidDevice::copyToHardDriveSupported()
+{
+ return true;
+}
+
+// called from ml_pmp
+__int64 AndroidDevice::songSizeOnHardDrive(songid_t song)
+{
+ // how big a song will be when copied back. Return -1 for not supported.
+ // TODO: implement
+ return 0;
+
+}
+
+// called from ml_pmp
+int AndroidDevice::copyToHardDrive(songid_t song, // the song to copy
+ wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ )
+{
+ // -1 for failed/not supported. 0 for success.
+ AndroidSong* track = (AndroidSong*)song;
+ wchar_t * ext = PathFindExtensionW(track->filename);
+ if (ext && (lstrlen(ext)<10)) StringCchCat(path,MAX_PATH, ext); // append correct extention
+ return CopyFile(track->filename,path,callbackContext, callback, killswitch);
+}
+
+// called from ml_pmp
+// art functions
+void AndroidDevice::setArt(songid_t songid, void *buf, int w, int h)
+{
+ //buf is in format ARGB32*
+ // TODO: implement
+}
+
+// called from ml_pmp
+pmpart_t AndroidDevice::getArt(songid_t songid)
+{
+ AndroidSong *song = (AndroidSong *)songid;
+ ARGB32 *bits;
+ int w, h;
+ if (AGAVE_API_ALBUMART && AGAVE_API_ALBUMART->GetAlbumArt(song->filename, L"cover", &w, &h, &bits) == ALBUMART_SUCCESS && bits)
+ {
+ return (pmpart_t) new AndroidArt(bits, w, h);
+ }
+ return 0;
+}
+
+// called from ml_pmp
+void AndroidDevice::releaseArt(pmpart_t art)
+{
+ AndroidArt *image = (AndroidArt *)art;
+ delete image;
+}
+
+// called from ml_pmp
+int AndroidDevice::drawArt(pmpart_t art, HDC dc, int x, int y, int w, int h)
+{
+ AndroidArt *image = (AndroidArt *)art;
+ if (image)
+ {
+ HQSkinBitmap temp(image->bits, image->w, image->h); // wrap into a SkinBitmap (no copying involved)
+ DCCanvas canvas(dc);
+ temp.stretch(&canvas,x,y,w,h);
+ return 1;
+ }
+ return 0;
+}
+
+// called from ml_pmp
+void AndroidDevice::getArtNaturalSize(pmpart_t art, int *w, int *h)
+{
+ AndroidArt *image = (AndroidArt *)art;
+ if (image)
+ {
+ *w = image->w;
+ *h = image->h;
+ }
+}
+
+// called from ml_pmp
+void AndroidDevice::setArtNaturalSize(pmpart_t art, int w, int h)
+{
+ // TODO: implement
+ //DebugBreak();
+}
+
+// called from ml_pmp
+void AndroidDevice::getArtData(pmpart_t art, void* data)
+{
+ AndroidArt *image = (AndroidArt *)art;
+ if (image)
+ memcpy(data, image->bits, image->w*image->h*sizeof(ARGB32));
+ // data ARGB32* is at natural size
+}
+
+// called from ml_pmp
+bool AndroidDevice::artIsEqual(pmpart_t a, pmpart_t b)
+{
+ if (a == b)
+ return true;
+ // TODO: implement
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Initialize class statics
+nde_database_t AndroidDevice::discDB = 0;
+
+
+// The getter that returns the master playlist
+// the playlist vector always carries a master playlist
+AndroidPlaylist* AndroidDevice::getMasterPlaylist()
+{
+ for (std::vector<AndroidPlaylist*>::const_iterator e = androidPlaylists.begin(); e != androidPlaylists.end(); e++)
+ {
+ AndroidPlaylist* playlist = (*e);
+ if (playlist->isMaster()) return playlist;
+ }
+ return NULL;
+}
+
+// constructor
+AndroidDevice::AndroidDevice(wchar_t drive, pmpDeviceLoading * load): transcoder(NULL)
+{
+ deviceTable = 0;
+
+ StringCchPrintf(ndeDataFile, 100, L"%c:\\Winamp\\winamp_metadata.dat", drive);
+ StringCchPrintf(ndeIndexFile, 100, L"%c:\\Winamp\\winamp_metadata.idx", drive);
+
+ load->dev = this;
+ load->UpdateCaption = NULL;
+
+ //pass load to ml_pmp, ml updates load->UpdateCaption and context
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)load,PMP_IPC_DEVICELOADING);
+
+ if (load->UpdateCaption)
+ {
+ wchar_t buf[100] = L"";
+ WASABI_API_LNGSTRINGW_BUF(IDS_LOADING_DRIVE_X,buf,100);
+ wchar_t * x = wcsrchr(buf,L'X');
+ if (x) *x = drive;
+ load->UpdateCaption(buf,load->context);
+ }
+
+ // load settings
+ StringCchCopy(iniFile, MAX_PATH, L"x:\\Winamp\\");
+ iniFile[0]=drive;
+
+ CreateDirectory(iniFile, NULL);
+ StringCchCat(iniFile,MAX_PATH,L"pmp_android.ini");
+
+ wchar_t customName[FIELD_LENGTH] = {0};
+ GetPrivateProfileString(L"pmp_android",L"pldir",L"X:\\Music",pldir,sizeof(pldir)/sizeof(wchar_t),iniFile);
+ GetPrivateProfileString(L"pmp_android",L"songFormat",L"X:\\Music\\<Artist>\\<Album>\\## - <Title>",songFormat,sizeof(songFormat)/sizeof(wchar_t),iniFile);
+ GetPrivateProfileString(L"pmp_android",L"supportedFormats",L"mp3;wav;m4a;mp4;m4v;avi;3gp;mid;ogg",supportedFormats,sizeof(supportedFormats)/sizeof(wchar_t),iniFile);
+ GetPrivateProfileString(L"pmp_android",L"purgeFolders",L"1",purgeFolders,sizeof(purgeFolders)/sizeof(wchar_t),iniFile);
+ GetPrivateProfileString(L"pmp_android",L"customName",L"",customName,sizeof(customName)/sizeof(wchar_t),iniFile);
+ pl_write_mode = GetPrivateProfileInt(L"pmp_android",L"pl_write_mode",0,iniFile);
+
+ pldir[0] = drive;
+ songFormat[0] = drive;
+
+ transferQueueLength = 0;
+ this->drive = drive;
+ AndroidPlaylist * mpl = new AndroidPlaylist(*this, customName, true);
+ androidPlaylists.push_back(mpl);
+ wchar_t * pl = _wcsdup(pldir);
+ pl[0] = drive;
+ RecursiveCreateDirectory(pl);
+ wchar_t root[3] = L"X:";
+ root[0] = drive;
+
+ openDeviceTable();
+
+ fileProbe(root);
+
+ // sort out and read playlists....
+ if (WASABI_API_PLAYLISTMNGR != NULL && WASABI_API_PLAYLISTMNGR != (api_playlistmanager *)1)
+ {
+ for (std::vector<AndroidPlaylist*>::const_iterator e = androidPlaylists.begin(); e != androidPlaylists.end(); e++)
+ {
+ AndroidPlaylist* playlist = (*e);
+ if (playlist->isMaster() == false)
+ {
+ WASABI_API_PLAYLISTMNGR->Load(playlist->getFilename(), playlist);
+ }
+ }
+ }
+
+ tag();
+ devices.push_back(this);
+ extern HWND config;
+ if (config) PostMessage(config,WM_USER,0,0);
+
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICECONNECTED);
+ setupTranscoder();
+}
+
+AndroidDevice::AndroidDevice()
+{
+}
+
+AndroidDevice::~AndroidDevice()
+{
+ closeDeviceTable();
+ if (transcoder)
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)transcoder,PMP_IPC_RELEASE_TRANSCODER);
+}
+
+//read files from device's folder 'indir'
+void AndroidDevice::fileProbe(wchar_t * indir)
+{
+ wchar_t dir[MAX_PATH] = {0};
+ WIN32_FIND_DATA FindFileData = {0};
+
+ StringCchPrintf(dir,MAX_PATH,L"%s\\*",indir);
+ HANDLE hFind = FindFirstFile(dir, &FindFileData);
+ if (hFind == INVALID_HANDLE_VALUE) return;
+
+ do
+ {
+ if (wcscmp(FindFileData.cFileName,L".") && wcscmp(FindFileData.cFileName,L".."))
+ {
+ wchar_t fullfile[MAX_PATH] = {0};
+ StringCchPrintf(fullfile,MAX_PATH,L"%s\\%s",indir,FindFileData.cFileName);
+
+ if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //file is directory
+ {
+ fileProbe(fullfile); //call until we have found a file
+ }
+ else // found a file!
+ {
+ wchar_t * ext = wcsrchr(FindFileData.cFileName,'.');
+ if (!ext) continue; //no files with extensions in the directory
+ ext++;
+
+ int isM3UPlaylistFormat = CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, ext, -1, L"m3u", -1)-2;
+ if (isM3UPlaylistFormat == 0) // its a playlist
+ {
+ AndroidPlaylist *playlist = new AndroidPlaylist(*this, fullfile, false);
+ androidPlaylists.push_back(playlist);
+ continue;
+ } //its a file
+
+ if (supportedFormat(fullfile, supportedFormats)) //check extension
+ {
+ AndroidSong *s = new AndroidSong();
+ lstrcpynW(s->filename, fullfile, MAX_PATH);
+ this->getMasterPlaylist()->push_back(s); //add track to alltrack list (playlist 0)
+ }
+ }
+ }
+ }
+ while (FindNextFile(hFind, &FindFileData) != 0);
+
+ FindClose(hFind);
+}
+
+int AndroidDevice::getFileInfoW(const wchar_t *filename, const wchar_t *metadata, wchar_t *dest, size_t len)
+{
+ dest[0]=0;
+ return AGAVE_API_METADATA->GetExtendedFileInfo(filename, metadata, dest, len);
+}
+
+// read all metadata from the metadata wasabi service
+void AndroidDevice::fillMetaData(AndroidSong *t)
+{
+ if (!t->filled)
+ {
+ wchar_t tmp[1024] = {0};
+ if (getFileInfoW(t->filename,L"artist",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ StringCchCopyW(t->artist, FIELD_LENGTH, tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename,L"title",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ StringCchCopyW(t->title, FIELD_LENGTH, tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename,L"album",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ StringCchCopyW(t->album, FIELD_LENGTH, tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename,L"composer",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ StringCchCopyW(t->composer, FIELD_LENGTH, tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename,L"publisher",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ StringCchCopyW(t->publisher, FIELD_LENGTH, tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename,L"albumartist",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ StringCchCopyW(t->albumartist, FIELD_LENGTH, tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename, L"length",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ t->length = _wtoi(tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename, L"track",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ t->track = _wtoi(tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename, L"disc",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ t->discnum = _wtoi(tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename, L"genre",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ StringCchCopyW(t->genre, FIELD_LENGTH, tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename, L"year",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ if (!wcsstr(tmp,L"__") && !wcsstr(tmp,L"/") && !wcsstr(tmp,L"\\") && !wcsstr(tmp,L"."))
+ {
+ wchar_t *p = tmp;
+ while (p && *p)
+ {
+ if (*p == L'_') *p=L'0';
+ p++;
+ }
+ t->year = _wtoi(tmp);
+ t->filled = true;
+ }
+ }
+
+ if (getFileInfoW(t->filename, L"bitrate",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ t->bitrate = _wtoi(tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename, L"size",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ t->size = _wtoi(tmp);
+ t->filled = true;
+ }
+ else
+ {
+ t->size = fileSize(t->filename);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename, L"playcount",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ t->playcount = _wtoi(tmp);
+ t->filled = true;
+ }
+ }
+}
+
+int AndroidDevice::openDeviceDatabase()
+{
+ Nullsoft::Utility::AutoLock lock(dbcs);
+ if (!discDB)
+ {
+ discDB = NDE_CreateDatabase(plugin.hDllInstance);
+ }
+ return NDE_ANDROID_SUCCESS;
+}
+
+void AndroidDevice::createDeviceFields()
+{
+ // create defaults
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_FILENAME, L"filename", FIELD_FILENAME);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_ARTIST, L"artist", FIELD_STRING);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_ALBUM, L"album", FIELD_STRING);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_TITLE, L"title", FIELD_STRING);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_GENRE, L"genre", FIELD_STRING);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_ALBUM_ARTIST, L"albumartist", FIELD_STRING);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_PUBLISHER, L"publisher", FIELD_STRING);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_COMPOSER, L"composer", FIELD_STRING);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_YEAR, L"year", FIELD_INTEGER);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_TRACK, L"track", FIELD_INTEGER);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_BITRATE, L"bitrate", FIELD_INTEGER);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_DISC_NUMBER, L"discnumber", FIELD_INTEGER);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_LENGTH, L"length", FIELD_INTEGER);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_SIZE, L"size", FIELD_INTEGER);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_PLAY_COUNT, L"playcount", FIELD_INTEGER);
+ NDE_Table_PostColumns(deviceTable);
+ NDE_Table_AddIndexByIDW(deviceTable, 0, L"filename");
+}
+
+int AndroidDevice::openDeviceTable()
+{
+ Nullsoft::Utility::AutoLock lock(dbcs);
+ int ret = openDeviceDatabase();
+ if (ret != NDE_ANDROID_SUCCESS)
+ return ret;
+
+ if (!deviceTable)
+ {
+ deviceTable = NDE_Database_OpenTable(discDB, ndeDataFile, ndeIndexFile,NDE_OPEN_ALWAYS,NDE_CACHE);
+ if (deviceTable)
+ {
+ createDeviceFields();
+ }
+ }
+ return deviceTable?NDE_ANDROID_SUCCESS:NDE_ANDROID_FAILURE;
+}
+
+/* static */
+void AndroidDevice::CloseDatabase()
+{
+ if (discDB)
+ {
+ NDE_DestroyDatabase(discDB);
+ discDB=0;
+ }
+}
+
+void AndroidDevice::closeDeviceTable()
+{
+ if (deviceTable)
+ {
+ NDE_Table_Sync(deviceTable);
+ NDE_Database_CloseTable(discDB, deviceTable);
+ deviceTable=0;
+ }
+}
+
+static void db_setFieldInt(nde_scanner_t s, unsigned char id, int data)
+{
+ nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
+ if (!f) f = NDE_Scanner_NewFieldByID(s, id);
+ NDE_IntegerField_SetValue(f, data);
+}
+
+static void db_setFieldString(nde_scanner_t s, unsigned char id, const wchar_t *data)
+{
+ nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
+ if (!f) f = NDE_Scanner_NewFieldByID(s, id);
+ NDE_StringField_SetString(f, data);
+}
+
+static void db_removeField(nde_scanner_t s, unsigned char id)
+{
+ nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
+ if (f)
+ {
+ NDE_Scanner_DeleteField(s, f);
+ }
+}
+
+static int db_getFieldInt(nde_scanner_t s, unsigned char id, int defaultVal)
+{
+ nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
+ if (f)
+ {
+ return NDE_IntegerField_GetValue(f);
+ }
+ else
+ {
+ return defaultVal;
+ }
+}
+
+static wchar_t* db_getFieldString(nde_scanner_t s, unsigned char id)
+{
+ nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
+ if (f)
+ {
+ return NDE_StringField_GetString(f);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+void AndroidDevice::refreshNDECache(void)
+{
+ tag();
+}
+
+
+AndroidSong *AndroidDevice::findSongInMasterPlaylist(const wchar_t *songfn)
+{
+ AndroidPlaylist* mpl = this->getMasterPlaylist();
+ return mpl->FindSong(songfn);
+}
+
+void AndroidDevice::tag(void)
+{
+ /**
+ loop thru the newly probed disk
+ check for updates on each of the songs
+ if there is an update or if metadata does not exist for the file, re-read the metadata
+ if there is no update and the song is found in the master playlist, just read from the db
+ */
+ AndroidPlaylist *mpl = this->getMasterPlaylist();
+ int top = (int)mpl->size();
+
+ //first load in all songs data from ID3 - this is what we were trying to avoid
+ for (int i = 0; i < top; i++)
+ {
+ AndroidSong *t = (AndroidSong *)mpl->at(i);
+
+ // now check if this song has changed
+ // check if the nde cache exists in the first place
+ if (songChanged(t) || !readRecordFromDB(t))
+ {
+ this->fillMetaData(t);
+ // now since we've refreshed the metadata write to NDE
+ this->writeRecordToDB(t);
+ }
+ }
+}
+
+// check change in filetimes for the song
+bool AndroidDevice::songChanged(AndroidSong* song)
+{
+ if (!song) return true;
+ if (!PathFileExists(ndeDataFile)) return true;
+
+ //For fLastAccess/LastWrite information, use GetFileAttributesEx
+ WIN32_FILE_ATTRIBUTE_DATA cacheFileInfo, tempInfo;
+ GetFileAttributesExW(ndeDataFile, GetFileExInfoStandard, (LPVOID)&cacheFileInfo);
+
+ if (song->filename)
+ {
+ GetFileAttributesExW(song->filename, GetFileExInfoStandard, (LPVOID)&tempInfo);
+ }
+ else
+ {
+ return true;
+ }
+
+ //cachetime - song time
+ if (CompareFileTime(&cacheFileInfo.ftLastWriteTime, &tempInfo.ftLastWriteTime) < 0)
+ {
+ return true;
+ }
+ return false;
+}
+
+// read metadata for a specific song from the NDE cache
+bool AndroidDevice::readRecordFromDB(AndroidSong* song)
+{
+ if (!song) return false;
+
+ Nullsoft::Utility::AutoLock lock(dbcs);
+ openDeviceTable();
+ nde_scanner_t scanner = NDE_Table_CreateScanner(deviceTable);
+
+ if (NDE_Scanner_LocateFilename(scanner, DEVICEVIEW_COL_FILENAME, FIRST_RECORD, song->filename))
+ {
+ nde_field_t artist = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_ARTIST);
+ wchar_t* artistString = NDE_StringField_GetString(artist);
+ lstrcpyn(song->artist, artistString, FIELD_LENGTH);
+
+ nde_field_t album = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_ALBUM);
+ wchar_t* albumString = NDE_StringField_GetString(album);
+ lstrcpyn(song->album, albumString, FIELD_LENGTH);
+
+ nde_field_t albumArtist = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_ALBUM_ARTIST);
+ wchar_t* albumArtistString = NDE_StringField_GetString(albumArtist);
+ lstrcpyn(song->albumartist, albumArtistString, FIELD_LENGTH);
+
+ nde_field_t publisher = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_PUBLISHER);
+ wchar_t* publisherString = NDE_StringField_GetString(publisher);
+ lstrcpyn(song->publisher, publisherString, FIELD_LENGTH);
+
+ nde_field_t composer = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_COMPOSER);
+ wchar_t* composerString = NDE_StringField_GetString(composer);
+ lstrcpyn(song->composer, composerString, FIELD_LENGTH);
+
+ nde_field_t title = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_TITLE);
+ wchar_t* titleString = NDE_StringField_GetString(title);
+ lstrcpyn(song->title, titleString, FIELD_LENGTH);
+
+ nde_field_t genre = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_GENRE);
+ wchar_t* genreString = NDE_StringField_GetString(genre);
+ lstrcpyn(song->genre, genreString, FIELD_LENGTH);
+
+ nde_field_t track = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_TRACK);
+ song->track = NDE_IntegerField_GetValue(track);
+
+ nde_field_t year = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_YEAR);
+ song->year = NDE_IntegerField_GetValue(year);
+
+ nde_field_t discNumber = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_DISC_NUMBER);
+ song->discnum = NDE_IntegerField_GetValue(discNumber);
+
+ nde_field_t length = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_LENGTH);
+ song->length = NDE_IntegerField_GetValue(length);
+
+ nde_field_t bitrate = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_BITRATE);
+ int bitrateInt= NDE_IntegerField_GetValue(bitrate);
+ song->bitrate = bitrateInt;
+
+ nde_field_t size = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_SIZE);
+ int sizeInt= NDE_IntegerField_GetValue(size);
+ song->size = sizeInt;
+
+ nde_field_t playcount = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_PLAY_COUNT);
+ song->playcount = NDE_IntegerField_GetValue(playcount);
+ }
+ else
+ {
+ return false;
+ }
+
+ NDE_Table_DestroyScanner(deviceTable, scanner);
+ //closeDeviceTable();
+ return true;
+}
+
+// write a single record to the nde database
+void AndroidDevice::writeRecordToDB(AndroidSong* songToPrint)
+{
+ Nullsoft::Utility::AutoLock lock(dbcs);
+ openDeviceTable();
+ nde_scanner_t s = NDE_Table_CreateScanner(deviceTable);
+
+ if (! NDE_Scanner_LocateFilename(s, DEVICEVIEW_COL_FILENAME, FIRST_RECORD, songToPrint->filename))
+ {
+ NDE_Scanner_New(s);
+ }
+
+ if (songToPrint->filename)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_FILENAME, songToPrint->filename);
+ }
+
+ if (songToPrint->artist)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_ARTIST, songToPrint->artist);
+ }
+
+ if (songToPrint->albumartist)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_ALBUM_ARTIST, songToPrint->albumartist);
+ }
+
+ if (songToPrint->publisher)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_PUBLISHER, songToPrint->publisher);
+ }
+
+ if (songToPrint->composer)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_COMPOSER, songToPrint->composer);
+ }
+
+ if (songToPrint->album)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_ALBUM, songToPrint->album);
+ }
+
+ if (songToPrint->title)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_TITLE, songToPrint->title);
+ }
+
+ if (songToPrint->genre)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_GENRE, songToPrint->genre);
+ }
+
+ if (songToPrint->year)
+ {
+ db_setFieldInt(s, DEVICEVIEW_COL_YEAR, songToPrint->year);
+ }
+
+ if (songToPrint->track)
+ {
+ db_setFieldInt(s, DEVICEVIEW_COL_TRACK, songToPrint->track);
+ }
+
+ if (songToPrint->bitrate)
+ {
+ db_setFieldInt(s, DEVICEVIEW_COL_BITRATE, songToPrint->bitrate);
+ }
+
+ if (songToPrint->discnum)
+ {
+ db_setFieldInt(s, DEVICEVIEW_COL_DISC_NUMBER, songToPrint->discnum);
+ }
+
+ if (songToPrint->length)
+ {
+ db_setFieldInt(s, DEVICEVIEW_COL_LENGTH, songToPrint->length);
+ }
+
+ if (songToPrint->size)
+ {
+ db_setFieldInt(s, DEVICEVIEW_COL_SIZE, (int)songToPrint->size);
+ }
+
+ if (songToPrint->playcount)
+ {
+ db_setFieldInt(s, DEVICEVIEW_COL_PLAY_COUNT, songToPrint->playcount);
+ }
+ NDE_Scanner_Post(s);
+ NDE_Table_DestroyScanner(deviceTable, s);
+ // NDE_Table_Sync(deviceTable);
+ //closeDeviceTable();
+}
+
+void AndroidDevice::setupTranscoder()
+{
+ if (transcoder) SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)transcoder,PMP_IPC_RELEASE_TRANSCODER);
+ transcoder = (Transcoder*)SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)this,PMP_IPC_GET_TRANSCODER);
+ if (!transcoder) return;
+
+ wchar_t * p = supportedFormats;
+ while (p && *p)
+ {
+ wchar_t * np = wcschr(p,L';');
+ if (np) *np = 0;
+ transcoder->AddAcceptableFormat(p);
+ if (np)
+ {
+ *np = L';';
+ p=np+1;
+ }
+ else return;
+ }
+}
+
+BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam)
+{
+ wchar_t cl[32] = {0};
+ GetClassNameW(hwnd, cl, ARRAYSIZE(cl));
+ if (!lstrcmpiW(cl, WC_TREEVIEW))
+ {
+ PostMessage(hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection(hwnd));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+wchar_t pldir[MAX_PATH] = {0};
+int CALLBACK WINAPI BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ if (uMsg == BFFM_INITIALIZED)
+ {
+ SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)pldir);
+
+ // this is not nice but it fixes the selection not working correctly on all OSes
+ EnumChildWindows(hwnd, browseEnumProc, 0);
+ }
+ return 0;
+}
+
+static INT_PTR CALLBACK prefs_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ static AndroidDevice * dev;
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ prefsParam* p = (prefsParam*)lParam;
+ dev = (AndroidDevice*)p->dev;
+ p->config_tab_init(hwndDlg,p->parent);
+ SetDlgItemTextW(hwndDlg,IDC_NAMEFORMAT,dev->songFormat);
+ SetDlgItemTextW(hwndDlg,IDC_PLDIR,dev->pldir);
+ SetDlgItemTextW(hwndDlg,IDC_SUPPORTEDFORMATS,dev->supportedFormats);
+ if (dev->purgeFolders[0]=='1') CheckDlgButton(hwndDlg,IDC_PURGEFOLDERS,BST_CHECKED);
+ else CheckDlgButton(hwndDlg,IDC_PURGEFOLDERS,BST_UNCHECKED);
+
+ SendDlgItemMessageW(hwndDlg,IDC_PL_WRITE_COMBO,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_SLASH_AT_START));
+ SendDlgItemMessageW(hwndDlg,IDC_PL_WRITE_COMBO,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_DOT_AT_START));
+ SendDlgItemMessageW(hwndDlg,IDC_PL_WRITE_COMBO,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_NO_SLASH_OR_DOT));
+ SendDlgItemMessage(hwndDlg,IDC_PL_WRITE_COMBO,CB_SETCURSEL,dev->pl_write_mode,0);
+ SetDlgItemTextW(hwndDlg,IDC_PL_WRITE_EG,WASABI_API_LNGSTRINGW(IDS_EG_SLASH+dev->pl_write_mode));
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_NAMEFORMAT:
+ if (HIWORD(wParam)==EN_CHANGE)
+ {
+ GetDlgItemTextW(hwndDlg,IDC_NAMEFORMAT,dev->songFormat,sizeof(dev->songFormat)/sizeof(wchar_t));
+ WritePrivateProfileStringW(L"pmp_android",L"songFormat",dev->songFormat,dev->iniFile);
+ }
+ break;
+
+ case IDC_PLDIR:
+ if (HIWORD(wParam)==EN_CHANGE)
+ {
+ GetDlgItemTextW(hwndDlg,IDC_PLDIR,dev->pldir,sizeof(dev->pldir)/sizeof(wchar_t));
+ WritePrivateProfileStringW(L"pmp_android",L"pldir",dev->pldir,dev->iniFile);
+ }
+ break;
+
+ case IDC_SUPPORTEDFORMATS:
+ if (HIWORD(wParam)==EN_CHANGE)
+ {
+ GetDlgItemTextW(hwndDlg,IDC_SUPPORTEDFORMATS,dev->supportedFormats,sizeof(dev->supportedFormats)/sizeof(wchar_t));
+ WritePrivateProfileStringW(L"pmp_android",L"supportedFormats",dev->supportedFormats,dev->iniFile);
+ }
+ break;
+
+ case IDC_REFRESHCACHE:
+ {
+ char titleStr[32] = {0};
+ dev->refreshNDECache();
+ MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_CACHE_UPDATED),
+ WASABI_API_LNGSTRING_BUF(IDS_SUCCESS,titleStr,32),MB_OK);
+ break;
+ }
+
+ case IDC_PL_WRITE_COMBO:
+ {
+ dev->pl_write_mode = (int)SendMessage((HWND)lParam,CB_GETCURSEL,0,0);
+ SetDlgItemTextW(hwndDlg,IDC_PL_WRITE_EG,WASABI_API_LNGSTRINGW(IDS_EG_SLASH+dev->pl_write_mode));
+
+ wchar_t tmp[16] = {0};
+ StringCchPrintf(tmp, 16, L"%d", dev->pl_write_mode);
+ WritePrivateProfileStringW(L"pmp_android",L"pl_write_mode",tmp,dev->iniFile);
+ break;
+ }
+
+ case IDC_FILENAMEHELP:
+ {
+ char titleStr[64] = {0};
+ MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_FILENAME_FORMATTING_INFO),
+ WASABI_API_LNGSTRING_BUF(IDS_FILENAME_FORMAT_HELP,titleStr,64),MB_OK);
+ }
+ break;
+
+ case IDC_PLBROWSE:
+ {
+ wchar_t *tempWS = 0;
+ BROWSEINFO bi = {0};
+ LPMALLOC lpm = 0;
+ wchar_t bffFileName[MAX_PATH] = {0};
+
+ bi.hwndOwner = hwndDlg;
+ bi.pszDisplayName = bffFileName;
+ bi.lpszTitle = WASABI_API_LNGSTRINGW(IDS_SELECT_FOLDER_TO_LOAD_PLAYLISTS);
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_EDITBOX | BIF_NEWDIALOGSTYLE;
+ bi.lpfn = BrowseCallbackProc;
+ lstrcpynW(pldir, dev->pldir, MAX_PATH);
+ LPITEMIDLIST iil = SHBrowseForFolder(&bi);
+ if (iil)
+ {
+ SHGetPathFromIDListW(iil,bffFileName);
+ SHGetMalloc(&lpm);
+ // path is now in bffFileName
+ }
+
+ tempWS = _wcsdup(bffFileName);
+ if (tempWS[0] == dev->drive)
+ {
+ lstrcpynW(dev->pldir, tempWS, MAX_PATH);
+ SetDlgItemText(hwndDlg,IDC_PLDIR,tempWS);
+ }
+ else
+ {
+ if (bffFileName[0] != 0) //dont print error if the user selected 'cancel'
+ {
+ char titleStr[32] = {0};
+ MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_ERR_SELECTED_PATH_NOT_ON_DEVICE),
+ WASABI_API_LNGSTRING_BUF(IDS_ERROR,titleStr,32), MB_OK);
+ }
+ }
+ free(tempWS);
+ }
+ break;
+
+ case IDC_FORMATSHELP:
+ {
+ char titleStr[64] = {0};
+ MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_SUPPORTED_FORMAT_INFO),
+ WASABI_API_LNGSTRING_BUF(IDS_SUPPORTED_FORMAT_HELP,titleStr,64),MB_OK);
+ }
+ break;
+
+ case IDC_PURGEFOLDERS:
+ {
+ if (IsDlgButtonChecked(hwndDlg,IDC_PURGEFOLDERS) == BST_CHECKED)
+ {
+ wcsncpy(dev->purgeFolders,L"1",2);
+ }
+ else
+ {
+ wcsncpy(dev->purgeFolders,L"0",2);
+ }
+ WritePrivateProfileStringW(L"pmp_android",L"purgeFolders",dev->purgeFolders,dev->iniFile);
+ }
+ break;
+
+ case IDC_RESCAN:
+ {
+ //update changes
+ SetFileAttributesW(dev->iniFile,FILE_ATTRIBUTE_HIDDEN);
+
+ wchar_t driveletter = dev->drive; //hold on to driveletter before it goes away
+ //disconnect
+ dev->Close();
+
+ //connect
+ pmpDeviceLoading load;
+ dev = new AndroidDevice(driveletter,&load);
+ char titleStr[64] = {0};
+ MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_RESCAN_COMPLETE_SAVED),
+ WASABI_API_LNGSTRING_BUF(IDS_RESCAN_COMPLETE,titleStr,64),MB_OK);
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+// update a track with new metadata (string)
+void AndroidDevice::updateTrackField(AndroidSong* song, unsigned int col, const void* newValue, int fieldType)
+{
+ if (!song) return;
+
+ Nullsoft::Utility::AutoLock lock(dbcs);
+ openDeviceTable();
+ nde_scanner_t s = NDE_Table_CreateScanner(deviceTable);
+
+ if (NDE_Scanner_LocateFilename(s, DEVICEVIEW_COL_FILENAME, FIRST_RECORD, song->filename))
+ {
+ switch (fieldType)
+ {
+ case FIELD_STRING:
+ db_setFieldString(s, col, (wchar_t *)(newValue));
+ break;
+ case FIELD_INTEGER:
+ db_setFieldInt(s, col, *((int *)newValue));
+ default:
+ break;
+ }
+ }
+
+ NDE_Scanner_Post(s);
+ NDE_Table_DestroyScanner(deviceTable, s);
+ // NDE_Table_Sync(deviceTable);
+ //closeDeviceTable();
+}
+
+AndroidSong::AndroidSong()
+{
+ filename[0]=artist[0]=album[0]=title[0]=genre[0]=albumartist[0]=publisher[0]=composer[0]=0;
+ filled=year=track=length=discnum=bitrate=playcount=(int)(size=0);
+}
+
+
+AndroidArt::AndroidArt(ARGB32 *bits, int w, int h) :bits(bits), w(w), h(h)
+{
+}
+
+AndroidArt::~AndroidArt()
+{
+ if (bits)
+ WASABI_API_MEMMGR->sysFree(bits);
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_android/androiddevice.h b/Src/Plugins/Portable/pmp_android/androiddevice.h
new file mode 100644
index 00000000..331a808f
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/androiddevice.h
@@ -0,0 +1,240 @@
+#pragma once
+#include <windows.h>
+#include <Dbt.h>
+
+#include "../../Library/ml_pmp/transcoder.h"
+#include "../../Library/ml_pmp/pmp.h"
+
+#include "../nde/nde_c.h"
+#include "../nu/AutoLock.h"
+
+#include <vector>
+
+#define WINAMP_ANDROID_MARKER_FILE L"\\.winamp\\winamp.info"
+
+//Filename="E:\Howling Bells - Into The Chaos.MP3"
+//Artist="Howling Bells"
+//Album="E:"
+//Title="Into The Chaos"
+//Genre=""
+//AlbumArtist=""
+//Publisher=""
+//Composer=""
+//Year="0"
+//Track="0"
+//Bitrate="0"
+//Playcount="0"
+//Discnum="0"
+//Length="0"
+//Size="7767879"
+enum
+{
+ NDE_ANDROID_FAILURE=0,
+ NDE_ANDROID_SUCCESS=1,
+};
+
+enum
+{
+ DEVICEVIEW_COL_FILENAME = 0,
+ DEVICEVIEW_COL_ARTIST=1,
+ DEVICEVIEW_COL_ALBUM=2,
+ DEVICEVIEW_COL_TITLE=3,
+ DEVICEVIEW_COL_GENRE=4,
+ DEVICEVIEW_COL_ALBUM_ARTIST=5,
+ DEVICEVIEW_COL_PUBLISHER=6,
+ DEVICEVIEW_COL_COMPOSER=7,
+ DEVICEVIEW_COL_YEAR=8,
+ DEVICEVIEW_COL_TRACK=9,
+ DEVICEVIEW_COL_BITRATE=10,
+ DEVICEVIEW_COL_DISC_NUMBER=11,
+ DEVICEVIEW_COL_LENGTH=12,
+ DEVICEVIEW_COL_SIZE=13,
+ DEVICEVIEW_COL_PLAY_COUNT=14,
+};
+
+#define TAG_CACHE L"winamp_metadata.dat"
+#define FIELD_LENGTH 1024
+
+class AndroidSong {
+public:
+ AndroidSong();
+ wchar_t filename[MAX_PATH];
+ wchar_t artist[FIELD_LENGTH];
+ wchar_t album[FIELD_LENGTH];
+ wchar_t title[FIELD_LENGTH];
+ wchar_t genre[FIELD_LENGTH];
+ wchar_t albumartist[FIELD_LENGTH];
+ wchar_t publisher[FIELD_LENGTH];
+ wchar_t composer[FIELD_LENGTH];
+ int year,track,length,discnum,bitrate,playcount;
+ __int64 size;
+ BOOL filled;
+ wchar_t ext[ 6 ];
+};
+
+enum DeviceType {
+ TYPE_OTHER,
+ TYPE_PSP,
+};
+
+class AndroidPlaylist;
+
+class AndroidArt
+{
+public:
+ AndroidArt(ARGB32 *bits, int w, int h);
+ ~AndroidArt();
+ ARGB32 *bits;
+ int w,h;
+};
+
+class AndroidDevice : public Device
+{
+public:
+ AndroidDevice(wchar_t drive, pmpDeviceLoading * load);
+ ~AndroidDevice();
+ AndroidDevice();
+ void fileProbe(wchar_t * indir);
+ void tag(void); //load ID3 tags from cache or mp3 file
+ void createDeviceFields();
+ int openDeviceDatabase();
+ int openDeviceTable();
+ void closeDeviceTable();
+
+ static void CloseDatabase();
+ void SeekToBegininngOfDevice(nde_scanner_t s);
+ void refreshNDECache(void);
+ void fillMetaData(AndroidSong *s);
+ static int getFileInfoW(const wchar_t *filename, const wchar_t *metadata, wchar_t *dest, size_t len);
+ void setupTranscoder();
+ AndroidPlaylist* getMasterPlaylist();
+ AndroidSong* findSongInMasterPlaylist(const wchar_t *songfn);
+ void writeRecordToDB(AndroidSong* songToPrint);
+ //////////////////////////////////////////
+
+ virtual __int64 getDeviceCapacityAvailable(); // in bytes
+ virtual __int64 getDeviceCapacityTotal(); // in bytes
+
+ virtual void Eject(); // if you ejected successfully, you MUST call PMP_IPC_DEVICEDISCONNECTED and delete this;
+ virtual void Close(); // save any changes, and call PMP_IPC_DEVICEDISCONNECTED AND delete this;
+
+ // return 0 for success, -1 for failed or cancelled
+ virtual int transferTrackToDevice(const itemRecordW * track, // the track to transfer
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void *callbackContext, wchar_t *status), // call this every so often so the GUI can be updated. Including when finished!
+ songid_t * songid, // fill in the songid when you are finished
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ );
+ virtual int trackAddedToTransferQueue(const itemRecordW *track); // return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
+ virtual void trackRemovedFromTransferQueue(const itemRecordW *track);
+
+ // return the amount of space that will be taken up on the device by the track (once it has been tranferred)
+ // or 0 for incompatable. This is usually the filesize, unless you are transcoding. An estimate is acceptable.
+ virtual __int64 getTrackSizeOnDevice(const itemRecordW *track);
+
+ virtual void deleteTrack(songid_t songid); // physically remove from device. Be sure to remove it from all the playlists!
+
+ virtual void commitChanges(); // optional. Will be called at a good time to save changes
+
+ virtual int getPlaylistCount(); // always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
+ // PlaylistName(0) should return the name of the device.
+ virtual void getPlaylistName(int playlistnumber, wchar_t *buf, int len);
+ virtual int getPlaylistLength(int playlistnumber);
+ virtual songid_t getPlaylistTrack(int playlistnumber,int songnum); // returns a songid
+
+ virtual void setPlaylistName(int playlistnumber, const wchar_t *buf); // with playlistnumber==0, set the name of the device.
+ virtual void playlistSwapItems(int playlistnumber, int posA, int posB); // swap the songs at position posA and posB
+ virtual void sortPlaylist(int playlistnumber, int sortBy);
+ virtual void addTrackToPlaylist(int playlistnumber, songid_t songid); // adds songid to the end of the playlist
+ virtual void removeTrackFromPlaylist(int playlistnumber, int songnum); //where songnum is the position of the track in the playlist
+
+ virtual void deletePlaylist(int playlistnumber);
+ virtual int newPlaylist(const wchar_t *name); // create empty playlist, returns playlistnumber. -1 for failed.
+
+ virtual void getTrackArtist(songid_t songid, wchar_t *buf, int len);
+ virtual void getTrackAlbum(songid_t songid, wchar_t *buf, int len);
+ virtual void getTrackTitle(songid_t songid, wchar_t *buf, int len);
+ virtual int getTrackTrackNum(songid_t songid);
+ virtual int getTrackDiscNum(songid_t songid);
+ virtual void getTrackGenre(songid_t songid, wchar_t * buf, int len);
+ virtual int getTrackYear(songid_t songid);
+ virtual __int64 getTrackSize(songid_t songid); // in bytes
+ virtual int getTrackLength(songid_t songid); // in millisecs
+ virtual int getTrackBitrate(songid_t songid); // in kbps
+ virtual int getTrackPlayCount(songid_t songid);
+ virtual int getTrackRating(songid_t songid); //0-5
+ virtual __time64_t getTrackLastPlayed(songid_t songid); // in unix time format
+ virtual __time64_t getTrackLastUpdated(songid_t songid); // in unix time format
+ virtual void getTrackAlbumArtist(songid_t songid, wchar_t *buf, int len);
+ virtual void getTrackPublisher(songid_t songid, wchar_t *buf, int len);
+ virtual void getTrackComposer(songid_t songid, wchar_t *buf, int len);
+ virtual int getTrackType(songid_t songid);
+ virtual void getTrackExtraInfo(songid_t songid, const wchar_t *field, wchar_t *buf, int len) ; //optional
+
+ // feel free to ignore any you don't support
+ virtual void setTrackArtist(songid_t songid, const wchar_t *value);
+ virtual void setTrackAlbum(songid_t songid, const wchar_t *value);
+ virtual void setTrackTitle(songid_t songid, const wchar_t *value);
+ virtual void setTrackTrackNum(songid_t songid, int value);
+ virtual void setTrackDiscNum(songid_t songid, int value);
+ virtual void setTrackGenre(songid_t songid, const wchar_t *value);
+ virtual void setTrackYear(songid_t songid, int year);
+ virtual void setTrackPlayCount(songid_t songid, int value);
+ virtual void setTrackRating(songid_t songid, int value);
+ virtual void setTrackLastPlayed(songid_t songid, __time64_t value); // in unix time format
+ virtual void setTrackLastUpdated(songid_t songid, __time64_t value); // in unix time format
+ virtual void setTrackAlbumArtist(songid_t songid, const wchar_t *value);
+ virtual void setTrackPublisher(songid_t songid, const wchar_t *value);
+ virtual void setTrackComposer(songid_t songid, const wchar_t *value);
+ virtual void setTrackExtraInfo(songid_t songid, const wchar_t *field, const wchar_t *value) ; //optional
+
+ virtual bool playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue); // return false if unsupported
+
+ virtual intptr_t extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4);
+
+ virtual bool copyToHardDriveSupported();
+
+ virtual __int64 songSizeOnHardDrive(songid_t song); // how big a song will be when copied back. Return -1 for not supported.
+
+ virtual int copyToHardDrive(songid_t song, // the song to copy
+ wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ ); // -1 for failed/not supported. 0 for success.
+
+ // art functions
+ virtual void setArt(songid_t songid, void *buf, int w, int h); //buf is in format ARGB32*
+ virtual pmpart_t getArt(songid_t songid);
+ virtual void releaseArt(pmpart_t art);
+ virtual int drawArt(pmpart_t art, HDC dc, int x, int y, int w, int h);
+ virtual void getArtNaturalSize(pmpart_t art, int *w, int *h);
+ virtual void setArtNaturalSize(pmpart_t art, int w, int h);
+ virtual void getArtData(pmpart_t art, void* data); // data ARGB32* is at natural size
+ virtual bool artIsEqual(pmpart_t a, pmpart_t b);
+
+ // Additional attributes
+ Transcoder *transcoder;
+ wchar_t drive;
+ wchar_t iniFile[MAX_PATH];
+ wchar_t pldir[MAX_PATH];
+ wchar_t songFormat[MAX_PATH];
+ wchar_t supportedFormats[MAX_PATH];
+ wchar_t purgeFolders[2];
+ int pl_write_mode; // used to determine how the playlists are stored
+ __int64 transferQueueLength;
+ std::vector<AndroidPlaylist*> androidPlaylists;
+ bool loadedUpToDate; //whether or not songs in memory are tagged and correct
+
+ static nde_database_t discDB;
+ nde_table_t deviceTable;
+ Nullsoft::Utility::LockGuard dbcs;
+ wchar_t ndeDataFile[100];
+ wchar_t ndeIndexFile[100];
+
+private:
+ // update a track with new metadata (string)
+ void updateTrackField(AndroidSong* song, unsigned int col, const void* newValue, int fieldType);
+ bool readRecordFromDB(AndroidSong* song);
+ bool songChanged(AndroidSong* song);
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_android/androidplaylist.cpp b/Src/Plugins/Portable/pmp_android/androidplaylist.cpp
new file mode 100644
index 00000000..ac4a3076
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/androidplaylist.cpp
@@ -0,0 +1,134 @@
+#include "./androiddevice.h"
+#include "./AndroidPlaylist.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+// dtor
+// cleanup the memory allocated for the vector of songs
+AndroidPlaylist::~AndroidPlaylist()
+{
+
+}
+
+// this is the constructor that gets called
+AndroidPlaylist::AndroidPlaylist(AndroidDevice& d, LPCTSTR fileName, BOOL m)
+: device(d), master(m), dirty(false)
+{
+ StringCbCopyW(filename, sizeof(filename), fileName);
+ StringCbCopyW(playlistName, sizeof(playlistName), PathFindFileName(fileName));
+ StringCbCopyW(playlistPath, sizeof(playlistName), fileName);
+ PathRemoveFileSpec(playlistPath);
+}
+
+
+void AndroidPlaylist::OnFile( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info )
+{
+ if ( filename == NULL )
+ return;
+
+ AndroidSong *song = NULL;
+ //Nullsoft::Utility::AutoLock songs_lock(songs_guard);
+ song = device.findSongInMasterPlaylist( filename );
+ songs.push_back( song );
+}
+
+size_t AndroidPlaylist::size()
+{
+ //Nullsoft::Utility::AutoLock songs_lock(songs_guard);
+ return songs.size();
+}
+
+AndroidSong *&AndroidPlaylist::at(size_t index)
+{
+ //Nullsoft::Utility::AutoLock songs_lock(songs_guard);
+ return songs.at(index);
+}
+
+void AndroidPlaylist::push_back(AndroidSong *callback)
+{
+ //Nullsoft::Utility::AutoLock songs_lock(songs_guard);
+ songs.push_back(callback);
+ dirty=TRUE;
+}
+
+void AndroidPlaylist::RemoveSong(AndroidSong *song)
+{
+ //Nullsoft::Utility::AutoLock songs_lock(songs_guard);
+ size_t old_size = songs.size();
+
+ //songs.eraseAll(song);
+ auto it = songs.begin();
+ while (it != songs.end())
+ {
+ if (*it != song)
+ {
+ it++;
+ continue;
+ }
+
+ it = songs.erase(it);
+ }
+
+ if (old_size != songs.size())
+ dirty=TRUE;
+}
+
+void AndroidPlaylist::swap(size_t index1, size_t index2)
+{
+ //Nullsoft::Utility::AutoLock songs_lock(songs_guard);
+ AndroidSong *temp = songs[index1];
+ songs[index1] = songs[index2];
+ songs[index2] = temp;
+ dirty = true;
+}
+
+void AndroidPlaylist::eraseAt(size_t index)
+{
+// Nullsoft::Utility::AutoLock songs_lock(songs_guard);
+ songs.erase(songs.begin() + index);
+ dirty=true;
+}
+
+static int filenamecmp( const wchar_t *f1, const wchar_t *f2 )
+{
+ for ( ;;)
+ {
+ wchar_t c1 = *f1++;
+ wchar_t c2 = *f2++;
+ if ( !c1 && !c2 )
+ return 0;
+ if ( !c1 )
+ return -1;
+ if ( !c2 )
+ return 1;
+ c1 = towupper( c1 );
+ c2 = towupper( c2 );
+ if ( c1 == '\\' )
+ c1 = '/';
+ if ( c2 == '\\' )
+ c2 = '/';
+ if ( c1 < c2 )
+ return -1;
+ else if ( c1 > c2 )
+ return 1;
+ }
+}
+
+AndroidSong *AndroidPlaylist::FindSong(const wchar_t *filename)
+{
+ //Nullsoft::Utility::AutoLock songs_lock(songs_guard);
+ for (SongList::iterator e = songs.begin(); e != songs.end(); e++)
+ {
+ if (filenamecmp(filename, (*e)->filename) == 0)
+ {
+ return (*e);
+ }
+ }
+ return 0;
+}
+
+#define CBCLASS AndroidPlaylist
+START_DISPATCH;
+VCB(IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile)
+END_DISPATCH; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_android/androidplaylist.h b/Src/Plugins/Portable/pmp_android/androidplaylist.h
new file mode 100644
index 00000000..67511736
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/androidplaylist.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <vector>
+#include "../playlist/ifc_playlistloadercallback.h"
+#include "../nu/AutoLock.h"
+
+class AndroidDevice;
+class AndroidSong;
+
+class AndroidPlaylist: public ifc_playlistloadercallback
+{
+public:
+ AndroidPlaylist(AndroidDevice& d, LPCTSTR pszPlaylist, BOOL master);
+ ~AndroidPlaylist();
+
+public:
+ /*** ifc_playlistloadercallback ***/
+ void OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info);
+
+public:
+ // utility
+ BOOL isMaster() { return master; }
+ wchar_t* getFilename() { return filename; }
+ size_t size();
+ AndroidSong *&at(size_t index);
+ void push_back(AndroidSong *callback);
+ void RemoveSong(AndroidSong *song);
+ void swap(size_t index1, size_t index2);
+ void eraseAt(size_t index);
+ AndroidSong *FindSong(const wchar_t *filename);
+
+protected:
+ RECVS_DISPATCH;
+private:
+
+ AndroidDevice &device;
+ typedef std::vector<AndroidSong*> SongList;
+ SongList songs;
+public:
+ //Nullsoft::Utility::LockGuard songs_guard;
+ wchar_t playlistName[MAX_PATH];
+ wchar_t playlistPath[MAX_PATH];
+
+ wchar_t filename[MAX_PATH];
+ BOOL master;
+ BOOL dirty;
+};
+
+
diff --git a/Src/Plugins/Portable/pmp_android/androidplaylistsaver.cpp b/Src/Plugins/Portable/pmp_android/androidplaylistsaver.cpp
new file mode 100644
index 00000000..148f2767
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/androidplaylistsaver.cpp
@@ -0,0 +1,74 @@
+#include "./androidplaylistsaver.h"
+#include "./androidplaylist.h"
+#include "./androiddevice.h"
+#include "./api.h"
+
+#include <strsafe.h>
+
+
+AndroidPlaylistSaver::AndroidPlaylistSaver(LPCTSTR iFilename, LPCTSTR iPlaylistName, AndroidPlaylist *iPlaylist)
+ : filename((LPTSTR)iFilename), title((LPTSTR)iPlaylistName), playlist(iPlaylist)
+{
+}
+
+AndroidPlaylistSaver::~AndroidPlaylistSaver()
+{
+}
+
+HRESULT AndroidPlaylistSaver::Save()
+{
+ INT result = WASABI_API_PLAYLISTMNGR->Save(filename, this);
+
+ return (PLAYLISTMANAGER_SUCCESS == result) ? S_OK : E_FAIL;
+}
+
+size_t AndroidPlaylistSaver::GetNumItems()
+{
+ return playlist->size();
+}
+
+size_t AndroidPlaylistSaver::GetItem(size_t item, wchar_t *filename, size_t filenameCch)
+{
+ AndroidSong* song = (AndroidSong *) playlist->at(item);
+ if (!song) return 0;
+
+ HRESULT hr = StringCchCopyEx(filename, filenameCch, song->filename, NULL, NULL, STRSAFE_IGNORE_NULLS);
+ if (FAILED(hr))
+ *filename = L'\0';
+
+ return SUCCEEDED(hr);
+}
+
+size_t AndroidPlaylistSaver::GetItemTitle(size_t item, wchar_t *title, size_t titleCch)
+{
+ AndroidSong* song = (AndroidSong *) playlist->at(item);
+ if (!song) return 0;
+
+ HRESULT hr = StringCchCopyEx(title, titleCch, song->title, NULL, NULL, STRSAFE_IGNORE_NULLS);
+ if (FAILED(hr))
+ *title = L'\0';
+
+ return SUCCEEDED(hr);
+}
+
+int AndroidPlaylistSaver::GetItemLengthMs(size_t item)
+{
+ AndroidSong* song = (AndroidSong *) playlist->at(item);
+ if (!song) return 0;
+
+ return song->length ? song->length: -1;
+}
+
+size_t AndroidPlaylistSaver::GetItemExtendedInfo(size_t item, const wchar_t *metadata, wchar_t *info, size_t infoCch)
+{
+ return 0;
+}
+
+#define CBCLASS AndroidPlaylistSaver
+START_DISPATCH;
+CB(IFC_PLAYLIST_GETNUMITEMS, GetNumItems)
+CB(IFC_PLAYLIST_GETITEM, GetItem)
+CB(IFC_PLAYLIST_GETITEMTITLE, GetItemTitle)
+CB(IFC_PLAYLIST_GETITEMLENGTHMILLISECONDS, GetItemLengthMs)
+CB(IFC_PLAYLIST_GETITEMEXTENDEDINFO, GetItemExtendedInfo)
+END_DISPATCH; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_android/androidplaylistsaver.h b/Src/Plugins/Portable/pmp_android/androidplaylistsaver.h
new file mode 100644
index 00000000..7925fc79
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/androidplaylistsaver.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <wtypes.h>
+#include "../playlist/ifc_playlist.h"
+
+class AndroidPlaylist;
+
+class AndroidPlaylistSaver : public ifc_playlist
+{
+
+public:
+ AndroidPlaylistSaver(LPCTSTR iFilename, LPCTSTR iTitle, AndroidPlaylist * iPlaylist);
+ virtual ~AndroidPlaylistSaver();
+
+public:
+ /*** ifc_playlist ***/
+ size_t GetNumItems();
+ size_t GetItem(size_t item, wchar_t *filename, size_t filenameCch);
+ size_t GetItemTitle(size_t item, wchar_t *title, size_t titleCch);
+ int GetItemLengthMs(size_t item); // TODO: maybe microsecond for better resolution?
+ size_t GetItemExtendedInfo(size_t item, const wchar_t *metadata, wchar_t *info, size_t infoCch);
+
+ HRESULT Save();
+protected:
+ RECVS_DISPATCH;
+
+protected:
+ LPTSTR title;
+ LPTSTR filename;
+ AndroidPlaylist *playlist;
+};
+
+
diff --git a/Src/Plugins/Portable/pmp_android/api.cpp b/Src/Plugins/Portable/pmp_android/api.cpp
new file mode 100644
index 00000000..da21b0a9
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/api.cpp
@@ -0,0 +1,64 @@
+#include "../../Library/ml_pmp/pmp.h"
+#include "api.h"
+#include <api/service/waservicefactory.h>
+
+api_language *WASABI_API_LNG = 0;
+HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
+
+// Metadata service
+api_metadata *AGAVE_API_METADATA=0;
+api_playlistmanager *WASABI_API_PLAYLISTMNGR=0;
+api_threadpool *WASABI_API_THREADPOOL=0;
+api_albumart *AGAVE_API_ALBUMART=0;
+api_memmgr *WASABI_API_MEMMGR=0;
+api_application *WASABI_API_APP=0;
+api_devicemanager *AGAVE_API_DEVICEMANAGER = 0;
+
+extern PMPDevicePlugin plugin;
+
+template <class api_T>
+void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
+{
+ if (plugin.service)
+ {
+ waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
+ if (factory)
+ api_t = reinterpret_cast<api_T *>( factory->getInterface() );
+ }
+}
+
+template <class api_T>
+void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
+{
+ if (plugin.service && api_t)
+ {
+ waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
+ if (factory)
+ factory->releaseInterface(api_t);
+ }
+ api_t = NULL;
+}
+
+void WasabiInit()
+{
+ ServiceBuild(WASABI_API_LNG, languageApiGUID);
+ ServiceBuild(AGAVE_API_METADATA, api_metadataGUID);
+ ServiceBuild(WASABI_API_PLAYLISTMNGR, api_playlistmanagerGUID);
+ ServiceBuild(WASABI_API_THREADPOOL, ThreadPoolGUID);
+ ServiceBuild(AGAVE_API_ALBUMART, albumArtGUID);
+ ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
+ ServiceBuild(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
+}
+
+void WasabiQuit()
+{
+ ServiceRelease(WASABI_API_LNG, languageApiGUID);
+ ServiceRelease(WASABI_API_PLAYLISTMNGR, api_playlistmanagerGUID);
+ ServiceRelease(AGAVE_API_METADATA, api_metadataGUID);
+ ServiceRelease(WASABI_API_THREADPOOL, ThreadPoolGUID);
+ ServiceRelease(AGAVE_API_ALBUMART, albumArtGUID);
+ ServiceRelease(WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ ServiceRelease(WASABI_API_APP, applicationApiServiceGuid);
+ ServiceRelease(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_android/api.h b/Src/Plugins/Portable/pmp_android/api.h
new file mode 100644
index 00000000..f7cfd662
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/api.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "../Agave/Language/api_language.h"
+
+#include "../Agave/Metadata/api_metadata.h"
+extern api_metadata *metadataApi;
+#define AGAVE_API_METADATA metadataApi
+
+#include "../playlist/api_playlistmanager.h"
+extern api_playlistmanager *playlistManagerApi;
+#define WASABI_API_PLAYLISTMNGR playlistManagerApi
+
+#include "../nu/threadpool/api_threadpool.h"
+extern api_threadpool *threadPoolApi;
+#define WASABI_API_THREADPOOL threadPoolApi
+
+#include "../Agave/AlbumArt/api_albumart.h"
+extern api_albumart *albumArtApi;
+#define AGAVE_API_ALBUMART albumArtApi
+
+#include <api/memmgr/api_memmgr.h>
+extern api_memmgr *memmgr;
+#define WASABI_API_MEMMGR memmgr
+
+#include <api/application/api_application.h>
+extern api_application *applicationApi;
+#define WASABI_API_APP applicationApi
+
+#include "../devices/api_devicemanager.h"
+extern api_devicemanager *deviceManagerApi;
+#define AGAVE_API_DEVICEMANAGER deviceManagerApi
+
+void WasabiInit();
+void WasabiQuit();
diff --git a/Src/Plugins/Portable/pmp_android/deviceprovider.cpp b/Src/Plugins/Portable/pmp_android/deviceprovider.cpp
new file mode 100644
index 00000000..05e73d21
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/deviceprovider.cpp
@@ -0,0 +1,343 @@
+#include "api.h"
+#include "./deviceprovider.h"
+#include "../devices/api_devicemanager.h"
+
+extern PMPDevicePlugin plugin;
+void connectDrive(wchar_t drive, bool checkSize, bool checkBlacklist);
+
+static size_t tlsIndex = (size_t)-1;
+
+static BOOL
+DiscoveryProvider_RegisterCancelSwitch(BOOL *cancelSwitch)
+{
+ if ((size_t)-1 != tlsIndex &&
+ NULL != WASABI_API_APP)
+ {
+ WASABI_API_APP->SetThreadStorage(tlsIndex, cancelSwitch);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static BOOL
+DiscoveryProvider_GetCancelSwitchOn()
+{
+ if ((size_t)-1 != tlsIndex &&
+ NULL != WASABI_API_APP)
+ {
+ BOOL *cancelSwitch = (BOOL*)WASABI_API_APP->GetThreadStorage(tlsIndex);
+ if (NULL != cancelSwitch &&
+ FALSE != *cancelSwitch)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+DeviceProvider_DriverEnumCb(wchar_t drive, unsigned int type)
+{
+ if (DRIVE_REMOVABLE == type &&
+ FALSE == DiscoveryProvider_GetCancelSwitchOn())
+ {
+ connectDrive(drive,true,true);
+ }
+}
+
+DeviceProvider::DeviceProvider()
+ : ref(1), activity(0), manager(NULL), readyEvent(NULL), cancelDiscovery(FALSE)
+{
+ InitializeCriticalSection(&lock);
+ enumerator = (ENUMDRIVES)SendMessageW(plugin.hwndPortablesParent,
+ WM_PMP_IPC, 0, PMP_IPC_ENUM_ACTIVE_DRIVES);
+}
+
+DeviceProvider::~DeviceProvider()
+{
+ CancelDiscovery();
+
+ if (NULL != readyEvent)
+ CloseHandle(readyEvent);
+
+ DeleteCriticalSection(&lock);
+}
+
+HRESULT DeviceProvider::CreateInstance(DeviceProvider **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = new DeviceProvider();
+
+ if (NULL == *instance)
+ return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t DeviceProvider::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t DeviceProvider::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int DeviceProvider::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object)
+ return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_DeviceProvider))
+ *object = static_cast<ifc_deviceprovider*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+void DeviceProvider::Lock()
+{
+ EnterCriticalSection(&lock);
+}
+
+void DeviceProvider::Unlock()
+{
+ LeaveCriticalSection(&lock);
+}
+
+DWORD DeviceProvider::DiscoveryThread()
+{
+ IncrementActivity();
+
+ if (NULL != enumerator &&
+ FALSE == cancelDiscovery)
+ {
+ DiscoveryProvider_RegisterCancelSwitch(&cancelDiscovery);
+
+ enumerator(DeviceProvider_DriverEnumCb);
+
+ DiscoveryProvider_RegisterCancelSwitch(NULL);
+ }
+
+ DecrementActivity();
+
+ Lock();
+
+ if (NULL != readyEvent)
+ SetEvent(readyEvent);
+
+ Unlock();
+
+
+ return 0;
+}
+
+static int DeviceProvider_DiscoveryThreadStarter(HANDLE handle, void *user, intptr_t id)
+{
+ DeviceProvider *self;
+ DWORD result;
+
+ self = (DeviceProvider*)user;
+
+ if (NULL != self)
+ result = self->DiscoveryThread();
+ else
+ result = -2;
+
+ return result;
+}
+
+HRESULT DeviceProvider::BeginDiscovery(api_devicemanager *manager)
+{
+ HRESULT hr;
+
+ if (NULL == enumerator)
+ return E_UNEXPECTED;
+
+ Lock();
+
+ if (NULL != readyEvent &&
+ WAIT_TIMEOUT == WaitForSingleObject(readyEvent, 0))
+ {
+ hr = E_PENDING;
+ }
+ else
+ {
+ hr = S_OK;
+
+ if (NULL == readyEvent)
+ {
+ readyEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (NULL == readyEvent)
+ hr = E_FAIL;
+ }
+
+ if ((size_t)-1 == tlsIndex &&
+ NULL != WASABI_API_APP)
+ {
+ tlsIndex = WASABI_API_APP->AllocateThreadStorage();
+ }
+
+ if (SUCCEEDED(hr))
+ {
+
+ cancelDiscovery = FALSE;
+ ResetEvent(readyEvent);
+
+ if (0 != WASABI_API_THREADPOOL->RunFunction(0, DeviceProvider_DiscoveryThreadStarter,
+ this, 0, api_threadpool::FLAG_LONG_EXECUTION))
+ {
+
+ SetEvent(readyEvent);
+ hr = E_FAIL;
+ }
+ }
+ }
+
+ Unlock();
+
+ return hr;
+}
+
+HRESULT DeviceProvider::CancelDiscovery()
+{
+ HRESULT hr;
+
+ hr = S_FALSE;
+
+ Lock();
+
+ if (NULL != readyEvent)
+ {
+ cancelDiscovery = TRUE;
+ if (WAIT_OBJECT_0 == WaitForSingleObject(readyEvent, 0))
+ hr = S_OK;
+
+ cancelDiscovery = FALSE;
+ }
+
+ Unlock();
+
+ return hr;
+}
+
+HRESULT DeviceProvider::GetActive()
+{
+ HRESULT hr;
+
+ Lock();
+
+ if (0 != activity)
+ hr = S_OK;
+ else
+ hr = S_FALSE;
+
+ Unlock();
+
+ return hr;
+}
+
+HRESULT DeviceProvider::Register(api_devicemanager *manager)
+{
+ HRESULT hr;
+
+ if (NULL != this->manager)
+ return E_UNEXPECTED;
+
+ if (NULL == manager)
+ return E_POINTER;
+
+ hr = manager->RegisterProvider(this);
+ if (SUCCEEDED(hr))
+ {
+ this->manager = manager;
+ manager->AddRef();
+ }
+ return hr;
+}
+
+HRESULT DeviceProvider::Unregister()
+{
+ HRESULT hr;
+
+ if (NULL == manager)
+ return E_UNEXPECTED;
+
+ hr = manager->UnregisterProvider(this);
+ manager->Release();
+ manager = NULL;
+ return hr;
+}
+
+size_t DeviceProvider::IncrementActivity()
+{
+ size_t a;
+
+ Lock();
+
+ activity++;
+ if (1 == activity &&
+ NULL != manager)
+ {
+ manager->SetProviderActive(this, TRUE);
+ }
+
+ a = activity;
+
+ Unlock();
+
+ return a;
+}
+
+size_t DeviceProvider::DecrementActivity()
+{
+ size_t a;
+
+ Lock();
+
+ if (0 != activity)
+ {
+ activity--;
+ if (0 == activity &&
+ NULL != manager)
+ {
+ manager->SetProviderActive(this, FALSE);
+ }
+ }
+
+ a = activity;
+
+ Unlock();
+
+ return a;
+}
+
+#define CBCLASS DeviceProvider
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_BEGINDISCOVERY, BeginDiscovery)
+CB(API_CANCELDISCOVERY, CancelDiscovery)
+CB(API_GETACTIVE, GetActive)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_android/deviceprovider.h b/Src/Plugins/Portable/pmp_android/deviceprovider.h
new file mode 100644
index 00000000..a771e82e
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/deviceprovider.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <wtypes.h>
+#include "../devices/ifc_deviceprovider.h"
+#include "../../Library/ml_pmp/pmp.h"
+
+class DeviceProvider : public ifc_deviceprovider
+{
+protected:
+ DeviceProvider();
+ ~DeviceProvider();
+
+public:
+ static HRESULT CreateInstance(DeviceProvider **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_deviceprovider */
+ HRESULT BeginDiscovery(api_devicemanager *manager);
+ HRESULT CancelDiscovery();
+ HRESULT GetActive();
+
+public:
+ HRESULT Register(api_devicemanager *manager);
+ HRESULT Unregister();
+ size_t IncrementActivity();
+ size_t DecrementActivity();
+
+private:
+ void Lock();
+ void Unlock();
+ DWORD DiscoveryThread();
+ friend static int DeviceProvider_DiscoveryThreadStarter(HANDLE handle, void *user_data, intptr_t id);
+
+protected:
+ size_t ref;
+ size_t activity;
+ CRITICAL_SECTION lock;
+ api_devicemanager *manager;
+ ENUMDRIVES enumerator;
+ HANDLE readyEvent;
+ BOOL cancelDiscovery;
+
+protected:
+ RECVS_DISPATCH;
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_android/eject.cpp b/Src/Plugins/Portable/pmp_android/eject.cpp
new file mode 100644
index 00000000..fd9dd9c1
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/eject.cpp
@@ -0,0 +1,138 @@
+// this file almost totally copied from MSDN
+
+#include <windows.h>
+#include <stdio.h>
+#include <winioctl.h>
+
+#define LOCK_TIMEOUT 3000 // 10 Seconds
+#define LOCK_RETRIES 20
+
+static HANDLE OpenVolume(TCHAR cDriveLetter)
+{
+ HANDLE hVolume;
+ UINT uDriveType;
+ wchar_t szVolumeName[8] = {0};
+ wchar_t szRootName[5] = {0};
+ DWORD dwAccessFlags = 0;
+
+ wsprintf(szRootName, L"%c:\\", cDriveLetter);
+
+ uDriveType = GetDriveType(szRootName);
+ switch(uDriveType) {
+ case DRIVE_REMOVABLE:
+ dwAccessFlags = GENERIC_READ | GENERIC_WRITE;
+ break;
+ case DRIVE_CDROM:
+ dwAccessFlags = GENERIC_READ;
+ break;
+ default:
+ printf("Cannot eject. Drive type is incorrect.\n");
+ return INVALID_HANDLE_VALUE;
+ }
+
+ wsprintf(szVolumeName, L"\\\\.\\%c:", cDriveLetter);
+
+ hVolume = CreateFile( szVolumeName,
+ dwAccessFlags,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL );
+
+ if (hVolume == INVALID_HANDLE_VALUE)
+ printf("CreateFile error %d\n", GetLastError());
+ return hVolume;
+}
+
+static BOOL CloseVolume(HANDLE hVolume)
+{
+ return CloseHandle(hVolume);
+}
+
+static BOOL LockVolume(HANDLE hVolume)
+{
+ DWORD dwBytesReturned;
+ DWORD dwSleepAmount;
+ int nTryCount;
+
+ dwSleepAmount = LOCK_TIMEOUT / LOCK_RETRIES;
+
+ // Do this in a loop until a timeout period has expired
+ for (nTryCount = 0; nTryCount < LOCK_RETRIES; nTryCount++) {
+ if (DeviceIoControl(hVolume,
+ FSCTL_LOCK_VOLUME,
+ NULL, 0,
+ NULL, 0,
+ &dwBytesReturned,
+ NULL))
+ return TRUE;
+
+ Sleep(dwSleepAmount);
+ }
+ return FALSE;
+}
+
+static BOOL DismountVolume(HANDLE hVolume)
+{
+ DWORD dwBytesReturned;
+
+ return DeviceIoControl( hVolume,
+ FSCTL_DISMOUNT_VOLUME,
+ NULL, 0,
+ NULL, 0,
+ &dwBytesReturned,
+ NULL);
+}
+
+static BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPreventRemoval)
+{
+ DWORD dwBytesReturned;
+ PREVENT_MEDIA_REMOVAL PMRBuffer;
+
+ PMRBuffer.PreventMediaRemoval = fPreventRemoval;
+
+ return DeviceIoControl( hVolume,
+ IOCTL_STORAGE_MEDIA_REMOVAL,
+ &PMRBuffer, sizeof(PREVENT_MEDIA_REMOVAL),
+ NULL, 0,
+ &dwBytesReturned,
+ NULL);
+}
+
+static int AutoEjectVolume(HANDLE hVolume)
+{
+ DWORD dwBytesReturned;
+
+ return DeviceIoControl( hVolume,
+ IOCTL_STORAGE_EJECT_MEDIA,
+ NULL, 0,
+ NULL, 0,
+ &dwBytesReturned,
+ NULL);
+}
+
+BOOL EjectVolume(TCHAR cDriveLetter)
+{
+ HANDLE hVolume;
+
+ BOOL fAutoEject = FALSE;
+
+ hVolume = OpenVolume(cDriveLetter);
+ if (hVolume == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ // Lock and dismount the volume.
+ if (LockVolume(hVolume) && DismountVolume(hVolume)) {
+ // Set prevent removal to false and eject the volume.
+ if (PreventRemovalOfVolume(hVolume, FALSE) && AutoEjectVolume(hVolume))
+ fAutoEject = TRUE;
+ }
+
+ // Close the volume so other processes can use the drive.
+ if (!CloseVolume(hVolume))
+ return FALSE;
+
+ if (fAutoEject) return TRUE;
+ else return FALSE;
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_android/filecopy.cpp b/Src/Plugins/Portable/pmp_android/filecopy.cpp
new file mode 100644
index 00000000..aecf9422
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/filecopy.cpp
@@ -0,0 +1,67 @@
+#include "api.h"
+#include <windows.h>
+#include <stdio.h>
+#include <wchar.h>
+#include "resource.h"
+#include <strsafe.h>
+
+typedef struct CopyData
+{
+ void * callbackContext;
+ void (*callback)(void * callbackContext, wchar_t * status);
+} CopyData;
+
+DWORD CALLBACK CopyToIpodProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred,
+ LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred,
+ DWORD dwStreamNumber,
+ DWORD dwCallbackReason,
+ HANDLE hSourceFile, HANDLE hDestinationFile,
+ LPVOID lpData)
+{
+ CopyData *inst = (CopyData *)lpData;
+ if (inst && inst->callback)
+ {
+ wchar_t status[100] = {0};
+ wchar_t langtemp[100] = {0};
+ StringCbPrintf(status, sizeof(status), WASABI_API_LNGSTRINGW_BUF(IDS_TRANSFERING_PERCENT, langtemp, 100), (int)(100ULL * TotalBytesTransferred.QuadPart / (TotalFileSize.QuadPart)));
+ inst->callback(inst->callbackContext,status);
+ }
+ return PROGRESS_CONTINUE;
+}
+
+int CopyFile(const wchar_t *infile, const wchar_t *outfile, void * callbackContext, void (*callback)(void * callbackContext, wchar_t * status), int * killswitch)
+{
+ wchar_t langtemp[100] = {0};
+
+ CopyData c;
+ c.callback = callback;
+ c.callbackContext = callbackContext;
+
+ if (CopyFileEx(infile, outfile, CopyToIpodProgressRoutine, &c, killswitch,0))
+ {
+ if (callback)
+ {
+ callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_DONE, langtemp, 100));
+ }
+ return 0;
+ }
+ else
+ {
+ switch(GetLastError())
+ {
+ case ERROR_REQUEST_ABORTED:
+ DeleteFile(outfile);
+ if (callback)
+ {
+ callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_CANCELLED, langtemp, 100));
+ }
+
+ default:
+ if (callback)
+ {
+ callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_TRANSFER_FAILED, langtemp, 100));
+ }
+ }
+ return -1;
+ }
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_android/main.cpp b/Src/Plugins/Portable/pmp_android/main.cpp
new file mode 100644
index 00000000..2aea1066
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/main.cpp
@@ -0,0 +1,601 @@
+#include "../../Library/ml_pmp/pmp.h"
+#include "../Winamp/wa_ipc.h"
+#include <vector>
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "../nu/Alias.h"
+
+#include <api/service/waServiceFactory.h>
+
+#include "api.h"
+#include "resource.h"
+#include "androiddevice.h"
+#include "deviceprovider.h"
+
+#include <devguid.h>
+#include <shlobj.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define PLUGIN_VERSION L"1.72"
+static int Init();
+static void Quit();
+static bool doRegisterForDevNotification(void);
+static intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3);
+
+extern PMPDevicePlugin plugin = {PMPHDR_VER,0,Init,Quit,MessageProc};
+
+// start-android
+static const wchar_t *winampini;
+static std::vector<wchar_t*> blacklist;
+bool loading_devices[26] = {0,};
+
+static HDEVNOTIFY hDevNotify;
+
+std::vector<AndroidDevice*> devices;
+HWND config;
+
+static DeviceProvider *deviceProvider = NULL;
+static UINT_PTR rescanTimer = 0;
+
+static void blacklistLoad() {
+ wchar_t keyname[64] = {0};
+ int l = GetPrivateProfileIntW(L"pmp_android", L"blacklistnum", 0, winampini);
+ for(int i=l>100?l-100:0; i<l; i++) {
+ wchar_t buf[100] = {0};
+ StringCchPrintfW(keyname, 64, L"blacklist-%d", i);
+ GetPrivateProfileStringW(L"pmp_android", keyname, L"", buf, 100, winampini);
+ if(buf[0])
+ {
+ blacklist.push_back(_wcsdup(buf));
+ }
+ }
+}
+
+static void blacklistSave() {
+ wchar_t buf[64] = {0};
+ StringCchPrintfW(buf, 64, L"%d", blacklist.size());
+ WritePrivateProfileStringW(L"pmp_android", L"blacklistnum", buf, winampini);
+ for(size_t i=0; i<blacklist.size(); i++)
+ {
+ StringCchPrintfW(buf, 64, L"blacklist-%d", i);
+ WritePrivateProfileStringW(L"pmp_android", buf, (const wchar_t*)blacklist.at(i), winampini);
+ }
+}
+
+static wchar_t *makeBlacklistString(wchar_t drive) {
+ wchar_t path[4]={drive,L":\\"};
+ wchar_t name[100]=L"";
+ wchar_t buf[FIELD_LENGTH]=L"";
+ DWORD serial=0;
+
+ UINT olderrmode=SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
+ GetVolumeInformation(path,name,100,&serial,NULL,NULL,NULL,0);
+
+ if(serial)
+ {
+ StringCchPrintf(buf, FIELD_LENGTH, L"s:%d",serial);
+ SetErrorMode(olderrmode);
+ return _wcsdup(buf);
+ }
+
+ {
+ ULARGE_INTEGER tfree={0,}, total={0,}, freeb={0,};
+ GetDiskFreeSpaceEx(path, &tfree, &total, &freeb);
+ StringCchPrintf(buf, FIELD_LENGTH, L"n:%s,%d,%d", name, total.HighPart, total.LowPart);
+ SetErrorMode(olderrmode);
+ return _wcsdup(buf);
+ }
+}
+
+static bool blacklistCheck(wchar_t drive)
+{
+ wchar_t *s = makeBlacklistString(drive);
+ if (s)
+ {
+ for(size_t i=0; i<blacklist.size(); i++)
+ {
+ if(!wcscmp(s,(wchar_t*)blacklist.at(i)))
+ {
+ free(s);
+ return true;
+ }
+ }
+ free(s);
+ }
+ return false;
+}
+
+static bool blacklistAdd(const wchar_t drive)
+{
+ wchar_t *s = makeBlacklistString(drive);
+ if (s)
+ {
+ for(size_t i=0; i<blacklist.size(); i++)
+ {
+ if(!wcscmp(s,(wchar_t*)blacklist.at(i)))
+ {
+ free(s);
+ return false;
+ }
+ }
+ blacklist.push_back(s);
+ }
+ return true;
+}
+
+static BOOL
+Device_IsiPod(const wchar_t drive)
+{
+ const wchar_t test[] = {drive, L":\\iPod_Control"};
+ WIN32_FIND_DATAW findData;
+ HANDLE file = FindFirstFileW(test, &findData);
+ if (INVALID_HANDLE_VALUE != file)
+ {
+ FindClose(file);
+ if (0 != (FILE_ATTRIBUTE_DIRECTORY & findData.dwFileAttributes))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static BOOL
+Device_IsAndroid(const wchar_t drive)
+{
+ const wchar_t test[] = {drive, L":\\Android"};
+ WIN32_FIND_DATAW findData;
+ HANDLE file = FindFirstFileW(test, &findData);
+ if (INVALID_HANDLE_VALUE != file)
+ {
+ FindClose(file);
+ if (0 != (FILE_ATTRIBUTE_DIRECTORY & findData.dwFileAttributes))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static BOOL
+Device_IsSizeOk(const wchar_t drive)
+{
+ const wchar_t test[] = {drive, L":\\"};
+ ULARGE_INTEGER total;
+
+ if (0 == GetDiskFreeSpaceExW(test, NULL, &total, NULL) ||
+ total.HighPart == 0 && total.LowPart == 0)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static BOOL
+Device_IsOkToConnect(const wchar_t drive)
+{
+ const wchar_t test[] = {drive, TEXT(":\\Winamp\\")TAG_CACHE};
+ wchar_t title[128] = {0};
+ wchar_t message[1024] = {0};
+ int result;
+
+ if (FALSE != PathFileExistsW(test))
+ return TRUE;
+
+ StringCbPrintfW(message, sizeof(message), WASABI_API_LNGSTRINGW(IDS_REMOVEABLE_DRIVE_DETECTED),
+ towupper(drive));
+
+ WASABI_API_LNGSTRINGW_BUF(IDS_WINAMP_PMP_SUPPORT,title,ARRAYSIZE(title));
+
+ result = MessageBoxW(NULL, message, title,
+ MB_YESNO | MB_SETFOREGROUND | MB_TOPMOST |
+ MB_ICONINFORMATION);
+
+ if(IDNO == result)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+static Nullsoft::Utility::LockGuard connect_guard;
+
+static int ThreadFunc_Load(HANDLE handle, void *user_data, intptr_t id)
+{
+ wchar_t drive = (wchar_t)id;
+
+ if (FALSE == Device_IsOkToConnect(drive))
+ {
+ Nullsoft::Utility::AutoLock connect_lock(connect_guard);
+ blacklistAdd(drive);
+ blacklistSave();
+ }
+ else
+ {
+ pmpDeviceLoading load;
+ Device * d = new AndroidDevice(drive,&load);
+ }
+
+ loading_devices[drive-'A'] = false;
+ deviceProvider->DecrementActivity();
+
+ return 0;
+}
+
+//#include <WinIoCtl.h>
+
+void connectDrive(wchar_t drive, bool checkSize=true, bool checkBlacklist=true)
+{
+ Nullsoft::Utility::AutoLock connect_lock(connect_guard);
+ // capitalize
+ if (drive >= 'a' && drive <= 'z')
+ drive = drive - 32;
+
+ // reject invalid drive letters
+ if (drive < 'A' || drive > 'Z')
+ return;
+
+ if(checkBlacklist && blacklistCheck(drive))
+ return;
+
+ // if device is taken already ignore
+ for (std::vector<AndroidDevice*>::const_iterator e = devices.begin(); e != devices.end(); e++)
+ {
+ if ((*e)->drive == drive)
+ return;
+ }
+
+ if (loading_devices[drive-'A'])
+ return;
+
+ loading_devices[drive-'A'] = true;
+
+ if(FALSE == checkSize || FALSE != Device_IsSizeOk(drive))
+ {
+ if (FALSE != Device_IsAndroid(drive) &&
+ FALSE == Device_IsiPod(drive))
+ {
+
+ deviceProvider->IncrementActivity();
+ if (NULL != WASABI_API_THREADPOOL &&
+ 0 == WASABI_API_THREADPOOL->RunFunction(0, ThreadFunc_Load, 0,
+ (int)drive, api_threadpool::FLAG_LONG_EXECUTION))
+ {
+ return;
+ }
+ deviceProvider->DecrementActivity();
+ }
+ }
+
+ loading_devices[drive-'A'] = false;
+}
+
+static void autoDetectCallback(wchar_t drive,UINT type)
+{
+ if(type == DRIVE_REMOVABLE)
+ {
+ connectDrive(drive, true, true);
+ }
+}
+
+
+// end-android
+static int Init()
+{
+ WasabiInit();
+
+ // start-android
+ winampini = (const wchar_t*)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_GETINIFILEW);
+ // need to have this initialised before we try to do anything with localisation features
+ WASABI_API_START_LANG(plugin.hDllInstance,PmpAndroidLangGUID);
+ // end-android
+
+ static wchar_t szDescription[256];
+ StringCchPrintfW(szDescription, ARRAYSIZE(szDescription),
+ WASABI_API_LNGSTRINGW(IDS_NULLSOFT_ANDROID_DEVICE_PLUGIN), PLUGIN_VERSION);
+ plugin.description = szDescription;
+
+ /** load up the backlist */
+ blacklistLoad();
+
+ if (NULL != AGAVE_API_DEVICEMANAGER &&
+ NULL == deviceProvider)
+ {
+ if (SUCCEEDED(DeviceProvider::CreateInstance(&deviceProvider)) &&
+ FAILED(deviceProvider->Register(AGAVE_API_DEVICEMANAGER)))
+ {
+ deviceProvider->Release();
+ deviceProvider = NULL;
+ }
+ }
+
+ /* Our device shows up as a normal drive */
+ if (NULL == deviceProvider ||
+ FAILED(deviceProvider->BeginDiscovery(AGAVE_API_DEVICEMANAGER)))
+ {
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)autoDetectCallback,PMP_IPC_ENUM_ACTIVE_DRIVES);
+ }
+
+ return 0;
+}
+
+static void Quit()
+{
+ if (NULL != deviceProvider)
+ {
+ deviceProvider->Unregister();
+ deviceProvider->Release();
+ deviceProvider = NULL;
+ }
+
+ WasabiQuit();
+ UnregisterDeviceNotification(hDevNotify);
+
+ AndroidDevice::CloseDatabase();
+}
+
+static wchar_t FirstDriveFromMask(ULONG *unitmask) {
+ char i;
+ ULONG adj = 0x1, mask = *unitmask;
+ for(i=0; i<26; ++i) {
+ if(mask & 0x1) {
+ *unitmask -= adj;
+ break;
+ }
+ adj = adj << 1;
+ mask = mask >> 1;
+ }
+ return (i+L'A');
+}
+
+static int GetNumberOfDrivesFromMask(ULONG unitmask) {
+ int count = 0;
+ for(int i=0; i<26; ++i)
+ {
+ if(unitmask & 0x1)
+ count++;
+
+ unitmask = unitmask >> 1;
+ }
+ return count;
+}
+
+static void CALLBACK RescanOnTimer(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ KillTimer(hwnd, idEvent);
+ if (idEvent == rescanTimer)
+ rescanTimer = 0;
+
+ if (NULL == deviceProvider ||
+ FAILED(deviceProvider->BeginDiscovery(AGAVE_API_DEVICEMANAGER)))
+ {
+ PostMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)autoDetectCallback,PMP_IPC_ENUM_ACTIVE_DRIVES);
+ }
+}
+
+
+int wmDeviceChange(WPARAM wParam, LPARAM lParam)
+{
+ UINT olderrmode=SetErrorMode(SEM_FAILCRITICALERRORS);
+ if(wParam==DBT_DEVICEARRIVAL || wParam==DBT_DEVICEREMOVECOMPLETE)
+ { // something has been inserted or removed
+ PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
+ if(lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
+ { // its a volume
+ PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
+ if((!(lpdbv->dbcv_flags & DBTF_MEDIA) && !(lpdbv->dbcv_flags & DBTF_NET)))
+ { // its not a network drive or a CD/floppy, game on!
+ ULONG dbcv_unitmask = lpdbv->dbcv_unitmask;
+
+ // see just how many drives have been flagged on the action
+ // eg one android drive could have multiple partitions that we handle
+ int count = GetNumberOfDrivesFromMask(dbcv_unitmask);
+ for(int j = 0; j < count; j++)
+ {
+ wchar_t drive = FirstDriveFromMask(&dbcv_unitmask);
+ if((wParam == DBT_DEVICEARRIVAL) && !blacklistCheck(drive))
+ { // connected
+ connectDrive(drive);
+ //send a message as if the user just selected a drive from the combo box, this way the fields are refreshed to the correct device's settings
+ SendMessage(config, WM_COMMAND,MAKEWPARAM(IDC_DRIVESELECT,CBN_SELCHANGE),0);
+ }
+ else
+ { // removal
+ for(size_t i=0; i < devices.size(); i++)
+ {
+ AndroidDevice * d = (AndroidDevice*)devices.at(i);
+ if(d->drive == drive)
+ {
+ devices.erase(devices.begin() + i);
+ if(config) SendMessage(config,WM_USER,0,0); //refresh fields
+ if(config) SendMessage(config,WM_COMMAND, MAKEWPARAM(IDC_DRIVESELECT,CBN_SELCHANGE),0); //update to correct device change as if the user had clicked on the combo box themself
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)d,PMP_IPC_DEVICEDISCONNECTED);
+ delete d;
+ i--;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ rescanTimer = SetTimer(NULL, rescanTimer, 10000, RescanOnTimer);
+ }
+ SetErrorMode(olderrmode);
+ return 0;
+}
+
+static int IsDriveConnectedToPMP(wchar_t drive)
+{
+ for(size_t i = 0; i < devices.size(); i++)
+ {
+ if(((AndroidDevice*)devices.at(i))->drive == drive)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static INT_PTR CALLBACK config_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ for(wchar_t d=L'A'; d<='Z'; d++)
+ {
+ wchar_t drive[3] = {d,L':',0}, drv[4] = {d,L':','\\',0};
+ UINT uDriveType = GetDriveType(drv);
+ if(uDriveType == DRIVE_REMOVABLE || uDriveType == DRIVE_CDROM || uDriveType == DRIVE_FIXED) {
+ int position = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_ADDSTRING,0,(LPARAM)drive);
+ SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_SETITEMDATA,position,d);
+ }
+ }
+ SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_SETCURSEL,0,0);
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_COMBO_MANUALCONNECT,CBN_SELCHANGE),0);
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hwndDlg,0);
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_COMBO_MANUALCONNECT:
+ {
+ if(HIWORD(wParam)==CBN_SELCHANGE) {
+ int indx = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETCURSEL,0,0);
+ wchar_t drive = (wchar_t)SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETITEMDATA,indx,0);
+ if(indx >= 0)
+ {
+ int connected = IsDriveConnectedToPMP(drive), isblacklisted = blacklistCheck(drive);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALCONNECT), !connected && !isblacklisted);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALDISCONNECT), connected);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALBLACKLIST), TRUE);
+ SetDlgItemText(hwndDlg, IDC_MANUALBLACKLIST, WASABI_API_LNGSTRINGW(isblacklisted ? IDS_UNBLACKLIST_DRIVE : IDS_BLACKLIST_DRIVE));
+ }
+ }
+ }
+ break;
+ case IDC_MANUALCONNECT:
+ {
+ char titleStr[32] = {0};
+ if(MessageBoxA(hwndDlg, WASABI_API_LNGSTRING(IDS_MANUAL_CONNECT_PROMPT),
+ WASABI_API_LNGSTRING_BUF(IDS_WARNING,titleStr,32), MB_YESNO) == IDYES)
+ {
+ int indx = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETCURSEL,0,0);
+ wchar_t drive = (wchar_t)SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETITEMDATA,indx,0);
+ if(drive >= L'A' && drive <= L'Z') {
+ wchar_t *bl = makeBlacklistString(drive);
+ if (bl)
+ {
+ for(size_t i=0; i<blacklist.size(); i++)
+ {
+ if(!wcscmp(bl,(wchar_t*)blacklist.at(i)))
+ {
+ free(blacklist.at(i));
+ blacklist.erase(blacklist.begin() + i);
+ break;
+ }
+ }
+ free(bl);
+ }
+ connectDrive(drive,false);
+ // should do a better check here incase of failure, etc
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALCONNECT), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALDISCONNECT), TRUE);
+ }
+ }
+ }
+ break;
+ case IDC_MANUALDISCONNECT:
+ {
+ int indx = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETCURSEL,0,0);
+ wchar_t drive = (wchar_t)SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETITEMDATA,indx,0);
+ if(drive >= L'A' && drive <= L'Z')
+ {
+ for(size_t i=0; i < devices.size(); i++)
+ {
+ AndroidDevice * d = (AndroidDevice*)devices.at(i);
+ if(d->drive == drive)
+ {
+ devices.erase(devices.begin() + i);
+ if(config) SendMessage(config,WM_USER,0,0); //refresh fields
+ if(config) SendMessage(config,WM_COMMAND, MAKEWPARAM(IDC_DRIVESELECT,CBN_SELCHANGE),0); //update to correct device change as if the user had clicked on the combo box themself
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)d,PMP_IPC_DEVICEDISCONNECTED);
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_COMBO_MANUALCONNECT,CBN_SELCHANGE),0);
+ delete d;
+ i--;
+ }
+ }
+ }
+ }
+ break;
+ case IDC_MANUALBLACKLIST:
+ {
+ int indx = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETCURSEL,0,0);
+ wchar_t drive = (wchar_t)SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETITEMDATA,indx,0);
+ if(drive >= L'A' && drive <= L'Z') {
+ wchar_t *bl = makeBlacklistString(drive);
+ if (bl)
+ {
+ if(!blacklistCheck(drive)) {
+ blacklist.push_back(bl);
+ // see if we've got a connected drive and prompt to remove it or wait till restart
+ if(IsDriveConnectedToPMP(drive)) {
+ wchar_t title[96] = {0};
+ GetWindowText(hwndDlg, title, 96);
+ if(MessageBox(hwndDlg,WASABI_API_LNGSTRINGW(IDS_DRIVE_CONNECTED_DISCONNECT_Q),title,MB_YESNO)==IDYES){
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_MANUALDISCONNECT,0),0);
+ }
+ }
+ }
+ else
+ {
+ for(size_t i=0; i < blacklist.size(); i++)
+ {
+ if(!wcscmp(bl,(wchar_t*)blacklist.at(i)))
+ {
+ free(blacklist.at(i));
+ blacklist.erase(blacklist.begin() + i);
+ break;
+ }
+ }
+ free(bl);
+ }
+ }
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_COMBO_MANUALCONNECT,CBN_SELCHANGE),0);
+ }
+ }
+ break;
+ case IDOK:
+ case IDCANCEL:
+ blacklistSave();
+ EndDialog(hwndDlg,0);
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+
+static intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3)
+{
+ switch(msg) {
+ case PMP_DEVICECHANGE:
+ return wmDeviceChange(param1,param2);
+ case PMP_CONFIG:
+ WASABI_API_DIALOGBOXW(IDD_CONFIG_GLOBAL,(HWND)param1,config_dialogProc);
+ return 1;
+ }
+ return 0;
+}
+
+extern "C" __declspec(dllexport) PMPDevicePlugin *winampGetPMPDevicePlugin()
+{
+ return &plugin;
+}
+
diff --git a/Src/Plugins/Portable/pmp_android/pmp_android.rc b/Src/Plugins/Portable/pmp_android/pmp_android.rc
new file mode 100644
index 00000000..2d312229
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/pmp_android.rc
@@ -0,0 +1,209 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""version.rc2""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// PNG
+//
+
+IDB_ANDROID_160 PNG "resources\\generic_android.png"
+IDR_ANDROID_ICON PNG "resources\\androidIcon.png"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_CONFIG DIALOGEX 0, 0, 264, 226
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "File Name Format",IDC_STATIC,7,10,56,8
+ EDITTEXT IDC_NAMEFORMAT,80,7,127,14,ES_AUTOHSCROLL
+ PUSHBUTTON "Format Help",IDC_FILENAMEHELP,211,7,46,14
+ LTEXT "Playlist Directory",IDC_STATIC,7,26,54,8
+ EDITTEXT IDC_PLDIR,80,24,128,14,ES_AUTOHSCROLL
+ PUSHBUTTON "Browse...",IDC_PLBROWSE,211,23,46,14
+ LTEXT "Supported Formats",IDC_STATIC,7,42,62,8
+ EDITTEXT IDC_SUPPORTEDFORMATS,80,40,128,14,ES_AUTOHSCROLL
+ PUSHBUTTON "Syntax Help",IDC_FORMATSHELP,211,40,46,14
+ LTEXT "Delete Empty Folders",IDC_STATIC,7,55,69,8
+ CONTROL "",IDC_PURGEFOLDERS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,80,56,8,8
+ PUSHBUTTON "Save and Rescan",IDC_RESCAN,7,71,66,14
+ PUSHBUTTON "Refresh Cache",IDC_REFRESHCACHE,79,71,66,14
+ GROUPBOX "Playlist Writing Options",IDC_STATIC,7,95,250,49
+ COMBOBOX IDC_PL_WRITE_COMBO,12,108,120,35,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Changing how Winamp saves its playlists may improve compatability with other portable devices.",IDC_STATIC,137,104,113,34
+ LTEXT "",IDC_PL_WRITE_EG,12,126,120,10
+END
+
+IDD_CONFIG_GLOBAL DIALOGEX 0, 0, 196, 90
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Android Device Support Configuration"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Select the Drive to use from the available list below",IDC_STATIC,5,3,186,67
+ COMBOBOX IDC_COMBO_MANUALCONNECT,31,17,40,242,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Connect Drive",IDC_MANUALCONNECT,75,17,90,13
+ PUSHBUTTON "Disconnect Drive",IDC_MANUALDISCONNECT,75,34,90,13
+ PUSHBUTTON "Blacklist Drive",IDC_MANUALBLACKLIST,75,51,90,13
+ DEFPUSHBUTTON "Close",IDOK,75,73,45,13
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_CONFIG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 257
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 218
+ END
+
+ IDD_CONFIG_GLOBAL, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 191
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 86
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_NULLSOFT_ANDROID_DEVICE_PLUGIN "Nullsoft Android Device Plug-in v%s"
+ 65535 "{EBFF6E00-39D8-45e6-B3EC-E3B07A45E6B0}"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_CANNOT_OPEN_FILE "Cannot open file"
+ IDS_CANNOT_CREATE_FILE "Cannot create file"
+ IDS_TRANSFERING_PERCENT "Transferring %d%%"
+ IDS_CANCELLED "Cancelled"
+ IDS_DONE "Done"
+ IDS_TRANSFER_FAILED "Transfer failed"
+ IDS_REMOVEABLE_DRIVE_DETECTED
+ "Winamp has detected an Android device on %c:.\nIs this a device that you want to manage with Winamp?"
+ IDS_WINAMP_PMP_SUPPORT "Winamp Portable Music Player Support"
+ IDS_MANUAL_CONNECT_PROMPT
+ "Manually connecting the wrong device could cause problems.\nPlease be sure that you have entered a valid Android device letter.\n\nAre you sure you wish to continue?"
+ IDS_WARNING "Warning"
+ IDS_LOADING_DRIVE_X "Loading Drive X:"
+ IDS_FAILED_TO_EJECT_DRIVE
+ "Failed to eject device. Is something else using it?"
+ IDS_ERROR "Error"
+ IDS_ANDROID_DRIVE_X "ANDROID Drive X:"
+ IDS_TRACK_IN_USE "Track is in use - Could not delete!"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_CACHE_UPDATED "Cache updated."
+ IDS_SUCCESS "Success"
+ IDS_FILENAME_FORMATTING_INFO
+ "You may enter a filename format string for your files.\nIt can contain \\ or / to delimit a path, and the following keywords:\n\n <Artist> - inserts the artist with the default capitalization\n <ARTIST> - inserts the artist in all uppercase\n <artist> - inserts the artist in all lowercase\n <Albumartist>/<ALBUMARTIST>/<albumartist> - inserts the album artist\n <Album>/<ALBUM>/<album> - inserts the album\n <year> - inserts the album year\n <Genre>/<GENRE>/<genre> - inserts the album genre\n <Title>/<TITLE>/<title> - inserts the track title\n <filename> - inserts the original filename (extension safe)\n <disc> - inserts the disc number\n #, ##, or ### - inserts the track number, with leading 0s if ## or ###\n\n For Example: E:\\Music\\<Artist>\\<Album>\\## - <Title>\n"
+ IDS_FILENAME_FORMAT_HELP "Filename Format Help"
+ IDS_SELECT_FOLDER_TO_LOAD_PLAYLISTS
+ "Please select a folder to load playlists from the device."
+ IDS_ERR_SELECTED_PATH_NOT_ON_DEVICE
+ "Error: selected path is not on device!"
+ IDS_SUPPORTED_FORMAT_INFO
+ "You may enter supported extensions in the form of\nextensions separated by semicolons.\n\nFor Example: mp3;wav;wma"
+ IDS_SUPPORTED_FORMAT_HELP "Supported Formats Help"
+ IDS_RESCAN_COMPLETE_SAVED "Rescan complete, device settings saved."
+ IDS_RESCAN_COMPLETE "Rescan complete"
+ IDS_ADVANCED "Advanced"
+ IDS_UNBLACKLIST_DRIVE "Un-blacklist Drive"
+ IDS_BLACKLIST_DRIVE "Blacklist Drive"
+ IDS_DRIVE_CONNECTED_DISCONNECT_Q
+ "The Drive you have selected to blacklist is currently connected and being managed.\n\nWould you like to disconnect the Drive now or you can wait until you restart Winamp."
+ IDS_SLASH_AT_START "Slash at start of paths (default)"
+ IDS_DOT_AT_START "Dot at start of paths"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_NO_SLASH_OR_DOT "No slash or dot at start"
+ IDS_EG_SLASH "e.g. \\path\\to\\file.mp3"
+ IDS_EG_DOT "e.g. .\\path\\to\\file.mp3"
+ IDS_EG_NEITHER "e.g. path\\to\\file.mp3"
+ IDS_DELAYLOAD_FAILURE "Android plug-in cannot load the database to write the cache file"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc2"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/Plugins/Portable/pmp_android/pmp_android.sln b/Src/Plugins/Portable/pmp_android/pmp_android.sln
new file mode 100644
index 00000000..3e21ea33
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/pmp_android.sln
@@ -0,0 +1,130 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29509.3
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmp_android", "pmp_android.vcxproj", "{491665B2-6437-4D30-9AEC-DE7D1CB20E1E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27} = {57C90706-B25D-4ACA-9B33-95CDB2427C27}
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A} = {4D25C321-7F8B-424E-9899-D80A364BAF1A}
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1} = {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915} = {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}
+ {E105A0A2-7391-47C5-86AC-718003524C3D} = {E105A0A2-7391-47C5-86AC-718003524C3D}
+ {255B68B5-7EF8-45EF-A675-2D6B88147909} = {255B68B5-7EF8-45EF-A675-2D6B88147909}
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bfc", "..\Wasabi\bfc\bfc.vcxproj", "{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tataki", "..\tataki\tataki.vcxproj", "{255B68B5-7EF8-45EF-A675-2D6B88147909}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsutil", "..\nsutil\nsutil.vcxproj", "{DABE6307-F8DD-416D-9DAC-673E2DECB73F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nde", "..\nde\nde.vcxproj", "{4D25C321-7F8B-424E-9899-D80A364BAF1A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nx", "..\replicant\nx\nx.vcxproj", "{57C90706-B25D-4ACA-9B33-95CDB2427C27}"
+ ProjectSection(ProjectDependencies) = postProject
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nu", "..\replicant\nu\nu.vcxproj", "{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jnetlib", "..\replicant\jnetlib\jnetlib.vcxproj", "{E105A0A2-7391-47C5-86AC-718003524C3D}"
+ ProjectSection(ProjectDependencies) = postProject
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\replicant\zlib\zlib.vcxproj", "{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Debug|Win32.Build.0 = Debug|Win32
+ {491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Debug|x64.ActiveCfg = Debug|x64
+ {491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Debug|x64.Build.0 = Debug|x64
+ {491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Release|Win32.ActiveCfg = Release|Win32
+ {491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Release|Win32.Build.0 = Release|Win32
+ {491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Release|x64.ActiveCfg = Release|x64
+ {491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Release|x64.Build.0 = Release|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.Build.0 = Debug|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.ActiveCfg = Debug|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.Build.0 = Debug|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.ActiveCfg = Release|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.Build.0 = Release|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.ActiveCfg = Release|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.Build.0 = Release|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|Win32.ActiveCfg = Debug|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|Win32.Build.0 = Debug|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|x64.ActiveCfg = Debug|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|x64.Build.0 = Debug|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|Win32.ActiveCfg = Release|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|Win32.Build.0 = Release|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|x64.ActiveCfg = Release|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|x64.Build.0 = Release|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.Build.0 = Debug|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.ActiveCfg = Debug|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.Build.0 = Debug|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.ActiveCfg = Release|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.Build.0 = Release|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.ActiveCfg = Release|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.Build.0 = Release|x64
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|Win32.Build.0 = Debug|Win32
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|x64.ActiveCfg = Debug|x64
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|x64.Build.0 = Debug|x64
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|Win32.ActiveCfg = Release|Win32
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|Win32.Build.0 = Release|Win32
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|x64.ActiveCfg = Release|x64
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|x64.Build.0 = Release|x64
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.ActiveCfg = Debug|Win32
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.Build.0 = Debug|Win32
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.ActiveCfg = Debug|x64
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.Build.0 = Debug|x64
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.ActiveCfg = Release|Win32
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.Build.0 = Release|Win32
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.ActiveCfg = Release|x64
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.Build.0 = Release|x64
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.Build.0 = Debug|Win32
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.ActiveCfg = Debug|x64
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.Build.0 = Debug|x64
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.ActiveCfg = Release|Win32
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.Build.0 = Release|Win32
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.ActiveCfg = Release|x64
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.Build.0 = Release|x64
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.Build.0 = Debug|Win32
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.ActiveCfg = Debug|x64
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.Build.0 = Debug|x64
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.ActiveCfg = Release|Win32
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.Build.0 = Release|Win32
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.ActiveCfg = Release|x64
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.Build.0 = Release|x64
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.Build.0 = Debug|Win32
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.ActiveCfg = Debug|x64
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.Build.0 = Debug|x64
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.ActiveCfg = Release|Win32
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.Build.0 = Release|Win32
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.ActiveCfg = Release|x64
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {C4E799C1-027B-487B-8E1A-31F2D26A1AFE}
+ EndGlobalSection
+EndGlobal
diff --git a/Src/Plugins/Portable/pmp_android/pmp_android.vcxproj b/Src/Plugins/Portable/pmp_android/pmp_android.vcxproj
new file mode 100644
index 00000000..34236c88
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/pmp_android.vcxproj
@@ -0,0 +1,332 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{491665B2-6437-4D30-9AEC-DE7D1CB20E1E}</ProjectGuid>
+ <RootNamespace>pmp_android</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg">
+ <VcpkgEnableManifest>false</VcpkgEnableManifest>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;..\..\..\Wasabi;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_WINDOWS;_UNICODE;UNICODE;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;shlwapi.lib;fmtd.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalIncludeDirectories)</AdditionalLibraryDirectories>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;..\..\..\Wasabi;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_WINDOWS;_UNICODE;UNICODE;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN64;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>.;..\..\..\Wasabi;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_WINDOWS;_UNICODE;UNICODE;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>.;..\..\..\Wasabi;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_WINDOWS;_UNICODE;UNICODE;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN64;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp" />
+ <ClCompile Include="albumart.cpp" />
+ <ClCompile Include="androiddevice.cpp" />
+ <ClCompile Include="androidplaylist.cpp" />
+ <ClCompile Include="androidplaylistsaver.cpp" />
+ <ClCompile Include="api.cpp" />
+ <ClCompile Include="deviceprovider.cpp" />
+ <ClCompile Include="eject.cpp" />
+ <ClCompile Include="filecopy.cpp" />
+ <ClCompile Include="main.cpp" />
+ <ClCompile Include="utils.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\General\gen_ml\ml.h" />
+ <ClInclude Include="..\..\Library\ml_pmp\pmp.h" />
+ <ClInclude Include="androiddevice.h" />
+ <ClInclude Include="androidplaylist.h" />
+ <ClInclude Include="androidplaylistsaver.h" />
+ <ClInclude Include="api.h" />
+ <ClInclude Include="deviceprovider.h" />
+ <ClInclude Include="resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="resources\androidIcon.png" />
+ <Image Include="resources\generic_android.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="pmp_android.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\nde\nde.vcxproj">
+ <Project>{4d25c321-7f8b-424e-9899-d80a364baf1a}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\replicant\nu\nu.vcxproj">
+ <Project>{f1f5cd60-0d5b-4cea-9eeb-2f87ff9aa915}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\tataki\tataki.vcxproj">
+ <Project>{255b68b5-7ef8-45ef-a675-2d6b88147909}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
+ <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\WAT\WAT.vcxproj">
+ <Project>{c5714908-a71f-4644-bd95-aad8ee7914da}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_android/pmp_android.vcxproj.filters b/Src/Plugins/Portable/pmp_android/pmp_android.vcxproj.filters
new file mode 100644
index 00000000..ead498ac
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/pmp_android.vcxproj.filters
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="albumart.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="androiddevice.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="androidplaylist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="androidplaylistsaver.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="api.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="deviceprovider.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="eject.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="filecopy.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="androiddevice.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="androidplaylist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="androidplaylistsaver.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="api.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="deviceprovider.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\General\gen_ml\ml.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Library\ml_pmp\pmp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="resources\generic_android.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resources\androidIcon.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{82d6647a-a3b9-4ade-b2cc-4a360f5ed80d}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Ressource Files">
+ <UniqueIdentifier>{8731ac77-4c42-42fc-8ff8-f64922843c99}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{06318ce7-b270-4a39-833a-4ab306c760ed}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Image Files">
+ <UniqueIdentifier>{d2febc64-2e0e-4a50-8994-0dcaab423352}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="pmp_android.rc">
+ <Filter>Ressource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_android/resource.h b/Src/Plugins/Portable/pmp_android/resource.h
new file mode 100644
index 00000000..4ca89908
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/resource.h
@@ -0,0 +1,75 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by pmp_android.rc
+//
+#define IDS_CANNOT_OPEN_FILE 1
+#define IDS_CANNOT_CREATE_FILE 2
+#define IDS_TRANSFERING_PERCENT 3
+#define IDS_CANCELLED 4
+#define IDS_DONE 5
+#define IDS_TRANSFER_FAILED 6
+#define IDS_REMOVEABLE_DRIVE_DETECTED 7
+#define IDS_WINAMP_PMP_SUPPORT 8
+#define IDS_MANUAL_CONNECT_PROMPT 9
+#define IDS_WARNING 10
+#define IDS_LOADING_DRIVE_X 11
+#define IDS_FAILED_TO_EJECT_DRIVE 12
+#define IDS_ERROR 13
+#define IDS_STRING14 14
+#define IDS_ANDROID_DRIVE_X 14
+#define IDS_TRACK_IN_USE 15
+#define IDS_CACHE_UPDATED 16
+#define IDS_SUCCESS 17
+#define IDS_FILENAME_FORMATTING_INFO 18
+#define IDS_FILENAME_FORMAT_HELP 19
+#define IDS_SELECT_FOLDER_TO_LOAD_PLAYLISTS 20
+#define IDS_ERR_SELECTED_PATH_NOT_ON_DEVICE 21
+#define IDS_SUPPORTED_FORMAT_INFO 22
+#define IDS_SUPPORTED_FORMAT_HELP 23
+#define IDS_RESCAN_COMPLETE_SAVED 24
+#define IDS_RESCAN_COMPLETE 25
+#define IDS_ADVANCED 26
+#define IDS_UNBLACKLIST_DRIVE 27
+#define IDS_BLACKLIST_DRIVE 28
+#define IDS_DRIVE_CONNECTED_DISCONNECT_Q 29
+#define IDS_SLASH_AT_START 30
+#define IDS_DOT_AT_START 31
+#define IDS_NO_SLASH_OR_DOT 32
+#define IDS_EG_SLASH 33
+#define IDS_EG_DOT 34
+#define IDS_STRING35 35
+#define IDS_EG_NEITHER 35
+#define IDS_DELAYLOAD_FAILURE 36
+#define IDD_CONFIG 102
+#define IDD_CONFIG_GLOBAL 105
+#define IDB_ANDROID_160 110
+#define IDB_PNG1 111
+#define IDR_ANDROID_ICON 111
+#define IDC_PLDIR 1001
+#define IDC_NAMEFORMAT 1002
+#define IDC_SUPPORTEDFORMATS 1003
+#define IDC_DRIVESELECT 1004
+#define IDC_COMBO_MANUALCONNECT 1005
+#define IDC_MANUALCONNECT 1006
+#define IDC_MANUALDISCONNECT 1007
+#define IDC_MANUALBLACKLIST 1008
+#define IDC_REFRESHCACHE 1011
+#define IDC_FILENAMEHELP 1012
+#define IDC_PLBROWSE 1013
+#define IDC_FORMATSHELP 1014
+#define IDC_RESCAN 1015
+#define IDC_PURGEFOLDERS 1016
+#define IDC_PL_WRITE_COMBO 1017
+#define IDC_PL_WRITE_EG 1018
+#define IDS_NULLSOFT_ANDROID_DEVICE_PLUGIN 65534
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 113
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1019
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/Plugins/Portable/pmp_android/resources/androidIcon.png b/Src/Plugins/Portable/pmp_android/resources/androidIcon.png
new file mode 100644
index 00000000..674c4774
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/resources/androidIcon.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_android/resources/generic_android.png b/Src/Plugins/Portable/pmp_android/resources/generic_android.png
new file mode 100644
index 00000000..bafdb3ce
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/resources/generic_android.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_android/utils.cpp b/Src/Plugins/Portable/pmp_android/utils.cpp
new file mode 100644
index 00000000..b81093dc
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/utils.cpp
@@ -0,0 +1,334 @@
+#include <windows.h>
+#include "../../General/gen_ml/ml.h"
+#include "../../Library/ml_pmp/pmp.h"
+#include "AndroidDevice.h"
+#include <strsafe.h>
+#include <shlwapi.h>
+
+BOOL RecursiveCreateDirectory(wchar_t* buf1);
+__int64 fileSize(wchar_t * filename);
+bool supportedFormat(wchar_t * file, wchar_t * supportedFormats);
+DeviceType detectDeviceType(wchar_t drive);
+void removebadchars(wchar_t *s);
+wchar_t * FixReplacementVars(wchar_t *str, int str_size, Device * dev, songid_t song);
+
+void removebadchars(wchar_t *s) {
+ while (s && *s)
+ {
+ if (*s == L'?' || *s == L'/' || *s == L'\\' || *s == L':' || *s == L'*' || *s == L'\"' || *s == L'<' || *s == L'>' || *s == L'|')
+ *s = L'_';
+ s = CharNextW(s);
+ }
+}
+
+__int64 fileSize(wchar_t * filename)
+{
+ WIN32_FIND_DATA f={0};
+ HANDLE h = FindFirstFileW(filename,&f);
+ if(h == INVALID_HANDLE_VALUE) return -1;
+ FindClose(h);
+ ULARGE_INTEGER i;
+ i.HighPart = f.nFileSizeHigh;
+ i.LowPart = f.nFileSizeLow;
+ return i.QuadPart;
+}
+
+// RecursiveCreateDirectory: creates all non-existent folders in a path
+BOOL RecursiveCreateDirectory(wchar_t* buf1) {
+ wchar_t *p=buf1;
+ int errors = 0;
+ if (*p) {
+ p = PathSkipRoot(buf1);
+ if (!p) return true ;
+
+ wchar_t ch='c';
+ while (ch) {
+ while (p && *p != '\\' && *p) p = CharNext(p);
+ ch = (p ? *p : 0);
+ if (p) *p = 0;
+ int pp = (int)wcslen(buf1)-1;
+
+ while(buf1[pp] == '.' || buf1[pp] == ' ' ||
+ (buf1[pp] == '\\' && (buf1[pp-1] == '.' || buf1[pp-1] == ' ' || buf1[pp-1] == '/')) ||
+ buf1[pp] == '/' && buf1)
+ {
+ if(buf1[pp] == '\\')
+ {
+ buf1[pp-1] = '_';
+ pp -= 2;
+ } else {
+ buf1[pp] = '_';
+ pp--;
+ }
+ }
+
+ WIN32_FIND_DATA fd = {0};
+ // Avoid a "There is no disk in the drive" error box on empty removable drives
+ UINT prevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
+ HANDLE h = FindFirstFile(buf1,&fd);
+ SetErrorMode(prevErrorMode);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ if (!CreateDirectory(buf1,NULL)) errors++;
+ } else {
+ FindClose(h);
+ if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) errors++;
+ }
+ if (p) *p++ = ch;
+ }
+ }
+
+ return errors != 0;
+}
+
+bool supportedFormat(wchar_t * file, wchar_t * supportedFormats) {
+ wchar_t * ext = wcsrchr(file,'.');
+ if(!ext) return false;
+ ext++;
+ wchar_t * p = supportedFormats;
+ while(p && *p) {
+ bool ret=false;
+ wchar_t * np = wcschr(p,L';');
+ if(np) *np = 0;
+ if(!_wcsicmp(ext,p)) ret=true;
+ if(np) { *np = L';'; p=np+1; }
+ else return ret;
+ if(ret) return true;
+ }
+ return false;
+}
+
+// FixReplacementVars: replaces <Artist>, <Title>, <Album>, and #, ##, ##, with appropriate data
+// DOES NOT add a file extention!!
+wchar_t * fixReplacementVars(wchar_t *str, int str_size, Device * dev, songid_t song)
+{
+ #define ADD_STR(x) { x(song,outp,str_size-1-(outp-str)); removebadchars(outp); while (outp && *outp) outp++; }
+ #define ADD_STR_U(x) { x(song,outp,str_size-1-(outp-str)); removebadchars(outp); while (outp && *outp) { *outp=towupper(*outp); outp++; } }
+ #define ADD_STR_L(x) { x(song,outp,str_size-1-(outp-str)); removebadchars(outp); while (outp && *outp) { *outp=towlower(*outp); outp++; } }
+
+ wchar_t tmpsrc[4096] = {0};
+ lstrcpyn(tmpsrc,str,sizeof(tmpsrc)/sizeof(wchar_t)); //lstrcpyn is nice enough to make sure it's null terminated.
+
+ wchar_t *inp = tmpsrc;
+ wchar_t *outp = str;
+ int slash = 0;
+
+ while (inp && *inp && outp-str < str_size-2)
+ {
+ if (*inp == L'<')
+ {
+ if (!wcsncmp(inp,L"<TITLE>",7))
+ {
+ ADD_STR_U(dev->getTrackTitle);
+ inp+=7;
+ }
+ else if (!wcsncmp(inp,L"<title>",7))
+ {
+ ADD_STR_L(dev->getTrackTitle);
+ inp+=7;
+ }
+ else if (!_wcsnicmp(inp,L"<Title>",7))
+ {
+ ADD_STR(dev->getTrackTitle);
+ inp+=7;
+ }
+ else if (!wcsncmp(inp,L"<ALBUM>",7))
+ {
+ ADD_STR_U(dev->getTrackAlbum);
+ inp+=7;
+ }
+ else if (!wcsncmp(inp,L"<album>",7))
+ {
+ ADD_STR_L(dev->getTrackAlbum);
+ inp+=7;
+ }
+ else if (!_wcsnicmp(inp,L"<Album>",7))
+ {
+ ADD_STR(dev->getTrackAlbum);
+ inp+=7;
+ }
+ else if (!wcsncmp(inp,L"<GENRE>",7))
+ {
+ ADD_STR_U(dev->getTrackGenre);
+ inp+=7;
+ }
+ else if (!wcsncmp(inp,L"<genre>",7))
+ {
+ ADD_STR_L(dev->getTrackGenre);
+ inp+=7;
+ }
+ else if (!_wcsnicmp(inp,L"<Genre>",7))
+ {
+ ADD_STR(dev->getTrackGenre);
+ inp+=7;
+ }
+ else if (!wcsncmp(inp,L"<ARTIST>",8))
+ {
+ ADD_STR_U(dev->getTrackArtist);
+ inp+=8;
+ }
+ else if (!wcsncmp(inp,L"<artist>",8))
+ {
+ ADD_STR_L(dev->getTrackArtist);
+ inp+=8;
+ }
+ else if (!_wcsnicmp(inp,L"<Artist>",8))
+ {
+ ADD_STR(dev->getTrackArtist);
+ inp+=8;
+ }
+ else if (!wcsncmp(inp,L"<ALBUMARTIST>",13))
+ {
+ wchar_t temp[128] = {0};
+
+ dev->getTrackAlbumArtist(song, temp, 128);
+ if (temp[0] == 0)
+ dev->getTrackArtist(song, temp, 128);
+
+ lstrcpyn(outp,temp,str_size-1-(outp-str));
+ removebadchars(outp);
+ while (outp && *outp) { *outp=towupper(*outp); outp++; }
+
+ inp+=13;
+ }
+ else if (!wcsncmp(inp,L"<albumartist>",13))
+ {
+ wchar_t temp[128] = {0};
+
+ dev->getTrackAlbumArtist(song, temp, 128);
+ if (temp[0] == 0)
+ dev->getTrackArtist(song, temp, 128);
+
+ lstrcpyn(outp,temp,str_size-1-(outp-str));
+ removebadchars(outp);
+ while (outp && *outp) { *outp=towlower(*outp); outp++; }
+ inp+=13;
+ }
+ else if (!_wcsnicmp(inp,L"<Albumartist>",13))
+ {
+ wchar_t temp[128] = {0};
+
+ dev->getTrackAlbumArtist(song, temp, 128);
+ if (temp[0] == 0)
+ dev->getTrackArtist(song, temp, 128);
+
+ lstrcpyn(outp,temp, (int)str_size-1-(outp-str));
+ removebadchars(outp);
+ while (outp && *outp) outp++;
+ inp+=13;
+ }
+ else if (!_wcsnicmp(inp,L"<year>",6))
+ {
+ wchar_t year[64] = {0};
+ int y = dev->getTrackYear(song);
+ if (y) StringCchPrintf(year, ARRAYSIZE(year), L"%d", y);
+ lstrcpyn(outp,year, (int)str_size-1-(outp-str)); while (outp && *outp) outp++;
+ inp+=6;
+ }
+ else if (!_wcsnicmp(inp,L"<disc>",6))
+ {
+ wchar_t disc[16] = {0};
+ int d = dev->getTrackDiscNum(song);
+ if (d) StringCchPrintf(disc, ARRAYSIZE(disc), L"%d", d);
+ lstrcpyn(outp,disc, (int)str_size-1-(outp-str)); while (outp && *outp) outp++;
+ inp+=6;
+ }
+ else if (!_wcsnicmp(inp,L"<filename>",10))
+ {
+ wchar_t tfn[MAX_PATH], *ext, *fn;
+ StringCchCopy(tfn,MAX_PATH,((AndroidSong*)song)->filename);
+ ext = wcsrchr(tfn, L'.');
+ *ext = 0; //kill extension since its added later
+ fn = wcsrchr(tfn, L'\\');
+ fn++;
+ lstrcpyn(outp,fn, (int)str_size-1-(outp-str));
+ while (outp && *outp) outp++;
+ inp+=10;
+ }
+ else
+ {
+ // use this to skip over unknown tags
+ while (inp && *inp && *inp != L'>') inp++;
+ if (inp) inp++;
+ }
+ }
+ else if (*inp == L'#')
+ {
+ int nd=0;
+ wchar_t tmp[64] = {0};
+ while (inp && *inp == L'#') nd++,inp++;
+ int track = dev->getTrackTrackNum(song);
+ if (!track)
+ {
+ while (inp && *inp == L' ') inp++;
+ while (inp && *inp == L'\\') inp++;
+ if (inp && (*inp == L'-' || *inp == L'.' || *inp == L'_')) // separator
+ {
+ inp++;
+ while (inp && *inp == L' ') inp++;
+ }
+ }
+ else
+ {
+ if (nd > 1)
+ {
+ wchar_t tmp2[32] = {0};
+ if (nd > 5) nd=5;
+ StringCchPrintf(tmp2, ARRAYSIZE(tmp2), L"%%%02dd",nd);
+ StringCchPrintf(tmp, ARRAYSIZE(tmp), tmp2,track);
+ }
+ else StringCchPrintf(tmp, ARRAYSIZE(tmp), L"%d",track);
+ }
+ lstrcpyn(outp,tmp, (int)str_size-1-(outp-str)); while (outp && *outp) outp++;
+ }
+ else
+ {
+ if (*inp == L'\\') slash += 1;
+ *outp++=*inp++;
+ }
+ }
+
+ if (outp) *outp = 0;
+
+ // if we end up with something like U:\\\ then this
+ // will set it to be just <filename> so it'll not
+ // end up making a load of bad files e.g. U:\.mp3
+ int out_len = lstrlen(str);
+ if (out_len)
+ {
+ if (out_len - 2 == slash)
+ {
+ outp = str + 3;
+ wchar_t tfn[MAX_PATH], *ext, *fn;
+ StringCchCopy(tfn,MAX_PATH,((AndroidSong*)song)->filename);
+ ext = wcsrchr(tfn, L'.');
+ *ext = 0; //kill extension since its added later
+ fn = wcsrchr(tfn, L'\\');
+ fn++;
+ lstrcpyn(outp,fn, (int)str_size-1-(outp-str));
+ while (outp && *outp) outp++;
+ if (outp) *outp = 0;
+ }
+ }
+
+ inp=str;
+ outp=str;
+ wchar_t lastc=0;
+ while (inp && *inp)
+ {
+ wchar_t ch=*inp++;
+ if (ch == L'\t') ch=L' ';
+
+ if (ch == L' ' && (lastc == L' ' || lastc == L'\\' || lastc == L'/')) continue; // ignore space after slash, or another space
+
+ if ((ch == L'\\' || ch == L'/') && lastc == L' ') outp--; // if we have a space then slash, back up to write the slash where the space was
+ *outp++=ch;
+ lastc=ch;
+ }
+ if (outp) *outp=0;
+ #undef ADD_STR
+ #undef ADD_STR_L
+ #undef ADD_STR_U
+
+ return str;
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_android/version.rc2 b/Src/Plugins/Portable/pmp_android/version.rc2
new file mode 100644
index 00000000..0bc218ca
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_android/version.rc2
@@ -0,0 +1,39 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#include "../../../Winamp/buildType.h"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,72,0,0
+ PRODUCTVERSION WINAMP_PRODUCTVER
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Winamp SA"
+ VALUE "FileDescription", "Winamp Portable Device Plug-in"
+ VALUE "FileVersion", "1,72,0,0"
+ VALUE "InternalName", "Nullsoft Android Device"
+ VALUE "LegalCopyright", "Copyright © 2010-2023 Winamp SA"
+ VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
+ VALUE "OriginalFilename", "pmp_android.dll"
+ VALUE "ProductName", "Winamp"
+ VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/Src/Plugins/Portable/pmp_ipod/SysInfoXML.cpp b/Src/Plugins/Portable/pmp_ipod/SysInfoXML.cpp
new file mode 100644
index 00000000..61246c8f
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/SysInfoXML.cpp
@@ -0,0 +1,149 @@
+#include <windows.h>
+#include <stddef.h> // for offsetof
+#include <winioctl.h>
+#include <strsafe.h>
+
+ typedef struct {
+ USHORT Length;
+ UCHAR ScsiStatus;
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+ UCHAR CdbLength;
+ UCHAR SenseInfoLength;
+ UCHAR DataIn;
+ ULONG DataTransferLength;
+ ULONG TimeOutValue;
+ PVOID DataBuffer;
+ ULONG SenseInfoOffset;
+ UCHAR Cdb[16];
+} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
+
+
+ typedef struct {
+ SCSI_PASS_THROUGH_DIRECT spt;
+ ULONG Filler;
+ UCHAR ucSenseBuf[32];
+} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
+
+
+
+ #define IOCTL_SCSI_BASE 0x00000004
+
+/*
+ * constants for DataIn member of SCSI_PASS_THROUGH* structures
+ */
+#define SCSI_IOCTL_DATA_OUT 0
+#define SCSI_IOCTL_DATA_IN 1
+#define SCSI_IOCTL_DATA_UNSPECIFIED 2
+
+/*
+ * Standard IOCTL define
+ */
+#define CTL_CODE( DevType, Function, Method, Access ) ( \
+ ((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
+)
+
+#define IOCTL_SCSI_PASS_THROUGH CTL_CODE( IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
+#define IOCTL_SCSI_MINIPORT CTL_CODE( IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
+#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE( IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE( IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE( IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
+#define IOCTL_SCSI_GET_ADDRESS CTL_CODE( IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS
+
+static bool scsi_inquiry(HANDLE deviceHandle, UCHAR page, UCHAR *inqbuf, size_t &buf_len)
+{
+ char buf[2048] = {0};
+ BOOL status;
+ PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER pswb;
+
+ DWORD length=0, returned=0;
+
+ /*
+ * Get the drive inquiry data
+ */
+ ZeroMemory( &buf, 2048 );
+ ZeroMemory( inqbuf, buf_len );
+ pswb = (PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)buf;
+ pswb->spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
+ pswb->spt.CdbLength = 6;
+ pswb->spt.SenseInfoLength = 32;
+ pswb->spt.DataIn = SCSI_IOCTL_DATA_IN;
+ pswb->spt.DataTransferLength = buf_len;
+ pswb->spt.TimeOutValue = 2;
+ pswb->spt.DataBuffer = inqbuf;
+ pswb->spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER,ucSenseBuf);
+ pswb->spt.Cdb[0] = 0x12;
+ pswb->spt.Cdb[1] = 0x1;
+ pswb->spt.Cdb[2] = page;
+ pswb->spt.Cdb[4] = (UCHAR)buf_len;
+
+ length = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
+ status = DeviceIoControl( deviceHandle,
+ IOCTL_SCSI_PASS_THROUGH_DIRECT,
+ pswb,
+ length,
+ pswb,
+ length,
+ &returned,
+ NULL );
+
+
+ if (status && returned >3)
+ {
+ buf_len=returned;
+ return true;
+ }
+ else
+ {
+ buf_len=0;
+ return false;
+ }
+}
+
+static bool AddPagetoXML(HANDLE dev, char *&dest, size_t &destlen, UCHAR page)
+{
+ UCHAR buf[256] = {0};
+ size_t buflen=255;
+ if (scsi_inquiry(dev, page, buf, buflen))
+ {
+ size_t len = buf[3];
+ StringCchCopyNExA(dest, destlen, (char *)buf+4, len, &dest, &destlen, 0);
+ return true;
+ }
+ return false;
+}
+
+static bool BuildXML(HANDLE dev, char *xml, size_t xmllen)
+{
+ *xml=0;
+ UCHAR pages[255] = {0};
+ size_t pageslen=255;
+ if (scsi_inquiry(dev, 0xc0, pages, pageslen) && pageslen>3)
+ {
+ unsigned char numPages=pages[3];
+ if (numPages+4 <= 255)
+ {
+ for (int i=0;i<numPages;i++)
+ {
+ if (!AddPagetoXML(dev, xml, xmllen, pages[i+4]))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool ParseSysInfoXML(wchar_t drive_letter, char * xml, int xmllen)
+{
+ wchar_t fn[MAX_PATH] = {0};
+ StringCchPrintf(fn, MAX_PATH, L"\\\\.\\%c:", drive_letter);
+ HANDLE hfile = CreateFileW(fn, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
+ if (hfile != INVALID_HANDLE_VALUE)
+ {
+ bool ret = BuildXML(hfile, xml, xmllen);
+ CloseHandle(hfile);
+ return ret;
+ }
+ return false;
+}
diff --git a/Src/Plugins/Portable/pmp_ipod/api.h b/Src/Plugins/Portable/pmp_ipod/api.h
new file mode 100644
index 00000000..3443671f
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/api.h
@@ -0,0 +1,30 @@
+#ifndef NULLSOFT_PMP_IPOD_API_H
+#define NULLSOFT_PMP_IPOD_API_H
+
+#include <api/memmgr/api_memmgr.h>
+extern api_memmgr *memmgr;
+#define WASABI_API_MEMMGR memmgr
+
+#include "../Agave/AlbumArt/api_albumart.h"
+extern api_albumart *albumArtApi;
+#define AGAVE_API_ALBUMART albumArtApi
+
+#include "../Agave/Config/api_config.h"
+extern api_config *agaveConfigApi;
+#define AGAVE_API_CONFIG agaveConfigApi
+
+#include "../Agave/Language/api_language.h"
+
+#include "../nu/threadpool/api_threadpool.h"
+extern api_threadpool *threadPoolApi;
+#define WASABI_API_THREADPOOL threadPoolApi
+
+#include <api/application/api_application.h>
+extern api_application *applicationApi;
+#define WASABI_API_APP applicationApi
+
+#include "../devices/api_devicemanager.h"
+extern api_devicemanager *deviceManagerApi;
+#define AGAVE_API_DEVICEMANAGER deviceManagerApi
+
+#endif \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_ipod/deviceprovider.cpp b/Src/Plugins/Portable/pmp_ipod/deviceprovider.cpp
new file mode 100644
index 00000000..8b68922a
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/deviceprovider.cpp
@@ -0,0 +1,343 @@
+#include "api.h"
+#include "./deviceprovider.h"
+#include "../devices/api_devicemanager.h"
+
+extern PMPDevicePlugin plugin;
+bool ConnectDrive(wchar_t drive, bool connect);
+
+static size_t tlsIndex = (size_t)-1;
+
+static BOOL
+DiscoveryProvider_RegisterCancelSwitch(BOOL *cancelSwitch)
+{
+ if ((size_t)-1 != tlsIndex &&
+ NULL != WASABI_API_APP)
+ {
+ WASABI_API_APP->SetThreadStorage(tlsIndex, cancelSwitch);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static BOOL
+DiscoveryProvider_GetCancelSwitchOn()
+{
+ if ((size_t)-1 != tlsIndex &&
+ NULL != WASABI_API_APP)
+ {
+ BOOL *cancelSwitch = (BOOL*)WASABI_API_APP->GetThreadStorage(tlsIndex);
+ if (NULL != cancelSwitch &&
+ FALSE != *cancelSwitch)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+DeviceProvider_DriverEnumCb(wchar_t drive, unsigned int type)
+{
+ if (DRIVE_REMOVABLE == type &&
+ FALSE == DiscoveryProvider_GetCancelSwitchOn())
+ {
+ ConnectDrive(drive,true);
+ }
+}
+
+DeviceProvider::DeviceProvider()
+ : ref(1), activity(0), manager(NULL), readyEvent(NULL), cancelDiscovery(FALSE)
+{
+ InitializeCriticalSection(&lock);
+ enumerator = (ENUMDRIVES)SendMessageW(plugin.hwndPortablesParent,
+ WM_PMP_IPC, 0, PMP_IPC_ENUM_ACTIVE_DRIVES);
+}
+
+DeviceProvider::~DeviceProvider()
+{
+ CancelDiscovery();
+
+ if (NULL != readyEvent)
+ CloseHandle(readyEvent);
+
+ DeleteCriticalSection(&lock);
+}
+
+HRESULT DeviceProvider::CreateInstance(DeviceProvider **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = new DeviceProvider();
+
+ if (NULL == *instance)
+ return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t DeviceProvider::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t DeviceProvider::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int DeviceProvider::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object)
+ return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_DeviceProvider))
+ *object = static_cast<ifc_deviceprovider*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+void DeviceProvider::Lock()
+{
+ EnterCriticalSection(&lock);
+}
+
+void DeviceProvider::Unlock()
+{
+ LeaveCriticalSection(&lock);
+}
+
+DWORD DeviceProvider::DiscoveryThread()
+{
+ IncrementActivity();
+
+ if (NULL != enumerator &&
+ FALSE == cancelDiscovery)
+ {
+ DiscoveryProvider_RegisterCancelSwitch(&cancelDiscovery);
+
+ enumerator(DeviceProvider_DriverEnumCb);
+
+ DiscoveryProvider_RegisterCancelSwitch(NULL);
+ }
+
+ DecrementActivity();
+
+ Lock();
+
+ if (NULL != readyEvent)
+ SetEvent(readyEvent);
+
+ Unlock();
+
+
+ return 0;
+}
+
+static int DeviceProvider_DiscoveryThreadStarter(HANDLE handle, void *user, intptr_t id)
+{
+ DeviceProvider *self;
+ DWORD result;
+
+ self = (DeviceProvider*)user;
+
+ if (NULL != self)
+ result = self->DiscoveryThread();
+ else
+ result = -2;
+
+ return result;
+}
+
+HRESULT DeviceProvider::BeginDiscovery(api_devicemanager *manager)
+{
+ HRESULT hr;
+
+ if (NULL == enumerator)
+ return E_UNEXPECTED;
+
+ Lock();
+
+ if (NULL != readyEvent &&
+ WAIT_TIMEOUT == WaitForSingleObject(readyEvent, 0))
+ {
+ hr = E_PENDING;
+ }
+ else
+ {
+ hr = S_OK;
+
+ if (NULL == readyEvent)
+ {
+ readyEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (NULL == readyEvent)
+ hr = E_FAIL;
+ }
+
+ if ((size_t)-1 == tlsIndex &&
+ NULL != WASABI_API_APP)
+ {
+ tlsIndex = WASABI_API_APP->AllocateThreadStorage();
+ }
+
+ if (SUCCEEDED(hr))
+ {
+
+ cancelDiscovery = FALSE;
+ ResetEvent(readyEvent);
+
+ if (0 != WASABI_API_THREADPOOL->RunFunction(0, DeviceProvider_DiscoveryThreadStarter,
+ this, 0, api_threadpool::FLAG_LONG_EXECUTION))
+ {
+
+ SetEvent(readyEvent);
+ hr = E_FAIL;
+ }
+ }
+ }
+
+ Unlock();
+
+ return hr;
+}
+
+HRESULT DeviceProvider::CancelDiscovery()
+{
+ HRESULT hr;
+
+ hr = S_FALSE;
+
+ Lock();
+
+ if (NULL != readyEvent)
+ {
+ cancelDiscovery = TRUE;
+ if (WAIT_OBJECT_0 == WaitForSingleObject(readyEvent, 0))
+ hr = S_OK;
+
+ cancelDiscovery = FALSE;
+ }
+
+ Unlock();
+
+ return hr;
+}
+
+HRESULT DeviceProvider::GetActive()
+{
+ HRESULT hr;
+
+ Lock();
+
+ if (0 != activity)
+ hr = S_OK;
+ else
+ hr = S_FALSE;
+
+ Unlock();
+
+ return hr;
+}
+
+HRESULT DeviceProvider::Register(api_devicemanager *manager)
+{
+ HRESULT hr;
+
+ if (NULL != this->manager)
+ return E_UNEXPECTED;
+
+ if (NULL == manager)
+ return E_POINTER;
+
+ hr = manager->RegisterProvider(this);
+ if (SUCCEEDED(hr))
+ {
+ this->manager = manager;
+ manager->AddRef();
+ }
+ return hr;
+}
+
+HRESULT DeviceProvider::Unregister()
+{
+ HRESULT hr;
+
+ if (NULL == manager)
+ return E_UNEXPECTED;
+
+ hr = manager->UnregisterProvider(this);
+ manager->Release();
+ manager = NULL;
+ return hr;
+}
+
+size_t DeviceProvider::IncrementActivity()
+{
+ size_t a;
+
+ Lock();
+
+ activity++;
+ if (1 == activity &&
+ NULL != manager)
+ {
+ manager->SetProviderActive(this, TRUE);
+ }
+
+ a = activity;
+
+ Unlock();
+
+ return a;
+}
+
+size_t DeviceProvider::DecrementActivity()
+{
+ size_t a;
+
+ Lock();
+
+ if (0 != activity)
+ {
+ activity--;
+ if (0 == activity &&
+ NULL != manager)
+ {
+ manager->SetProviderActive(this, FALSE);
+ }
+ }
+
+ a = activity;
+
+ Unlock();
+
+ return a;
+}
+
+#define CBCLASS DeviceProvider
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_BEGINDISCOVERY, BeginDiscovery)
+CB(API_CANCELDISCOVERY, CancelDiscovery)
+CB(API_GETACTIVE, GetActive)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_ipod/deviceprovider.h b/Src/Plugins/Portable/pmp_ipod/deviceprovider.h
new file mode 100644
index 00000000..d2a6b3a6
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/deviceprovider.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <wtypes.h>
+#include "../devices/ifc_deviceprovider.h"
+#include "..\..\Library\ml_pmp/pmp.h"
+
+class DeviceProvider : public ifc_deviceprovider
+{
+protected:
+ DeviceProvider();
+ ~DeviceProvider();
+
+public:
+ static HRESULT CreateInstance(DeviceProvider **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_deviceprovider */
+ HRESULT BeginDiscovery(api_devicemanager *manager);
+ HRESULT CancelDiscovery();
+ HRESULT GetActive();
+
+public:
+ HRESULT Register(api_devicemanager *manager);
+ HRESULT Unregister();
+ size_t IncrementActivity();
+ size_t DecrementActivity();
+
+private:
+ void Lock();
+ void Unlock();
+ DWORD DiscoveryThread();
+ friend static int DeviceProvider_DiscoveryThreadStarter(HANDLE handle, void *user_data, intptr_t id);
+
+protected:
+ size_t ref;
+ size_t activity;
+ CRITICAL_SECTION lock;
+ api_devicemanager *manager;
+ ENUMDRIVES enumerator;
+ HANDLE readyEvent;
+ BOOL cancelDiscovery;
+
+protected:
+ RECVS_DISPATCH;
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_ipod/eject.cpp b/Src/Plugins/Portable/pmp_ipod/eject.cpp
new file mode 100644
index 00000000..0786f141
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/eject.cpp
@@ -0,0 +1,357 @@
+// this file almost totally copied from MSDN
+
+#include <windows.h>
+#include <stdio.h>
+#include <winioctl.h>
+
+#define LOCK_TIMEOUT 3000 // 10 Seconds
+#define LOCK_RETRIES 20
+
+#if 1 // old way
+static HANDLE OpenVolume(TCHAR cDriveLetter)
+{
+ HANDLE hVolume;
+ UINT uDriveType;
+ wchar_t szVolumeName[8] = {0};
+ wchar_t szRootName[5] = {0};
+ DWORD dwAccessFlags = 0;
+ cDriveLetter &= ~0x20; // capitalize
+ wsprintf(szRootName, L"%c:\\", cDriveLetter);
+
+ uDriveType = GetDriveType(szRootName);
+ switch(uDriveType) {
+ case DRIVE_REMOVABLE:
+ dwAccessFlags = GENERIC_READ | GENERIC_WRITE;
+ break;
+ case DRIVE_CDROM:
+ dwAccessFlags = GENERIC_READ;
+ break;
+ default:
+ printf("Cannot eject. Drive type is incorrect.\n");
+ return INVALID_HANDLE_VALUE;
+ }
+
+ wsprintf(szVolumeName, L"\\\\.\\%c:", cDriveLetter);
+
+ hVolume = CreateFile( szVolumeName,
+ dwAccessFlags,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL );
+
+ if (hVolume == INVALID_HANDLE_VALUE)
+ printf("CreateFile error %d\n", GetLastError());
+ return hVolume;
+}
+
+static BOOL CloseVolume(HANDLE hVolume)
+{
+ return CloseHandle(hVolume);
+}
+
+static BOOL LockVolume(HANDLE hVolume)
+{
+ DWORD dwBytesReturned;
+ DWORD dwSleepAmount;
+ int nTryCount;
+
+ dwSleepAmount = LOCK_TIMEOUT / LOCK_RETRIES;
+
+ // Do this in a loop until a timeout period has expired
+ for (nTryCount = 0; nTryCount < LOCK_RETRIES; nTryCount++) {
+ if (DeviceIoControl(hVolume,
+ FSCTL_LOCK_VOLUME,
+ NULL, 0,
+ NULL, 0,
+ &dwBytesReturned,
+ NULL))
+ return TRUE;
+
+ Sleep(dwSleepAmount);
+ }
+ return FALSE;
+}
+
+static BOOL DismountVolume(HANDLE hVolume)
+{
+ DWORD dwBytesReturned;
+
+ return DeviceIoControl( hVolume,
+ FSCTL_DISMOUNT_VOLUME,
+ NULL, 0,
+ NULL, 0,
+ &dwBytesReturned,
+ NULL);
+}
+
+static BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPreventRemoval)
+{
+ DWORD dwBytesReturned;
+ PREVENT_MEDIA_REMOVAL PMRBuffer;
+
+ PMRBuffer.PreventMediaRemoval = fPreventRemoval;
+
+ return DeviceIoControl( hVolume,
+ IOCTL_STORAGE_MEDIA_REMOVAL,
+ &PMRBuffer, sizeof(PREVENT_MEDIA_REMOVAL),
+ NULL, 0,
+ &dwBytesReturned,
+ NULL);
+}
+
+static int AutoEjectVolume(HANDLE hVolume)
+{
+ DWORD dwBytesReturned;
+
+ return DeviceIoControl( hVolume,
+ IOCTL_STORAGE_EJECT_MEDIA,
+ NULL, 0,
+ NULL, 0,
+ &dwBytesReturned,
+ NULL);
+}
+
+BOOL EjectVolume(TCHAR cDriveLetter)
+{
+ HANDLE hVolume;
+
+ BOOL fAutoEject = FALSE;
+
+ hVolume = OpenVolume(cDriveLetter);
+ if (hVolume == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ // Lock and dismount the volume.
+ if (LockVolume(hVolume) && DismountVolume(hVolume)) {
+ // Set prevent removal to false and eject the volume.
+ if (PreventRemovalOfVolume(hVolume, FALSE) && AutoEjectVolume(hVolume))
+ fAutoEject = TRUE;
+ }
+
+ // Close the volume so other processes can use the drive.
+ if (!CloseVolume(hVolume))
+ return FALSE;
+
+ if (fAutoEject) return TRUE;
+ else return FALSE;
+}
+#else
+#include <stdio.h>
+
+#include <windows.h>
+
+#include <Setupapi.h>
+#include <winioctl.h>
+#include <winioctl.h>
+#include <cfgmgr32.h>
+#pragma comment(lib, "setupapi.lib")
+//-------------------------------------------------
+//----------------------------------------------------------------------
+// returns the device instance handle of a storage volume or 0 on error
+//----------------------------------------------------------------------
+static DEVINST GetDrivesDevInstByDeviceNumber(long DeviceNumber, UINT DriveType, const wchar_t* szDosDeviceName)
+{
+ bool IsFloppy = (wcsstr(szDosDeviceName, L"\\Floppy") != NULL); // who knows a better way?
+
+ GUID* guid;
+
+ switch (DriveType) {
+ case DRIVE_REMOVABLE:
+ if ( IsFloppy ) {
+ guid = (GUID*)&GUID_DEVINTERFACE_FLOPPY;
+ } else {
+ guid = (GUID*)&GUID_DEVINTERFACE_DISK;
+ }
+ break;
+ case DRIVE_FIXED:
+ guid = (GUID*)&GUID_DEVINTERFACE_DISK;
+ break;
+ case DRIVE_CDROM:
+ guid = (GUID*)&GUID_DEVINTERFACE_CDROM;
+ break;
+ default:
+ return 0;
+ }
+
+ // Get device interface info set handle for all devices attached to system
+ HDEVINFO hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+
+ if (hDevInfo == INVALID_HANDLE_VALUE) {
+ return 0;
+ }
+
+ // Retrieve a context structure for a device interface of a device information set
+ DWORD dwIndex = 0;
+ long res;
+
+ BYTE Buf[1024] = {0};
+ PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
+ SP_DEVICE_INTERFACE_DATA spdid;
+ SP_DEVINFO_DATA spdd;
+ DWORD dwSize;
+
+ spdid.cbSize = sizeof(spdid);
+
+ while ( true ) {
+ res = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guid, dwIndex, &spdid);
+ if ( !res ) {
+ break;
+ }
+
+ dwSize = 0;
+ SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize, NULL); // check the buffer size
+
+ if ( dwSize!=0 && dwSize<=sizeof(Buf) ) {
+
+ pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!
+
+ ZeroMemory(&spdd, sizeof(spdd));
+ spdd.cbSize = sizeof(spdd);
+
+ long res = SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, pspdidd, dwSize, &dwSize, &spdd);
+ if ( res ) {
+
+ // in case you are interested in the USB serial number:
+ // the device id string contains the serial number if the device has one,
+ // otherwise a generated id that contains the '&' char...
+ /*
+ DEVINST DevInstParent = 0;
+ CM_Get_Parent(&DevInstParent, spdd.DevInst, 0);
+ char szDeviceIdString[MAX_PATH] = {0};
+ CM_Get_Device_ID(DevInstParent, szDeviceIdString, MAX_PATH, 0);
+ printf("DeviceId=%s\n", szDeviceIdString);
+ */
+
+ // open the disk or cdrom or floppy
+ HANDLE hDrive = CreateFile(pspdidd->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ if ( hDrive != INVALID_HANDLE_VALUE ) {
+ // get its device number
+ STORAGE_DEVICE_NUMBER sdn;
+ DWORD dwBytesReturned = 0;
+ res = DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);
+ if ( res ) {
+ if ( DeviceNumber == (long)sdn.DeviceNumber ) { // match the given device number with the one of the current device
+ CloseHandle(hDrive);
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+ return spdd.DevInst;
+ }
+ }
+ CloseHandle(hDrive);
+ }
+ }
+ }
+ dwIndex++;
+ }
+
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+
+ return 0;
+}
+//-------------------------------------------------
+
+
+
+//-------------------------------------------------
+BOOL EjectVolume(TCHAR DriveLetter)
+{
+ DriveLetter &= ~0x20; // uppercase
+
+ if ( DriveLetter < 'A' || DriveLetter > 'Z' ) {
+ return FALSE;
+ }
+
+ wchar_t szRootPath[] = L"X:\\"; // "X:\" -> for GetDriveType
+ szRootPath[0] = DriveLetter;
+
+ wchar_t szDevicePath[] = L"X:"; // "X:" -> for QueryDosDevice
+ szDevicePath[0] = DriveLetter;
+
+ wchar_t szVolumeAccessPath[] = L"\\\\.\\X:"; // "\\.\X:" -> to open the volume
+ szVolumeAccessPath[4] = DriveLetter;
+
+ long DeviceNumber = -1;
+
+ // open the storage volume
+ HANDLE hVolume = CreateFileW(szVolumeAccessPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
+ if (hVolume == INVALID_HANDLE_VALUE) {
+ return FALSE;
+ }
+
+ // get the volume's device number
+ STORAGE_DEVICE_NUMBER sdn;
+ DWORD dwBytesReturned = 0;
+ long res = DeviceIoControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);
+ if ( res ) {
+ DeviceNumber = sdn.DeviceNumber;
+ }
+ CloseHandle(hVolume);
+
+ if ( DeviceNumber == -1 ) {
+ return FALSE;
+ }
+
+ // get the drive type which is required to match the device numbers correctely
+ UINT DriveType = GetDriveType(szRootPath);
+
+ // get the dos device name (like \device\floppy0) to decide if it's a floppy or not - who knows a better way?
+ wchar_t szDosDeviceName[MAX_PATH] = {0};
+ res = QueryDosDevice(szDevicePath, szDosDeviceName, MAX_PATH);
+ if ( !res ) {
+ return FALSE;
+ }
+
+ // get the device instance handle of the storage volume by means of a SetupDi enum and matching the device number
+ DEVINST DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber, DriveType, szDosDeviceName);
+
+ if ( DevInst == 0 ) {
+ return FALSE;
+ }
+
+ PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown;
+ wchar_t VetoNameW[MAX_PATH] = {0};
+ bool bSuccess = false;
+
+ // get drives's parent, e.g. the USB bridge, the SATA port, an IDE channel with two drives!
+ DEVINST DevInstParent = 0;
+ res = CM_Get_Parent(&DevInstParent, DevInst, 0);
+
+ for ( long tries=1; tries<=3; tries++ ) { // sometimes we need some tries...
+
+ VetoNameW[0] = 0;
+
+ // CM_Query_And_Remove_SubTree doesn't work for restricted users
+ //res = CM_Query_And_Remove_SubTreeW(DevInstParent, &VetoType, VetoNameW, MAX_PATH, CM_REMOVE_NO_RESTART); // CM_Query_And_Remove_SubTreeA is not implemented under W2K!
+ //res = CM_Query_And_Remove_SubTreeW(DevInstParent, NULL, NULL, 0, CM_REMOVE_NO_RESTART); // with messagebox (W2K, Vista) or balloon (XP)
+
+ res = CM_Request_Device_EjectW(DevInstParent, &VetoType, VetoNameW, MAX_PATH, 0);
+ //res = CM_Request_Device_EjectW(DevInstParent, NULL, NULL, 0, 0); // with messagebox (W2K, Vista) or balloon (XP)
+
+ bSuccess = (res==CR_SUCCESS && VetoType==PNP_VetoTypeUnknown);
+ if ( bSuccess ) {
+ break;
+ }
+
+ Sleep(500); // required to give the next tries a chance!
+ }
+
+ if ( bSuccess ) {
+ printf("Success\n\n");
+ return TRUE;
+ }
+
+ printf("failed\n");
+
+ printf("Result=0x%2X\n", res);
+
+ if ( VetoNameW[0] ) {
+ printf("VetoName=%ws)\n\n", VetoNameW);
+ }
+ return FALSE;
+}
+//-----------------------------------------------------------
+
+
+
+#endif \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_ipod/filecopy.cpp b/Src/Plugins/Portable/pmp_ipod/filecopy.cpp
new file mode 100644
index 00000000..e229d795
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/filecopy.cpp
@@ -0,0 +1,69 @@
+#include "api.h"
+#include <windows.h>
+#include <stdio.h>
+#include <wchar.h>
+#include "resource.h"
+#include <strsafe.h>
+
+typedef struct CopyData
+{
+ void * callbackContext;
+ void (*callback)(void * callbackContext, wchar_t * status);
+} CopyData;
+
+DWORD CALLBACK CopyToIpodProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred,
+ LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred,
+ DWORD dwStreamNumber,
+ DWORD dwCallbackReason,
+ HANDLE hSourceFile, HANDLE hDestinationFile,
+ LPVOID lpData)
+{
+ CopyData *inst = (CopyData *)lpData;
+ if (inst && inst->callback)
+ {
+ wchar_t status[100] = {0};
+ wchar_t langtemp[100] = {0};
+ StringCbPrintf(status, sizeof(status), WASABI_API_LNGSTRINGW_BUF(IDS_TRANSFERRING_PERCENT, langtemp, 100), (int)(100ULL * TotalBytesTransferred.QuadPart / (TotalFileSize.QuadPart)));
+ inst->callback(inst->callbackContext,status);
+ }
+ return PROGRESS_CONTINUE;
+}
+
+int CopyFile(const wchar_t *infile, const wchar_t *outfile, void * callbackContext, void (*callback)(void * callbackContext, wchar_t * status), int * killswitch)
+{
+ wchar_t langtemp[100] = {0};
+
+ CopyData c;
+ c.callback = callback;
+ c.callbackContext = callbackContext;
+
+ if (CopyFileEx(infile, outfile, CopyToIpodProgressRoutine, &c, killswitch,0))
+ {
+ if (callback)
+ {
+ callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_DONE, langtemp, 100));
+ }
+ return 0;
+ }
+ else
+ {
+ switch(GetLastError())
+ {
+ case ERROR_REQUEST_ABORTED:
+ DeleteFile(outfile);
+ if (callback)
+ {
+ callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_CANCELLED, langtemp, 100));
+ }
+
+ default:
+ if (callback)
+ {
+ callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_TRANSFER_FAILED, langtemp, 100));
+ }
+
+ }
+ return -1;
+ }
+
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_ipod/hash58.cpp b/Src/Plugins/Portable/pmp_ipod/hash58.cpp
new file mode 100644
index 00000000..ca10af92
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/hash58.cpp
@@ -0,0 +1,154 @@
+#include "sha1.h"
+#include <memory.h>
+#include <algorithm>
+
+unsigned char invTable[256] = {
+ 0x74, 0x85, 0x96, 0xA7, 0xB8, 0xC9, 0xDA, 0xEB, 0xFC, 0x0D, 0x1E, 0x2F, 0x40, 0x51, 0x62, 0x73,
+ 0x84, 0x95, 0xA6, 0xB7, 0xC8, 0xD9, 0xEA, 0xFB, 0x0C, 0x1D, 0x2E, 0x3F, 0x50, 0x61, 0x72, 0x83,
+ 0x94, 0xA5, 0xB6, 0xC7, 0xD8, 0xE9, 0xFA, 0x0B, 0x1C, 0x2D, 0x3E, 0x4F, 0x60, 0x71, 0x82, 0x93,
+ 0xA4, 0xB5, 0xC6, 0xD7, 0xE8, 0xF9, 0x0A, 0x1B, 0x2C, 0x3D, 0x4E, 0x5F, 0x70, 0x81, 0x92, 0xA3,
+ 0xB4, 0xC5, 0xD6, 0xE7, 0xF8, 0x09, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E, 0x6F, 0x80, 0x91, 0xA2, 0xB3,
+ 0xC4, 0xD5, 0xE6, 0xF7, 0x08, 0x19, 0x2A, 0x3B, 0x4C, 0x5D, 0x6E, 0x7F, 0x90, 0xA1, 0xB2, 0xC3,
+ 0xD4, 0xE5, 0xF6, 0x07, 0x18, 0x29, 0x3A, 0x4B, 0x5C, 0x6D, 0x7E, 0x8F, 0xA0, 0xB1, 0xC2, 0xD3,
+ 0xE4, 0xF5, 0x06, 0x17, 0x28, 0x39, 0x4A, 0x5B, 0x6C, 0x7D, 0x8E, 0x9F, 0xB0, 0xC1, 0xD2, 0xE3,
+ 0xF4, 0x05, 0x16, 0x27, 0x38, 0x49, 0x5A, 0x6B, 0x7C, 0x8D, 0x9E, 0xAF, 0xC0, 0xD1, 0xE2, 0xF3,
+ 0x04, 0x15, 0x26, 0x37, 0x48, 0x59, 0x6A, 0x7B, 0x8C, 0x9D, 0xAE, 0xBF, 0xD0, 0xE1, 0xF2, 0x03,
+ 0x14, 0x25, 0x36, 0x47, 0x58, 0x69, 0x7A, 0x8B, 0x9C, 0xAD, 0xBE, 0xCF, 0xE0, 0xF1, 0x02, 0x13,
+ 0x24, 0x35, 0x46, 0x57, 0x68, 0x79, 0x8A, 0x9B, 0xAC, 0xBD, 0xCE, 0xDF, 0xF0, 0x01, 0x12, 0x23,
+ 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0x9A, 0xAB, 0xBC, 0xCD, 0xDE, 0xEF, 0x00, 0x11, 0x22, 0x33,
+ 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x10, 0x21, 0x32, 0x43,
+ 0x54, 0x65, 0x76, 0x87, 0x98, 0xA9, 0xBA, 0xCB, 0xDC, 0xED, 0xFE, 0x0F, 0x20, 0x31, 0x42, 0x53,
+ 0x64, 0x75, 0x86, 0x97, 0xA8, 0xB9, 0xCA, 0xDB, 0xEC, 0xFD, 0x0E, 0x1F, 0x30, 0x41, 0x52, 0x63
+};
+
+unsigned char table1[256] = {
+ 0x3A, 0x3F, 0x3E, 0x72, 0xBD, 0xA2, 0xD6, 0xB4, 0x63, 0xC0, 0x6E, 0x62, 0x59, 0x1E, 0xE2, 0x71,
+ 0xB5, 0x0D, 0xE8, 0x0C, 0x25, 0x38, 0xCE, 0x23, 0x7C, 0xB7, 0xAD, 0x16, 0xDF, 0x47, 0x3D, 0xB3,
+ 0x7E, 0x8C, 0xAA, 0x61, 0x31, 0x66, 0xBE, 0x4F, 0x97, 0x14, 0x54, 0xF0, 0x70, 0xEB, 0x30, 0xC4,
+ 0x27, 0x4E, 0xFA, 0x1A, 0x2B, 0x11, 0xF4, 0x45, 0x8E, 0x5D, 0x73, 0xED, 0x22, 0x2E, 0x7D, 0xA4,
+ 0x28, 0xDA, 0x2F, 0xC5, 0x92, 0x09, 0x05, 0x13, 0x9D, 0x32, 0x51, 0x4A, 0xC8, 0xBA, 0x96, 0xA7,
+ 0x6A, 0x50, 0xF3, 0xBC, 0x93, 0xBF, 0xB0, 0xD2, 0xD5, 0x82, 0x19, 0x98, 0x35, 0xCF, 0x6B, 0xB6,
+ 0x83, 0x56, 0x15, 0xF2, 0x9A, 0x9C, 0xCA, 0x74, 0x34, 0x58, 0x8D, 0xA6, 0x03, 0xFF, 0x46, 0x7B,
+ 0xD0, 0x7A, 0x33, 0x76, 0xDD, 0xAC, 0xCB, 0x24, 0x7F, 0xB1, 0x85, 0x60, 0xC3, 0x26, 0x8A, 0x1D,
+ 0x1C, 0x8F, 0x2A, 0xEF, 0x06, 0xDE, 0x67, 0x5E, 0xE7, 0xAE, 0xD9, 0xCC, 0x07, 0x6C, 0xF8, 0x0A,
+ 0xD3, 0x40, 0x36, 0x1F, 0x2D, 0x95, 0x43, 0xDB, 0x01, 0x89, 0x4B, 0xF7, 0xB9, 0x39, 0xC2, 0x52,
+ 0x53, 0xFD, 0x65, 0xF5, 0x68, 0xC1, 0xC7, 0x9F, 0x4D, 0xEA, 0xAF, 0x6D, 0x10, 0x44, 0x87, 0xD8,
+ 0xEE, 0x1B, 0xFE, 0x3C, 0xDC, 0x84, 0x69, 0x48, 0x6F, 0xD1, 0x57, 0x55, 0xD4, 0xA5, 0x49, 0x5B,
+ 0xE5, 0x0B, 0x94, 0xC9, 0x5F, 0xE1, 0x17, 0x81, 0xBB, 0xEC, 0xD7, 0xC6, 0x02, 0x4C, 0x42, 0x75,
+ 0xA3, 0x99, 0xE4, 0xA1, 0x9B, 0x5A, 0xF1, 0x29, 0xA0, 0x64, 0x9E, 0x18, 0x41, 0x80, 0x2C, 0x79,
+ 0x20, 0x8B, 0xAB, 0x90, 0x08, 0xB8, 0xA9, 0x77, 0x12, 0xF9, 0x0E, 0x88, 0xE9, 0x04, 0xFB, 0x86,
+ 0x0F, 0xE0, 0xA8, 0x5C, 0xE6, 0x21, 0xCD, 0x3B, 0x00, 0x78, 0xFC, 0xF6, 0xE3, 0x37, 0xB2, 0x91
+};
+
+unsigned char table2[256] = {
+ 0xF3, 0xE4, 0x1B, 0x38, 0xE5, 0x6F, 0xE8, 0x9D, 0x3E, 0x55, 0xBA, 0xC7, 0xAC, 0xEA, 0x66, 0xA2,
+ 0xB9, 0x7A, 0x34, 0x43, 0x02, 0x4E, 0xFE, 0x36, 0x41, 0x57, 0x1A, 0xB1, 0x31, 0x87, 0x04, 0x52,
+ 0x21, 0x22, 0xE1, 0x13, 0x7F, 0x03, 0x3A, 0x90, 0xF7, 0x69, 0x78, 0x12, 0x83, 0x0B, 0x9A, 0x97,
+ 0x4D, 0xB7, 0x8C, 0xBF, 0x2D, 0x94, 0xD1, 0x93, 0x2F, 0x42, 0x23, 0xA4, 0xE0, 0x92, 0xDC, 0x68,
+ 0xD3, 0xDD, 0xAF, 0x91, 0x9F, 0xED, 0x3D, 0x8F, 0xA1, 0x51, 0xD9, 0xE9, 0x70, 0x28, 0xEF, 0xB3,
+ 0x49, 0xA5, 0x0D, 0xC5, 0xD0, 0x60, 0xB4, 0x2B, 0x07, 0xF8, 0xDF, 0xE6, 0x16, 0xC0, 0x30, 0x71,
+ 0x85, 0xFD, 0x72, 0x95, 0x29, 0x79, 0x0A, 0x7B, 0x46, 0x11, 0x7D, 0x88, 0x1D, 0x2A, 0x48, 0x1F,
+ 0x45, 0x89, 0x47, 0xEE, 0xBB, 0xBE, 0x6E, 0xC3, 0x6C, 0xCE, 0x10, 0x5A, 0x2C, 0xCA, 0xFB, 0xB2,
+ 0xCB, 0x1C, 0x9C, 0xEC, 0x2E, 0x56, 0x59, 0x9B, 0xA6, 0x53, 0xAE, 0x17, 0x25, 0xC1, 0x3F, 0x6A,
+ 0x0F, 0x09, 0x01, 0xA3, 0xD6, 0xA0, 0xD8, 0x08, 0xE3, 0x74, 0x06, 0x6D, 0x19, 0x98, 0x1E, 0x77,
+ 0x76, 0xBC, 0xEB, 0x3C, 0xB0, 0xC4, 0xC8, 0x64, 0x0E, 0x86, 0x63, 0xD7, 0xDB, 0xBD, 0xA7, 0x82,
+ 0x39, 0x4F, 0x27, 0xD2, 0x5F, 0x73, 0xF4, 0x75, 0x6B, 0xC2, 0xD5, 0x67, 0x5D, 0x80, 0xAB, 0x81,
+ 0xDE, 0xF0, 0xAD, 0xAA, 0xCD, 0xB6, 0xF6, 0x7C, 0xFC, 0x33, 0x05, 0x14, 0x96, 0x15, 0xC9, 0x9E,
+ 0x35, 0x5C, 0x7E, 0x44, 0x54, 0x58, 0x3B, 0x40, 0x20, 0xA8, 0x8B, 0x5E, 0x4A, 0x24, 0x99, 0x8E,
+ 0xF5, 0xB5, 0x62, 0x00, 0x37, 0x5B, 0x18, 0x65, 0x8D, 0x32, 0xE2, 0xF9, 0xDA, 0x8A, 0xD4, 0xCC,
+ 0x26, 0xF2, 0xF1, 0xE7, 0x4B, 0xC6, 0xCF, 0xFF, 0x4C, 0x84, 0x61, 0xFA, 0xB8, 0x0C, 0xA9, 0x50
+};
+
+unsigned char fixed[18] = {
+ 0x67, 0x23, 0xFE, 0x30, 0x45, 0x33, 0xF8, 0x90, 0x99, 0x21, 0x07, 0xC1, 0xD0, 0x12, 0xB2, 0xA1, 0x07, 0x81
+};
+
+int GCD(int a, int b){
+ while( 1 )
+ {
+ a = a % b;
+ if( a == 0 )
+ return b;
+ b = b % a;
+ if( b == 0 )
+ return a;
+ }
+}
+
+int LCM(int a, int b)
+{
+ if(a==0 || b==0)
+ return 1;
+
+ return (a*b)/GCD(a,b);
+}
+
+
+//pFWID -> 8 bytes
+//pKey -> 64 byte buffer
+void GenerateKey(unsigned char *pFWID, unsigned char *pKey){
+ memset(pKey,0, 64);
+
+ int i;
+ unsigned char y[16] = {0};
+ //take LCM of each two bytes in the FWID in turn
+ for(i=0;i<4;i++){
+ int a=pFWID[i*2];
+ int b=pFWID[i*2+1];
+ int lcm = LCM(a,b);
+
+ unsigned char hi = (lcm & 0xFF00) >> 8;
+ unsigned char lo = lcm & 0xFF;
+
+ y[i*4] = ((table1[hi] * 0xB5) - 3);
+ y[i*4 + 1] = ((table2[hi] * 0xB7) + 0x49);
+ y[i*4 + 2] = ((table1[lo] * 0xB5) - 3);
+ y[i*4 + 3] = ((table2[lo] * 0xB7) + 0x49);
+ }
+
+ //convert y
+ for(i=0;i<16;i++){
+ y[i] = invTable[y[i]];
+ }
+
+ //hash
+ SHA1_CTX context;
+ SHA1Init(&context);
+ SHA1Update(&context, fixed, 18);
+ SHA1Update(&context, y, 16);
+ SHA1Final(pKey, &context);
+}
+
+//pDataBase -> iTunesDB
+//pFWID -> 8 bytes
+//pHash -> 20 byte buffer
+void GenerateHash(unsigned char *pFWID, unsigned char *pDataBase0, long lSize, unsigned char *pHash)
+{
+ unsigned char *pDataBase = (unsigned char*)malloc(lSize);
+ memcpy(pDataBase,pDataBase0,lSize);
+ //generate invtable
+ unsigned char key[64] = {0};
+ GenerateKey(pFWID, key);
+
+ //hmac sha1
+ int i;
+ for (i=0; i < 64; i++)
+ key[i] ^= 0x36;
+
+ SHA1_CTX context;
+
+ SHA1Init(&context);
+ SHA1Update(&context, key, 64);
+ SHA1Update(&context, pDataBase, lSize);
+ SHA1Final(pHash, &context);
+
+ for (i=0; i < 64; i++)
+ key[i] ^= 0x36 ^ 0x5c;
+
+ SHA1Init(&context);
+ SHA1Update(&context, key, 64);
+ SHA1Update(&context, pHash, 20);
+ SHA1Final(pHash, &context);
+
+ free(pDataBase);
+}
diff --git a/Src/Plugins/Portable/pmp_ipod/hash58.h b/Src/Plugins/Portable/pmp_ipod/hash58.h
new file mode 100644
index 00000000..ec9153bb
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/hash58.h
@@ -0,0 +1 @@
+void GenerateHash(unsigned char *pFWID, unsigned char *pDataBase, long lSize, unsigned char *pHash);
diff --git a/Src/Plugins/Portable/pmp_ipod/iPodArtworkDB.cpp b/Src/Plugins/Portable/pmp_ipod/iPodArtworkDB.cpp
new file mode 100644
index 00000000..a3eca956
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/iPodArtworkDB.cpp
@@ -0,0 +1,914 @@
+/*
+ *
+ *
+ * Copyright (c) 2007 Will Fisher (will.fisher@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ *
+ */
+
+#include "iPodArtworkDB.h"
+#include <algorithm>
+#include <strsafe.h>
+
+//utilities
+#define SAFEDELETE(x) {if(x) delete (x); (x)=0;}
+#define SAFEFREE(x) {if(x) free(x); (x)=0;}
+
+static __forceinline unsigned short rev1(const BYTE *data)
+{
+ return ((unsigned short) data[0]);
+}
+
+static __forceinline unsigned short rev1i(const BYTE *data, int &ptr)
+{
+ unsigned short ret = rev1(data+ptr);
+ ptr+=1;
+ return ret;
+}
+
+static __forceinline unsigned short rev2(const BYTE *data)
+{
+ unsigned short ret;
+ ret = ((unsigned short) data[1]) << 8;
+ ret += ((unsigned short) data[0]);
+ return ret;
+}
+
+static __forceinline unsigned short rev2i(const BYTE *data, int &ptr)
+{
+ unsigned short ret = rev2(data+ptr);
+ ptr+=2;
+ return ret;
+}
+
+// get 4 bytes from data, reversed
+static __forceinline unsigned int rev4(const BYTE * data)
+{
+ unsigned int ret;
+ ret = ((unsigned long) data[3]) << 24;
+ ret += ((unsigned long) data[2]) << 16;
+ ret += ((unsigned long) data[1]) << 8;
+ ret += ((unsigned long) data[0]);
+ return ret;
+}
+
+static __forceinline unsigned int rev4i(const BYTE * data, int &ptr)
+{
+ unsigned int ret = rev4(data+ptr);
+ ptr+=4;
+ return ret;
+}
+
+// get 4 bytes from data
+static __forceinline unsigned long get4(const unsigned char * data)
+{
+ unsigned long ret;
+ ret = ((unsigned long) data[0]) << 24;
+ ret += ((unsigned long) data[1]) << 16;
+ ret += ((unsigned long) data[2]) << 8;
+ ret += ((unsigned long) data[3]);
+ return ret;
+}
+
+static __forceinline unsigned long get4i(const unsigned char * data, int &ptr)
+{
+ unsigned long ret = get4(data+ptr);
+ ptr+=4;
+ return ret;
+}
+
+// get 8 bytes from data
+static __forceinline unsigned __int64 get8(const unsigned char * data)
+{
+ unsigned __int64 ret;
+ ret = get4(data);
+ ret = ret << 32;
+ ret+= get4(data+4);
+ return ret;
+}
+
+// get 8 bytes from data
+static __forceinline unsigned __int64 get8i(const unsigned char * data, int &ptr)
+{
+ unsigned __int64 ret = get8(data+ptr);
+ ptr+=8;
+ return ret;
+}
+
+// reverse 8 bytes in place
+static __forceinline unsigned __int64 rev8(unsigned __int64 number)
+{
+ unsigned __int64 ret;
+ ret = (number&0x00000000000000FF) << 56;
+ ret+= (number&0x000000000000FF00) << 40;
+ ret+= (number&0x0000000000FF0000) << 24;
+ ret+= (number&0x00000000FF000000) << 8;
+ ret+= (number&0x000000FF00000000) >> 8;
+ ret+= (number&0x0000FF0000000000) >> 24;
+ ret+= (number&0x00FF000000000000) >> 40;
+ ret+= (number&0xFF00000000000000) >> 56;
+ return ret;
+}
+
+static __forceinline void putmh(const char* x, BYTE *data, int &ptr) {
+ data[0+ptr]=x[0];
+ data[1+ptr]=x[1];
+ data[2+ptr]=x[2];
+ data[3+ptr]=x[3];
+ ptr+=4;
+}
+
+
+//write 4 bytes reversed
+static __forceinline void rev4(const unsigned long number, unsigned char * data)
+{
+ data[3] = (unsigned char)(number >> 24) & 0xff;
+ data[2] = (unsigned char)(number >> 16) & 0xff;
+ data[1] = (unsigned char)(number >> 8) & 0xff;
+ data[0] = (unsigned char)number & 0xff;
+}
+
+static __forceinline void rev4i(const unsigned int number, BYTE* data, int &ptr)
+{
+ rev4(number,data+ptr);
+ ptr+=4;
+}
+
+static __forceinline void rev2(const unsigned short number, unsigned char * data)
+{
+ data[1] = (unsigned char)(number >> 8) & 0xff;
+ data[0] = (unsigned char)number & 0xff;
+}
+
+static __forceinline void rev2i(const unsigned short number, BYTE* data, int &ptr)
+{
+ rev2(number,data+ptr);
+ ptr+=2;
+}
+
+static __forceinline void rev1(const unsigned char number, unsigned char * data)
+{
+ data[0] = number;
+}
+
+static __forceinline void rev1i(const unsigned char number, BYTE* data, int &ptr)
+{
+ rev1(number,data+ptr);
+ ptr+=1;
+}
+
+// write 8 bytes normal
+static __forceinline void put8(unsigned __int64 number, unsigned char * data)
+{
+ data[0] = (unsigned char)(number >> 56) & 0xff;
+ data[1] = (unsigned char)(number >> 48) & 0xff;
+ data[2] = (unsigned char)(number >> 40) & 0xff;
+ data[3] = (unsigned char)(number >> 32) & 0xff;
+ data[4] = (unsigned char)(number >> 24) & 0xff;
+ data[5] = (unsigned char)(number >> 16) & 0xff;
+ data[6] = (unsigned char)(number >> 8) & 0xff;
+ data[7] = (unsigned char)number & 0xff;
+}
+
+static __forceinline void put8i(unsigned __int64 number, unsigned char * data, int &ptr) {
+ put8(number,data+ptr);
+ ptr+=8;
+}
+
+static __forceinline void pad(BYTE * data, int endpoint, int& startpoint) {
+ if(endpoint == startpoint) return;
+ ZeroMemory(data+startpoint, endpoint - startpoint);
+ startpoint = endpoint;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ArtDB
+
+ArtDB::ArtDB() :
+ headerlen(0x84),
+ totallen(0),
+ unk1(0),
+ unk2(2),
+ unk3(0),
+ nextid(0x40),
+ unk5(0),
+ unk6(0),
+ unk7(0),
+ unk8(0),
+ unk9(0),
+ unk10(0),
+ unk11(0),
+ imageListDS(0),
+ albumListDS(0),
+ fileListDS(0)
+{
+}
+
+ArtDB::~ArtDB() {
+ SAFEDELETE(imageListDS);
+ SAFEDELETE(albumListDS);
+ SAFEDELETE(fileListDS);
+}
+
+int ArtDB::parse(BYTE * data, int len, wchar_t drive) {
+ int ptr=4;
+ if(len < headerlen) return -1;
+ if (_strnicmp((char *)data,"mhfd",4)) return -1;
+ headerlen = rev4i(data,ptr);
+ if(headerlen < 0x84) return -1;
+ totallen = rev4i(data,ptr);
+ unk1 = rev4i(data,ptr);
+ unk2 = rev4i(data,ptr);
+ int numchildren = rev4i(data,ptr);
+ unk3 = rev4i(data,ptr);
+ nextid = rev4i(data,ptr);
+ unk5 = rev8(get8i(data,ptr));
+ unk6 = rev8(get8i(data,ptr));
+ unk7 = rev4i(data,ptr);
+ unk8 = rev4i(data,ptr);
+ unk9 = rev4i(data,ptr);
+ unk10 = rev4i(data,ptr);
+ unk11 = rev4i(data,ptr);
+
+ ptr=headerlen;
+
+ for(int i=0; i<numchildren; i++) {
+ ArtDataSet * d = new ArtDataSet;
+ int p = d->parse(data+ptr,len-ptr);
+ if(p == -1) return -1;
+ switch(d->index) {
+ case 1: imageListDS = d; break;
+ case 2: albumListDS = d; break;
+ case 3: fileListDS = d; break;
+ default: delete d;
+ }
+ ptr+=p;
+ }
+ if(!imageListDS) imageListDS = new ArtDataSet(1);
+ if(!albumListDS) albumListDS = new ArtDataSet(2);
+ if(!fileListDS) fileListDS = new ArtDataSet(3);
+
+ for(ArtImageList::ArtImageMapIterator i = imageListDS->imageList->images.begin(); i!=imageListDS->imageList->images.end(); i++) {
+ if(i->second) {
+ for(auto j = i->second->dataobjs.begin(); j != i->second->dataobjs.end(); j++) {
+ if((*j)->image) {
+ ArtFile *f = fileListDS->fileList->getFile((*j)->image->corrid);
+ if(!f) {
+ f = new ArtFile();
+ f->corrid = (*j)->image->corrid;
+ fileListDS->fileList->files.push_back(f);
+ }
+ f->images.push_back(new ArtFileImage((*j)->image->ithmboffset,(*j)->image->imagesize,1));
+ }
+ }
+ }
+ }
+
+ for(auto i = fileListDS->fileList->files.begin(); i!=fileListDS->fileList->files.end(); i++) {
+ wchar_t file[MAX_PATH] = {0};
+ StringCchPrintfW(file, MAX_PATH, L"%c:\\iPod_Control\\Artwork\\F%04d_1.ithmb",drive,(*i)->corrid);
+ (*i)->file = _wcsdup(file);
+ (*i)->sortImages();
+ }
+
+ return totallen;
+}
+
+int ArtDB::write(BYTE *data, int len) {
+ int ptr=0;
+ if(headerlen > len) return -1;
+ putmh("mhfd",data,ptr);
+ rev4i(headerlen,data,ptr);
+ rev4i(0,data,ptr); // fill total len here later
+ rev4i(unk1,data,ptr);
+ rev4i(unk2,data,ptr); // always seems to be "2" when iTunes writes it
+ rev4i(3,data,ptr); // num children
+ rev4i(unk3,data,ptr);
+ rev4i(nextid,data,ptr);
+ put8i(rev8(unk5),data,ptr);
+ put8i(rev8(unk6),data,ptr);
+ rev4i(unk7,data,ptr);
+ rev4i(unk8,data,ptr);
+ rev4i(unk9,data,ptr);
+ rev4i(unk10,data,ptr);
+ rev4i(unk11,data,ptr);
+
+ pad(data,headerlen,ptr);
+
+ // write out children
+ int p;
+ p = imageListDS->write(data+ptr,len-ptr);
+ if(p<0) return -1;
+ ptr+=p;
+
+ p = albumListDS->write(data+ptr,len-ptr);
+ if(p<0) return -1;
+ ptr+=p;
+
+ p = fileListDS->write(data+ptr,len-ptr);
+ if(p<0) return -1;
+ ptr+=p;
+
+ rev4(ptr,&data[8]); // fill in total length
+
+ return ptr;
+}
+
+void ArtDB::makeEmptyDB(wchar_t drive) {
+ imageListDS = new ArtDataSet(1);
+ albumListDS = new ArtDataSet(2);
+ fileListDS = new ArtDataSet(3);
+
+ for(auto i = fileListDS->fileList->files.begin(); i!=fileListDS->fileList->files.end(); i++) {
+ wchar_t file[MAX_PATH] = {0};
+ StringCchPrintfW(file, MAX_PATH, L"%c:\\iPod_Control\\Artwork\\F%04d_1.ithmb",drive,(*i)->corrid);
+ (*i)->file = _wcsdup(file);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ArtDatSet
+
+ArtDataSet::ArtDataSet() :
+ headerlen(0x60),
+ totallen(0),
+ index(0),
+ imageList(0),
+ albumList(0),
+ fileList(0)
+{
+}
+
+ArtDataSet::ArtDataSet(int idx) :
+ headerlen(0x60),
+ totallen(0),
+ index(idx),
+ imageList(0),
+ albumList(0),
+ fileList(0)
+{
+ switch(idx) {
+ case 1: imageList = new ArtImageList; break;
+ case 2: albumList = new ArtAlbumList; break;
+ case 3: fileList = new ArtFileList; break;
+ default: index=0;
+ }
+}
+
+ArtDataSet::~ArtDataSet() {
+ SAFEDELETE(imageList);
+ SAFEDELETE(albumList);
+ SAFEDELETE(fileList);
+}
+
+int ArtDataSet::parse(BYTE *data, int len) {
+ int ptr=4;
+ if(len < headerlen) return -1;
+ if (_strnicmp((char *)data,"mhsd",4)) return -1;
+ headerlen = rev4i(data,ptr);
+ if(headerlen < 0x60) return -1;
+ totallen = rev4i(data,ptr);
+ index = rev4i(data,ptr);
+
+ ptr=headerlen;
+
+ int p=0;
+ switch(index) {
+ case 1: imageList = new ArtImageList; p = imageList->parse(data+ptr, len-ptr); break;
+ case 2: albumList = new ArtAlbumList; p = albumList->parse(data+ptr, len-ptr); break;
+ case 3: fileList = new ArtFileList; p = fileList->parse(data+ptr, len-ptr); break;
+ }
+
+ if(p < 0) return -1;
+ return totallen;
+}
+
+int ArtDataSet::write(BYTE *data, int len) {
+ int ptr=0;
+ if(headerlen > len) return -1;
+ putmh("mhsd",data,ptr);
+ rev4i(headerlen,data,ptr);
+ rev4i(0,data,ptr); // fill total len here later
+ rev4i(index,data,ptr);
+ pad(data,headerlen,ptr);
+ int p=0;
+ switch(index) {
+ case 1: p=imageList->write(data+ptr, len-ptr); break;
+ case 2: p=albumList->write(data+ptr, len-ptr); break;
+ case 3: p=fileList->write(data+ptr, len-ptr); break;
+ }
+ if(p<0) return -1;
+ ptr+=p;
+
+ rev4(ptr,&data[8]); // fill in total length
+ return ptr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ArtImageList
+ArtImageList::ArtImageList() :
+ headerlen(0x5c)
+{
+}
+
+ArtImageList::~ArtImageList() {
+ for(ArtImageMapIterator f = images.begin(); f != images.end(); f++)
+ delete f->second;
+ images.clear();
+}
+
+int ArtImageList::parse(BYTE *data, int len) {
+ int ptr=4;
+ if(len < headerlen) return -1;
+ if (_strnicmp((char *)data,"mhli",4)) return -1;
+ headerlen = rev4i(data,ptr);
+ if(headerlen < 0x5c) return -1;
+ int children = rev4i(data,ptr);
+
+ ptr=headerlen;
+
+ for(int i=0; i<children; i++) {
+ ArtImage * f = new ArtImage;
+ int p = f->parse(data+ptr,len-ptr);
+ if(p<0) {delete f; return -1;}
+ ptr+=p;
+ images.insert(ArtImageMapPair(f->songid,f));
+ }
+ return ptr;
+}
+
+int ArtImageList::write(BYTE *data, int len) {
+ int ptr=0;
+ if(headerlen > len) return -1;
+ putmh("mhli",data,ptr);
+ rev4i(headerlen,data,ptr);
+ rev4i(images.size(),data,ptr);
+ pad(data,headerlen,ptr);
+
+ for(ArtImageMapIterator f = images.begin(); f != images.end(); f++) {
+ int p = f->second->write(data+ptr,len-ptr);
+ if(p<0) return -1;
+ ptr+=p;
+ }
+ return ptr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ArtImage
+ArtImage::ArtImage() :
+ headerlen(0x98),
+ totallen(0),
+ id(0),
+ songid(0),
+ unk4(0),
+ rating(0),
+ unk6(0),
+ originalDate(0),
+ digitizedDate(0),
+ srcImageSize(0)
+{
+}
+
+ArtImage::~ArtImage()
+{
+ for (auto obj : dataobjs)
+ {
+ delete obj;
+ }
+ dataobjs.clear();
+}
+
+int ArtImage::parse(BYTE *data, int len) {
+ int ptr=4;
+ if(len < headerlen) return -1;
+ if (_strnicmp((char *)data,"mhii",4)) return -1;
+ headerlen = rev4i(data,ptr);
+ if(headerlen < 0x98) return -1;
+ totallen = rev4i(data,ptr);
+ int numchildren = rev4i(data,ptr);
+ id = rev4i(data,ptr);
+ songid = rev8(get8i(data,ptr));
+ unk4 = rev4i(data,ptr);
+ rating = rev4i(data,ptr);
+ unk6 = rev4i(data,ptr);
+ originalDate = rev4i(data,ptr);
+ digitizedDate = rev4i(data,ptr);
+ srcImageSize = rev4i(data,ptr);
+
+ ptr = headerlen;
+ for(int i=0; i<numchildren; i++) {
+ ArtDataObject *d = new ArtDataObject;
+ int p = d->parse(data+ptr,len-ptr);
+ if(p<0) { delete d; return -1; }
+ ptr+=p;
+ // fuck with d. ugh.
+ if((d->type == 2 || d->type == 5) && d->data) { // this is a container mhod
+ d->image = new ArtImageName;
+ int p2 = d->image->parse(d->data,d->datalen);
+ if(p2>0) {
+ SAFEFREE(d->data);
+ d->datalen=0;
+ } else SAFEDELETE(d->image);
+ }
+ dataobjs.push_back(d);
+ }
+ return totallen;
+}
+
+template<class T>
+BYTE *expandMemWrite(T * x, int &len, int maxsize=1024000) {
+ int s = 1024;
+ for(;;) {
+ BYTE *r = (BYTE*)malloc(s);
+ int p = x->write(r,s);
+ if(p>0) {
+ len=p;
+ return r;
+ }
+ free(r);
+ s = s+s;
+ if(s > maxsize) break;
+ }
+ return NULL;
+}
+
+int ArtImage::write(BYTE *data, int len) {
+ int ptr=0;
+ if(headerlen > len) return -1;
+ putmh("mhii",data,ptr);
+ rev4i(headerlen,data,ptr);
+ rev4i(0,data,ptr); // fill in total length later
+ rev4i(dataobjs.size(),data,ptr);
+ rev4i(id,data,ptr);
+ put8i(rev8(songid),data,ptr);
+ rev4i(unk4,data,ptr);
+ rev4i(rating,data,ptr);
+ rev4i(unk6,data,ptr);
+ rev4i(originalDate,data,ptr);
+ rev4i(digitizedDate,data,ptr);
+ rev4i(srcImageSize,data,ptr);
+ pad(data,headerlen,ptr);
+
+ for(auto f = dataobjs.begin(); f != dataobjs.end(); f++) {
+ if((*f)->image) {
+ int len=0;
+ BYTE *b = expandMemWrite((*f)->image,len);
+ if(!b) return -1;
+ (*f)->data = b;
+ (*f)->datalen = len;
+ }
+ int p = (*f)->write(data+ptr,len-ptr);
+ if((*f)->image) {
+ SAFEFREE((*f)->data);
+ (*f)->datalen=0;
+ }
+ if(p<0) return -1;
+ ptr+=p;
+ }
+ rev4(ptr,&data[8]); // fill in total length
+ return ptr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ArtDataObj
+
+ArtDataObject::ArtDataObject() :
+ headerlen(0x18),
+ type(0),
+ data(0),
+ datalen(0),
+ image(0),
+ unk1(0)
+{
+}
+
+ArtDataObject::~ArtDataObject() {
+ SAFEDELETE(image);
+ SAFEFREE(data);
+}
+
+int ArtDataObject::parse(BYTE *data, int len) {
+ int ptr=4;
+ if(len < headerlen) return -1;
+ if (_strnicmp((char *)data,"mhod",4)) return -1;
+ headerlen = rev4i(data,ptr);
+ if(headerlen < 0x18) return -1;
+ int totallen = rev4i(data,ptr);
+ if(len < totallen) return -1;
+ type = rev2i(data,ptr);
+ unk1 = (unsigned char)rev1i(data,ptr);
+ short padding = rev1i(data,ptr);
+ ptr = headerlen;
+ if(type == 3 && rev2(&data[totallen-2]) == 0)
+ datalen = wcslen((wchar_t*)(data+ptr+12))*sizeof(wchar_t) + 12;
+ else
+ datalen = totallen - headerlen - padding;
+ if(datalen > 0x400 || datalen < 0) return -1;
+ this->data = (BYTE*)malloc(datalen);
+ memcpy(this->data,data+ptr,datalen);
+
+ return totallen;
+}
+
+int ArtDataObject::write(BYTE *data, int len) {
+ int ptr=0;
+ if(headerlen > len) return -1;
+ putmh("mhod",data,ptr);
+ rev4i(headerlen,data,ptr);
+ short padding = (4 - ((headerlen + datalen) % 4));// % 4;
+ if(padding == 4) padding = 0;
+ rev4i(headerlen+datalen+padding,data,ptr);
+ rev2i(type,data,ptr);
+ rev1i(unk1,data,ptr);
+ rev1i((unsigned char)padding,data,ptr);
+ pad(data,headerlen,ptr);
+ //write data
+ memcpy(data+ptr,this->data,datalen);
+ ptr+=datalen;
+ //add padding...
+ pad(data,ptr+padding,ptr);
+ return ptr;
+}
+
+void ArtDataObject::GetString(wchar_t * str, int len) {
+ if(rev4(data+4) != 2) { str[0]=0; return; }//not utf-16!
+ int l = (rev4(data)/sizeof(wchar_t));
+ StringCchCopyN(str, len, (wchar_t*)&data[12], l);
+ //lstrcpyn(str,(wchar_t*)&data[12],min(l,len));
+}
+
+void ArtDataObject::SetString(wchar_t * str) {
+ SAFEFREE(data);
+ datalen = wcslen(str)*sizeof(wchar_t) + 12;
+ data = (BYTE*)malloc(datalen);
+ rev4(wcslen(str)*sizeof(wchar_t),data);
+ rev4(2,data+4); //type 2 means utf-16
+ rev4(0,data+8); //unk
+ memcpy(data+12,str,wcslen(str)*sizeof(wchar_t));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ArtImageName
+ArtImageName::ArtImageName() :
+ headerlen(0x4c),
+ totallen(0),
+ corrid(0),
+ ithmboffset(0),
+ imagesize(0),
+ vpad(0),
+ hpad(0),
+ imgh(0),
+ imgw(0),
+ filename(0)
+{
+}
+
+ArtImageName::~ArtImageName() {
+ SAFEDELETE(filename);
+}
+
+int ArtImageName::parse(BYTE *data, int len) {
+ int ptr=4;
+ if(len < headerlen) return -1;
+ if (_strnicmp((char *)data,"mhni",4)) return -1;
+ headerlen = rev4i(data,ptr);
+ if(headerlen < 0x4c) return -1;
+ totallen = rev4i(data,ptr);
+ int children = rev4i(data,ptr);
+ corrid = rev4i(data,ptr);
+ ithmboffset = rev4i(data,ptr);
+ imagesize = rev4i(data,ptr);
+ vpad = (short)rev2i(data,ptr);
+ hpad = (short)rev2i(data,ptr);
+ imgw = rev2i(data,ptr);
+ imgh = rev2i(data,ptr);
+
+ ptr = headerlen;
+
+ if(children) {
+ filename = new ArtDataObject();
+ int p = filename->parse(data+ptr,len-ptr);
+ if(p<0) SAFEDELETE(filename);
+ }
+ return totallen;
+}
+
+int ArtImageName::write(BYTE *data, int len) {
+ int ptr=0;
+ if(headerlen > len) return -1;
+ putmh("mhni",data,ptr);
+ rev4i(headerlen,data,ptr);
+ rev4i(0,data,ptr); // fill in totallen later
+ rev4i(filename?1:0,data,ptr); //num children
+ rev4i(corrid,data,ptr);
+ rev4i(ithmboffset,data,ptr);
+ rev4i(imagesize,data,ptr);
+ rev2i(vpad,data,ptr);
+ rev2i(hpad,data,ptr);
+ rev2i(imgw,data,ptr);
+ rev2i(imgh,data,ptr);
+ pad(data,headerlen,ptr);
+ if(filename) {
+ int p = filename->write(data+ptr,len-ptr);
+ if(p<0) return -1;
+ ptr+=p;
+ }
+ rev4(ptr,&data[8]); // fill in totallen
+ return ptr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ArtAlbumList
+ArtAlbumList::ArtAlbumList() :
+ headerlen(0x5c)
+{
+}
+
+ArtAlbumList::~ArtAlbumList() {}
+
+int ArtAlbumList::parse(BYTE *data, int len) {
+ int ptr=4;
+ if(len < headerlen) return -1;
+ if (_strnicmp((char *)data,"mhla",4)) return -1;
+ headerlen = rev4i(data,ptr);
+ if(headerlen < 0x5c) return -1;
+ int children = rev4i(data,ptr);
+
+ if(children != 0) return -1;
+
+ return headerlen;
+}
+
+int ArtAlbumList::write(BYTE *data, int len) {
+ int ptr=0;
+ if(headerlen > len) return -1;
+ putmh("mhla",data,ptr);
+ rev4i(headerlen,data,ptr);
+ rev4i(0,data,ptr); // num children
+ pad(data,headerlen,ptr);
+
+ return ptr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ArtFileList
+ArtFileList::ArtFileList() :
+ headerlen(0x5c)
+{
+}
+
+ArtFileList::~ArtFileList()
+{
+ for (auto file : files)
+ {
+ delete file;
+ }
+ files.clear();
+}
+
+int ArtFileList::parse(BYTE *data, int len) {
+ int ptr=4;
+ if(len < headerlen) return -1;
+ if (_strnicmp((char *)data,"mhlf",4)) return -1;
+ headerlen = rev4i(data,ptr);
+ if(headerlen < 0x5c) return -1;
+ int children = rev4i(data,ptr);
+
+ ptr = headerlen;
+
+ for(int i=0; i<children; i++) {
+ ArtFile * f = new ArtFile;
+ int p = f->parse(data+ptr,len-ptr);
+ if(p<0) { delete f; return -1; }
+ ptr+=p;
+ files.push_back(f);
+ }
+ return ptr;
+}
+
+int ArtFileList::write(BYTE *data, int len) {
+ int ptr=0;
+ if(headerlen > len) return -1;
+ putmh("mhlf",data,ptr);
+ rev4i(headerlen,data,ptr);
+ rev4i(files.size(),data,ptr); // num children
+ pad(data,headerlen,ptr);
+
+ for(auto f = files.begin(); f != files.end(); f++) {
+ int p = (*f)->write(data+ptr,len-ptr);
+ if(p<0) return -1;
+ ptr+=p;
+ }
+
+ return ptr;
+}
+
+ArtFile * ArtFileList::getFile(int corrid) {
+ for(auto i = files.begin(); i!=files.end(); i++) {
+ if((*i)->corrid == corrid) return *i;
+ }
+ return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ArtFile
+ArtFile::ArtFile() :
+ headerlen(0x7c),
+ corrid(0),
+ imagesize(0),
+ file(0)
+{
+}
+
+ArtFile::~ArtFile() {
+ SAFEFREE(file);
+}
+
+int ArtFile::parse(BYTE *data, int len) {
+ int ptr=4;
+ if(len < headerlen) return -1;
+ if (_strnicmp((char *)data,"mhif",4)) return -1;
+ headerlen = rev4i(data,ptr);
+ if(headerlen < 0x7c) return -1;
+ int totallen = rev4i(data,ptr);
+ rev4i(data,ptr); // might not be numchildren, it's really unk1
+ corrid = rev4i(data,ptr);
+ imagesize = rev4i(data,ptr);
+
+ return totallen;
+}
+
+int ArtFile::write(BYTE *data, int len) {
+ int ptr=0;
+ if(headerlen > len) return -1;
+ putmh("mhif",data,ptr);
+ rev4i(headerlen,data,ptr);
+ rev4i(0,data,ptr); // total len, fill in later
+ rev4i(0,data,ptr); // numchildren/unk1
+ rev4i(corrid,data,ptr);
+ rev4i(imagesize,data,ptr);
+ pad(data,headerlen,ptr);
+ // write children, if we had any...
+ rev4(ptr,&data[8]); // fill in total len
+ return ptr;
+}
+
+struct ArtFileImageSort {
+ bool operator()(ArtFileImage*& ap,ArtFileImage*& bp) {
+ return ap->start < bp->start;
+ }
+};
+
+void ArtFile::sortImages() {
+ std::sort(images.begin(),images.end(),ArtFileImageSort());
+ for(size_t i = 1; i != images.size(); i++)
+ {
+ if(images[i]->start == images[i-1]->start)
+ {
+ images.erase(images.begin() + i);
+ i--;
+ images[i]->refcount++;
+ }
+ }
+}
+
+size_t ArtFile::getNextHole(size_t size) {
+ size_t s=0;
+ for(auto i = images.begin(); i!=images.end(); i++) {
+ if((*i)->start - s >= size) return s;
+ s = (*i)->start + (*i)->len;
+ }
+ return s;
+}
+
+bool writeDataToThumb(wchar_t *file, unsigned short * data, int len) {
+ FILE * f = _wfopen(file,L"ab");
+ if(!f) return false;
+ fwrite(data,len,sizeof(short),f);
+ fclose(f);
+ return true;
+}
diff --git a/Src/Plugins/Portable/pmp_ipod/iPodArtworkDB.h b/Src/Plugins/Portable/pmp_ipod/iPodArtworkDB.h
new file mode 100644
index 00000000..8e74e3e0
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/iPodArtworkDB.h
@@ -0,0 +1,232 @@
+/*
+ *
+ *
+ * Copyright (c) 2007 Will Fisher (will.fisher@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ *
+ */
+
+#ifndef __IPODARTDB_H__
+#define __IPODARTDB_H__
+
+#pragma once
+
+//#include <stdio.h>
+#include <windows.h>
+#include <vector>
+#include <map>
+#include <bfc/platform/types.h>
+
+class ArtDB;
+class ArtDataSet;
+class ArtImageList;
+class ArtImage;
+class ArtImageName;
+class ArtDataObject;
+class ArtAlbumList;
+class ArtFileList;
+class ArtFile;
+class ArtFileImage;
+
+// this contains our whole art database
+class ArtDB { //mhfd
+public:
+ int headerlen; //0x84
+ int totallen;
+ int unk1;
+ int unk2; // must be 2
+ // numchildren // should be 3
+ int unk3;
+ uint32_t nextid; // for ArtImage ids, starts at 0x40
+ __int64 unk5;
+ __int64 unk6;
+ int unk7; // 2
+ int unk8; // 0
+ int unk9; // 0
+ int unk10;
+ int unk11;
+ ArtDataSet * imageListDS;
+ ArtDataSet * albumListDS;
+ ArtDataSet * fileListDS;
+
+ ArtDB();
+ ~ArtDB();
+ int parse(BYTE * data, int len, wchar_t drive);
+ int write(BYTE * data, int len);
+
+ void makeEmptyDB(wchar_t drive);
+};
+
+class ArtDataSet { //mhsd
+public:
+ int headerlen; //0x60
+ int totallen;
+ int index; // 1=image list, 2=album list, 3=file list
+ ArtImageList * imageList;
+ ArtAlbumList * albumList;
+ ArtFileList * fileList;
+
+ ArtDataSet();
+ ArtDataSet(int idx);
+ ~ArtDataSet();
+ int parse(BYTE *data, int len);
+ int write(BYTE *data, int len);
+};
+
+// contains a list of images
+class ArtImageList { //mhli
+public:
+ typedef std::map<uint64_t ,ArtImage*> ArtImageMap;
+ typedef ArtImageMap::iterator ArtImageMapIterator;
+ typedef ArtImageMap::value_type ArtImageMapPair;
+
+ int headerlen; //0x5c
+ //int numchildren;
+ ArtImageMap images;
+
+ ArtImageList();
+ ~ArtImageList();
+ int parse(BYTE *data, int len);
+ int write(BYTE *data, int len);
+};
+
+// contains a reference to an image within an .ithmb file
+class ArtImage { //mhii
+public:
+ int headerlen; //0x98
+ int totallen;
+ //int numchildren;
+ uint32_t id;
+ uint64_t songid;
+ int32_t unk4;
+ int32_t rating;
+ int32_t unk6;
+ uint32_t originalDate; //0
+ uint32_t digitizedDate; //0
+ uint32_t srcImageSize; // in bytes
+ std::vector<ArtDataObject*> dataobjs;
+
+ ArtImage();
+ ~ArtImage();
+ int parse(BYTE *data, int len);
+ int write(BYTE *data, int len);
+};
+
+class ArtDataObject { //mhod
+public:
+ int headerlen; //0x18
+ // total length
+ short type;
+ unsigned char unk1;
+ // unsigned char padding; // must pad to a multiple of 4 bytes! this is usually 2, but can be 0,1,2 or 3
+ BYTE * data;
+ int datalen;
+ ArtImageName * image;
+
+ ArtDataObject();
+ ~ArtDataObject();
+ int parse(BYTE *data, int len);
+ int write(BYTE *data, int len);
+
+ void GetString(wchar_t * str, int len);
+ void SetString(wchar_t * str);
+};
+
+class ArtImageName { //mhni
+public:
+ int headerlen; //0x4c
+ int totallen;
+ //num children = 1
+ unsigned int corrid;
+ unsigned int ithmboffset;
+ unsigned int imagesize; // in bytes
+ short vpad;
+ short hpad;
+ unsigned short imgh;
+ unsigned short imgw;
+ ArtDataObject* filename;
+
+ ArtImageName();
+ ~ArtImageName();
+ int parse(BYTE *data, int len);
+ int write(BYTE *data, int len);
+};
+
+// this is only used in photo databases (which we don't care about) so it's only a stub
+class ArtAlbumList { //mhla
+public:
+ int headerlen; //0x5c
+ //num children, should be 0 for artwork db
+ ArtAlbumList();
+ ~ArtAlbumList();
+ int parse(BYTE *data, int len);
+ int write(BYTE *data, int len);
+};
+
+// this contains the list of .ithmb files
+class ArtFileList { //mhlf
+public:
+ int headerlen; //0x5c
+ // num children
+ std::vector<ArtFile*> files;
+
+ ArtFileList();
+ ~ArtFileList();
+ int parse(BYTE *data, int len);
+ int write(BYTE *data, int len);
+ ArtFile * getFile(int corrid);
+};
+
+// this talks about a .ithmb file
+class ArtFile { //mhif
+public:
+ int headerlen; //0x7c
+ unsigned int corrid;
+ unsigned int imagesize; // bytes
+
+ ArtFile();
+ ~ArtFile();
+ int parse(BYTE *data, int len);
+ int write(BYTE *data, int len);
+
+ std::vector<ArtFileImage*> images;
+ wchar_t * file;
+ void sortImages();
+ size_t getNextHole(size_t size);
+};
+
+class ArtFileImage {
+public:
+ size_t start;
+ size_t len;
+ int refcount;
+ ArtFileImage(size_t start, size_t len, int refcount) : start(start), len(len), refcount(refcount) {}
+};
+
+bool writeDataToThumb(wchar_t *file, unsigned short * data, int len);
+
+#endif //__IPODARTDB_H__ \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_ipod/iPodDB.cpp b/Src/Plugins/Portable/pmp_ipod/iPodDB.cpp
new file mode 100644
index 00000000..1fe94190
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/iPodDB.cpp
@@ -0,0 +1,4807 @@
+/*
+*
+*
+* Copyright (c) 2004 Samuel Wood (sam.wood@gmail.com)
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+* derived from this software without specific prior permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*
+*
+*/
+
+
+// For more information on how all this stuff works, see:
+// http://www.ipodlinux.org/ITunesDB
+
+
+
+// iPodDB.cpp: implementation of the iPod classes.
+//
+//////////////////////////////////////////////////////////////////////
+
+#pragma warning( disable : 4786)
+
+#include "iPodDB.h"
+#include <bfc/platform/types.h>
+#include <assert.h>
+#include <time.h>
+#include <windows.h>
+#include <tchar.h>
+#include <math.h>
+#include <vector>
+
+/*
+#ifdef ASSERT
+#undef ASSERT
+#define ASSERT(x) {}
+#endif
+*/
+//#define IPODDB_PROFILER // Uncomment to enable profiler measurments
+
+#ifdef IPODDB_PROFILER
+/* profiler code from Foobar2000's PFC library:
+*
+* Copyright (c) 2001-2003, Peter Pawlowski
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+*
+* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+class profiler_static
+{
+private:
+ const char * name;
+ __int64 total_time,num_called;
+
+public:
+ profiler_static(const char * p_name)
+ {
+ name = p_name;
+ total_time = 0;
+ num_called = 0;
+ }
+ ~profiler_static()
+ {
+ char blah[512] = {0};
+ char total_time_text[128] = {0};
+ char num_text[128] = {0};
+ _i64toa(total_time,total_time_text,10);
+ _i64toa(num_called,num_text,10);
+ _snprintf(blah, sizeof(blah), "profiler: %s - %s cycles (executed %s times)\n",name,total_time_text,num_text);
+ OutputDebugStringA(blah);
+ }
+ void add_time(__int64 delta) {total_time+=delta;num_called++;}
+};
+
+class profiler_local
+{
+private:
+ static __int64 get_timestamp();
+ __int64 start;
+ profiler_static * owner;
+public:
+ profiler_local(profiler_static * p_owner)
+ {
+ owner = p_owner;
+ start = get_timestamp();
+ }
+ ~profiler_local()
+ {
+ __int64 end = get_timestamp();
+ owner->add_time(end-start);
+ }
+
+};
+
+__declspec(naked) __int64 profiler_local::get_timestamp()
+{
+ __asm
+ {
+ rdtsc
+ ret
+ }
+}
+
+
+#define profiler(name) \
+ static profiler_static profiler_static_##name(#name); \
+ profiler_local profiler_local_##name(&profiler_static_##name);
+
+#endif
+
+
+#ifdef _DEBUG
+#define MYDEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__)
+// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
+//allocations to be of _CLIENT_BLOCK type
+
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#define new MYDEBUG_NEW
+#endif
+
+
+//
+// useful functions
+//////////////////////////////////////////////////////////////////////
+inline BOOL WINAPI IsCharSpaceW(wchar_t c) { return (c == L' ' || c == L'\t'); }
+inline bool IsTheW(const wchar_t *str) { if (str && (str[0] == L't' || str[0] == L'T') && (str[1] == L'h' || str[1] == L'H') && (str[2] == L'e' || str[2] == L'E') && (str[3] == L' ')) return true; else return false; }
+#define SKIP_THE_AND_WHITESPACE(x) { wchar_t *save##x=(wchar_t*)x; while (IsCharSpaceW(*x) && *x) x++; if (IsTheW(x)) x+=4; while (IsCharSpaceW(*x)) x++; if (!*x) x=save##x; }
+///#define SKIP_THE_AND_WHITESPACE(x) { while (!iswalnum(*x) && *x) x++; if (!_wcsnicmp(x,L"the ",4)) x+=4; while (*x == L' ') x++; }
+int STRCMP_NULLOK(const wchar_t *pa, const wchar_t *pb) {
+ if (!pa) pa=L"";
+ else SKIP_THE_AND_WHITESPACE(pa)
+ if (!pb) pb=L"";
+ else SKIP_THE_AND_WHITESPACE(pb)
+ return lstrcmpi(pa,pb);
+}
+#undef SKIP_THE_AND_WHITESPACE
+
+// convert Macintosh timestamp to windows timestamp
+time_t mactime_to_wintime (const unsigned long mactime)
+{
+ if (mactime != 0) return (time_t)(mactime - 2082844800);
+ else return (time_t)mactime;
+}
+
+// convert windows timestamp to Macintosh timestamp
+unsigned long wintime_to_mactime (const __time64_t time)
+{
+ return (unsigned long)(time + 2082844800);
+}
+
+char * UTF16_to_UTF8(wchar_t * str)
+{
+ const unsigned int tempstrLen = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
+ char * tempstr=(char *)malloc(tempstrLen + 1);
+ int ret=WideCharToMultiByte( CP_UTF8, 0, str, -1, tempstr, tempstrLen, NULL, NULL );
+ tempstr[tempstrLen]='\0';
+
+ if (!ret) DWORD bob=GetLastError();
+
+ return tempstr;
+}
+wchar_t* UTF8_to_UTF16(char *str)
+{
+ const unsigned int tempstrLen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+
+ wchar_t *tempstr = (wchar_t*)malloc((tempstrLen * 2) + 2);
+ MultiByteToWideChar(CP_UTF8, 0, str, -1, tempstr, tempstrLen);
+ tempstr[tempstrLen] = '\0';
+
+ return tempstr;
+}
+
+// get 2 bytes from data, reversed
+static __forceinline uint16_t rev2(const uint8_t * data)
+{
+ uint16_t ret;
+ ret = ((uint16_t) data[1]) << 8;
+ ret += ((uint16_t) data[0]);
+ return ret;
+}
+
+static __forceinline void rev2(const unsigned short number, unsigned char * data)
+{
+ data[1] = (unsigned char)(number >> 8) & 0xff;
+ data[0] = (unsigned char)number & 0xff;
+}
+
+// get 4 bytes from data, reversed
+static __forceinline uint32_t rev4(const uint8_t * data)
+{
+ unsigned long ret;
+ ret = ((unsigned long) data[3]) << 24;
+ ret += ((unsigned long) data[2]) << 16;
+ ret += ((unsigned long) data[1]) << 8;
+ ret += ((unsigned long) data[0]);
+ return ret;
+}
+
+// get 4 bytes from data
+static __forceinline uint32_t get4(const uint8_t * data)
+{
+ unsigned long ret;
+ ret = ((unsigned long) data[0]) << 24;
+ ret += ((unsigned long) data[1]) << 16;
+ ret += ((unsigned long) data[2]) << 8;
+ ret += ((unsigned long) data[3]);
+ return ret;
+}
+
+// get 8 bytes from data
+static __forceinline unsigned __int64 get8(const uint8_t * data)
+{
+ unsigned __int64 ret;
+ ret = get4(data);
+ ret = ret << 32;
+ ret += get4(&data[4]);
+ return ret;
+}
+
+// reverse 8 bytes in place
+static __forceinline unsigned __int64 rev8(uint64_t number)
+{
+ unsigned __int64 ret;
+ ret = (number&0x00000000000000FF) << 56;
+ ret+= (number&0x000000000000FF00) << 40;
+ ret+= (number&0x0000000000FF0000) << 24;
+ ret+= (number&0x00000000FF000000) << 8;
+ ret+= (number&0x000000FF00000000) >> 8;
+ ret+= (number&0x0000FF0000000000) >> 24;
+ ret+= (number&0x00FF000000000000) >> 40;
+ ret+= (number&0xFF00000000000000) >> 56;
+ return ret;
+}
+
+//write 4 bytes reversed
+static __forceinline void rev4(const unsigned long number, uint8_t * data)
+{
+ data[3] = (uint8_t)(number >> 24) & 0xff;
+ data[2] = (uint8_t)(number >> 16) & 0xff;
+ data[1] = (uint8_t)(number >> 8) & 0xff;
+ data[0] = (uint8_t)number & 0xff;
+}
+
+//write 4 bytes normal
+static __forceinline void put4(const unsigned long number, uint8_t * data)
+{
+ data[0] = (uint8_t)(number >> 24) & 0xff;
+ data[1] = (uint8_t)(number >> 16) & 0xff;
+ data[2] = (uint8_t)(number >> 8) & 0xff;
+ data[3] = (uint8_t)number & 0xff;
+}
+
+// write 8 bytes normal
+static __forceinline void put8(const unsigned __int64 number, uint8_t * data)
+{
+ data[0] = (uint8_t)(number >> 56) & 0xff;
+ data[1] = (uint8_t)(number >> 48) & 0xff;
+ data[2] = (uint8_t)(number >> 40) & 0xff;
+ data[3] = (uint8_t)(number >> 32) & 0xff;
+ data[4] = (uint8_t)(number >> 24) & 0xff;
+ data[5] = (uint8_t)(number >> 16) & 0xff;
+ data[6] = (uint8_t)(number >> 8) & 0xff;
+ data[7] = (uint8_t)number & 0xff;
+}
+
+
+
+// get 3 bytes from data, reversed
+static __forceinline unsigned long rev3(const uint8_t * data)
+{
+ unsigned long ret = 0;
+ ret += ((unsigned long) data[2]) << 16;
+ ret += ((unsigned long) data[1]) << 8;
+ ret += ((unsigned long) data[0]);
+ return ret;
+}
+
+//write 3 bytes normal (used in iTunesSD)
+static __forceinline void put3(const unsigned long number, uint8_t * data)
+{
+ data[0] = (uint8_t)(number >> 16) & 0xff;
+ data[1] = (uint8_t)(number >> 8) & 0xff;
+ data[2] = (uint8_t)number & 0xff;
+}
+
+//write 3 bytes reversed
+static __forceinline void rev3(const unsigned long number, uint8_t * data)
+{
+ data[2] = (uint8_t)(number >> 16) & 0xff;
+ data[1] = (uint8_t)(number >> 8) & 0xff;
+ data[0] = (uint8_t)number & 0xff;
+}
+
+// pass data and ptr, updates ptr automatically (by reference)
+static __forceinline void write_uint32_t(uint8_t *data, size_t &offset, uint32_t value)
+{
+ rev4(value, &data[offset]);
+ offset+=4;
+}
+
+static __forceinline uint32_t read_uint32_t(const uint8_t *data, size_t &offset)
+{
+ const uint8_t *ptr = &data[offset];
+ offset+=4;
+ return rev4(ptr);
+}
+
+static __forceinline uint32_t read_uint16_t(const uint8_t *data, size_t &offset)
+{
+ const uint8_t *ptr = &data[offset];
+ offset+=2;
+ return rev2(ptr);
+}
+
+static unsigned __int64 Generate64BitID()
+{
+ GUID tmp;
+ CoCreateGuid(&tmp);
+ unsigned __int64 one = tmp.Data1;
+ unsigned __int64 two = tmp.Data2;
+ unsigned __int64 three = tmp.Data3;
+ unsigned __int64 four = rand();
+ return(one << 32 | two << 16 | three | four);
+}
+
+// useful function to convert from UTF16 to chars
+char * UTF16_to_char(wchar_t * str, int length)
+{
+ char * tempstr=(char *)malloc(length/2+1);
+ int ret=WideCharToMultiByte( CP_MACCP, 0, str, length/2, tempstr, length/2, "x", NULL );
+ tempstr[length/2]='\0';
+
+ if (!ret) DWORD bob=GetLastError();
+
+ return tempstr;
+}
+
+// Case insensitive version of wcsstr
+wchar_t *wcsistr (const wchar_t *s1, const wchar_t *s2)
+{
+ wchar_t *cp = (wchar_t*) s1;
+ wchar_t *s, *t, *endp;
+ wchar_t l, r;
+
+ endp = (wchar_t*)s1 + ( lstrlen(s1) - lstrlen(s2)) ;
+ while (cp && *cp && (cp <= endp))
+ {
+ s = cp;
+ t = (wchar_t*)s2;
+ while (s && *s && t && *t)
+ {
+ l = towupper(*s);
+ r = towupper(*t);
+ if (l != r)
+ break;
+ s++, t++;
+ }
+
+ if (*t == 0)
+ return cp;
+
+ cp = CharNext(cp);
+ }
+
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////
+// iPodObj - Base for all iPod classes
+//////////////////////////////////////////////////////////////////////
+
+iPodObj::iPodObj() :
+size_head(0),
+size_total(0)
+{
+}
+
+iPodObj::~iPodObj()
+{
+}
+
+//////////////////////////////////////////////////////////////////////
+// iPod_mhbd - iTunes database class
+//////////////////////////////////////////////////////////////////////
+
+iPod_mhbd::iPod_mhbd() :
+unk1(1),
+dbversion(0x0c), // iTunes 4.2 = 0x09, 4.5 = 0x0a, 4.7 = 0x0b, 4.7.1 = 0x0c, 0x0d, 0x13
+children(2),
+id(0),
+platform(2),
+language('ne'), // byte-swapped 'en'
+library_id(0),
+timezone(0),
+audio_language(0),
+unk80(1),
+unk84(15),
+subtitle_language(0),
+unk164(0),
+unk166(0),
+unk168(0)
+{
+ // get timezone info
+ _tzset(); // this function call ensures that _timezone global var is valid
+ timezone = -_timezone;
+
+ id = Generate64BitID();
+
+ mhsdsongs = new iPod_mhsd(1);
+ mhsdplaylists = new iPod_mhsd(3);
+ mhsdsmartplaylists = new iPod_mhsd(5);
+}
+
+iPod_mhbd::~iPod_mhbd()
+{
+ delete mhsdsongs;
+ delete mhsdplaylists;
+}
+
+long iPod_mhbd::parse(const uint8_t *data)
+{
+ size_t ptr=0;
+
+ //check mhbd header
+ if (_strnicmp((char *)&data[ptr],"mhbd",4)) return -1;
+ ptr+=4;
+
+ // get sizes
+ size_head=read_uint32_t(data, ptr);
+ size_total=read_uint32_t(data, ptr);
+
+ //ASSERT(size_head == 0xbc);
+
+ // get unk's and numchildren
+ unk1=read_uint32_t(data, ptr);
+ dbversion=read_uint32_t(data, ptr);
+ children=read_uint32_t(data, ptr);
+ id=rev8(get8(&data[ptr]));
+ ptr+=8;
+ if(id == 0)
+ {
+ // Force the id to be a valid value.
+ // This may not always be the right thing to do, but I can't think of any reason why it wouldn't be ok...
+ id = Generate64BitID();
+ }
+ platform=read_uint16_t(data, ptr);
+
+ ptr = 0x46;
+ language = read_uint16_t(data, ptr);
+ library_id = rev8(get8(&data[ptr]));
+ ptr+=8;
+ unk80 = read_uint32_t(data, ptr);
+ unk84 = read_uint32_t(data, ptr);
+
+ ptr = 0xA0;
+ audio_language = read_uint16_t(data, ptr);
+ subtitle_language =read_uint16_t(data, ptr);
+ unk164 = read_uint16_t(data, ptr);
+ unk166 = read_uint16_t(data, ptr);
+ unk168 = read_uint16_t(data, ptr);
+
+ // timezone is at 0x6c, but we want to calculate this based on the computer timezone
+ // TODO: 4 byte field at 0xA0 that contains FFFFFFFF for the ipod shuffle I'm playing with
+
+ //if (children != 2) return -1;
+
+ //skip over nulls
+ ptr=size_head;
+
+ // get the mhsd's
+ bool parsedPlaylists = false;
+ for(unsigned int i=0; i<children; i++)
+ {
+ iPod_mhsd * mhsd = new iPod_mhsd(0);
+ long ret = mhsd->parse(&data[ptr]);
+ if(ret<0) return ret;
+ else ptr+=ret;
+ if(mhsd->index == 1)
+ {
+ delete mhsdsongs;
+ mhsdsongs = mhsd;
+ }
+ else if(mhsd->index == 3 && !parsedPlaylists)
+ {
+ delete mhsdplaylists;
+ mhsdplaylists = mhsd;
+ parsedPlaylists = true;
+ }
+ else if(mhsd->index == 2 && !parsedPlaylists)
+ {
+ delete mhsdplaylists;
+ mhsdplaylists = mhsd;
+ }
+ else if(mhsd->index == 5)
+ {
+ delete mhsdsmartplaylists;
+ mhsdsmartplaylists = mhsd;
+ }
+ else
+ {
+ delete mhsd;
+ }
+ }
+
+ return size_total;
+}
+
+long iPod_mhbd::write(unsigned char * data, const unsigned long datasize)
+{
+ return write(data,datasize,NULL);
+}
+
+extern void GenerateHash(unsigned char *pFWID, unsigned char *pDataBase, long lSize, unsigned char *pHash);
+
+long iPod_mhbd::write(unsigned char * data, const unsigned long datasize, unsigned char *fwid)
+{
+ //const unsigned int headsize=0xbc; // for db version 0x19
+ const unsigned int headsize=188; // for db version 0x2A
+ // check for header size
+ if (headsize>datasize) return -1;
+
+ long ptr=0;
+
+ //write mhbd header
+ data[0]='m';data[1]='h';data[2]='b';data[3]='d';
+ ptr+=4;
+
+ // write sizes
+ rev4(headsize,&data[ptr]); // header size
+ ptr+=4;
+ rev4(0x00,&data[ptr]); // placeholder for total size (fill in later)
+ ptr+=4;
+
+ //write unks
+ rev4(unk1,&data[ptr]);
+ ptr+=4;
+ rev4(0x2a/*dbversion*/,&data[ptr]);
+ ptr+=4;
+
+ //write numchildren
+ //ASSERT (children == 2); // seen no other case in an iTunesDB yet
+ children = 4;
+ rev4(children,&data[ptr]);
+ ptr+=4;
+
+ // fill this in later (it's the db id, it has to be 0 for the hash generation)
+ put8(0,&data[ptr]);
+ ptr+=8;
+
+ rev2(2, &data[ptr]); // platform (2 == Windows)
+ ptr+=2;
+
+ // fill up the rest of the header with nulls
+ for (unsigned int i=ptr;i<headsize;i++)
+ data[i]=0;
+ ptr=headsize;
+
+ rev2(1, &data[0x30]);
+
+ rev2(language, &data[0x46]);
+ put8(library_id, &data[0x48]);
+ rev4(unk80, &data[0x50]);
+ rev4(unk84, &data[0x54]);
+ rev4(timezone, &data[0x6c]);
+ rev2(2, &data[0x70]);
+ rev2(audio_language, &data[0xA0]);
+ rev2(subtitle_language, &data[0xA2]);
+ rev2(unk164, &data[0xA4]);
+ rev2(unk166, &data[0xA6]);
+ rev2(unk168, &data[0xA8]);
+
+ long ret;
+ // write the mhla (album list)
+ iPod_mhsd mhsd_mhla(4);
+ iPod_mhla *album_list = mhsd_mhla.mhla;
+
+ iPod_mhlt::mhit_map_t::const_iterator begin = mhsdsongs->mhlt->mhit.begin();
+ iPod_mhlt::mhit_map_t::const_iterator end = mhsdsongs->mhlt->mhit.end();
+ for(iPod_mhlt::mhit_map_t::const_iterator it = begin; it != end; it++)
+ {
+ wchar_t * artist = L"";
+ wchar_t * album = L"";
+ iPod_mhit *m = static_cast<iPod_mhit*>((*it).second);
+ iPod_mhod *mhartist = m->FindString(MHOD_ARTIST);
+ iPod_mhod *mhalbum = m->FindString(MHOD_ALBUM);
+
+ if(mhartist && mhartist->str)
+ artist = mhartist->str;
+
+ if(mhalbum && mhalbum->str)
+ album = mhalbum->str;
+
+ m->album_id = mhsd_mhla.mhla->GetAlbumId(artist, album);
+ }
+
+ ret=mhsd_mhla.write(&data[ptr], datasize-ptr, 4);
+ ASSERT(ret >= 0);
+ if (ret<0) return ret;
+ else ptr+=ret;
+
+ // write the mhsd's
+ ret=mhsdsongs->write(&data[ptr], datasize-ptr);
+ ASSERT(ret >= 0);
+ if (ret<0) return ret;
+ else ptr+=ret;
+
+ ret=mhsdplaylists->write(&data[ptr], datasize-ptr, 3);
+ ASSERT(ret >= 0);
+ if (ret<0) return ret;
+ else ptr+=ret;
+
+ ret=mhsdplaylists->write(&data[ptr], datasize-ptr, 2);
+ ASSERT(ret >= 0);
+ if (ret<0) return ret;
+ else ptr+=ret;
+
+ if(mhsdsmartplaylists->mhlp_smart) {
+ ret=mhsdsmartplaylists->write(&data[ptr], datasize-ptr, 5);
+ ASSERT(ret >= 0);
+ if (ret<0) return ret;
+ else ptr+=ret;
+ } else children--;
+
+ // fix the total size
+ rev4(ptr,&data[8]);
+ rev4(children,&data[20]);
+
+ if(fwid)
+ GenerateHash(fwid,data,ptr,data+0x58); // fuck you, gaydickian
+
+ put8(rev8(id),&data[0x18]); // put this back in -- it has to be 0 for the hash generation.
+
+ return ptr;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// iPod_mhsd - Holds tracklists and playlists
+//////////////////////////////////////////////////////////////////////
+
+iPod_mhsd::iPod_mhsd() :
+index(0),
+mhlt(NULL),
+mhlp(NULL),
+mhlp_smart(NULL),
+mhla(NULL)
+{
+}
+
+iPod_mhsd::iPod_mhsd(int newindex) :
+index(newindex),
+mhlt(NULL),
+mhlp(NULL),
+mhlp_smart(NULL),
+mhla(NULL)
+{
+ switch(newindex)
+ {
+ case 1: mhlt=new iPod_mhlt(); break;
+ case 2:
+ case 3:
+ case 5: mhlp=new iPod_mhlp(); break;
+ case 4: mhla=new iPod_mhla(); break;
+ default: index=0;
+ }
+}
+
+iPod_mhsd::~iPod_mhsd()
+{
+ delete mhlt;
+ delete mhlp;
+ delete mhla;
+}
+
+long iPod_mhsd::parse(const uint8_t *data)
+{
+ unsigned long ptr=0;
+
+ //check mhsd header
+ if (_strnicmp((char *)&data[ptr],"mhsd",4)) return -1;
+ ptr+=4;
+
+ // get sizes
+ size_head=rev4(&data[ptr]);
+ ptr+=4;
+ size_total=rev4(&data[ptr]);
+ ptr+=4;
+
+ ASSERT(size_head == 0x60);
+
+ // get index number
+ index=rev4(&data[ptr]);
+ ptr+=4;
+
+ // skip null padding
+ ptr=size_head;
+
+ long ret;
+
+ // check to see if this is a holder for an mhlt or an mhlp
+ if (!_strnicmp((char *)&data[ptr],"mhlt",4))
+ {
+ if (mhlt==NULL)
+ {
+ mhlt=new iPod_mhlt();
+ //index=1;
+ }
+ ret=mhlt->parse(&data[ptr]);
+ ASSERT(ret >= 0);
+ if (ret<0) return ret;
+ else ptr+=ret;
+ }
+ else if (!_strnicmp((char *)&data[ptr],"mhlp",4) && (index == 2 || index == 3))
+ {
+ if (mhlp==NULL)
+ {
+ mhlp=new iPod_mhlp();
+ if(index != 2) index=3;
+ }
+ ret=mhlp->parse(&data[ptr]);
+ ASSERT(ret >= 0);
+ if (ret<0) return ret;
+ else ptr+=ret;
+ }
+ else if (!_strnicmp((char *)&data[ptr],"mhlp",4) && index == 5) // smart playlists
+ {
+ if (mhlp_smart==NULL)
+ mhlp_smart=new iPod_mhlp();
+ ret=mhlp_smart->parse(&data[ptr]);
+ ASSERT(ret >= 0);
+ if (ret<0) return ret;
+ else ptr+=ret;
+ }
+ else {
+ }
+ //return -1;
+
+ //if (ptr != size_total) return -1;
+
+ return size_total;
+}
+
+long iPod_mhsd::write(unsigned char * data, const unsigned long datasize, int index)
+{
+ const unsigned int headsize=0x60;
+ // check for header size
+ if (headsize>datasize) return -1;
+
+ long ptr=0;
+
+ //write mhsd header
+ data[0]='m';data[1]='h';data[2]='s';data[3]='d';
+ ptr+=4;
+
+ // write sizes
+ rev4(headsize,&data[ptr]); // header size
+ ptr+=4;
+ rev4(0x00,&data[ptr]); // placeholder for total size (fill in later)
+ ptr+=4;
+
+ // write index number
+ rev4(index,&data[ptr]);
+ ptr+=4;
+
+ // fill up the rest of the header with nulls
+ for (unsigned int i=ptr;i<headsize;i++)
+ data[i]=0;
+ ptr=headsize;
+
+ // write out the songs or the playlists, depending on index
+ long ret;
+ if (index==1) // mhlt
+ ret=mhlt->write(&data[ptr],datasize-ptr);
+ else if (index==2 || index==3) // mhlp
+ ret=mhlp->write(&data[ptr],datasize-ptr,index);
+ else if (index == 4) // mhla
+ ret=mhla->write(&data[ptr],datasize-ptr);
+ else if (index==5) // mhlp_smart
+ ret=mhlp_smart->write(&data[ptr],datasize-ptr,3);
+ else return -1;
+
+ ASSERT(ret>=0);
+ if (ret<0) return ret;
+ else ptr+=ret;
+
+ // fix the total size
+ rev4(ptr,&data[8]);
+
+ return ptr;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////
+// iPod_mhlt - TrackList class
+//////////////////////////////////////////////////////////////////////
+
+iPod_mhlt::iPod_mhlt() :
+mhit(),
+next_mhit_id(100)
+{
+}
+
+iPod_mhlt::~iPod_mhlt()
+{
+ // It is unnecessary (and slow) to clear the map, since the object is being destroyed anyway
+ ClearTracks(false);
+}
+
+long iPod_mhlt::parse(const uint8_t *data)
+{
+ long ptr=0;
+
+ //check mhlt header
+ if (_strnicmp((char *)&data[ptr],"mhlt",4)) return -1;
+ ptr+=4;
+
+ // get size
+ size_head=rev4(&data[ptr]);
+ ptr+=4;
+
+ ASSERT(size_head == 0x5c);
+
+ // get num children (num songs on iPod)
+ const unsigned long children=rev4(&data[ptr]); // Only used locally - child count is obtained from the mhit list
+ ptr+=4;
+
+ //skip nulls
+ ptr=size_head;
+
+ long ret;
+
+ // get children one by one
+ for (unsigned long i=0;i<children;i++)
+ {
+ iPod_mhit *m = new iPod_mhit;
+ ret=m->parse(&data[ptr]);
+ ASSERT(ret >= 0);
+ if (ret<0)
+ {
+ delete m;
+ return ret;
+ }
+
+ ptr+=ret;
+
+ mhit.insert(mhit_value_t(m->id, m));
+ mhit_indexer.push_back(m->id);
+ }
+
+ if (!mhit.empty())
+ {
+ //InterlockedExchange(&next_mhit_id, mhit.back().first);
+ uint32_t id = mhit_indexer[mhit_indexer.size() - 1];
+ InterlockedExchange(&next_mhit_id, id);
+ }
+ return ptr;
+}
+
+uint32_t iPod_mhlt::GetNextID()
+{
+ return (uint32_t)InterlockedIncrement(&next_mhit_id);
+}
+
+long iPod_mhlt::write(unsigned char * data, const unsigned long datasize)
+{
+ const unsigned int headsize=0x5c;
+ // check for header size
+ if (headsize>datasize) return -1;
+
+ long ptr=0;
+
+ //write mhlt header
+ data[0]='m';data[1]='h';data[2]='l';data[3]='t';
+ ptr+=4;
+
+ // write size
+ rev4(headsize,&data[ptr]); // header size
+ ptr+=4;
+
+ // write numchildren (numsongs)
+ const unsigned long children = GetChildrenCount();
+ rev4(children,&data[ptr]);
+ ptr+=4;
+
+ // fill up the rest of the header with nulls
+ for (unsigned long i=ptr;i<headsize;i++)
+ data[i]=0;
+ ptr=headsize;
+
+ long ret;
+
+ // write children one by one
+ mhit_map_t::const_iterator begin = mhit.begin();
+ mhit_map_t::const_iterator end = mhit.end();
+ for(mhit_map_t::const_iterator it = begin; it != end; it++)
+ {
+ iPod_mhit *m = static_cast<iPod_mhit*>(it->second);
+
+#ifdef _DEBUG
+ const unsigned int mapID = (*it).first;
+ ASSERT(mapID == m->id);
+#endif
+
+ ret=m->write(&data[ptr],datasize-ptr);
+ ASSERT(ret >= 0);
+ if (ret<0) return ret;
+ else ptr+=ret;
+ }
+
+ return ptr;
+}
+
+iPod_mhit * iPod_mhlt::NewTrack()
+{
+ iPod_mhit *track = new iPod_mhit;
+ if (track != NULL)
+ {
+ track->addedtime = wintime_to_mactime(time(0));
+ track->id = GetNextID();
+ }
+
+ return track;
+}
+
+void iPod_mhlt::AddTrack(iPod_mhit *new_track)
+{
+ mhit_indexer.push_back(new_track->id);
+ mhit.insert(mhit_value_t(new_track->id, new_track));
+}
+
+bool iPod_mhlt::DeleteTrack(const unsigned long index)
+{
+ //unsigned int i=0;
+ //for(mhit_map_t::const_iterator it = mhit.begin(); it != mhit.end(); it++, i++)
+ //{
+ // if(i == index)
+ // {
+ // iPod_mhit *m = static_cast<iPod_mhit*>(it->second);
+ // return(DeleteTrackByID(m->id));
+ // }
+ //}
+ //return false;
+
+ if (index > mhit_indexer.size())
+ {
+ return false;
+ }
+
+ auto key = mhit_indexer[index];
+ auto it = mhit.find(key);
+ if (mhit.end() == it)
+ {
+ return false;
+ }
+
+ return DeleteTrackByID(it->first);
+}
+
+bool iPod_mhlt::DeleteTrackByID(const unsigned long id)
+{
+ mhit_map_t::iterator it = mhit.find(id);
+ if(it != mhit.end())
+ {
+ iPod_mhit *m = static_cast<iPod_mhit*>(it->second);
+ mhit.erase(it);
+ // remove also from indexer!!
+ for (size_t n = 0; n < mhit_indexer.size(); ++n)
+ {
+ if (id == mhit_indexer[n])
+ {
+ mhit_indexer.erase(mhit_indexer.begin() + n);
+ break;
+ }
+ }
+ delete m;
+ return true;
+ }
+ return false;
+}
+
+iPod_mhit * iPod_mhlt::GetTrack(uint32_t index) const
+{
+ //mhit_map_t::value_type value = mhit.at(index);
+ //return value.second;
+
+ if (index > mhit_indexer.size())
+ {
+ return nullptr;
+ }
+ uint32_t key = mhit_indexer[index];
+ auto it = mhit.find(key);
+ if (mhit.end() == it)
+ {
+ return nullptr;
+ }
+
+ return it->second;
+}
+
+iPod_mhit * iPod_mhlt::GetTrackByID(const unsigned long id)
+{
+ mhit_map_t::const_iterator it = mhit.find(id);
+ if(it == mhit.end())
+ return NULL;
+
+ return static_cast<iPod_mhit*>(it->second);
+}
+
+bool iPod_mhlt::ClearTracks(const bool clearMap)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhlt_ClearTracks);
+#endif
+
+ mhit_map_t::const_iterator begin = mhit.begin();
+ mhit_map_t::const_iterator end = mhit.end();
+ for(mhit_map_t::const_iterator it = begin; it != end; it++)
+ {
+ delete static_cast<iPod_mhit*>(it->second);
+ }
+
+ if (clearMap)
+ {
+ mhit.clear();
+ mhit_indexer.clear();
+ }
+
+ return true;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// iPod_mhit - Holds info about a song
+//////////////////////////////////////////////////////////////////////
+
+iPod_mhit::iPod_mhit() :
+id(0),
+visible(1),
+filetype(0),
+vbr(0),
+type(0),
+compilation(0),
+stars(0),
+lastmodifiedtime(0),
+size(0),
+length(0),
+tracknum(0),
+totaltracks(0),
+year(0),
+bitrate(0),
+samplerate(0),
+samplerate_fixedpoint(0),
+volume(0),
+starttime(0),
+stoptime(0),
+soundcheck(0),
+playcount(0),
+playcount2(0),
+lastplayedtime(0),
+cdnum(0),
+totalcds(0),
+userID(0),
+addedtime(0),
+bookmarktime(0),
+dbid(0),
+BPM(0),
+app_rating(0),
+checked(0),
+unk9(0),
+artworkcount(0),
+artworksize(0),
+unk11(0),
+samplerate2(0),
+releasedtime(0),
+unk14(0),
+unk15(0),
+unk16(0),
+skipcount(0),
+skippedtime(0),
+hasArtwork(2), // iTunes 4.7.1 always seems to write 2 for unk19
+skipShuffle(0),
+rememberPosition(0),
+unk19(0),
+dbid2(0),
+lyrics_flag(0),
+movie_flag(0),
+mark_unplayed(0),
+unk20(0),
+unk21(0),
+pregap(0),
+samplecount(0),
+unk25(0),
+postgap(0),
+unk27(0),
+mediatype(0),
+seasonNumber(0),
+episodeNumber(0),
+unk31(0),
+unk32(0),
+unk33(0),
+unk34(0),
+unk35(0),
+unk36(0),
+unk37(0),
+gaplessData(0),
+unk39(0),
+albumgapless(0),
+trackgapless(0),
+unk40(0),
+unk41(0),
+unk42(0),
+unk43(0),
+unk44(0),
+unk45(0),
+unk46(0),
+album_id(0),
+unk48(0),
+unk49(0),
+unk50(0),
+unk51(0),
+unk52(0),
+unk53(0),
+unk54(0),
+unk55(0),
+unk56(0),
+mhii_link(0),
+
+mhod()
+{
+ // Create a highly randomized 64 bit value for the dbID
+ dbid = Generate64BitID();
+ dbid2 = dbid;
+ for(int i=0; i<25; i++) mhodcache[i]=NULL;
+ mhod.reserve(8);
+}
+
+iPod_mhit::~iPod_mhit()
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhit_destructor);
+#endif
+
+ const unsigned long count = GetChildrenCount();
+ for (unsigned long i=0;i<count;i++)
+ delete mhod[i];
+}
+
+long iPod_mhit::parse(const uint8_t *data)
+{
+ size_t ptr=0;
+ unsigned long temp=0;
+
+ //check mhit header
+ if (_strnicmp((char *)&data[ptr],"mhit",4)) return -1;
+ ptr+=4;
+
+ // get sizes
+ size_head=read_uint32_t(data, ptr);
+ size_total=read_uint32_t(data, ptr);
+
+ ASSERT(size_head == 0x9c || size_head == 0xf4 || size_head == 0x148 || size_head == 0x184 || size_head == 0x248); // if this is false, this is a new mhit format
+
+ // get rest of data
+ unsigned long mhodnum=read_uint32_t(data, ptr); // Only used locally
+ id=read_uint32_t(data, ptr);
+ visible=read_uint32_t(data, ptr);
+ filetype=read_uint32_t(data, ptr);
+
+ vbr = data[ptr++];
+ type = data[ptr++];
+ compilation = data[ptr++];
+ stars = data[ptr++];
+
+ lastmodifiedtime=read_uint32_t(data, ptr);
+ size=read_uint32_t(data, ptr);
+ length=read_uint32_t(data, ptr);
+ tracknum=read_uint32_t(data, ptr);
+ totaltracks=read_uint32_t(data, ptr);
+ year=read_uint32_t(data, ptr);
+ bitrate=read_uint32_t(data, ptr);
+
+ temp=rev4(&data[ptr]);
+ ptr+=4;
+ samplerate = (uint16_t)(temp >> 16);
+ samplerate_fixedpoint = (uint16_t)(temp & 0x0000ffff);
+
+ volume=read_uint32_t(data, ptr);
+ starttime=read_uint32_t(data, ptr);
+ stoptime=read_uint32_t(data, ptr);
+ soundcheck=read_uint32_t(data, ptr);
+ playcount=read_uint32_t(data, ptr);
+ playcount2=read_uint32_t(data, ptr);
+ lastplayedtime=read_uint32_t(data, ptr);
+ cdnum=read_uint32_t(data, ptr);;
+ totalcds=read_uint32_t(data, ptr);
+ userID=read_uint32_t(data, ptr);
+ addedtime=read_uint32_t(data, ptr);
+ bookmarktime=read_uint32_t(data, ptr);
+ dbid=rev8(get8(&data[ptr]));
+ ptr+=8;
+ if(dbid == 0)
+ {
+ // Force the dbid to be a valid value.
+ // This may not always be the right thing to do, but I can't think of any reason why it wouldn't be ok...
+ dbid = Generate64BitID();
+ }
+
+ temp=rev4(&data[ptr]);
+ BPM=temp>>16;
+ app_rating=(temp&0xff00) >> 8;
+ checked = (uint8_t)(temp&0xff);
+ ptr+=4;
+
+ artworkcount=rev2(&data[ptr]);
+ ptr+=2;
+ unk9=rev2(&data[ptr]);
+ ptr+=2;
+
+ artworksize=read_uint32_t(data, ptr);
+ unk11=read_uint32_t(data, ptr);
+ memcpy(&samplerate2, &data[ptr], sizeof(float));
+ ptr+=4;
+
+ releasedtime=read_uint32_t(data, ptr);
+ unk14=read_uint32_t(data, ptr);
+ unk15=read_uint32_t(data, ptr);
+ unk16=read_uint32_t(data, ptr);
+
+ // Newly added as of dbversion 0x0c
+ if(size_head >= 0xf4)
+ {
+ skipcount=read_uint32_t(data, ptr);
+ skippedtime=read_uint32_t(data, ptr);
+ hasArtwork=data[ptr++];
+ skipShuffle=data[ptr++];
+ rememberPosition=data[ptr++];
+ unk19=data[ptr++];
+ dbid2=rev8(get8(&data[ptr]));
+ ptr+=8;
+ if(dbid2 == 0)
+ dbid2 = dbid;
+ lyrics_flag=data[ptr++];
+ movie_flag=data[ptr++];
+ mark_unplayed=data[ptr++];
+ unk20=data[ptr++];
+ unk21=read_uint32_t(data, ptr); // 180
+ pregap=read_uint32_t(data, ptr);
+ samplecount=rev8(get8(&data[ptr])); //sample count
+ ptr+=8;
+ unk25=read_uint32_t(data, ptr); // 196
+ postgap=read_uint32_t(data, ptr);
+ unk27=read_uint32_t(data, ptr);
+ mediatype=read_uint32_t(data, ptr);
+ seasonNumber=read_uint32_t(data, ptr);
+ episodeNumber=read_uint32_t(data, ptr);
+ unk31=read_uint32_t(data, ptr);
+ unk32=read_uint32_t(data, ptr);
+ unk33=read_uint32_t(data, ptr);
+ unk34=read_uint32_t(data, ptr);
+ unk35=read_uint32_t(data, ptr);
+ unk36=read_uint32_t(data, ptr);
+ }
+
+ if(size_head >= 0x148)
+ { // dbversion 0x13
+ unk37=read_uint32_t(data, ptr);
+ gaplessData=read_uint32_t(data, ptr);
+ unk39=read_uint32_t(data, ptr);
+ trackgapless = read_uint16_t(data, ptr);
+ albumgapless = read_uint16_t(data, ptr);
+ unk40=read_uint32_t(data, ptr); // 260
+ unk41=read_uint32_t(data, ptr); // 264
+ unk42=read_uint32_t(data, ptr); // 268
+ unk43=read_uint32_t(data, ptr); // 272
+ unk44=read_uint32_t(data, ptr); // 276
+ unk45=read_uint32_t(data, ptr); // 280
+ unk46=read_uint32_t(data, ptr); // 284
+ album_id=read_uint32_t(data, ptr); // 288 - libgpod lists "album_id"
+ unk48=read_uint32_t(data, ptr); // 292 - libgpod lists first half of an id
+ unk49=read_uint32_t(data, ptr); // 296 - libgpod lists second half of an id
+ unk50=read_uint32_t(data, ptr); // 300 - libgpod lists file size
+ unk51=read_uint32_t(data, ptr); // 304
+ unk52=read_uint32_t(data, ptr); // 308 - libgpod mentions 8 bytes of 0x80
+ unk53=read_uint32_t(data, ptr); // 312 - libgpod mentions 8 bytes of 0x80
+ unk54=read_uint32_t(data, ptr); // 316
+ unk55=read_uint32_t(data, ptr); // 320
+ unk56=read_uint32_t(data, ptr); // 324
+ }
+ if(size_head >= 0x184)
+ {
+ ptr = 0x148; // line it up, just in case
+ ptr += 22; // dunno what the first 22 bytes are
+ album_id = read_uint16_t(data, ptr);
+ mhii_link = read_uint32_t(data, ptr);
+
+ }
+
+#ifdef _DEBUG
+ // If these trigger an assertion, something in the database format has changed/been added
+ ASSERT(visible == 1);
+ ASSERT(unk11 == 0);
+ ASSERT(unk16 == 0);
+// ASSERT(unk19 == 0);
+ // ASSERT(hasArtwork == 2); // iTunes always sets unk19 to 2, but older programs won't have set it
+ ASSERT(unk20 == 0);
+ ASSERT(unk21 == 0);
+ ASSERT(unk25 == 0);
+ // ASSERT(unk27 == 0);
+ //ASSERT(unk31 == 0);
+ ASSERT(unk32 == 0);
+ ASSERT(unk33 == 0);
+ ASSERT(unk34 == 0);
+ ASSERT(unk35 == 0);
+ ASSERT(unk36 == 0);
+ ASSERT(unk37 == 0);
+ ASSERT(unk39 == 0);
+ ASSERT(unk40 == 0);
+ ASSERT(unk41 == 0);
+ ASSERT(unk42 == 0);
+ ASSERT(unk43 == 0);
+ ASSERT(unk44 == 0);
+ ASSERT(unk45 == 0);
+ ASSERT(unk46 == 0);
+ // ASSERT(unk47 == 0);
+ //ASSERT(unk48 == 0);
+ // ASSERT(unk49 == 0);
+ ASSERT(unk50 == 0 || unk50 == size);
+ ASSERT(unk51 == 0);
+ // ASSERT(unk52 == 0);
+ ASSERT(unk53 == 0 || unk53 == 0x8080 || unk53 == 0x8081);
+ ASSERT(unk54 == 0);
+ ASSERT(unk55 == 0);
+ ASSERT(unk56 == 0);
+#endif
+
+ // skip nulls
+ ptr=size_head;
+
+ long ret;
+ for (unsigned long i=0;i<mhodnum;i++)
+ {
+ iPod_mhod *m = new iPod_mhod;
+ ret=m->parse(&data[ptr]);
+ ASSERT(ret >= 0);
+ if (ret<0)
+ {
+ delete m;
+ return ret;
+ }
+
+ ptr+=ret;
+ mhod.push_back(m);
+ if(m->type <= 25 && m->type >= 1) mhodcache[m->type-1] = m;
+ }
+
+ return size_total;
+}
+
+
+long iPod_mhit::write(unsigned char * data, const unsigned long datasize)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhit_write);
+#endif
+
+ //const unsigned int headsize=0x148; // was 0x9c in db version <= 0x0b
+ const unsigned int headsize=0x184; // db version 0x19
+ // check for header size
+ if (headsize>datasize) return -1;
+
+ size_t ptr=0;
+
+ //write mhlt header
+ data[0]='m';data[1]='h';data[2]='i';data[3]='t';
+ ptr+=4;
+
+ // write sizes
+ write_uint32_t(data, ptr, headsize); // header size
+ write_uint32_t(data, ptr, 0); // placeholder for total size (fill in later)
+
+ unsigned long temp, i;
+
+ // Remove all empty MHOD strings before continuing
+ for(i=0;i<GetChildrenCount();i++)
+ {
+ iPod_mhod *m = mhod[i];
+ ASSERT(m != NULL);
+ if(m == NULL)
+ continue;
+
+ if(m->type < 50 && m->length == 0)
+ {
+ //DeleteString(m->type);
+ //i = 0;
+ }
+ }
+
+ // write stuff out
+ unsigned long mhodnum = GetChildrenCount();
+ write_uint32_t(data, ptr, mhodnum);
+ write_uint32_t(data, ptr, id);
+ write_uint32_t(data, ptr, visible);
+
+ if(filetype == 0)
+ {
+ iPod_mhod *mhod = FindString(MHOD_LOCATION);
+ if(mhod)
+ {
+ filetype = GetFileTypeID(mhod->str);
+ }
+ }
+ write_uint32_t(data, ptr, filetype);
+
+ vbr = data[ptr++] = vbr;
+ type = data[ptr++] = type;
+ compilation = data[ptr++] = compilation;
+ stars = data[ptr++] = stars;
+
+ write_uint32_t(data, ptr, lastmodifiedtime);
+ write_uint32_t(data, ptr, size);
+ write_uint32_t(data, ptr, length);
+ write_uint32_t(data, ptr, tracknum);
+ write_uint32_t(data, ptr, totaltracks);
+
+ write_uint32_t(data, ptr, year);
+ write_uint32_t(data, ptr, bitrate);
+
+
+ temp = samplerate << 16 | samplerate_fixedpoint & 0x0000ffff;
+ rev4(temp,&data[ptr]);
+ ptr+=4;
+
+ write_uint32_t(data, ptr, volume);
+ write_uint32_t(data, ptr, starttime);
+ write_uint32_t(data, ptr, stoptime);
+ write_uint32_t(data, ptr, soundcheck);
+ write_uint32_t(data, ptr, playcount);
+ write_uint32_t(data, ptr, playcount2);
+ write_uint32_t(data, ptr, lastplayedtime);
+ write_uint32_t(data, ptr, cdnum);
+ write_uint32_t(data, ptr, totalcds);
+ write_uint32_t(data, ptr, userID);
+ write_uint32_t(data, ptr, addedtime);
+ write_uint32_t(data, ptr, bookmarktime);
+ put8(rev8(dbid),&data[ptr]);
+ ptr+=8;
+
+ temp = BPM << 16 | (app_rating & 0xff) << 8 | (checked & 0xff);
+ write_uint32_t(data, ptr, temp);
+
+ rev2(artworkcount, &data[ptr]);
+ ptr+=2;
+ rev2(unk9, &data[ptr]);
+ ptr+=2;
+
+ write_uint32_t(data, ptr, artworksize);
+ write_uint32_t(data, ptr, unk11);
+
+ // If samplerate2 is not set, base it off of samplerate
+ if(samplerate2 == 0)
+ {
+ // samplerate2 is the binary representation of the samplerate, as a 32 bit float
+ const float foo = (float)samplerate;
+ memcpy(&data[ptr], &foo, 4);
+ }
+ else
+ {
+ memcpy(&data[ptr], &samplerate2, 4);
+ }
+ ptr+=4;
+
+ rev4(releasedtime,&data[ptr]);
+ ptr+=4;
+ rev4(unk14,&data[ptr]);
+ ptr+=4;
+ rev4(unk15,&data[ptr]);
+ ptr+=4;
+ rev4(unk16,&data[ptr]);
+ ptr+=4;
+
+ // New data as of dbversion 0x0c
+ if(headsize >= 0xf4)
+ {
+ rev4(skipcount,&data[ptr]);
+ ptr+=4;
+ rev4(skippedtime,&data[ptr]);
+ ptr+=4;
+ data[ptr++]=hasArtwork;
+ data[ptr++]=skipShuffle;
+ data[ptr++]=rememberPosition;
+ data[ptr++]=unk19;
+ put8(rev8(dbid2),&data[ptr]);
+ ptr+=8;
+ data[ptr++]=lyrics_flag;
+ data[ptr++]=movie_flag;
+ data[ptr++]=mark_unplayed;
+ data[ptr++]=unk20;
+ rev4(unk21,&data[ptr]);
+ ptr+=4;
+ rev4(pregap,&data[ptr]);
+ ptr+=4;
+ put8(rev8(samplecount),&data[ptr]);
+ ptr+=8;
+ rev4(unk25,&data[ptr]);
+ ptr+=4;
+ rev4(postgap,&data[ptr]);
+ ptr+=4;
+ rev4(unk27,&data[ptr]);
+ ptr+=4;
+ rev4(mediatype,&data[ptr]);
+ ptr+=4;
+ rev4(seasonNumber,&data[ptr]);
+ ptr+=4;
+ rev4(episodeNumber,&data[ptr]);
+ ptr+=4;
+ rev4(unk31,&data[ptr]);
+ ptr+=4;
+ rev4(unk32,&data[ptr]);
+ ptr+=4;
+ rev4(unk33,&data[ptr]);
+ ptr+=4;
+ rev4(unk34,&data[ptr]);
+ ptr+=4;
+ rev4(unk35,&data[ptr]);
+ ptr+=4;
+ rev4(unk36,&data[ptr]);
+ ptr+=4;
+ }
+ if(headsize >= 0x148)
+ {
+ rev4(unk37,&data[ptr]); ptr+=4;
+ rev4(gaplessData,&data[ptr]); ptr+=4;
+ rev4(unk39,&data[ptr]); ptr+=4;
+
+ temp = albumgapless << 16 | (trackgapless & 0xffff);
+ rev4(temp, &data[ptr]); ptr+=4;
+
+ rev4(unk40,&data[ptr]); ptr+=4;
+ rev4(unk41,&data[ptr]); ptr+=4;
+ rev4(unk42,&data[ptr]); ptr+=4;
+ rev4(unk43,&data[ptr]); ptr+=4;
+ rev4(unk44,&data[ptr]); ptr+=4;
+ rev4(unk45,&data[ptr]); ptr+=4;
+ rev4(unk46,&data[ptr]); ptr+=4;
+ rev4(album_id,&data[ptr]); ptr+=4;
+ rev4(unk48,&data[ptr]); ptr+=4;
+ rev4(unk49,&data[ptr]); ptr+=4;
+ rev4(size,&data[ptr]); ptr+=4;
+ rev4(unk51,&data[ptr]); ptr+=4;
+ rev4(unk52,&data[ptr]); ptr+=4;
+ rev4(unk53,&data[ptr]); ptr+=4;
+ rev4(unk54,&data[ptr]); ptr+=4;
+ rev4(unk55,&data[ptr]); ptr+=4;
+ rev4(unk56,&data[ptr]); ptr+=4;
+ }
+
+ if (headsize >= 0x184)
+ {
+ ptr = 0x148; // line it up, just in case
+ memset(&data[ptr], 0, 22); // write a bunch of zeroes
+ ptr+=22;
+ rev2(album_id, &data[ptr]); ptr+=2;
+ rev4(mhii_link,&data[ptr]); ptr+=4;
+ memset(&data[ptr], 0, 32); // write a bunch of zeroes
+ ptr+=32;
+ }
+
+ ASSERT(ptr==headsize); // if this ain't true, I screwed up badly somewhere above
+
+ long ret;
+ for (i=0;i<mhodnum;i++)
+ {
+ ret=mhod[i]->write(&data[ptr],datasize-ptr);
+ ASSERT(ret >= 0);
+ if (ret<0) return ret;
+ else ptr+=ret;
+ }
+
+ // fix the total size
+ rev4(ptr,&data[8]);
+
+ return ptr;
+}
+
+iPod_mhod * iPod_mhit::AddString(const int type)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhit_AddString);
+#endif
+
+ iPod_mhod * m;
+ if (type)
+ {
+ m = FindString(type);
+ if (m != NULL)
+ {
+ return m;
+ }
+ }
+
+ m=new iPod_mhod;
+ if (m!=NULL && type) m->type=type;
+ mhod.push_back(m);
+ if(m->type <= 25 && m->type >= 1) mhodcache[m->type-1] = m;
+ return m;
+}
+
+iPod_mhod * iPod_mhit::FindString(const unsigned long type) const
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhit_FindString);
+#endif
+
+ if(type <= 25 && type >= 1) return mhodcache[type-1];
+
+ const unsigned long children = GetChildrenCount();
+ for (unsigned long i=0;i<children;i++)
+ {
+ if (mhod[i]->type == type) return mhod[i];
+ }
+
+ return NULL;
+}
+
+unsigned long iPod_mhit::DeleteString(const unsigned long type)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhit_DeleteString);
+#endif
+ if(type <= 25 && type >= 1) mhodcache[type-1] = NULL;
+ unsigned long count=0;
+
+ for (unsigned long i=0; i != GetChildrenCount(); i++)
+ {
+ if (mhod[i]->type == type)
+ {
+ iPod_mhod * m = mhod.at(i);
+ mhod.erase(mhod.begin() + i);
+ delete m;
+ i = i > 0 ? i - 1 : 0; // do this to ensure that it checks the new entry in position i next
+ count++;
+ }
+ }
+ return count;
+}
+
+unsigned int iPod_mhit::GetFileTypeID(const wchar_t *filename)
+{
+ ASSERT(filename);
+ if(filename == NULL)
+ return(0);
+
+ // Incredibly, this is really the file extension as ASCII characters
+ // e.g. 0x4d = 'M', 0x50 = 'P', 0x33 = '3', 0x20 = '<space>'
+ if(wcsistr(filename, L".mp3") != NULL)
+ return FILETYPE_MP3;
+ else if(wcsistr(filename, L".m4a") != NULL)
+ return FILETYPE_M4A;
+ else if(wcsistr(filename, L".m4b") != NULL)
+ return(0x4d344220);
+ else if(wcsistr(filename, L".m4p") != NULL)
+ return(0x4d345020);
+ else if(wcsistr(filename, L".wav") != NULL)
+ return FILETYPE_WAV;
+
+ return(0);
+}
+
+
+iPod_mhit& iPod_mhit::operator=(const iPod_mhit& src)
+{
+ Duplicate(&src,this);
+ return *this;
+}
+
+void iPod_mhit::Duplicate(const iPod_mhit *src, iPod_mhit *dst)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhit_Duplicate);
+#endif
+
+ if(src == NULL || dst == NULL)
+ return;
+
+ dst->id = src->id;
+ dst->visible = src->visible;
+ dst->filetype = src->filetype;
+ dst->vbr = src->vbr;
+ dst->type = src->type;
+ dst->compilation = src->compilation;
+ dst->stars = src->stars;
+ dst->lastmodifiedtime = src->lastmodifiedtime;
+ dst->size = src->size;
+ dst->length = src->length;
+ dst->tracknum = src->tracknum;
+ dst->totaltracks = src->totaltracks;
+ dst->year = src->year;
+ dst->bitrate = src->bitrate;
+ dst->samplerate = src->samplerate;
+ dst->samplerate_fixedpoint = src->samplerate_fixedpoint;
+ dst->volume = src->volume;
+ dst->starttime = src->starttime;
+ dst->stoptime = src->stoptime;
+ dst->soundcheck = src->soundcheck;
+ dst->playcount = src->playcount;
+ dst->playcount2 = src->playcount2;
+ dst->lastplayedtime = src->lastplayedtime;
+ dst->cdnum = src->cdnum;
+ dst->totalcds = src->totalcds;
+ dst->userID = src->userID;
+ dst->addedtime = src->addedtime;
+ dst->bookmarktime = src->bookmarktime;
+ dst->dbid = src->dbid;
+ dst->BPM = src->BPM;
+ dst->app_rating = src->app_rating;
+ dst->checked = src->checked;
+ dst->unk9 = src->unk9;
+ dst->artworksize = src->artworksize;
+ dst->unk11 = src->unk11;
+ dst->samplerate2 = src->samplerate2;
+ dst->releasedtime = src->releasedtime;
+ dst->unk14 = src->unk14;
+ dst->unk15 = src->unk15;
+ dst->unk16 = src->unk16;
+ dst->skipcount = src->skipcount;
+ dst->skippedtime = src->skippedtime;
+ dst->hasArtwork = src->hasArtwork;
+ dst->skipShuffle = src->skipShuffle;
+ dst->rememberPosition = src->rememberPosition;
+ dst->unk19 = src->unk19;
+ dst->dbid2 = src->dbid2;
+ dst->lyrics_flag = src->lyrics_flag;
+ dst->movie_flag = src->movie_flag;
+ dst->mark_unplayed = src->mark_unplayed;
+ dst->unk20 = src->unk20;
+ dst->unk21 = src->unk21;
+ dst->pregap = src->pregap;
+ dst->samplecount = src->samplecount;
+ dst->unk25 = src->unk25;
+ dst->postgap = src->postgap;
+ dst->unk27 = src->unk27;
+ dst->mediatype = src->mediatype;
+ dst->seasonNumber = src->seasonNumber;
+ dst->episodeNumber = src->episodeNumber;
+ dst->unk31 = src->unk31;
+ dst->unk32 = src->unk32;
+ dst->unk33 = src->unk33;
+ dst->unk34 = src->unk34;
+ dst->unk35 = src->unk35;
+ dst->unk36 = src->unk36;
+ dst->unk37 = src->unk37;
+ dst->gaplessData = src->gaplessData;
+ dst->unk39 = src->unk39;
+ dst->albumgapless = src->albumgapless;
+ dst->trackgapless = src->trackgapless;
+ dst->unk40 = src->unk40;
+ dst->unk41 = src->unk41;
+ dst->unk42 = src->unk42;
+ dst->unk43 = src->unk43;
+ dst->unk44 = src->unk44;
+ dst->unk45 = src->unk45;
+ dst->unk46 = src->unk46;
+ dst->album_id = src->album_id;
+ dst->unk48 = src->unk48;
+ dst->unk49 = src->unk49;
+ dst->unk50 = src->unk50;
+ dst->unk51 = src->unk51;
+ dst->unk52 = src->unk52;
+ dst->unk53 = src->unk53;
+ dst->unk54 = src->unk54;
+ dst->unk55 = src->unk55;
+ dst->unk56 = src->unk56;
+
+ dst->mhii_link = src->mhii_link;
+
+ const unsigned int mhodSize = src->mhod.size();
+ for(unsigned int i=0; i<mhodSize; i++)
+ {
+ iPod_mhod *src_mhod = src->mhod[i];
+ if(src_mhod == NULL)
+ continue;
+
+ iPod_mhod *dst_mhod = dst->AddString(src_mhod->type);
+ if(dst_mhod)
+ dst_mhod->Duplicate(src_mhod, dst_mhod);
+ }
+}
+
+int iPod_mhit::GetEQSetting()
+{
+ iPod_mhod *mhod = FindString(MHOD_EQSETTING);
+ if(mhod == NULL)
+ return(EQ_NONE);
+
+ ASSERT(lstrlen(mhod->str) == 9);
+ if(lstrlen(mhod->str) != 9)
+ return(EQ_NONE);
+
+ wchar_t strval[4] = {0};
+ lstrcpyn(strval, mhod->str + 3, 3);
+ int val = _wtoi(strval);
+ ASSERT(val >= EQ_ACOUSTIC && val <= EQ_VOCALBOOSTER);
+ return(val);
+}
+
+void iPod_mhit::SetEQSetting(int value)
+{
+ DeleteString(MHOD_EQSETTING);
+ if(value < 0)
+ return;
+
+ ASSERT(value >= EQ_ACOUSTIC && value <= EQ_VOCALBOOSTER);
+
+ wchar_t strval[10] = {0};
+ _snwprintf(strval, 9, L"#!#%d#!#", value);
+ strval[9] = '\0';
+
+ iPod_mhod *mhod = AddString(MHOD_EQSETTING);
+ ASSERT(mhod);
+ if(mhod == NULL)
+ return;
+
+ mhod->SetString(strval);
+}
+
+//////////////////////////////////////////////////////////////////////
+// iPod_mhod - Holds strings for a song or playlist, among other things
+//////////////////////////////////////////////////////////////////////
+
+iPod_mhod::iPod_mhod() :
+type(0),
+unk1(0),
+unk2(0),
+position(1),
+length(0),
+unk3(1),
+unk4(0),
+str(NULL),
+binary(NULL),
+liveupdate(1),
+checkrules(0),
+matchcheckedonly(0),
+limitsort_opposite(0),
+limittype(0),
+limitsort(0),
+limitvalue(0),
+unk5(0),
+rules_operator(SPLMATCH_AND),
+parseSmartPlaylists(true)
+{
+}
+
+
+iPod_mhod::~iPod_mhod()
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhod_destructor);
+#endif
+
+ if (str) delete [] str;
+ if (binary) delete [] binary;
+
+ const unsigned int size = rule.size();
+ for (unsigned int i=0;i<size;i++)
+ delete rule[i];
+}
+
+long iPod_mhod::parse(const uint8_t *data)
+{
+ size_t ptr=0;
+ unsigned long i = 0;
+
+ //check mhod header
+ if (_strnicmp((char *)&data[ptr],"mhod",4)) return -1;
+ ptr+=4;
+
+ // get sizes
+ size_head=read_uint32_t(data, ptr);
+ size_total=read_uint32_t(data, ptr);
+
+ ASSERT(size_head == 0x18);
+
+ // get type
+ type=read_uint32_t(data, ptr);
+
+ // dunno what these are, but they are definitely common among all the types of mhods
+ // smartlist types prove that.
+ // they're usually zero though.. null padding for the MHOD header?
+ unk1=read_uint32_t(data, ptr);
+ unk2=read_uint32_t(data, ptr);
+
+ if (iPod_mhod::IsSimpleStringType(type))
+ {
+ // string types get parsed
+ // 1 == UTF-16, 2 == UTF-8
+ // TODO: handle UTF-8
+ encoding_type=read_uint32_t(data, ptr);
+ length=read_uint32_t(data, ptr);
+ unk3=read_uint32_t(data, ptr);
+ unk4=read_uint32_t(data, ptr);
+
+ str=new wchar_t[length + 1];
+ memcpy(str,&data[ptr],length);
+ str[length / 2] = '\0';
+ ptr+=length;
+ }
+ else if (type == MHOD_ENCLOSUREURL || type == MHOD_RSSFEEDURL)
+ {
+ // Apple makes life hard again! These are almost like regular/simple MHOD string types,
+ // except the string is UTF-8 encoded and there is no length or position fields
+ length = size_total - size_head;
+ ASSERT(length > 0);
+ if(length > 0)
+ {
+ char *tmp = new char[length + 1];
+ ASSERT(tmp);
+ if(tmp != NULL)
+ {
+ memcpy(tmp, &data[ptr], length);
+ tmp[length] = '\0';
+
+ wchar_t *tmpUTF = UTF8_to_UTF16(tmp);
+ unsigned int len = wcslen(tmpUTF);
+ str=new wchar_t[len + 1];
+ wcsncpy(str, tmpUTF, len);
+ str[len] = '\0';
+
+ free(tmpUTF);
+ }
+
+ ptr+=length;
+ }
+ }
+ else if (type==MHOD_SPLPREF)
+ {
+ if(parseSmartPlaylists)
+ {
+ liveupdate=data[ptr]; ptr++;
+ checkrules=data[ptr]; ptr++;
+ checklimits=data[ptr]; ptr++;
+ limittype=data[ptr]; ptr++;
+ limitsort=data[ptr]; ptr++;
+ ptr+=3;
+ limitvalue=read_uint32_t(data, ptr);
+ matchcheckedonly=data[ptr]; ptr++;
+
+ // if the opposite flag is on, set limitsort's high bit
+ limitsort_opposite=data[ptr]; ptr++;
+ if(limitsort_opposite)
+ limitsort += 0x80000000;
+ }
+ }
+ else if (type==MHOD_SPLDATA)
+ {
+ if(parseSmartPlaylists)
+ {
+ // strangely, SPL Data is the only thing in the file that *isn't* byte reversed.
+ // check for SLst header
+ if (_strnicmp((char *)&data[ptr],"SLst",4)) return -1;
+ ptr+=4;
+ unk5=get4(&data[ptr]); ptr+=4;
+ const unsigned int numrules=get4(&data[ptr]); ptr+=4;
+ rules_operator=get4(&data[ptr]); ptr+=4;
+ ptr+=120;
+
+ rule.reserve(numrules);
+
+ for (i=0;i<numrules;i++)
+ {
+ SPLRule * r = new SPLRule;
+ ASSERT(r);
+ if(r == NULL)
+ continue;
+
+ r->field=get4(&data[ptr]); ptr+=4;
+ r->action=get4(&data[ptr]); ptr+=4;
+ ptr+=44;
+ r->length=get4(&data[ptr]); ptr+=4;
+
+#ifdef _DEBUG
+ switch(r->action)
+ {
+ case SPLACTION_IS_INT:
+ case SPLACTION_IS_GREATER_THAN:
+ case SPLACTION_IS_NOT_GREATER_THAN:
+ case SPLACTION_IS_LESS_THAN:
+ case SPLACTION_IS_NOT_LESS_THAN:
+ case SPLACTION_IS_IN_THE_RANGE:
+ case SPLACTION_IS_NOT_IN_THE_RANGE:
+ case SPLACTION_IS_IN_THE_LAST:
+ case SPLACTION_IS_STRING:
+ case SPLACTION_CONTAINS:
+ case SPLACTION_STARTS_WITH:
+ case SPLACTION_DOES_NOT_START_WITH:
+ case SPLACTION_ENDS_WITH:
+ case SPLACTION_DOES_NOT_END_WITH:
+ case SPLACTION_IS_NOT_INT:
+ case SPLACTION_IS_NOT_IN_THE_LAST:
+ case SPLACTION_IS_NOT:
+ case SPLACTION_DOES_NOT_CONTAIN:
+ case SPLACTION_BINARY_AND:
+ case SPLACTION_UNKNOWN2:
+ break;
+
+ default:
+ // New action!
+ //printf("New Action Discovered = %x\n",r->action);
+ ASSERT(0);
+ break;
+ }
+#endif
+
+ const bool hasString = iPod_slst::GetFieldType(r->field) == iPod_slst::ftString;
+
+ if(hasString)
+ {
+ // For some unknown reason, smart playlist strings have UTF-16 characters that are byte swapped
+ unsigned char *c = (unsigned char*)r->string;
+ const unsigned len = min(r->length, SPL_MAXSTRINGLENGTH);
+ for(unsigned int i=0; i<len; i+=2)
+ {
+ *(c + i) = data[ptr + i + 1];
+ *(c + i + 1) = data[ptr + i];
+ }
+
+ ptr += r->length;
+ }
+ else
+ {
+ // from/to combos always seem to be 0x44 in length in all cases...
+ // fix this to be smarter if it turns out not to be the case
+ ASSERT(r->length == 0x44);
+
+ r->fromvalue=get8(&data[ptr]); ptr+=8;
+ r->fromdate=get8(&data[ptr]); ptr+=8;
+ r->fromunits=get8(&data[ptr]); ptr+=8;
+
+ r->tovalue=get8(&data[ptr]); ptr+=8;
+ r->todate=get8(&data[ptr]); ptr+=8;
+ r->tounits=get8(&data[ptr]); ptr+=8;
+
+ // SPLFIELD_PLAYLIST seems to use the unks here...
+ r->unk1=get4(&data[ptr]); ptr+=4;
+ r->unk2=get4(&data[ptr]); ptr+=4;
+ r->unk3=get4(&data[ptr]); ptr+=4;
+ r->unk4=get4(&data[ptr]); ptr+=4;
+ r->unk5=get4(&data[ptr]); ptr+=4;
+ }
+
+ rule.push_back(r);
+ }
+ }
+ }
+ else if(type == MHOD_PLAYLIST)
+ {
+ position=read_uint32_t(data, ptr);
+
+ // Skip to the end
+ ptr+=16;
+ }
+ else
+ {
+ // non string/smart playlist types get copied in.. with the header and such being ignored
+ binary=new unsigned char[size_total-size_head];
+ memcpy(binary,&data[ptr],size_total-size_head);
+ // in this case, we'll use the length field to store the length of the binary stuffs,
+ // since it's not being used for anything else in these entries.
+ // this helps in the writing phase of the process.
+ // note that if, for some reason, you decide to create a mhod for type 50+ from scratch,
+ // you need to set the length = the size of your binary space
+ length=size_total-size_head;
+ }
+
+ return size_total;
+}
+
+long iPod_mhod::write(unsigned char * data, const unsigned long datasize)
+{
+ const unsigned long headsize=0x18;
+ // check for header size
+ if (headsize>datasize) return -1;
+
+ long ptr=0;
+
+ //write mhod header
+ data[0]='m';data[1]='h';data[2]='o';data[3]='d';
+ ptr+=4;
+
+ // write sizes
+ rev4(headsize,&data[ptr]); // header size
+ ptr+=4;
+ rev4(0x00,&data[ptr]); // placeholder for total size (fill in later)
+ ptr+=4;
+
+ // write stuff out
+ rev4(type,&data[ptr]);
+ ptr+=4;
+ rev4(unk1,&data[ptr]);
+ ptr+=4;
+ rev4(unk2,&data[ptr]);
+ ptr+=4;
+
+ if (iPod_mhod::IsSimpleStringType(type))
+ {
+ // check for string size
+ if (16+length+headsize>datasize) return -1;
+
+ rev4(position,&data[ptr]);
+ ptr+=4;
+ rev4(length,&data[ptr]);
+ ptr+=4;
+ rev4(unk3,&data[ptr]);
+ ptr+=4;
+ rev4(unk4,&data[ptr]);
+ ptr+=4;
+
+ const unsigned int len = length / 2;
+ for (unsigned int i=0;i<len;i++)
+ {
+ data[ptr]=str[i] & 0xff;
+ ptr++;
+ data[ptr]=(str[i] >> 8) & 0xff;
+ ptr++;
+ }
+ }
+ else if (type == MHOD_ENCLOSUREURL || type == MHOD_RSSFEEDURL)
+ {
+ // Convert the UTF-16 string back to UTF-8
+ char *utf8Str = UTF16_to_UTF8(str);
+ const unsigned int len = strlen(utf8Str);
+ if (16+len+headsize>datasize) { free(utf8Str); return -1; }
+ memcpy(data + ptr, utf8Str, len);
+ free(utf8Str);
+ ptr += len;
+ }
+ else if (type==MHOD_SPLPREF)
+ {
+ if (16+74 > datasize) return -1;
+
+ // write the type 50 mhod
+ data[ptr]=liveupdate; ptr++;
+ data[ptr]=checkrules; ptr++;
+ data[ptr]=checklimits; ptr++;
+ data[ptr]=(unsigned char)(limittype); ptr++;
+ data[ptr]=(unsigned char)((limitsort & 0x000000ff)); ptr++;
+ data[ptr]=0; ptr++;
+ data[ptr]=0; ptr++;
+ data[ptr]=0; ptr++;
+ rev4(limitvalue,&data[ptr]); ptr+=4;
+ data[ptr]=matchcheckedonly; ptr++;
+ // set the limitsort_opposite flag by checking the high bit of limitsort
+ data[ptr] = limitsort & 0x80000000 ? 1 : 0; ptr++;
+
+ // insert 58 nulls
+ memset(data + ptr, 0, 58); ptr += 58;
+ }
+ else if (type==MHOD_SPLDATA)
+ {
+ const unsigned int ruleCount = rule.size();
+
+ if (16+136+ (ruleCount*(124+515)) > datasize) return -1;
+
+ // put "SLst" header
+ data[ptr]='S';data[ptr+1]='L';data[ptr+2]='s';data[ptr+3]='t';
+ ptr+=4;
+ put4(unk5,&data[ptr]); ptr+=4;
+ put4(ruleCount,&data[ptr]); ptr+=4;
+ put4(rules_operator,&data[ptr]); ptr+=4;
+ memset(data + ptr, 0, 120); ptr+=120;
+
+ for (unsigned int i=0;i<ruleCount;i++)
+ {
+ SPLRule *r = rule[i];
+ ASSERT(r);
+ if(r == NULL)
+ continue;
+
+ put4(r->field,&data[ptr]); ptr+=4;
+ put4(r->action,&data[ptr]); ptr+=4;
+ memset(data + ptr, 0, 44); ptr+=44;
+ put4(r->length,&data[ptr]); ptr+=4;
+
+ const bool hasString = iPod_slst::GetFieldType(r->field) == iPod_slst::ftString;
+ if(hasString)
+ {
+ // Byte swap the characters
+ unsigned char *c = (unsigned char*)r->string;
+ for(unsigned int i=0; i<r->length; i+=2)
+ {
+ data[ptr + i] = *(c + i + 1);
+ data[ptr + i + 1] = *(c + i);
+ }
+
+ ptr += r->length;
+ }
+ else
+ {
+ put8(r->fromvalue,&data[ptr]); ptr+=8;
+ put8(r->fromdate,&data[ptr]); ptr+=8;
+ put8(r->fromunits,&data[ptr]); ptr+=8;
+ put8(r->tovalue,&data[ptr]); ptr+=8;
+ put8(r->todate,&data[ptr]); ptr+=8;
+ put8(r->tounits,&data[ptr]); ptr+=8;
+
+ put4(r->unk1,&data[ptr]); ptr+=4;
+ put4(r->unk2,&data[ptr]); ptr+=4;
+ put4(r->unk3,&data[ptr]); ptr+=4;
+ put4(r->unk4,&data[ptr]); ptr+=4;
+ put4(r->unk5,&data[ptr]); ptr+=4;
+
+ }
+ } // end for
+ }
+ else if(type == MHOD_PLAYLIST)
+ {
+ if (16+20 > datasize) return -1;
+
+ rev4(position,&data[ptr]); // position in playlist
+ ptr+=4;
+ rev4(0,&data[ptr]); // four nulls
+ ptr+=4;
+ rev4(0,&data[ptr]);
+ ptr+=4;
+ rev4(0,&data[ptr]);
+ ptr+=4;
+ rev4(0,&data[ptr]);
+ ptr+=4;
+ }
+ else // not a known type, use the binary
+ {
+ // check for binary size
+ if (length+headsize>datasize) return -1;
+ for (unsigned int i=0;i<length;i++)
+ {
+ data[ptr]=binary[i];
+ ptr++;
+ }
+ }
+
+ // fix the total size
+ rev4(ptr,&data[8]);
+
+ return ptr;
+}
+
+void iPod_mhod::SetString(const wchar_t *string)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhod_SetString);
+#endif
+
+ if(!string)
+ return;
+
+ delete [] str;
+ length = 0;
+
+ unsigned int stringLen = min(wcslen(string), 512);
+ str = new wchar_t[stringLen + 1];
+ memset(str, 0, sizeof(wchar_t) * (stringLen + 1));
+
+ if(str)
+ {
+ wcsncpy(str, string, stringLen);
+ length = stringLen * 2;
+ }
+}
+
+bool iPod_mhod::IsSimpleStringType(const unsigned int type)
+{
+ switch(type)
+ {
+ case MHOD_TITLE:
+ case MHOD_LOCATION:
+ case MHOD_ALBUM:
+ case MHOD_ARTIST:
+ case MHOD_GENRE:
+ case MHOD_FILETYPE:
+ case MHOD_EQSETTING:
+ case MHOD_COMMENT:
+ case MHOD_CATEGORY:
+ case MHOD_COMPOSER:
+ case MHOD_GROUPING:
+ case MHOD_DESCRIPTION:
+ case MHOD_SUBTITLE:
+ case MHOD_ALBUMARTIST:
+ case MHOD_ARTIST_SORT:
+ case MHOD_TITLE_SORT:
+ case MHOD_ALBUM_SORT:
+ case MHOD_ALBUMARTIST_SORT:
+ case MHOD_COMPOSER_SORT:
+ case MHOD_SHOW_SORT:
+ case MHOD_ALBUMLIST_ALBUM:
+ case MHOD_ALBUMLIST_ARTIST:
+ return(true);
+ }
+
+ return(false);
+}
+
+
+void iPod_mhod::Duplicate(iPod_mhod *src, iPod_mhod *dst)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhod_Duplicate);
+#endif
+
+ if(src == NULL || dst == NULL)
+ return;
+
+ dst->type = src->type;
+ dst->unk1 = src->unk1;
+ dst->unk2 = src->unk2;
+ dst->position = src->position;
+ dst->length = src->length;
+ dst->unk3 = src->unk3;
+ dst->unk4 = src->unk4;
+ dst->liveupdate = src->liveupdate;
+ dst->checkrules = src->checkrules;
+ dst->checklimits = src->checklimits;
+ dst->limittype = src->limittype;
+ dst->limitsort = src->limitsort;
+ dst->limitvalue = src->limitvalue;
+ dst->matchcheckedonly = src->matchcheckedonly;
+ dst->limitsort_opposite = src->limitsort_opposite;
+ dst->unk5 = src->unk5;
+ dst->rules_operator = src->rules_operator;
+
+ if(src->str)
+ {
+ dst->SetString(src->str);
+ }
+ else if(src->binary)
+ {
+ dst->binary = new unsigned char[src->length];
+ if(dst->binary)
+ memcpy(dst->binary, src->binary, src->length);
+ }
+
+
+ const unsigned int ruleLen = src->rule.size();
+ for(unsigned int i=0; i<ruleLen; i++)
+ {
+ SPLRule *srcRule = src->rule[i];
+ if(srcRule)
+ {
+ SPLRule *dstRule = new SPLRule;
+ if(dstRule)
+ memcpy(dstRule, srcRule, sizeof(SPLRule));
+
+ dst->rule.push_back(dstRule);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+// iPod_mhlp - Holds playlists
+//////////////////////////////////////////////////////////////////////
+
+iPod_mhlp::iPod_mhlp() :
+mhyp(),
+beingDeleted(false)
+{
+ // Always start off with an empty, hidden, default playlist
+ ASSERT(GetChildrenCount() == 0);
+ GetDefaultPlaylist();
+}
+
+iPod_mhlp::~iPod_mhlp()
+{
+ // This is unnecessary (and slow) to clear the vector list,
+ // since the object is being destroyed anyway...
+ beingDeleted = true;
+ ClearPlaylists();
+}
+
+long iPod_mhlp::parse(const uint8_t *data)
+{
+ long ptr=0;
+
+ //check mhlp header
+ if (_strnicmp((char *)&data[ptr],"mhlp",4)) return -1;
+ ptr+=4;
+
+ // get sizes
+ size_head=rev4(&data[ptr]);
+ ptr+=4;
+ const unsigned long children=rev4(&data[ptr]); // Only used locally - child count is obtained from the mhyp vector list
+ ptr+=4;
+
+ ASSERT(size_head == 0x5c);
+
+ // skip nulls
+ ptr=size_head;
+
+ mhyp.reserve(children); // pre allocate the space, for speed
+
+ ClearPlaylists();
+
+ long ret;
+ for (unsigned long i=0;i<children; i++)
+ {
+ iPod_mhyp *m = new iPod_mhyp;
+ ret=m->parse(&data[ptr]);
+ ASSERT(ret >= 0);
+ if (ret<0)
+ {
+ delete m;
+ return ret;
+ }
+
+ // If this is really a smart playlist, we need to parse it again as a smart playlist
+ if(m->FindString(MHOD_SPLPREF) != NULL)
+ {
+ delete m;
+ptr+=ret;
+continue;
+ m = new iPod_slst;
+ ASSERT(m);
+ ret = m->parse(&data[ptr]);
+ ASSERT(ret >= 0);
+ if(ret < 0)
+ {
+ delete m;
+ return ret;
+ }
+
+ }
+
+ ptr+=ret;
+ mhyp.push_back(m);
+ }
+
+ return ptr;
+}
+
+long iPod_mhlp::write(unsigned char * data, const unsigned long datasize, int index)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhlp_write);
+#endif
+
+ const unsigned int headsize=0x5c;
+ // check for header size
+ if (headsize>datasize) return -1;
+
+ long ptr=0;
+
+ //write mhlp header
+ data[0]='m';data[1]='h';data[2]='l';data[3]='p';
+ ptr+=4;
+
+ // write sizes
+ rev4(headsize,&data[ptr]); // header size
+ ptr+=4;
+
+ // write num of children
+ const unsigned long children = GetChildrenCount();
+ rev4(children,&data[ptr]);
+ ptr+=4;
+
+ // fill up the rest of the header with nulls
+ unsigned int i;
+ for (i=ptr;i<headsize;i++)
+ data[i]=0;
+ ptr=headsize;
+
+ long ret;
+ for (i=0;i<children; i++)
+ {
+ ret=mhyp[i]->write(&data[ptr],datasize-ptr,index);
+ ASSERT(ret >= 0);
+ if (ret<0) return ret;
+ ptr+=ret;
+ }
+
+ return ptr;
+}
+
+iPod_mhyp * iPod_mhlp::AddPlaylist()
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhlp_AddPlaylist);
+#endif
+
+ iPod_mhyp * m = new iPod_mhyp;
+ ASSERT(m);
+ if (m != NULL)
+ {
+ mhyp.push_back(m);
+ return m;
+ }
+ else return NULL;
+}
+
+
+iPod_mhyp * iPod_mhlp::FindPlaylist(const unsigned __int64 playlistID)
+{
+ const unsigned long count = GetChildrenCount();
+ for (unsigned long i=0; i<count; i++)
+ {
+ iPod_mhyp * m = GetPlaylist(i);
+ if (m->playlistID == playlistID)
+ return m;
+ }
+ return NULL;
+}
+
+
+// deletes the playlist at a position
+bool iPod_mhlp::DeletePlaylist(const unsigned long pos)
+{
+ if (GetChildrenCount() > pos)
+ {
+ iPod_mhyp *m = GetPlaylist(pos);
+ mhyp.erase(mhyp.begin() + pos);
+ delete m;
+ return true;
+ }
+ else return false;
+}
+
+bool iPod_mhlp::DeletePlaylistByID(const unsigned __int64 playlistID)
+{
+ if(playlistID == 0)
+ return(false);
+
+ const unsigned int count = GetChildrenCount();
+ for(unsigned int i=0; i<count; i++)
+ {
+ iPod_mhyp *m = GetPlaylist(i);
+ ASSERT(m);
+ if(m == NULL)
+ continue;
+
+ if(m->playlistID == playlistID)
+ return(DeletePlaylist(i));
+ }
+
+ return(false);
+}
+
+
+
+iPod_mhyp * iPod_mhlp::GetDefaultPlaylist()
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhlp_GetDefaultPlaylist);
+#endif
+
+ if (!mhyp.empty())
+ return GetPlaylist(0);
+ else
+ {
+ // Create a new hidden playlist, and set a default title
+ iPod_mhyp * playlist = AddPlaylist();
+ ASSERT(playlist);
+ if(playlist)
+ {
+ playlist->hidden = 1;
+
+ iPod_mhod *mhod = playlist->AddString(MHOD_TITLE);
+ if(mhod)
+ mhod->SetString(L"iPod");
+ }
+
+ return playlist;
+ }
+}
+
+bool iPod_mhlp::ClearPlaylists(const bool createDefaultPlaylist)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhlp_ClearPlaylists);
+#endif
+
+ const unsigned long count = GetChildrenCount();
+ for (unsigned long i=0;i<count;i++)
+ {
+ iPod_mhyp *m=GetPlaylist(i);
+ delete m;
+ }
+
+ if(!beingDeleted)
+ mhyp.clear();
+
+ // create the default playlist again, if it's gone
+ // XXX - Normally this is the right thing to do, but if we
+ // are about to parse the playlists from the iPod, we can't create
+ // the default playlist. Doing so will create two default/hidden
+ // playlists - this one and the one that will be created when
+ // the playlists are parsed!
+ if(createDefaultPlaylist)
+ GetDefaultPlaylist();
+
+ return true;
+}
+
+void iPod_mhlp::RemoveDeadPlaylistEntries(iPod_mhlt *mhlt)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhlp_RemoveDeadPlaylistEntries);
+#endif
+
+ if(mhlt == NULL)
+ return;
+
+ const unsigned int playlistCount = GetChildrenCount();
+ for(unsigned int i=0; i<playlistCount; i++)
+ {
+ iPod_mhyp *m = mhyp[i];
+ ASSERT(m);
+ if(m == NULL)
+ continue;
+
+ std::vector<unsigned int> deleteList;
+
+ const unsigned int songCount = m->GetMhipChildrenCount();
+ for(unsigned int j=0; j<songCount; j++)
+ {
+ iPod_mhip *p = m->mhip.at(j);
+ ASSERT(p);
+ if(p == NULL)
+ continue;
+
+ if(mhlt->GetTrackByID(p->songindex) != NULL)
+ continue;
+
+ // Found a dead song
+ deleteList.push_back(p->songindex);
+ }
+
+ const unsigned int deleteCount = deleteList.size();
+ for(unsigned int k=0; k<deleteCount; k++)
+ {
+ const bool retval = m->DeletePlaylistEntryByID(deleteList[k]);
+ ASSERT(retval == true);
+ }
+ }
+}
+
+void iPod_mhlp::SortPlaylists() {
+ std::sort(mhyp.begin(),mhyp.end(),iPod_mhyp());
+}
+
+//////////////////////////////////////////////////////////////////////
+// iPod_mhyp - A Playlist
+//////////////////////////////////////////////////////////////////////
+
+iPod_mhyp::iPod_mhyp() :
+hidden(0),
+timestamp(0),
+unk3(0),
+numStringMHODs(0),
+podcastflag(0),
+numLibraryMHODs(0),
+mhod(),
+mhip(),
+mhit(NULL),
+isSmartPlaylist(false),
+isPopulated(true), // consider normal playlists to be populated always
+writeLibraryMHODs(true)
+{
+ timestamp = wintime_to_mactime(time(NULL));
+
+ // Create a highly randomized 64 bit value for the playlistID
+ playlistID = Generate64BitID();
+}
+
+iPod_mhyp::~iPod_mhyp()
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhyp_destructor);
+#endif
+
+ const unsigned long mhodCount = GetMhodChildrenCount();
+ const unsigned long mhipCount = GetMhipChildrenCount();
+ unsigned long i;
+ for (i=0;i<mhodCount;i++)
+ delete mhod[i];
+ for (i=0;i<mhipCount;i++)
+ delete mhip[i];
+}
+
+long iPod_mhyp::parse(const uint8_t *data)
+{
+ size_t ptr=0;
+
+ //check mhyp header
+ if (_strnicmp((char *)&data[ptr],"mhyp",4)) return -1;
+ ptr+=4;
+
+ // get sizes
+ size_head=read_uint32_t(data, ptr);
+ size_total=read_uint32_t(data, ptr);
+
+ ASSERT(size_head == 0x6c || size_head == 0x8c);
+
+ const unsigned long mhodnum=read_uint32_t(data, ptr); // only used locally
+ const unsigned long numsongs=read_uint32_t(data, ptr); // only used locally
+ hidden=read_uint32_t(data, ptr);
+ timestamp=read_uint32_t(data, ptr);
+ playlistID = rev8(get8(&data[ptr]));
+ if(playlistID == 0)
+ {
+ // Force the playlistID to be a valid value.
+ // This may not always be the right thing to do, but I can't think of any reason why it wouldn't be ok...
+ playlistID = Generate64BitID();
+ }
+ ptr+=8;
+ unk3=read_uint32_t(data, ptr);
+ unsigned long temp = rev4(&data[ptr]);
+ numStringMHODs = temp && 0xFFFF;
+ podcastflag = (uint16_t)(temp >> 16);
+ ptr+=4;
+ numLibraryMHODs=read_uint32_t(data, ptr);
+
+ ptr=size_head;
+
+ long ret;
+ unsigned long i;
+
+ mhod.reserve(mhodnum); // pre allocate the space, for speed
+ mhip.reserve(numsongs);
+
+ for (i=0;i<mhodnum;i++)
+ {
+ iPod_mhod *m = new iPod_mhod;
+
+ // parseSmartPlaylists is an optimization for when dealing with smart playlists.
+ // Since the playlist has to be parsed in order to determine if it is a smart playlist,
+ // and if it is, parsed again as a smart playlist, this optimization prevents some duplicate parsing.
+ m->parseSmartPlaylists = isSmartPlaylist;
+ ret=m->parse(&data[ptr]);
+ ASSERT(ret >= 0);
+ if (ret<0)
+ {
+ delete m;
+ continue;
+ return ret;
+ }
+
+ ptr+=ret;
+
+ // Don't add Type 52 MHODs - if the file changes, the indexes are no longer valid
+ if(m->type == MHOD_LIBRARY || m->type == MHOD_LIBRARY_LETTER)
+ {
+ delete m;
+ continue;
+ }
+
+ // Reset the Type 52 MHOD count to zero
+ numLibraryMHODs = 0;
+
+ if(m->type == MHOD_PLAYLIST)
+ delete m; // fuck 'em!
+ else
+ mhod.push_back(m);
+
+ }
+
+ for (i=0;i<numsongs;i++)
+ {
+ iPod_mhip *m = new iPod_mhip;
+ ret=m->parse(&data[ptr]);
+ ASSERT(ret >= 0);
+ if (ret<0)
+ {
+ delete m;
+ return ret;
+ }
+ else
+ {
+ ptr+=ret;
+ }
+ mhip.push_back(m);
+ }
+
+ return ptr;
+}
+
+long iPod_mhyp::write(unsigned char * data, const unsigned long datasize, int index)
+{
+
+ const unsigned int headsize=0x6c;
+ // check for header size
+ ASSERT(headsize <= datasize);
+ if (headsize>datasize) return -1;
+
+ size_t ptr=0;
+
+ // List of Type 52 MHODs to write
+ unsigned int indexType[] = { TYPE52_SONG_NAME, TYPE52_ARTIST, TYPE52_ALBUM, TYPE52_GENRE, TYPE52_COMPOSER };
+ const unsigned int indexTypeCount = sizeof(indexType) / sizeof(unsigned int);
+
+ //write mhyp header
+ data[0]='m';data[1]='h';data[2]='y';data[3]='p';
+ ptr+=4;
+
+ // write sizes
+ write_uint32_t(data, ptr, headsize);// header size
+ write_uint32_t(data, ptr, 0); // placeholder for total size (fill in later)
+
+ writeLibraryMHODs = true;
+ bool writeType52MHOD = writeLibraryMHODs && (hidden > 0 && mhit != NULL);
+
+ // fill in stuff
+ const unsigned long mhodnum = GetMhodChildrenCount();
+
+ numStringMHODs = (uint16_t)mhodnum;
+
+ if(writeType52MHOD)
+ {
+ write_uint32_t(data, ptr, mhodnum + indexTypeCount); // Include the extra MHOD Type 52s that aren't in the MHOD list
+ numLibraryMHODs = indexTypeCount;
+ }
+ else
+ {
+ write_uint32_t(data, ptr, mhodnum);
+ }
+
+ const unsigned long numsongs = GetMhipChildrenCount();
+ write_uint32_t(data, ptr, numsongs);
+ write_uint32_t(data, ptr, hidden);
+ write_uint32_t(data, ptr, timestamp);
+
+ put8(rev8(playlistID),&data[ptr]);
+ ptr+=8;
+ write_uint32_t(data, ptr, unk3);
+ unsigned long temp = numStringMHODs | podcastflag << 16;
+ rev4(temp,&data[ptr]);
+ ptr+=4;
+ write_uint32_t(data, ptr, numLibraryMHODs);
+
+ unsigned long i;
+ // fill up the rest of the header with nulls
+ for (i=ptr;i<headsize;i++)
+ data[i]=0;
+ ptr=headsize;
+
+ long ret;
+ for (i=0;i<mhodnum; i++)
+ {
+ ret=mhod[i]->write(&data[ptr],datasize-ptr);
+ ASSERT(ret >= 0);
+ if (ret<0) return ret;
+ else ptr+=ret;
+ }
+
+ // If this is the default hidden playlist, create the type 52 MHODs that are used to accelerate the browse menus
+ if(writeType52MHOD)
+ {
+
+ /*
+ header identifier | 4 | mhod
+ header length | 4 | size of the mhod header
+ total length | 4 | size of the header and all the index entries
+ type | 4 | the type indicator ( 52 )
+ unk1 | 4 | unknown (always zero)
+ unk2 | 4 | unknown (always zero)
+ index type | 4 | what this index is sorted on (see list above)
+ count | 4 | number of entries. Always the same as the number of entries in the playlist, which is the same as the number of songs on the iPod.
+ null padding | 40| lots of padding
+ -----
+ 72 bytes (0x48)
+ index entries | 4 * count | The index entries themselves. This is an index into the mhit list, in order, starting from 0 for the first mhit.
+ */
+ for(unsigned int i=0; i<indexTypeCount; i++)
+ {
+ unsigned int mhodType = 0;
+ const unsigned int mhod52Type = indexType[i];
+
+ // Map the index type to the MHOD type
+ switch(mhod52Type)
+ {
+ case TYPE52_SONG_NAME:
+ mhodType = MHOD_TITLE;
+ break;
+ case TYPE52_ALBUM:
+ mhodType = MHOD_ALBUM;
+ break;
+ case TYPE52_ARTIST:
+ mhodType = MHOD_ARTIST;
+ break;
+ case TYPE52_GENRE:
+ mhodType = MHOD_GENRE;
+ break;
+ case TYPE52_COMPOSER:
+ mhodType = MHOD_COMPOSER;
+ break;
+ default:
+ ASSERT(0); // unknown type
+ mhodType = 0;
+ }
+
+ if(mhodType == 0)
+ continue;
+
+ ASSERT(mhit->size() == numsongs);
+ if(mhit->size() != numsongs)
+ continue;
+
+
+ // Start writing the MHOD...
+ const unsigned long headsize = 0x18;
+ const unsigned long totalsize = 0x48 + (4 * numsongs);
+
+ //write mhod header
+ data[ptr++]='m';data[ptr++]='h';data[ptr++]='o';data[ptr++]='d';
+
+ // write sizes
+
+
+ write_uint32_t(data, ptr, headsize); // header size
+ write_uint32_t(data, ptr, totalsize); // total size = 72 * (4 * number of songs)
+
+ // This is type 52 MHOD
+ write_uint32_t(data, ptr, MHOD_LIBRARY);
+
+ // Unknowns (always zero)
+ unsigned long unk1 = 0, unk2 = 0;
+ write_uint32_t(data, ptr, unk1);
+ write_uint32_t(data, ptr, unk2);
+
+ // What kind of index is this?
+ write_uint32_t(data, ptr, mhod52Type);
+
+ // Song Count
+ write_uint32_t(data, ptr, numsongs);
+
+ // 40 NULLs
+ for(unsigned int j=0;j<40;j++)
+ data[ptr++]=0;
+
+ // Build the sort by string vector list
+ std::vector<indexMhit*> strList;
+ strList.reserve(numsongs);
+
+ unsigned int ki = 0;
+ /*
+ iPod_mhlt::mhit_map_t::const_iterator begin = mhit->begin();
+ iPod_mhlt::mhit_map_t::const_iterator end = mhit->end();
+ for(iPod_mhlt::mhit_map_t::const_iterator it = begin; it != end; it++)
+ {
+ iPod_mhit *m = static_cast<iPod_mhit*>((*it).second);
+ */
+ int kl = mhip.size();
+ for(int k=0; k < kl; k++) {
+
+ iPod_mhit *m = mhit->find(mhip.at(k)->songindex)->second;
+
+ ASSERT(m != NULL);
+ if(m == NULL)
+ continue;
+
+ indexMhit *foo = new indexMhit;
+ foo->index = ki++;
+
+
+ iPod_mhod *d;
+ if(mhod52Type == TYPE52_COMPOSER) {
+ foo->track = 0;
+ foo->str[0] = L"";
+ foo->str[1] = L"";
+ d = m->FindString(MHOD_COMPOSER);
+ foo->str[2] = d?d->str:L"";
+ } else {
+ foo->track = (int)m->tracknum;
+ d = (mhod52Type >= TYPE52_GENRE)?m->FindString(MHOD_GENRE):NULL;
+ foo->str[0] = d?d->str:L"";
+ d = (mhod52Type >= TYPE52_ARTIST)?m->FindString(MHOD_ARTIST):NULL;
+ foo->str[1] = d?d->str:L"";
+ d = (mhod52Type >= TYPE52_ALBUM)?m->FindString(MHOD_ALBUM):NULL;
+ foo->str[2] = d?d->str:L"";
+ }
+ d = m->FindString(MHOD_TITLE);
+ foo->str[3] = d?d->str:L"";
+
+ strList.push_back(foo);
+ }
+
+ // Sort the list alphabetically
+ std::sort(strList.begin(), strList.end(), indexMhit());
+
+ // Write out the index entries
+ const unsigned indexCount = strList.size();
+ ASSERT(indexCount == numsongs);
+ for(unsigned int mi =0; mi<indexCount; mi++)
+ {
+ const unsigned int index = strList[mi]->index;
+ write_uint32_t(data, ptr, index);
+ }
+
+ // Free the list of indexMhits
+ for(unsigned int li=0;li<indexCount;li++)
+ {
+ delete strList[li];
+ }
+ }
+ }
+
+ int SongNum = 0;
+ for (i=0;i<numsongs;i++)
+ {
+ //FUCKO: use index here to write out podcast list differently
+ if(index == 3 || mhip[i]->podcastgroupflag == 0)
+ {
+ if(mhip[i]->podcastgroupflag == 0)
+ SongNum++;
+ unsigned long temp=0;
+ if(index == 2)
+ {
+ temp = mhip[i]->podcastgroupref;
+ mhip[i]->podcastgroupref = 0;
+ }
+ ret=mhip[i]->write(&data[ptr],datasize-ptr, SongNum);
+ if(index == 2)
+ mhip[i]->podcastgroupref=temp;
+ ASSERT(ret >= 0);
+ if (ret<0)
+ return ret;
+ else
+ ptr+=ret;
+ }
+ }
+
+ // fix the total size
+ rev4(ptr,&data[8]);
+ // fix number of songs written
+ if(index == 2) rev4(SongNum,&data[16]);
+
+ return ptr;
+}
+
+long iPod_mhyp::AddPlaylistEntry(iPod_mhip * entry, const unsigned long id)
+{
+ entry = new iPod_mhip;
+ ASSERT(entry != NULL);
+ if (entry !=NULL)
+ {
+ entry->songindex=id;
+ entry->timestamp = wintime_to_mactime(time(NULL));
+
+ mhip.push_back(entry);
+ return GetMhipChildrenCount()-1;
+ }
+ else return -1;
+}
+
+long iPod_mhyp::FindPlaylistEntry(const unsigned long id) const
+{
+ const unsigned long children = GetMhipChildrenCount();
+ for (unsigned long i=0;i<children;i++)
+ {
+ if (mhip.at(i)->songindex==id)
+ return i;
+ }
+ return -1;
+}
+
+bool iPod_mhyp::DeletePlaylistEntry(unsigned long pos)
+{
+ if (GetMhipChildrenCount() >= pos)
+ {
+ iPod_mhip * m = GetPlaylistEntry(pos);
+ if (pos < mhip.size())
+ {
+ mhip.erase(mhip.begin() + pos);
+ }
+ delete m;
+ return true;
+ }
+ return false;
+}
+
+bool iPod_mhyp::DeletePlaylistEntryByID(unsigned long songindex)
+{
+ // Search the list of mhips until the matching mhip(s) are found
+ bool retval = false;
+ unsigned int count = GetMhipChildrenCount();
+ for(unsigned int i=0; i<count; i++)
+ {
+ iPod_mhip *m = GetPlaylistEntry(i);
+ if(m->songindex == songindex)
+ {
+ DeletePlaylistEntry(i);
+ count = GetMhipChildrenCount();
+ i=0;
+ retval = true;
+ continue;
+ }
+ }
+
+ return(retval);
+}
+
+
+bool iPod_mhyp::ClearPlaylist()
+{
+ const unsigned long count = GetMhipChildrenCount();
+ for (unsigned long i=0;i<count;i++)
+ {
+ iPod_mhip * m = GetPlaylistEntry(i);
+ delete m;
+ }
+ mhip.clear();
+ return true;
+}
+
+long iPod_mhyp::PopulatePlaylist(iPod_mhlt * tracks, int hidden_field)
+{
+ ASSERT(tracks != NULL);
+ if(tracks == NULL)
+ return(-1);
+
+ const unsigned long trackCount = tracks->GetChildrenCount();
+ if(trackCount == 0)
+ return(0);
+
+ ClearPlaylist();
+
+ // Speed up getting the id as follows:
+ // Iterate the whole tracks->mhit map, storing the ids in a local vector
+ std::vector<unsigned long> ids;
+ ids.reserve(trackCount);
+
+ iPod_mhlt::mhit_map_t::const_iterator begin = tracks->mhit.begin();
+ iPod_mhlt::mhit_map_t::const_iterator end = tracks->mhit.end();
+ for(iPod_mhlt::mhit_map_t::const_iterator it = begin; it != end; it++)
+ ids.push_back(static_cast<unsigned long>((*it).first));
+
+ for (unsigned long i=0;i<trackCount;i++)
+ {
+ // Add the playlist entry locally rather than using
+ // AddPlaylistEntry() for speed optimization reasons
+ iPod_mhip *entry = new iPod_mhip;
+ ASSERT(entry != NULL);
+ if(entry)
+ {
+ entry->songindex = ids[i];
+ mhip.push_back(entry);
+ }
+ }
+
+ hidden=hidden_field;
+ return GetMhipChildrenCount();
+}
+
+iPod_mhod * iPod_mhyp::AddString(const int type)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhyp_AddString);
+#endif
+
+ iPod_mhod * m;
+ if (type)
+ {
+ m = FindString(type);
+ if (m!=NULL) return m;
+ }
+
+ m=new iPod_mhod;
+ if (m!=NULL && type) m->type=type;
+
+ mhod.push_back(m);
+ return m;
+}
+
+
+iPod_mhod * iPod_mhyp::FindString(const unsigned long type)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhyp_FindString);
+#endif
+
+ const unsigned long children = GetMhodChildrenCount();
+ for (unsigned long i=0;i<children;i++)
+ {
+ if (mhod[i]->type == type) return mhod[i];
+ }
+
+ return NULL;
+}
+
+unsigned long iPod_mhyp::DeleteString(const unsigned long type)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhyp_DeleteString);
+#endif
+
+ unsigned long count=0;
+
+ for (unsigned long i=0; i != GetMhodChildrenCount(); i++)
+ {
+ if (mhod[i]->type == type)
+ {
+ iPod_mhod * m = mhod.at(i);
+ mhod.erase(mhod.begin() + i);
+ delete m;
+ i = i > 0 ? i - 1 : 0; // do this to ensure that it checks the new entry in position i next
+ count++;
+ }
+ }
+ return count;
+}
+
+void iPod_mhyp::SetPlaylistTitle(const wchar_t *string)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhyp_SetPlaylistTitle);
+#endif
+
+ if(string == NULL)
+ return;
+
+ iPod_mhod *mhod = AddString(MHOD_TITLE);
+ ASSERT(mhod);
+ if(mhod)
+ mhod->SetString(string);
+}
+
+void iPod_mhyp::Duplicate(iPod_mhyp *src, iPod_mhyp *dst)
+{
+ if(src == NULL || dst == NULL)
+ return;
+
+ dst->hidden = src->hidden;
+ dst->timestamp = src->timestamp;
+ dst->playlistID = src->playlistID;
+ dst->unk3 = src->unk3;
+ dst->numStringMHODs = src->numStringMHODs;
+ dst->podcastflag = src->podcastflag;
+ dst->numLibraryMHODs = src->numLibraryMHODs;
+ dst->isSmartPlaylist = src->isSmartPlaylist;
+ dst->isPopulated = src->isPopulated;
+
+ const unsigned int mhodCount = src->mhod.size();
+ const unsigned int mhipCount = src->mhip.size();
+
+ unsigned int i;
+ for(i=0; i<mhodCount; i++)
+ {
+ iPod_mhod *mhod = dst->AddString();
+ ASSERT(mhod);
+ if(mhod)
+ {
+ iPod_mhod *srcMHOD = src->mhod[i];
+ ASSERT(srcMHOD);
+ if(srcMHOD)
+ mhod->Duplicate(srcMHOD, mhod);
+ }
+ }
+
+ for(i=0; i<mhipCount; i++)
+ {
+ iPod_mhip *mhip = NULL;
+ if(dst->AddPlaylistEntry(mhip) >= 0 && mhip != NULL)
+ {
+ iPod_mhip *srcMHIP = src->mhip[i];
+ ASSERT(srcMHIP);
+ if(srcMHIP)
+ mhip->Duplicate(srcMHIP, mhip);
+ }
+ }
+}
+
+bool iPod_mhyp::operator()(iPod_mhyp*& one, iPod_mhyp*& two) {
+ if(one->hidden & 0xff) return true;
+ if(two->hidden & 0xff) return false;
+ wchar_t * a = one->FindString(MHOD_TITLE)->str;
+ wchar_t * b = two->FindString(MHOD_TITLE)->str;
+ return _wcsicmp(a?a:L"",b?b:L"") < 0;
+}
+
+//////////////////////////////////////////////////////////////////////
+// iPod_mhip - Playlist Entry
+//////////////////////////////////////////////////////////////////////
+iPod_mhip::iPod_mhip() :
+dataobjectcount(1),
+podcastgroupflag(0),
+groupid(0),
+songindex(0),
+timestamp(0),
+podcastgroupref(0)
+{
+}
+
+iPod_mhip::~iPod_mhip()
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhip_destructor);
+#endif
+}
+
+long iPod_mhip::parse(const uint8_t *data)
+{
+ long ptr=0;
+
+ //check mhyp header
+ if (_strnicmp((char *)&data[ptr],"mhip",4)) return -1;
+ ptr+=4;
+
+ // get sizes
+ size_head=rev4(&data[ptr]);
+ ptr+=4;
+ size_total=rev4(&data[ptr]);
+ ptr+=4;
+
+ ASSERT(size_head == 0x4c);
+
+ // read in the useful info
+ dataobjectcount=rev4(&data[ptr]); //data object count
+ ptr+=4;
+ podcastgroupflag=rev4(&data[ptr]); //podcast group flag
+ ptr+=4;
+ groupid=rev4(&data[ptr]); // group id
+ ptr+=4;
+ songindex=rev4(&data[ptr]); //trackid
+ ptr+=4;
+ timestamp=rev4(&data[ptr]); // timestamp
+ ptr+=4;
+ podcastgroupref=rev4(&data[ptr]); // group ref
+ ptr+=4;
+
+ ptr=size_head;
+
+ // dump the mhod after the mhip, as it's just a position number in the playlist
+ // and useless to read in since we get them in order anyway
+ for(uint32_t i=0; i!=dataobjectcount; i++) {
+ iPod_mhod *m = new iPod_mhod;
+ long ret = m->parse(&data[ptr]);
+ ASSERT(ret >= 0);
+ if(ret<0) return ret;
+ ptr+=ret;
+ if(m->type == 100) delete m; //fuck 'em
+ else mhod.push_back(m);
+ }
+
+ return ptr;
+}
+
+
+long iPod_mhip::write(unsigned char * data, const unsigned long datasize, int entrynum)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhip_write);
+#endif
+
+ long ptr=0;
+
+ const unsigned int headsize=0x4c;
+ // check for header size and mhod size
+ if (headsize+0x2c>datasize)
+ {
+ ASSERT(0);
+ return -1;
+ }
+
+ //write mhip header
+ data[0]='m';data[1]='h';data[2]='i';data[3]='p';
+ ptr+=4;
+
+ // write sizes
+ rev4(headsize,&data[ptr]); // header size
+ ptr+=4;
+ //rev4(headsize,&data[ptr]); // mhips have no children or subdata
+ ptr+=4;
+
+ // fill in stuff
+ rev4(mhod.size() + ((podcastgroupflag!=0)?0:1),&data[ptr]);
+ ptr+=4;
+ rev4(podcastgroupflag,&data[ptr]);
+ ptr+=4;
+ rev4(groupid,&data[ptr]);
+ ptr+=4;
+ rev4(songindex,&data[ptr]);
+ ptr+=4;
+ rev4(timestamp,&data[ptr]);
+ ptr+=4;
+ rev4(podcastgroupref,&data[ptr]);
+ ptr+=4;
+
+ // fill up the rest of the header with nulls
+ for (unsigned int i=ptr;i<headsize;i++)
+ data[i]=0;
+ ptr=headsize;
+
+ if(!podcastgroupflag) {
+ // create an faked up mhod type 100 for position info
+ // (required at this point, albeit seemingly useless.. type 100 mhods are weird)
+ data[ptr]='m';data[ptr+1]='h';data[ptr+2]='o';data[ptr+3]='d';
+ ptr+=4;
+ rev4(0x18,&data[ptr]); // header size
+ ptr+=4;
+ rev4(0x2c,&data[ptr]); // total size
+ ptr+=4;
+ rev4(100,&data[ptr]); // type
+ ptr+=4;
+ rev4(0,&data[ptr]); // two nulls
+ ptr+=4;
+ rev4(0,&data[ptr]);
+ ptr+=4;
+ rev4(entrynum,&data[ptr]); // position in playlist
+ ptr+=4;
+ rev4(0,&data[ptr]); // four nulls
+ ptr+=4;
+ rev4(0,&data[ptr]);
+ ptr+=4;
+ rev4(0,&data[ptr]);
+ ptr+=4;
+ rev4(0,&data[ptr]);
+ ptr+=4;
+ // the above code could be more optimized, but this is simpler to read, methinks
+ }
+
+ for(unsigned long i = 0; i < mhod.size(); i++) {
+ long ret = mhod[i]->write(&data[ptr],datasize-ptr);
+ ASSERT(ret >= 0);
+ if(ret<0) return ret;
+ else ptr+=ret;
+ }
+ rev4(ptr,&data[8]);
+ return ptr;
+}
+
+void iPod_mhip::Duplicate(iPod_mhip *src, iPod_mhip *dst)
+{
+ if(src == NULL || dst == NULL)
+ return;
+
+ dst->dataobjectcount = src->dataobjectcount;
+ dst->podcastgroupflag = src->podcastgroupflag;
+ dst->groupid = src->groupid;
+ dst->songindex = src->songindex;
+ dst->timestamp = src->timestamp;
+ dst->podcastgroupref = src->podcastgroupref;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////
+// iPod_slst - Smart Playlist
+//////////////////////////////////////////////////////////////////////
+
+iPod_slst::iPod_slst() :
+splPref(NULL),
+splData(NULL)
+{
+ isSmartPlaylist = true;
+ isPopulated = false; // smart playlists are not considered populated by default
+ Reset();
+}
+
+iPod_slst::~iPod_slst()
+{
+ RemoveAllRules();
+}
+
+
+iPod_slst::FieldType iPod_slst::GetFieldType(const unsigned long field)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_slst_GetFieldType);
+#endif
+
+ switch(field)
+ {
+ case SPLFIELD_SONG_NAME:
+ case SPLFIELD_ALBUM:
+ case SPLFIELD_ARTIST:
+ case SPLFIELD_GENRE:
+ case SPLFIELD_KIND:
+ case SPLFIELD_COMMENT:
+ case SPLFIELD_COMPOSER:
+ case SPLFIELD_GROUPING:
+ return(ftString);
+
+ case SPLFIELD_BITRATE:
+ case SPLFIELD_SAMPLE_RATE:
+ case SPLFIELD_YEAR:
+ case SPLFIELD_TRACKNUMBER:
+ case SPLFIELD_SIZE:
+ case SPLFIELD_PLAYCOUNT:
+ case SPLFIELD_DISC_NUMBER:
+ case SPLFIELD_BPM:
+ case SPLFIELD_RATING:
+ case SPLFIELD_TIME: // time is the length of the track in milliseconds
+ case SPLFIELD_VIDEO_KIND:
+ return(ftInt);
+
+ case SPLFIELD_COMPILATION:
+ return(ftBoolean);
+
+ case SPLFIELD_DATE_MODIFIED:
+ case SPLFIELD_DATE_ADDED:
+ case SPLFIELD_LAST_PLAYED:
+ return(ftDate);
+
+ case SPLFIELD_PLAYLIST:
+ return(ftPlaylist);
+
+ default:
+ // Unknown field type
+ ASSERT(0);
+ }
+
+ return(ftUnknown);
+}
+
+iPod_slst::ActionType iPod_slst::GetActionType(const unsigned long field, const unsigned long action)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_slst_GetActionType);
+#endif
+
+ const FieldType fieldType = GetFieldType(field);
+ switch(fieldType)
+ {
+ case ftString:
+ switch(action)
+ {
+ case SPLACTION_IS_STRING:
+ case SPLACTION_IS_NOT:
+ case SPLACTION_CONTAINS:
+ case SPLACTION_DOES_NOT_CONTAIN:
+ case SPLACTION_STARTS_WITH:
+ case SPLACTION_DOES_NOT_START_WITH:
+ case SPLACTION_ENDS_WITH:
+ case SPLACTION_DOES_NOT_END_WITH:
+ return(atString);
+
+ case SPLACTION_IS_NOT_IN_THE_RANGE:
+ case SPLACTION_IS_INT:
+ case SPLACTION_IS_NOT_INT:
+ case SPLACTION_IS_GREATER_THAN:
+ case SPLACTION_IS_NOT_GREATER_THAN:
+ case SPLACTION_IS_LESS_THAN:
+ case SPLACTION_IS_NOT_LESS_THAN:
+ case SPLACTION_IS_IN_THE_RANGE:
+ case SPLACTION_IS_IN_THE_LAST:
+ case SPLACTION_IS_NOT_IN_THE_LAST:
+ return(atInvalid);
+
+ default:
+ // Unknown action type
+ ASSERT(0);
+ return(atUnknown);
+ }
+ break;
+
+ case ftInt:
+ switch(action)
+ {
+ case SPLACTION_IS_INT:
+ case SPLACTION_IS_NOT_INT:
+ case SPLACTION_IS_GREATER_THAN:
+ case SPLACTION_IS_NOT_GREATER_THAN:
+ case SPLACTION_IS_LESS_THAN:
+ case SPLACTION_IS_NOT_LESS_THAN:
+ return(atInt);
+
+ case SPLACTION_IS_NOT_IN_THE_RANGE:
+ case SPLACTION_IS_IN_THE_RANGE:
+ return(atRange);
+
+ case SPLACTION_IS_STRING:
+ case SPLACTION_CONTAINS:
+ case SPLACTION_STARTS_WITH:
+ case SPLACTION_DOES_NOT_START_WITH:
+ case SPLACTION_ENDS_WITH:
+ case SPLACTION_DOES_NOT_END_WITH:
+ case SPLACTION_IS_IN_THE_LAST:
+ case SPLACTION_IS_NOT_IN_THE_LAST:
+ case SPLACTION_IS_NOT:
+ case SPLACTION_DOES_NOT_CONTAIN:
+ return(atInvalid);
+
+ default:
+ // Unknown action type
+ ASSERT(0);
+ return(atUnknown);
+ }
+ break;
+
+ case ftBoolean:
+ return(atNone);
+
+ case ftDate:
+ switch(action)
+ {
+ case SPLACTION_IS_INT:
+ case SPLACTION_IS_NOT_INT:
+ case SPLACTION_IS_GREATER_THAN:
+ case SPLACTION_IS_NOT_GREATER_THAN:
+ case SPLACTION_IS_LESS_THAN:
+ case SPLACTION_IS_NOT_LESS_THAN:
+ return(atDate);
+
+ case SPLACTION_IS_IN_THE_LAST:
+ case SPLACTION_IS_NOT_IN_THE_LAST:
+ return(atInTheLast);
+
+ case SPLACTION_IS_IN_THE_RANGE:
+ case SPLACTION_IS_NOT_IN_THE_RANGE:
+ return(atRange);
+
+ case SPLACTION_IS_STRING:
+ case SPLACTION_CONTAINS:
+ case SPLACTION_STARTS_WITH:
+ case SPLACTION_DOES_NOT_START_WITH:
+ case SPLACTION_ENDS_WITH:
+ case SPLACTION_DOES_NOT_END_WITH:
+ case SPLACTION_IS_NOT:
+ case SPLACTION_DOES_NOT_CONTAIN:
+ return(atInvalid);
+
+ default:
+ // Unknown action type
+ ASSERT(0);
+ return(atUnknown);
+ }
+ break;
+
+ case ftPlaylist:
+ switch(action)
+ {
+ case SPLACTION_IS_INT:
+ case SPLACTION_IS_NOT_INT:
+ return (atPlaylist);
+
+ case SPLACTION_IS_GREATER_THAN:
+ case SPLACTION_IS_NOT_GREATER_THAN:
+ case SPLACTION_IS_LESS_THAN:
+ case SPLACTION_IS_NOT_LESS_THAN:
+ case SPLACTION_IS_IN_THE_LAST:
+ case SPLACTION_IS_NOT_IN_THE_LAST:
+ case SPLACTION_IS_IN_THE_RANGE:
+ case SPLACTION_IS_NOT_IN_THE_RANGE:
+ case SPLACTION_IS_STRING:
+ case SPLACTION_CONTAINS:
+ case SPLACTION_STARTS_WITH:
+ case SPLACTION_DOES_NOT_START_WITH:
+ case SPLACTION_ENDS_WITH:
+ case SPLACTION_DOES_NOT_END_WITH:
+ case SPLACTION_IS_NOT:
+ case SPLACTION_DOES_NOT_CONTAIN:
+ return (atInvalid);
+
+ default:
+ ASSERT(0);
+ return(atUnknown);
+ }
+
+ case ftUnknown:
+ // Unknown action type
+ ASSERT(0);
+ break;
+ }
+
+ return(atUnknown);
+}
+
+
+void iPod_slst::UpdateMHODPointers()
+{
+ if(IsSmartPlaylist() == false)
+ return;
+
+ splPref = AddString(MHOD_SPLPREF);
+ splData = AddString(MHOD_SPLDATA);
+}
+
+void iPod_slst::SetPrefs(const bool liveupdate, const bool rules_enabled, const bool limits_enabled,
+ const unsigned long limitvalue, const unsigned long limittype, const unsigned long limitsort)
+{
+ UpdateMHODPointers();
+
+ ASSERT(splPref);
+ if(splPref)
+ {
+ splPref->liveupdate = liveupdate ? 1 : 0;
+ splPref->checkrules = rules_enabled ? 1 : 0;
+ splPref->checklimits = limits_enabled ? 1 : 0;
+ splPref->matchcheckedonly = 0;
+ splPref->limitsort_opposite = limitsort & 0x80000000 ? 1 : 0;
+ splPref->limittype = limittype;
+ splPref->limitsort = limitsort & 0x000000ff;
+ splPref->limitvalue = limitvalue;
+ }
+}
+
+unsigned long iPod_slst::GetRuleCount()
+{
+ UpdateMHODPointers();
+
+ ASSERT(splData);
+ if(splData == NULL)
+ return(0);
+
+ return(splData->rule.size());
+}
+
+
+int iPod_slst::AddRule(const unsigned long field,
+ const unsigned long action,
+ const wchar_t * string, // use string for string based rules
+ const unsigned __int64 value, // use value for single variable rules
+ const unsigned __int64 from, // use from and to for range based rules
+ const unsigned __int64 to,
+ const unsigned __int64 units) // use units for "In The Last" based rules
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_slst_AddRule);
+#endif
+
+ UpdateMHODPointers();
+
+ ASSERT(splPref != NULL && splData != NULL);
+ if (splPref == NULL || splData == NULL) return -1;
+
+ // create a new rule
+ SPLRule *r = new SPLRule;
+ ASSERT(r);
+ if(r == NULL)
+ return(-1);
+
+ const FieldType ft = GetFieldType(field);
+ const ActionType at = GetActionType(field, action);
+
+ if(ft == ftUnknown || at == atUnknown)
+ {
+ ASSERT(0);
+ return(-1);
+ }
+
+
+ r->field = field;
+ r->action = action;
+ r->unk1 = 0;
+ r->unk2 = 0;
+ r->unk3 = 0;
+ r->unk4 = 0;
+ r->unk5 = 0;
+
+ if(ft == ftString)
+ {
+ // it's a string type (SetString() sets the length)
+ r->SetString(string);
+ }
+ else
+ {
+ // All non-string rules currently have a length of 68 bytes
+ r->length = 0x44;
+
+ /* Values based on ActionType:
+ * int: fromvalue = value, fromdate = 0, fromunits = 1, tovalue = value, todate = 0, tounits = 1
+ * playlist: same as int
+ * boolean: same as int, except fromvalue/tovalue are 1 if set, 0 if not set
+ * date: same as int
+ * range: same as int, except use from and to, instead of value
+ * in the last: fromvalue = 0x2dae2dae2dae2dae (SPLDATE_IDENTIFIER), fromdate = 0xffffffffffffffff - value, fromunits = seconds in period,
+ * tovalue = 0x2dae2dae2dae2dae (SPLDATE_IDENTIFIER), todate = 0xffffffffffffffff - value, tounits = seconds in period
+ */
+ switch(at)
+ {
+ case atInt:
+ case atPlaylist:
+ case atDate:
+ r->fromvalue = value;
+ r->fromdate = 0;
+ r->fromunits = 1;
+ r->tovalue = value;
+ r->todate = 0;
+ r->tounits = 1;
+ break;
+ case atBoolean:
+ r->fromvalue = value > 0 ? 1 : 0;
+ r->fromdate = 0;
+ r->fromunits = 1;
+ r->tovalue = r->fromvalue;
+ r->todate = 0;
+ r->tounits = 1;
+ break;
+ case atRange:
+ r->fromvalue = from;
+ r->fromdate = 0;
+ r->fromunits = 1;
+ r->tovalue = to;
+ r->todate = 0;
+ r->tounits = 1;
+ break;
+ case atInTheLast:
+ r->fromvalue = SPLDATE_IDENTIFIER;
+ r->fromdate = ConvertNumToDateValue(value);
+ r->fromunits = units;
+ r->tovalue = SPLDATE_IDENTIFIER;
+ r->todate = ConvertNumToDateValue(value);
+ r->tounits = units;
+ break;
+ case atNone:
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ }
+
+ // set isPopulated to false, since we're modifying the rules
+ isPopulated = false;
+
+ // push the rule into the mhod
+ splData->rule.push_back(r);
+ return(splData->rule.size() - 1);
+}
+
+int iPod_slst::AddRule(const SPLRule &rule)
+{
+ UpdateMHODPointers();
+
+ ASSERT(splPref != NULL && splData != NULL);
+ if (splPref == NULL || splData == NULL)
+ return -1;
+
+ SPLRule *r = new SPLRule;
+ ASSERT(r);
+ if(r == NULL)
+ return(-1);
+
+ r->action = rule.action;
+ r->field = rule.field;
+ r->fromdate = rule.fromdate;
+ r->fromunits = rule.fromunits;
+ r->fromvalue = rule.fromvalue;
+ r->length = rule.length;
+ r->SetString(rule.string);
+ r->todate = rule.todate;
+ r->tounits = rule.tounits;
+ r->tovalue = rule.tovalue;
+ r->unk1 = rule.unk1;
+ r->unk2 = rule.unk2;
+ r->unk3 = rule.unk3;
+ r->unk4 = rule.unk4;
+ r->unk5 = rule.unk5;
+
+ // set isPopulated to false, since we're modifying the rules
+ isPopulated = false;
+
+ // push the rule into the mhod
+ splData->rule.push_back(r);
+ return(splData->rule.size() - 1);
+}
+
+void iPod_slst::RemoveAllRules()
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_slst_RemoveAllRules);
+#endif
+
+ // Note: Don't update MHOD pointers here...if they don't already exist, there is no point in creating them
+ if(splData == NULL)
+ return;
+
+ //while(splData->rule.size() > 0)
+ //{
+ // // set isPopulated to false, since we're modifying the rules
+ // isPopulated = false;
+
+ // SPLRule *r = splData->rule[0];
+ // splData->rule.eraseindex(0);
+ // delete r;
+ //}
+ auto it = splData->rule.begin();
+ while ( it != splData->rule.end())
+ {
+ // set isPopulated to false, since we're modifying the rules
+ isPopulated = false;
+
+ SPLRule* r = *it;
+ it = splData->rule.erase(it);
+ delete r;
+ }
+
+ splData->rule.clear();
+}
+
+
+void iPod_slst::Reset()
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_slst_Reset);
+#endif
+
+ // Note: Don't update MHOD pointers here...if they don't already exist, there is no point in creating them
+ RemoveAllRules();
+
+ isPopulated = false;
+
+ if(splPref)
+ {
+ splPref->liveupdate = 1;
+ splPref->checkrules = 1;
+ splPref->checklimits = 0;
+ splPref->matchcheckedonly = 0;
+ splPref->limittype = LIMITTYPE_SONGS;
+ splPref->limitsort = LIMITSORT_RANDOM;
+ splPref->limitsort_opposite = 0;
+ splPref->limitvalue = 25;
+ }
+
+ if(splData)
+ {
+ splData->rules_operator = SPLMATCH_AND;
+ splData->unk5 = 0;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+// iPod_mhdp - Class for parsing the Play Counts file
+//////////////////////////////////////////////////////////////////////
+
+iPod_mhdp::iPod_mhdp()
+{
+ children = 0;
+ entry = 0;
+}
+
+iPod_mhdp::~iPod_mhdp()
+{
+ free(entry);
+}
+
+long iPod_mhdp::parse(const uint8_t *data)
+{
+ long ptr=0;
+
+ //check mhdp header
+ if (_strnicmp((char *)&data[ptr],"mhdp",4)) return -1;
+ ptr+=4;
+
+ // get sizes
+ size_head=rev4(&data[ptr]);
+ ptr+=4;
+ entrysize=rev4(&data[ptr]);
+ ptr+=4;
+ if (entrysize != 0x10 && entrysize != 0x0c && entrysize != 0x14 && entrysize != 0x1c)
+ {
+ ASSERT(0);
+ return -1; // can't understand new versions of this file
+ }
+
+ children=rev4(&data[ptr]);
+ ptr+=4;
+
+ // skip dummy space
+ ptr=size_head;
+
+ unsigned long i;
+
+ entry = (PCEntry *)malloc(children * sizeof(PCEntry));
+
+ for (i=0;i<children;i++)
+ {
+ PCEntry &e = entry[i];
+
+ e.playcount=rev4(&data[ptr]);
+ ptr+=4;
+ e.lastplayedtime=rev4(&data[ptr]);
+ ptr+=4;
+ e.bookmarktime=rev4(&data[ptr]);
+ ptr+=4;
+ if (entrysize >= 0x10)
+ {
+ e.stars=rev4(&data[ptr]);
+ ptr+=4;
+ }
+ else
+ e.stars = 0;
+
+ if (entrysize >= 0x14)
+ {
+ e.unk1 = rev4(&data[ptr]);
+ ptr+=4;
+ }
+ else
+ e.unk1 = 0;
+
+ if (entrysize >= 0x1c)
+ {
+ e.skipcount = rev4(&data[ptr]);
+ ptr+=4;
+ e.skippedtime = rev4(&data[ptr]);
+ ptr+=4;
+ }
+ else
+ {
+ e.skipcount = 0;
+ e.skippedtime = 0;
+ }
+ }
+
+ return children;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// iPod_mhpo - Class for parsing the OTGPlaylist file
+//////////////////////////////////////////////////////////////////////
+
+iPod_mhpo::iPod_mhpo() :
+size_head(0),
+unk1(0),
+unk2(0)
+{
+ idList = 0;
+ children = 0;
+}
+
+iPod_mhpo::~iPod_mhpo()
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhpo_destructor);
+#endif
+ free(idList);
+}
+
+long iPod_mhpo::parse(const uint8_t *data)
+{
+ long ptr=0;
+
+ //check mhdp header
+ if (_strnicmp((char *)&data[ptr],"mhpo",4)) return -1;
+ ptr+=4;
+
+ // get sizes
+ size_head=rev4(&data[ptr]);
+ ptr+=4;
+
+ unk1=rev4(&data[ptr]);
+ ptr+=4;
+
+ children=rev4(&data[ptr]); // Only used locally
+ ptr+=4;
+
+ unk2=rev4(&data[ptr]);
+ ptr+=4;
+
+ if (ptr!=size_head) return -1; // if this isn't true, I screwed up somewhere
+
+ unsigned long i;
+
+ idList = (uint32_t *)malloc(children * sizeof(uint32_t));
+
+ for (i=0;i<children;i++)
+ {
+ unsigned long temp;
+ temp=rev4(&data[ptr]);
+ ptr+=4;
+ idList[i]=temp;
+ }
+
+ return ptr;
+}
+
+long iPod_mhpo::write(unsigned char * data, const unsigned long datasize)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iPod_mhpo_write);
+#endif
+
+ long ptr=0;
+
+ const unsigned int headsize=0x14;
+ // check for header size + child size
+ if (headsize+(GetChildrenCount()*4)>datasize) return -1;
+
+ //write mhpo header
+ data[0]='m';data[1]='h';data[2]='p';data[3]='o';
+ ptr+=4;
+
+ // write size
+ rev4(headsize,&data[ptr]); // header size
+ ptr+=4;
+
+ // fill in stuff
+ rev4(unk1,&data[ptr]);
+ ptr+=4;
+ const unsigned long children = GetChildrenCount();
+ rev4(children,&data[ptr]);
+ ptr+=4;
+ rev4(unk2,&data[ptr]);
+ ptr+=4;
+
+ for (unsigned long i=0;i<children;i++)
+ {
+ rev4(idList[i],&data[ptr]);
+ ptr+=4;
+
+ }
+ return ptr;
+}
+
+
+iPod_mhyp * iPod_mhpo::CreatePlaylistFromOTG(iPod_mhbd * iPodDB, wchar_t * name)
+{
+ // create playlist
+ iPod_mhyp * myplaylist = iPodDB->mhsdplaylists->mhlp->AddPlaylist();
+ if (myplaylist == NULL)
+ return NULL;
+
+ // set name
+ iPod_mhod * playlistName = myplaylist->AddString(MHOD_TITLE);
+ playlistName->SetString(name);
+
+ unsigned long count = GetChildrenCount();
+ // for every track
+ for (unsigned long i=0;i<count;i++)
+ {
+ // find the track
+ iPod_mhit * track = iPodDB->mhsdsongs->mhlt->GetTrack(idList[i]);
+
+ // myplaylist->AddPlaylistEntry(iPod_mhip * entry, track->id);
+
+ // Add the playlist entry locally rather than using
+ // AddPlaylistEntry() for speed optimization reasons
+ iPod_mhip *entry = new iPod_mhip;
+ ASSERT(entry != NULL);
+ if(entry && track)
+ {
+ entry->songindex = track->id;
+ myplaylist->mhip.push_back(entry);
+ }
+ }
+
+ return myplaylist;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// iPod_mqed - Class for parsing the EQ Presets file
+//////////////////////////////////////////////////////////////////////
+iPod_mqed::iPod_mqed() :
+unk1(1),
+unk2(1),
+eqList(),
+size_head(0x68)
+{
+}
+
+iPod_mqed::~iPod_mqed()
+{
+ const unsigned long count = GetChildrenCount();
+ for (unsigned long i=0;i<count;i++)
+ {
+ iPod_pqed * m=eqList[i];
+ delete m;
+ }
+ eqList.clear();
+}
+
+long iPod_mqed::parse(const uint8_t *data)
+{
+ unsigned long ptr=0;
+ uint32_t i;
+
+ //check mqed header
+ if (_strnicmp((char *)&data[ptr],"mqed",4)) return -1;
+ ptr+=4;
+
+ size_head=rev4(&data[ptr]);
+ ptr+=4;
+
+ ASSERT(size_head == 0x68);
+
+ unk1=rev4(&data[ptr]);
+ ptr+=4;
+ unk2=rev4(&data[ptr]);
+ ptr+=4;
+ unsigned long numchildren=rev4(&data[ptr]);
+ ptr+=4;
+ unsigned long childsize=rev4(&data[ptr]);
+ ptr+=4;
+
+ ASSERT(childsize == 588);
+ if (childsize != 588) return -1;
+
+ // skip the nulls
+ ptr=size_head;
+
+ for (i=0;i<numchildren;i++)
+ {
+ iPod_pqed * e = new iPod_pqed;
+ long ret = e->parse(&data[ptr]);
+ if (ret < 0)
+ {
+ delete e;
+ return ret;
+ }
+
+ eqList.push_back(e);
+ ptr+=ret;
+ }
+
+ return ptr;
+}
+
+
+long iPod_mqed::write(unsigned char * data, const unsigned long datasize)
+{
+ unsigned long ptr=0;
+ uint32_t i;
+
+ //write mqed header
+ data[0]='m';data[1]='q';data[2]='e';data[3]='d';
+ ptr+=4;
+
+ rev4(size_head,&data[ptr]);
+ ptr+=4;
+ rev4(unk1,&data[ptr]);
+ ptr+=4;
+ rev4(unk2,&data[ptr]);
+ ptr+=4;
+
+ rev4(GetChildrenCount(),&data[ptr]);
+ ptr+=4;
+
+ rev4(588,&data[ptr]);
+ ptr+=4;
+
+ // fill with nulls
+ while (ptr<size_head)
+ {
+ data[ptr]=0; ptr++;
+ }
+
+ // write the eq settings
+ for (i=0;i<GetChildrenCount();i++)
+ {
+ long ret=eqList[i]->write(&data[ptr],datasize-ptr);
+ if (ret <0) return -1;
+ ptr+=ret;
+ }
+
+ return ptr;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////
+// iPod_pqed - Class for parsing the EQ Entries
+//////////////////////////////////////////////////////////////////////
+iPod_pqed::iPod_pqed() :
+name(NULL),
+preamp(0)
+{
+ int i;
+ for (i=0;i<10;i++)
+ eq[i]=0;
+ for (i=0;i<5;i++)
+ short_eq[i]=0;
+}
+
+iPod_pqed::~iPod_pqed()
+{
+ if (name) delete [] name;
+}
+
+long iPod_pqed::parse(const uint8_t *data)
+{
+ unsigned long ptr=0;
+ uint32_t i;
+
+ //check pqed header
+ if (_strnicmp((char *)&data[ptr],"pqed",4)) return -1;
+ ptr+=4;
+
+ // get string length
+ length=data[ptr]; ptr++;
+ length+=data[ptr]*256; ptr++;
+
+ name=new wchar_t[length + 1];
+ memcpy(name,&data[ptr],length);
+ name[length / 2] = '\0';
+
+ // skip the nulls
+ ptr=516;
+
+ preamp = rev4(&data[ptr]);
+ ptr+=4;
+
+ unsigned long numbands;
+ numbands = rev4(&data[ptr]);
+ ptr+=4;
+
+ ASSERT (numbands == 10);
+ if (numbands != 10) return -1;
+
+ for (i=0;i!=numbands;i++)
+ {
+ eq[i]=rev4(&data[ptr]);
+ ptr+=4;
+ }
+
+ numbands = rev4(&data[ptr]);
+ ptr+=4;
+ ASSERT (numbands == 5);
+ if (numbands != 5) return -1;
+
+ for (i=0;i!=numbands;i++)
+ {
+ short_eq[i]=rev4(&data[ptr]);
+ ptr+=4;
+ }
+
+ return ptr;
+}
+
+long iPod_pqed::write(unsigned char * data, const unsigned long datasize)
+{
+ long ptr=0;
+ uint32_t i;
+
+ //write pqed header
+ data[0]='p';data[1]='q';data[2]='e';data[3]='d';
+ ptr+=4;
+
+ // write 2 byte string length
+ data[ptr++]=(uint8_t)(length & 0xff);
+ data[ptr++]=(uint8_t)((length >> 8) & 0xff);
+
+ for (i=0;i!=length;i++)
+ {
+ data[ptr++]=name[i] & 0xff;
+ data[ptr++]=(name[i] >> 8) & 0xff;
+ }
+
+ // fill rest with nulls
+ while (ptr<516)
+ {
+ data[ptr++]=0;
+ }
+
+ rev4(preamp,&data[ptr]);
+ ptr+=4;
+
+ rev4(10,&data[ptr]);
+ ptr+=4;
+ for (i=0;i<10;i++)
+ {
+ rev4(eq[i],&data[ptr]);
+ ptr+=4;
+ }
+
+ rev4(5,&data[ptr]);
+ ptr+=4;
+ for (i=0;i<5;i++)
+ {
+ rev4(short_eq[i],&data[ptr]);
+ ptr+=4;
+ }
+
+ return ptr;
+}
+
+
+
+
+iTunesStats::iTunesStats() :
+mhlt(NULL)
+{
+ entry = 0;
+ children = 0;
+}
+
+iTunesStats::~iTunesStats()
+{
+ free(entry);
+}
+
+long iTunesStats::parse(const uint8_t *data)
+{
+ long ptr=0;
+
+ children = rev3(&data[ptr]);
+ ptr+=3;
+ unk1 = rev3(&data[ptr]);
+ ptr+=3;
+
+ unsigned long i;
+
+ entry = (iTunesStatsEntry *)malloc(children*sizeof(iTunesStatsEntry));
+
+ for (i=0;i<children;i++)
+ {
+ iTunesStatsEntry &e = entry[i];
+
+ e.entry_size = rev3(&data[ptr]);
+ ptr+=3;
+ e.bookmarktime = rev3(&data[ptr]);
+ ptr+=3;
+ e.unk1 = rev3(&data[ptr]);
+ ptr+=3;
+ e.unk2 = rev3(&data[ptr]);
+ ptr+=3;
+ e.playcount = rev3(&data[ptr]);
+ ptr+=3;
+ e.skippedcount = rev3(&data[ptr]);
+ ptr+=3;
+
+#ifdef _DEBUG
+ // If any of these trigger an assertion, something new is in the database format
+ ASSERT(e.entry_size == 0x12);
+ //ASSERT(e.unk1 == 0);
+ ASSERT(e.unk2 == 0);
+#endif
+ }
+
+ return children;
+}
+
+// Unlike Play Counts, iTunesStats needs to be created by the application - apparently only for the bookmark time
+long iTunesStats::write(unsigned char * data, const unsigned long datasize)
+{
+ ASSERT(mhlt != NULL);
+ if(mhlt == NULL)
+ return(-1);
+
+ const unsigned int numentries = mhlt->GetChildrenCount();
+ const unsigned int total_size = 6 + (numentries * sizeof(iTunesStatsEntry)); // 6 bytes for the header
+ ASSERT(datasize >= total_size);
+ if(datasize < total_size)
+ return(-1);
+
+ long ptr=0;
+
+ rev3(numentries, &data[ptr]);
+ ptr+=3;
+
+ put3(unk1, &data[ptr]);
+ ptr+=3;
+
+ // Create a new iTunesStatsEntry for each song, only preserving the bookmark time
+ long ret = 0;
+ for(unsigned int i=0; i<numentries; i++)
+ {
+ iPod_mhit *mhit = mhlt->GetTrack(i);
+ ASSERT(mhit);
+ if(mhit == NULL)
+ return(-1);
+
+ rev3(0x12, &data[ptr]); // Entry size
+ ptr+=3;
+ rev3(mhit->bookmarktime / 256, &data[ptr]);
+ ptr+=3;
+ rev3(0, &data[ptr]); // iTunesStatsEntry.unk1
+ ptr+=3;
+ rev3(0, &data[ptr]); // iTunesStatsEntry.unk2
+ ptr+=3;
+ rev3(0, &data[ptr]); // Don't write out the playcount
+ ptr+=3;
+ rev3(0, &data[ptr]); // or the skipped count
+ ptr+=3;
+ }
+
+ return(ptr);
+}
+
+iTunesShuffle::iTunesShuffle() :
+datasize(0)
+{
+ numentries=0;
+ entry = 0;
+}
+
+iTunesShuffle::~iTunesShuffle()
+{
+ free(entry);
+}
+
+long iTunesShuffle::parse(const uint8_t *data)
+{
+ ASSERT(datasize > 0);
+
+ // iTunesShuffle is simply a list of reversed 3 byte indexes
+ ASSERT(datasize % 3 == 0);
+ if(datasize % 3 != 0)
+ return(-1);
+
+ free(entry);
+ long ptr = 0;
+ numentries = datasize / 3;
+ entry = (uint32_t *)malloc(numentries*sizeof(uint32_t));
+ for(unsigned int i=0; i<numentries; i++)
+ {
+ unsigned int value = rev3(&data[ptr]);
+ if(value == 0xffffff) // This can happen if iTunesSD::playflags doesn't have the shuffle bit set
+ value = 0;
+
+ entry[i]=value;
+ ptr+=3;
+ }
+
+ return(ptr);
+}
+
+long iTunesShuffle::write(unsigned char *data, const unsigned long datasize)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iTunesShuffle_write);
+#endif
+
+ const unsigned int total_size = numentries * 3;
+ ASSERT(datasize >= total_size);
+ if(datasize < total_size)
+ return(-1);
+
+ long ptr = 0;
+
+ for(unsigned int i=0; i<numentries; i++)
+ {
+ rev3(entry[i], &data[ptr]);
+ ptr+=3;
+ }
+
+ return(ptr);
+}
+
+void iTunesShuffle::Randomize()
+{
+ Randomize(numentries);
+}
+
+void iTunesShuffle::Randomize(const unsigned int numsongs)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iTunesShuffle_randomize);
+#endif
+
+ if(numsongs == 0)
+ return;
+
+ if (numentries < numsongs)
+ {
+ free(entry);
+ entry = (uint32_t *)malloc(numsongs*sizeof(uint32_t));
+ }
+
+ numentries=numsongs;
+
+ for (uint32_t i=0;i!=numsongs;i++)
+ {
+ entry[i] = i;
+ }
+
+ std::random_shuffle(entry, entry+numsongs);
+}
+
+//////////////////////////////////////////////////////////////////////
+// MHIA - Album Item
+//////////////////////////////////////////////////////////////////////
+
+iPod_mhia::iPod_mhia()
+: unk1(0), albumid(0), type(2)
+{
+ dbid = Generate64BitID();
+}
+
+iPod_mhia::~iPod_mhia()
+{
+ for (auto obj : mhod)
+ {
+ delete obj;
+ }
+ mhod.clear();
+}
+
+long iPod_mhia::parse(const uint8_t *data)
+{
+ return 0;
+ /*
+ long ptr = 0;
+ if (_strnicmp((char *)&data[ptr],"mhia",4)) return -1;
+ ptr+=4;
+
+ uint32_t size_head=rev4(&data[ptr]);
+ ptr+=4;
+ uint32_t size_total=rev4(&data[ptr]);
+ ptr+=4;
+ uint32_t num_children=rev4(&data[ptr]);
+ ptr+=4;
+ unk1 = rev2(&data[ptr]);
+ ptr+=2;
+ albumid = rev4(&data[ptr]);
+ ptr+=4;
+ dbid = rev8(get8(&data[ptr]));
+ ptr+=8;
+ type = rev4(&data[ptr]);
+ ptr+=4;
+
+ ptr = size_head; // skip nulls
+
+ for(uint32_t i = 0; i < num_children; i++)
+ {
+ iPod_mhod* m = new iPod_mhod();
+ long ret = m->parse(data + ptr);
+ if(ret == -1)
+ {
+ delete m;
+ return -1;
+ }
+ mhod.push_back(m);
+ ptr += ret;
+ }
+
+ return ptr;
+ */
+}
+
+long iPod_mhia::write(unsigned char * data, const unsigned long datasize)
+{
+ const unsigned int headsize=0x5C;
+ // check for header size
+ if (headsize>datasize) return -1;
+
+ long ptr=0;
+
+ //write mhla header
+ data[0]='m';data[1]='h';data[2]='i';data[3]='a';
+ ptr+=4;
+
+ rev4(headsize,&data[ptr]); // header size
+ ptr+=4;
+ rev4(-1,&data[ptr]); // total size (put this in later)
+ ptr+=4;
+ rev4((uint32_t)mhod.size(),&data[ptr]); // number of strings
+ ptr+=4;
+ rev2(unk1, &data[ptr]);
+ ptr+=2;
+ rev2(albumid, &data[ptr]);
+ ptr+=2;
+ put8(rev8(dbid), &data[ptr]);
+ ptr+=8;
+ rev4(type, &data[ptr]);
+ ptr+=4;
+
+ memset(&data[ptr], 0, 60); // a whole shitload of zeroes
+ ptr+=60;
+
+ for (size_t i=0;i!=mhod.size();i++)
+ {
+ long ret = mhod[i]->write(data + ptr, datasize - ptr);
+ if (ret == -1)
+ return -1;
+ ptr += ret;
+ }
+
+ // put in total size
+ rev4(ptr, &data[8]);
+
+ return ptr;
+}
+
+//////////////////////////////////////////////////////////////////////
+// MHLA - Album List
+//////////////////////////////////////////////////////////////////////
+
+iPod_mhla::iPod_mhla() : nextAlbumId(400)
+{
+}
+iPod_mhla::~iPod_mhla()
+{
+}
+
+long iPod_mhla::parse(const uint8_t *data)
+{
+ return 0;
+ /*
+ long ptr=0;
+
+ if (_strnicmp((char *)&data[ptr],"mhla",4)) return -1;
+ ptr+=4;
+
+ uint32_t size_head=rev4(&data[ptr]);
+ ptr+=4;
+ uint32_t num_children=rev4(&data[ptr]);
+ ptr+=4;
+
+ ptr = size_head; // skip nulls
+
+ for(uint32_t i = 0; i < num_children; i++)
+ {
+ iPod_mhia* m = new iPod_mhia();
+ long ret = m->parse(data + ptr);
+ if(ret == -1)
+ {
+ delete m;
+ return -1;
+ }
+ mhia.push_back(m);
+ ptr += ret;
+ }
+
+ return ptr;
+ */
+}
+
+long iPod_mhla::write(unsigned char * data, const unsigned long datasize)
+{
+ const unsigned int headsize=0x5C;
+ // check for header size
+ if (headsize>datasize) return -1;
+
+ long ptr=0;
+
+ //write mhla header
+ data[0]='m';data[1]='h';data[2]='l';data[3]='a';
+ ptr+=4;
+
+ rev4(headsize,&data[ptr]); // header size
+ ptr+=4;
+ rev4((uint32_t)albums.size(),&data[ptr]); // number of albums
+ ptr+=4;
+ memset(&data[ptr], 0, 80); // a whole shitload of zeroes
+ ptr+=80;
+
+ /*
+ for (size_t i=0;i!=mhia.size();i++)
+ {
+ long ret = mhia[i]->write(data + ptr, datasize - ptr);
+ if (ret == -1)
+ return -1;
+ ptr += ret;
+ }
+ */
+
+ for(albums_map_t::iterator i = albums.begin(); i!=albums.end(); i++)
+ {
+ iPod_mhia mhia;
+ mhia.albumid = i->second;
+ iPod_mhod* artist = new iPod_mhod();
+ artist->SetString(i->first.artist);
+ artist->type = MHOD_ALBUMLIST_ARTIST;
+ mhia.mhod.push_back(artist);
+
+ iPod_mhod* album = new iPod_mhod();
+ album->SetString(i->first.album);
+ album->type = MHOD_ALBUMLIST_ALBUM;
+ mhia.mhod.push_back(album);
+
+ long ret = mhia.write(data + ptr, datasize - ptr);
+ if (ret == -1)
+ return -1;
+ ptr += ret;
+ }
+
+ return ptr;
+}
+
+uint16_t iPod_mhla::GetAlbumId(const wchar_t* artist, const wchar_t* album)
+{
+ ArtistAlbumPair key(artist, album);
+ if(albums.find(key) == albums.end())
+ {
+ albums[key] = nextAlbumId;
+ return nextAlbumId++;
+ }
+ return albums[key];
+}
+
+void iPod_mhla::ClearAlbumsList()
+{
+ nextAlbumId = 0;
+ albums.clear();
+}
+
+
diff --git a/Src/Plugins/Portable/pmp_ipod/iPodDB.h b/Src/Plugins/Portable/pmp_ipod/iPodDB.h
new file mode 100644
index 00000000..dd4878fa
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/iPodDB.h
@@ -0,0 +1,1256 @@
+/*
+ *
+ *
+ * Copyright (c) 2004 Samuel Wood (sam.wood@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ *
+ */
+
+
+// For more information on how all this stuff works, see:
+// http://www.ipodlinux.org/ITunesDB
+
+
+// iPodDB.h: interface for the iPod classes.
+//
+//////////////////////////////////////////////////////////////////////
+
+#ifndef __IPODDB_H__
+#define __IPODDB_H__
+
+#pragma once
+
+#pragma warning( disable : 4786)
+
+#include <algorithm>
+#include <windows.h>
+#include <bfc/platform/types.h>
+#include <map>
+#include <vector>
+
+#ifdef _DEBUG
+#undef ASSERT
+#define ASSERT(x) assert(x)
+#else
+#define ASSERT(x) {}
+#endif
+
+
+
+// mhod types
+#define MHOD_TITLE 1
+#define MHOD_LOCATION 2
+#define MHOD_ALBUM 3
+#define MHOD_ARTIST 4
+#define MHOD_GENRE 5
+#define MHOD_FILETYPE 6
+#define MHOD_EQSETTING 7
+#define MHOD_COMMENT 8
+#define MHOD_CATEGORY 9 // iTunes Music Store Podcast category
+#define MHOD_COMPOSER 12
+#define MHOD_GROUPING 13
+#define MHOD_DESCRIPTION 14 // Podcast show notes text - accessible via the center iPod button
+#define MHOD_ENCLOSUREURL 15 // Used by iTunes 4.9 for a Podcast's original enclosure URL
+#define MHOD_RSSFEEDURL 16 // Used by iTunes 4.9 for a Podcast's RSS 2.0 feed URL
+#define MHOD_CHAPTER 17 // M4A-style tagged data that is used to support subsongs/chapters
+#define MHOD_SUBTITLE 18
+#define MHOD_SHOW 19
+#define MHOD_EPISODE 20
+#define MHOD_TVNETWORK 21
+#define MHOD_ALBUMARTIST 22
+#define MHOD_ARTIST_SORT 23
+#define MHOD_TITLE_SORT 27
+#define MHOD_ALBUM_SORT 28
+#define MHOD_ALBUMARTIST_SORT 29
+#define MHOD_COMPOSER_SORT 30
+#define MHOD_SHOW_SORT 31
+#define MHOD_SPLPREF 50
+#define MHOD_SPLDATA 51
+#define MHOD_LIBRARY 52 // Found in the default hidden playlist
+#define MHOD_LIBRARY_LETTER 53 // letter jump table
+#define MHOD_PLAYLIST 100
+#define MHOD_ALBUMLIST_ALBUM 200
+#define MHOD_ALBUMLIST_ARTIST 201
+#define MHOD_ALBUMLIST_ARTIST_SORT 202
+#define MHOD_ALBUMLIST_PODCASTURL 203
+#define MHOD_ALBUMLIST_SHOW 204
+
+
+// Equalizer defines
+#define EQ_NONE -1
+#define EQ_ACOUSTIC 100
+#define EQ_BASSBOOSTER 101
+#define EQ_BASSREDUCER 102
+#define EQ_CLASSICAL 103
+#define EQ_DANCE 104
+#define EQ_DEEP 105
+#define EQ_ELECTRONIC 106
+#define EQ_FLAT 107
+#define EQ_HIPHOP 108
+#define EQ_JAZZ 109
+#define EQ_LATIN 110
+#define EQ_LOUDNESS 111
+#define EQ_LOUNGE 112
+#define EQ_PIANO 113
+#define EQ_POP 114
+#define EQ_RNB 115
+#define EQ_ROCK 116
+#define EQ_SMALLSPEAKERS 117
+#define EQ_SPOKENWORD 118
+#define EQ_TREBLEBOOSTER 119
+#define EQ_TREBLEREDUCER 120
+#define EQ_VOCALBOOSTER 121
+
+
+
+// Smart Playlist stuff
+#define SPLMATCH_AND 0 // AND rule - all of the rules must be true in order for the combined rule to be applied
+#define SPLMATCH_OR 1 // OR rule
+
+// Limit Types.. like limit playlist to 100 minutes or to 100 songs
+#define LIMITTYPE_MINUTES 0x01
+#define LIMITTYPE_MB 0x02
+#define LIMITTYPE_SONGS 0x03
+#define LIMITTYPE_HOURS 0x04
+#define LIMITTYPE_GB 0x05
+
+// Limit Sorts.. Like which songs to pick when using a limit type
+// Special note: the values for LIMITSORT_LEAST_RECENTLY_ADDED, LIMITSORT_LEAST_OFTEN_PLAYED,
+// LIMITSORT_LEAST_RECENTLY_PLAYED, and LIMITSORT_LOWEST_RATING are really 0x10, 0x14,
+// 0x15, 0x17, with the 'limitsort_opposite' flag set. This is the same value as the
+// "positive" value (i.e. LIMITSORT_LEAST_RECENTLY_ADDED), and is really very terribly
+// awfully weird, so we map the values to iPodDB specific values with the high bit set.
+//
+// On writing, we check the high bit and write the limitsort_opposite from that. That
+// way, we don't have to deal with programs using the class needing to set the wrong
+// limit and then make it into the "opposite", which would be frickin' annoying.
+#define LIMITSORT_RANDOM 0x02
+#define LIMITSORT_SONG_NAME 0x03
+#define LIMITSORT_ALBUM 0x04
+#define LIMITSORT_ARTIST 0x05
+#define LIMITSORT_GENRE 0x07
+#define LIMITSORT_MOST_RECENTLY_ADDED 0x10
+#define LIMITSORT_COMPOSER 0x12 // Not used by iTunes, but inferred from the Type 52 MHOD's Composer type
+#define LIMITSORT_LEAST_RECENTLY_ADDED 0x80000010 // See note above
+#define LIMITSORT_MOST_OFTEN_PLAYED 0x14
+#define LIMITSORT_LEAST_OFTEN_PLAYED 0x80000014 // See note above
+#define LIMITSORT_MOST_RECENTLY_PLAYED 0x15
+#define LIMITSORT_LEAST_RECENTLY_PLAYED 0x80000015 // See note above
+#define LIMITSORT_HIGHEST_RATING 0x17
+#define LIMITSORT_LOWEST_RATING 0x80000017 // See note above
+
+// Smartlist Actions - Used in the rules.
+/*
+ really this is a bitmapped field...
+ high byte
+ bit 0 = "string" values if set, "int" values if not set
+ bit 1 = "not", or to negate the check.
+ lower 2 bytes
+ bit 0 = simple "IS" query
+ bit 1 = contains
+ bit 2 = begins with
+ bit 3 = ends with
+ bit 4 = greater than
+ bit 5 = unknown, but probably greater than or equal to
+ bit 6 = less than
+ bit 7 = unknown, but probably less than or equal to
+ bit 8 = a range selection
+ bit 9 = "in the last"
+*/
+#define SPLACTION_IS_INT 0x00000001 // Also called "Is Set" in iTunes
+#define SPLACTION_IS_GREATER_THAN 0x00000010 // Also called "Is After" in iTunes
+#define SPLACTION_IS_LESS_THAN 0x00000040 // Also called "Is Before" in iTunes
+#define SPLACTION_IS_IN_THE_RANGE 0x00000100
+#define SPLACTION_IS_IN_THE_LAST 0x00000200
+#define SPLACTION_BINARY_AND 0x00000400
+
+#define SPLACTION_IS_STRING 0x01000001
+#define SPLACTION_CONTAINS 0x01000002
+#define SPLACTION_STARTS_WITH 0x01000004
+#define SPLACTION_ENDS_WITH 0x01000008
+
+#define SPLACTION_IS_NOT_INT 0x02000001 // Also called "Is Not Set" in iTunes
+#define SPLACTION_IS_NOT_GREATER_THAN 0x02000010 // Note: Not available in iTunes
+#define SPLACTION_IS_NOT_LESS_THAN 0x02000040 // Note: Not available in iTunes
+#define SPLACTION_IS_NOT_IN_THE_RANGE 0x02000100 // Note: Not available in iTunes
+#define SPLACTION_IS_NOT_IN_THE_LAST 0x02000200
+#define SPLACTION_UNKNOWN2 0x02000800
+
+#define SPLACTION_IS_NOT 0x03000001
+#define SPLACTION_DOES_NOT_CONTAIN 0x03000002
+#define SPLACTION_DOES_NOT_START_WITH 0x03000004 // Note: Not available in iTunes
+#define SPLACTION_DOES_NOT_END_WITH 0x03000008 // Note: Not available in iTunes
+
+
+// these are to pass to AddRule() when you need a unit for the two "in the last" action types
+// Or, in theory, you can use any time range... iTunes might not like it, but the iPod might.
+#define SPLACTION_LAST_DAYS_VALUE 86400 // number of seconds in 24 hours
+#define SPLACTION_LAST_WEEKS_VALUE 604800 // number of seconds in 7 days
+#define SPLACTION_LAST_MONTHS_VALUE 2628000 // number of seconds in 30.4167 days ~= 1 month
+
+// Hey, why limit ourselves to what iTunes can do? If the iPod can deal with it, excellent!
+#define SPLACTION_LAST_SECONDS_RULE 1 // one second
+#define SPLACTION_LAST_HOURS_VALUE 3600 // number of seconds in 1 hour
+#define SPLACTION_LAST_MINUTES_VALUE 60 // number of seconds in 1 minute
+#define SPLACTION_LAST_YEARS_VALUE 31536000 // number of seconds in 365 days
+
+// fun ones.. Near as I can tell, all of these work. It's open like that. :)
+#define SPLACTION_LAST_LUNARCYCLE_VALUE 2551443 // a "lunar cycle" is the time it takes the moon to circle the earth
+#define SPLACTION_LAST_SIDEREAL_DAY 86164 // a "sidereal day" is time in one revolution of earth on its axis
+#define SPLACTION_LAST_SWATCH_BEAT 86 // a "swatch beat" is 1/1000th of a day.. search for "internet time" on google
+#define SPLACTION_LAST_MOMENT 90 // a "moment" is 1/40th of an hour, or 1.5 minutes
+#define SPLACTION_LAST_OSTENT 600 // an "ostent" is 1/10th of an hour, or 6 minutes
+#define SPLACTION_LAST_FORTNIGHT 1209600 // a "fortnight" is 14 days
+#define SPLACTION_LAST_VINAL 1728000 // a "vinal" is 20 days
+#define SPLACTION_LAST_QUARTER 7889231 // a "quarter" is a quarter year
+#define SPLACTION_LAST_SOLAR_YEAR 31556926 // a "solar year" is the time it takes the earth to go around the sun
+#define SPLACTION_LAST_SIDEREAL_YEAR 31558150 // a "sidereal year" is the time it takes the earth to reach the same point in space again, compared to the stars
+
+
+// Smartlist fields - Used for rules.
+#define SPLFIELD_SONG_NAME 0x02 // String
+#define SPLFIELD_ALBUM 0x03 // String
+#define SPLFIELD_ARTIST 0x04 // String
+#define SPLFIELD_BITRATE 0x05 // Int (e.g. from/to = 128)
+#define SPLFIELD_SAMPLE_RATE 0x06 // Int (e.g. from/to = 44100)
+#define SPLFIELD_YEAR 0x07 // Int (e.g. from/to = 2004)
+#define SPLFIELD_GENRE 0x08 // String
+#define SPLFIELD_KIND 0x09 // String
+#define SPLFIELD_DATE_MODIFIED 0x0a // Int/Mac Timestamp (e.g. from/to = bcf93280 == is before 6/19/2004)
+#define SPLFIELD_TRACKNUMBER 0x0b // Int (e.g. from = 1, to = 2)
+#define SPLFIELD_SIZE 0x0c // Int (e.g. from/to = 0x00600000 for 6MB)
+#define SPLFIELD_TIME 0x0d // Int (e.g. from/to = 83999 for 1:23/83 seconds)
+#define SPLFIELD_COMMENT 0x0e // String
+#define SPLFIELD_DATE_ADDED 0x10 // Int/Mac Timestamp (e.g. from/to = bcfa83ff == is after 6/19/2004)
+#define SPLFIELD_COMPOSER 0x12 // String
+#define SPLFIELD_PLAYCOUNT 0x16 // Int (e.g. from/to = 1)
+#define SPLFIELD_LAST_PLAYED 0x17 // Int/Mac Timestamp (e.g. from = bcfa83ff (6/19/2004), to = 0xbcfbd57f (6/20/2004))
+#define SPLFIELD_DISC_NUMBER 0x18 // Int (e.g. from/to = 1)
+#define SPLFIELD_RATING 0x19 // Int/Stars Rating (e.g. from/to = 60 (3 stars))
+#define SPLFIELD_COMPILATION 0x1f // Int (e.g. is set -> SPLACTION_IS_INT/from=1, is not set -> SPLACTION_IS_NOT_INT/from=1)
+#define SPLFIELD_BPM 0x23 // Int (e.g. from/to = 60)
+#define SPLFIELD_GROUPING 0x27 // String
+#define SPLFIELD_PLAYLIST 0x28 // XXX - Unknown...not parsed correctly...from/to = 0xb6fbad5f for "Purchased Music". Extra data after "to"...
+#define SPLFIELD_VIDEO_KIND 0x3C // Logic Int (???)
+#define SPLFIELD_TVSHOW 0x3E // Int
+#define SPLFIELD_SEASON_NR 0x3F // Int
+#define SPLFIELD_SKIPCOUNT 0x44 // Int
+#define SPLFIELD_ALBUMARTIST 0x47 // string
+
+#define SPLDATE_IDENTIFIER 0x2dae2dae2dae2dae
+
+
+// MHOD Type 52 types
+#define TYPE52_SONG_NAME 0x03
+#define TYPE52_ARTIST 0x05
+#define TYPE52_ALBUM 0x04
+#define TYPE52_GENRE 0x07
+#define TYPE52_COMPOSER 0x12
+
+static const uint32_t FILETYPE_M4A=0x4d344120;
+static const uint32_t FILETYPE_MP3=0x4d503320;
+static const uint32_t FILETYPE_WAV=0x57415620;
+
+// useful functions
+time_t mactime_to_wintime (const unsigned long mactime);
+unsigned long wintime_to_mactime (const __time64_t time);
+char * UTF16_to_char(wchar_t * str, int length);
+
+
+// Pre-declare iPod_* classes
+class iPod_mhbd;
+class iPod_mhsd;
+class iPod_mhlt;
+class iPod_mhit;
+class iPod_mhlp;
+class iPod_mhyp;
+class iPod_slst;
+class iPod_mhip;
+class iPod_mhod;
+class iPod_mqed;
+class iPod_mhpo;
+class iPod_pqed;
+class iPod_mhla;
+
+// Maximum string length that iTunes writes to the database
+#define SPL_MAXSTRINGLENGTH 255
+
+
+// a struct to hold smart playlist rules in mhods
+struct SPLRule
+{
+ SPLRule() :
+ field(0),
+ action(0),
+ length(0),
+ fromvalue(0),
+ fromdate(0),
+ fromunits(0),
+ tovalue(0),
+ todate(0),
+ tounits(0),
+ unk1(0),
+ unk2(0),
+ unk3(0),
+ unk4(0),
+ unk5(0)
+ {
+ memset(string, 0, sizeof(string));
+ }
+
+ void SetString(const wchar_t *value)
+ {
+ if(value)
+ {
+ lstrcpynW(string, value, SPL_MAXSTRINGLENGTH);
+ length = lstrlenW(string) * 2;
+ }
+ else
+ {
+ memset(string, 0, sizeof(string));
+ length = 0;
+ }
+ }
+
+ unsigned long field;
+ unsigned long action;
+ unsigned long length;
+ wchar_t string[SPL_MAXSTRINGLENGTH + 1];
+
+ // from and to are pretty stupid.. if it's a date type of field, then
+ // value = 0x2dae2dae2dae2dae,
+ // date = some number, like 2 or -2
+ // units = unit in seconds, like 604800 = a week
+ // but if this is actually some kind of integer comparison, like rating = 60 (3 stars)
+ // value = the value we care about
+ // date = 0
+ // units = 1
+ // So we leave these as they are, and will just deal with it in the rules functions.
+ uint64_t fromvalue;
+ int64_t fromdate;
+ uint64_t fromunits;
+ uint64_t tovalue;
+ int64_t todate;
+ uint64_t tounits;
+ unsigned long unk1;
+ unsigned long unk2;
+ unsigned long unk3;
+ unsigned long unk4;
+ unsigned long unk5;
+};
+
+
+// PCEntry: Play Count struct for the entries in iPod_mhdp
+struct PCEntry
+{
+ unsigned long playcount;
+ unsigned long lastplayedtime;
+ unsigned long bookmarktime;
+ unsigned long stars;
+ uint32_t unk1;
+ uint32_t skipcount;
+ uint32_t skippedtime;
+};
+
+
+/**************************************
+ iTunesDB Database Layout
+
+ MHBD (Database)
+ |
+ |-MHSD (Data Set)
+ | |
+ | |-MHLT (Track List)
+ | | |
+ | | |-MHIT (Track Item)
+ | | | |
+ | | | |-MHOD (Description Object)
+ | | | |-MHOD
+ | | | | ...
+ | | |
+ | | |-MHIT
+ | | | |
+ | | | |-MHOD
+ | | | |-MHOD
+ | | | | ...
+ | | |
+ | | |-...
+ |
+ |
+ |-MHSD
+ | |
+ | |-MHLP (Playlists List)
+ | | |
+ | | |-MHYP (Playlist)
+ | | | |
+ | | | |-MHOD
+ | | | |-MHIP (Playlist Item)
+ | | | | ...
+ | | |
+ | | |-MHYP
+ | | | |
+ | | | |-MHOD
+ | | | |-MHIP
+ | | | | ...
+ | | |
+ | | |-...
+
+**************************************/
+
+
+// base class, not used directly
+class iPodObj
+{
+public:
+ iPodObj();
+ virtual ~iPodObj();
+
+ // parse function is required in all subclasses
+ // feed it a iTunesDB, it creates an object hierarchy
+ virtual long parse(const uint8_t *data) = 0;
+
+ // write function is required too
+ // feed it a buffer and the size of the buffer, it fills it with an iTunesDB
+ // return value is size of the resulting iTunesDB
+ // return of -1 means the buffer was too small
+ virtual long write(uint8_t * data, const unsigned long datasize) = 0;
+
+ unsigned long size_head;
+ unsigned long size_total;
+};
+
+
+// MHBD: The database - parent of all items
+class iPod_mhbd : public iPodObj
+{
+public:
+ iPod_mhbd();
+ virtual ~iPod_mhbd();
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(uint8_t * data, const unsigned long datasize);
+ virtual long write(uint8_t * data, const unsigned long datasize, uint8_t * fwid);
+
+ uint32_t unk1;
+ uint32_t dbversion;
+ uint32_t children;
+ uint64_t id;
+ uint16_t platform;
+ uint16_t language;
+ uint64_t library_id;
+ uint32_t unk80;
+ uint32_t unk84;
+ int32_t timezone; // in seconds
+ uint16_t audio_language;
+ uint16_t subtitle_language;
+ uint16_t unk164;
+ uint16_t unk166;
+ uint16_t unk168;
+
+ iPod_mhsd *mhsdsongs;
+ iPod_mhsd *mhsdplaylists;
+ iPod_mhsd *mhsdsmartplaylists;
+};
+
+
+// MHSD: List container - parent of MHLT or MHLP, child of MHBD
+class iPod_mhsd : public iPodObj
+{
+public:
+ iPod_mhsd();
+ iPod_mhsd(int newindex);
+ virtual ~iPod_mhsd();
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(unsigned char * data, const unsigned long datasize) {return write(data,datasize,1);}
+ virtual long write(unsigned char * data, const unsigned long datasize, int index);
+
+ uint32_t index; // 1 = mhlt, 3 = mhlp, 2 = legacy mhlp, 4 = album list, 5 = mhlp_smart
+ iPod_mhlt * mhlt;
+ iPod_mhlp * mhlp;
+ iPod_mhlp * mhlp_smart;
+ iPod_mhla * mhla;
+};
+
+class iPod_mhia : public iPodObj
+{
+public:
+ iPod_mhia();
+ virtual ~iPod_mhia();
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(unsigned char * data, const unsigned long datasize);
+
+ uint16_t unk1;
+ uint16_t albumid;
+ uint64_t dbid;
+ uint32_t type;
+
+ std::vector<iPod_mhod*> mhod;
+};
+
+class ArtistAlbumPair
+{
+public:
+ const wchar_t* artist;
+ const wchar_t* album;
+ ArtistAlbumPair() : artist(0), album(0) {}
+ ArtistAlbumPair(const wchar_t* artist, const wchar_t* album) : artist(artist), album(album) {}
+ /*bool operator < (const ArtistAlbumPair& that) const
+ {
+ int yy = _wcsicmp(artist, that.artist);
+ if(yy) return yy < 0;
+ return _wcsicmp(album, that.album) < 0;
+ }*/
+};
+
+struct ArtistAlbumPairComparer
+{
+ int operator ()(const ArtistAlbumPair &a, const ArtistAlbumPair &b) const
+ {
+ int yy = _wcsicmp(a.artist, b.artist);
+ if(yy) return yy;
+ return _wcsicmp(a.album, b.album);
+ }
+};
+
+class iPod_mhla : public iPodObj
+{
+public:
+ iPod_mhla();
+ virtual ~iPod_mhla();
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(unsigned char * data, const unsigned long datasize);
+ uint16_t GetAlbumId(const wchar_t* artist, const wchar_t* album);
+ void ClearAlbumsList();
+
+ //typedef std::map<ArtistAlbumPair, uint16_t> albums_map_t;
+ typedef std::map<ArtistAlbumPair, uint16_t, ArtistAlbumPairComparer> albums_map_t;
+ albums_map_t albums;
+ uint16_t nextAlbumId;
+};
+
+
+// MHLT: song list container - parent of MHIT, child of MHSD
+class iPod_mhlt : public iPodObj
+{
+public:
+ typedef std::map<uint32_t, iPod_mhit*> mhit_map_t;
+ //typedef std::map<unsigned long, iPod_mhit*> mhit_map_t; // Map the unique mhit.id to a mhit object
+ typedef mhit_map_t::value_type mhit_value_t;
+
+ iPod_mhlt();
+ virtual ~iPod_mhlt();
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(unsigned char * data, const unsigned long datasize);
+
+ const unsigned long GetChildrenCount() const { return mhit.size(); }
+
+ // returns a pointer to the new iPod_mhit object in the track list, which you edit directly
+ iPod_mhit *NewTrack();
+ void AddTrack(iPod_mhit *new_track);
+
+ // takes a position index, returns a pointer to the track itself, or NULL if the index isn't found.
+ iPod_mhit *GetTrack(uint32_t index) const;
+
+ // searches for a track based on the track's id number (mhit.id). returns mhit pointer, or NULL if the id isn't found.
+ iPod_mhit * GetTrackByID(const unsigned long id);
+
+ // couple of ways to delete a track
+ bool DeleteTrack(const unsigned long index);
+ bool DeleteTrackByID(const unsigned long id);
+
+ // clears out the tracklist
+ bool ClearTracks(const bool clearMap = true);
+
+ // the map of the tracks themselves
+ mhit_map_t mhit;
+ std::vector<uint32_t> mhit_indexer;
+
+ uint32_t GetNextID();
+
+private:
+ volatile uint32_t next_mhit_id;
+};
+
+
+// MHIT: song item - parent of MHOD, child of MHLT
+class iPod_mhit : public iPodObj
+{
+public:
+ iPod_mhit();
+ virtual ~iPod_mhit();
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(unsigned char * data, const unsigned long datasize);
+
+ const unsigned long GetChildrenCount() const { return(mhod.size()); }
+
+ // will add a new mhod string to the mhit
+ // optional: pass in a type to get an existing string, if there is one,
+ // or a new one with the type filled in already, if there is not one
+ iPod_mhod * AddString(const int type=0);
+
+ // Find a string by type
+ iPod_mhod * FindString(const unsigned long type) const;
+
+ // deletes a string from the track
+ // if more than one string of given type exists, all of that type will be deleted,
+ // to ensure consistency. Pointers to these strings will be invalid after this.
+ // return val is how many strings were deleted
+ unsigned long DeleteString(const unsigned long type);
+
+ // Creates a copy of the mhit. The operator = is overloaded so you can
+ // more easily copy mhit's.
+ static void Duplicate(const iPod_mhit *src, iPod_mhit *dst);
+ iPod_mhit& operator=(const iPod_mhit& src);
+
+ int GetRating() { return stars/20; }
+ void SetRating(int rating) { stars=rating*20; }
+
+ int GetEQSetting();
+ void SetEQSetting(int value);
+
+ unsigned int GetFileTypeID(const wchar_t *filename);
+
+
+ uint32_t id;
+ uint32_t visible; // 0x01 means the song shows up on the iPod, all other values means it is hidden
+ uint32_t filetype; // MP3 = 0x4d503320, M4A = 0x4d344120, M4B = 0x4d344220, M4P = 0x4d345020, WAV = 0x57415620, AA = ???
+ uint8_t vbr;
+ uint8_t type;
+ uint8_t compilation;
+ uint8_t stars;
+ uint32_t lastmodifiedtime; // iTunes sets this the UTC time value for the Windows Last Modified timestamp
+ uint32_t size;
+ uint32_t length;
+ uint32_t tracknum;
+ uint32_t totaltracks;
+ uint32_t year;
+ uint32_t bitrate;
+ uint16_t samplerate;
+ uint16_t samplerate_fixedpoint;
+ uint32_t volume;
+ uint32_t starttime;
+ uint32_t stoptime;
+ uint32_t soundcheck;
+ uint32_t playcount;
+ uint32_t playcount2; // Seems to always be the same as playcount(?!?)
+ uint32_t lastplayedtime;
+ uint32_t cdnum;
+ uint32_t totalcds;
+ uint32_t userID; // Apple Store User ID
+ uint32_t addedtime; // iTunes sets this to the UTC time value for when the file was added to the iTunes library
+ uint32_t bookmarktime;
+ uint64_t dbid; // 64 bit value that identifies this mhit across iPod databases. iTunes increments this by 1 for each additional song. (previously unk7 and unk8)
+ uint32_t BPM;
+ uint32_t app_rating; // The rating set by the application, as opposed to the rating set on the iPod itself
+ uint8_t checked; // a "checked" song has the value of 0, a non-checked song is 1
+ uint16_t unk9; // Seems to always be 0xffff...
+ uint16_t artworkcount; // Number of artwork files attached to this song
+ uint32_t artworksize; // Size of all artwork files attached to this song, in bytes. (was unk10);
+ uint32_t unk11;
+ float samplerate2;
+ uint32_t releasedtime;
+ uint32_t unk14;
+ uint32_t unk15;
+ uint32_t unk16;
+ /* --- */
+ uint32_t skipcount;
+ uint32_t skippedtime;
+ uint8_t hasArtwork;
+ uint8_t skipShuffle;
+ uint8_t rememberPosition;
+ uint8_t unk19;
+ uint64_t dbid2; // same as dbid?
+ uint8_t lyrics_flag;
+ uint8_t movie_flag;
+ uint8_t mark_unplayed;
+ uint8_t unk20;
+ uint32_t unk21;
+ uint32_t pregap;
+ uint64_t samplecount;
+ uint32_t unk25;
+ uint32_t postgap;
+ uint32_t unk27;
+ uint32_t mediatype;
+ uint32_t seasonNumber;
+ uint32_t episodeNumber;
+ uint32_t unk31;
+ uint32_t unk32;
+ uint32_t unk33;
+ uint32_t unk34;
+ uint32_t unk35;
+ uint32_t unk36;
+ /* --- */
+ uint32_t unk37;
+ uint32_t gaplessData;
+ uint32_t unk39;
+ uint16_t albumgapless;
+ uint16_t trackgapless;
+ uint32_t unk40;
+ uint32_t unk41;
+ uint32_t unk42;
+ uint32_t unk43;
+ uint32_t unk44;
+ uint32_t unk45;
+ uint32_t unk46;
+ uint32_t album_id;
+ uint32_t unk48;
+ uint32_t unk49;
+ uint32_t unk50;
+ uint32_t unk51;
+ uint32_t unk52;
+ uint32_t unk53;
+ uint32_t unk54;
+ uint32_t unk55;
+ uint32_t unk56;
+
+ /* --- */
+ // 22 bytes of unknown (we'll just write back zeroes)
+
+ uint32_t mhii_link; // TODO: benski> figure this thing out
+ // 32 more bytes of unknown (we'll just write back zeroes)
+
+/* benski> this is a hack. i'm putting this in here so we can retrieve album art from the transfer thread and add it in the main thread
+it doesn't really belong as part of this object, though! */
+
+ // protect these members, so stuff doesn't fuck up my cache
+protected:
+ std::vector<iPod_mhod*> mhod;
+ iPod_mhod * mhodcache[25];
+};
+
+
+// MHLP: playlist container - parent of MHYP, child of MHSD
+
+// Important note: Playlist zero must always be the default playlist, containing every
+// track in the DB. To do this, always call "GetDefaultPlaylist()" before you create any
+// other playlists, if you start from scratch.
+// After you're done adding/deleting tracks in the database, and just before you call
+// write(), do the following: GetDefaultPlaylist()->PopulatePlaylist(ptr_to_mhlt);
+
+class iPod_mhlp : public iPodObj
+{
+public:
+ iPod_mhlp();
+ virtual ~iPod_mhlp();
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(unsigned char * data, const unsigned long datasize) {return write(data,datasize,3);}
+ virtual long write(unsigned char * data, const unsigned long datasize, int index);
+
+ const unsigned long GetChildrenCount() const { return mhyp.size(); }
+
+ // returns a new playlist for you
+ iPod_mhyp * AddPlaylist();
+
+ // gets a playlist
+ iPod_mhyp * GetPlaylist(const unsigned long pos) const { return mhyp.at(pos); }
+
+ // finds a playlist by its ID
+ iPod_mhyp * FindPlaylist(const uint64_t playlistID);
+
+ // deletes the playlist at a position
+ bool DeletePlaylist(const unsigned long pos);
+
+ // deletes the playlist matching the ID
+ bool DeletePlaylistByID(const uint64_t playlistID);
+
+ // gets the default playlist ( GetPlaylist(0); )
+ // if there are no playlists yet (empty db), then it creates the default playlist
+ // and returns a pointer to it
+ iPod_mhyp * GetDefaultPlaylist();
+
+ // erases all playlists, including the default one, so be careful here.
+ // Set createDefaultPlaylist to create a new, empty default playlist
+ bool ClearPlaylists(const bool createDefaultPlaylist = false);
+
+ // Goes through all playlists and removed any songs that are no longer in the MHLT
+ void RemoveDeadPlaylistEntries(iPod_mhlt *mhlt);
+
+ std::vector<iPod_mhyp*> mhyp;
+
+ void SortPlaylists();
+
+private:
+ bool beingDeleted;
+};
+
+int STRCMP_NULLOK(const wchar_t *pa, const wchar_t *pb);
+
+// MHYP: playlist - parent of MHOD or MHIP, child of MHLP
+class iPod_mhyp : public iPodObj
+{
+public:
+ iPod_mhyp();
+ virtual ~iPod_mhyp();
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(unsigned char * data, const unsigned long datasize) {return write(data,datasize,3);}
+ virtual long write(unsigned char * data, const unsigned long datasize, int index);
+
+ bool IsSmartPlaylist(void) const { return(isSmartPlaylist); }
+
+ // add an entry to the playlist. Creates a new entry, returns the position in the vector
+ // optionally fills in the songindex for you, with the ID from a track you might have
+ long AddPlaylistEntry(iPod_mhip * entry, const unsigned long id=0);
+
+ // give it a song id, it'll return a position in the playlist
+ // -1, as always, means not found
+ // if the same entry is in the playlist multiple times, this only gives back the first one
+ long FindPlaylistEntry(const unsigned long id) const;
+
+ // get an mhip given its position
+ iPod_mhip * GetPlaylistEntry(const unsigned long pos) const { return mhip.at(pos); }
+
+ // deletes an entry from the playlist. Pointers to that entry become invalid
+ bool DeletePlaylistEntry(const unsigned long pos);
+
+ // Removes all playlist entries matching the songindex parameter
+ bool DeletePlaylistEntryByID(unsigned long songindex);
+
+ // clears a playlist of all mhip entries
+ bool ClearPlaylist();
+
+ // populates a playlist to be the same as a track list you pass into it.
+ // Mainly only useful for building the default playlist after you add/delete tracks
+ // GetDefaultPlaylist()->PopulatePlaylist(ptr_to_mhlt);
+ // for example...
+ long PopulatePlaylist(iPod_mhlt * tracks, int hidden_field=1);
+
+ // will add a new string to the playlist
+ // optional: pass in a type to get an existing string, if there is one,
+ // or a new one with the type filled in already, if there is not one
+ iPod_mhod * AddString(const int type=0);
+
+ // get an mhod given it's type.. Only really useful with MHOD_TITLE here, until
+ // smartlists get worked out better
+ iPod_mhod * FindString(const unsigned long type);
+
+ // deletes a string from the playlist
+ // if more than one string of given type exists, all of that type will be deleted,
+ // to ensure consistency. Pointers to these strings will be invalid after this.
+ // ret val is number of strings removed
+ unsigned long DeleteString(const unsigned long type);
+
+ void SetPlaylistTitle(const wchar_t *string);
+
+ const unsigned long GetMhodChildrenCount() const { return mhod.size(); }
+ const unsigned long GetMhipChildrenCount() const { return mhip.size(); }
+
+ static void Duplicate(iPod_mhyp *src, iPod_mhyp *dst);
+
+ unsigned long hidden;
+ unsigned long timestamp;
+ uint64_t playlistID; // ID of the playlist, used in smart playlist rules
+ unsigned long unk3;
+ unsigned short numStringMHODs;
+ unsigned short podcastflag;
+ unsigned long numLibraryMHODs;
+
+ std::vector<iPod_mhod*> mhod;
+ std::vector<iPod_mhip*> mhip;
+
+ struct indexMhit
+ {
+ __forceinline bool operator()(indexMhit*& one, indexMhit*& two)
+ {
+#define RETIFNZ(x) { int yy = x; if(yy != 0) return yy < 0; }
+ //return(STRCMP_NULLOK(one->str.c_str(), two->str.c_str()) < 0 ? true : false);
+ RETIFNZ(STRCMP_NULLOK(one->str[0],two->str[0]));
+ RETIFNZ(STRCMP_NULLOK(one->str[1],two->str[1]));
+ RETIFNZ(STRCMP_NULLOK(one->str[2],two->str[2]));
+ RETIFNZ(one->track - two->track);
+ RETIFNZ(STRCMP_NULLOK(one->str[3],two->str[3]));
+ return true;
+#undef RETIFNZ
+ }
+
+ unsigned int index;
+ const wchar_t *str[4];
+ int track;
+ };
+
+ iPod_mhlt::mhit_map_t *mhit;
+ std::vector<uint32_t> mhit_indexer;
+ bool writeLibraryMHODs;
+
+ bool operator()(iPod_mhyp*& one, iPod_mhyp*& two);
+
+protected:
+ bool isSmartPlaylist;
+ bool isPopulated;
+};
+
+
+// MHIP: playlist item - child of MHYP
+class iPod_mhip : public iPodObj
+{
+public:
+ iPod_mhip();
+ virtual ~iPod_mhip();
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(unsigned char * data, const unsigned long datasize) { return write(data,datasize,0); }
+ virtual long write(unsigned char * data, const unsigned long datasize, int entrynum);
+
+ static void Duplicate(iPod_mhip *src, iPod_mhip *dst);
+
+ unsigned long dataobjectcount; // was unk1
+ unsigned long podcastgroupflag; // was corrid
+ unsigned long groupid; // was unk2
+ unsigned long songindex;
+ unsigned long timestamp;
+ unsigned long podcastgroupref;
+ std::vector<iPod_mhod*> mhod;
+};
+
+// MHOD: string container item, child of MHIT or MHYP
+// MHOD: string container item, child of MHIT or MHYP
+class iPod_mhod : public iPodObj
+{
+public:
+ iPod_mhod();
+ virtual ~iPod_mhod();
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(unsigned char * data, const unsigned long datasize);
+
+ void SetString(const wchar_t *string);
+
+ static void Duplicate(iPod_mhod *src, iPod_mhod *dst);
+
+ static bool IsSimpleStringType(const unsigned int type);
+
+ uint32_t type;
+ uint32_t unk1;
+ uint32_t unk2;
+
+ // renamed this from corrid.. all it is is a position in the playlist
+ // for type 100 mhods that come immediately after mhips.
+ // for strings, this is the encoded type. 1 == UTF-16, 2 == UTF-8
+ union
+ {
+ uint32_t position;
+ uint32_t encoding_type;
+ };
+
+ uint32_t length;
+ uint32_t unk3;
+ uint32_t unk4;
+
+ // string mhods get the string put here, unaltered, still byte reversed
+ // Use unicode functions to work with this string.
+ wchar_t *str;
+
+ // mhod types 50 and up get the whole thing put here.
+ // until I can figure out all of these, I won't bother to try to recreate them
+ // and i'll just copy them back as needed when rewriting the iTunesDB file.
+ uint8_t * binary;
+
+ // stuff for type 50 mhod
+ uint8_t liveupdate; // "Live Updating" check box
+ uint8_t checkrules; // "Match X of the following conditions" check box
+ uint8_t checklimits; // "Limit To..." check box. 1 = checked, 0 = not checked
+ uint8_t matchcheckedonly; // "Match only checked songs" check box.
+ uint8_t limitsort_opposite; // Limit Sort rule is reversed (e.g. limitsort == LIMIT_HIGHEST_RATING really means LIMIT_LOWEST_RATING...quite weird...)
+ uint32_t limittype; // See Limit Types defines above
+ uint32_t limitsort; // See Limit Sort defines above
+ uint32_t limitvalue; // Whatever value you type next to "limit type".
+
+ // stuff for type 51 mhod
+ uint32_t unk5; // not sure, probably junk data
+ uint32_t rules_operator; // "All" (logical AND / value = 0) or "Any" (logical OR / value = 1).
+ std::vector<SPLRule*> rule;
+
+ bool parseSmartPlaylists;
+};
+
+
+// Smart Playlist. A smart playlist doesn't act different from a regular playlist,
+// except that it contains a type 50 and type 51 MHOD. But deriving the iPod_slst
+// class makes sense, since there are a lot of functions that are only appropriate
+// for smart playlists, and it can guarantee that a type 50 and 51 MHOD will always
+// be available.
+class iPod_slst : public iPod_mhyp
+{
+public:
+ enum FieldType
+ {
+ ftString,
+ ftInt,
+ ftBoolean,
+ ftDate,
+ ftPlaylist,
+ ftUnknown,
+ ftBinaryAnd,
+ };
+
+ enum ActionType
+ {
+ atString,
+ atInt,
+ atBoolean,
+ atDate,
+ atRange,
+ atInTheLast,
+ atPlaylist,
+ atNone,
+ atInvalid,
+ atUnknown,
+ atBinaryAnd,
+ };
+
+
+ iPod_slst();
+ virtual ~iPod_slst();
+
+ iPod_mhod* GetPrefs(void) { UpdateMHODPointers(); return(splPref); }
+ void SetPrefs(const bool liveupdate = true, const bool rules_enabled = true, const bool limits_enabled = false,
+ const unsigned long limitvalue = 0, const unsigned long limittype = 0, const unsigned long limitsort = 0);
+
+ static FieldType GetFieldType(const unsigned long field);
+ static ActionType GetActionType(const unsigned long field, const unsigned long action);
+
+ static uint64_t ConvertDateValueToNum(const uint64_t val) { return(-(int64_t)val); }
+ static uint64_t ConvertNumToDateValue(const uint64_t val) { return(-(int64_t)val); }
+
+ // returns a pointer to the SPLDATA mhod
+ iPod_mhod* GetRules() { UpdateMHODPointers(); return(splData); }
+
+ // get the number of rules in the smart playlist
+ unsigned long GetRuleCount();
+
+ // Returns rule number (0 == first rule, -1 == error)
+ int AddRule(const unsigned long field,
+ const unsigned long action,
+ const wchar_t * string = NULL, // use string for string based rules
+ const uint64_t value = 0, // use value for single variable rules
+ const uint64_t from = 0, // use from and to for range based rules
+ const uint64_t to = 0,
+ const uint64_t units = 0); // use units for "in the last" based rules
+
+ int AddRule(const SPLRule& rule);
+
+ void RemoveAllRules(void);
+
+ // populates a smart playlist
+ // Pass in the mhlt with all the songs on the iPod, and it populates the playlist
+ // given those songs and the current rules
+ // Return value is number of songs in the resulting playlist.
+ long PopulateSmartPlaylist(iPod_mhlt * tracks, iPod_mhlp * playlists);
+
+ // used in PopulateSmartPlaylist
+ static bool EvalRule(
+ SPLRule * r,
+ iPod_mhit * track,
+ iPod_mhlt * tracks = NULL, // if you're going to allow playlist type rules
+ iPod_mhlp * playlists = NULL // these are required to be passed in
+ );
+
+ // Restore default prefs and remove all rules
+ void Reset(void);
+
+protected:
+ void UpdateMHODPointers(void);
+
+ iPod_mhod *splPref;
+ iPod_mhod *splData;
+};
+
+
+
+
+// MHDP: Play Count class
+class iPod_mhdp
+{
+public:
+ iPod_mhdp();
+ ~iPod_mhdp();
+ unsigned long size_head;
+ unsigned long entrysize;
+
+ const unsigned long GetChildrenCount() const { return children; }
+
+ // return value is number of songs or -1 if error.
+ // you should probably check to make sure the number of songs is the same
+ // as the number of songs you read in from parsing the iTunesDB
+ virtual long parse(const uint8_t *data);
+
+ // there is no write() function because there is no conceivable need to ever write a
+ // play counts file.
+
+ const PCEntry &GetPlayCount(const unsigned int pos) const { return entry[pos]; }
+
+ // playcounts are stored in the Play Counts file, in the same order as the mhits are
+ // stored in the iTunesDB. So you should apply the changes from these entries to the
+ // mhits in order and then probably delete the Play Counts file entirely to prevent
+ // doing it more than once.
+ PCEntry *entry;
+ uint32_t children;
+};
+
+
+
+
+// MHPO: On-The-Go Playlist class
+class iPod_mhpo
+{
+public:
+ iPod_mhpo();
+ virtual ~iPod_mhpo();
+
+ unsigned long size_head;
+ unsigned long unk1;
+ unsigned long unk2; // this looks like a timestamp, sorta
+
+ const unsigned long GetChildrenCount() const { return children; }
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(unsigned char * data, const unsigned long datasize);
+
+ // This will create a new playlist from the OTGPlaylist..
+ // Give it the DB to create the playlist in and from, and a name for the playlist.
+ // Return value is a pointer to the playlist itself, which will be inside the DB you
+ // give to it as well.
+ // Returns NULL on error (can't create the playlist)
+ iPod_mhyp * CreatePlaylistFromOTG(iPod_mhbd * iPodDB, wchar_t * name);
+
+ // OTGPlaylists are stored in the OTGPlaylist file. When iTunes copies them into a
+ // new playlist, it deletes the file afterwards. I do not know if creating this file
+ // will make the iPod have an OTGPlaylist after you undock it. I added the write function
+ // anyway, in case somebody wants to try it. Not much use for it though, IMO.
+ uint32_t *idList;
+ uint32_t children;
+};
+
+
+// MQED: EQ Presets holder
+class iPod_mqed
+{
+public:
+ iPod_mqed();
+ virtual ~iPod_mqed();
+
+ unsigned long size_head;
+ unsigned long unk1;
+ unsigned long unk2; // this looks like a timestamp, sorta
+
+ const unsigned long GetChildrenCount() const { return eqList.size(); }
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(unsigned char * data, const unsigned long datasize);
+
+ std::vector<iPod_pqed*> eqList;
+};
+
+// PQED: A single EQ Preset
+class iPod_pqed
+{
+public:
+ iPod_pqed();
+ virtual ~iPod_pqed();
+
+ unsigned long length; // length of name string
+ wchar_t * name; // name string
+
+/*
+ 10 band eq is not exactly what iTunes shows it to be.. It really is these:
+ 32Hz, 64Hz, 128Hz, 256Hz, 512Hz, 1024Hz, 2048Hz, 4096Hz, 8192Hz, 16384Hz
+
+ Also note that although these are longs, The range is only -1200 to +1200. That's dB * 100.
+*/
+
+ signed long preamp; // preamp setting
+
+ signed long eq[10]; // iTunes shows 10 bands for EQ presets
+ signed long short_eq[5]; // This is a 5 band version of the same thing (possibly what the iPod actually uses?)
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(unsigned char * data, const unsigned long datasize);
+};
+
+
+
+
+struct iTunesStatsEntry
+{
+ unsigned int GetBookmarkTimeInMilliseconds() { if(bookmarktime == 0xffffff) return(0); return(bookmarktime * 256); }
+
+ // These are 3 byte values
+ unsigned int entry_size;
+ unsigned int bookmarktime; // In 0.256 seconds units
+ unsigned int unk1; // Somehow associated with bookmark time
+ unsigned int unk2;
+ unsigned int playcount;
+ unsigned int skippedcount;
+};
+
+class iTunesStats
+{
+public:
+ iTunesStats();
+ ~iTunesStats();
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(unsigned char * data, const unsigned long datasize);
+
+ const unsigned long GetChildrenCount() const { return children; }
+ const iTunesStatsEntry &GetEntry(const unsigned int pos) const { return entry[pos];}
+
+ // This is a 3 byte value
+ unsigned int unk1;
+
+ iTunesStatsEntry *entry;
+ uint32_t children;
+ iPod_mhlt *mhlt;
+};
+
+
+class iTunesShuffle
+{
+public:
+ iTunesShuffle();
+ ~iTunesShuffle();
+
+ virtual long parse(const uint8_t *data);
+ virtual long write(unsigned char *data, const unsigned long datasize);
+
+ unsigned int GetChildrenCount() const { return numentries; }
+ unsigned int GetEntry(const unsigned int pos) const { return entry[pos]; }
+ //void AddEntry(const unsigned int index) { entry.push_back(index); }
+ void Randomize();
+ void Randomize(const unsigned int numsongs);
+
+ uint32_t *entry;
+ uint32_t numentries;
+ unsigned int datasize;
+};
+#endif
diff --git a/Src/Plugins/Portable/pmp_ipod/iPodDevice.cpp b/Src/Plugins/Portable/pmp_ipod/iPodDevice.cpp
new file mode 100644
index 00000000..60b5e2aa
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/iPodDevice.cpp
@@ -0,0 +1,1795 @@
+#include "iPodDevice.h"
+//#include <assert.h>
+#include "..\..\General\gen_ml/itemlist.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "../Winamp/wa_ipc.h"
+#include <math.h>
+#include "../Agave/Language/api_language.h"
+#include "api.h"
+#include <tataki/bitmap/bitmap.h>
+#include <tataki/canvas/bltcanvas.h>
+#include "iPodSD.h"
+#include <strsafe.h>
+#include <shlwapi.h>
+//#include "../nu/combobox.h"
+// needed to query for replaygain stuff
+
+static const GUID playbackConfigGroupGUID =
+{ 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } };
+
+extern PMPDevicePlugin plugin;
+extern time_t mactime_to_wintime (const unsigned long mactime);
+extern unsigned long wintime_to_mactime (const __time64_t time);
+extern wchar_t* UTF8_to_UTF16(char *str);
+extern BOOL EjectVolume(TCHAR cDriveLetter);
+
+extern std::vector<iPodDevice*> iPods;
+
+static __int64 fileSize(const wchar_t * filename);
+
+iPodDevice::iPodDevice(char deviceDrive)
+{
+ fwid=0;
+ info=0;
+ artdb=0;
+ gapscanner=0;
+ transcoder=0;
+ image16 = 0;
+ image160 = 0;
+ drive = deviceDrive;
+ driveW = ((int)(drive - 'A')) + L'A';
+ transferQueueLength=0;
+ db=NULL;
+ srand(GetTickCount());
+ dirnum = rand() % 20;
+
+
+ {
+ wchar_t artwork[] = {driveW,L":\\iPod_Control\\Artwork"};
+ _wmkdir(artwork);
+ wchar_t device[] = {driveW,L":\\iPod_Control\\Device"};
+ _wmkdir(device);
+ }
+
+ iPods.push_back(this);
+
+ pmpDeviceLoading load;
+ load.dev = this;
+ load.UpdateCaption = NULL;
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)&load,PMP_IPC_DEVICELOADING);
+
+ if(load.UpdateCaption)
+ {
+ load.UpdateCaption(WASABI_API_LNGSTRINGW(IDS_IPOD_LOADING),load.context);
+ }
+
+ info = GetiPodInfo(driveW);
+
+ // Get the artwork formats that are supported
+ if(info && info->numberOfSupportedFormats >0)
+ {
+ // formats are already available, read from the sysinfo xml
+ // just use them
+ for (int i=0; i<info->numberOfSupportedFormats; i++)
+ {
+ thumbs.push_back(&info->supportedArtworkFormats[i]);
+ }
+ }
+ else
+ {
+ // revert to the static list of supported artwork formats
+ const ArtworkFormat* art = GetArtworkFormats(info);
+ if(art) for(int i=0; art[i].type != THUMB_INVALID; i++)
+ {
+ if(art[i].type >= THUMB_COVER_SMALL && art[i].type <= THUMB_COVER_LARGE)
+ thumbs.push_back(&art[i]);
+ }
+ }
+
+ if(!info || parseiTunesDB(thumbs.size()!=0) < 0)
+ {
+ //iPods.eraseObject(this);
+ auto it = std::find(iPods.begin(), iPods.end(), this);
+ if (it != iPods.end())
+ {
+ iPods.erase(it);
+ }
+
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
+ delete this;
+ return;
+ }
+
+ image16 = info->image16;
+ image160 = info->image160;
+
+ db->mhsdplaylists->mhlp->SortPlaylists();
+
+ int n = db->mhsdplaylists->mhlp->GetChildrenCount();
+ for(int i=0; i<n; i++)
+ playlists.Add(db->mhsdplaylists->mhlp->GetPlaylist(i));
+
+
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICECONNECTED);
+
+ transcoder = (Transcoder*)SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)this,PMP_IPC_GET_TRANSCODER);
+ if(transcoder)
+ {
+ transcoder->AddAcceptableFormat(mmioFOURCC('M','4','A',' '));
+ transcoder->AddAcceptableFormat(L"mp3");
+ //transcoder->AddAcceptableFormat(L"wav");
+ transcoder->AddAcceptableFormat(L"m4v");
+ transcoder->AddAcceptableFormat(L"m4b");
+ transcoder->AddAcceptableFormat(L"aa\0\0");
+ transcoder->AddAcceptableFormat(L"mp4");
+ }
+ if (info->fwid)
+ {
+ fwid = (uint8_t *)malloc(8);
+ memcpy(fwid, info->fwid, 8);
+ }
+}
+
+iPodDevice::~iPodDevice() {
+ if(gapscanner) SendMessage(gapscanner,WM_CLOSE,0,0);
+ if(db) delete db; db=NULL;
+
+ char lockPath[] = {drive, ":\\iPod_Control\\iTunes\\iTunesLock"};
+ _unlink(lockPath);
+ if(transcoder) SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)transcoder,PMP_IPC_RELEASE_TRANSCODER);
+ delete info;
+ info=0;
+ free(fwid);
+}
+
+static unsigned char * readFile(char * path, int &len) {
+ FILE * f = fopen(path,"rb");
+ if(!f) return 0;
+ fseek(f,0,2); //seek to end
+ int l = ftell(f); //length of file
+ unsigned char * data = (unsigned char *)malloc(l);
+ if(!data)
+ {
+ fclose(f);
+ return 0;
+ }
+ fseek(f,0,0);
+ if(fread(data,1,l,f) != l) { fclose(f); free(data); return 0; }
+ fclose(f);
+ len = l;
+ return data;
+}
+
+static unsigned char * readFile(char * path) {
+ int l=0;
+ return readFile(path,l);
+}
+
+static HANDLE iTunesLock(char drive) { // returns false for unable to aquire lock.
+ char lockPath[] = {drive, ":\\iPod_Control\\iTunes\\iTunesLock"};
+ HANDLE h=CreateFileA(lockPath,GENERIC_READ,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
+ if(h == INVALID_HANDLE_VALUE) return h;
+ while(!LockFile(h,0,0,0,0)) Sleep(50);
+ return h;
+}
+
+static void iTunesUnlock(HANDLE h) {
+ UnlockFile(h,0,0,0,0);
+ CloseHandle(h);
+}
+
+int iPodDevice::parseiTunesDB(bool parseArt) {
+ HANDLE hLock = iTunesLock(drive);
+ if(hLock == INVALID_HANDLE_VALUE) return -1;
+ char dbPath[] = "x:\\iPod_Control\\iTunes\\iTunesDB";
+ dbPath[0]=drive;
+ unsigned char * data = readFile(dbPath);
+ if(data==0) {
+ iTunesUnlock(hLock);
+ return -1;
+ }
+ db = new iPod_mhbd;
+ int ret = db->parse(data);
+ free(data);
+ bool changed=false;
+ char playcounts[] = "x:\\iPod_Control\\iTunes\\Play Counts";
+ playcounts[0]=drive;
+ data = readFile(playcounts);
+ if(data) {
+ iPod_mhdp * mhdp = new iPod_mhdp;
+ int l = db->mhsdsongs->mhlt->GetChildrenCount();
+ if(mhdp->parse(data) == l) {
+ changed=true;
+ for(int i=0; i<l; i++) {
+ PCEntry p = mhdp->GetPlayCount(i);
+ iPod_mhit * mhit = db->mhsdsongs->mhlt->GetTrack(i);
+ if(!mhit) continue;
+ mhit->bookmarktime = p.bookmarktime;
+ mhit->lastplayedtime = p.lastplayedtime;
+ mhit->stars = (unsigned char)p.stars;
+ mhit->playcount = p.playcount;
+ mhit->skipcount = p.skipcount;
+ mhit->skippedtime = p.skippedtime;
+ }
+ }
+ delete mhdp;
+ free(data);
+ }
+ _unlink(playcounts);
+ db->mhsdplaylists->mhlp->GetPlaylist(0)->mhit = &db->mhsdsongs->mhlt->mhit;
+ char otg[] = "x:\\iPod_Control\\iTunes\\OTGPlaylistInfo";
+ otg[0]=drive;
+ data = readFile(otg);
+ if(data) {
+ iPod_mhpo * mhpo = new iPod_mhpo;
+ mhpo->parse(data);
+ mhpo->CreatePlaylistFromOTG(db,L"On The Go");
+ changed=true;
+ delete mhpo;
+ free(data);
+ }
+ _unlink(otg);
+ iTunesUnlock(hLock);
+ if(changed) writeiTunesDB();
+
+ if(parseArt) {
+ char dbPath[] = "x:\\iPod_Control\\Artwork\\ArtworkDB";
+ dbPath[0]=drive;
+ int l=0;
+ unsigned char * data = readFile(dbPath,l);
+ bool createNew=false;
+ if(data) {
+ artdb = new ArtDB();
+ int r = artdb->parse(data,l,driveW);
+ if(r<0) {
+ delete artdb;
+ artdb=NULL;
+ }
+ free(data);
+ } else createNew=true;
+
+ if(createNew) {
+ char dir[] = {drive,":\\iPod_Control\\Artwork"};
+ CreateDirectoryA(dir,NULL);
+ artdb = new ArtDB();
+ artdb->makeEmptyDB(driveW);
+ }
+ }
+
+ return ret;
+}
+
+extern bool ParseSysInfoXML(wchar_t drive_letter, char * xml, int xmllen);
+
+static unsigned char *GetFwId(wchar_t drive, unsigned char *fwid)
+{
+ char xml[65536] = {0};
+ if(!ParseSysInfoXML(drive, xml, sizeof(xml)/sizeof(char))) return NULL;
+ char *p = strstr(xml,"<key>FireWireGUID</key>");
+ if(!p) return 0;
+ p = strstr(p,"<string>");
+ if(!p) return 0;
+ p += strlen("<string>");
+ for(int i=0; i<8 && *p; i++) {
+ char num[3]={0,0,0};
+ num[0] = *(p++);
+ num[1] = *(p++);
+ fwid[i] = (uint8_t)strtoul(num,NULL,16);
+ }
+ return fwid;
+}
+
+int iPodDevice::writeiTunesDB()
+{
+ char dbPath[] = "x:\\iPod_Control\\iTunes\\iTunesDB"; dbPath[0]=drive;
+ char dbPathOld[] = "x:\\iPod_Control\\iTunes\\iTunesDB.old_mlpmp"; dbPathOld[0]=drive;
+ char dbPathNew[] = "x:\\iPod_Control\\iTunes\\iTunesDB.new_mlpmp"; dbPathNew[0]=drive;
+ if(!db) return -1;
+ HANDLE hLock = iTunesLock(drive);
+ if(hLock == INVALID_HANDLE_VALUE) return -1;
+ uint32_t allocate = (uint32_t)fileSize(AutoWide(dbPath));
+ int incr = 10000000;
+ bool done=false;
+ int i=0;
+ int ret=0;
+ unsigned char * data;
+
+ while(!done)
+ {
+ if(i++ > 10)
+ {
+ iTunesUnlock(hLock);
+ return -1;
+ }
+ allocate += incr;
+ data = (unsigned char*)malloc(allocate);
+ if(!data) return -1; //what else can we do?
+
+ // TODO: i'd like to cut this but it seems to still be causing problems to parse it from XML
+ unsigned char fwid[8]={0};
+ GetFwId(driveW, fwid);
+#ifdef _DEBUG
+ if (memcmp(fwid, this->fwid, 8) || memcmp(fwid, info->fwid, 8))
+ {
+ DebugBreak();
+ }
+#endif
+
+ int len = db->write(data,allocate, fwid);
+ if(len > 0) {
+ _unlink(dbPathOld);
+ _unlink(dbPathNew);
+ FILE * f = fopen(dbPathNew,"wb");
+ if(!f) {
+ iTunesUnlock(hLock);
+ return -1;
+ }
+ fwrite(data,1,len,f);
+ fclose(f);
+ rename(dbPath,dbPathOld);
+ _unlink(dbPath);
+ rename(dbPathNew,dbPath);
+ done=true;
+ ret=len;
+ } else free(data);
+ }
+
+
+ if(data)
+ {
+ if (info->shadow_db_version == 1)
+ {
+ iTunesSD1 sd;
+ int l = sd.write(&db->mhsdsongs->mhlt->mhit, data,allocate);
+ if(l>0)
+ {
+ char dbPath[] = "x:\\iPod_Control\\iTunes\\iTunesSD"; dbPath[0]=drive;
+ FILE * f = fopen(dbPath,"wb");
+ if(f) {
+ fwrite(data,1,l,f);
+ fclose(f);
+ }
+ }
+ }
+ else if (info->shadow_db_version == 2)
+ {
+ iTunesSD2 sd;
+ int l = sd.write(db->mhsdsongs->mhlt, db->mhsdplaylists->mhlp, data,allocate);
+ if(l>0)
+ {
+ char dbPath[] = "x:\\iPod_Control\\iTunes\\iTunesSD"; dbPath[0]=drive;
+ FILE * f = fopen(dbPath,"wb");
+ if(f) {
+ fwrite(data,1,l,f);
+ fclose(f);
+ }
+ }
+ }
+ }
+
+ if(artdb && data) {
+ int l = artdb->write(data,allocate);
+ if(l>0) {
+ char dbPath[] = "x:\\iPod_Control\\Artwork\\ArtworkDB"; dbPath[0]=drive;
+ FILE * f = fopen(dbPath,"wb");
+ if(f) {
+ fwrite(data,1,l,f);
+ fclose(f);
+ }
+ }
+ }
+
+ iTunesUnlock(hLock);
+ if(data) free(data);
+
+ return ret;
+}
+
+__int64 iPodDevice::getDeviceCapacityAvailable() {
+ ULARGE_INTEGER tfree={0,}, total={0,}, freeb={0,};
+ wchar_t path[4]=L"x:\\";
+ path[0]=drive;
+ GetDiskFreeSpaceEx(path, &tfree, &total, &freeb);
+ return freeb.QuadPart;
+}
+
+__int64 iPodDevice::getDeviceCapacityTotal() {
+ ULARGE_INTEGER tfree={0,}, total={0,}, freeb={0,};
+ wchar_t path[4]=L"x:\\";
+ path[0]=drive;
+ GetDiskFreeSpaceEx(path, &tfree, &total, &freeb);
+ return total.QuadPart;
+}
+
+void iPodDevice::Close()
+{
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
+ //writeiTunesDB();
+
+ //iPods.eraseObject(this);
+ auto it = std::find(iPods.begin(), iPods.end(), this);
+ if (it != iPods.end())
+ {
+ iPods.erase(it);
+ }
+
+ delete this;
+}
+
+void iPodDevice::Eject()
+{
+ //iPods.eraseObject(this);
+ auto it = std::find(iPods.begin(), iPods.end(), this);
+ if (it != iPods.end())
+ {
+ iPods.erase(it);
+ }
+
+ if(EjectVolume(drive))
+ {
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
+ delete this;
+ }
+ else
+ {
+ wchar_t titleStr[32] = {0};
+ iPods.push_back(this);
+ MessageBox(plugin.hwndLibraryParent,WASABI_API_LNGSTRINGW(IDS_FAILED_TO_EJECT_IPOD),
+ WASABI_API_LNGSTRINGW_BUF(IDS_ERROR,titleStr,32),0);
+ }
+}
+
+extern int CopyFile(const wchar_t * infile, const wchar_t * outfile, void * callbackContext, void (*callback)(void * callbackContext, wchar_t * status), int * killswitch);
+
+static __int64 fileSize(const wchar_t * filename)
+{
+ WIN32_FIND_DATA f={0};
+ HANDLE h = FindFirstFileW(filename,&f);
+ if(h == INVALID_HANDLE_VALUE) return -1;
+ FindClose(h);
+ ULARGE_INTEGER i;
+ i.HighPart = f.nFileSizeHigh;
+ i.LowPart = f.nFileSizeLow;
+ return i.QuadPart;
+}
+
+void GetFileInfo(const wchar_t * file, const wchar_t * metadata, wchar_t * buf, int len) {
+ buf[0]=0;
+ extendedFileInfoStructW m = {file,metadata,buf,(size_t)len};
+ SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&m,IPC_GET_EXTENDED_FILE_INFOW);
+}
+
+__int64 GetFileInfoInt64(wchar_t * file, wchar_t * metadata, BOOL *w=NULL) {
+ wchar_t buf[100]=L"";
+ GetFileInfo(file,metadata,buf,100);
+ if(w && buf[0]==0) {(*w) = 0; return 0;}
+ return _wtoi64(buf);
+}
+
+int GetFileInfoInt(wchar_t * file, wchar_t * metadata, BOOL *w=NULL) {
+ wchar_t buf[100]=L"";
+ GetFileInfo(file,metadata,buf,100);
+ if(w && buf[0]==0) {(*w) = 0; return 0;}
+ return _wtoi(buf);
+}
+
+int iPodDevice::transferTrackToDevice(const itemRecordW *track,void * callbackContext,void (*callback)(void * callbackContext, wchar_t * status),songid_t * songid,int * killswitch)
+{
+ bool transcodefile = false;
+ wchar_t outfile[2048] = {0};
+ wchar_t infile[MAX_PATH] = {0};
+ StringCchCopy(infile, MAX_PATH, track->filename);
+ bool nocopy=false;
+
+ iPod_mhit * mhit = db->mhsdsongs->mhlt->NewTrack();
+ dirnum = (dirnum + 1) % 20;
+
+ // create the output filename and directory
+ wchar_t ext[10]=L"";
+ const wchar_t *e = wcsrchr(infile,L'.');
+ if(e)
+ StringCbCopyW(ext, sizeof(ext), e);
+
+ if(transcoder && transcoder->ShouldTranscode(infile)) {
+ int r = transcoder->CanTranscode(infile,ext, track->length);
+ if(r != 0 && r != -1) transcodefile = true;
+ }
+
+ bool video = !_wcsicmp(ext,L".m4v");
+
+ if(!_wcsicmp(ext,L".mp4")) {
+ wchar_t buf[100]=L"0";
+ extendedFileInfoStructW m = {infile,L"type",buf,100};
+ SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&m,IPC_GET_EXTENDED_FILE_INFOW);
+ if(!wcscmp(buf,L"1")) { video=true; wcsncpy(ext,L".m4v",10); }
+ else wcsncpy(ext,L".m4a",10);
+ }
+
+ // and the location in the ipod naming scheme
+ if (infile[0] == drive && infile[1] && infile[1] == L':')
+ {
+ // file already on the ipod? add it directly
+ StringCbCopy(outfile, sizeof(outfile), infile);
+ nocopy=true;
+ }
+ else
+ {
+ StringCbPrintf(outfile,sizeof(outfile),L"%c:\\iPod_Control\\Music\\F%02d\\",(wchar_t)drive,dirnum);
+ CreateDirectory(outfile,NULL);
+ StringCbPrintf(outfile,sizeof(outfile),L"%c:\\iPod_Control\\Music\\F%02d\\w%05d%s",(wchar_t)drive,dirnum,mhit->id,ext);
+ }
+
+ wchar_t location[2048] = {0};
+ StringCbCopy(location, sizeof(location), outfile+2);
+ int i=0;
+ while(location[i] != 0) { if(location[i]==L'\\') location[i]=L':'; i++; }
+
+ {
+ wchar_t buf[100]=L"";
+ int which = AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"replaygain_source", 0);
+ extendedFileInfoStructW m = {infile,which?L"replaygain_album_gain":L"replaygain_track_gain",buf,100};
+ SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&m,IPC_GET_EXTENDED_FILE_INFOW);
+ if(buf[0]) {
+ double gain = _wtof(&buf[buf[0]==L'+'?1:0]);
+ mhit->soundcheck = (unsigned long)(1000.0 * pow(10.0,-0.1*gain));
+ }
+ }
+
+ // fill in the new MHIT (track item) with our metadata
+ mhit->AddString(MHOD_TITLE)->SetString(track->title);
+ mhit->AddString(MHOD_LOCATION)->SetString(location);
+ mhit->AddString(MHOD_ALBUM)->SetString(track->album);
+ mhit->AddString(MHOD_ARTIST)->SetString(track->artist);
+ mhit->AddString(MHOD_GENRE)->SetString(track->genre);
+ mhit->AddString(MHOD_COMMENT)->SetString(track->comment);
+ mhit->AddString(MHOD_ALBUMARTIST)->SetString(track->albumartist);
+ mhit->AddString(MHOD_COMPOSER)->SetString(track->composer);
+ mhit->length = (track->length>0)?track->length*1000:0;
+ mhit->year = (track->year>0)?track->year:0;
+ mhit->tracknum = (track->track>0)?track->track:0;
+ mhit->totaltracks = (track->tracks>0)?track->tracks:0;
+ mhit->stars = (unsigned char)(mhit->app_rating = track->rating);
+ mhit->playcount = mhit->playcount2 = track->playcount;
+ mhit->lastplayedtime = wintime_to_mactime(track->lastplay);
+ mhit->lastmodifiedtime = wintime_to_mactime(track->lastupd);
+ mhit->compilation = track->albumartist && !_wcsicmp(track->albumartist, L"various artists");
+ mhit->samplerate = 44100; // TODO: benski> we could query this from the input plugin, but we'd have to be careful with HE-AAC
+ mhit->samplerate2 = 44100.0f;
+ mhit->mediatype = video?0x02:0x01;
+ mhit->movie_flag = video?1:0;
+ mhit->cdnum = (track->disc>0)?track->disc:0;
+ mhit->totalcds = (track->discs>0)?track->discs:0;
+ mhit->BPM=(track->bpm>0)?track->bpm:0;
+
+ wchar_t *pubdate = getRecordExtendedItem(track,L"podcastpubdate");
+ if(pubdate && *pubdate) mhit->releasedtime=wintime_to_mactime(_wtoi(pubdate));
+
+ // copy the file over
+ int r;
+ if(transcodefile)
+ r = transcoder->TranscodeFile(infile,outfile,killswitch,callback,callbackContext);
+ else if (!nocopy)
+ r = CopyFile(infile,outfile,callbackContext,callback,killswitch);
+ else
+ {
+ if (callback)
+ {
+ wchar_t langtemp[100] = {0};
+ callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_DONE, langtemp, 100));
+ }
+ r=0;
+ }
+ if(r == 0)
+ {
+ StringCbCopyW(ext, sizeof(ext), wcsrchr(outfile,L'.'));
+ if (!_wcsicmp(ext, L".m4a") || !_wcsicmp(ext, L".mp4"))
+ {
+ mhit->vbr = 0;
+ mhit->type = 0;
+ mhit->unk14 = 51;
+ mhit->filetype = FILETYPE_M4A;
+ }
+ else if (!_wcsicmp(ext, L".mp3"))
+ {
+ mhit->type = 1;
+ mhit->unk27 = 1;
+ mhit->unk14 = 12;
+ mhit->AddString(MHOD_FILETYPE)->SetString(L"MPEG audio file");
+ mhit->filetype = FILETYPE_MP3;
+ }
+ else if (!_wcsicmp(ext, L".wav"))
+ {
+ mhit->filetype = FILETYPE_WAV;
+ }
+ mhit->samplecount = GetFileInfoInt64(outfile,L"numsamples");
+ mhit->pregap = (unsigned long)GetFileInfoInt64(outfile,L"pregap");
+ mhit->postgap = (unsigned long)GetFileInfoInt64(outfile,L"postgap");
+ mhit->gaplessData = (unsigned long)GetFileInfoInt64(outfile,L"endoffset");
+ mhit->trackgapless = 1;
+
+ mhit->size = (unsigned long)fileSize(outfile);
+ if (!transcodefile && track->bitrate > 0)
+ mhit->bitrate = track->bitrate;
+ else
+ {
+ mhit->bitrate = (unsigned long)GetFileInfoInt64(outfile,L"bitrate");
+ if (!mhit->bitrate)
+ {
+ if (track->length > 0)
+ mhit->bitrate = (mhit->size / track->length)/125;
+ else
+ mhit->bitrate = 128;
+ }
+ }
+
+
+ *songid = (songid_t)mhit;
+ }
+ else
+ {
+ DeleteFileW(outfile);
+ delete mhit;
+ }
+ return r;
+}
+
+int iPodDevice::trackAddedToTransferQueue(const itemRecordW *track) {
+ __int64 l;
+ if(transcoder && transcoder->ShouldTranscode(track->filename)) {
+ int k = transcoder->CanTranscode(track->filename, 0, track->length);
+ if(k == -1) return -2;
+ if(k == 0) l = (__int64)fileSize(track->filename);
+ else l = (__int64)k;
+ } else {
+ wchar_t * ext = wcsrchr(track->filename,L'.');
+ if(!ext) return -2;
+ if(_wcsicmp(ext,L".mp3") && _wcsicmp(ext,L".wav") && _wcsicmp(ext,L".m4a") &&
+ _wcsicmp(ext,L".m4b") && _wcsicmp(ext,L".aa") && _wcsicmp(ext,L".m4v") &&
+ _wcsicmp(ext,L".mp4")) return -2;
+
+ l = (__int64)fileSize(track->filename);
+ }
+ __int64 avail = getDeviceCapacityAvailable();
+ __int64 cmp = transferQueueLength;
+ cmp += l;
+ cmp += (__int64)3000000;
+
+ if(cmp > avail)
+ return -1;
+ else {
+ transferQueueLength += l;
+ return 0;
+ }
+}
+
+void iPodDevice::trackRemovedFromTransferQueue(const itemRecordW *track) {
+ __int64 l = (__int64)fileSize(track->filename);
+ if(transcoder && transcoder->ShouldTranscode(track->filename)) {
+ int k = transcoder->CanTranscode(track->filename, 0, track->length);
+ if(k != -1 && k != 0) l = (__int64)k;
+ }
+ transferQueueLength -= l;
+}
+
+__int64 iPodDevice::getTrackSizeOnDevice(const itemRecordW *track) {
+ if(transcoder && transcoder->ShouldTranscode(track->filename)) {
+ int k = transcoder->CanTranscode(track->filename, 0, track->length);
+ if(k != -1 && k != 0) return k;
+ }
+ wchar_t * ext = wcsrchr(track->filename,'.');
+ if(!ext) return 0;
+ if(_wcsicmp(ext,L".mp3") && _wcsicmp(ext,L".wav") && _wcsicmp(ext,L".m4a") &&
+ _wcsicmp(ext,L".m4b") && _wcsicmp(ext,L".aa") && _wcsicmp(ext,L".m4v") &&
+ _wcsicmp(ext,L"mp4")) return 0;
+ return fileSize(track->filename);
+}
+
+void iPodDevice::deleteTrack(songid_t songid) {
+
+ iPod_mhit * mhit = (iPod_mhit *)songid;
+ iPod_mhod * mhod = mhit->FindString(MHOD_LOCATION);
+ if(!mhod) return;
+ wchar_t * t = mhod->str;
+
+ // change ':' to '\\;
+ wchar_t * p = t;
+ int l = wcslen(t);
+ for(int j=0; j<l; j++) if(*(p++)==L':') *(p-1)=L'\\';
+
+ // add drive onto front
+ wchar_t file[2048] = L"x:\\";
+ file[0] = driveW;
+ wcscat(file,t);
+
+ //check this file isn't playing...
+ wchar_t* curPlaying = (wchar_t*)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_GET_PLAYING_FILENAME);
+ if(curPlaying && !_wcsicmp(curPlaying,file)) SendMessage(plugin.hwndWinampParent,WM_COMMAND,40047,0); //stop
+
+ //delete :)
+ // benski> we might have a file that has been deleted from the disk but not the DB
+ if(!DeleteFileW(file) // check for file failure
+ && GetFileAttributes(file) != INVALID_FILE_ATTRIBUTES) // but only fail if the file actually exists
+ return;
+
+ setArt(songid,NULL,0,0);
+
+ l = playlists.GetSize();
+ for(int i=0; i<l; i++) {
+ iPod_mhyp * mhyp = ((iPod_mhyp*)playlists.Get(i)); //->DeletePlaylistEntryByID(mhit->id);
+ for(unsigned int j=0; j<mhyp->GetMhipChildrenCount(); j++) {
+ if(mhyp->GetPlaylistEntry(j)->songindex == mhit->id) mhyp->DeletePlaylistEntry(j);
+ }
+ }
+
+
+ db->mhsdsongs->mhlt->DeleteTrackByID(mhit->id);
+}
+
+int iPodDevice::getPlaylistCount() {
+ return playlists.GetSize();
+}
+
+static void readStringMHOD(iPod_mhod * mhod, wchar_t * buf, int len) {
+ if(mhod) lstrcpyn(buf,mhod->str,len);
+ else buf[0]=0;
+}
+
+static void setStringMHOD(iPod_mhod * mhod, const wchar_t *buf) {
+ mhod->SetString(buf);
+}
+
+void iPodDevice::getPlaylistName(int playlistnumber, wchar_t * buf, int len) {
+ iPod_mhod * name = ((iPod_mhyp*)playlists.Get(playlistnumber))->FindString(MHOD_TITLE);
+ readStringMHOD(name,buf,len);
+}
+
+int iPodDevice::getPlaylistLength(int playlistnumber) {
+ return ((iPod_mhyp*)playlists.Get(playlistnumber))->GetMhipChildrenCount();
+}
+
+static iPod_mhit blank;
+
+songid_t iPodDevice::getPlaylistTrack(int playlistnumber,int songnum) {
+ int idx = ((iPod_mhyp*)playlists.Get(playlistnumber))->GetPlaylistEntry(songnum)->songindex;
+ iPod_mhlt::mhit_map_t::const_iterator f = db->mhsdsongs->mhlt->mhit.find(idx);
+ if(f != db->mhsdsongs->mhlt->mhit.end() && idx) return (songid_t)f->second;
+ else {
+ iPod_mhip* m = ((iPod_mhyp*)playlists.Get(playlistnumber))->GetPlaylistEntry(songnum);
+ blank.DeleteString(4);
+ if(m->podcastgroupflag && m->mhod[0]) {
+ iPod_mhod * mh = blank.AddString(4);
+ mh->SetString(m->mhod[0]->str);
+ }
+ return (songid_t)&blank;
+ }
+}
+
+void iPodDevice::setPlaylistName(int playlistnumber, const wchar_t *buf) {
+ iPod_mhod * name = ((iPod_mhyp*)playlists.Get(playlistnumber))->FindString(MHOD_TITLE);
+ if(!name) name = ((iPod_mhyp*)playlists.Get(playlistnumber))->AddString(MHOD_TITLE);
+ setStringMHOD(name,buf);
+ if(playlistnumber == 0) {
+ wchar_t volumename[12] = {0};
+ const wchar_t * p = buf;
+ for(int i=0; i<11;) {
+ if(*p!=L' ' && *p!=L'\t') volumename[i++]=*p;
+ if(*(p++)==0) break;
+ }
+ volumename[11]=0;
+ char root[] = {drive,":\\"};
+ SetVolumeLabel(AutoWide(root),volumename);
+ }
+}
+
+void iPodDevice::playlistSwapItems(int playlistnumber, int posA, int posB) {
+ iPod_mhyp * p = ((iPod_mhyp*)playlists.Get(playlistnumber));
+ iPod_mhip * a = p->mhip.at(posA);
+ iPod_mhip * b = p->mhip.at(posB);
+ if(a && b) {
+ p->mhip[posA] = b;
+ p->mhip[posB] = a;
+ }
+}
+
+static iPod_mhyp * sortpl;
+static int sortby;
+static iPod_mhbd * sortdb;
+
+#define CMPFIELDS(x) { int v=0; iPod_mhod * am = a->FindString(x); iPod_mhod * bm = b->FindString(x); if(am && bm) v = lstrcmpi(am->str,bm->str); else if(am != bm) v = am==NULL?-1:1; if(v!=0) return v<0; }
+#define CMPINTFIELDS(x,y) { int v = x-y; if(v!=0) return v<0; }
+
+struct PlaylistItemSort {
+ bool operator()(iPod_mhip*& ap,iPod_mhip*& bp) {
+ int use_by = sortby;
+ iPod_mhit * a = sortdb->mhsdsongs->mhlt->mhit.find(ap->songindex)->second;
+ iPod_mhit * b = sortdb->mhsdsongs->mhlt->mhit.find(bp->songindex)->second;
+
+ // this might be too slow, but it'd be nice
+ int x;
+ for (x = 0; x < 5; x ++)
+ {
+ if (use_by == SORTBY_TITLE) // title -> artist -> album -> disc -> track
+ {
+ CMPFIELDS(MHOD_TITLE);
+ use_by=SORTBY_ARTIST;
+ }
+ else if (use_by == SORTBY_ARTIST) // artist -> album -> disc -> track -> title
+ {
+ CMPFIELDS(MHOD_ARTIST);
+ use_by=SORTBY_ALBUM;
+ }
+ else if (use_by == SORTBY_ALBUM) // album -> disc -> track -> title -> artist
+ {
+ CMPFIELDS(MHOD_ALBUM);
+ use_by=SORTBY_DISCNUM;
+ }
+ else if (use_by == SORTBY_DISCNUM) // disc -> track -> title -> artist -> album
+ {
+ CMPINTFIELDS(a->cdnum,b->cdnum);
+ use_by=SORTBY_TRACKNUM;
+ }
+ else if (use_by == SORTBY_TRACKNUM) // track -> title -> artist -> album -> disc
+ {
+ CMPINTFIELDS(a->tracknum,b->tracknum);
+ use_by=SORTBY_TITLE;
+ }
+ else if (use_by == SORTBY_GENRE) // genre -> artist -> album -> disc -> track
+ {
+ CMPFIELDS(MHOD_GENRE);
+ use_by=SORTBY_ARTIST;
+ }
+ else if (use_by == SORTBY_PLAYCOUNT) // size -> artist -> album -> disc -> track
+ {
+ CMPINTFIELDS(a->playcount,b->playcount);
+ use_by=SORTBY_ARTIST;
+ }
+ else if (use_by == SORTBY_RATING) // size -> artist -> album -> disc -> track
+ {
+ CMPINTFIELDS(a->stars,b->stars);
+ use_by=SORTBY_ARTIST;
+ }
+ else if (use_by == SORTBY_LASTPLAYED)
+ {
+ double t = difftime(a->lastplayedtime,b->lastplayedtime);
+ if(t != 0) return t>0;
+ use_by=SORTBY_ARTIST;
+ }
+ else break; // no sort order?
+ }
+ return false;
+ }
+};
+
+#undef CMPFIELDS
+#undef CMPINTFIELDS
+
+void iPodDevice::sortPlaylist(int playlistnumber, int sortby0) {
+ sortpl = ((iPod_mhyp*)playlists.Get(playlistnumber));
+ sortby = sortby0;
+ sortdb = db;
+ std::sort(sortpl->mhip.begin(),sortpl->mhip.end(),PlaylistItemSort());
+}
+
+void iPodDevice::addTrackToPlaylist(int playlistnumber, songid_t songid)
+{
+ iPod_mhit *mhit = (iPod_mhit *)songid;
+
+ if (playlistnumber == 0)
+ {
+ db->mhsdsongs->mhlt->AddTrack(mhit);
+ db->mhsdplaylists->mhlp->GetDefaultPlaylist()->AddPlaylistEntry(NULL, mhit->id);
+ }
+ else
+ {
+ ((iPod_mhyp*)playlists.Get(playlistnumber))->AddPlaylistEntry(NULL, mhit->id);
+ }
+}
+
+void iPodDevice::removeTrackFromPlaylist(int playlistnumber, int songnum) {
+ ((iPod_mhyp*)playlists.Get(playlistnumber))->DeletePlaylistEntry(songnum);
+}
+
+void iPodDevice::deletePlaylist(int playlistnumber) {
+ iPod_mhyp* p = ((iPod_mhyp*)playlists.Get(playlistnumber));
+ playlists.Del(playlistnumber);
+ db->mhsdplaylists->mhlp->DeletePlaylistByID(p->playlistID);
+}
+
+int iPodDevice::newPlaylist(const wchar_t *name) {
+ iPod_mhyp * p = db->mhsdplaylists->mhlp->AddPlaylist();
+ playlists.Add(p);
+ int ret = db->mhsdplaylists->mhlp->GetChildrenCount() - 1;
+ setPlaylistName(ret,name);
+ db->mhsdplaylists->mhlp->SortPlaylists();
+ return ret;
+}
+
+void iPodDevice::getTrackArtist(songid_t songid, wchar_t * buf, int len) {
+ iPod_mhod * mhod = ((iPod_mhit *)songid)->FindString(MHOD_ARTIST);
+ readStringMHOD(mhod,buf,len);
+}
+
+void iPodDevice::getTrackAlbum(songid_t songid, wchar_t * buf, int len) {
+ iPod_mhod * mhod = ((iPod_mhit *)songid)->FindString(MHOD_ALBUM);
+ readStringMHOD(mhod,buf,len);
+}
+
+void iPodDevice::getTrackTitle(songid_t songid, wchar_t * buf, int len) {
+ iPod_mhod * mhod = ((iPod_mhit *)songid)->FindString(MHOD_TITLE);
+ readStringMHOD(mhod,buf,len);
+}
+
+void iPodDevice::getTrackGenre(songid_t songid, wchar_t * buf, int len) {
+ iPod_mhod * mhod = ((iPod_mhit *)songid)->FindString(MHOD_GENRE);
+ readStringMHOD(mhod,buf,len);
+}
+
+int iPodDevice::getTrackTrackNum(songid_t songid) {
+ return ((iPod_mhit *)songid)->tracknum;
+}
+
+int iPodDevice::getTrackDiscNum(songid_t songid) {
+ return ((iPod_mhit *)songid)->cdnum;
+}
+
+int iPodDevice::getTrackYear(songid_t songid) {
+ return (int)(((iPod_mhit *)songid)->year);
+}
+
+__int64 iPodDevice::getTrackSize(songid_t songid) {
+ return ((iPod_mhit *)songid)->size;
+}
+
+int iPodDevice::getTrackLength(songid_t songid) {
+ return ((iPod_mhit *)songid)->length;
+}
+
+int iPodDevice::getTrackBitrate(songid_t songid) {
+ return ((iPod_mhit *)songid)->bitrate;
+}
+
+int iPodDevice::getTrackPlayCount(songid_t songid) {
+ return ((iPod_mhit *)songid)->playcount;
+}
+
+int iPodDevice::getTrackRating(songid_t songid) {
+ return ((iPod_mhit *)songid)->stars / 20;
+}
+
+__time64_t iPodDevice::getTrackLastPlayed(songid_t songid) {
+ return mactime_to_wintime(((iPod_mhit *)songid)->lastplayedtime);
+}
+
+__time64_t iPodDevice::getTrackLastUpdated(songid_t songid) {
+ return mactime_to_wintime(((iPod_mhit *)songid)->lastmodifiedtime);
+}
+
+void iPodDevice::getTrackAlbumArtist(songid_t songid, wchar_t * buf, int len) {
+ iPod_mhod * mhod = ((iPod_mhit *)songid)->FindString(MHOD_ALBUMARTIST);
+ readStringMHOD(mhod,buf,len);
+ if(!mhod) getTrackArtist(songid,buf,len);
+}
+void iPodDevice::getTrackComposer(songid_t songid, wchar_t * buf, int len) {
+ iPod_mhod * mhod = ((iPod_mhit *)songid)->FindString(MHOD_COMPOSER);
+ readStringMHOD(mhod,buf,len);
+}
+
+int iPodDevice::getTrackType(songid_t songid) {
+ iPod_mhod * mhod = ((iPod_mhit *)songid)->FindString(MHOD_LOCATION);
+ if(!mhod) return 0;
+ wchar_t * ext = wcsrchr(mhod->str,L'.');
+ if(!ext) return 0;
+ if(!_wcsicmp(ext,L".m4v")) return 1;
+ return 0;
+}
+
+void iPodDevice::getTrackExtraInfo(songid_t songid, const wchar_t *field, wchar_t * buf, int len) {
+ if(!wcscmp(field,FIELD_EXTENSION)) {
+ wchar_t buf2[1024]=L"";
+ getFilename(buf2,1024,songid);
+ wchar_t * ext = wcsrchr(buf2,L'.');
+ if(ext) { ext++; lstrcpyn(buf,ext,len); }
+ }
+}
+
+void iPodDevice::setTrackArtist(songid_t songid, const wchar_t *value) {
+ iPod_mhod * mhod = ((iPod_mhit *)songid)->FindString(MHOD_ARTIST);
+ if(!mhod) mhod = ((iPod_mhit *)songid)->AddString(MHOD_ARTIST);
+ setStringMHOD(mhod,value);
+}
+
+void iPodDevice::setTrackAlbum(songid_t songid, const wchar_t *value) {
+ iPod_mhod * mhod = ((iPod_mhit *)songid)->FindString(MHOD_ALBUM);
+ if(!mhod) mhod = ((iPod_mhit *)songid)->AddString(MHOD_ALBUM);
+ setStringMHOD(mhod,value);
+}
+
+void iPodDevice::setTrackTitle(songid_t songid, const wchar_t *value) {
+ iPod_mhod * mhod = ((iPod_mhit *)songid)->FindString(MHOD_TITLE);
+ if(!mhod) mhod = ((iPod_mhit *)songid)->AddString(MHOD_TITLE);
+ setStringMHOD(mhod,value);
+}
+
+void iPodDevice::setTrackTrackNum(songid_t songid, int value) {
+ ((iPod_mhit *)songid)->tracknum = value;
+}
+
+void iPodDevice::setTrackDiscNum(songid_t songid, int value) {
+ ((iPod_mhit *)songid)->cdnum = value;
+}
+
+void iPodDevice::setTrackGenre(songid_t songid, const wchar_t *value) {
+ iPod_mhod * mhod = ((iPod_mhit *)songid)->FindString(MHOD_GENRE);
+ if(!mhod) mhod = ((iPod_mhit *)songid)->AddString(MHOD_GENRE);
+ setStringMHOD(mhod,value);
+}
+
+void iPodDevice::setTrackYear(songid_t songid, int value) {
+ ((iPod_mhit *)songid)->year = (unsigned long)value;
+}
+
+void iPodDevice::setTrackPlayCount(songid_t songid, int value) {
+ ((iPod_mhit *)songid)->playcount = value;
+}
+
+void iPodDevice::setTrackRating(songid_t songid, int value) {
+ ((iPod_mhit *)songid)->app_rating = ((iPod_mhit *)songid)->stars = value*20;
+}
+
+void iPodDevice::setTrackLastPlayed(songid_t songid, __time64_t value) {
+ ((iPod_mhit *)songid)->lastplayedtime = wintime_to_mactime(value);
+}
+
+void iPodDevice::setTrackLastUpdated(songid_t songid, __time64_t value) {
+ ((iPod_mhit *)songid)->lastmodifiedtime = wintime_to_mactime(value);
+}
+
+void iPodDevice::setTrackAlbumArtist(songid_t songid, const wchar_t *value) {
+ iPod_mhod * mhod = ((iPod_mhit *)songid)->FindString(MHOD_ALBUMARTIST);
+ if(!mhod) mhod = ((iPod_mhit *)songid)->AddString(MHOD_ALBUMARTIST);
+ setStringMHOD(mhod,value);
+}
+
+void iPodDevice::setTrackComposer(songid_t songid, const wchar_t *value) {
+ iPod_mhod * mhod = ((iPod_mhit *)songid)->FindString(MHOD_COMPOSER);
+ if(!mhod) mhod = ((iPod_mhit *)songid)->AddString(MHOD_COMPOSER);
+ setStringMHOD(mhod,value);
+}
+
+void iPodDevice::getFilename(char * buf, int len, songid_t song) {
+ iPod_mhod * mhod = ((iPod_mhit *)song)->FindString(MHOD_LOCATION);
+ if(!mhod) {buf[0]=0; return;}
+ char * filename = UTF16_to_char(mhod->str,mhod->length);
+ char * p = filename;
+ buf[0] = drive;
+ buf[1] = ':';
+ int j=2;
+ while(p && *p && j < len-1) { if(*p==':') buf[j]='\\'; else buf[j]=*p; p++; j++; }
+ buf[j]=0;
+ free(filename);
+}
+
+void iPodDevice::getFilename(wchar_t * buf, int len, songid_t song) {
+ iPod_mhod * mhod = ((iPod_mhit *)song)->FindString(MHOD_LOCATION);
+ if(!mhod) {buf[0]=0; return;}
+ wchar_t * filename = mhod->str;
+ wchar_t * p = filename;
+ buf[0] = drive;
+ buf[1] = L':';
+ int j=2;
+ while(p && *p && j < len-1) { if(*p==L':') buf[j]=L'\\'; else buf[j]=*p; p++; j++; }
+ buf[j]=0;
+}
+
+typedef struct { songid_t song; Device * dev; const wchar_t * filename; } tagItem;
+
+static wchar_t * tagFunc(const wchar_t * tag, void * p) { //return 0 if not found, -1 for empty tag
+ tagItem * s = (tagItem *)p;
+ int len = 2048;
+ wchar_t * buf = (wchar_t *)malloc(sizeof(wchar_t)*len);
+ if (!_wcsicmp(tag, L"artist")) s->dev->getTrackArtist(s->song,buf,len);
+ else if (!_wcsicmp(tag, L"album")) s->dev->getTrackAlbum(s->song,buf,len);
+ else if (!_wcsicmp(tag, L"title")) s->dev->getTrackTitle(s->song,buf,len);
+ else if (!_wcsicmp(tag, L"genre")) s->dev->getTrackGenre(s->song,buf,len);
+ else if (!_wcsicmp(tag, L"year"))
+ {
+ int year = s->dev->getTrackYear(s->song);
+ if (year>0)
+ StringCchPrintf(buf,len,L"%d",year);
+ else
+ buf[0]=0;
+ }
+ else if (!_wcsicmp(tag, L"tracknumber") || !_wcsicmp(tag, L"track"))
+ {
+ int track = s->dev->getTrackTrackNum(s->song);
+ if (track>0)
+ StringCchPrintf(buf,len,L"%d",track);
+ else
+ buf[0]=0;
+ }
+ else if (!_wcsicmp(tag, L"discnumber"))
+ {
+ int disc = s->dev->getTrackDiscNum(s->song);
+ if (disc>0)
+ StringCchPrintf(buf,len,L"%d",disc);
+ else
+ buf[0]=0;
+ }
+ else if (!_wcsicmp(tag, L"bitrate"))
+ {
+ int bitrate = s->dev->getTrackBitrate(s->song);
+ if (bitrate>0)
+ StringCchPrintf(buf,len,L"%d",bitrate);
+ else
+ buf[0]=0;
+ }
+ else if (!_wcsicmp(tag, L"filename")) lstrcpyn(buf,s->filename,len);
+ else buf[0]=0;
+ return buf;
+}
+
+static void tagFreeFunc(wchar_t *tag, void *p) { if(tag) free(tag); }
+
+void getTitle(Device * dev, songid_t song, const wchar_t * filename, wchar_t * buf, int len) {
+ buf[0]=0; buf[len-1]=0;
+ tagItem item = {song,dev,filename};
+ waFormatTitleExtended fmt={filename,0,NULL,&item,buf,len,tagFunc,tagFreeFunc};
+ SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&fmt, IPC_FORMAT_TITLE_EXTENDED);
+}
+
+bool iPodDevice::playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue) {
+ //char buf[2048]="";
+ wchar_t wbuf[2048]=L"";
+
+ if(!enqueue) { //clear playlist
+ SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_DELETE);
+ /*int l=SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_PE_GETINDEXTOTAL);
+ while(l>=0) SendMessage(plugin.hwndWinampParent,WM_WA_IPC,--l,IPC_PE_DELETEINDEX);*/
+ }
+
+ for(int i=0; i<listLength; i++) {
+ getFilename(wbuf,2048,songidList[i]);
+ //strcpy(buf,AutoChar(wbuf));
+
+ wchar_t title[2048] = {0};
+ getTitle(this,songidList[i],wbuf,title,2048);
+
+ /*enqueueFileWithMetaStruct s={buf,strdup(AutoChar(title)),getTrackLength(songidList[i])/1000};
+ SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILE);
+ free((void*)s.title);*/
+
+ enqueueFileWithMetaStructW s={wbuf,_wcsdup(title),PathFindExtensionW(wbuf),getTrackLength(songidList[i]) / 1000};
+ SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
+ free((void*)s.title);
+ }
+
+ if(!enqueue) { //play item startPlaybackAt
+ SendMessage(plugin.hwndWinampParent,WM_WA_IPC,startPlaybackAt,IPC_SETPLAYLISTPOS);
+ SendMessage(plugin.hwndWinampParent,WM_COMMAND,40047,0); //stop
+ SendMessage(plugin.hwndWinampParent,WM_COMMAND,40045,0); //play
+ }
+ return true;
+}
+
+int iPodDevice::copyToHardDrive(songid_t song, // the song to copy
+ wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ ) // -1 for failed/not supported. 0 for success.
+{
+ wchar_t fn[2048] = {0}; // song filename on ipod
+ getFilename(fn,2048,song);
+ wchar_t * ext = wcsrchr(fn,L'.');
+ if(!ext) { callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_INVALID_TRACK)); return -1; }
+ wcscat(path,ext);
+ return CopyFile(fn,path,callbackContext,callback,killswitch);
+}
+
+// art functions
+static void fileputinhole(const wchar_t* file, unsigned int pos, int len, void* newdata) {
+ __int64 fs = fileSize(file);
+ int open_flags = OPEN_EXISTING;
+ if(fs <= 0) open_flags = CREATE_NEW;
+ HANDLE hw = CreateFile(file,GENERIC_WRITE | GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,open_flags,0,NULL);
+ if(hw == INVALID_HANDLE_VALUE) return;
+ SetFilePointer(hw,pos,NULL,FILE_BEGIN);
+ DWORD written=0;
+ WriteFile(hw,newdata,len,&written,NULL);
+ CloseHandle(hw);
+}
+
+ArtDataObject * makeThumbMetadata(const ArtworkFormat * thumb, wchar_t drive, Image * image, ArtDB *artdb) {
+ wchar_t file[MAX_PATH] = {0};
+ wsprintfW(file,L"%c:\\iPod_Control\\Artwork\\F%04d_1.ithmb",drive,thumb->correlation_id);
+
+ bool found=false;
+ ArtFile *f=NULL;
+ for(size_t i=0; i < artdb->fileListDS->fileList->files.size(); i++) {
+ f = artdb->fileListDS->fileList->files[i];
+ if(f->corrid == thumb->correlation_id) { found=true; break; }
+ }
+ if(!found) {
+ f = new ArtFile;
+ f->corrid = thumb->correlation_id;
+ f->imagesize = image->get16BitSize(thumb->row_align, thumb->image_align);
+ artdb->fileListDS->fileList->files.push_back(f);
+ f->file = _wcsdup(file);
+ }
+
+ ArtDataObject * ms = new ArtDataObject;
+ ms->type=2;
+ ms->image = new ArtImageName;
+ ms->image->corrid = thumb->correlation_id;
+ ms->image->imgw = thumb->width;
+ ms->image->imgh = thumb->height;
+ ms->image->imagesize = image->get16BitSize(thumb->row_align, thumb->image_align);
+
+ //__int64 fs = fileSize(file);
+ //ms->image->ithmboffset = fs>0?fs:0;
+ ms->image->ithmboffset = f->getNextHole(ms->image->imagesize);
+
+ wchar_t buf[100] = {0};
+ StringCchPrintf(buf,100,L":F%04d_1.ithmb",thumb->correlation_id);
+ ms->image->filename = new ArtDataObject;
+ ms->image->filename->type=3;
+ ms->image->filename->SetString(buf);
+ unsigned short *data = (unsigned short *)calloc(ms->image->imagesize,1);
+ image->exportToRGB565((RGB565*)data, thumb->format, thumb->row_align, thumb->image_align);
+ fileputinhole(file,ms->image->ithmboffset,ms->image->imagesize,data);
+ //writeDataToThumb(file,data,thumb->width * thumb->height);
+ free(data);
+
+ f->images.push_back(new ArtFileImage(ms->image->ithmboffset,ms->image->imagesize,1));
+ f->sortImages();
+
+ return ms;
+}
+
+void GetTempFilePath(wchar_t *path) {
+ wchar_t dir[MAX_PATH] = {0};
+ GetTempPath(MAX_PATH,dir);
+ GetTempFileName(dir,L"ml_pmp",0,path);
+}
+
+static void fileclosehole(const wchar_t* file, unsigned int pos, int len) {
+ HANDLE hw = CreateFile(file,GENERIC_WRITE | GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
+ if(hw == INVALID_HANDLE_VALUE) return;
+ HANDLE hr = CreateFile(file,GENERIC_WRITE | GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
+ if(hr == INVALID_HANDLE_VALUE) { CloseHandle(hw); return; }
+ SetFilePointer(hw,pos,NULL,FILE_BEGIN);
+ SetFilePointer(hr,pos+len,NULL,FILE_BEGIN);
+ DWORD fs = GetFileSize(hw,NULL);
+ if(pos == 0 && len == fs) { CloseHandle(hr); CloseHandle(hw); _wunlink(file); return; }
+ unsigned int p = pos;
+ while(1) {
+ BYTE buf[65536] = {0};
+ DWORD read=0;
+ ReadFile(hr,buf,sizeof(buf),&read,NULL);
+ if(!read) break;
+ DWORD written=0;
+ WriteFile(hw,buf,read,&written,NULL);
+ if(!written) break;
+ p+=read;
+ if(p>=fs) break;
+ }
+
+ SetFilePointer(hw,fs - len,NULL,FILE_BEGIN);
+ SetEndOfFile(hw);
+ CloseHandle(hr);
+ CloseHandle(hw);
+
+}
+
+static bool replaceart(songid_t songid, wchar_t driveW, ArtDB *artdb, std::vector<const ArtworkFormat*> * thumbs, std::vector<Image*> * images) {
+ //return false;
+ __int64 dbid = ((iPod_mhit*)songid)->dbid;
+ int done=0;
+ ArtImageList::ArtImageMapIterator art = artdb->imageListDS->imageList->images.find(dbid);
+ if(art != artdb->imageListDS->imageList->images.end() && art->second) { // replace old art
+ for(size_t i=0; i!=art->second->dataobjs.size(); i++) if(art->second->dataobjs[i]->image) {
+ ArtImageName * in = art->second->dataobjs[i]->image;
+ for(size_t j=0; j!=thumbs->size(); j++)
+ {
+ if(in->corrid == thumbs->at(j)->correlation_id) {
+ wchar_t file[MAX_PATH] = {0};
+ wsprintfW(file,L"%c:\\iPod_Control\\Artwork\\F%04d_1.ithmb",driveW,in->corrid);
+ int size = images->at(j)->get16BitSize(thumbs->at(j)->row_align, thumbs->at(j)->image_align);
+ if(size == in->imagesize) {
+ unsigned short *data = (unsigned short *)malloc(size);
+ images->at(j)->exportToRGB565((RGB565*)data, thumbs->at(j)->format, thumbs->at(j)->row_align, thumbs->at(j)->image_align);
+ fileputinhole(file,in->ithmboffset,in->imagesize,data);
+ free(data);
+ done++;
+ }
+ }
+ }
+ }
+ }
+ return (done == thumbs->size());
+}
+
+void iPodDevice::setArt(songid_t songid, void *bits, int w, int h) { //buf is in format ARGB32*
+
+ if(!artdb || !thumbs.size()) return; // art not supported
+ iPod_mhit * mhit = (iPod_mhit *)songid;
+
+ if(bits == NULL || w == 0 || h == 0) { // remove art
+ ArtImageList::ArtImageMapIterator arti = artdb->imageListDS->imageList->images.find(mhit->dbid);
+ if(arti == artdb->imageListDS->imageList->images.end() || !arti->second) return;
+ ArtImage * art = arti->second;
+ for(auto j = art->dataobjs.begin(); j!=art->dataobjs.end(); j++) {
+ ArtImageName *n = (*j)->image;
+ if(n)
+ {
+ ArtFile * f = artdb->fileListDS->fileList->getFile(n->corrid);
+ if(f)
+ {
+ bool found=false;
+ for(size_t i=0; i!=f->images.size(); i++)
+ {
+ if(!found && f->images[i]->start == n->ithmboffset && --f->images[i]->refcount==0)
+ {
+ delete f->images[i];
+ f->images.erase(f->images.begin() + i);
+ i--;
+ found=true;
+ }
+ }
+ }
+ }
+ }
+ mhit->mhii_link = 0;
+ mhit->artworkcount = 0;
+ mhit->hasArtwork = 0;
+ artdb->imageListDS->imageList->images.erase(arti);
+ delete art;
+ } else {
+ //setArt(songid,NULL,0,0); // clear old art first
+
+ HQSkinBitmap albumart((ARGB32*)bits, w, h); // wrap image into a bitmap object (no copying done)
+
+ std::vector<Image*> images;
+ for(size_t i=0; i!=thumbs.size(); i++) {
+ BltCanvas canvas(thumbs[i]->width,thumbs[i]->height);
+ albumart.stretch(&canvas, 0, 0, thumbs[i]->width,thumbs[i]->height);
+ images.push_back(new Image((ARGB32 *)canvas.getBits(), thumbs[i]->width,thumbs[i]->height));
+ }
+
+ if(!replaceart(songid,driveW,artdb,&thumbs,&images)) {
+ setArt(songid,NULL,0,0);
+ ArtImage * artimg = new ArtImage();
+ artimg->songid = mhit->dbid;
+ artimg->id = artdb->nextid++;
+ artimg->srcImageSize = w*h*4;//0; //fileSize(infile);
+ //artimg->srcImageSize = mhit->unk45 = rand();
+ mhit->artworksize = 0;
+ for(size_t i=0; i!=thumbs.size(); i++)
+ {
+ artimg->dataobjs.push_back(makeThumbMetadata(thumbs[i],driveW,images[i],artdb));
+ mhit->artworksize += thumbs[i]->width * thumbs[i]->height * sizeof(short);
+ }
+ artdb->imageListDS->imageList->images.insert(ArtImageList::ArtImageMapPair(artimg->songid,artimg));
+ mhit->artworkcount = 1;//thumbs.size();
+ mhit->hasArtwork = 1;//thumbs.size();
+ mhit->mhii_link = artimg->id;
+ }
+
+ //images.deleteAll();
+ for (auto image : images)
+ {
+ delete image;
+ }
+ images.clear();
+ }
+}
+
+class ipodart_t {
+public:
+ ipodart_t(ArtImageName *in, wchar_t driveW,int w, int h, const ArtworkFormat* format): w(w),h(h),image(0),error(0),resized(0),format(format) {
+ wsprintf(fn,L"%c:\\iPod_Control\\Artwork",driveW);
+ wchar_t *p = fn+wcslen(fn);
+ in->filename->GetString(p,MAX_PATH - (p - fn));
+ while(p && *p) {if(*p == L':') *p=L'\\'; p++;}
+ offset = in->ithmboffset;
+ }
+ ~ipodart_t() { if(image) delete image; }
+ Image * GetImage() {
+ if(image || error) return image;
+ int size = Image::get16BitSize(w,h,format->row_align, format->image_align);
+ RGB565 * r = (RGB565*)calloc(size,1);
+ if(!r) { return 0; error=1; }
+ FILE *f = _wfopen(fn,L"rb");
+ if(!f) { free(r); error=1; return 0; }
+ fseek(f,offset,0);
+ if(fread(r,size,1,f) != 1) { free(r); fclose(f); error=1; return 0; }
+ fclose(f);
+ image = new Image(r,w,h,format->format,format->row_align, format->image_align);
+ free(r);
+ return image;
+ }
+ Image * RegetImage() {
+ if(image) delete image; image=0;
+ return GetImage();
+ }
+ int GetError() {return error;}
+ int getHeight(){if(image) return image->getHeight(); else return h;}
+ int getWidth() {if(image) return image->getWidth(); else return w;}
+ int resized;
+ void Resize(int neww, int newh)
+ {
+ HQSkinBitmap temp(image->getData(), image->getWidth(), image->getHeight()); // wrap into a SkinBitmap (no copying involved)
+ BltCanvas newImage(neww,newh);
+ temp.stretch(&newImage, 0, 0, neww, newh);
+ delete image;
+ image = new Image((ARGB32 *)newImage.getBits(), neww, newh);
+ resized=1;
+ }
+private:
+ wchar_t fn[MAX_PATH];
+ int offset;
+ int w,h;
+ Image * image;
+ int error;
+ const ArtworkFormat* format;
+};
+
+pmpart_t iPodDevice::getArt(songid_t songid) {
+ if(!artdb) return 0;
+ __int64 dbid = ((iPod_mhit*)songid)->dbid;
+ ArtImageList::ArtImageMapIterator art = artdb->imageListDS->imageList->images.find(dbid);
+ if(art == artdb->imageListDS->imageList->images.end() || !art->second) return 0;
+ int l = art->second->dataobjs.size();
+
+ ArtImageName * in=0;
+ int w=0,h=0;
+ const ArtworkFormat * format=0;
+
+ for(int i=0; i<l; i++) {
+ if(art->second->dataobjs[i]->image && (w < art->second->dataobjs[i]->image->imgw || h < art->second->dataobjs[i]->image->imgh)) {
+ in = art->second->dataobjs[i]->image;
+ w = in->imgw;
+ h = in->imgh;
+ for(size_t i=0; i < thumbs.size(); i++)
+ {
+ const ArtworkFormat *f = thumbs.at(i);
+ if(f->width == w && f->height == h)
+ format = f;
+ }
+ }
+ }
+ if(!in || !format) return 0;
+
+ return (pmpart_t)new ipodart_t(in,driveW,w,h,format);
+}
+
+void iPodDevice::releaseArt(pmpart_t art) {
+ if(!art) return;
+ ipodart_t *image = (ipodart_t *)art;
+ delete image;
+}
+
+int iPodDevice::drawArt(pmpart_t art, HDC dc, int x, int y, int w, int h) {
+ Image *image = ((ipodart_t*)art)->GetImage();
+ if(!image) return 0;
+ HQSkinBitmap temp(image->getData(), image->getWidth(), image->getHeight()); // wrap into a SkinBitmap (no copying involved)
+ DCCanvas canvas(dc);
+ temp.stretch(&canvas,x,y,w,h);
+ return 1;
+
+}
+
+void iPodDevice::getArtNaturalSize(pmpart_t art, int *w, int *h){
+ ipodart_t *image = (ipodart_t*)art;
+ if(!image) return;
+ *h = image->getHeight();
+ *w = image->getWidth();
+}
+
+void iPodDevice::setArtNaturalSize(pmpart_t art, int w, int h){
+ Image *image = ((ipodart_t*)art)->GetImage();
+ if(!image) return;
+ if(w == image->getWidth() && h == image->getHeight()) return;
+ if(((ipodart_t*)art)->resized) {
+ image = ((ipodart_t*)art)->RegetImage();
+ if(!image) return;
+ }
+ ((ipodart_t*)art)->Resize(w, h);
+}
+
+void iPodDevice::getArtData(pmpart_t art, void* data){ // data ARGB32* is at natural size
+ Image *image = ((ipodart_t*)art)->GetImage();
+ if(!image) return;
+ image->exportToARGB32((ARGB32*)data);
+}
+
+bool iPodDevice::artIsEqual(pmpart_t at, pmpart_t bt) {
+ if(at == bt) return true;
+ if(!at || !bt) return false;
+ if(((ipodart_t*)at)->getWidth() != ((ipodart_t*)bt)->getWidth()) return false;
+ if(((ipodart_t*)at)->getHeight() != ((ipodart_t*)bt)->getHeight()) return false;
+ Image *a = ((ipodart_t*)at)->RegetImage();
+ Image *b = ((ipodart_t*)bt)->RegetImage();
+ if(!a && !b) return true;
+ if(!a || !b) return false;
+ if(a->getWidth() != b->getWidth()) return false;
+ if(b->getHeight() != b->getHeight()) return false;
+ return memcmp(a->getData(),b->getData(),a->getWidth()*a->getHeight()*sizeof(ARGB32)) == 0;
+}
+
+static INT_PTR CALLBACK gapscan_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
+ static iPodDevice * dev;
+ static int i;
+ switch(uMsg) {
+ case WM_INITDIALOG:
+ SetWindowPos(hwndDlg,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
+ dev = (iPodDevice*)lParam;
+ i=0;
+ dev->gapscanner = hwndDlg;
+ SendDlgItemMessage(hwndDlg,IDC_PROGRESS1,PBM_SETRANGE32,0,dev->getPlaylistLength(0));
+ SendDlgItemMessage(hwndDlg,IDC_PROGRESS1,PBM_SETPOS,0,0);
+ SetTimer(hwndDlg,1,100,NULL);
+ break;
+ case WM_TIMER:
+ if(wParam == 1) {
+ KillTimer(hwndDlg,1);
+ int l = dev->getPlaylistLength(0);
+ int j=0;
+ for(;;) {
+ if(i >= l) return gapscan_dialogProc(hwndDlg,WM_CLOSE,0,0);
+ iPod_mhit * mhit = (iPod_mhit *)dev->getPlaylistTrack(0,i++);
+ if(!mhit->trackgapless && !mhit->gaplessData) {
+ wchar_t artist[50] = {0}, title[50] = {0}, buf[200] = {0};
+ dev->getTrackArtist((songid_t)mhit,artist,50);
+ dev->getTrackTitle((songid_t)mhit,title,50);
+ StringCchPrintf(buf,200,L"%d/%d: %s - %s",i+1,l,artist,title);
+ SetDlgItemText(hwndDlg,IDC_CAPTION,buf);
+ wchar_t infile[MAX_PATH]=L"";
+ dev->getFilename(infile,MAX_PATH,(songid_t)mhit);
+ BOOL worked=TRUE;
+ mhit->samplecount = GetFileInfoInt64(infile,L"numsamples",&worked);
+ mhit->pregap = (unsigned long)GetFileInfoInt64(infile,L"pregap",&worked);
+ mhit->postgap = (unsigned long)GetFileInfoInt64(infile,L"postgap",&worked);
+ mhit->gaplessData = (unsigned long)GetFileInfoInt64(infile,L"endoffset",&worked);
+ mhit->trackgapless = worked?1:0;
+ j++;
+ } else if(!(i%23)) SetDlgItemText(hwndDlg,IDC_CAPTION,WASABI_API_LNGSTRINGW(IDS_SCANNING));
+ if(j > 3 || !(i % 50)) {
+ SendDlgItemMessage(hwndDlg,IDC_PROGRESS1,PBM_SETPOS,i,0);
+ SetTimer(hwndDlg,1,25,NULL);
+ return 0;
+ }
+ }
+ }
+ break;
+ case WM_CLOSE:
+ dev->writeiTunesDB();
+ EndDialog(hwndDlg,0);
+ dev->gapscanner = NULL;
+ break;
+ case WM_DESTROY:
+ dev->gapscanner = NULL;
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ gapscan_dialogProc(hwndDlg,WM_CLOSE,0,0);
+ break;
+ case IDC_BG:
+ ShowWindow(hwndDlg,SW_HIDE);
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+static INT_PTR CALLBACK config_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
+ static iPodDevice * dev;
+ switch(uMsg) {
+ case WM_INITDIALOG:
+ {
+ prefsParam* p = (prefsParam*)lParam;
+ p->config_tab_init(hwndDlg,p->parent);
+ dev = (iPodDevice*)p->dev;
+ if(dev->artdb && dev->thumbs.size()) {
+ wchar_t inifile[] = {dev->driveW,L":\\iPod_Control\\iTunes\\ml_pmp.ini"};
+ ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC_ARTGROUP),SW_SHOWNA);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_CHECK_USEART),SW_SHOWNA);
+ CheckDlgButton(hwndDlg,IDC_CHECK_USEART,GetPrivateProfileInt(L"ml_pmp",L"albumart",1,inifile));
+ //ShowWindow(GetDlgItem(hwndDlg,IDC_COMBO_ARTMODE),SW_SHOWNA);
+ /*ComboBox combo(hwndDlg,IDC_COMBO_USEART);
+ combo.AddString(L"Add to all tracks");
+ combo.AddString(L"Only add to the first track in an album");
+ combo.AddString(L"Don't add to any tracks");
+ */
+ }
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_SCAN:
+ if(dev->gapscanner) ShowWindow(dev->gapscanner,SW_SHOW);
+ else WASABI_API_DIALOGBOXPARAM(IDD_GAPSCAN,NULL,gapscan_dialogProc,(LPARAM)dev);
+ break;
+ case IDC_CHECK_USEART:
+ wchar_t inifile[] = {dev->driveW,L":\\iPod_Control\\iTunes\\ml_pmp.ini"}, s[32] = {0};
+ StringCchPrintf(s, 32, L"%d", (IsDlgButtonChecked(hwndDlg, IDC_CHECK_USEART)==BST_CHECKED));
+ WritePrivateProfileString(L"ml_pmp", L"albumart", s, inifile);
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+static const intptr_t encoder_blacklist[] =
+{
+ mmioFOURCC('W','M','A',' '),
+ mmioFOURCC('A','A','C','H'),
+ mmioFOURCC('A','A','C','P'),
+ mmioFOURCC('A','A','C','r'),
+ mmioFOURCC('F','L','A','C'),
+ mmioFOURCC('O','G','G',' '),
+ mmioFOURCC('M','P','2',' '),
+ mmioFOURCC('M','4','A','H'),
+ mmioFOURCC('M','4','A','+'),
+ mmioFOURCC('A','D','T','S'),
+};
+
+intptr_t iPodDevice::extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4) {
+ switch(param1) {
+ case DEVICE_SET_ICON: // icons
+ {
+ MLTREEIMAGE * i = (MLTREEIMAGE*)param2;
+ i->hinst = plugin.hDllInstance;
+ i->resourceId = image16;
+ }
+ break;
+ case DEVICE_GET_ICON:
+ {
+ if (param2 <= 16 && param3 <= 16)
+ {
+ // TODO: get the name of the DLL at load time
+ StringCchPrintfW((wchar_t *)param4, 260, L"res://%s/PNG/#%u", L"pmp_ipod.dll", image16);
+ }
+ else
+ {
+ // TODO: get the name of the DLL at load time
+ StringCchPrintfW((wchar_t *)param4, 260, L"res://%s/PNG/#%u", L"pmp_ipod.dll", image160);
+ }
+ }
+ break;
+ case DEVICE_SUPPORTED_METADATA:
+ return 0xffff | (artdb?SUPPORTS_ALBUMART:0);
+ case DEVICE_CAN_RENAME_DEVICE:
+ return 1;
+ case DEVICE_GET_INI_FILE:
+ {
+ wchar_t inifile[] = {driveW,L":\\iPod_Control\\iTunes\\ml_pmp.ini"};
+ wcsncpy((wchar_t*)param2,inifile,MAX_PATH);
+ }
+ break;
+ case DEVICE_GET_PREFS_DIALOG:
+ if(param3 == 0) {
+ pref_tab * p = (pref_tab *)param2;
+ p->hinst = WASABI_API_LNG_HINST;
+ p->dlg_proc = config_dialogProc;
+ p->res_id = IDD_CONFIG;
+ WASABI_API_LNGSTRINGW_BUF(IDS_ADVANCED,p->title,100);
+ }
+ break;
+ case DEVICE_REFRESH:
+ {
+ char drive = this->drive;
+
+ //iPods.eraseObject(this);
+ auto it = std::find(iPods.begin(), iPods.end(), this);
+ if (it != iPods.end())
+ {
+ iPods.erase(it);
+ }
+
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
+ delete this;
+ new iPodDevice(drive);
+ }
+ break;
+ case DEVICE_ADDPODCASTGROUP:
+ {
+ int pos = param3;
+ wchar_t * name = (wchar_t *)param4;
+ iPod_mhyp* pl = (iPod_mhyp*)playlists.Get(param2);
+ pl->podcastflag=1;
+ iPod_mhip * mhip = new iPod_mhip();
+ mhip->podcastgroupflag=256;
+ mhip->podcastgroupref=0;
+ iPod_mhod * d = new iPod_mhod();
+ d->SetString(name);
+ d->type=1;
+ mhip->mhod.push_back(d);
+ pl->mhip.insert(pl->mhip.begin()+pos,mhip);
+ }
+ break;
+ case DEVICE_ADDPODCASTGROUP_FINISH:
+ {
+ iPod_mhyp* pl = (iPod_mhyp*)playlists.Get(param2);
+ pl->numLibraryMHODs=0x18;
+ int groupref=0;
+ for(size_t i=0; i < pl->mhip.size(); i++) {
+ iPod_mhip * m = pl->mhip[i];
+ m->groupid = i+1000000;
+ if(m->podcastgroupflag & 256) groupref = m->groupid;
+ else m->podcastgroupref = groupref;
+ }
+ }
+ break;
+ case DEVICE_SUPPORTS_VIDEO:
+ return 1;
+ case DEVICE_VETO_ENCODER:
+ {
+ for (size_t i=0;i<sizeof(encoder_blacklist)/sizeof(*encoder_blacklist);i++)
+ {
+ // TODO: check device info XML for aacPlus support
+ if (param2 == encoder_blacklist[i])
+ return 1;
+ }
+ }
+ return 0;
+ case DEVICE_GET_MODEL:
+ {
+ wchar_t *model_buffer = (wchar_t *)param2;
+ unsigned int cch = (unsigned int)param3;
+ if (!info)
+ {
+ StringCchCopyW(model_buffer, cch, L"Apple iPod");
+ }
+ else switch(info->family_id)
+ {
+ default:
+ StringCchCopyW(model_buffer, cch, L"Apple iPod");
+ break;
+ case 3:
+ StringCchCopyW(model_buffer, cch, L"Apple iPod Mini");
+ break;
+ case 4:
+ StringCchCopyW(model_buffer, cch, L"Apple iPod 4G");
+ break;
+ case 5:
+ StringCchCopyW(model_buffer, cch, L"Apple iPod Photo");
+ break;
+ case 6:
+ StringCchCopyW(model_buffer, cch, L"Apple iPod 5G");
+ break;
+ case 7:
+ StringCchCopyW(model_buffer, cch, L"Apple iPod Nano 1G");
+ break;
+ case 9:
+ StringCchCopyW(model_buffer, cch, L"Apple iPod Nano 2G");
+ break;
+ case 11:
+ StringCchCopyW(model_buffer, cch, L"Apple iPod Classic");
+ break;
+ case 12:
+ StringCchCopyW(model_buffer, cch, L"Apple iPod Fat Nano");
+ break;
+ case 15:
+ StringCchCopyW(model_buffer, cch, L"Apple iPod Nano4G");
+ break;
+ case 128:
+ StringCchCopyW(model_buffer, cch, L"Apple iPod Shuffle");
+ break;
+ case 130:
+ StringCchCopyW(model_buffer, cch, L"Apple iPod Shuffle 2G");
+ break;
+ case 132:
+ StringCchCopyW(model_buffer, cch, L"Apple iPod Shuffle 3G");
+ break;
+ }
+
+ }
+ return 1;
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_ipod/iPodDevice.h b/Src/Plugins/Portable/pmp_ipod/iPodDevice.h
new file mode 100644
index 00000000..375dcf85
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/iPodDevice.h
@@ -0,0 +1,142 @@
+#ifndef _IPODDEVICE_H_
+#define _IPODDEVICE_H_
+
+#include <windows.h>
+#include <windowsx.h>
+#include <stdio.h>
+#include <shlobj.h>
+#include <time.h>
+#include "..\..\General\gen_ml/ml.h"
+#include "..\..\Library\ml_pmp/pmp.h"
+#include "..\..\Library\ml_pmp/transcoder.h"
+#include "../winamp/wa_ipc.h"
+#include "../winamp/ipc_pe.h"
+#include "iPodDB.h"
+#include "resource.h"
+#include "..\..\General\gen_ml/itemlist.h"
+#include "yail.h"
+#include "iPodArtworkDB.h"
+#include "iPodInfo.h"
+#include <vector>
+
+class iPodDevice : public Device {
+public:
+ HWND gapscanner;
+ C_ItemList playlists; // list of iPod_mhyp*
+ Transcoder * transcoder;
+ iPod_mhbd * db;
+ char drive;
+ wchar_t driveW;
+ int dirnum;
+ __int64 transferQueueLength;
+
+ int image16;
+ int image160;
+
+ ArtDB * artdb;
+ std::vector<const ArtworkFormat*> thumbs;
+ uint8_t *fwid;
+ const iPodInfo *info;
+ iPodDevice(char drive);
+ virtual ~iPodDevice();
+ virtual int parseiTunesDB(bool parseArt);
+ virtual int writeiTunesDB();
+ virtual void getFilename(char * buf, int len, songid_t song);
+ virtual void getFilename(wchar_t *buf, int len, songid_t song);
+ virtual __int64 getDeviceCapacityAvailable(); // in bytes
+ virtual __int64 getDeviceCapacityTotal(); // in bytes
+
+ virtual void Eject(); // if you ejected successfully, you MUST call plugin.deviceDisconnected(this) and delete this;
+ virtual void Close(); // save any changes, and call plugin.deviceDisconnected(this) AND delete this;
+
+ // return 0 for success, -1 for failed or cancelled
+ virtual int transferTrackToDevice(const itemRecordW * track, // the track to transfer
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this with stats every so often so the GUI can be updated
+ songid_t * songid, // fill in the songid when you are finished
+ int * killswitch); // if this gets set to 1, the transfer has been cancelled by the user
+ virtual int trackAddedToTransferQueue(const itemRecordW *track); // return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
+ virtual void trackRemovedFromTransferQueue(const itemRecordW *track);
+ virtual __int64 getTrackSizeOnDevice(const itemRecordW *track); // return the amount of space taken up on the device by the track, or 0 for incompatable (usually the filesize, unless you are transcoding)
+
+ virtual void deleteTrack(songid_t songid); // physically remove from device. Be sure to remove it from all the playlists!
+
+ virtual void commitChanges(){writeiTunesDB();} // optional. Will be called at a good time to save changes
+
+ virtual int getPlaylistCount(); // always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
+ // PlaylistName(0) should return the name of the device.
+ virtual void getPlaylistName(int playlistnumber, wchar_t *buf, int len);
+ virtual int getPlaylistLength(int playlistnumber);
+ virtual songid_t getPlaylistTrack(int playlistnumber,int songnum); // returns a songid
+
+ virtual void setPlaylistName(int playlistnumber, const wchar_t *buf); // with playlistnumber==0, set the name of the device.
+ virtual void playlistSwapItems(int playlistnumber, int posA, int posB); // swap the songs at position posA and posB
+ virtual void sortPlaylist(int playlistnumber, int sortBy);
+ virtual void addTrackToPlaylist(int playlistnumber, songid_t songid); // adds songid to the end of the playlist
+ virtual void removeTrackFromPlaylist(int playlistnumber, int songnum); //where songnum is the position of the track in the playlist
+
+ virtual void deletePlaylist(int playlistnumber);
+ virtual int newPlaylist(const wchar_t *name); // create empty playlist, returns playlistnumber
+
+ virtual void getTrackArtist(songid_t songid, wchar_t *buf, int len);
+ virtual void getTrackAlbum(songid_t songid, wchar_t *buf, int len);
+ virtual void getTrackTitle(songid_t songid, wchar_t *buf, int len);
+ virtual int getTrackTrackNum(songid_t songid);
+ virtual int getTrackDiscNum(songid_t songid);
+ virtual void getTrackGenre(songid_t songid, wchar_t *buf, int len);
+ virtual int getTrackYear(songid_t songid);
+ virtual __int64 getTrackSize(songid_t songid); // in bytes
+ virtual int getTrackLength(songid_t songid); // in millisecs
+ virtual int getTrackBitrate(songid_t songid); // in kbps
+ virtual int getTrackPlayCount(songid_t songid);
+ virtual int getTrackRating(songid_t songid); //0-5
+ virtual __time64_t getTrackLastPlayed(songid_t songid); // in unix time format
+ virtual __time64_t getTrackLastUpdated(songid_t songid); // in unix time format
+ virtual void getTrackAlbumArtist(songid_t songid, wchar_t * buf, int len);
+ virtual void getTrackComposer(songid_t songid, wchar_t * buf, int len);
+ virtual int getTrackType(songid_t songid);
+ virtual void getTrackExtraInfo(songid_t songid, const wchar_t *field, wchar_t * buf, int len); //optional
+
+ // feel free to ignore any you don't support
+ virtual void setTrackArtist(intptr_t songid, const wchar_t *value);
+ virtual void setTrackAlbum(intptr_t songid, const wchar_t *value);
+ virtual void setTrackTitle(intptr_t songid, const wchar_t *value);
+ virtual void setTrackTrackNum(intptr_t songid, int value);
+ virtual void setTrackDiscNum(intptr_t songid, int value);
+ virtual void setTrackGenre(intptr_t songid, const wchar_t *value);
+ virtual void setTrackYear(intptr_t songid, int year);
+ virtual void setTrackPlayCount(intptr_t songid, int value);
+ virtual void setTrackRating(intptr_t songid, int value);
+ virtual void setTrackLastPlayed(intptr_t songid, __time64_t value); // in unix time format
+ virtual void setTrackLastUpdated(intptr_t songid, __time64_t value); // in unix time format
+ virtual void setTrackAlbumArtist(songid_t songid, const wchar_t *value);
+ virtual void setTrackComposer(songid_t songid, const wchar_t *value);
+ virtual void setTrackExtraInfo(intptr_t songid, const wchar_t *field, const wchar_t *value) {}; //optional
+
+ virtual bool playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue); // return false if unsupported
+
+ virtual intptr_t extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4); // This does nothing yet. For future use.
+
+ virtual bool copyToHardDriveSupported() {return true;}
+
+ virtual __int64 songSizeOnHardDrive(songid_t song) {return getTrackSize(song);} // how big a song will be when copied back. Return -1 for not supported.
+
+ virtual int copyToHardDrive(songid_t song, // the song to copy
+ wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ ); // -1 for failed/not supported. 0 for success.
+
+ // art functions
+ virtual void setArt(songid_t songid, void *buf, int w, int h); //buf is in format ARGB32*
+ virtual pmpart_t getArt(songid_t songid);
+ virtual void releaseArt(pmpart_t art);
+ virtual int drawArt(pmpart_t art, HDC dc, int x, int y, int w, int h);
+ virtual void getArtNaturalSize(pmpart_t art, int *w, int *h);
+ virtual void setArtNaturalSize(pmpart_t art, int w, int h);
+ virtual void getArtData(pmpart_t art, void* data); // data ARGB32* is at natural size
+ virtual bool artIsEqual(pmpart_t a, pmpart_t b);
+};
+
+#endif // _IPODDEVICE_H_ \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_ipod/iPodInfo.cpp b/Src/Plugins/Portable/pmp_ipod/iPodInfo.cpp
new file mode 100644
index 00000000..94870553
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/iPodInfo.cpp
@@ -0,0 +1,1040 @@
+#include "api.h"
+#include "iPodInfo.h"
+#include "resource.h"
+#include "../../General/gen_ml/ml.h"
+#include "../../Library/ml_pmp/pmp.h"
+
+#include "../xml/obj_xml.h"
+#include "../plist/loader.h"
+
+#include <api/service/waservicefactory.h>
+
+#include <stdio.h>
+#include <windows.h>
+#include <strsafe.h>
+
+extern PMPDevicePlugin plugin;
+
+static const ArtworkFormat ipod_color_artwork_info[] =
+{
+ {THUMB_COVER_SMALL, 56, 56, 1017, RGB_565, 4, 4},
+ {THUMB_COVER_LARGE, 140, 140, 1016, RGB_565, 4, 4},
+ {THUMB_PHOTO_TV_SCREEN, 720, 480, 1019, RGB_565, 4, 4},
+ {THUMB_PHOTO_LARGE, 130, 88, 1015, RGB_565, 4, 4},
+ {THUMB_PHOTO_FULL_SCREEN, 220, 176, 1013, RGB_565, 4, 4},
+ {THUMB_PHOTO_SMALL, 42, 30, 1009, RGB_565, 4, 4},
+ {THUMB_INVALID, -1, -1, -1, RGB_565, 4, 4}
+};
+
+static const ArtworkFormat ipod_nano_artwork_info[] =
+{
+ {THUMB_COVER_SMALL, 42, 42, 1031, RGB_565, 4, 4},
+ {THUMB_COVER_LARGE, 100, 100, 1027, RGB_565, 4, 4},
+ {THUMB_PHOTO_LARGE, 42, 37, 1032, RGB_565, 4, 4},
+ {THUMB_PHOTO_FULL_SCREEN, 176, 132, 1023, RGB_565, 4, 4},
+ {THUMB_INVALID, -1, -1, -1, RGB_565, 4, 4}
+};
+
+static const ArtworkFormat ipod_video_artwork_info[] =
+{
+ {THUMB_COVER_SMALL, 100, 100, 1028, RGB_565, 4, 4},
+ {THUMB_COVER_LARGE, 200, 200, 1029, RGB_565, 4, 4},
+ {THUMB_PHOTO_TV_SCREEN, 720, 480, 1019, RGB_565, 4, 4},
+ {THUMB_PHOTO_LARGE, 130, 88, 1015, RGB_565, 4, 4},
+ {THUMB_PHOTO_FULL_SCREEN, 320, 240, 1024, RGB_565, 4, 4},
+ {THUMB_PHOTO_SMALL, 50, 41, 1036, RGB_565, 4, 4},
+ {THUMB_INVALID, -1, -1, -1, RGB_565, 4, 4}
+};
+
+static const ArtworkFormat ipod_7g_artwork_info[] =
+{
+ {THUMB_COVER_SMALL, 55, 55, 1061, RGB_565, 4, 4},
+ {THUMB_COVER_MEDIUM1, 128, 128, 1055, RGB_565, 4, 4},
+ {THUMB_COVER_LARGE, 320, 320, 1060, RGB_565, 4, 4},
+ {THUMB_INVALID, -1, -1, -1, RGB_565, 4, 4}
+};
+
+static const ArtworkFormat ipod_touch_artwork_info[] =
+{
+ {THUMB_COVER_SMALL, 55, 55, 3006, RGB_555, 16, 4096},
+ {THUMB_COVER_MEDIUM1, 64, 64, 3003, RGB_555_REC, 16, 4096},
+ {THUMB_COVER_MEDIUM2, 88, 88, 3007, RGB_555, 16, 4096},
+ {THUMB_COVER_MEDIUM3, 128, 128, 3002, RGB_555_REC, 16, 4096},
+ {THUMB_COVER_MEDIUM4, 256, 256, 3001, RGB_555_REC, 16, 4096},
+ {THUMB_COVER_LARGE, 320, 320, 3005, RGB_555, 16, 4096},
+ {THUMB_INVALID, -1, -1, -1, RGB_555, 4, 4}
+};
+
+/*
+static const ArtworkFormat ipod_mobile_1_artwork_info[] = {
+ {THUMB_COVER_SMALL, 50, 50, 2002},
+ {THUMB_COVER_LARGE, 150, 150, 2003},
+ {THUMB_INVALID, -1, -1, -1}
+};
+*/
+
+//maps model to artwork format
+static const ArtworkFormat *ipod_artwork_info_table[] =
+{
+ NULL, // invalid
+ ipod_color_artwork_info, // color
+ NULL, // regular
+ NULL, // mini
+ NULL, // shuffle
+ ipod_video_artwork_info, // video
+ ipod_nano_artwork_info, // nano
+ ipod_7g_artwork_info, // classic
+ ipod_7g_artwork_info, // fat nano
+ ipod_touch_artwork_info, // touch
+};
+
+
+// this list compiled from http://www.thismuchiknow.co.uk/?page_id=27 and is kept in the same order as that table for easy updating
+// when new ipods come out, let's keep this up to date.
+// at the moment this is just used as a mapping from part number to model, for album art
+static const iPodModelInfo ipod_info_table[] =
+{
+ //1st gen ipods
+ {L"8513", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160}, //mac
+ {L"8541", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160}, //mac
+ {L"8697", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160}, //pc
+ {L"8709", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160}, //mac
+
+ //2nd gen ipods
+ {L"8737", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160}, //mac
+ {L"8740", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160}, //pc
+ {L"8738", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160}, //mac
+ {L"8741", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160}, //pc
+
+ //3rd gen ipods
+ {L"8976", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"8946", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"8948", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9244", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9245", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9460", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ //1st gen mini
+ {L"9160", IPOD_MODEL_MINI, IPOD_COLOR_SILVER, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9436", IPOD_MODEL_MINI, IPOD_COLOR_BLUE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9435", IPOD_MODEL_MINI, IPOD_COLOR_PINK, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9434", IPOD_MODEL_MINI, IPOD_COLOR_GREEN, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9437", IPOD_MODEL_MINI, IPOD_COLOR_GOLD, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ //4th gen ipods
+ {L"9282", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9268", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"E435", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160}, //HP branded
+ {L"E436", IPOD_MODEL_REGULAR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160}, //HP branded
+ {L"9787", IPOD_MODEL_REGULAR, IPOD_COLOR_U2, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ //4th gen ipod photos
+ {L"9585", IPOD_MODEL_COLOR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9586", IPOD_MODEL_COLOR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ //shuffles
+ {L"A133", IPOD_MODEL_SHUFFLE, IPOD_COLOR_WHITE, IDB_SHUFFLE1G_16, IDB_SHUFFLE1G_160},
+ {L"9724", IPOD_MODEL_SHUFFLE, IPOD_COLOR_WHITE, IDB_SHUFFLE1G_16, IDB_SHUFFLE1G_160},
+ {L"9725", IPOD_MODEL_SHUFFLE, IPOD_COLOR_WHITE, IDB_SHUFFLE1G_16, IDB_SHUFFLE1G_160},
+
+ // more ipod photos
+ {L"9829", IPOD_MODEL_COLOR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9830", IPOD_MODEL_COLOR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ // ipod mini 2nd gen
+ {L"9959", IPOD_MODEL_MINI, IPOD_COLOR_SILVER, IDB_CLASSIC_16, IDB_CLASSIC_160}, // pepsi giveaway ipod
+ {L"9800", IPOD_MODEL_MINI, IPOD_COLOR_SILVER, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9802", IPOD_MODEL_MINI, IPOD_COLOR_BLUE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9804", IPOD_MODEL_MINI, IPOD_COLOR_PINK, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9806", IPOD_MODEL_MINI, IPOD_COLOR_GREEN, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9801", IPOD_MODEL_MINI, IPOD_COLOR_SILVER, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9803", IPOD_MODEL_MINI, IPOD_COLOR_BLUE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9805", IPOD_MODEL_MINI, IPOD_COLOR_PINK, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"9807", IPOD_MODEL_MINI, IPOD_COLOR_GREEN, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ //HP colour ipods
+ {L"S492", IPOD_MODEL_COLOR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"S493", IPOD_MODEL_COLOR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ //HP ipod mini 2nd gen
+ {L"W753", IPOD_MODEL_MINI, IPOD_COLOR_SILVER, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"X762", IPOD_MODEL_MINI, IPOD_COLOR_SILVER, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ //more 4th gen ipod photos
+ {L"A079", IPOD_MODEL_COLOR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"A127", IPOD_MODEL_COLOR, IPOD_COLOR_U2, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ //HP ipod shuffles
+ {L"X765", IPOD_MODEL_SHUFFLE, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"X766", IPOD_MODEL_SHUFFLE, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ /*
+ //harry potter ipod 4G, don't know serial number. but that's ok because it was only on sale for a month, so fuck it.
+ {L"????", IPOD_MODEL_COLOR, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ */
+
+ //ipod nano 1st gen
+ {L"A004", IPOD_MODEL_NANO, IPOD_COLOR_WHITE, IDB_NANO1G_16, IDB_NANO1G_160},
+ {L"A099", IPOD_MODEL_NANO, IPOD_COLOR_BLACK, IDB_NANO1G_16, IDB_NANO1G_160},
+ {L"A005", IPOD_MODEL_NANO, IPOD_COLOR_WHITE, IDB_NANO1G_16, IDB_NANO1G_160},
+ {L"A107", IPOD_MODEL_NANO, IPOD_COLOR_BLACK, IDB_NANO1G_16, IDB_NANO1G_160},
+
+ //ipod video
+ {L"A002", IPOD_MODEL_VIDEO, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"A146", IPOD_MODEL_VIDEO, IPOD_COLOR_BLACK, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"A003", IPOD_MODEL_VIDEO, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"A147", IPOD_MODEL_VIDEO, IPOD_COLOR_BLACK, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"A253", IPOD_MODEL_VIDEO, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160}, //harry potter ipod 5G
+
+ //1gig nano
+ {L"A350", IPOD_MODEL_NANO, IPOD_COLOR_WHITE, IDB_NANO1G_16, IDB_NANO1G_160},
+ {L"A352", IPOD_MODEL_NANO, IPOD_COLOR_BLACK, IDB_NANO1G_16, IDB_NANO1G_160},
+
+ // U2 ipod video
+ {L"A452", IPOD_MODEL_VIDEO, IPOD_COLOR_U2, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ //2nd gen nano
+ {L"A477", IPOD_MODEL_NANO, IPOD_COLOR_SILVER, IDB_NANO2G_16, IDB_NANO2G_160},
+ {L"A426", IPOD_MODEL_NANO, IPOD_COLOR_SILVER, IDB_NANO2G_16, IDB_NANO2G_160},
+ {L"A428", IPOD_MODEL_NANO, IPOD_COLOR_BLUE, IDB_NANO2G_16, IDB_NANO2G_160},
+ {L"A487", IPOD_MODEL_NANO, IPOD_COLOR_GREEN, IDB_NANO2G_16, IDB_NANO2G_160},
+ {L"A489", IPOD_MODEL_NANO, IPOD_COLOR_PINK, IDB_NANO2G_16, IDB_NANO2G_160},
+ {L"A497", IPOD_MODEL_NANO, IPOD_COLOR_BLACK, IDB_NANO2G_16, IDB_NANO2G_160},
+
+ // ipod video 6th gen
+ {L"A444", IPOD_MODEL_VIDEO, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"A446", IPOD_MODEL_VIDEO, IPOD_COLOR_BLACK, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"A448", IPOD_MODEL_VIDEO, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"A450", IPOD_MODEL_VIDEO, IPOD_COLOR_BLACK, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ //2nd gen shuffle
+ {L"A564", IPOD_MODEL_SHUFFLE, IPOD_COLOR_SILVER, IDB_SHUFFLE2G_16, IDB_SHUFFLE2G_160},
+
+ // ipod video u2 6th gen
+ {L"A664", IPOD_MODEL_VIDEO, IPOD_COLOR_U2, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ //product red ipod nano
+ {L"A725", IPOD_MODEL_NANO, IPOD_COLOR_RED, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"A899", IPOD_MODEL_NANO, IPOD_COLOR_RED, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ // coloured versions of ipod shuffle 2nd gen
+ {L"A947", IPOD_MODEL_SHUFFLE, IPOD_COLOR_PINK, IDB_SHUFFLE2G_16, IDB_SHUFFLE2G_160},
+ {L"A949", IPOD_MODEL_SHUFFLE, IPOD_COLOR_BLUE, IDB_SHUFFLE2G_16, IDB_SHUFFLE2G_160},
+ {L"A951", IPOD_MODEL_SHUFFLE, IPOD_COLOR_GREEN, IDB_SHUFFLE2G_16, IDB_SHUFFLE2G_160},
+ {L"A953", IPOD_MODEL_SHUFFLE, IPOD_COLOR_ORANGE, IDB_SHUFFLE2G_16, IDB_SHUFFLE2G_160},
+
+ // fat nanos
+ {L"A978", IPOD_MODEL_FATNANO, IPOD_COLOR_SILVER, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"A980", IPOD_MODEL_FATNANO, IPOD_COLOR_SILVER, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"B249", IPOD_MODEL_FATNANO, IPOD_COLOR_BLUE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"B253", IPOD_MODEL_FATNANO, IPOD_COLOR_GREEN, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"B261", IPOD_MODEL_FATNANO, IPOD_COLOR_BLACK, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"B257", IPOD_MODEL_FATNANO, IPOD_COLOR_RED, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ // ipod classic
+ {L"B147", IPOD_MODEL_CLASSIC, IPOD_COLOR_BLACK, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"B029", IPOD_MODEL_CLASSIC, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"B150", IPOD_MODEL_CLASSIC, IPOD_COLOR_BLACK, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"B145", IPOD_MODEL_CLASSIC, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ // ipod touch
+ {L"A623", IPOD_MODEL_TOUCH, IPOD_COLOR_BLACK, IDB_CLASSIC_16, IDB_CLASSIC_160},
+ {L"A627", IPOD_MODEL_TOUCH, IPOD_COLOR_BLACK, IDB_CLASSIC_16, IDB_CLASSIC_160},
+
+ //insert info about new models here (be sure to take first char off the product code)...
+};
+
+static const iPodModelInfo
+shuffle1g_info = {L"XXXX", IPOD_MODEL_SHUFFLE, IPOD_COLOR_PINK, IDB_SHUFFLE1G_16, IDB_SHUFFLE1G_160},
+shuffle2g_info = {L"XXXX", IPOD_MODEL_SHUFFLE, IPOD_COLOR_PINK, IDB_SHUFFLE2G_16, IDB_SHUFFLE2G_160},
+shuffle3g_info = {L"XXXX", IPOD_MODEL_SHUFFLE, IPOD_COLOR_SILVER, IDB_SHUFFLE3G_16, IDB_SHUFFLE3G_160},
+shuffle4g_info = {L"XXXX", IPOD_MODEL_SHUFFLE, IPOD_COLOR_SILVER, IDB_SHUFFLE4G_16, IDB_SHUFFLE4G_160},
+classic_info = {L"XXXX", IPOD_MODEL_CLASSIC, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+video_info = {L"XXXX", IPOD_MODEL_VIDEO, IPOD_COLOR_WHITE, IDB_CLASSIC_16, IDB_CLASSIC_160},
+nano1g_info = {L"XXXX", IPOD_MODEL_NANO, IPOD_COLOR_WHITE, IDB_NANO1G_16, IDB_NANO1G_160},
+nano2g_info = {L"XXXX", IPOD_MODEL_NANO, IPOD_COLOR_WHITE, IDB_NANO2G_16, IDB_NANO2G_160},
+nano3g_info = {L"XXXX", IPOD_MODEL_NANO, IPOD_COLOR_WHITE, IDB_NANO3G_16, IDB_NANO3G_160},
+nano4g_info = {L"XXXX", IPOD_MODEL_NANO, IPOD_COLOR_WHITE, IDB_NANO4G_16, IDB_NANO4G_160};
+
+static INT_PTR CALLBACK selectipodtype_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ BringWindowToTop(hwndDlg);
+ wchar_t * sysinfo = (wchar_t*)lParam;
+ SetWindowLongPtr(hwndDlg,GWLP_USERDATA,lParam);
+ wchar_t path[] = {sysinfo[0],L":\\"};
+ wchar_t name[32] = {0};
+ GetVolumeInformation(path,name,32,NULL,NULL,NULL,NULL,0);
+ wchar_t buf[100] = {0};
+ wchar_t s[32] = {0};
+ GetDlgItemText(hwndDlg,IDC_IPODINFO,s,32);
+ StringCchPrintf(buf,100,L"%s (%s) %s",path,name,s);
+ SetDlgItemText(hwndDlg,IDC_IPODINFO,buf);
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_RADIO1:
+ case IDC_RADIO2:
+ case IDC_RADIO3:
+ case IDC_RADIO4:
+ case IDC_RADIO5:
+ case IDC_RADIO6:
+ case IDC_RADIO7:
+ case IDC_RADIO8:
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),TRUE);
+ break;
+ case IDCANCEL:
+ EndDialog(hwndDlg,1);
+ break;
+ case IDOK:
+ {
+ char *m;
+ if (IsDlgButtonChecked(hwndDlg,IDC_RADIO1)) m = "A133"; //shuffle
+ else if (IsDlgButtonChecked(hwndDlg,IDC_RADIO2)) m = "9586"; //photo
+ else if (IsDlgButtonChecked(hwndDlg,IDC_RADIO3)) m = "A002"; //video
+ else if (IsDlgButtonChecked(hwndDlg,IDC_RADIO4)) m = "A005"; //nano
+ else if (IsDlgButtonChecked(hwndDlg,IDC_RADIO6)) m = "A623"; //touch
+ else if (IsDlgButtonChecked(hwndDlg,IDC_RADIO7)) m = "B145"; //classic
+ else if (IsDlgButtonChecked(hwndDlg,IDC_RADIO8)) m = "B257"; //fatnano
+ else m = "8976"; //other
+ wchar_t * sysinfo = (wchar_t*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
+ FILE *f = _wfopen(sysinfo,L"a+b");
+ if (f)
+ {
+ fprintf(f,"ModelNumStr: M%s\n",m);
+ fclose(f);
+ }
+ }
+ EndDialog(hwndDlg,0);
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+/* This table was extracted from ipod-model-table from podsleuth svn trunk
+ * on 2008-06-14 (which seems to match podsleuth 0.6.2)
+*/
+static const iPodSerialToModel serial_to_model_mapping[] =
+{
+ { L"LG6", L"8541" },
+ { L"NAM", L"8541" },
+ { L"MJ2", L"8541" },
+ { L"ML1", L"8709" },
+ { L"MME", L"8709" },
+ { L"MMB", L"8737" },
+ { L"MMC", L"8738" },
+ { L"NGE", L"8740" },
+ { L"NGH", L"8740" },
+ { L"MMF", L"8741" },
+ { L"NLW", L"8946" },
+ { L"NRH", L"8976" },
+ { L"QQF", L"9460" },
+ { L"PQ5", L"9244" },
+ { L"PNT", L"9244" },
+ { L"NLY", L"8948" },
+ { L"NM7", L"8948" },
+ { L"PNU", L"9245" },
+ { L"PS9", L"9282" },
+ { L"Q8U", L"9282" },
+ { L"V9V", L"9787" },
+ { L"S2X", L"9787" },
+ { L"PQ7", L"9268" },
+ { L"TDU", L"A079" },
+ { L"TDS", L"A079" },
+ { L"TM2", L"A127" },
+ { L"SAZ", L"9830" },
+ { L"SB1", L"9830" },
+ { L"SAY", L"9829" },
+ { L"R5Q", L"9585" },
+ { L"R5R", L"9586" },
+ { L"R5T", L"9586" },
+ { L"PFW", L"9160" },
+ { L"PRC", L"9160" },
+ { L"QKL", L"9436" },
+ { L"QKQ", L"9436" },
+ { L"QKK", L"9435" },
+ { L"QKP", L"9435" },
+ { L"QKJ", L"9434" },
+ { L"QKN", L"9434" },
+ { L"QKM", L"9437" },
+ { L"QKR", L"9437" },
+ { L"S41", L"9800" },
+ { L"S4C", L"9800" },
+ { L"S43", L"9802" },
+ { L"S45", L"9804" },
+ { L"S47", L"9806" },
+ { L"S4J", L"9806" },
+ { L"S42", L"9801" },
+ { L"S44", L"9803" },
+ { L"S48", L"9807" },
+ { L"RS9", L"9724" },
+ { L"QGV", L"9724" },
+ { L"TSX", L"9724" },
+ { L"PFV", L"9724" },
+ { L"R80", L"9724" },
+ { L"RSA", L"9725" },
+ { L"TSY", L"9725" },
+ { L"C60", L"9725" },
+ { L"VTE", L"A546" },
+ { L"VTF", L"A546" },
+ { L"XQ5", L"A947" },
+ { L"XQS", L"A947" },
+ { L"XQV", L"A949" },
+ { L"XQX", L"A949" },
+ { L"YX7", L"A949" },
+ { L"XQY", L"A951" },
+ { L"YX8", L"A951" },
+ { L"XR1", L"A953" },
+ { L"YXA", L"B233" },
+ { L"YX6", L"B225" },
+ { L"YX7", L"B228" },
+ { L"YX9", L"B225" },
+ { L"UNA", L"A350" },
+ { L"UNB", L"A350" },
+ { L"UPR", L"A352" },
+ { L"UPS", L"A352" },
+ { L"SZB", L"A004" },
+ { L"SZV", L"A004" },
+ { L"SZW", L"A004" },
+ { L"SZC", L"A005" },
+ { L"SZT", L"A005" },
+ { L"TJT", L"A099" },
+ { L"TJU", L"A099" },
+ { L"TK2", L"A107" },
+ { L"TK3", L"A107" },
+ { L"VQ5", L"A477" },
+ { L"VQ6", L"A477" },
+ { L"V8T", L"A426" },
+ { L"V8U", L"A426" },
+ { L"V8W", L"A428" },
+ { L"V8X", L"A428" },
+ { L"VQH", L"A487" },
+ { L"VQJ", L"A487" },
+ { L"VQK", L"A489" },
+ { L"VKL", L"A489" },
+ { L"WL2", L"A725" },
+ { L"WL3", L"A725" },
+ { L"X9A", L"A726" },
+ { L"X9B", L"A726" },
+ { L"VQT", L"A497" },
+ { L"VQU", L"A497" },
+ { L"Y0P", L"A978" },
+ { L"Y0R", L"A980" },
+ { L"YXR", L"B249" },
+ { L"YXV", L"B257" },
+ { L"YXT", L"B253" },
+ { L"YXX", L"B261" },
+ { L"SZ9", L"A002" },
+ { L"WEC", L"A002" },
+ { L"WED", L"A002" },
+ { L"WEG", L"A002" },
+ { L"WEH", L"A002" },
+ { L"WEL", L"A002" },
+ { L"TXK", L"A146" },
+ { L"TXM", L"A146" },
+ { L"WEE", L"A146" },
+ { L"WEF", L"A146" },
+ { L"WEJ", L"A146" },
+ { L"WEK", L"A146" },
+ { L"SZA", L"A003" },
+ { L"SZU", L"A003" },
+ { L"TXL", L"A147" },
+ { L"TXN", L"A147" },
+ { L"V9K", L"A444" },
+ { L"V9L", L"A444" },
+ { L"WU9", L"A444" },
+ { L"VQM", L"A446" },
+ { L"V9M", L"A446" },
+ { L"V9N", L"A446" },
+ { L"WEE", L"A446" },
+ { L"V9P", L"A448" },
+ { L"V9Q", L"A448" },
+ { L"V9R", L"A450" },
+ { L"V9S", L"A450" },
+ { L"V95", L"A450" },
+ { L"V96", L"A450" },
+ { L"WUC", L"A450" },
+ { L"W9G", L"A664" }, /* 30GB iPod Video U2 5.5g */
+ { L"Y5N", L"B029" }, /* Silver Classic 80GB */
+ { L"YMV", L"B147" }, /* Black Classic 80GB */
+ { L"YMU", L"B145" }, /* Silver Classic 160GB */
+ { L"YMX", L"B150" }, /* Black Classic 160GB */
+ { L"2C5", L"B562" }, /* Silver Classic 120GB */
+ { L"2C7", L"B565" }, /* Black Classic 120GB */
+ { L"9ZS", L"C293" }, /* Silver Classic 160GB (2009) */
+ { L"9ZU", L"C297" }, /* Black Classic 160GB (2009) */
+
+ { L"37P", L"B663" }, /* 4GB Green Nano 4g */
+ { L"37Q", L"B666" }, /* 4GB Yellow Nano 4g */
+ { L"37H", L"B654" }, /* 4GB Pink Nano 4g */
+ { L"1P1", L"B480" }, /* 4GB Silver Nano 4g */
+ { L"37K", L"B657" }, /* 4GB Purple Nano 4g */
+ { L"37L", L"B660" }, /* 4GB Orange Nano 4g */
+ { L"2ME", L"B598" }, /* 8GB Silver Nano 4g */
+ { L"3QS", L"B732" }, /* 8GB Blue Nano 4g */
+ { L"3QT", L"B735" }, /* 8GB Pink Nano 4g */
+ { L"3QU", L"B739" }, /* 8GB Purple Nano 4g */
+ { L"3QW", L"B742" }, /* 8GB Orange Nano 4g */
+ { L"3QX", L"B745" }, /* 8GB Green Nano 4g */
+ { L"3QY", L"B748" }, /* 8GB Yellow Nano 4g */
+ { L"3R0", L"B754" }, /* 8GB Black Nano 4g */
+ { L"3QZ", L"B751" }, /* 8GB Red Nano 4g */
+ { L"5B7", L"B903" }, /* 16GB Silver Nano 4g */
+ { L"5B8", L"B905" }, /* 16GB Blue Nano 4g */
+ { L"5B9", L"B907" }, /* 16GB Pink Nano 4g */
+ { L"5BA", L"B909" }, /* 16GB Purple Nano 4g */
+ { L"5BB", L"B911" }, /* 16GB Orange Nano 4g */
+ { L"5BC", L"B913" }, /* 16GB Green Nano 4g */
+ { L"5BD", L"B915" }, /* 16GB Yellow Nano 4g */
+ { L"5BE", L"B917" }, /* 16GB Red Nano 4g */
+ { L"5BF", L"B918" }, /* 16GB Black Nano 4g */
+
+ { L"71V", L"C027" }, /* 8GB Silver Nano 5g */
+ { L"71Y", L"C031" }, /* 8GB Black Nano 5g */
+ { L"721", L"C034" }, /* 8GB Purple Nano 5g */
+ { L"726", L"C037" }, /* 8GB Blue Nano 5g */
+ { L"72A", L"C040" }, /* 8GB Green Nano 5g */
+ { L"72F", L"C046" }, /* 8GB Orange Nano 5g */
+ { L"72L", L"C050" }, /* 8GB Pink Nano 5g */
+
+ { L"72Q", L"C060" }, /* 16GB Silver Nano 5g */
+ { L"72R", L"C062" }, /* 16GB Black Nano 5g */
+ { L"72S", L"C064" }, /* 16GB Purple Nano 5g */
+ { L"72X", L"C066" }, /* 16GB Blue Nano 5g */
+ { L"734", L"C068" }, /* 16GB Green Nano 5g */
+ { L"738", L"C070" }, /* 16GB Yellow Nano 5g */
+ { L"739", L"C072" }, /* 16GB Orange Nano 5g */
+ { L"73A", L"C074" }, /* 16GB Red Nano 5g */
+ { L"73B", L"C075" }, /* 16GB Pink Nano 5g */
+
+ { L"4NZ", L"B867" }, /* 4GB Silver Shuffle 4g */
+ { L"891", L"C164" }, /* 4GB Black Shuffle 4g */
+
+ { L"W4T", L"A627" }, /* 16GB Silver iPod Touch (1st gen) */
+ { L"0JW", L"B376" }, /* 32GB Silver iPod Touch (1st gen) */
+ { L"201", L"B528" }, /* 8GB Silver iPod Touch (2nd gen) */
+ { L"203", L"B531" }, /* 16GB Silver iPod Touch (2nd gen) */
+ { L"75J", L"C086" }, /* 8GB Silver iPod Touch (3rd gen) */
+ { L"6K2", L"C008" }, /* 32GB Silver iPod Touch (3rd gen) */
+ { L"6K4", L"C011" }, /* 64GB Silver iPod Touch (3rd gen) */
+
+ { L"VR0", L"A501" }, /* 4GB Silver iPhone 1st gen */
+ { L"WH8", L"A712" }, /* 8GB Silver iPhone */
+ { L"0KH", L"B384" }, /* 16GB Silver iPhone */
+ { L"Y7H", L"B046" }, /* 8GB Black iPhone 3G */
+ { L"Y7K", L"B496" }, /* 16GB Black iPhone 3G */
+ { L"3NP", L"C131" }, /* 16GB Black iPhone 3GS */
+ { L"3NR", L"C133" } /* 32GB Black iPhone 3GS */
+};
+
+static const wchar_t *GetModelStrForFamilyID(unsigned int familyID)
+{
+ switch (familyID)
+ {
+ case 4: // iPod 4
+ return L"9282";
+ case 5: // iPod 4 (photo)
+ return L"9830";
+ case 6: // iPod 5
+ return L"A002";
+ case 7: // nano 1
+ return L"A004";
+ case 9: // nano 2
+ return L"A477";
+ case 11: // classic
+ return L"B147";
+ case 12: // fat nano
+ return L"A978";
+ case 128: // shuffle
+ return L"A133";
+ case 130: // shuffle 2
+ return L"A947";
+ default:
+ return 0;
+ }
+}
+
+static const iPodModelInfo *GetiPodInfoForModelStr(const wchar_t *modelstr)
+{
+ // now locate this ipod in our table
+ int l = sizeof(ipod_info_table)/sizeof(ipod_info_table[0]);
+ for (int i=0; i<l; i++)
+ {
+ if (_wcsnicmp(ipod_info_table[i].model_number,modelstr,wcslen(ipod_info_table[i].model_number))==0)
+ return &ipod_info_table[i]; // success!
+ }
+ return 0;
+}
+
+static const iPodModelInfo *GetiPodInfoForFamilyID(unsigned int familyID)
+{
+ switch(familyID)
+ {
+ case 6:
+ return &video_info;
+ case 7:
+ return &nano1g_info;
+ case 9:
+ return &nano2g_info;
+ case 11:
+ return &classic_info;
+ case 12:
+ return &nano3g_info;
+ case 15:
+ return &nano4g_info;
+ case 128:
+ return &shuffle1g_info;
+ case 130: // shuffle 2G
+ return &shuffle2g_info;
+ case 132: // shuffle 3G
+ return &shuffle3g_info;
+ case 133: // shuffle 4G
+ return &shuffle4g_info;
+ }
+ return 0;
+}
+
+const wchar_t* GetModelStrForSerialNumber(const wchar_t *serialNumber)
+{
+ // now locate this ipod in our table
+ int l = sizeof(serial_to_model_mapping)/sizeof(iPodSerialToModel);
+
+ INT serialNumberLen = lstrlen(serialNumber);
+
+ if (serialNumberLen < 3)
+ {
+ return NULL;
+ }
+
+ const wchar_t *last3OfSerialNumber = &serialNumber[serialNumberLen-3];
+
+ for (int i=0; i<l; i++)
+ {
+ int compareRet = CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, last3OfSerialNumber, -1, serial_to_model_mapping[i].serial, -1)-2;
+ if (compareRet==0)
+ return serial_to_model_mapping[i].model_number; // success!
+ }
+ return 0;
+}
+
+extern bool ParseSysInfoXML(wchar_t drive_letter, char * xml, int xmllen);
+
+iPodInfo::iPodInfo(const iPodModelInfo *_model)
+{
+ family_id = 0;
+ color = _model->color;
+ model = _model->model;
+ model_number = _wcsdup(_model->model_number);
+ image16 = _model->image16;
+ image160 = _model->image160;
+ fwid=0;
+ supportedArtworkFormats=0;
+ numberOfSupportedFormats=0;
+ shadow_db_version=0;
+}
+
+iPodInfo::~iPodInfo()
+{
+ free(fwid);
+ free(model_number);
+ delete supportedArtworkFormats;
+}
+
+void iPodInfo::SetFWID(const uint8_t *new_fwid)
+{
+ fwid = (uint8_t *)malloc(8);
+ memcpy(fwid, new_fwid, 8);
+}
+
+iPodInfo *GetiPodInfo(wchar_t drive)
+{
+ static const iPodModelInfo unknown = {NULL, IPOD_MODEL_INVALID, IPOD_COLOR_WHITE};
+
+ unsigned char fwid[8]={0};
+ bool have_fwid=false;
+ char xml[65536] = {0};
+ if (ParseSysInfoXML(drive, xml, sizeof(xml)/sizeof(char)))
+ {
+ // go fetch the FamilyID so we can construct a model string
+ DWORD bytesRead = strlen(xml);//sizeof(xml)/sizeof(char);
+
+ // use the plist handler here instead of fishing for the familyid string
+ // in the xml
+
+ // instantiate the plist loader
+ plistLoader it;
+
+ obj_xml *parser=0;
+ waServiceFactory *factory = plugin.service->service_getServiceByGuid(obj_xmlGUID);
+ if (factory)
+ {
+ parser = (obj_xml *)factory->getInterface();
+ }
+
+ if (parser)
+ {
+ // load the XML, this creates an iTunes DB in memory, and returns the root key
+ parser->xmlreader_open();
+ parser->xmlreader_registerCallback(L"plist\f*", &it);
+ parser->xmlreader_feed(xml, bytesRead);
+ parser->xmlreader_feed(0, 0);
+ parser->xmlreader_unregisterCallback(&it);
+ parser->xmlreader_close();
+ plistKey *root_key = &it;
+ plistData *root_dict = root_key->getData();
+ if (root_dict)
+ {
+ // get Firewire ID
+ plistKey *fwidKey = ((plistDict*)root_dict)->getKey(L"FireWireGUID");
+ if (fwidKey)
+ {
+ plistData *fwidData = fwidKey->getData();
+ if (fwidData)
+ {
+ const wchar_t* p = fwidData->getString();
+ for (int i=0; i<8 && *p; i++)
+ {
+ char num[3]={0,0,0};
+ num[0] = *(p++);
+ num[1] = *(p++);
+ fwid[i] = (uint8_t)strtoul(num,NULL,16);
+ }
+ have_fwid=true;
+ }
+ }
+
+
+ // check for the existance of sqlite
+ plistKey *sqliteKey = ((plistDict*)root_dict)->getKey(L"SQLiteDB");
+ if (sqliteKey)
+ {
+ plistData *sqliteData = sqliteKey->getData();
+ if (sqliteData)
+ {
+ const wchar_t* sqliteString = sqliteData->getString();
+ if (sqliteString)
+ {
+ int compareRet = CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, sqliteString, -1, L"1", -1)-2;
+
+ // At this point we dont want to support the sqlite family of ipods
+ // so, return unknown if sqlite found
+ if (compareRet == 0)
+ {
+ return 0;
+ }
+ }
+ }
+ } // end sqlite check
+
+ // check for FamilyID
+ plistKey *familyKey = ((plistDict*)root_dict)->getKey(L"FamilyID");
+ if (familyKey)
+ {
+ plistData *familyData = familyKey->getData();
+ if (familyData)
+ {
+ const wchar_t* familyIDString = familyData->getString();
+ if (familyIDString)
+ {
+ const wchar_t *modelStr = NULL;
+ unsigned int familyID = _wtoi(familyIDString);
+ // first, try to look up the iPod by family ID
+ const iPodModelInfo *info = GetiPodInfoForFamilyID(familyID);
+ if (!info)
+ {
+ modelStr = GetModelStrForFamilyID(familyID);
+
+ // if modelString not apparent, as the case is in most
+ // 5th gen nanos and classics
+ if (!info && !modelStr)
+ {
+ plistKey *serialNumberKey = ((plistDict*)root_dict)->getKey(L"SerialNumber");
+ if (serialNumberKey)
+ {
+ plistData *serialNumberData = serialNumberKey->getData();
+ if (serialNumberData)
+ {
+ const wchar_t* serialNumberString = serialNumberData->getString();
+
+ if (serialNumberString)
+ {
+ modelStr = GetModelStrForSerialNumber(serialNumberString);
+ }
+ }
+ }
+ }
+ }
+
+ if (modelStr || info)
+ {
+ if (!info)
+ info = GetiPodInfoForModelStr(modelStr);
+
+ if (info)
+ {
+ iPodInfo* retInfo = new iPodInfo(info);
+
+ if (have_fwid)
+ retInfo->SetFWID(fwid);
+
+ plistKey *shadow_db_key = ((plistDict*)root_dict)->getKey(L"ShadowDB");
+ if (shadow_db_key)
+ {
+ plistData *shadow_db_data = shadow_db_key->getData();
+ if (shadow_db_data && shadow_db_data->getType() == PLISTDATA_BOOLEAN)
+ {
+ plistBoolean *shadow_db_boolean = (plistBoolean *)shadow_db_data;
+ if (shadow_db_boolean->getValue())
+ retInfo->shadow_db_version = 1;
+
+ plistKey *shadow_db_version_key = ((plistDict*)root_dict)->getKey(L"ShadowDBVersion");
+ if (shadow_db_version_key)
+ {
+ plistData *shadow_db_version_data = shadow_db_version_key->getData();
+ if (shadow_db_version_data && shadow_db_version_data->getType() == PLISTDATA_INTEGER)
+ {
+ plistInteger *shadow_db_version_integer= (plistInteger *)shadow_db_version_data;
+ retInfo->shadow_db_version = shadow_db_version_integer->getValue();
+ }
+ }
+ }
+ }
+ // now try and populate the ArtworkFormats from the plist
+ // looks something like this
+ /*****************************************************
+ <key>AlbumArt</key>
+ <array>
+ <key>1069</key>
+ <dict>
+ <key>FormatId</key>
+ <integer>1069</integer>
+ <key>RenderWidth</key>
+ <integer>142</integer>
+ <key>RenderHeight</key>
+ <integer>142</integer>
+ <key>PixelFormat</key>
+ <string>4C353635</string>
+ <key>Interlaced</key>
+ <false/>
+ <key>ColorAdjustment</key>
+ <integer>0</integer>
+ <key>GammaAdjustment</key>
+ <real>2.2</real>
+ <key>Crop</key>
+ <false/>
+ <key>AlignRowBytes</key>
+ <true/>
+ <key>BackColor</key>
+ <string>00000000</string>
+ <key>AssociatedFormat</key>
+ <integer>131072</integer>
+ <key>ExcludedFormats</key>
+ <integer>-1</integer>
+ </dict>
+ <key>1055</key>
+ <dict>
+ <key>FormatId</key>
+ <integer>1055</integer>
+ <key>RenderWidth</key>
+ <integer>128</integer>
+ <key>RenderHeight</key>
+ <integer>128</integer>
+ <key>PixelFormat</key>
+ <string>4C353635</string>
+ <key>Interlaced</key>
+ <false/>
+ <key>ColorAdjustment</key>
+ <integer>0</integer>
+ <key>GammaAdjustment</key>
+ <real>2.2</real>
+ <key>Crop</key>
+ <true/>
+ <key>AlignRowBytes</key>
+ <true/>
+ <key>BackColor</key>
+ <string>00000000</string>
+ <key>AssociatedFormat</key>
+ <integer>0</integer>
+ </dict>
+ </array>
+ *******************************************************************/
+
+ // look for the AlbumArt dict
+ plistKey *albumArtKey = ((plistDict*)root_dict)->getKey(L"AlbumArt");
+
+ if (albumArtKey)
+ {
+ plistArray* albumArtArray = (plistArray *) albumArtKey->getData();
+
+ if (albumArtArray)
+ {
+ int numFormats = albumArtArray->getNumItems();
+ ArtworkFormat* artworkFormats = new ArtworkFormat[numFormats];
+
+
+ retInfo->supportedArtworkFormats = &artworkFormats[0];
+ retInfo->numberOfSupportedFormats = numFormats;
+
+ for (int i=0;i<numFormats;i++)
+ {
+ // we need to populate this structure
+ /**
+ static const ArtworkFormat ipod_color_artwork_info[] = {
+ {THUMB_COVER_SMALL, 56, 56, 1017, RGB_565, 4, 4},
+ {THUMB_COVER_LARGE, 140, 140, 1016, RGB_565, 4, 4},
+ {THUMB_PHOTO_TV_SCREEN, 720, 480, 1019, RGB_565, 4, 4},
+ {THUMB_PHOTO_LARGE, 130, 88, 1015, RGB_565, 4, 4},
+ {THUMB_PHOTO_FULL_SCREEN, 220, 176, 1013, RGB_565, 4, 4},
+ {THUMB_PHOTO_SMALL, 42, 30, 1009, RGB_565, 4, 4},
+ {THUMB_INVALID, -1, -1, -1, RGB_565, 4, 4}
+ };
+ */
+ plistDict *albumArtFormatDict = 0;
+ plistData *albumArtFormatKey = (plistKey *)albumArtArray->enumItem(i);
+ if (albumArtFormatKey->getType() == PLISTDATA_KEY)
+ {
+ albumArtFormatDict = (plistDict *)((plistKey *)albumArtFormatKey)->getData();
+ }
+ else
+ { // Nano 4G doesn't store keys in the AlbumArt array
+ albumArtFormatDict = (plistDict *)albumArtFormatKey;
+ }
+
+ int numKeys = albumArtFormatDict->getNumKeys();
+
+ if (numKeys)
+ {
+ for (int j=0; j<numKeys; j++)
+ {
+ plistKey *albumArtFormatItemKey = albumArtFormatDict->enumKey(j);
+ const wchar_t* albumArtFormatKeyName = albumArtFormatItemKey->getName();
+
+ // we need all the arwork formats under AlbumArt, just use
+ // a thumb type that we know is accepted
+ artworkFormats[i].type = THUMB_COVER_SMALL;
+
+ // these are 4, they just are
+ artworkFormats[i].row_align = 4;
+ artworkFormats[i].image_align = 4;
+
+ // gather the FormatId
+ if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, albumArtFormatKeyName, -1, L"FormatId", -1)-2 == 0)
+ {
+ const wchar_t* albumArtFormatValue = albumArtFormatItemKey->getData()->getString();
+ if (albumArtFormatValue != NULL)
+ {
+ artworkFormats[i].correlation_id = _wtoi(albumArtFormatValue);
+ }
+ }
+ // gather the RenderWidth
+ if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, albumArtFormatKeyName, -1, L"RenderWidth", -1)-2 == 0)
+ {
+ const wchar_t* albumArtFormatValue = albumArtFormatItemKey->getData()->getString();
+ if (albumArtFormatValue != NULL)
+ {
+ artworkFormats[i].width = _wtoi(albumArtFormatValue);
+ }
+ }
+ // gather the RenderHeight
+ if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, albumArtFormatKeyName, -1, L"RenderHeight", -1)-2 == 0)
+ {
+ const wchar_t* albumArtFormatValue = albumArtFormatItemKey->getData()->getString();
+ if (albumArtFormatValue != NULL)
+ {
+ artworkFormats[i].height = _wtoi(albumArtFormatValue);
+ }
+ }
+ // gather the PixelFormat
+ if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, albumArtFormatKeyName, -1, L"PixelFormat", -1)-2 == 0)
+ {
+ const wchar_t* albumArtFormatValue = albumArtFormatItemKey->getData()->getString();
+ if (albumArtFormatValue != NULL)
+ {
+ artworkFormats[i].format = RGB_565;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ retInfo->family_id = familyID;
+ return retInfo;
+ }
+ }
+
+ }
+ }
+ } // end familyid
+ }
+ } // end plist parser
+ }
+
+ for (int yy=0; yy<2; yy++)
+ {
+ wchar_t sysinfo[] = {drive,L":\\iPod_Control\\Device\\SysInfo"};
+
+ FILE *f = _wfopen(sysinfo,L"rt");
+ if (f)
+ {
+ wchar_t *modelnr=NULL;
+ wchar_t buf[1024] = {0};
+ while (fgetws(buf,1024,f))
+ {
+ int len = wcslen(buf);
+ //snip off trailing newline
+ if (len>0 && buf[len-1]==10)
+ {
+ buf[len-1]=0; len--;
+ }
+ wchar_t *colon = wcschr(buf,L':');
+ if (colon)
+ {
+ *colon=0;
+ if (!wcscmp(L"ModelNumStr",buf)) // found ModelNumStr line..
+ {
+ modelnr = colon+1;
+ while (modelnr && *modelnr == L' ') modelnr++;
+ if (!(*modelnr >= L'0' && *modelnr <= L'9')) modelnr++;
+ break; // modelnr found, so we're done
+ }
+ }
+ }
+
+ fclose(f);
+
+ if (modelnr && *modelnr)
+ {
+ const iPodModelInfo *info = GetiPodInfoForModelStr(modelnr);
+ if (info)
+ {
+ iPodInfo* retInfo = new iPodInfo(info);
+ if (have_fwid)
+ retInfo->SetFWID(fwid);
+
+ return retInfo;
+ }
+ }
+ }
+ if (!yy)
+ {
+ int d = WASABI_API_DIALOGBOXPARAM(IDD_SELECTIPODTYPE,plugin.hwndWinampParent,selectipodtype_dlgproc,(LPARAM)sysinfo);
+ if (d) return NULL;
+ }
+ }
+ return new iPodInfo(&unknown);
+}
+
+const ArtworkFormat* GetArtworkFormats(const iPodInfo* info)
+{
+ if (!info) return NULL;
+ return ipod_artwork_info_table[info->model];
+}
+
diff --git a/Src/Plugins/Portable/pmp_ipod/iPodInfo.h b/Src/Plugins/Portable/pmp_ipod/iPodInfo.h
new file mode 100644
index 00000000..7414e004
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/iPodInfo.h
@@ -0,0 +1,97 @@
+#ifndef _IPOD_INFO_H_
+#define _IPOD_INFO_H_
+
+#define RGB_565 0
+#define RGB_555 1
+#define RGB_555_REC 2
+typedef enum {
+ THUMB_INVALID = -1,
+ THUMB_COVER_SMALL,
+ THUMB_COVER_MEDIUM1,
+ THUMB_COVER_MEDIUM2,
+ THUMB_COVER_MEDIUM3,
+ THUMB_COVER_MEDIUM4,
+ THUMB_COVER_LARGE,
+ THUMB_PHOTO_SMALL,
+ THUMB_PHOTO_LARGE,
+ THUMB_PHOTO_FULL_SCREEN,
+ THUMB_PHOTO_TV_SCREEN,
+} ThumbType;
+
+typedef enum {
+ IPOD_COLOR_WHITE,
+ IPOD_COLOR_BLACK,
+ IPOD_COLOR_SILVER,
+ IPOD_COLOR_BLUE,
+ IPOD_COLOR_PINK,
+ IPOD_COLOR_GREEN,
+ IPOD_COLOR_ORANGE,
+ IPOD_COLOR_GOLD,
+ IPOD_COLOR_RED,
+ IPOD_COLOR_U2,
+} iPodColor;
+
+typedef enum {
+ IPOD_MODEL_INVALID=0,
+ IPOD_MODEL_COLOR=1,
+ IPOD_MODEL_REGULAR=2,
+ IPOD_MODEL_MINI=3,
+ IPOD_MODEL_SHUFFLE=4,
+ IPOD_MODEL_VIDEO=5,
+ IPOD_MODEL_NANO=6,
+ IPOD_MODEL_CLASSIC=7,
+ IPOD_MODEL_FATNANO=8,
+ IPOD_MODEL_TOUCH=9,
+} iPodModel;
+
+typedef struct {
+ ThumbType type;
+ int width;
+ int height;
+ int correlation_id;
+ int format;
+ int row_align;
+ int image_align;
+} ArtworkFormat;
+
+struct iPodModelInfo
+{
+ // model_number is abbreviated: if the first character is not numeric, it is ommited. e.g. "MA350 -> A350", "M9829 -> 9829"
+ const wchar_t *model_number;
+ iPodModel model;
+ iPodColor color;
+ int image16;
+ int image160;
+};
+
+class iPodInfo
+{
+public:
+ iPodInfo(const iPodModelInfo *model);
+ ~iPodInfo();
+ void SetFWID(const uint8_t *new_fwid);
+ int family_id;
+ wchar_t *model_number;
+ iPodModel model;
+ iPodColor color;
+ int image16;
+ int image160;
+ // Store the supported artwork formats if we
+ // can dynamically read it from the extended sysinfo xml
+ ArtworkFormat* supportedArtworkFormats;
+ size_t numberOfSupportedFormats;
+ unsigned char *fwid;
+ unsigned int shadow_db_version;
+};
+
+struct _iPodSerialToModel {
+ const wchar_t *serial;
+ const wchar_t *model_number;
+};
+typedef struct _iPodSerialToModel iPodSerialToModel;
+
+iPodInfo *GetiPodInfo(wchar_t drive);
+
+const ArtworkFormat* GetArtworkFormats(const iPodInfo* info);
+
+#endif //_IPOD_INFO_H_
diff --git a/Src/Plugins/Portable/pmp_ipod/iPodSD.cpp b/Src/Plugins/Portable/pmp_ipod/iPodSD.cpp
new file mode 100644
index 00000000..098473cf
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/iPodSD.cpp
@@ -0,0 +1,523 @@
+#include "iPodSD.h"
+#include <math.h>
+#include <assert.h>
+// get 3 bytes from data (used in iTunesSD1)
+static __forceinline unsigned long get3(const uint8_t * data)
+{
+ unsigned long ret = 0;
+ ret += ((unsigned long) data[0]) << 16;
+ ret += ((unsigned long) data[1]) << 8;
+ ret += ((unsigned long) data[2]);
+ return ret;
+}
+//write 3 bytes normal (used in iTunesSD1)
+static __forceinline void put3(const unsigned long number, uint8_t * data)
+{
+ data[0] = (uint8_t)(number >> 16) & 0xff;
+ data[1] = (uint8_t)(number >> 8) & 0xff;
+ data[2] = (uint8_t)number & 0xff;
+}
+
+// pass data and ptr, updates ptr automatically (by reference)
+static __forceinline void write_uint64_t(uint8_t *data, size_t &offset, uint64_t value)
+{
+ memcpy(&data[offset], &value, 8);
+ offset+=8;
+}
+
+// pass data and ptr, updates ptr automatically (by reference)
+static __forceinline void write_uint32_t(uint8_t *data, size_t &offset, uint32_t value)
+{
+ memcpy(&data[offset], &value, 4);
+ offset+=4;
+}
+
+// pass data and ptr, updates ptr automatically (by reference)
+static __forceinline void write_uint16_t(uint8_t *data, size_t &offset, uint16_t value)
+{
+ memcpy(&data[offset], &value, 2);
+ offset+=2;
+}
+
+
+// pass data and ptr, updates ptr automatically (by reference)
+static __forceinline void write_uint8_t(uint8_t *data, size_t &offset, uint8_t value)
+{
+ data[offset++] = value;
+}
+
+// pass data and ptr, updates ptr automatically (by reference)
+static __forceinline void write_header(uint8_t *data, size_t &offset, const char *header)
+{
+ data[offset++] = header[0];
+ data[offset++] = header[1];
+ data[offset++] = header[2];
+ data[offset++] = header[3];
+}
+
+
+// Case insensitive version of wcsstr
+static wchar_t *wcsistr (const wchar_t *s1, const wchar_t *s2)
+{
+ wchar_t *cp = (wchar_t*) s1;
+ wchar_t *s, *t, *endp;
+ wchar_t l, r;
+
+ endp = (wchar_t*)s1 + ( lstrlen(s1) - lstrlen(s2)) ;
+ while (cp && *cp && (cp <= endp))
+ {
+ s = cp;
+ t = (wchar_t*)s2;
+ while (s && *s && t && *t)
+ {
+ l = towupper(*s);
+ r = towupper(*t);
+ if (l != r)
+ break;
+ s++, t++;
+ }
+
+ if (*t == 0)
+ return cp;
+
+ cp = CharNext(cp);
+ }
+
+ return NULL;
+}
+//////////////////////////////////////////////////////////////////////
+// iTunesSD1 - Classes for dealing with the iPodShuffle
+//////////////////////////////////////////////////////////////////////
+
+iTunesSD1::iTunesSD1()
+{
+}
+
+iTunesSD1::~iTunesSD1()
+{
+}
+
+
+long iTunesSD1::write(const iPod_mhlt::mhit_map_t *songs, unsigned char * data, const unsigned long datasize)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iTunesSD_write);
+#endif
+
+ const unsigned int numsongs = songs->size();
+ const unsigned int total_size = 18 + (numsongs * 558);
+ ASSERT(datasize >= total_size);
+ if(datasize < total_size)
+ return(-1);
+
+ long ptr=0;
+
+ put3(numsongs, &data[ptr]);
+ ptr+=3;
+
+ put3(0x010600, &data[ptr]);
+ ptr+=3;
+
+ put3(0x12, &data[ptr]);
+ ptr+=3;
+
+ put3(0, &data[ptr]);
+ ptr+=3;
+ put3(0, &data[ptr]);
+ ptr+=3;
+ put3(0, &data[ptr]);
+ ptr+=3;
+
+ iPod_mhlt::mhit_map_t::const_iterator begin = songs->begin();
+ iPod_mhlt::mhit_map_t::const_iterator end = songs->end();
+ for(iPod_mhlt::mhit_map_t::const_iterator it = begin; it != end; it++)
+ {
+ iPod_mhit *m = ((*it).second);
+ iTunesSD_Song song(m);
+ long ret = song.write(&data[ptr], datasize - ptr);
+ if (ret < 0)
+ return ret;
+ ptr += ret;
+ }
+
+ return(ptr);
+}
+
+
+iTunesSD_Song::iTunesSD_Song(const iPod_mhit *m) : size_total(0x22e), starttime(0), stoptime(0), volume(0x64), filetype(0), playflags(iTunesSD_Song::SHUFFLE)
+{
+ memset(filename, 0, (SDSONG_FILENAME_LEN + 1) * sizeof(wchar_t));
+
+
+ iPod_mhod *mhod = m->FindString(MHOD_LOCATION);
+ ASSERT(mhod);
+ if(mhod)
+ {
+ // Convert from HFS format (:iPod_Control:Music:F00:filename) to quasi-FAT format (/iPod_Control/Music/F00/filename) filepaths
+ SetFilename(mhod->str);
+ wchar_t *w = filename;
+ while(w && *w != '\0')
+ {
+ if(*w == ':')
+ *w = '/';
+
+ w = CharNext(w);
+ }
+
+
+ SetStartTime(m->starttime);
+ SetStopTime(m->stoptime);
+
+ int volume = (int)m->volume;
+
+ // If Sound Check information is present, use that instead of volume
+ if(m->soundcheck != 0)
+ {
+ // This code converts SoundCheck back into a gain value, then into a -255 to 255 mhit::volume value
+ const double gain = -10.0 * log10(m->soundcheck / 1000.0);
+ volume = (int)(gain * 12.75); // XXX - this might not be the best way to convert the gain value...
+ }
+
+ if(volume < -255)
+ volume = -255;
+ else if(volume > 255)
+ volume = 255;
+
+ // Convert the volume value into a percentage for SetVolume
+ SetVolume((int)((double)volume / 2.55));
+
+
+ // To determine the filetype, first check the MHOD_FILETYPE type. If that isn't available, fallback to file extension
+ iPod_mhod *mtype = m->FindString(MHOD_FILETYPE);
+ if(mtype != NULL)
+ {
+ if(wcsistr(mtype->str, L"MPEG") != NULL || wcsistr(mtype->str, L"MP3") != NULL)
+ filetype = iTunesSD_Song::MP3;
+ else if(wcsistr(mtype->str, L"AAC") != NULL)
+ filetype = iTunesSD_Song::AAC;
+ else if(wcsistr(mtype->str, L"WAV") != NULL)
+ filetype = iTunesSD_Song::WAV;
+ }
+ if(filetype == 0)
+ {
+ if(wcsistr(mhod->str, L".mp3") != NULL)
+ filetype = iTunesSD_Song::MP3;
+ else if(wcsistr(mhod->str, L".m4a") != NULL || wcsistr(mhod->str, L".m4b") != NULL || wcsistr(mhod->str, L".m4p") != NULL)
+ filetype = iTunesSD_Song::AAC;
+ else if(wcsistr(mhod->str, L".wav") != NULL)
+ filetype = iTunesSD_Song::WAV;
+ }
+ ASSERT(filetype != 0);
+ if(filename == 0)
+ filetype = iTunesSD_Song::MP3; // Default to mp3
+
+
+ if(wcsistr(mhod->str, L".m4b") != NULL)
+ playflags = iTunesSD_Song::BOOKMARKABLE; // Only playback in normal mode
+ else
+ playflags = iTunesSD_Song::SHUFFLE; // Playable in normal/shuffle modes, but not bookmarkable
+ }
+}
+
+
+long iTunesSD_Song::write(unsigned char * data, const unsigned long datasize)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iTunesSD_Song_write);
+#endif
+ long ptr=0;
+
+ ASSERT(size_total == 0x22e);
+ ASSERT(filetype != 0);
+
+ put3(size_total, &data[ptr]);
+ ptr+=3;
+
+ put3(0x005aa501, &data[ptr]);
+
+ ptr+=3;
+ put3(starttime, &data[ptr]);
+ ptr+=3;
+ put3(0, &data[ptr]);
+ ptr+=3;
+ put3(0, &data[ptr]);
+ ptr+=3;
+ put3(stoptime, &data[ptr]);
+ ptr+=3;
+ put3(0, &data[ptr]);
+ ptr+=3;
+ put3(0, &data[ptr]);
+ ptr+=3;
+ put3(volume, &data[ptr]);
+ ptr+=3;
+ put3(filetype, &data[ptr]);
+ ptr+=3;
+ put3(0x200, &data[ptr]);
+ ptr+=3;
+
+ const unsigned int bufSize = (SDSONG_FILENAME_LEN + 1) * sizeof(wchar_t);
+ memcpy(&data[ptr], filename, bufSize);
+ ptr+=bufSize;
+
+ put3(playflags, &data[ptr]);
+ ptr+=3;
+
+ ASSERT(size_total == ptr);
+ return(ptr);
+}
+
+void iTunesSD_Song::SetFilename(const wchar_t *filename)
+{
+#ifdef IPODDB_PROFILER
+ profiler(iPodDB__iTunesStats_SetFilename);
+#endif
+
+ ASSERT(filename != NULL);
+ if(filename == NULL)
+ return;
+
+ if(filename)
+ {
+ lstrcpyn(this->filename, filename, SDSONG_FILENAME_LEN);
+ }
+ else
+ {
+ memset(this->filename, 0, SDSONG_FILENAME_LEN * sizeof(wchar_t));
+ }
+}
+
+// Accepts values from -100 to 100, with 0 meaning no volume change
+void iTunesSD_Song::SetVolume(const int percent)
+{
+ int p = percent;
+ if(p > 100)
+ p = 100;
+ else if(p < -100)
+ p = -100;
+
+ // Volume ranges from 0 (-100%) to 100 (0%) to 200 (100%)
+ volume = (unsigned int)(percent + 100);
+}
+
+
+/* Shadow DB version 2 */
+long iTunesSD2::write(const iPod_mhlt *songs, const iPod_mhlp *playlists, unsigned char * data, const unsigned long datasize)
+{
+ uint32_t numsongs = songs->GetChildrenCount();
+ uint32_t numplaylists = playlists->GetChildrenCount();
+ size_t offset=0;
+ size_t ptr=0;
+
+ if (datasize < 64)
+ return -1;
+
+ write_header(data, ptr, "bdhs");
+ write_uint32_t(data, ptr, 0x02000003); /* also have seen 0x02010001, perhaps a DB version number? */
+ write_uint32_t(data, ptr, 64); /* length of header */
+ write_uint32_t(data, ptr, numsongs);
+ write_uint32_t(data, ptr, numplaylists); /* number of playlists */
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ write_uint8_t(data, ptr, 0); /* volume limit */
+ write_uint8_t(data, ptr, 1); /* voiceover */
+ write_uint16_t(data, ptr, 0);
+ write_uint32_t(data, ptr, numsongs); /* TODO number of tracks w/o podcasts and audiobooks*/
+ write_uint32_t(data, ptr, 64); /* track header offset */
+ write_uint32_t(data, ptr, 64+20 + numsongs*4+iTunesSD2_Song::header_size*numsongs); /* playlist header offset */
+
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ offset = 64;
+
+ uint32_t hths_header_size = 20+numsongs*4;
+ if (datasize - ptr < hths_header_size)
+ return -1;
+ write_header(data, ptr, "hths");
+ write_uint32_t(data, ptr, hths_header_size); /* header length */
+ write_uint32_t(data, ptr, numsongs);
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ offset += hths_header_size;
+ /* positions for each track */
+ for (size_t i=0;i<numsongs;i++)
+ {
+ write_uint32_t(data, ptr, offset + iTunesSD2_Song::header_size * i);
+ }
+
+ /* write tracks */
+ for (uint32_t i=0;i<numsongs;i++)
+ {
+ iPod_mhit *m = songs->GetTrack(i);
+ long ret = iTunesSD2_Song::write(m, &data[ptr], datasize - ptr);
+ if (ret < 0)
+ return ret;
+ ptr += ret;
+ offset += ret;
+ }
+
+ uint32_t podcast_playlist_count=0;
+ for (size_t i=0;i<numplaylists;i++)
+ {
+ iPod_mhyp *p = playlists->GetPlaylist(i);
+ if (p->podcastflag)
+ podcast_playlist_count++;
+ }
+
+ uint32_t hphs_header_size = 20 + numplaylists*4;
+ if (datasize - ptr < hphs_header_size)
+ return -1;
+
+ write_header(data, ptr, "hphs");
+ write_uint32_t(data, ptr, hphs_header_size); /* header length */
+ write_uint32_t(data, ptr, numplaylists);
+ write_uint16_t(data, ptr, 0);
+ write_uint16_t(data, ptr, numplaylists-podcast_playlist_count); /* non-podcast playlists */
+ write_uint16_t(data, ptr, 1); /* master playlists */
+ write_uint16_t(data, ptr, numplaylists); /* non-audiobook playlists */
+ offset += hphs_header_size;
+
+ /* write offsets for each track */
+ for (size_t i=0;i<numplaylists;i++)
+ {
+ iPod_mhyp *p = playlists->GetPlaylist(i);
+ write_uint32_t(data, ptr, offset);
+ offset += p->GetMhipChildrenCount()*4 + 44;
+ }
+
+ iPod_mhyp *master_playlist = playlists->GetPlaylist(0);
+ /* write playlists */
+ for (size_t i=0;i<numplaylists;i++)
+ {
+ iPod_mhyp *p = playlists->GetPlaylist(i);
+ long ret = iTunesSD2_Playlist::write(master_playlist, p, &data[ptr], datasize - ptr);
+ if (ret < 0)
+ return ret;
+ ptr += ret;
+ }
+ return ptr;
+}
+uint32_t iTunesSD2_Song::header_size = 372;
+
+long iTunesSD2_Song::write(const iPod_mhit *mhit, unsigned char *data, const unsigned long datasize)
+{
+ if (datasize < header_size)
+ return -1;
+
+ size_t ptr=0;
+ write_header(data, ptr, "rths");
+ write_uint32_t(data, ptr, header_size); /* length of header */
+ write_uint32_t(data, ptr, mhit->starttime); /* start time, in milliseconds */
+ write_uint32_t(data, ptr, mhit->stoptime); /* stop time, in milliseconds */
+ write_uint32_t(data, ptr, mhit->volume); /* volume */
+ switch(mhit->filetype)
+ {
+ case FILETYPE_WAV:
+ write_uint32_t(data, ptr, iTunesSD_Song::WAV); /* file type */
+ break;
+ case FILETYPE_M4A:
+ case 0x4d344220:
+ case 0x4d345020:
+ write_uint32_t(data, ptr, iTunesSD_Song::AAC); /* file type */
+ break;
+ case FILETYPE_MP3:
+ default:
+ write_uint32_t(data, ptr, iTunesSD_Song::MP3); /* file type */
+ break;
+ }
+
+ iPod_mhod *mhod = mhit->FindString(MHOD_LOCATION);
+
+ char filename[256] = {0};
+ int converted = WideCharToMultiByte(CP_UTF8, 0, mhod->str, -1, filename, 256, 0, 0);
+ for (int i=0;i<converted;i++)
+ {
+ if (filename[i] == ':')
+ filename[i] = '/';
+ }
+ memcpy(&data[ptr], filename, converted);
+ ptr+=converted;
+ memset(&data[ptr], 0, 256-converted);
+ ptr+=256-converted;
+
+ write_uint32_t(data, ptr, mhit->bookmarktime); /* bookmark time */
+ write_uint8_t(data, ptr, 0); /* skip flag */
+ write_uint8_t(data, ptr, mhit->rememberPosition); /* remember playback position */
+ write_uint8_t(data, ptr, 0); /* part of gapless album */
+ write_uint8_t(data, ptr, 0);
+ write_uint32_t(data, ptr, mhit->pregap); /* pre-gap */
+ write_uint32_t(data, ptr, mhit->postgap); /* post-gap */
+ write_uint64_t(data, ptr, mhit->samplecount); /* number of samples */
+ write_uint32_t(data, ptr, mhit->gaplessData); /* gapless data */
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, mhit->album_id); /* album ID */
+ write_uint16_t(data, ptr, mhit->tracknum); /* track number */
+ write_uint16_t(data, ptr, mhit->cdnum); /* disc number */
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ write_uint64_t(data, ptr, mhit->dbid); /* dbid */
+ write_uint32_t(data, ptr, 0); /* artist ID */
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+
+ return ptr;
+}
+
+long iTunesSD2_Playlist::write(const iPod_mhyp *master_playlist, const iPod_mhyp *playlist, unsigned char * data, const unsigned long datasize)
+{
+ size_t ptr=0;
+ uint32_t tracks = playlist->GetMhipChildrenCount();
+ uint32_t header_size = 44 + tracks*4;
+ if (datasize < header_size)
+ return -1;
+
+ write_header(data, ptr, "lphs");
+ write_uint32_t(data, ptr, header_size); /* header length */
+ write_uint32_t(data, ptr, tracks); /* number of tracks */
+
+ /* number of music tracks TODO: special handling for master playlist */
+ if (playlist->podcastflag)
+ write_uint32_t(data, ptr, 0);
+ else
+ write_uint32_t(data, ptr, tracks);
+
+ write_uint64_t(data, ptr, playlist->playlistID); /* playlist ID */
+
+ /* playlist type */
+ if (playlist->podcastflag)
+ write_uint32_t(data, ptr, 3); /* podcast */
+ else if (playlist->hidden)
+ write_uint32_t(data, ptr, 1); /* master playlist */
+ else
+ write_uint32_t(data, ptr, 2); /* normal */
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ write_uint32_t(data, ptr, 0);
+ if (master_playlist == playlist)
+ {
+ for (uint32_t i=0;i<tracks;i++)
+ {
+ write_uint32_t(data, ptr, i);
+ }
+ }
+ else
+ {
+ for (uint32_t i=0;i<tracks;i++)
+ {
+ iPod_mhip *item = playlist->GetPlaylistEntry(i);
+ uint32_t master_index = master_playlist->FindPlaylistEntry(item->songindex);
+ assert(master_index != -1);
+ write_uint32_t(data, ptr, master_index);
+ }
+ }
+ return ptr;
+}
diff --git a/Src/Plugins/Portable/pmp_ipod/iPodSD.h b/Src/Plugins/Portable/pmp_ipod/iPodSD.h
new file mode 100644
index 00000000..8d2fc6f1
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/iPodSD.h
@@ -0,0 +1,78 @@
+#pragma once
+#include <bfc/platform/types.h>
+#include "iPodDB.h"
+/* iPod shuffle Shadow Database code */
+
+// iTunesSD (iPod Shuffle) Database Classes
+class iTunesSD_Song;
+class iTunesSD2_Song;
+
+
+class iTunesSD1
+{
+public:
+ iTunesSD1();
+ ~iTunesSD1();
+
+ long write(const iPod_mhlt::mhit_map_t *mhit, unsigned char * data, const unsigned long datasize);
+};
+
+class iTunesSD2
+{
+public:
+ long write(const iPod_mhlt *mhit, const iPod_mhlp *playlists, unsigned char * data, const unsigned long datasize);
+};
+
+#define SDSONG_FILENAME_LEN 260
+
+
+class iTunesSD_Song
+{
+public:
+ iTunesSD_Song(const iPod_mhit *mhit);
+ enum FileType
+ {
+ MP3 = 0x01,
+ AAC = 0x02,
+ WAV = 0x04
+ };
+
+ enum PlayFlags
+ {
+ UNKNOWN = 0x000001, // Might do something special, but nothing has been observed so far
+ BOOKMARKABLE = 0x000100, // Any song that has flag is bookmarked
+ SHUFFLE = 0x010000 // Only songs that have this flag are available in shuffle playback mode
+ };
+
+
+
+
+ long write(unsigned char * data, const unsigned long datasize);
+
+ void SetFilename(const wchar_t *filename);
+ void SetStartTime(const double milliseconds) { starttime = (unsigned int)(milliseconds / 256.0); }
+ void SetStopTime(const double milliseconds) { stoptime = (unsigned int)(milliseconds / 256.0); }
+ void SetVolume(const int percent);
+
+ // These are also only 3 byte values
+ uint32_t size_total;
+ uint32_t starttime;
+ uint32_t stoptime;
+ uint32_t volume; // -100% = 0x0, 0% = 0x64 (100), 100% = 0xc8 (200)
+ uint32_t filetype; // 0x01 = MP3, 0x02 = AAC, 0x04 = WAV
+ wchar_t filename[SDSONG_FILENAME_LEN + 1]; // Equal to Windows' MAX_PATH, plus the trailing NULL (261 wide chars = 522 bytes)
+ unsigned int playflags;
+};
+
+class iTunesSD2_Song
+{
+public:
+ static long write(const iPod_mhit *mhit, unsigned char * data, const unsigned long datasize);
+ static uint32_t header_size;
+};
+
+class iTunesSD2_Playlist
+{
+public:
+ static long write(const iPod_mhyp *master_playlist, const iPod_mhyp *playlist, unsigned char * data, const unsigned long datasize);
+};
diff --git a/Src/Plugins/Portable/pmp_ipod/main.cpp b/Src/Plugins/Portable/pmp_ipod/main.cpp
new file mode 100644
index 00000000..c1df71fe
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/main.cpp
@@ -0,0 +1,336 @@
+//#define PLUGIN_NAME "Nullsoft iPod Plug-in"
+#define PLUGIN_VERSION L"0.91"
+
+#include "iPodDevice.h"
+#include <Dbt.h>
+#include "..\..\General\gen_ml/itemlist.h"
+#include <api/service/waservicefactory.h>
+#include "api.h"
+#include "../nu/autoLock.h"
+#include "deviceprovider.h"
+#include <tataki/export.h>
+#include <shlwapi.h>
+
+int init();
+void quit();
+intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3);
+
+extern PMPDevicePlugin plugin = {PMPHDR_VER,0,init,quit,MessageProc};
+
+static DWORD WINAPI ThreadFunc_DeviceChange(LPVOID lpParam);
+
+bool g_detectAll=false;
+
+std::vector<iPodDevice*> iPods;
+
+api_config *AGAVE_API_CONFIG=0;
+api_memmgr *WASABI_API_MEMMGR=0;
+api_albumart *AGAVE_API_ALBUMART=0;
+api_threadpool *WASABI_API_THREADPOOL=0;
+api_application *WASABI_API_APP=0;
+api_devicemanager *AGAVE_API_DEVICEMANAGER = 0;
+
+// wasabi based services for localisation support
+api_language *WASABI_API_LNG = 0;
+
+HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
+
+static Nullsoft::Utility::LockGuard connect_guard;
+static DeviceProvider *deviceProvider = NULL;
+static bool loading_devices[26] = {0,};
+
+template <class api_T>
+void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
+{
+ if (plugin.service)
+ {
+ waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
+ if (factory)
+ api_t = reinterpret_cast<api_T *>( factory->getInterface() );
+ }
+}
+
+template <class api_T>
+void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
+{
+ if (plugin.service && api_t)
+ {
+ waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
+ if (factory)
+ factory->releaseInterface(api_t);
+ }
+ api_t = NULL;
+}
+
+static bool createBlankDatabase(wchar_t drive) {
+ wchar_t ipodtest[]={drive,L":\\iPod_Control\\iTunes\\iTunesDB"};
+ iPod_mhbd db;
+ BYTE data[4096] = {0};
+ long l = db.write(data,sizeof(data));
+ if(l <= 0) return false;
+ FILE* fh=_wfopen(ipodtest,L"wb");
+ if(!fh) return false;
+ if(fwrite(data,l,1,fh))
+ {
+ wchar_t ipodtest2[]={drive,L":\\iPod_Control\\iTunes\\firsttime"};
+ _wunlink(ipodtest2);
+ }
+ fclose(fh);
+ wchar_t music[] = {drive,L":\\iPod_Control\\Music"};
+ CreateDirectoryW(music,NULL);
+ return true;
+}
+
+
+bool ConnectDrive(wchar_t drive, bool connect)
+{
+ bool result;
+ size_t index;
+ iPodDevice *device;
+
+ Nullsoft::Utility::AutoLock connect_lock(connect_guard);
+
+ // capitalize
+ if (drive >= L'a' && drive <= L'z')
+ drive = drive - 32;
+
+ // reject invalid drive letters
+ if (drive < L'A' || drive > L'Z')
+ return false;
+
+ if (false != loading_devices[drive-'A'])
+ return false;
+
+
+ loading_devices[drive-'A'] = true;
+
+ if (false != connect)
+ {
+ result = true;
+
+ char ipodtest[]= {(char)drive,":\\iPod_Control\\iTunes\\iTunesDB"};
+ if (GetFileAttributes(ipodtest) == INVALID_FILE_ATTRIBUTES)
+ {
+ char ipodtest2[]={(char)drive,":\\iPod_Control\\iTunes\\firsttime"};
+ if (GetFileAttributes(ipodtest2) == INVALID_FILE_ATTRIBUTES ||
+ false == createBlankDatabase(drive))
+ {
+ result = false;
+ }
+ }
+
+ if (false != result)
+ {
+ index = iPods.size();
+ while(index--)
+ {
+ device = iPods[index];
+ if(device->drive == drive)
+ break;
+ }
+
+ if((size_t)-1 == index)
+ {
+ iPodDevice *d = new iPodDevice((char)drive);
+ }
+ else
+ result = false;
+ }
+ }
+ else
+ {
+ result = false;
+
+ index = iPods.size();
+ while(index--)
+ {
+ device = iPods.at(index);
+ if (device->drive == drive)
+ {
+ SendNotifyMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)device,PMP_IPC_DEVICEDISCONNECTED);
+ iPods.erase(iPods.begin() + index);
+ delete device;
+ result = true;
+ break;
+ }
+ }
+ }
+
+ loading_devices[drive-'A'] = false;
+
+ return result;
+}
+
+
+static void autoDetectCallback(wchar_t driveW, UINT type)
+{
+ if(false == g_detectAll && DRIVE_REMOVABLE != type)
+ return;
+
+ ConnectDrive(driveW, true);
+}
+
+int init()
+{
+ wchar_t mlipod[MAX_PATH] = {0};
+ PathCombineW(mlipod, (LPCWSTR)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_GETPLUGINDIRECTORYW), L"ml_ipod.dll");
+ FILE * f = _wfopen(mlipod, L"rb");
+ if (f) {
+ fclose(f);
+ return -1;
+ }
+
+ Tataki::Init(plugin.service);
+
+ ServiceBuild(AGAVE_API_CONFIG, AgaveConfigGUID);
+ ServiceBuild(WASABI_API_LNG, languageApiGUID);
+ ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ ServiceBuild(AGAVE_API_ALBUMART, albumArtGUID);
+ ServiceBuild(WASABI_API_THREADPOOL, ThreadPoolGUID);
+ ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
+ ServiceBuild(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
+
+ // need to have this initialised before we try to do anything with localisation features
+ WASABI_API_START_LANG(plugin.hDllInstance,PmpIPODLangGUID);
+
+ static wchar_t szDescription[256];
+ swprintf(szDescription, ARRAYSIZE(szDescription),
+ WASABI_API_LNGSTRINGW(IDS_NULLSOFT_IPOD_PLUGIN), PLUGIN_VERSION);
+ plugin.description = szDescription;
+
+ if (NULL != AGAVE_API_DEVICEMANAGER &&
+ NULL == deviceProvider)
+ {
+ if (SUCCEEDED(DeviceProvider::CreateInstance(&deviceProvider)) &&
+ FAILED(deviceProvider->Register(AGAVE_API_DEVICEMANAGER)))
+ {
+ deviceProvider->Release();
+ deviceProvider = NULL;
+ }
+ }
+
+ /* Our device shows up as a normal drive */
+ if (NULL == deviceProvider ||
+ FAILED(deviceProvider->BeginDiscovery(AGAVE_API_DEVICEMANAGER)))
+ {
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)autoDetectCallback,PMP_IPC_ENUM_ACTIVE_DRIVES);
+ }
+
+ return 0;
+}
+
+void quit()
+{
+ ServiceRelease(AGAVE_API_CONFIG, AgaveConfigGUID);
+ ServiceRelease(WASABI_API_LNG, languageApiGUID);
+ ServiceRelease(WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ ServiceRelease(AGAVE_API_ALBUMART, albumArtGUID);
+ ServiceRelease(WASABI_API_THREADPOOL, ThreadPoolGUID);
+ ServiceRelease(WASABI_API_APP, applicationApiServiceGuid);
+ ServiceRelease(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
+
+ Tataki::Quit();
+}
+
+static char FirstDriveFromMask(ULONG unitmask) {
+ char i;
+ for(i=0; i<26; ++i) {
+ if(unitmask & 0x1) break;
+ unitmask = unitmask >> 1;
+ }
+ return (i+'A');
+}
+
+
+int wmDeviceChange(WPARAM wParam, LPARAM lParam)
+{
+ if(wParam == DBT_DEVICEARRIVAL || wParam == DBT_DEVICEREMOVECOMPLETE)
+ {
+ PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
+ if(lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
+ { // its a volume
+ PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
+ if(0 == ((DBTF_MEDIA | DBTF_NET) & lpdbv->dbcv_flags) || g_detectAll)
+ { // its not a network drive or a CD/floppy, game on!
+ unsigned long unitmask = lpdbv->dbcv_unitmask;
+ for (int i = 0; i < 26; i++)
+ {
+ if (0 != (0x1 & unitmask))
+ {
+ int p = (int)('A' + i);
+ if (DBT_DEVICEARRIVAL == wParam)
+ p += 0x10000;
+
+ ThreadFunc_DeviceChange((void*)(intptr_t)p);
+
+ unitmask = unitmask >> 1;
+ if (0 == unitmask)
+ break;
+ }
+ else
+ unitmask = unitmask >> 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+static DWORD WINAPI ThreadFunc_DeviceChange(LPVOID lpParam)
+{
+ int p = (int)lpParam;
+ bool connect = p > 0x10000;
+
+ if(connect)
+ p -= 0x10000;
+
+ char drive = (char)p;
+ if(drive == 0)
+ return 0;
+
+ if(connect)
+ { // something plugged in
+ ConnectDrive(drive, connect);
+ }
+ else
+ { //something removed
+ size_t index;
+
+ index = iPods.size();
+ while(index--)
+ {
+ iPodDevice *device = iPods.at(index);
+ if (device->drive == drive)
+ {
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)device,PMP_IPC_DEVICEDISCONNECTED);
+ iPods.erase(iPods.begin() + index);
+ delete device;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+
+intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3) {
+ switch(msg) {
+ case PMP_DEVICECHANGE:
+ return wmDeviceChange(param1,param2);
+ case PMP_NO_CONFIG:
+ return TRUE;
+ case PMP_CONFIG:
+ return 0;
+ }
+ return 0;
+}
+
+extern "C" {
+ __declspec( dllexport ) PMPDevicePlugin * winampGetPMPDevicePlugin(){return &plugin;}
+ __declspec( dllexport ) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) {
+ int i = iPods.size();
+ while(i-- > 0) iPods[i]->Close();
+ return PMP_PLUGIN_UNINSTALL_NOW;
+ }
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_ipod/pmp_ipod.rc b/Src/Plugins/Portable/pmp_ipod/pmp_ipod.rc
new file mode 100644
index 00000000..6bcfbacb
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/pmp_ipod.rc
@@ -0,0 +1,194 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""version.rc2""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// PNG
+//
+
+IDB_CLASSIC_16 PNG "resources\\apple_ipod_classic_16.png"
+IDB_NANO1G_16 PNG "resources\\apple_ipod_nano_1g_16.png"
+IDB_NANO2G_16 PNG "resources\\apple_ipod_nano_2g_16.png"
+IDB_NANO3G_16 PNG "resources\\apple_ipod_nano_3g_16.png"
+IDB_NANO4G_16 PNG "resources\\apple_ipod_nano_4g_16.png"
+IDB_NANO5G_16 PNG "resources\\apple_ipod_nano_5g_16.png"
+IDB_SHUFFLE1G_16 PNG "resources\\apple_ipod_shuffle_1g_16.png"
+IDB_SHUFFLE2G_16 PNG "resources\\apple_ipod_shuffle_2g_16.png"
+IDB_SHUFFLE3G_16 PNG "resources\\apple_ipod_shuffle_3g_16.png"
+IDB_CLASSIC_160 PNG "resources\\apple_ipod_classic.png"
+IDB_NANO1G_160 PNG "resources\\apple_ipod_nano_1g.png"
+IDB_NANO2G_160 PNG "resources\\apple_ipod_nano_2g.png"
+IDB_NANO3G_160 PNG "resources\\apple_ipod_nano_3g.png"
+IDB_NANO4G_160 PNG "resources\\apple_ipod_nano_4g.png"
+IDB_NANO5G_160 PNG "resources\\apple_ipod_nano_5g.png"
+IDB_SHUFFLE1G_160 PNG "resources\\apple_ipod_shuffle_1g.png"
+IDB_SHUFFLE2G_160 PNG "resources\\apple_ipod_shuffle_2g.png"
+IDB_SHUFFLE3G_160 PNG "resources\\apple_ipod_shuffle_3g.png"
+IDB_SHUFFLE4G_160 PNG "resources\\apple_ipod_shuffle_4g.png"
+IDB_SHUFFLE4G_16 PNG "resources\\apple_ipod_shuffle_4g_16.png"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_CONFIG DIALOGEX 0, 0, 264, 226
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Gapless Playback",IDC_STATIC,4,3,255,44
+ LTEXT "Some iPods support the gapless playback of files.\nTo enable this, Winamp needs to scan the files on your iPod. Click ""Scan"" to begin this process.",IDC_STATIC,12,14,179,24
+ PUSHBUTTON "Scan",IDC_SCAN,201,19,50,14
+ GROUPBOX "Album Art",IDC_STATIC_ARTGROUP,4,54,255,30,NOT WS_VISIBLE
+ CONTROL "Add album art to tracks during transfer",IDC_CHECK_USEART,
+ "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,9,67,141,10
+END
+
+IDD_GAPSCAN DIALOGEX 0, 0, 186, 55
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Scanning for gapless playback information"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Scanning...",IDC_CAPTION,7,7,172,8
+ CONTROL "",IDC_PROGRESS1,"msctls_progress32",WS_BORDER,7,17,172,14
+ PUSHBUTTON "Scan in Background",IDC_BG,21,34,69,14
+ PUSHBUTTON "Stop Scan",IDCANCEL,95,34,50,14
+END
+
+IDD_SELECTIPODTYPE DIALOGEX 0, 0, 186, 140
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_TOPMOST | WS_EX_APPWINDOW
+CAPTION "Select iPod Type"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "In order to support some new features, we need to know which iPod model you have.",IDC_STATIC,7,7,172,17
+ LTEXT "My iPod model is:",IDC_IPODINFO,7,27,172,8
+ CONTROL "iPod Touch",IDC_RADIO6,"Button",BS_AUTORADIOBUTTON,7,40,51,10
+ CONTROL "iPod Classic",IDC_RADIO7,"Button",BS_AUTORADIOBUTTON,7,50,53,10
+ CONTROL "iPod Nano (widescreen)",IDC_RADIO8,"Button",BS_AUTORADIOBUTTON,7,59,91,10
+ CONTROL "iPod Shuffle",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,7,69,54,10
+ CONTROL "iPod Photo",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,7,79,50,10
+ CONTROL "iPod Video",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,7,89,49,10
+ CONTROL "iPod Nano",IDC_RADIO4,"Button",BS_AUTORADIOBUTTON,7,99,48,10
+ CONTROL "Other",IDC_RADIO5,"Button",BS_AUTORADIOBUTTON,7,109,35,10
+ DEFPUSHBUTTON "OK",IDOK,67,119,50,14,WS_DISABLED
+ PUSHBUTTON "Cancel",IDCANCEL,127,119,52,14
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_GAPSCAN, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 48
+ END
+
+ IDD_SELECTIPODTYPE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_NULLSOFT_IPOD_PLUGIN "Nullsoft iPod Device Plug-in v%s"
+ 65535 "{C2EE3DA5-B29B-42a0-AB5E-B202393435D6}"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_CANNOT_OPEN_FILE "Cannot open file"
+ IDS_CANNOT_CREATE_FILE "Cannot create file"
+ IDS_TRANSFERRING_PERCENT "Transferring %d%%"
+ IDS_CANCELLED "Cancelled"
+ IDS_DONE "Done"
+ IDS_TRANSFER_FAILED "Transfer failed"
+ IDS_IPOD_LOADING "iPod Loading..."
+ IDS_FAILED_TO_EJECT_IPOD
+ "Failed to Eject iPod. Is something else using it?"
+ IDS_ERROR "Error"
+ IDS_INVALID_TRACK "Invalid Track"
+ IDS_SCANNING "Scanning..."
+ IDS_ADVANCED "Advanced"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc2"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/Plugins/Portable/pmp_ipod/pmp_ipod.sln b/Src/Plugins/Portable/pmp_ipod/pmp_ipod.sln
new file mode 100644
index 00000000..3e6362f4
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/pmp_ipod.sln
@@ -0,0 +1,75 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29424.173
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmp_ipod", "pmp_ipod.vcxproj", "{54C393C2-5A0A-497F-930B-DA5316351B00}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1} = {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}
+ {5ED1729B-EA41-4163-9506-741A8B76F625} = {5ED1729B-EA41-4163-9506-741A8B76F625}
+ {255B68B5-7EF8-45EF-A675-2D6B88147909} = {255B68B5-7EF8-45EF-A675-2D6B88147909}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bfc", "..\Wasabi\bfc\bfc.vcxproj", "{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plist", "..\plist\plist.vcxproj", "{5ED1729B-EA41-4163-9506-741A8B76F625}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tataki", "..\tataki\tataki.vcxproj", "{255B68B5-7EF8-45EF-A675-2D6B88147909}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsutil", "..\nsutil\nsutil.vcxproj", "{DABE6307-F8DD-416D-9DAC-673E2DECB73F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {54C393C2-5A0A-497F-930B-DA5316351B00}.Debug|Win32.ActiveCfg = Debug|Win32
+ {54C393C2-5A0A-497F-930B-DA5316351B00}.Debug|Win32.Build.0 = Debug|Win32
+ {54C393C2-5A0A-497F-930B-DA5316351B00}.Debug|x64.ActiveCfg = Debug|x64
+ {54C393C2-5A0A-497F-930B-DA5316351B00}.Debug|x64.Build.0 = Debug|x64
+ {54C393C2-5A0A-497F-930B-DA5316351B00}.Release|Win32.ActiveCfg = Release|Win32
+ {54C393C2-5A0A-497F-930B-DA5316351B00}.Release|Win32.Build.0 = Release|Win32
+ {54C393C2-5A0A-497F-930B-DA5316351B00}.Release|x64.ActiveCfg = Release|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.Build.0 = Debug|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.ActiveCfg = Debug|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.ActiveCfg = Release|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.Build.0 = Release|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.ActiveCfg = Release|x64
+ {5ED1729B-EA41-4163-9506-741A8B76F625}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5ED1729B-EA41-4163-9506-741A8B76F625}.Debug|Win32.Build.0 = Debug|Win32
+ {5ED1729B-EA41-4163-9506-741A8B76F625}.Debug|x64.ActiveCfg = Debug|x64
+ {5ED1729B-EA41-4163-9506-741A8B76F625}.Release|Win32.ActiveCfg = Release|Win32
+ {5ED1729B-EA41-4163-9506-741A8B76F625}.Release|Win32.Build.0 = Release|Win32
+ {5ED1729B-EA41-4163-9506-741A8B76F625}.Release|x64.ActiveCfg = Release|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|Win32.ActiveCfg = Debug|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|Win32.Build.0 = Debug|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|x64.ActiveCfg = Debug|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|x64.Build.0 = Debug|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|Win32.ActiveCfg = Release|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|Win32.Build.0 = Release|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|x64.ActiveCfg = Release|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|x64.Build.0 = Release|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.Build.0 = Debug|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.ActiveCfg = Debug|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.Build.0 = Debug|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.ActiveCfg = Release|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.Build.0 = Release|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.ActiveCfg = Release|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {FC646532-2050-40A5-A2AB-F699F1C071C4}
+ EndGlobalSection
+EndGlobal
diff --git a/Src/Plugins/Portable/pmp_ipod/pmp_ipod.vcxproj b/Src/Plugins/Portable/pmp_ipod/pmp_ipod.vcxproj
new file mode 100644
index 00000000..0e0444f7
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/pmp_ipod.vcxproj
@@ -0,0 +1,355 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{54C393C2-5A0A-497F-930B-DA5316351B00}</ProjectGuid>
+ <RootNamespace>pmp_ipod</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg">
+ <VcpkgEnableManifest>false</VcpkgEnableManifest>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\..\Wasabi;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4018;4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapExports>false</MapExports>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>true</RandomizedBaseAddress>
+ <DataExecutionPrevention>true</DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\..\Wasabi;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4018;4244;4302;4311;4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapExports>false</MapExports>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>true</RandomizedBaseAddress>
+ <DataExecutionPrevention>true</DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\..\Wasabi;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4018;4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\..\Wasabi;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4018;4244;4302;4311;4267;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\plist\plist.vcxproj">
+ <Project>{5ed1729b-ea41-4163-9506-741a8b76f625}</Project>
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\tataki\tataki.vcxproj">
+ <Project>{255b68b5-7ef8-45ef-a675-2d6b88147909}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Wasabi\bfc\bfc.vcxproj">
+ <Project>{d0ec862e-dddd-4f4f-934f-b75dc9062dc1}</Project>
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
+ <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\General\gen_ml\itemlist.cpp" />
+ <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp" />
+ <ClCompile Include="deviceprovider.cpp" />
+ <ClCompile Include="eject.cpp" />
+ <ClCompile Include="filecopy.cpp" />
+ <ClCompile Include="hash58.cpp" />
+ <ClCompile Include="iPodArtworkDB.cpp" />
+ <ClCompile Include="iPodDB.cpp" />
+ <ClCompile Include="iPodDevice.cpp" />
+ <ClCompile Include="iPodInfo.cpp" />
+ <ClCompile Include="iPodSD.cpp" />
+ <ClCompile Include="main.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;ML_ex_EXPORTS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">WIN64;_DEBUG;_WINDOWS;_MBCS;_USRDLL;ML_ex_EXPORTS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;ML_ex_EXPORTS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">WIN64;NDEBUG;_WINDOWS;_MBCS;_USRDLL;ML_ex_EXPORTS</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="sha1.c" />
+ <ClCompile Include="SysInfoXML.cpp" />
+ <ClCompile Include="yail.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\General\gen_ml\itemlist.h" />
+ <ClInclude Include="..\..\General\gen_ml\ml.h" />
+ <ClInclude Include="..\..\Library\ml_pmp\pmp.h" />
+ <ClInclude Include="..\..\..\nu\Map.h" />
+ <ClInclude Include="api.h" />
+ <ClInclude Include="deviceprovider.h" />
+ <ClInclude Include="hash58.h" />
+ <ClInclude Include="iPodArtworkDB.h" />
+ <ClInclude Include="iPodDB.h" />
+ <ClInclude Include="iPodDevice.h" />
+ <ClInclude Include="iPodInfo.h" />
+ <ClInclude Include="iPodSD.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="sha1.h" />
+ <ClInclude Include="yail.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="pmp_ipod.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_ipod/pmp_ipod.vcxproj.filters b/Src/Plugins/Portable/pmp_ipod/pmp_ipod.vcxproj.filters
new file mode 100644
index 00000000..84bca7be
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/pmp_ipod.vcxproj.filters
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="deviceprovider.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="eject.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="filecopy.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="hash58.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="iPodArtworkDB.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="iPodDB.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="iPodDevice.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="iPodInfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="iPodSD.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="sha1.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SysInfoXML.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="yail.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\General\gen_ml\itemlist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="api.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="deviceprovider.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="hash58.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="iPodArtworkDB.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="iPodDB.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="iPodDevice.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="iPodInfo.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="iPodSD.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="sha1.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="yail.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\General\gen_ml\itemlist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\nu\Map.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\General\gen_ml\ml.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Library\ml_pmp\pmp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{8a27dfc8-8c21-4608-a4b0-2de0009d3411}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Ressource Files">
+ <UniqueIdentifier>{72f38cc1-6101-41e6-a08e-3583fa56c3ba}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{b8889dfc-5b23-471a-821f-74e6540a3df2}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="pmp_ipod.rc">
+ <Filter>Ressource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_ipod/resource.h b/Src/Plugins/Portable/pmp_ipod/resource.h
new file mode 100644
index 00000000..61f771f3
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resource.h
@@ -0,0 +1,71 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by pmp_ipod1.rc
+//
+#define IDS_CANNOT_OPEN_FILE 1
+#define IDS_CANNOT_CREATE_FILE 2
+#define IDS_TRANSFERRING_PERCENT 3
+#define IDS_CANCELLED 4
+#define IDS_DONE 5
+#define IDS_TRANSFER_FAILED 6
+#define IDS_IPOD_LOADING 7
+#define IDS_FAILED_TO_EJECT_IPOD 8
+#define IDS_ERROR 9
+#define IDS_INVALID_TRACK 10
+#define IDS_SCANNING 11
+#define IDS_STRING12 12
+#define IDS_ADVANCED 12
+#define IDD_CONFIG 102
+#define IDD_GAPSCAN 103
+#define IDD_DIALOG1 106
+#define IDD_SELECTIPODTYPE 106
+#define IDB_CLASSIC_16 110
+#define IDB_NANO1G_16 111
+#define IDB_NANO2G_16 112
+#define IDB_NANO3G_16 113
+#define IDB_NANO4G_16 114
+#define IDB_NANO5G_16 115
+#define IDB_SHUFFLE1G_16 116
+#define IDB_SHUFFLE2G_16 117
+#define IDB_SHUFFLE3G_16 118
+#define IDB_CLASSIC_160 119
+#define IDB_NANO1G_160 120
+#define IDB_NANO2G_160 121
+#define IDB_NANO3G_160 122
+#define IDB_NANO4G_160 123
+#define IDB_NANO5G_160 124
+#define IDB_SHUFFLE1G_160 125
+#define IDB_SHUFFLE2G_160 126
+#define IDB_PNG9 127
+#define IDB_SHUFFLE3G_160 127
+#define IDB_SHUFFLE4G_160 128
+#define IDB_PNG1 129
+#define IDB_SHUFFLE4G_16 129
+#define IDC_SCAN 1001
+#define IDC_PROGRESS1 1002
+#define IDC_CAPTION 1003
+#define IDC_BUTTON1 1004
+#define IDC_BG 1004
+#define IDC_RADIO1 1005
+#define IDC_RADIO2 1006
+#define IDC_RADIO3 1007
+#define IDC_RADIO4 1008
+#define IDC_IPODINFO 1009
+#define IDC_RADIO5 1010
+#define IDC_CHECK_USEART 1011
+#define IDC_RADIO6 1011
+#define IDC_RADIO7 1012
+#define IDC_STATIC_ARTGROUP 1013
+#define IDC_RADIO8 1013
+#define IDS_NULLSOFT_IPOD_PLUGIN 65534
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 131
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1014
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_classic.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_classic.png
new file mode 100644
index 00000000..3e1ab968
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_classic.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_classic_16.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_classic_16.png
new file mode 100644
index 00000000..3dc4defd
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_classic_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_1g.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_1g.png
new file mode 100644
index 00000000..466100c5
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_1g.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_1g_16.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_1g_16.png
new file mode 100644
index 00000000..a7d27890
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_1g_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_2g.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_2g.png
new file mode 100644
index 00000000..5b59d389
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_2g.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_2g_16.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_2g_16.png
new file mode 100644
index 00000000..5a4fa632
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_2g_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_3g.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_3g.png
new file mode 100644
index 00000000..59b7c098
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_3g.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_3g_16.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_3g_16.png
new file mode 100644
index 00000000..c7358d0a
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_3g_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_4g.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_4g.png
new file mode 100644
index 00000000..b455b90e
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_4g.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_4g_16.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_4g_16.png
new file mode 100644
index 00000000..7fac0d7a
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_4g_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_5g.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_5g.png
new file mode 100644
index 00000000..dbca3467
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_5g.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_5g_16.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_5g_16.png
new file mode 100644
index 00000000..d29a4ef5
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_nano_5g_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_1g.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_1g.png
new file mode 100644
index 00000000..6ebebb72
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_1g.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_1g_16.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_1g_16.png
new file mode 100644
index 00000000..14ed7814
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_1g_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_2g.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_2g.png
new file mode 100644
index 00000000..9f1ca1db
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_2g.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_2g_16.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_2g_16.png
new file mode 100644
index 00000000..39f45806
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_2g_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_3g.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_3g.png
new file mode 100644
index 00000000..5c00b6f9
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_3g.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_3g_16.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_3g_16.png
new file mode 100644
index 00000000..570d9c16
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_3g_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_4g.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_4g.png
new file mode 100644
index 00000000..65a5147c
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_4g.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_4g_16.png b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_4g_16.png
new file mode 100644
index 00000000..e6ea3a13
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/resources/apple_ipod_shuffle_4g_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_ipod/sha1.c b/Src/Plugins/Portable/pmp_ipod/sha1.c
new file mode 100644
index 00000000..09b3dd9d
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/sha1.c
@@ -0,0 +1,240 @@
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#define LITTLE_ENDIAN /* This should be #define'd if true. */
+/* #define SHA1HANDSOFF * Copies data before messing with it. */
+
+#include <stdio.h>
+#include <string.h>
+
+typedef struct {
+ unsigned long state[5];
+ unsigned long count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(unsigned long state[5], unsigned char buffer[64]);
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len);
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#ifdef LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(unsigned long state[5], unsigned char buffer[64])
+{
+ unsigned long a, b, c, d, e;
+ typedef union {
+ unsigned char c[64];
+ unsigned long l[16];
+ } CHAR64LONG16;
+ CHAR64LONG16* block;
+
+ /*
+ printf("SHA1Transform:\n");
+ for (k = 0; k < 4; k++) {
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ printf("%02X", buffer[k*16+i*4+j]);
+ }
+ putchar(' ');
+ }
+ putchar('\n');
+ }
+ printf("SHA1Transform (translated):\n");
+ for (k = 0; k < 4; k++) {
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ long x = buffer[k*16+i*4+j] & 0xFF;
+ printf("%02X", cryptTable[x] & 0xFF);
+ }
+ putchar(' ');
+ }
+ putchar('\n');
+ }
+ */
+
+#ifdef SHA1HANDSOFF
+ static unsigned char workspace[64];
+ block = (CHAR64LONG16*)workspace;
+ memcpy(block, buffer, 64);
+#else
+ block = (CHAR64LONG16*)buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len)
+{
+ unsigned int i, j;
+
+ j = (context->count[0] >> 3) & 63;
+ if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+ context->count[1] += (len >> 29);
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+ unsigned long i, j;
+ unsigned char finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (unsigned char *)"\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ SHA1Update(context, (unsigned char *)"\0", 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ i = j = 0;
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+ memset(&finalcount, 0, 8);
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
+ SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+
+/*************************************************************/
+
+/*
+int main(int argc, char** argv)
+{
+ int i, j;
+ SHA1_CTX context;
+ unsigned char digest[20], buffer[16384];
+ FILE* file;
+
+ if (argc > 2) {
+ puts("Public domain SHA-1 implementation - by Steve Reid <steve@edmweb.com>");
+ puts("Produces the SHA-1 hash of a file, or stdin if no file is specified.");
+ exit(0);
+ }
+ if (argc < 2) {
+ file = stdin;
+ }
+ else {
+ if (!(file = fopen(argv[1], "rb"))) {
+ fputs("Unable to open file.", stderr);
+ exit(-1);
+ }
+ }
+ SHA1Init(&context);
+ while (!feof(file)) { /* note: what if ferror(file)
+ i = fread(buffer, 1, 16384, file);
+ SHA1Update(&context, buffer, i);
+ }
+ SHA1Final(digest, &context);
+ fclose(file);
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 4; j++) {
+ printf("%02X", digest[i*4+j]);
+ }
+ putchar(' ');
+ }
+ putchar('\n');
+ exit(0);
+}
+*/
diff --git a/Src/Plugins/Portable/pmp_ipod/sha1.h b/Src/Plugins/Portable/pmp_ipod/sha1.h
new file mode 100644
index 00000000..7601f7ee
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/sha1.h
@@ -0,0 +1,9 @@
+typedef struct {
+ unsigned long state[5];
+ unsigned long count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+extern "C" void SHA1Init(SHA1_CTX* context);
+extern "C" void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len);
+extern "C" void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
diff --git a/Src/Plugins/Portable/pmp_ipod/version.rc2 b/Src/Plugins/Portable/pmp_ipod/version.rc2
new file mode 100644
index 00000000..802c1f4d
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/version.rc2
@@ -0,0 +1,39 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#include "../../../Winamp/buildType.h"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,91,0,0
+ PRODUCTVERSION WINAMP_PRODUCTVER
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Winamp SA"
+ VALUE "FileDescription", "Winamp Portable Device Plug-in"
+ VALUE "FileVersion", "0,91,0,0"
+ VALUE "InternalName", "Nullsoft iPod Device"
+ VALUE "LegalCopyright", "Copyright © 2006-2023 Winamp SA"
+ VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
+ VALUE "OriginalFilename", "pmp_ipod.dll"
+ VALUE "ProductName", "Winamp"
+ VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/Src/Plugins/Portable/pmp_ipod/yail.cpp b/Src/Plugins/Portable/pmp_ipod/yail.cpp
new file mode 100644
index 00000000..1be65450
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/yail.cpp
@@ -0,0 +1,114 @@
+#include "iPodDevice.h"
+#include <stdlib.h>
+#include <memory.h>
+#include <api/service/waservicefactory.h>
+#include <api/service/svcs/svc_imgload.h>
+#include "api.h"
+#include <tataki/export.h>
+
+#include "yail.h"
+
+extern PMPDevicePlugin plugin;
+static void recTransform (RGB565 *destination, RGB565 *source, int width, int height, int row_stride);
+
+static __forceinline ARGB32 pixto32bit(RGB565 pix0, int format) {
+ unsigned long pix = pix0;
+ if(format == RGB_565)
+ return (ARGB32)(((pix & 0x001F) << 3) | ((pix & 0x07E0) << 5) | ((pix & 0xF800) << 8) | 0xff000000);
+ else // format == RGB_555. Ignore alpha channel.
+ return (ARGB32)(((pix & 0x001F) << 3) | ((pix & 0x03E0) << 6) | ((pix & 0x7C00) << 9) | 0xff000000);
+}
+
+static __forceinline RGB565 pixto16bit(ARGB32 pix, int format) {
+ // 10987654321098765432109876543210
+ // ARGB32 is AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB
+ // RGB565 is RRRRRGGGGGGBBBBB
+ // RGB555 is ARRRRRGGGGGBBBBB
+ if(format == RGB_565)
+ return (RGB565)( ((pix >> 8) & 0xF800) | ((pix >> 5) & 0x07E0) | ((pix >> 3) & 0x001F) );
+ else // format == RGB_555. set A to 1 for now.
+ return (RGB565)( 0x8000 | ((pix >> 9) & 0x7C00) | ((pix >> 6) & 0x03E0) | ((pix >> 3) & 0x001F) );
+}
+
+Image::Image(const ARGB32 * d, int w, int h) : width(w), height(h) {
+ int size = sizeof(ARGB32)*w*h;
+ data = (ARGB32*)calloc(size,1);
+ memcpy(data,d,size);
+}
+
+#define ALIGN(size, boundary) ((((boundary) - ((size) % (boundary))) % (boundary)) + (size))
+
+Image::Image(const RGB565 * d, int w, int h, int format, int alignRowBytes, int alignImageBytes) : width(w), height(h) {
+ data = (ARGB32*)calloc(w*h*sizeof(ARGB32),1);
+ int rowgap = (ALIGN(sizeof(RGB565) * width, alignRowBytes) / sizeof(RGB565)) - width;
+ int p=0, q=0;
+ for(int j=0; j<height; j++)
+ {
+ for(int i=0; i<width; i++)
+ {
+ data[p++] = pixto32bit(d[q++], format);
+ }
+ q += rowgap;
+ }
+}
+
+Image::~Image() {
+ if(data) free(data); data=0;
+}
+
+void Image::exportToRGB565(RGB565* d_, int format, int alignRowBytes, int alignImageBytes) const {
+ int p=0, q=0;
+ int rowgap = (ALIGN(sizeof(RGB565) * width, alignRowBytes) / sizeof(RGB565)) - width;
+
+ RGB565* d;
+ if(format == RGB_555_REC)
+ {
+ int l = get16BitSize(width, height, alignRowBytes, alignImageBytes);
+ d = (RGB565*)calloc(l, 1);
+ }
+ else
+ d = d_;
+
+ for(int j=0; j<height; j++)
+ {
+ for(int i=0; i<width; i++)
+ {
+ d[p++] = pixto16bit(data[q++], format);
+ }
+ p += rowgap;
+ }
+
+ if(format == RGB_555_REC)
+ { // do wierd transform
+ recTransform(d_, d, width, height, width + rowgap);
+ free(d);
+ }
+}
+
+void Image::exportToARGB32(ARGB32* d) const {
+ memcpy(d,data,sizeof(ARGB32)*width*height);
+}
+
+int Image::get16BitSize(int width, int height, int alignRowBytes, int alignImageBytes) {
+ int rowSize = ALIGN(sizeof(RGB565) * width, alignRowBytes);
+ return ALIGN(rowSize * height, alignImageBytes);
+}
+
+
+static void recTransform (RGB565 *destination, RGB565 *source, int width, int height, int row_stride)
+{
+ if (width == 1)
+ {
+ *destination = *source;
+ }
+ else
+ {
+ recTransform(destination, source, width/2, height/2, row_stride);
+
+ recTransform(destination + (width/2)*(height/2), source + (height/2)*row_stride, width/2, height/2, row_stride);
+
+ recTransform(destination + 2*(width/2)*(height/2), source + width/2, width/2, height/2, row_stride);
+
+ recTransform(destination + 3*(width/2)*(height/2), source + (height/2)*row_stride + width/2, width/2, height/2, row_stride);
+ }
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_ipod/yail.h b/Src/Plugins/Portable/pmp_ipod/yail.h
new file mode 100644
index 00000000..374b376f
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_ipod/yail.h
@@ -0,0 +1,25 @@
+#ifndef _YAIL_H_
+#define _YAIL_H_
+
+// yet another image library. Because everything else SUCKS. Fact.
+
+typedef unsigned short RGB565;
+
+class Image {
+public:
+ Image(const ARGB32 * data, int w, int h);
+ Image(const RGB565 * data, int w, int h, int format, int alignRowBytes, int alignImageBytes);
+ ~Image();
+ void exportToRGB565(RGB565* data, int format, int alignRowBytes, int alignImageBytes) const;
+ void exportToARGB32(ARGB32* data) const;
+ ARGB32 * getData() {return data;}
+ int getWidth() const {return width;}
+ int getHeight() const {return height;}
+ int get16BitSize(int alignRowBytes, int alignImageBytes) { return get16BitSize(width,height,alignRowBytes, alignImageBytes); }
+ static int get16BitSize(int width, int height, int alignRowBytes, int alignImageBytes);
+protected:
+ ARGB32 *data;
+ int width,height;
+};
+
+#endif //_YAIL_H_ \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_njb/NJBDevice.cpp b/Src/Plugins/Portable/pmp_njb/NJBDevice.cpp
new file mode 100644
index 00000000..4eb0d41d
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_njb/NJBDevice.cpp
@@ -0,0 +1,714 @@
+#include "NJBDevice.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+
+HWND CreateDummyWindow();
+extern HWND mainMessageWindow;
+
+static __int64 fileSize(wchar_t * filename)
+{
+ WIN32_FIND_DATA f={0};
+ HANDLE h = FindFirstFileW(filename,&f);
+ if(h == INVALID_HANDLE_VALUE) return -1;
+ FindClose(h);
+ ULARGE_INTEGER i;
+ i.HighPart = f.nFileSizeHigh;
+ i.LowPart = f.nFileSizeLow;
+ return i.QuadPart;
+}
+
+static void FillSongFromMeta(BYTE * buf,Song * song) {
+ BYTE * ptr = buf;
+ short count = 0;
+ short type = 0;
+ short NameLen = 0;
+ long DataLen = 0;
+ long lData;
+
+ memcpy(&count, ptr, sizeof(short));
+ ptr += sizeof(short);
+
+ for(int i=0; i<count; i++)
+ {
+ memcpy(&type, ptr, sizeof(short));
+ ptr += sizeof(short);
+ memcpy(&NameLen, ptr, sizeof(short));
+ ptr += sizeof(short);
+ memcpy(&DataLen, ptr, sizeof(long));
+ ptr += sizeof(long);
+
+ char itemname[MAX_PATH] = {0};
+ memcpy(itemname, ptr, NameLen);
+ itemname[NameLen]=0;
+
+ ptr += NameLen;
+
+ if(type == 1) { // binary
+ memcpy(&lData, ptr, min(DataLen,4));
+ if (!_stricmp(itemname,LENGTH)) song->length = lData * 1000;
+ else if (!_stricmp(itemname,FILESIZE)) song->size = lData;
+ else if (!_stricmp(itemname,TRACKNUM)) song->track = lData;
+ else if (!_stricmp(itemname,YEAR)) song->year = lData;
+ else if (!_stricmp(itemname,TRACKID)) song->trackid = lData;
+ } else if(type == 2) { // unicode
+ if (!_stricmp(itemname,TITLE)) lstrcpyn(song->title,(WCHAR*)ptr,min((DataLen+2)/2,fieldlen));
+ else if (!_stricmp(itemname,ARTIST)) lstrcpyn(song->artist,(WCHAR*)ptr,min((DataLen+2)/2,fieldlen));
+ else if (!_stricmp(itemname,ALBUM)) lstrcpyn(song->album,(WCHAR*)ptr,min((DataLen+2)/2,fieldlen));
+ else if (!_stricmp(itemname,GENRE)) lstrcpyn(song->genre,(WCHAR*)ptr,min((DataLen+2)/2,fieldlen));
+ } else if(type == 0) { // ASCII
+ if (!_stricmp(itemname,CODEC)) {
+ int l=min(sizeof(song->codec)-1,DataLen);
+ memcpy(song->codec,ptr,l);
+ song->codec[l]=0;
+ }
+ }
+ ptr += DataLen;
+ }
+}
+
+static bool GetSong(DAPSDK_ID * item, long id, Song * song) {
+ long size;
+ if(m_pCTJukebox2->GetItemAttribute(id,(IUnknown*)item,0,&size,NULL) != S_OK) return false;
+ BYTE * buf = (BYTE*)calloc(size,sizeof(BYTE));
+ if(!buf) return false;
+ if(m_pCTJukebox2->GetItemAttribute(id,(IUnknown*)item,size,&size,(IUnknown*)buf) != S_OK) { free(buf); return false; }
+ FillSongFromMeta(buf,song);
+ free(buf);
+ return true;
+}
+
+static int song_sortfunc(const void *elem1, const void *elem2) {
+ Song *a=(Song *)*(void **)elem1;
+ Song *b=(Song *)*(void **)elem2;
+ return a->trackid - b->trackid;
+}
+
+static Song *BinaryChopFind(int id,Playlist * mpl) {
+ Song s;
+ s.trackid=id;
+ Song * d = &s;
+ Song ** ret = (Song**)bsearch(&d,mpl->songs.GetAll(),mpl->songs.GetSize(),sizeof(void*),song_sortfunc);
+ return ret?*ret:NULL;
+}
+
+static bool GetPlaylist(long id, DAPSDK_ID * item,Playlist * pl, Playlist * mpl)
+{
+ pl->dirty=false;
+ pl->plid = item->lID;
+ lstrcpyn(pl->name,item->bstrName,fieldlen);
+ SysFreeString(item->bstrName);
+ DAPSDK_ID song;
+ HRESULT hr = m_pCTJukebox2->FindFirstItem(id,(IUnknown*)item,(IUnknown*)&song);
+ while(hr == S_OK) {
+ Song * s = BinaryChopFind(song.lID,mpl);
+ if(s) pl->songs.Add(s);
+ hr = m_pCTJukebox2->FindNextItem(id,(IUnknown*)item,(IUnknown*)&song);
+ }
+ return true;
+}
+
+NJBDevice::NJBDevice(long id) : transcoder(NULL)
+{
+ InitializeCriticalSection(&csRevTransfer);
+ InitializeCriticalSection(&csTransfer);
+ devices.Add(this);
+
+ pmpDeviceLoading load;
+
+ load.dev = this;
+ load.UpdateCaption = NULL;
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)&load,PMP_IPC_DEVICELOADING);
+ if(load.UpdateCaption) {
+ load.UpdateCaption(WASABI_API_LNGSTRINGW(IDS_NJB_LOADING),load.context);
+ }
+
+ this->id = id;
+ transferQueueLength = 0;
+ messageWindow = CreateDummyWindow();
+ m_pCTJukebox2->SetCallbackWindow2(id,(long)messageWindow);
+
+ BYTE * ptr = NULL;
+ if(m_pCTJukebox2->GetDeviceProperties(id,kDeviceSerialNumberValue,(IUnknown*)ptr) == S_OK) {
+ memcpy(serial,ptr,16);
+ //free(ptr);
+ }
+
+ DAPSDK_ID item,parent,root;
+ Playlist * mpl = new Playlist;
+ BSTR name=NULL;
+ m_pCTJukebox2->GetDeviceProperties(id,kDeviceNameString,(IUnknown*)&name);
+ lstrcpyn(mpl->name,name?name:L"Creative Jukebox",fieldlen);
+ SysFreeString(name);
+
+ // search for tracks...
+ parent.lID = ALLTRACKSKEY;
+ parent.lType = kAudioTrackType;
+ HRESULT hr = m_pCTJukebox2->FindFirstItem(id,(IUnknown*)&parent,(IUnknown*)&item);
+
+ while(hr == S_OK) {
+ // add track
+ Song * song = new Song;
+ if(GetSong(&item,id,song)) {
+ mpl->songs.Add(song);
+ song->trackid = item.lID;
+ }
+ else delete song;
+ hr = m_pCTJukebox2->FindNextItem(id,(IUnknown*)&parent,(IUnknown*)&item);
+ }
+ qsort(mpl->songs.GetAll(),mpl->songs.GetSize(),sizeof(void*),song_sortfunc); // sort the master playlist by trackid, so we can find stuff later using binary chop
+ playlists.Add(mpl);
+
+ // search for playlists...
+ hr = m_pCTJukebox2->FindFirstRootItem(id,(IUnknown*)&root);
+ while(hr == S_OK) {
+ if(_wcsicmp(root.bstrName,L"PLAY LISTS")==0) {
+ playlistRoot.bstrName = L"PLAY LISTS";
+ playlistRoot.lID = root.lID;
+ playlistRoot.lType = root.lType;
+ HRESULT hr = m_pCTJukebox2->FindFirstParentItem(id,(IUnknown*)&root,(IUnknown*)&parent);
+ while(hr == S_OK) {
+ Playlist * pl = new Playlist;
+ if(GetPlaylist(id,&parent,pl,mpl)) playlists.Add(pl);
+ else delete pl;
+ hr = m_pCTJukebox2->FindNextParentItem(id,(IUnknown*)&root,(IUnknown*)&parent);
+ }
+ }
+ SysFreeString(root.bstrName);
+ hr = m_pCTJukebox2->FindNextRootItem(id,(IUnknown*)&root);
+ }
+
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICECONNECTED);
+ //transcoder = NULL;
+ transcoder = (Transcoder*)SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_GET_TRANSCODER);
+ if(transcoder) {
+ transcoder->AddAcceptableFormat(L"mp3");
+ //transcoder->AddAcceptableFormat(L"wav");
+ transcoder->AddAcceptableFormat(L"wma");
+ }
+}
+
+NJBDevice::~NJBDevice()
+{
+ m_pCTJukebox2->SetCallbackWindow2(id, (long)mainMessageWindow);
+ DestroyWindow(messageWindow);
+ messageWindow = NULL;
+ Playlist * mpl = (Playlist *)playlists.Get(0);
+ int l = mpl->songs.GetSize();
+ for(int i=0; i<l; i++) delete (Song *)mpl->songs.Get(i);
+ l = playlists.GetSize();
+ for(int i=0; i<l; i++) delete (Playlist *)playlists.Get(i);
+
+ for(int i=0; i<devices.GetSize(); i++) if(devices.Get(i) == this) { devices.Del(i); break; }
+ DeleteCriticalSection(&csRevTransfer);
+ DeleteCriticalSection(&csTransfer);
+ if(transcoder) SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)transcoder,PMP_IPC_RELEASE_TRANSCODER);
+}
+
+__int64 NJBDevice::getDeviceCapacityAvailable() {
+ DAPSDK_STORAGE_INFO s;
+ ULARGE_INTEGER ret;
+ m_pCTJukebox2->GetDeviceProperties(id,kStorageInfoStruct,(IUnknown*)&s);
+ ret.LowPart = s.freeL;
+ ret.HighPart = s.freeH;
+ return ret.QuadPart;
+}
+
+__int64 NJBDevice::getDeviceCapacityTotal() {
+ DAPSDK_STORAGE_INFO s;
+ ULARGE_INTEGER ret;
+ m_pCTJukebox2->GetDeviceProperties(id,kStorageInfoStruct,(IUnknown*)&s);
+ ret.LowPart = s.totalL;
+ ret.HighPart = s.totalH;
+ return ret.QuadPart;
+}
+
+void NJBDevice::Eject() {
+ Close();
+}
+
+void NJBDevice::Close()
+{
+ commitChanges();
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
+ if(devices.GetSize() == 1)
+ m_pCTJukebox2->SetCallbackWindow2(0,(long)mainMessageWindow);
+ delete this;
+}
+
+static BYTE * setAttrib(BYTE * ptr,short type, char * name, BYTE * data, int datalen) {
+ short namelen = (short)strlen(name);
+ memcpy(ptr,&type,2); ptr += 2;
+ memcpy(ptr,&namelen,2); ptr += 2;
+ memcpy(ptr,&datalen,4); ptr += 4;
+ memcpy(ptr,name,namelen); ptr += namelen;
+ memcpy(ptr,data,datalen); ptr += datalen;
+ return ptr;
+}
+
+static BYTE * makeMetaFromItemRecord(itemRecordW * item, wchar_t * file, long * size) {
+ char codec[4]="WAV";
+ wchar_t * ext = wcsrchr(file,L'.') + 1;
+ if(!_wcsicmp(ext,L"mp3")) strncpy(codec,"MP3",3);
+ else if(!_wcsicmp(ext,L"wma")) strncpy(codec,"WMA",3);
+
+ if(!item->album) item->album = _wcsdup(L"");
+ if(!item->artist) item->artist = _wcsdup(L"");
+ if(!item->title) item->title = _wcsdup(L"");
+
+ *size = (long)(2/*count*/+2/*type*/+6/*namelen+datalen*/+strlen(TITLE)+2*wcslen(item->title)
+ +2+6+strlen(ALBUM)+2*wcslen(item->album)
+ +2+6+strlen(ARTIST)+2*wcslen(item->artist)
+ +2+6+strlen(CODEC)+strlen(codec)
+ +2+6+strlen(FILESIZE)+sizeof(long)
+ +2+6+strlen(LENGTH)+sizeof(long));
+
+ int count = 6;
+ if (item->year > 0 ){
+ *size+=2+6+(long)strlen(YEAR)+sizeof(short);
+ count++;
+ }
+ if (item->genre) {
+ *size+=(long)(2+6+strlen(GENRE)+2*wcslen(item->genre));
+ count++;
+ }
+ if (item->track>0) {
+ *size+= (long)(2+6+strlen(TRACKNUM)+sizeof(short));
+ count++;
+ }
+ BYTE *buf = (BYTE*)calloc(1,*size);
+ BYTE *ptr = buf;
+ memcpy(ptr, &count, sizeof(short));
+ ptr += sizeof(short);
+
+ ptr = setAttrib(ptr,2,TITLE,(BYTE*)((wchar_t*)(item->title)),(int)wcslen(item->title)*2);
+ ptr = setAttrib(ptr,2,ARTIST,(BYTE*)((wchar_t*)(item->artist)), (int)wcslen(item->artist)*2);
+ ptr = setAttrib(ptr,2,ALBUM,(BYTE*)((wchar_t*)(item->album)), (int)wcslen(item->album)*2);
+ if(item->genre) ptr = setAttrib(ptr,2,GENRE,(BYTE*)((wchar_t*)(item->genre)), (int)wcslen(item->genre)*2);
+ short v = item->track;
+ if(item->track>0) ptr = setAttrib(ptr,1,TRACKNUM,(BYTE*)&v,2);
+ v = item->year;
+ if(item->year>0) ptr = setAttrib(ptr,1,YEAR,(BYTE*)&v,2);
+ ptr = setAttrib(ptr,0,CODEC,(BYTE*)codec,(int)strlen(codec));
+ ptr = setAttrib(ptr,1,LENGTH,(BYTE*)&item->length,4);
+ __int64 filesize = fileSize(file);
+ ptr = setAttrib(ptr,1,FILESIZE,(BYTE*)&filesize,4);
+
+ return buf;
+}
+
+BOOL NJBDevice::WindowMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ switch(uMsg) {
+ case WM_USER: // start add item
+ if(transferItem.status == 0) {
+ long size;
+ BYTE * buf = makeMetaFromItemRecord(const_cast<itemRecordW *>(transferItem.track),transferItem.file,&size);
+ HRESULT hr = m_pCTJukebox2->AddItem(id,kAudioTrackType,SysAllocString(transferItem.file),size,(IUnknown*)buf);
+ transferItem.meta = buf;
+ if(hr != S_OK) this->WindowMessage(hwnd,WM_DAPSDK_ADDITEM_COMPLETE,-1,0);
+ }
+ break;
+ case WM_DAPSDK_ADDITEM_PROGRESS:
+ {
+ wchar_t buf[100] = {0};
+ wsprintf(buf,WASABI_API_LNGSTRINGW(IDS_TRANSFERRING_PERCENT),(int)wParam);
+ transferItem.callback(transferItem.callbackContext,buf);
+ }
+ break;
+ case WM_DAPSDK_ADDITEM_COMPLETE:
+ if(wParam == 0) {
+ transferItem.callback(transferItem.callbackContext,WASABI_API_LNGSTRINGW(IDS_DONE));
+ Song * song = new Song;
+ song->trackid = (int)lParam;
+ FillSongFromMeta(transferItem.meta,song);
+ song->track = transferItem.track->track;
+ song->year = transferItem.track->year;
+ *transferItem.songid = (songid_t)song;
+ }
+ else {
+ transferItem.callback(transferItem.callbackContext,WASABI_API_LNGSTRINGW(IDS_ERROR));
+ }
+ transferItem.status = (wParam==0?1:2);
+ free(transferItem.meta);
+ break;
+ case WM_USER+1: // start get item
+ if(revTransferItem.status == 0) {
+ Song * song = (Song*)*revTransferItem.songid;
+ DAPSDK_ID item = {song->trackid,kAudioTrackType,song->title};
+ // memory allocated by SysAllocString is freed by COM (why, i don't know)
+ HRESULT hr = m_pCTJukebox2->GetItem(id,SysAllocString(revTransferItem.file),(IUnknown*)&item);
+ if(hr != S_OK) WindowMessage(hwnd,WM_DAPSDK_GETITEM_COMPLETE,-1,0);
+ }
+ break;
+ case WM_DAPSDK_GETITEM_PROGRESS:
+ {
+ wchar_t buf[100] = {0};
+ wsprintf(buf,WASABI_API_LNGSTRINGW(IDS_TRANSFERRING_PERCENT),(int)wParam);
+ revTransferItem.callback(revTransferItem.callbackContext,buf);
+ }
+ break;
+ case WM_DAPSDK_GETITEM_COMPLETE:
+ revTransferItem.callback(revTransferItem.callbackContext,
+ WASABI_API_LNGSTRINGW((wParam==0?IDS_DONE:IDS_ERROR)));
+ revTransferItem.status = (wParam==0?1:2);
+ break;
+ }
+ return 0;
+}
+//p75
+int NJBDevice::transferTrackToDevice(const itemRecordW * track,void * callbackContext,void (*callback)(void * callbackContext, wchar_t * status),songid_t * songid,int * killswitch) {
+ wchar_t file[2048] = {0};
+ wcsncpy(file,track->filename,2048);
+ bool deletefile = false;
+ if(transcoder) if(transcoder->ShouldTranscode(file)) {
+ wchar_t newfile[MAX_PATH] = {0};
+ wchar_t ext[10] = {0};
+ transcoder->CanTranscode(file,ext);
+ transcoder->GetTempFilePath(ext,newfile);
+ if(transcoder->TranscodeFile(file,newfile,killswitch,callback,callbackContext)) return -1;
+ wcsncpy(file,newfile,2048);
+ deletefile=true;
+ }
+ EnterCriticalSection(&csTransfer);
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_TRANSFERRING));
+ transferItem.file = file;
+ transferItem.callback = callback;
+ transferItem.callbackContext = callbackContext;
+ transferItem.status=0; // in progress
+ transferItem.killswitch = killswitch;
+ transferItem.songid = songid;
+ transferItem.track = track;
+
+ //now start the transfer
+ PostMessage(messageWindow,WM_USER,0,0);
+
+ while(transferItem.status==0) Sleep(10); // wait for transfer
+
+ // transfer completed
+ int ret = transferItem.status==1?0:-1;
+
+ LeaveCriticalSection(&csTransfer);
+ if(deletefile) _wunlink(file);
+ return ret;
+}
+
+int NJBDevice::trackAddedToTransferQueue(const itemRecordW * track) {
+ __int64 l;
+ if(transcoder && transcoder->ShouldTranscode(track->filename)) {
+ int k = transcoder->CanTranscode(track->filename);
+ if(k == -1) return -2;
+ if(k == 0) l = fileSize(track->filename);
+ else l = (__int64)k;
+ } else {
+ wchar_t * ext = wcsrchr(track->filename,L'.');
+ if(!ext) return -2;
+ if(_wcsicmp(ext,L".mp3") && _wcsicmp(ext,L".wma") && _wcsicmp(ext,L".wav")) return -2;
+ l = fileSize(track->filename);
+ }
+ if(transferQueueLength + l + 1000000 > getDeviceCapacityAvailable())
+ return -1;
+ else {
+ transferQueueLength += l;
+ return 0;
+ }
+}
+
+void NJBDevice::trackRemovedFromTransferQueue(const itemRecordW * track) {
+ __int64 l = (__int64)fileSize(track->filename);
+ if(transcoder && transcoder->ShouldTranscode(track->filename)) {
+ int k = transcoder->CanTranscode(track->filename);
+ if(k != -1 && k != 0) l = (__int64)k;
+ }
+ transferQueueLength -= l;
+}
+
+__int64 NJBDevice::getTrackSizeOnDevice(const itemRecordW * track) {
+ if(transcoder && transcoder->ShouldTranscode(track->filename)) {
+ int k = transcoder->CanTranscode(track->filename);
+ if(k != -1 && k != 0) return k;
+ }
+ wchar_t * ext = wcsrchr(track->filename,L'.');
+ if(!ext) return 0;
+ if(_wcsicmp(ext,L".mp3") && _wcsicmp(ext,L".wma") && _wcsicmp(ext,L".wav")) return 0;
+ return fileSize(track->filename);
+}
+
+void NJBDevice::deleteTrack(songid_t songid) {
+ Song * s = (Song*)songid;
+ for(int i=0; i<playlists.GetSize(); i++) {
+ Playlist * pl = (Playlist *)playlists.Get(i);
+ int l = pl->songs.GetSize();
+ while(l-- > 0) if(pl->songs.Get(l) == (void*)s) { pl->songs.Del(l); if(i>0) pl->dirty=true; }
+ }
+ DAPSDK_ID item = {s->trackid,kAudioTrackType,s->title};
+ m_pCTJukebox2->DeleteItem(id,(IUnknown*)&item);
+ delete s;
+}
+
+void NJBDevice::commitChanges() {
+ for(int i=1; i<playlists.GetSize(); i++) {
+ Playlist * pl = (Playlist *)playlists.Get(i);
+ if(pl->dirty) {
+ pl->dirty = false;
+ DAPSDK_ID parentold = {pl->plid,kPlaylistType,pl->name};
+ m_pCTJukebox2->DeleteParentItem(id,(IUnknown*)&parentold);
+ DAPSDK_ID parent = {0,kPlaylistType,_wcsdup(pl->name)};
+ m_pCTJukebox2->AddParentItem(id,(IUnknown*)&playlistRoot,(IUnknown*)&parent);
+ pl->plid = parent.lID;
+ long l = pl->songs.GetSize();
+ DAPSDK_ID * list = (DAPSDK_ID *)calloc(sizeof(DAPSDK_ID),l);
+ for(int j=0; j<l; j++) {
+ Song * s = (Song*)pl->songs.Get(j);
+ if(s) {
+ list[j].lID = s->trackid;
+ list[j].lType = kAudioTrackType;
+ list[j].bstrName = SysAllocString(s->title);
+ }
+ }
+ m_pCTJukebox2->AddItemsToParentItem(id,(IUnknown*)&parent,l,(IUnknown*)list);
+ free(list);
+ }
+ }
+}
+
+int NJBDevice::getPlaylistCount() {
+ return playlists.GetSize();
+}
+
+void NJBDevice::getPlaylistName(int playlistnumber, wchar_t * buf, int len) {
+ Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
+ lstrcpyn(buf,pl->name,len);
+}
+
+int NJBDevice::getPlaylistLength(int playlistnumber) {
+ Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
+ return pl->songs.GetSize();
+}
+
+songid_t NJBDevice::getPlaylistTrack(int playlistnumber,int songnum) {
+ Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
+ return (songid_t) pl->songs.Get(songnum);
+}
+
+void NJBDevice::setPlaylistName(int playlistnumber, const wchar_t * buf) {
+ Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
+ lstrcpyn(pl->name,buf,fieldlen);
+ DAPSDK_ID item = {pl->plid,kPlaylistType,pl->name};
+ BSTR name = SysAllocString(buf);
+ m_pCTJukebox2->RenameParentItem(id,(IUnknown*)&item, name);
+ SysFreeString(name);
+}
+
+void NJBDevice::playlistSwapItems(int playlistnumber, int posA, int posB) {
+ Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
+ void * a = pl->songs.Get(posA);
+ void * b = pl->songs.Get(posB);
+ pl->songs.Set(posA,b);
+ pl->songs.Set(posB,a);
+ pl->dirty = true;
+}
+
+static int sortby;
+#define RETIFNZ(v) if ((v)!=0) return v;
+#define STRCMP_NULLOK _wcsicmp
+
+static int sortFunc(const void *elem1, const void *elem2)
+{
+ int use_by = sortby;
+ Song *a=(Song *)*(void **)elem1;
+ Song *b=(Song *)*(void **)elem2;
+
+ // this might be too slow, but it'd be nice
+ int x;
+ for (x = 0; x < 5; x ++)
+ {
+ if (use_by == SORTBY_TITLE) // title -> artist -> album -> disc -> track
+ {
+ int v=STRCMP_NULLOK(a->title,b->title);
+ RETIFNZ(v)
+ use_by=SORTBY_ARTIST;
+ }
+ else if (use_by == SORTBY_ARTIST) // artist -> album -> disc -> track -> title
+ {
+ int v=STRCMP_NULLOK(a->artist,b->artist);
+ RETIFNZ(v)
+ use_by=SORTBY_ALBUM;
+ }
+ else if (use_by == SORTBY_ALBUM) // album -> disc -> track -> title -> artist
+ {
+ int v=STRCMP_NULLOK(a->album,b->album);
+ RETIFNZ(v)
+ use_by=SORTBY_DISCNUM;
+ }
+ else if (use_by == SORTBY_TRACKNUM) // track -> title -> artist -> album -> disc
+ {
+ int v1=a->track;
+ int v2=b->track;
+ if (v1<0)v1=0;
+ if (v2<0)v2=0;
+ RETIFNZ(v1-v2)
+ use_by=SORTBY_TITLE;
+ }
+ else if (use_by == SORTBY_GENRE) // genre -> artist -> album -> disc -> track
+ {
+ int v=STRCMP_NULLOK(a->genre,b->genre);
+ RETIFNZ(v)
+ use_by=SORTBY_ARTIST;
+ }
+ else break; // no sort order?
+ }
+
+ return 0;
+}
+#undef RETIFNZ
+#undef STRCMP_NULLOK
+
+
+void NJBDevice::sortPlaylist(int playlistnumber, int sortBy) {
+ sortby = sortBy;
+ Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
+ qsort(pl->songs.GetAll(),pl->songs.GetSize(),sizeof(void*),sortFunc);
+ pl->dirty=true;
+}
+
+void NJBDevice::addTrackToPlaylist(int playlistnumber, songid_t songid) {
+ Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
+ pl->songs.Add((void*)songid);
+ pl->dirty = true;
+}
+
+void NJBDevice::removeTrackFromPlaylist(int playlistnumber, int songnum) {
+ Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
+ pl->songs.Del(songnum);
+ pl->dirty = true;
+}
+
+void NJBDevice::deletePlaylist(int playlistnumber) {
+ Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
+ DAPSDK_ID parent = {pl->plid,kPlaylistType,pl->name};
+ m_pCTJukebox2->DeleteParentItem(id,(IUnknown*)&parent);
+ playlists.Del(playlistnumber);
+ delete pl;
+}
+
+int NJBDevice::newPlaylist(const wchar_t * name) {
+ Playlist * pl = new Playlist;
+ pl->dirty = false;
+ lstrcpyn(pl->name,name,fieldlen);
+ DAPSDK_ID parent = {0,kPlaylistType,pl->name};
+ m_pCTJukebox2->AddParentItem(id,(IUnknown*)&playlistRoot,(IUnknown*)&parent);
+ pl->plid = parent.lID;
+ playlists.Add(pl);
+ return playlists.GetSize() - 1;
+}
+
+void NJBDevice::getTrackArtist(songid_t songid, wchar_t * buf, int len) {lstrcpyn(buf,((Song*)songid)->artist,len);}
+void NJBDevice::getTrackAlbum(songid_t songid, wchar_t * buf, int len) {lstrcpyn(buf,((Song*)songid)->album,len);}
+void NJBDevice::getTrackTitle(songid_t songid, wchar_t * buf, int len) {lstrcpyn(buf,((Song*)songid)->title,len);}
+void NJBDevice::getTrackGenre(songid_t songid, wchar_t * buf, int len) {lstrcpyn(buf,((Song*)songid)->genre,len);}
+int NJBDevice::getTrackTrackNum(songid_t songid) {return ((Song*)songid)->track;}
+int NJBDevice::getTrackDiscNum(songid_t songid) {return -1;}
+int NJBDevice::getTrackYear(songid_t songid) {return ((Song*)songid)->year;}
+__int64 NJBDevice::getTrackSize(songid_t songid) {return ((Song*)songid)->size;}
+int NJBDevice::getTrackLength(songid_t songid) {return ((Song*)songid)->length;}
+int NJBDevice::getTrackBitrate(songid_t songid) {return -1;}
+int NJBDevice::getTrackPlayCount(songid_t songid) {return -1;}
+int NJBDevice::getTrackRating(songid_t songid) {return -1;}
+__time64_t NJBDevice::getTrackLastPlayed(songid_t songid) {return -1;}
+__time64_t NJBDevice::getTrackLastUpdated(songid_t songid) {return -1;}
+
+void NJBDevice::getTrackExtraInfo(songid_t songid, const wchar_t * field, wchar_t * buf, int len) {
+ if(!wcscmp(field,L"ext")) {
+ Song * s = (Song *)songid;
+ lstrcpyn(buf,(wchar_t*)AutoWide(s->codec),len);
+ wchar_t * p = buf;
+ while(p && *p) { *p=towlower(*p); p++; }
+ }
+}
+
+void NJBDevice::setTrackArtist(songid_t songid, const wchar_t * value) {
+ Song * s = (Song *)songid;
+ lstrcpyn(s->artist,value,fieldlen);
+ DAPSDK_ID item = {s->trackid,kAudioTrackType,s->title};
+ m_pCTJukebox2->SetItemAttribute(id,(IUnknown*)&item,L"ARTIST",2,(long)wcslen(value)*2+2,(IUnknown*)value);
+}
+
+void NJBDevice::setTrackAlbum(songid_t songid, const wchar_t * value) {
+ Song * s = (Song *)songid;
+ lstrcpyn(s->album,value,fieldlen);
+ DAPSDK_ID item = {s->trackid,kAudioTrackType,s->title};
+ m_pCTJukebox2->SetItemAttribute(id,(IUnknown*)&item,L"ALBUM",2, (long)wcslen(value)*2+2,(IUnknown*)value);
+}
+
+
+void NJBDevice::setTrackTitle(songid_t songid, const wchar_t * value) {
+ Song * s = (Song *)songid;
+ lstrcpyn(s->title,value,fieldlen);
+ DAPSDK_ID item = {s->trackid,kAudioTrackType,s->title};
+ m_pCTJukebox2->SetItemAttribute(id,(IUnknown*)&item,L"TITLE",2, (long)wcslen(value)*2+2,(IUnknown*)value);
+}
+
+
+void NJBDevice::setTrackGenre(songid_t songid, const wchar_t * value) {
+ Song * s = (Song *)songid;
+ lstrcpyn(s->genre,value,fieldlen);
+ DAPSDK_ID item = {s->trackid,kAudioTrackType,s->title};
+ m_pCTJukebox2->SetItemAttribute(id,(IUnknown*)&item,L"GENRE",2, (long)wcslen(value)*2+2,(IUnknown*)value);
+}
+
+
+void NJBDevice::setTrackTrackNum(songid_t songid, int value) {
+ Song * s = (Song *)songid;
+ s->track = value;
+ DAPSDK_ID item = {s->trackid,kAudioTrackType,s->title};
+ m_pCTJukebox2->SetItemAttribute(id,(IUnknown*)&item,L"TRACK NUM",1,sizeof(short),(IUnknown*)&value);
+}
+
+void NJBDevice::setTrackYear(songid_t songid, int value) {
+ Song * s = (Song *)songid;
+ s->year = value;
+ DAPSDK_ID item = {s->trackid,kAudioTrackType,s->title};
+ m_pCTJukebox2->SetItemAttribute(id,(IUnknown*)&item,L"YEAR",1,sizeof(short),(IUnknown*)&value);
+}
+
+int NJBDevice::copyToHardDrive(songid_t s,wchar_t * path,void * callbackContext,void (*callback)(void * callbackContext, wchar_t * status),int * killswitch) {
+ EnterCriticalSection(&csRevTransfer);
+
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_TRANSFERRING));
+ Song * song = (Song*)s;
+ wcscat(path,L".");
+ wcscat(path,AutoWide(song->codec));
+
+ wchar_t *p = wcsrchr(path,L'.');
+ while(p && *p) { *p = towlower(*p); p++; }
+
+ revTransferItem.callback = callback;
+ revTransferItem.callbackContext = callbackContext;
+ revTransferItem.killswitch = killswitch;
+ revTransferItem.songid = &s;
+ revTransferItem.file = path;
+ revTransferItem.status = 0;
+
+ PostMessage(messageWindow,WM_USER+1,0,0);
+
+ while(revTransferItem.status==0) Sleep(10); // wait for transfer
+
+ int ret = revTransferItem.status==1?0:-1;
+
+ LeaveCriticalSection(&csRevTransfer);
+ return ret;
+}
+
+intptr_t NJBDevice::extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4) {
+ switch(param1) {
+ case DEVICE_SET_ICON:
+ {
+ MLTREEIMAGE * i = (MLTREEIMAGE*)param2;
+ i->hinst = plugin.hDllInstance;
+ i->resourceId = IDR_ZEN_ICON;
+ }
+ break;
+ case DEVICE_SUPPORTED_METADATA:
+ return 0x3ef;
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_njb/NJBDevice.h b/Src/Plugins/Portable/pmp_njb/NJBDevice.h
new file mode 100644
index 00000000..d42b4070
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_njb/NJBDevice.h
@@ -0,0 +1,168 @@
+#ifndef _NJBDEVICE_H_
+#define _NJBDEVICE_H_
+
+#ifndef _UNICODE
+#define _UNICODE
+#endif
+
+#ifndef UNICODE
+#define UNICODE
+#endif
+
+#include <windows.h>
+#include <windowsx.h>
+#include <Objbase.h>
+#include <initguid.h>
+#include <stdio.h>
+#include <shlobj.h>
+#include <wchar.h>
+#include "../Plugins/General/gen_ml/ml.h"
+#include "../Plugins/Library/ml_pmp/pmp.h"
+#include "../Plugins/Library/ml_pmp/transcoder.h"
+#include "../Plugins/General/gen_ml/itemlist.h"
+#include "Nmsdk.h"
+#include "resource.h"
+
+#include "../Agave/Language/api_language.h"
+#include <api/service/waServiceFactory.h>
+
+extern PMPDevicePlugin plugin;
+extern LRESULT CALLBACK CallbackWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+extern C_ItemList devices;
+extern ICTJukebox2 * m_pCTJukebox2;
+
+#define fieldlen 256
+
+class Playlist {
+public:
+ bool dirty;
+ int plid;
+ wchar_t name[fieldlen];
+ C_ItemList songs;
+};
+
+class Song {
+public:
+ char codec[5];
+ int trackid;
+ wchar_t artist[fieldlen];
+ wchar_t album[fieldlen];
+ wchar_t title[fieldlen];
+ wchar_t genre[fieldlen];
+ int year,track,size,length;
+};
+
+class TransferItem {
+public:
+ const itemRecordW * track;
+ void* callbackContext;
+ void (*callback)(void * callbackContext, wchar_t * status);
+ songid_t * songid;
+ int * killswitch;
+ int status;
+ BYTE * meta;
+ wchar_t * file;
+};
+
+class NJBDevice : public Device {
+public:
+ Transcoder * transcoder;
+ BYTE serial[16];
+ __int64 transferQueueLength;
+ DAPSDK_ID playlistRoot;
+ C_ItemList playlists;
+ int id;
+ HWND messageWindow;
+ TransferItem transferItem;
+ TransferItem revTransferItem;
+ CRITICAL_SECTION csTransfer;
+ CRITICAL_SECTION csRevTransfer;
+
+ NJBDevice(long id);
+ virtual ~NJBDevice();
+
+ virtual BOOL WindowMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ virtual __int64 getDeviceCapacityAvailable(); // in bytes
+ virtual __int64 getDeviceCapacityTotal(); // in bytes
+
+ virtual void Eject(); // if you ejected successfully, you MUST call plugin.deviceDisconnected(this) and delete this;
+ virtual void Close(); // save any changes, and call plugin.deviceDisconnected(this) AND delete this;
+
+
+ // return 0 for success, -1 for failed or cancelled
+ virtual int transferTrackToDevice(const itemRecordW * track, // the track to transfer
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
+ songid_t * songid, // fill in the songid when you are finished
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ );
+ virtual int trackAddedToTransferQueue(const itemRecordW * track); // return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
+ virtual void trackRemovedFromTransferQueue(const itemRecordW * track);
+ virtual __int64 getTrackSizeOnDevice(const itemRecordW * track); // return the amount of space taken up on the device by the track, or 0 for incompatable (usually the filesize, unless you are transcoding)
+
+ virtual void deleteTrack(songid_t songid); // physically remove from device. Be sure to remove it from all the playlists!
+
+ virtual void commitChanges(); // optional. Will be called at a good time to save changes
+
+ virtual int getPlaylistCount(); // always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
+ // PlaylistName(0) should return the name of the device.
+ virtual void getPlaylistName(int playlistnumber, wchar_t * buf, int len);
+ virtual int getPlaylistLength(int playlistnumber);
+ virtual songid_t getPlaylistTrack(int playlistnumber,int songnum); // returns a songid
+
+ virtual void setPlaylistName(int playlistnumber, const wchar_t * buf); // with playlistnumber={}, set the name of the device.
+ virtual void playlistSwapItems(int playlistnumber, int posA, int posB); // swap the songs at position posA and posB
+ virtual void sortPlaylist(int playlistnumber, int sortBy); // only implement if you are a non-cached device!!!
+ virtual void addTrackToPlaylist(int playlistnumber, songid_t songid); // adds songid to the end of the playlist
+ virtual void removeTrackFromPlaylist(int playlistnumber, int songnum); //where songnum is the position of the track in the playlist
+
+ virtual void deletePlaylist(int playlistnumber);
+ virtual int newPlaylist(const wchar_t * name); // create empty playlist, returns playlistnumber
+
+ virtual void getTrackArtist(songid_t songid, wchar_t * buf, int len);
+ virtual void getTrackAlbum(songid_t songid, wchar_t * buf, int len);
+ virtual void getTrackTitle(songid_t songid, wchar_t * buf, int len);
+ virtual int getTrackTrackNum(songid_t songid);
+ virtual int getTrackDiscNum(songid_t songid);
+ virtual void getTrackGenre(songid_t songid, wchar_t * buf, int len);
+ virtual int getTrackYear(songid_t songid);
+ virtual __int64 getTrackSize(songid_t songid); // in bytes
+ virtual int getTrackLength(songid_t songid); // in millisecs
+ virtual int getTrackBitrate(songid_t songid); // in kbps
+ virtual int getTrackPlayCount(songid_t songid);
+ virtual int getTrackRating(songid_t songid); //0-5
+ virtual __time64_t getTrackLastPlayed(songid_t songid); // in unix time format
+ virtual __time64_t getTrackLastUpdated(songid_t songid); // in unix time format
+ virtual void getTrackExtraInfo(songid_t songid, const wchar_t * field, wchar_t * buf, int len); //optional
+
+ // feel free to ignore any you don't support
+ virtual void setTrackArtist(songid_t songid, const wchar_t * value);
+ virtual void setTrackAlbum(songid_t songid, const wchar_t * value);
+ virtual void setTrackTitle(songid_t songid, const wchar_t * value);
+ virtual void setTrackTrackNum(songid_t songid, int value);
+ virtual void setTrackDiscNum(songid_t songid, int value){};
+ virtual void setTrackGenre(songid_t songid, const wchar_t * value);
+ virtual void setTrackYear(songid_t songid, int year);
+ virtual void setTrackPlayCount(songid_t songid, int value){};
+ virtual void setTrackRating(songid_t songid, int value){};
+ virtual void setTrackLastPlayed(songid_t songid, __time64_t value){}; // in unix time format
+ virtual void setTrackLastUpdated(songid_t songid, __time64_t value){}; // in unix time format
+ virtual void setTrackExtraInfo(songid_t songid, const wchar_t * field, const wchar_t * value) {}; //optional
+
+ virtual bool playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue){return false;}; // return false if unsupported
+
+ virtual intptr_t extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4);
+
+ virtual bool copyToHardDriveSupported() {return true;} // for now...
+
+ virtual __int64 songSizeOnHardDrive(songid_t song) {return getTrackSize(song);} // how big a song will be when copied back. Return -1 for not supported.
+
+ virtual int copyToHardDrive(songid_t song, // the song to copy
+ wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ ); // -1 for failed/not supported. 0 for success.
+};
+
+#endif //_NJBDEVICE_H_ \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_njb/NOMAD DAP PC SDK v3_5.pdf b/Src/Plugins/Portable/pmp_njb/NOMAD DAP PC SDK v3_5.pdf
new file mode 100644
index 00000000..b044b758
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_njb/NOMAD DAP PC SDK v3_5.pdf
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_njb/Nmsdk.h b/Src/Plugins/Portable/pmp_njb/Nmsdk.h
new file mode 100644
index 00000000..892e04bb
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_njb/Nmsdk.h
@@ -0,0 +1,922 @@
+/////////////////////////////////////////////////////////////////////////////////////
+//
+// File: nmsdk.h
+//
+// Purpose: Combination of the Jukebox SDK2 header file and the NomadII SDK2 header file.
+//
+// Notes: Please make sure to include the COM Stuffs <Objbase.h> and <initguid.h>
+// at the beginning of the application programs. Otherwise, it will get Link Errors.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+// PARTICULAR PURPOSE.
+//
+// Copyright (c) Creative Technology Ltd., 2001. All rights reserved.
+//
+/////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+// nmsdk.h : main header file for export
+// Version: 1.0.7.0
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef __nmsdk_h__
+#define __nmsdk_h__
+
+//
+// COM Interface Declaration
+//
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+
+//////////////////////////////////////////////////////////////////////////
+// Class ID //
+//////////////////////////////////////////////////////////////////////////
+//CLSID CLSID_CTJukeBox2:
+// {BD1A6357-3E9B-4f1b-8375-AEE989ED6C5E}
+DEFINE_GUID(CLSID_CTJukeBox2,
+0xbd1a6357, 0x3e9b, 0x4f1b, 0x83, 0x75, 0xae, 0xe9, 0x89, 0xed, 0x6c, 0x5e);
+
+//CLSID CLSID_CTNOMAD2:
+// {0EBE3156-FD3A-4f5c-ABDB-71E3BEEAD091}
+DEFINE_GUID(CLSID_CTNOMAD2,
+0xebe3156, 0xfd3a, 0x4f5c, 0xab, 0xdb, 0x71, 0xe3, 0xbe, 0xea, 0xd0, 0x91);
+
+
+//////////////////////////////////////////////////////////////////////////
+// return codes //
+//////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////
+// JukeBox & NomadII shared stuffs //
+//////////////////////////////////////////////////////
+// Additional Error codes
+#define DAPSDK_SUCCESS 0x00
+// General Error
+#define DAPSDK_FAILED 0x01
+#define DAPSDK_E_DEVICE_BUSY 0x02
+#define DAPSDK_E_STORAGE_FULL 0x03
+#define DAPSDK_E_SETTIME_REJECTED 0x05
+#define DAPSDK_E_ITEM_SIZE_MISSING 0x14 //NMJB_E_TRACK_SIZE_MISSING
+#define DAPSDK_E_ITEM_UPLOAD_DENIED 0x18 //NMJB_E_TRACK_UPLOAD_DENIED
+#define DAPSDK_E_PLAYER_NOT_CONNECTED 0x80
+#define DAPSDK_E_CANCELLED 0x81
+#define DAPSDK_E_PORT_UNAVAILABLE 0x82
+#define DAPSDK_E_OUT_OF_MEMORY 0x83
+#define DAPSDK_E_FILEOPEN_ERR 0x84
+#define DAPSDK_E_ITEM_NOT_FOUND 0x85
+#define DAPSDK_E_LOAD_COMPONENTS_FAILED 0x86
+#define DAPSDK_E_ID_INVALID 0x87
+#define DAPSDK_E_FILETYPE_ILLEGAL 0x88
+#define DAPSDK_E_LOADRES_FAIL 0x89
+#define DAPSDK_E_FORMAT_NOT_FOUND 0x8a
+#define DAPSDK_E_FILE_ALREADY_EXISTS 0x8b
+#define DAPSDK_E_LIB_CORRUPTED 0x8c
+#define DAPSDK_E_LIB_BUSY 0x8d
+#define DAPSDK_E_FILE_READ_WRITE_FAILED 0x8e //NMJB_E_FILE_WRITE_FAILED
+#define DAPSDK_E_INVALID_FILEPATH 0x8f
+#define DAPSDK_E_UNSUPPORTED 0x91
+#define DAPSDK_E_NORIGHTS 0x95
+#define DAPSDK_E_UNDEFINED_ERR 0xff
+
+
+//////////////////////////////////////////////////////
+// NomadII stuffs //
+//////////////////////////////////////////////////////
+#define DAPSDK_E_SMARTMEDIA_WRITE_PROTECTED 0x98
+#define DAPSDK_E_NO_STORAGE 0x99 //No internal media or smart media
+
+//////////////////////////////////////////////////////
+// JukeBox stuffs //
+//////////////////////////////////////////////////////
+// General Error
+#define DAPSDK_E_HD_GENERAL_ERROR 0x04
+// Track Management Error
+#define DAPSDK_E_TRACK_NOT_FOUND 0x10
+#define DAPSDK_E_TRACK_ALREADY_EXIST 0x11
+#define DAPSDK_E_TRACK_TITLE_MISSING 0x12
+#define DAPSDK_E_TRACK_CODEC_MISSING 0x13
+#define DAPSDK_E_TRACK_IO_OPERATION_ABORTED 0x15
+#define DAPSDK_E_TRACK_READ_WRITE_ERROR 0x16
+#define DAPSDK_E_TRACK_NOT_OPENED 0x17
+// Playlist Error
+#define DAPSDK_E_PL_NOT_FOUND 0x20
+#define DAPSDK_E_PL_ALREADY_EXIST 0x21
+#define DAPSDK_E_PL_ITEM_NOT_FOUND 0x22
+#define DAPSDK_E_PL_ITEM_ALREADY_EXIST 0x23
+//Additional
+#define DAPSDK_E_DISKFULL_FOR_DOWNLOAD 0x90
+
+
+#define DAPSDK_E_STATUS_TIMEOUT 0x06
+
+// Transport Control Error
+#define DAPSDK_E_END_OF_TRACK 0x30
+#define DAPSDK_E_END_OF_LIST 0x31
+#define DAPSDK_E_CODEC_NOT_SUPPORTED 0x32
+#define DAPSDK_E_DATA_CORRUPTED 0x33
+#define DAPSDK_E_SAMPLING_RATE_NOT_SUPPORTED 0x34
+#define DAPSDK_E_DECODING_ERROR 0x35
+#define DAPSDK_E_POSITION_OUTOF_RANGE 0x36
+#define DAPSDK_E_NOT_STOPPED 0x37
+
+// Audio Control Error
+#define DAPSDK_E_UNKNOW_PROPERTY 0x40
+#define DAPSDK_E_VALUE_OUTOF_RANGE 0x41
+
+// USB Transaction Error
+#define DAPSDK_E_DATA_FILE_NOT_FOUND 0x60
+#define DAPSDK_E_DATA_FILE_TOO_BIG 0x61
+#define DAPSDK_E_DATA_FILE_ALREADY_EXIST 0x62
+#define DAPSDK_E_TOO_MANY_DATA_FILES 0x63
+
+//additional
+#define DAPSDK_E_WMDM_INIT_FAILED 0x92
+#define DAPSDK_E_INVALID_ARGUMENT 0x93
+#define DAPSDK_E_PARENTNODE_NOT_EXIST 0x94
+#define DAPSDK_E_NORIGHTS 0x95
+#define DAPSDK_E_PATH_EXCESS_LEN 0x96
+#define DAPSDK_E_LOAD_PROC_FAILED 0x97
+
+// New Error code for MultiApplication assess of Nomad Jukebox 2/3/Zen
+#define DAPSDK_E_PMSMAN_CREATEDIRECTORY_FAILED 0x0100
+#define DAPSDK_E_DEVICE_WRITE_FAILED 0x0200
+#define DAPSDK_E_DEVICE_READ_FAILED 0x0300
+#define DAPSDK_E_DB_INVALID_REQUEST_ID 0x0400
+#define DAPSDK_E_DB_INVALID_NODE_ID 0x0500
+#define DAPSDK_E_DWNTHRD_CREATEMETADATA_FAILED 0x0600
+#define DAPSDK_E_DEVINFO_INVALID_INDEX 0x0700
+#define DAPSDK_E_INVALID_DEVICESETTINGTYPE 0x0800
+#define DAPSDK_E_FILESIZE_TOO_BIG 0x0900
+#define DAPSDK_E_AUDIOFILE_FORMAT 0x0A00
+#define DAPSDK_E_AUDIOFILE_INVALID 0x0B00
+#define DAPSDK_E_ACCESS_DENIED 0x0C00
+#define DAPSDK_E_FILE_NOT_FOUND 0x0D00
+#define DAPSDK_E_EOF 0x0E00
+#define DAPSDK_E_COOKIE 0x0F00
+#define DAPSDK_E_PLAYBACK_INPROGRESS 0x1000
+#define DAPSDK_E_TRANSFER_INPROGRESS 0x1100
+#define DAPSDK_E_BUFFER_NOT_ENOUGH 0x1200
+
+// New Error code for Data Folder of Nomad Jukebox 2/3/Zen
+#define DAPSDK_E_NOT_A_FOLDER 0x1400 // the target file is not a folder
+#define DAPSDK_E_FOLDER_NOT_EMPTY 0x1600 // the target folder is not empty
+#define DAPSDK_E_FOLDER_EXIST 0x1700 // the target folder exist
+#define DAPSDK_E_FOLDER_NOTEXIST 0x1800 // the target folder does not exist
+#define DAPSDK_E_PARENTFOLDER_NOTEXIST 0x1900 // the target parent folder does not exist
+#define DAPSDK_E_FILEPATH_TOOLONG 0x1A00 // the target file path is too long
+#define DAPSDK_E_FILENAME_TOOLONG 0x1B00 // the target file name is too long
+#define DAPSDK_E_INVALID_OPERATION 0x1E00 // the operation cannot be perform
+
+
+//////////////////////////////////////////////////////////////////////////
+// Definitions for WM Messages //
+//////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////
+// JukeBox & NomadII shared stuffs //
+//////////////////////////////////////////////////////
+// Download message
+#define WM_DAPSDK_DOWNLOAD_PROGRESS WM_USER+500
+#define WM_DAPSDK_DOWNLOAD_COMPLETE WM_USER+501
+
+// Upload message
+#define WM_DAPSDK_GETITEM_PROGRESS WM_USER+502
+#define WM_DAPSDK_GETITEM_COMPLETE WM_USER+503
+
+//////////////////////////////////////////////////////
+// JukeBox stuffs //
+//////////////////////////////////////////////////////
+// Device change message
+#define WM_DAPSDK_JUKEBOX_REMOVAL WM_USER+508
+#define WM_DAPSDK_JUKEBOX_ARRIVAL WM_USER+509
+// Playback message
+#define WM_DAPSDK_PLAYBACK_COMPLETE WM_USER+504
+#define WM_DAPSDK_PLAYLIST_COMPLETE WM_USER+505
+#define WM_DAPSDK_PLAYBACK_ERROR WM_USER+506
+#define WM_DAPSDK_PLAYBACK_PROGRESS WM_USER+507
+
+
+// New callback messages for MultiApplication assess of Hotcake
+// Notification Messages for database change
+#define WM_DAPSDK_CHANGE_BASE WM_USER + 200
+#define WM_DAPSDK_MUSIC_ADD_FILE WM_DAPSDK_CHANGE_BASE + 0 // wParam = NodeId added, lParam = nil
+#define WM_DAPSDK_MUSIC_DEL_FILE WM_DAPSDK_CHANGE_BASE + 1 // wParam = NodeId deleted, lParam = nil
+#define WM_DAPSDK_MUSIC_SETATTR_FILE WM_DAPSDK_CHANGE_BASE + 2 // wParam = NodeId edited, lParam = nil
+#define WM_DAPSDK_DATA_ADD_FILE WM_DAPSDK_CHANGE_BASE + 3 // wParam = NodeId added, lParam = nil
+#define WM_DAPSDK_DATA_DEL_FILE WM_DAPSDK_CHANGE_BASE + 4 // wParam = NodeId deleted, lParam = nil
+#define WM_DAPSDK_DATA_SETATTR_FILE WM_DAPSDK_CHANGE_BASE + 5 // wParam = NodeId edited, lParam = nil
+#define WM_DAPSDK_PLAYLIST_ADD_FILE WM_DAPSDK_CHANGE_BASE + 6 // wParam = NodeId added, lParam = nil
+#define WM_DAPSDK_PLAYLIST_DEL_FILE WM_DAPSDK_CHANGE_BASE + 7 // wParam = NodeId deleted, lParam = nil
+#define WM_DAPSDK_PLAYLIST_SETATTR_FILE WM_DAPSDK_CHANGE_BASE + 8 // wParam = NodeId edited, lParam = nil
+#define WM_DAPSDK_PLAYLIST_ITEM_CHANGE WM_DAPSDK_CHANGE_BASE + 9 // wParam = PlaylistNodeId affected, lParam = nil
+#define WM_DAPSDK_STORAGEINFO_CHANGE WM_DAPSDK_CHANGE_BASE + 10 // wParam = deviceIndex that change occurred, lParam = nil
+
+
+#define WM_DAPSDK_ADDITEM_PROGRESS WM_USER+500
+#define WM_DAPSDK_ADDITEM_COMPLETE WM_USER+501
+
+
+/////////////////////////////////////////////////////////////////////////
+// struct defines //
+//////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////
+// JukeBox & NomadII shared stuffs //
+//////////////////////////////////////////////////////
+typedef struct _DAPSDK_DATE_TIME
+{
+ short Year, Month, Day, DayOfWeek;
+ short Hour, Min, Sec, MilliSec;
+} DATE_TIME, *PDATE_TIME;
+
+typedef struct _DAPSDK_FORMAT_INFO
+{
+ long lCodecID;
+ UCHAR szCodecName[128];
+ long lSamplingRate;
+ long lNumChannel;
+} FORMAT_INFO, *PFORMAT_INFO;
+
+//-- SDK and firmware version info structure --//
+//
+// used in GetSDKVersion()
+// used in GetDeviceProperties( kFirmwareVersion, kHardwareVersion)
+typedef struct _DAPSDK_VERSION
+{
+ WORD major;
+ WORD minor;
+ WORD build;
+ WORD specialBuild;
+} DAPSDK_VERSION, *PDAPSDK_VERSION;
+
+//-- Memory Storage Information Structure --//
+typedef struct _DAPSDK_STORAGE_INFO
+{
+ ULONG totalH;
+ ULONG totalL;
+ ULONG freeH;
+ ULONG freeL;
+} DAPSDK_STORAGE_INFO, *PDAPSDK_STORAGE_INFO;
+
+//-- Identification structure --//
+// same for RootItem, ParentItem and Item now //
+typedef struct _DAPSDK_ID
+{
+ long lID; // stores the unique ID
+ long lType; // stores the type (see enum above)
+ BSTR bstrName; // stores the name
+} DAPSDK_ID, *PDAPSDK_ID;
+
+//////////////////////////////////////////////////////
+// NomadII stuffs //
+//////////////////////////////////////////////////////
+typedef struct _DAPSDK_RADIOPRESET
+{
+ DWORD dwPresetIndex;
+ DWORD dwPresetValue;
+} RADIOPRESET, *PRADIOPRESET;
+
+
+// device info struct
+typedef struct _DAPSDK_DEVICE_INFO
+{
+ BYTE cDeviceId[16]; // player's ID
+ long dwFirmwareVersion; // player's firmware version
+ long dwHardwareVersion; // player's hardware version
+ char cDeviceName[32]; // player's name w/o NULL terminator
+ BYTE byPowerSource; // player's power source status in percent
+} DAPSDK_DEVICE_INFO, *PDAPSDK_DEVICE_INFO;
+
+enum
+{
+ kASCII = 0,
+ kBINARY,
+ kUNICODE,
+};
+
+//////////////////////////////////////////////////////
+// Item type for Jukebox (used by lRootItemType, //
+// lParentItemType, lItemType parameter) //
+//////////////////////////////////////////////////////
+enum
+{
+ kAudioTrackType = 1, // this is a audio track
+ kPlaylistType, // this is a track in the playlist
+ kDataFileType, // this is a data file
+ kDataFolderType, // this is a data file folder
+};
+
+/////////////////////////////////////////////////////////
+// Item type for NomadII (used in lItemType parameter) //
+/////////////////////////////////////////////////////////
+enum
+{
+ kInternalMemType = 0, // this item resides in internal memory
+ kExternalMemType, // this item resides in external (removeable) media
+};
+
+
+// Device Property Type Constant
+//-- Device Property type (used by lDevicePropertyType parameter in --//
+// GetDeviceProperties/SetDeviceProperties --//
+enum
+{
+//////////////////////////////////////////////////////
+// JukeBox & NomadII shared stuffs //
+//////////////////////////////////////////////////////
+ kDeviceSerialNumberValue = 1, // GET, <NOMAD II>given the Item type
+ // in "lpValue" parameter, the return value
+ // is a pointer to the serial number
+ // of the specified media.
+ kFirmwareVersion, // GET, return value is a pointer to
+ // DAPSDK_VERSION structure indicating the
+ // current firmware version in the device.
+ kDeviceNameString, // GET, return value is a pointer to
+ // BSTR string.
+ kPowerSourceValue,
+ kStorageInfoStruct, // GET, return value is a pointer to
+ // DAPSDK_STORAGE_INFO structure indicating
+ // the current memory usage.
+ kDateTimeStruct, // GET/SET, return/set value is a pointer to
+ // DATE_TIME structure (defined in SDK 1.0)
+ kOwnerNameString, // GET/SET, return/set value is a pointer to BSTR
+ // string.
+ kAudioFormatCount, // GET, return value is a pointer to the number of
+ // audio format supported by device.
+ kAudioFormatInfoStruct, // GET, given the index value in "lpValue"
+ // parameter, the return value is a pointer to
+ // FORMATINFO structure (defined in SDK 1.0).
+ kLangEncodeSupport, // GET, returns unsigned long value
+ // 0x01 == Latin 1(CP1252), 0x80000000 == UNICODE
+
+//////////////////////////////////////////////////////
+// JukeBox stuffs //
+//////////////////////////////////////////////////////
+ kHardwareVersion, // GET, return value is a pointer to
+ // DAPSDK_VERSION structure indicating the
+ // current hardware version in the device.
+ kAudioVolumeValue, // GET/SET, return/set value is the pointer to the
+ // volume level in percentage.
+ kAudioMuteValue, // GET/SET, return/set value is the pointer to the
+ // Mute status (1=on, 0=off).
+ // Treble level in percentage.
+ kEAXCount, // GET, return value is the pointer to the number
+ // of EAX settings.
+ kEAXNameString, // GET, given the index value in "lpValue"
+ // parameter, the return value is a pointer to
+ // a BSTR string.
+ kEAXAmountValue, // GET/SET, given the index value in "lpValue"
+ // parameter, the return value is the effect
+ // amount in percentage.
+ kEAXCurrentIndex, // GET/SET, the value in "lpValue" is used to set
+ // or retrieve the current EAX selection.
+ kAudioEQPresetCount, // GET, return value is the pointer to the number
+ // of EQ settings.
+ kAudioEQNameString, // GET, given the index value in "lpValue"
+ // parameter, the return value is a pointer to
+ // a BSTR string.
+ kAudioEQAmountValue, // GET/SET, return/set value is the pointer to the
+ // EQ amount in percentage.
+ kAudioEQCurrentIndex, // GET/SET, the value in "lpValue" is used to set
+ // or retrieve the current EQ selection.
+
+//////////////////////////////////////////////////////
+// NomadII stuffs //
+//////////////////////////////////////////////////////
+ kFMRadioPresetCount, // GET, returns pointer to number of FM radio
+ // presets available in the player.
+ kFMRadioPresetValue, // GET/SET, given the preset index value,
+ // returns an existing value or sets a new
+ // preset FM preset. Value in kHz.
+ kFormatStorage // SET, Do format storage.
+};
+//Note that all index value is zero-based. Client should call the "kxxxxxxCount" property first before trying to get the value for individual settings in list-type of properties, i.e. kEAXNameString, kAudioFormatInfoStruct...
+//Not all properties are readable and writable, some are read-only attributes. Those properties that are read-only are marked with the "GET" strings and those that are read and writable are marked as "GET/SET". Client should not call SetDeviceProperties() with the read-only property type, such call would fail.
+//New Property types maybe supported in future by simply adding into the enum list, and publish to developers.
+
+
+//////////////////////////////////////////////////////
+// JukeBox stuffs //
+//////////////////////////////////////////////////////
+//-- Playback operation type (used by lPlayOperationType parameter in --//
+//-- PlayControl() & QueueControl()) --//
+enum
+{
+ kPlayTrack = 1, // lpValue stores the pointer to the
+ // DAPSDK_ITEM_ID structure.
+ kStopTrack, // lpValue is not used, stop current track, no op
+ // if no track is currently playing.
+ kPauseTrack, // lpValue is not used, pause current track, no op
+ // if no track is currently playing.
+ kSetPlaybackPosition, // lpValue stores the pointer to the new playback
+ // position.
+ kQueueTrack, // lpValue stores the pointer to the
+ // DAPSDK_ITEM_ID structure.
+ kClearQueue, // lpValue is not used, clear existing queue.
+};
+
+#define TITLE "TITLE"
+#define FILESIZE "FILE SIZE"
+#define CODEC "CODEC"
+#define ALBUM "ALBUM"
+#define ARTIST "ARTIST"
+#define GENRE "GENRE"
+#define LENGTH "LENGTH"
+#define TRACKNUM "TRACK NUM"
+#define YEAR "YEAR"
+#define PLAYONLY "PLAYONLY"
+#define TRACKID "TRACK ID"
+
+// new attribute for datafile and datafolder
+#define MOD_FILETIME "MODIFIED FILETIME"
+#define FILE_ATTRIB "FILE ATTRIB"
+#define PARENT_FOLDER "PARENT FOLDER"
+#define FOLDERNAME "FOLDER NAME" // data folder name for Nomad Jukebox
+#define MULTI_ATTRIB "MULTI ATTRIB" // this is for user to change multiple file attribute at one time.
+
+#define FILENAME "FILE NAME" // file name for Nomad II, data file name for Nomad Jukebox
+
+#define ALLTRACKSKEY -1
+
+//////////////////////////////////////////////////////
+// NomadII stuffs //
+//////////////////////////////////////////////////////
+#define DOS_FILEATTRIB "DOS_FILEATTRIB"
+#define DOS_DATETIME "DOS_DATETIME"
+
+
+//////////////////////////////////////////////////////////////////////////
+// ICTJukebox (Interface 1) Methods //
+//////////////////////////////////////////////////////////////////////////
+
+// {DFC9207F-4B64-11D4-A4ED-00A0C98E46CC}
+DEFINE_GUID(IID_ICTJukebox,
+0xdfc9207f, 0x4b64, 0x11d4, 0xa4, 0xed, 0x00, 0xa0, 0xc9, 0x8e, 0x46, 0xcc);
+
+interface ICTJukebox : public IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE CancelTransfer(
+ /*[in]*/long lDeviceID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RenamePlaylist(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long lPlaylistID,
+ /*[in]*/BSTR bstrName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RemoveTracksFromPlaylist(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long lTrackCount,
+ /*[in]*/long* lpTrackList,
+ /*[in]*/long lPlaylist) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AddTracksToPlaylist(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long lTrackCount,
+ /*[in]*/long* lpTrackList,
+ /*[in]*/long lPlaylist) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE InsertPlaylist(
+ /*[in]*/long lDeviceID,
+ /*[in]*/BSTR bstrPlaylistName,
+ /*[out]*/long* lpPlaylistID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeletePlaylist(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long lPlaylistID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindNextTrackInPlaylist(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long lPlaylistID,
+ /*[out]*/long* lpTrackID,
+ /*[out]*/BSTR* lpbstrTrackName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindFirstTrackInPlaylist(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long lPlaylistID,
+ /*[out]*/long* lpTrackID,
+ /*[out]*/BSTR* lpbstrTrackName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindNextPlaylist(
+ /*[in]*/long lDeviceID,
+ /*[out]*/long* lpPlaylistID,
+ /*[out]*/BSTR* lpbstrPlaylistName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindFirstPlaylist(
+ /*[in]*/long lDeviceID,
+ /*[out]*/long* lpPlaylistID,
+ /*[out]*/BSTR* lpbstrPlaylistName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ChangeTrackInfo(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long lTarckID,
+ /*[in]*/long lSize,
+ /*[in]*/IUnknown* lpTrackInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeleteTrack(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long lTrackID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE InsertTrack(
+ /*[in]*/long lDeviceID,
+ /*[in]*/BSTR bstrFilePath,
+ /*[in]*/long lSize,
+ /*[in]*/IUnknown* lpTrackInfo,
+ /*[out]*/long* lpTrackID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTrackInfo(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long lTrackID,
+ /*[in]*/long lInSize,
+ /*[out]*/long* lpOutSize,
+ /*[out]*/IUnknown* lpTrackInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindNextTrack(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long lKeyID,
+ /*[out]*/long* lpTrackID,
+ /*[out]*/BSTR* lpbstrName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindFirstTrack(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long lKeyID,
+ /*[out]*/long* lpTrackID,
+ /*[out]*/BSTR* lpbstrName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindNextKey(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long lRootKeyID,
+ /*[out]*/long* lpKeyID,
+ /*[out]*/BSTR* lpbstrName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindFirstKey(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long lRootKeyID,
+ /*[out]*/long* lpKeyID,
+ /*[out]*/BSTR* lpbstrName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindNextRootKey(
+ /*[in]*/long lDeviceID,
+ /*[out]*/long* lpRootKeyID,
+ /*[out]*/BSTR* lpbstrName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindFirstRootKey(
+ /*[in]*/long lDeviceID,
+ /*[out]*/long* lpRootKeyID,
+ /*[out]*/BSTR* lpbstrName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetOwnerName(
+ /*[in]*/long lDeviceID,
+ /*[in]*/BSTR bstrName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOwnerName(
+ /*[in]*/long lDeviceID,
+ /*[out]*/BSTR* lpbstrName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetDateTime(
+ /*[in]*/long lDeviceID,
+ /*[out]*/IUnknown* lpDateTime) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDateTime(
+ /*[in]*/long lDeviceID,
+ /*[out]*/IUnknown* lpDateTime) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindNextFormatSupport(
+ /*[in]*/long lDeviceID,
+ /*[out]*/IUnknown* lpFormatInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindFirstFormatSupport(
+ /*[in]*/long lDeviceID,
+ /*[out]*/IUnknown* lpFormatInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStorageInfo(
+ /*[in]*/long lDeviceID,
+ /*[out]*/unsigned long* lpTotalMemHigh,
+ /*[out]*/unsigned long* lpTotalMemLow,
+ /*[out]*/unsigned long* lpFreeMemHigh,
+ /*[out]*/unsigned long* lpFreeMemLow ) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceInfo(
+ /*[in]*/long lDeviceID,
+ /*[out]*/IUnknown* lpDeviceInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceCount(
+ /*[out]*/long* lpDeviceCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCallbackWindow(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long hWnd) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSDKVersion(
+ /*[out]*/long* lpVersion) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ShutDown() = 0;
+ virtual HRESULT STDMETHODCALLTYPE Initialize() = 0;
+
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// ICTJukebox2 (Interface 2) Methods //
+//////////////////////////////////////////////////////////////////////////
+
+DEFINE_GUID(IID_ICTJukebox2,
+0xdfc92080, 0x4b64, 0x11d4, 0xa4, 0xed, 0x00, 0xa0, 0xc9, 0x8e, 0x46, 0xcc);
+
+interface ICTJukebox2 : public IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE Initialize2() = 0;
+ virtual HRESULT STDMETHODCALLTYPE ShutDown2() = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetCallbackWindow2(
+ long lDeviceID,
+ long hWnd ) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceCount2(
+ long* lpDeviceCount ) = 0;
+
+ //-- Canceling I/O --//
+ virtual HRESULT STDMETHODCALLTYPE CancelTransfer2(
+ long lDeviceID ) = 0;
+
+
+ //-- GetSDKVersion2() Fucntion Descriptions --//
+ // This function overides the same function in interface 1, this is to
+ // return a more meaningful version information to the client which is
+ // clearly specified in the DAPSDK_VERSION structure
+ virtual HRESULT STDMETHODCALLTYPE GetSDKVersion2(
+ IUnknown* lpSDKVersion ) = 0;
+
+
+ //_______________________ Querying RootItem __________________________//
+
+ virtual HRESULT STDMETHODCALLTYPE FindFirstRootItem (
+ long lDeviceID,
+ IUnknown* lpRootItemID ) = 0;
+ virtual HRESULT STDMETHODCALLTYPE FindNextRootItem (
+ long lDeviceID,
+ IUnknown* lpRootItemID ) = 0;
+
+ //______________________ Querying ParentItem __________________________//
+
+ virtual HRESULT STDMETHODCALLTYPE FindFirstParentItem (
+ long lDeviceID,
+ IUnknown* lRootItemID,
+ IUnknown* lpParentItemID ) = 0;
+ virtual HRESULT STDMETHODCALLTYPE FindNextParentItem (
+ long lDeviceID,
+ IUnknown* lRootItemID,
+ IUnknown* lpParentItemID ) = 0;
+
+
+ //______________________ ParentItem Management __________________________ //
+
+ //-- AddParentItem() Fucntion Descriptions --//
+ // Client can only add Parent Item of the same type as the RootItem. For
+ // example, client cannot add a kDataFileType Parent item into a RootItem
+ // type of kAudioTrackType.
+ //
+ // As of current firmware implementation, client can only add ParentItem
+ // into a RootItem that has a type of kPlaylistType. Adding ParentItem into
+ // other RootItem type will fail.
+ virtual HRESULT STDMETHODCALLTYPE AddParentItem (
+ long lDeviceID,
+ IUnknown* lRootItemID,
+ IUnknown* lParentItemID ) = 0;
+
+ //-- DeleteParentItem() Function Description --//
+ // Client can only delete ParentItem of type kPlaylistType. Deleting other
+ // ParentItem type will fail.
+ virtual HRESULT STDMETHODCALLTYPE DeleteParentItem (
+ long lDeviceID,
+ IUnknown* lParentItemID ) = 0;
+
+ //-- RenameParentItem() Function Description --//
+ // Client can only rename ParentItem of type kPlaylistType. Renaming other
+ // ParentItem type will fail.
+ //
+ // The updated DAPSDK_PARENTITEM_ID structure is returned in lParentItemID
+ // parameter.
+ virtual HRESULT STDMETHODCALLTYPE RenameParentItem (
+ long lDeviceID,
+ IUnknown* lParentItemID,
+ BSTR bstrNewParentItemName ) = 0;
+
+
+ //__________________________ Querying Item ______________________________//
+
+ virtual HRESULT STDMETHODCALLTYPE FindFirstItem (
+ long lDeviceID,
+ IUnknown* lParentItemID,
+ IUnknown* lpItemID ) = 0;
+ virtual HRESULT STDMETHODCALLTYPE FindNextItem (
+ long lDeviceID,
+ IUnknown* lParentItemID,
+ IUnknown* lpItemID ) = 0;
+
+
+ //_____________________ Getting Item Attributes __________________________//
+
+ //-- GetItemAttribute() Function Description --//
+ // This function returns the TrackInfo data for all Item type. But for
+ // kDataFileType and kPlaylistFileType, the TrackInfo data contain only
+ // file name, file type and file size. In contrast, the item attribute
+ // for a kAudioTrackType may contain all information similar to the ID3tag
+ // information that a typical MP3 file has.
+ virtual HRESULT STDMETHODCALLTYPE GetItemAttribute (
+ long lDeviceID,
+ IUnknown* lpItemID,
+ long lInItemInfoSize,
+ long* lOutItemInfoSize,
+ IUnknown* lpItemInfo ) = 0;
+
+
+ //-- SetItemAttribute() Function Description --//
+ // This function allows client to set TrackInfo attributes of a
+ // kAudioTrackItem only. Setting other item type will fail.
+ //
+ // It allows client to set a particular attribute data according to the name
+ // and type given in the parameters. Note that only one attribute can be set
+ // at a time.
+ virtual HRESULT STDMETHODCALLTYPE SetItemAttribute (
+ long lDeviceID,
+ IUnknown* lpItemID,
+ BSTR bstrAttributeName,
+ long lAttributeType,
+ long lAttributeDataSize,
+ IUnknown* lpAttributeData ) = 0;
+
+
+ //____________________________ Item Management ___________________________//
+
+ //-- AddItem() Function Description --//
+ // This function initiates the file download from the computer to the
+ // device. Client should call this function to download audio tracks
+ // like MP3, WMA and WAVE and data files. Client are not allow
+ // to download an item of kPlaylistType, use AddItemsToParentItem to add
+ // item of type kPlaylistType.
+ virtual HRESULT STDMETHODCALLTYPE AddItem (
+ long lDeviceID,
+ long lItemType,
+ BSTR bstrSrcFileName,
+ long lItemInfoSize,
+ IUnknown* lpItemInfo) = 0;
+
+ //-- AddItemsToParentItem() Function Description --//
+ // Client call this function to add kAudioTrackType item into the ParentItem
+ // of type kPlaylistType. Only kAudioTrackType items are accepted, and only
+ // ParentItem of type kPlaylistType can accept such addition.
+ virtual HRESULT STDMETHODCALLTYPE AddItemsToParentItem(
+ long lDeviceID,
+ IUnknown* lpParentItemID,
+ long lItemIDCount,
+ IUnknown* lpItemIDList ) = 0;
+
+ //-- DeleteItem() Function Description --//
+ // Client can call this function to remove item of type kAudioTrackType and
+ // kDataFileType. You cannot remove kPlaylistType item here.
+ virtual HRESULT STDMETHODCALLTYPE DeleteItem (
+ long lDeviceID,
+ IUnknown* lpItemID ) = 0;
+
+ //-- GetItem() Function Description --//
+ // Client can call this function to retrieve item that are kAudioTrackType
+ // and kDataFileType from the device to the computer. Note that client
+ // cannot retrieve item of type kPlaylistItem
+ virtual HRESULT STDMETHODCALLTYPE GetItem (
+ long lDeviceID,
+ BSTR bstrDestinationFileName,
+ IUnknown* lpItemID ) = 0;
+
+
+ //________________________ Device Properties ____________________________//
+
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceProperties (
+ long lDeviceID,
+ long lDevicePropertyType,
+ IUnknown* lpValue ) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetDeviceProperties (
+ long lDeviceID,
+ long lDevicePropertyType,
+ IUnknown* lpValue ) = 0;
+
+
+ //_______________________ Playback control ______________________________//
+
+ virtual HRESULT STDMETHODCALLTYPE PlayControl (
+ long lDeviceID,
+ long lPlayOperationType,
+ IUnknown* lpValue ) = 0;
+ virtual HRESULT STDMETHODCALLTYPE QueueControl (
+ long lDeviceID,
+ long lQueueOperationType,
+ IUnknown* lpValue ) = 0;
+
+};
+
+//////////////////////////////////////////////////////////////
+// ICTNomad2 Methods //
+//////////////////////////////////////////////////////////////
+
+// {368953D4-6A2F-4787-BC6F-4047A39A7557}
+DEFINE_GUID(IID_ICTNomad2,
+0x368953d4, 0x6a2f, 0x4787, 0xbc, 0x6f, 0x40, 0x47, 0xa3, 0x9a, 0x75, 0x57);
+
+interface ICTNomad2 : public IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE Initialize() = 0;
+ virtual HRESULT STDMETHODCALLTYPE ShutDown() = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCallbackWindow(
+ /*[in]*/long lDeviceID,
+ /*[in]*/long hWnd) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceCount(
+ /*[out]*/long* lpDeviceCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CancelTransfer(
+ /*[in]*/long lDeviceID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSDKVersion(
+ /*[out]*/IUnknown* lpVersion) = 0;
+
+
+ //__________________________ Querying Item ______________________________//
+
+ virtual HRESULT STDMETHODCALLTYPE FindFirstItem (
+ long lDeviceID,
+ IUnknown* lParentItemID,
+ IUnknown* lpItemID ) = 0;
+ virtual HRESULT STDMETHODCALLTYPE FindNextItem (
+ long lDeviceID,
+ IUnknown* lParentItemID,
+ IUnknown* lpItemID ) = 0;
+
+
+ //_____________________ Getting Item Attributes __________________________//
+
+ //-- GetItemAttribute() Function Description --//
+ // This function returns the TrackInfo data for all Item type. But for
+ // kDataFileType and kPlaylistFileType, the TrackInfo data contain only
+ // file name, file type and file size. In contrast, the item attribute
+ // for a kAudioTrackType may contain all information similar to the ID3tag
+ // information that a typical MP3 file has.
+ virtual HRESULT STDMETHODCALLTYPE GetItemAttribute (
+ long lDeviceID,
+ IUnknown* lpItemID,
+ long lInItemInfoSize,
+ long* lOutItemInfoSize,
+ IUnknown* lpItemInfo ) = 0;
+
+
+ //____________________________ Item Management ___________________________//
+
+ //-- AddItem() Function Description --//
+ // This function initiates the file download from the computer to the
+ // device. Client should call this function to download audio tracks
+ // like MP3, WMA and WAVE and data files. Client are not allow
+ // to download an item of kPlaylistType, use AddItemsToParentItem to add
+ // item of type kPlaylistType.
+ virtual HRESULT STDMETHODCALLTYPE AddItem (
+ long lDeviceID,
+ long lItemType,
+ BSTR bstrSrcFileName,
+ long lItemInfoSize,
+ IUnknown* lpItemInfo) = 0;
+
+ //-- DeleteItem() Function Description --//
+ // Client can call this function to remove item of type kAudioTrackType and
+ // kDataFileType. You cannot remove kPlaylistType item here.
+ virtual HRESULT STDMETHODCALLTYPE DeleteItem (
+ long lDeviceID,
+ IUnknown* lpItemID ) = 0;
+
+ //-- GetItem() Function Description --//
+ // Client can call this function to retrieve item that are kAudioTrackType
+ // and kDataFileType from the device to the computer. Note that client
+ // cannot retrieve item of type kPlaylistItem
+ virtual HRESULT STDMETHODCALLTYPE GetItem (
+ long lDeviceID,
+ BSTR bstrDestinationFileName,
+ IUnknown* lpItemID ) = 0;
+
+
+ //________________________ Device Properties ____________________________//
+
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceProperties (
+ long lDeviceID,
+ long lDevicePropertyType,
+ IUnknown* lpValue ) = 0;
+ virtual HRESULT STDMETHODCALLTYPE SetDeviceProperties (
+ long lDeviceID,
+ long lDevicePropertyType,
+ IUnknown* lpValue ) = 0;
+
+};
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif
+
diff --git a/Src/Plugins/Portable/pmp_njb/ctnmjb2.dll b/Src/Plugins/Portable/pmp_njb/ctnmjb2.dll
new file mode 100644
index 00000000..1d7d458a
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_njb/ctnmjb2.dll
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_njb/main.cpp b/Src/Plugins/Portable/pmp_njb/main.cpp
new file mode 100644
index 00000000..53998610
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_njb/main.cpp
@@ -0,0 +1,181 @@
+//#define PLUGIN_NAME "Nullsoft Creative NJB Plug-in"
+#define PLUGIN_VERSION L"0.57"
+
+#include "NJBDevice.h"
+#include "../Winamp/wa_ipc.h"
+
+#define WM_PMP_NJB_DEVICE_CONNECTED (WM_USER+23)
+int init();
+void quit();
+intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3);
+
+PMPDevicePlugin plugin = {PMPHDR_VER, 0, init, quit, MessageProc};
+
+LRESULT CALLBACK CallbackWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+C_ItemList devices;
+
+// wasabi based services for localisation support
+api_language *WASABI_API_LNG = 0;
+HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
+
+ICTJukebox2 * m_pCTJukebox2 = NULL;
+HWND mainMessageWindow = 0;
+static bool classRegistered = 0;
+HWND CreateDummyWindow()
+{
+ if (!classRegistered)
+ {
+ WNDCLASSW wc = {0, };
+
+ wc.style = 0;
+ wc.lpfnWndProc = CallbackWndProc;
+ wc.hInstance = plugin.hDllInstance;
+ wc.hIcon = 0;
+ wc.hCursor = NULL;
+ wc.lpszClassName = L"pmp_njb_window";
+
+ if (!RegisterClassW(&wc))
+ return 0;
+
+ classRegistered = true;
+ }
+ HWND dummy = CreateWindowW(L"pmp_njb_window", L"pmp_njb_window", 0, 0, 0, 0, 0, NULL, NULL, plugin.hDllInstance, NULL);
+
+ return dummy;
+}
+
+int init()
+{
+ waServiceFactory *sf = plugin.service->service_getServiceByGuid(languageApiGUID);
+ if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
+
+ // need to have this initialised before we try to do anything with localisation features
+ WASABI_API_START_LANG(plugin.hDllInstance,PmpNJBLangGUID);
+
+ static wchar_t szDescription[256];
+ swprintf(szDescription, ARRAYSIZE(szDescription),
+ WASABI_API_LNGSTRINGW(IDS_NULLSOFT_CREATIVE_NJB), PLUGIN_VERSION);
+ plugin.description = szDescription;
+
+ OleInitialize(NULL);
+ HRESULT hr = CoCreateInstance(CLSID_CTJukeBox2, NULL, CLSCTX_ALL, IID_ICTJukebox2, (void**) & m_pCTJukebox2);
+ if (hr != S_OK) return 0;
+
+ hr = m_pCTJukebox2->Initialize2();
+ if (hr != S_OK)
+ {
+ m_pCTJukebox2->Release();
+ m_pCTJukebox2=0;
+ return 0;
+ }
+
+ mainMessageWindow = CreateDummyWindow();
+ m_pCTJukebox2->SetCallbackWindow2(0, (long)mainMessageWindow);
+
+ long devCount = 0;
+ m_pCTJukebox2->GetDeviceCount2(&devCount);
+ for (long i = 1; i <= devCount; i++)
+ PostMessage(mainMessageWindow, WM_PMP_NJB_DEVICE_CONNECTED, i, 0);
+
+ return 0;
+}
+
+void quit()
+{
+
+ if (m_pCTJukebox2)
+ {
+ m_pCTJukebox2->ShutDown2();
+ m_pCTJukebox2->Release();
+ m_pCTJukebox2 = 0;
+ }
+ DestroyWindow(mainMessageWindow);
+ OleUninitialize();
+}
+
+LRESULT CALLBACK CallbackWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_PMP_NJB_DEVICE_CONNECTED:
+ {
+ new NJBDevice((int)wParam);
+ }
+ break;
+ case WM_DAPSDK_JUKEBOX_REMOVAL:
+ {
+ long devCount = 0;
+ if (m_pCTJukebox2->GetDeviceCount2(&devCount) == S_OK)
+ {
+ if (devCount == 0) // TODO benski> shouldn't we always register for messages?
+ m_pCTJukebox2->SetCallbackWindow2(0, (long)mainMessageWindow);
+ for (long i = 0; i < devices.GetSize(); /*i++*/)
+ {
+ NJBDevice * dev = (NJBDevice *)devices.Get(i);
+ bool attached = false;
+ for (long j = 1; j <= devCount; j++)
+ {
+ BYTE * ptr = NULL;
+ if (m_pCTJukebox2->GetDeviceProperties(j, kDeviceSerialNumberValue, (IUnknown*)ptr) == S_OK)
+ {
+ if (memcmp(ptr, dev->serial, 16) == 0)
+ {
+ attached = true;
+ dev->id = j;
+ break;
+ }
+ //free(ptr);
+ }
+ }
+ if (!attached)
+ {
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)dev,PMP_IPC_DEVICEDISCONNECTED);
+ delete dev;
+ }
+ else
+ i++;
+ }
+ }
+ }
+ break;
+ case WM_DAPSDK_JUKEBOX_ARRIVAL:
+ {
+ long devCount = 0;
+ if (m_pCTJukebox2->GetDeviceCount2(&devCount) == S_OK)
+ new NJBDevice(devCount);
+ }
+ break;
+ default:
+ {
+ for (int i = 0; i < devices.GetSize(); i++)
+ {
+ NJBDevice * dev = (NJBDevice *)devices.Get(i);
+ if (dev->messageWindow == hwnd)
+ return dev->WindowMessage(hwnd, uMsg, wParam, lParam);
+ }
+ }
+ }
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);;
+}
+
+intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3) {
+ switch(msg) {
+ case PMP_DEVICECHANGE:
+ return 0;
+ case PMP_NO_CONFIG:
+ return TRUE;
+ case PMP_CONFIG:
+ return 0;
+ }
+ return 0;
+}
+
+extern "C" {
+ __declspec( dllexport ) PMPDevicePlugin * winampGetPMPDevicePlugin(){return &plugin;}
+ __declspec( dllexport ) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) {
+ int i = devices.GetSize();
+ while(i-- > 0) ((Device*)devices.Get(i))->Close();
+ return PMP_PLUGIN_UNINSTALL_NOW;
+ }
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_njb/pmp_njb.rc b/Src/Plugins/Portable/pmp_njb/pmp_njb.rc
new file mode 100644
index 00000000..47812072
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_njb/pmp_njb.rc
@@ -0,0 +1,109 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""version.rc2""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+#if defined(APSTUDIO_INVOKED) || defined(DISABLED)
+#if defined(APSTUDIO_INVOKED)
+IDD_INVISI$(DISABLED) DIALOGEX 0, 0, 5, 5
+#else
+IDD_INVISI DIALOGEX 0, 0, 5, 5
+#endif
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+END
+#endif
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RCDATA
+//
+
+IDR_ZEN_ICON RCDATA ".\\resources\\zenIcon.png"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_NULLSOFT_CREATIVE_NJB "Nullsoft Creative NJB Plug-in v%s"
+ 65535 "{4F5B2300-19D1-4390-BE04-89019441100B}"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_NJB_LOADING "NJB Loading..."
+ IDS_TRANSFERRING_PERCENT "Transferring %d%%"
+ IDS_DONE "Done"
+ IDS_ERROR "Error"
+ IDS_TRANSFERRING "Transferring..."
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc2"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/Plugins/Portable/pmp_njb/pmp_njb.sln b/Src/Plugins/Portable/pmp_njb/pmp_njb.sln
new file mode 100644
index 00000000..baa96ce9
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_njb/pmp_njb.sln
@@ -0,0 +1,30 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29709.97
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmp_njb", "pmp_njb.vcxproj", "{0D2DCCBD-FF58-4A04-BC53-D6208D5EB3E4}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0D2DCCBD-FF58-4A04-BC53-D6208D5EB3E4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0D2DCCBD-FF58-4A04-BC53-D6208D5EB3E4}.Debug|Win32.Build.0 = Debug|Win32
+ {0D2DCCBD-FF58-4A04-BC53-D6208D5EB3E4}.Debug|x64.ActiveCfg = Debug|x64
+ {0D2DCCBD-FF58-4A04-BC53-D6208D5EB3E4}.Debug|x64.Build.0 = Debug|x64
+ {0D2DCCBD-FF58-4A04-BC53-D6208D5EB3E4}.Release|Win32.ActiveCfg = Release|Win32
+ {0D2DCCBD-FF58-4A04-BC53-D6208D5EB3E4}.Release|Win32.Build.0 = Release|Win32
+ {0D2DCCBD-FF58-4A04-BC53-D6208D5EB3E4}.Release|x64.ActiveCfg = Release|x64
+ {0D2DCCBD-FF58-4A04-BC53-D6208D5EB3E4}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {651853BB-3138-4841-BD5B-ACF5165F9161}
+ EndGlobalSection
+EndGlobal
diff --git a/Src/Plugins/Portable/pmp_njb/pmp_njb.vcxproj b/Src/Plugins/Portable/pmp_njb/pmp_njb.vcxproj
new file mode 100644
index 00000000..7a12022e
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_njb/pmp_njb.vcxproj
@@ -0,0 +1,315 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{0D2DCCBD-FF58-4A04-BC53-D6208D5EB3E4}</ProjectGuid>
+ <RootNamespace>pmp_njb</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg">
+ <VcpkgEnableManifest>false</VcpkgEnableManifest>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\..\replicant;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>odbc32.lib;odbccp32.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapExports>false</MapExports>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\..\replicant;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <DisableSpecificWarnings>4302;4311;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>odbc32.lib;odbccp32.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapExports>false</MapExports>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\..\replicant;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>odbc32.lib;odbccp32.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\..\replicant;..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4302;4311;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>odbc32.lib;odbccp32.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\General\gen_ml\itemlist.cpp" />
+ <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp" />
+ <ClCompile Include="main.cpp" />
+ <ClCompile Include="NJBDevice.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\General\gen_ml\itemlist.h" />
+ <ClInclude Include="..\..\General\gen_ml\ml.h" />
+ <ClInclude Include="..\..\Library\ml_pmp\pmp.h" />
+ <ClInclude Include="NJBDevice.h" />
+ <ClInclude Include="Nmsdk.h" />
+ <ClInclude Include="resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="pmp_njb.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="resources\zenIcon.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
+ <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_njb/pmp_njb.vcxproj.filters b/Src/Plugins/Portable/pmp_njb/pmp_njb.vcxproj.filters
new file mode 100644
index 00000000..1eb41b59
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_njb/pmp_njb.vcxproj.filters
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="NJBDevice.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\General\gen_ml\itemlist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="NJBDevice.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Nmsdk.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\General\gen_ml\itemlist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\General\gen_ml\ml.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Library\ml_pmp\pmp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{19f63d8f-2d94-424b-b8e5-1ae189920736}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Ressource Files">
+ <UniqueIdentifier>{675c67be-1ca6-4f01-aeb3-6b9329201724}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{df88e072-b108-4287-9243-92c4883b420e}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Image Files">
+ <UniqueIdentifier>{a2c922b0-d514-4e40-8e03-932a77c3e2fa}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="resources\zenIcon.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="pmp_njb.rc">
+ <Filter>Ressource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_njb/resource.h b/Src/Plugins/Portable/pmp_njb/resource.h
new file mode 100644
index 00000000..6f76d97a
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_njb/resource.h
@@ -0,0 +1,23 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by pmp_njb1.rc
+//
+#define IDS_NJB_LOADING 1
+#define IDS_TRANSFERRING_PERCENT 2
+#define IDS_DONE 3
+#define IDS_ERROR 4
+#define IDS_TRANSFERRING 5
+#define IDD_INVISI 9
+#define IDR_ZEN_ICON 103
+#define IDS_NULLSOFT_CREATIVE_NJB 65534
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 108
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/Plugins/Portable/pmp_njb/resources/zenIcon.png b/Src/Plugins/Portable/pmp_njb/resources/zenIcon.png
new file mode 100644
index 00000000..7352c626
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_njb/resources/zenIcon.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_njb/version.rc2 b/Src/Plugins/Portable/pmp_njb/version.rc2
new file mode 100644
index 00000000..7ff08345
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_njb/version.rc2
@@ -0,0 +1,39 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#include "../../../Winamp/buildType.h"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,57,0,0
+ PRODUCTVERSION WINAMP_PRODUCTVER
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Winamp SA"
+ VALUE "FileDescription", "Winamp Portable Device Plug-in"
+ VALUE "FileVersion", "0,57,0,0"
+ VALUE "InternalName", "Nullsoft Creative NJB"
+ VALUE "LegalCopyright", "Copyright © 2006-2023 Winamp SA"
+ VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
+ VALUE "OriginalFilename", "pmp_njb.dll"
+ VALUE "ProductName", "Winamp"
+ VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/Src/Plugins/Portable/pmp_p4s/Cert.zip b/Src/Plugins/Portable/pmp_p4s/Cert.zip
new file mode 100644
index 00000000..6c36c3bc
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/Cert.zip
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_p4s/MTP Error Codes.txt b/Src/Plugins/Portable/pmp_p4s/MTP Error Codes.txt
new file mode 100644
index 00000000..66de9592
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/MTP Error Codes.txt
@@ -0,0 +1,41 @@
+
+80004004 Operation aborted.
+80004005 Unspecified error.
+80004002 Interface not supported.
+80004001 Not implemented.
+80004003 Invalid pointer.
+8000FFFF Catastrophic failure.
+
+80070001 INVALID_FUNCTION
+80070002 FILE_NOT_FOUND
+80070003 PATH_NOT_FOUND
+80070004 TOO_MANY_OPEN_FILES
+80070005 ACCESS_DENIED
+80070006 INVALID_HANDLE
+80070007 ARENA_TRASHED
+80070008 NOT_ENOUGH_MEMORY
+8007000d INVALID_DATA
+80070015 ERROR_NOT_READY
+80070057 INVALIDARG
+
+80045000 BUSY
+80045001 INTERFACEDEAD
+80045002 INVALIDTYPE
+80045003 PROCESSFAILED
+80045004 NOTSUPPORTED
+80045005 NOTCERTIFIED
+80045006 NORIGHTS
+80045007 CALL_OUT_OF_SEQUENCE
+80045008 BUFFERTOOSMALL
+80045009 MOREDATA
+8004500A MAC_CHECK_FAILED
+8004500B USER_CANCELLED
+8004500C SDMI_TRIGGER
+8004500D SDMI_NOMORECOPIES
+8004500E REVOKED
+8004500F LICENSE_NOTEXIST
+80045010 INCORRECT_APPSEC
+80045011 INCORRECT_RIGHTS
+80045012 LICENSE_EXPIRED
+80045013 CANTOPEN_PMSN_SERVICE_PIPE
+80045013 TOO_MANY_SESSIONS \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_p4s/MyProgress.cpp b/Src/Plugins/Portable/pmp_p4s/MyProgress.cpp
new file mode 100644
index 00000000..0f3772e0
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/MyProgress.cpp
@@ -0,0 +1,95 @@
+#include "MyProgress.h"
+
+extern LPARAM ipc_transfer;
+
+MyProgress::MyProgress(TransferItem *_t)
+: t(_t), refcount(1), estTicks(0)
+{
+}
+
+MyProgress::~MyProgress() {}
+
+
+HRESULT MyProgress::Begin(DWORD dwEstimatedTicks)
+{
+ estTicks = dwEstimatedTicks / 100;
+ return S_OK;
+}
+
+HRESULT MyProgress::Progress(DWORD dwTranspiredTicks)
+{
+ if (estTicks > 0) {
+ int pc = dwTranspiredTicks / estTicks;
+ if(pc > 100) pc = 100;
+ t->pc = pc;
+ }
+ else t->pc = 0;
+
+ wchar_t buf[100] = {0};
+ wsprintf(buf,WASABI_API_LNGSTRINGW(IDS_TRANSFERRING_PERCENT), t->pc);
+ t->callback(t->callbackContext,buf);
+
+ if (*(t->killswitch))
+ return WMDM_E_USER_CANCELLED;
+
+ return S_OK;
+}
+
+#define PHASE_START 1
+#define PHASE_INPROGRESS 2
+#define PHASE_FINISH 3
+#define PHASE_DONE 4
+#define PHASE_ERROR 5
+
+HRESULT MyProgress::End()
+{
+ t->phase = PHASE_FINISH;
+ return S_OK;
+}
+
+#define IMPLEMENTS(ifc) if (riid == IID_ ## ifc) { ++refcount; *ppvObject = static_cast<ifc *>(this); return S_OK; }
+
+HRESULT MyProgress::QueryInterface(REFIID riid,void __RPC_FAR *__RPC_FAR *ppvObject)
+{
+ IMPLEMENTS(IUnknown);
+ IMPLEMENTS(IWMDMProgress);
+ IMPLEMENTS(IWMDMProgress2);
+ IMPLEMENTS(IWMDMProgress3);
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+}
+
+ULONG MyProgress::AddRef()
+{
+ return ++refcount;
+}
+ULONG MyProgress::Release()
+{
+ int x = --refcount;
+ if (x == 0)
+ delete this;
+
+ return x;
+}
+
+HRESULT MyProgress::End2(HRESULT hrCompletionCode)
+{
+ return End();
+}
+
+HRESULT MyProgress::Begin3(GUID EventId,DWORD dwEstimatedTicks,OPAQUECOMMAND* pContext)
+{
+ return Begin(dwEstimatedTicks);
+}
+
+HRESULT MyProgress::Progress3(GUID EventId,DWORD dwTranspiredTicks,OPAQUECOMMAND* pContext)
+{
+ return Progress(dwTranspiredTicks);
+}
+
+HRESULT MyProgress::End3(GUID EventId,HRESULT hrCompletionCode,OPAQUECOMMAND* pContext)
+{
+ return End2( hrCompletionCode);
+}
+
+
diff --git a/Src/Plugins/Portable/pmp_p4s/MyProgress.h b/Src/Plugins/Portable/pmp_p4s/MyProgress.h
new file mode 100644
index 00000000..967518cb
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/MyProgress.h
@@ -0,0 +1,35 @@
+#ifndef NULLSOFT_MYPROGRESSH
+#define NULLSOFT_MYPROGRESSH
+
+#include "P4SDevice.h"
+
+class MyProgress : public IWMDMProgress3
+{
+public:
+ MyProgress(TransferItem * t);
+ virtual ~MyProgress();
+
+ /* IUnknown methods */
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,void __RPC_FAR *__RPC_FAR *ppvObject);
+ virtual ULONG STDMETHODCALLTYPE AddRef();
+ virtual ULONG STDMETHODCALLTYPE Release();
+
+ /* IWMDMProgress methods */
+ virtual HRESULT STDMETHODCALLTYPE Begin(DWORD dwEstimatedTicks);
+ virtual HRESULT STDMETHODCALLTYPE Progress(DWORD dwTranspiredTicks);
+ virtual HRESULT STDMETHODCALLTYPE End();
+
+ /* IWMDMProgress2 methods */
+ virtual HRESULT STDMETHODCALLTYPE End2(HRESULT hrCompletionCode);
+
+ /* IWMDMProgress3 methods */
+ virtual HRESULT STDMETHODCALLTYPE Begin3(GUID EventId,DWORD dwEstimatedTicks,OPAQUECOMMAND* pContext);
+ virtual HRESULT STDMETHODCALLTYPE Progress3(GUID EventId,DWORD dwTranspiredTicks,OPAQUECOMMAND* pContext);
+ virtual HRESULT STDMETHODCALLTYPE End3(GUID EventId,HRESULT hrCompletionCode,OPAQUECOMMAND* pContext);
+public:
+ TransferItem *t;
+ ULONG refcount;
+ DWORD estTicks;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_p4s/P4SDevice.cpp b/Src/Plugins/Portable/pmp_p4s/P4SDevice.cpp
new file mode 100644
index 00000000..ef76577a
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/P4SDevice.cpp
@@ -0,0 +1,2185 @@
+#include "P4SDevice.h"
+#include <time.h>
+#include "msWMDM_i.c"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "../WAT/wa_logger.h"
+#include "MyProgress.h"
+
+#include "WMDRMDeviceApp_i.c"
+
+extern C_ItemList devices;
+extern HANDLE killEvent;
+extern CRITICAL_SECTION csTransfers;
+
+#define plext L"pla"
+
+BOOL FormatResProtocol(const wchar_t *resourceName, const wchar_t *resourceType, wchar_t *buffer, size_t bufferMax);
+
+static BYTE* GetMetadataItem(IWMDMStorage4 * store, const WCHAR * name);
+static IWMDMStorage4* GetOrCreateFolder(IWMDMStorage4 * store, wchar_t * name, P4SDevice * dev=NULL, bool album=false, const itemRecordW * item=NULL);
+
+// from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmdm/htm/wmdm_format_capability.asp
+void FreeFormatCapability(WMDM_FORMAT_CAPABILITY formatCap)
+{
+ // Loop through all configurations.
+ for (UINT i=0; i < formatCap.nPropConfig; i++)
+ {
+ // Loop through all descriptions of a configuration and delete
+ // the values particular to that description type.
+ for (UINT j=0; j < formatCap.pConfigs[i].nPropDesc; j++)
+ {
+ switch (formatCap.pConfigs[i].pPropDesc[j].ValidValuesForm)
+ {
+ case WMDM_ENUM_PROP_VALID_VALUES_ENUM:
+ for (UINT k=0; k < formatCap.pConfigs[i].pPropDesc[j].ValidValues.EnumeratedValidValues.cEnumValues; k++)
+ {
+ PropVariantClear (&(formatCap.pConfigs[i].pPropDesc[j].ValidValues.EnumeratedValidValues.pValues[k]));
+ }
+ CoTaskMemFree(formatCap.pConfigs[i].pPropDesc[j].ValidValues.EnumeratedValidValues.pValues);
+ break;
+ case WMDM_ENUM_PROP_VALID_VALUES_RANGE:
+ PropVariantClear (&(formatCap.pConfigs[i].pPropDesc[j].ValidValues.ValidValuesRange.rangeMin));
+ PropVariantClear (&(formatCap.pConfigs[i].pPropDesc[j].ValidValues.ValidValuesRange.rangeMax));
+ PropVariantClear (&(formatCap.pConfigs[i].pPropDesc[j].ValidValues.ValidValuesRange.rangeStep));
+ break;
+ case WMDM_ENUM_PROP_VALID_VALUES_ANY:
+ // No dynamically allocated memory for this value.
+ default:
+ break;
+ }
+
+ // Free the memory for the description name.
+ CoTaskMemFree(formatCap.pConfigs[i].pPropDesc[j].pwszPropName);
+ }
+ // Free the memory holding the array of description items for this configuration.
+ CoTaskMemFree(formatCap.pConfigs[i].pPropDesc);
+ }
+
+ // Free the memory pointing to the array of configurations.
+ CoTaskMemFree(formatCap.pConfigs);
+ formatCap.nPropConfig = 0;
+}
+
+static HRESULT GetFormatCaps(WMDM_FORMATCODE formatCode, IWMDMDevice3* pDevice)
+{
+ // Get a list of supported configurations for the format.
+ WMDM_FORMAT_CAPABILITY formatCapList;
+ HRESULT hr = pDevice->GetFormatCapability(formatCode, &formatCapList);
+ if (FAILED(hr)) return E_FAIL;
+ if (formatCapList.nPropConfig == 0)
+ {
+ FreeFormatCapability(formatCapList);
+ return E_FAIL; // operation succeeded, but format not supported.
+ }
+
+ // TODO: Display the format name.
+ // Loop through the configurations and examine each one.
+ for (UINT iConfig = 0; iConfig < formatCapList.nPropConfig; iConfig++)
+ {
+ WMDM_PROP_CONFIG formatConfig = formatCapList.pConfigs[iConfig];
+
+ // Preference level for this configuration (lower number means more preferred).
+ // TODO: Display the preference level for this format configuration.
+
+ // Loop through all properties for this configuration and get supported
+ // values for the property. Values can be a single value, a range,
+ // or a list of enumerated values.
+ for (UINT iDesc = 0; iDesc < formatConfig.nPropDesc; iDesc++)
+ {
+ WMDM_PROP_DESC propDesc = formatConfig.pPropDesc[iDesc];
+ // TODO: Display the property name.
+
+ // Three ways a value can be represented: any, a range, or a list.
+ switch (propDesc.ValidValuesForm)
+ {
+ case WMDM_ENUM_PROP_VALID_VALUES_ANY:
+ // TODO: Display a message indicating that all values are valid.
+ break;
+ case WMDM_ENUM_PROP_VALID_VALUES_RANGE:
+ {
+ // List these in the docs as the propvariants set.
+ WMDM_PROP_VALUES_RANGE rng =
+ propDesc.ValidValues.ValidValuesRange;
+ // TODO: Display the min, max, and step values.
+ }
+ break;
+ case WMDM_ENUM_PROP_VALID_VALUES_ENUM:
+ {
+ // TODO: Display a banner for the list of valid values.
+ /*
+ WMDM_PROP_VALUES_ENUM list = propDesc.ValidValues.EnumeratedValidValues;
+ PROPVARIANT pVal;
+ for (UINT iValue = 0; iValue < list.cEnumValues; iValue++)
+ {
+ pVal = list.pValues[iValue];
+ // TODO: Display each valid value.
+ PropVariantClear(&pVal);
+ PropVariantInit(&pVal);
+ }*/
+ }
+
+ break;
+ default:
+ FreeFormatCapability(formatCapList);
+ return E_FAIL;
+ //break;
+ }
+ }
+ }
+ // Now clear the memory used by WMDM_FORMAT_CAPABILITY.
+ FreeFormatCapability(formatCapList);
+ return hr;
+}
+
+static __time64_t wmdmDateTimeToUnixTime(_WMDMDATETIME * t) {
+ tm m={0};
+ m.tm_hour = t->wHour;
+ m.tm_min = t->wMinute;
+ m.tm_sec = t->wSecond;
+ m.tm_mday = t->wDay;
+ m.tm_mon = t->wMonth;
+ m.tm_year = t->wYear;
+ return _mktime64(&m);
+}
+
+HRESULT getMetadata(IWMDMStorage4 *store2,IWMDMMetaData ** meta, bool noMetadata) {
+ const wchar_t ** propnames = (const wchar_t**)calloc(15,sizeof(void*));
+ propnames[0] = g_wszWMDMFormatCode;
+ propnames[1] = g_wszWMDMTitle;
+ propnames[2] = g_wszWMDMAuthor;
+ propnames[3] = g_wszWMDMAlbumTitle;
+ propnames[4] = g_wszWMDMGenre;
+ propnames[5] = g_wszWMDMTrack;
+ propnames[6] = g_wszWMDMYear;
+ propnames[7] = g_wszWMDMFileSize;
+ propnames[8] = g_wszWMDMDuration;
+ propnames[9] = g_wszWMDMPlayCount;
+ propnames[10] = g_wszWMDMUserRating;
+ propnames[11] = g_wszWMDMUserLastPlayTime;
+ propnames[12] = g_wszWMDMLastModifiedDate;
+ propnames[13] = g_wszWMDMAlbumArtist;
+ propnames[14] = g_wszWMDMComposer;
+ HRESULT h;
+ if(noMetadata) {
+ h = store2->GetSpecifiedMetadata(1,(LPCWSTR*)propnames,meta);
+ if(h == WMDM_S_NOT_ALL_PROPERTIES_RETRIEVED) h = S_OK;
+ if(h != S_OK) { // ugh. Guess that this is an AAC/M4A. Dirty workaround hack!
+ if (SUCCEEDED(store2->CreateEmptyMetadataObject(meta))) {
+ h = S_OK;
+ DWORD type = WMDM_FORMATCODE_UNDEFINEDAUDIO;
+ (*meta)->AddItem(WMDM_TYPE_DWORD,g_wszWMDMFormatCode,(BYTE*)&type,sizeof(type));
+ }
+ }
+ } else {
+ h = store2->GetSpecifiedMetadata(13,(LPCWSTR*)propnames,meta);
+ if(h == WMDM_S_NOT_ALL_PROPERTIES_RETRIEVED) h = S_OK;
+ }
+ free(propnames);
+ return h;
+}
+
+void P4SDevice::foundSong(IWMDMStorage4 * store, IWMDMMetaData * meta,bool video,int pl,wchar_t * artist, wchar_t * album, IWMDMStorage4 * alb, IWMDMMetaData * albmeta) {
+ Playlist * pls = (Playlist *)playlists.Get(pl);
+ Song * song = new Song;
+ song->video = video;
+ song->meta = meta;
+ song->modified = false;
+ song->storage = store;
+ song->artist = artist;
+ song->album = album;
+ if(alb && albmeta) {
+ song->alb = alb;
+ song->albmeta = albmeta;
+ alb->AddRef();
+ albmeta->AddRef();
+ }
+ if(song->artist) song->artist = _wcsdup(song->artist);
+ if(song->album) song->album = _wcsdup(song->album);
+ pls->songs.Add(song);
+ store->AddRef();
+ meta->AddRef();
+ if(noMetadata || video) {
+ wchar_t buf[2048]=L"";
+ getTrackAlbum((songid_t)song,buf,2048);
+ if(video) meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumTitle,(BYTE*)L"~",4);
+ else {
+ meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumTitle,(BYTE*)buf,wcslen(buf)*2 + 2);
+ buf[0]=0;
+ getTrackArtist((songid_t)song,buf,2048);
+ }
+ meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAuthor,(BYTE*)buf,wcslen(buf)*2 + 2);
+ buf[0]=0;
+ getTrackTitle((songid_t)song,buf,2048);
+ meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMTitle,(BYTE*)buf,wcslen(buf)*2 + 2);
+ int n = getTrackTrackNum((songid_t)song);
+ meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMTrack,(BYTE*)&n,sizeof(DWORD));
+ __int64 s = (__int64)getTrackSize((songid_t)song);
+ meta->AddItem(WMDM_TYPE_QWORD,g_wszWMDMFileSize,(BYTE*)&s,sizeof(__int64));
+ }
+}
+
+void P4SDevice::foundPlaylist(IWMDMStorage4 * store, IWMDMMetaData * meta) {
+ DWORD count = 0;
+ IWMDMStorage ** stores;
+ wchar_t buf[100] = {0};
+ store->GetName(buf,100);
+ //OutputDebugString(buf);
+ if(store->GetReferences(&count,&stores) == S_OK) {
+ if(count > 0) {
+ Playlist * pl = new Playlist;
+ StringCchCopy(pl->name, ARRAYSIZE(pl->name), buf);
+ {wchar_t * ext = wcsrchr(pl->name,L'.'); if(ext) *ext=0;}
+ pl->storage = store;
+ pl->meta = meta;
+ meta->AddRef();
+ store->AddRef();
+ playlists.Add(pl);
+ int num = playlists.GetSize()-1;
+ for(unsigned int i=0; i<count; i++) {
+ IWMDMStorage4 * song=NULL;
+ /*{
+ wchar_t buf[100] = {0};
+ stores[i]->GetName(buf,100);
+ OutputDebugString(buf);
+ }*/
+ if(stores[i]->QueryInterface(&song) == S_OK) if(song) {
+ /*
+ Song * s = new Song;
+ s->modified=false;
+ s->storage=song;
+ HRESULT h = getMetadata(song,&s->meta);
+ if (SUCCEEDED(h)) pl->songs.Add(s);
+ else delete s;
+ */
+ //pl->songs.Add(song);
+ IWMDMMetaData * meta;
+ if (SUCCEEDED(getMetadata(song,&meta,noMetadata))) {
+ foundSong(song,meta,false,num); meta->Release();
+ }
+ song->Release();
+ }
+ stores[i]->Release();
+ }
+ } else {
+ //OutputDebugString(L"ref count zero");
+ }
+ CoTaskMemFree(stores);
+ } else {
+ //OutputDebugString(L"can't get playlist refs");
+ }
+}
+
+void P4SDevice::traverseStorage(IWMDMStorage * store, int level, wchar_t * artist, wchar_t * album) {
+ if(!store) return;
+ IWMDMStorage4 * store2=NULL;
+ ULONG num;
+ //OutputDebugStringA("1A");
+ C_ItemList storages;
+ {
+ IWMDMEnumStorage * enstore=NULL;
+ IWMDMStorage * storeold=NULL;
+ HRESULT hr = store->EnumStorage(&enstore);
+ while(SUCCEEDED(hr)) {
+ if (WaitForSingleObject(killEvent,0) == WAIT_OBJECT_0)
+ break;
+ hr = enstore->Next(1,&storeold,&num);
+ if(SUCCEEDED(hr) && storeold) {
+ hr = storeold->QueryInterface(&store2);
+ storeold->Release();
+ if(SUCCEEDED(hr) && store2) {
+ storages.Add(store2);
+ }
+ else break;
+ }
+ else break;
+ }
+ if(enstore) enstore->Release();
+ }
+ //OutputDebugStringA("2A");
+ //while (SUCCEEDED(hr) && enstore) {
+ IWMDMStorage4 * alb=NULL;
+ IWMDMMetaData * albmeta=NULL;
+
+ for(int i=0; i<storages.GetSize(); i++) {
+ wchar_t buf[256]=L"";
+ store2 = (IWMDMStorage4*)storages.Get(i);
+ store2->GetName(buf,256);
+ wchar_t *ext = wcsrchr(buf,L'.');
+ if(ext && _wcsicmp(ext,L".alb")==0) {
+ alb = store2;
+ alb->AddRef();
+ alb->GetMetadata(&albmeta);
+ break;
+ }
+ }
+
+ //albfiles.Add(new AlbFile(store2,meta));
+ for(int i=0; i<storages.GetSize(); i++) {
+ if (WaitForSingleObject(killEvent,0) == WAIT_OBJECT_0)
+ break;
+ //OutputDebugStringA("1");
+ store2 = (IWMDMStorage4*)storages.Get(i);
+
+ if(store2 == alb) continue;
+
+ wchar_t buf[256]=L"";
+ //OutputDebugStringA("2");
+ store2->GetName(buf,256);
+ if(playlistsDir == NULL && _wcsicmp(buf,L"My Playlists")==0) { playlistsDir = store2; store2->AddRef(); }
+ if(playlistsDir == NULL && _wcsicmp(buf,L"Playlists")==0) { playlistsDir = store2; store2->AddRef(); }
+
+ DWORD attribs=NULL;
+ store2->GetAttributes(&attribs,NULL);
+ //OutputDebugStringA("3");
+ if(attribs & WMDM_FILE_ATTR_FOLDER) {
+ if(level==0) artist=buf;
+ else if(level==1) album=buf;
+ //OutputDebugStringA("5");
+ WMDM_STORAGE_ENUM_MODE mode = ENUM_MODE_RAW;
+ store2->SetEnumPreference(&mode,0,NULL);
+ traverseStorage(store2,level+1,artist,album);
+ } else if(attribs & WMDM_FILE_ATTR_FILE || !attribs) {
+ IWMDMMetaData * meta=NULL;
+ //OutputDebugStringA("1");
+ HRESULT h = getMetadata(store2,&meta,noMetadata);
+ //OutputDebugStringA("2");
+ //OutputDebugStringA("4");
+ /*{
+ wchar_t buf2[400] = {0};
+ wsprintf(buf2,L"name: %s atr: 0x%x, hr: 0x%x %s",buf,attribs,h,h == E_INVALIDARG?L"POOT":L"");
+ OutputDebugString(buf2);
+ }*/
+ if(meta && h == S_OK) {
+ wchar_t * name=NULL;
+ WMDM_TAG_DATATYPE type;
+ BYTE * value=NULL;
+ UINT valuelen;
+ if(meta->QueryByName(g_wszWMDMFormatCode,&type,&value,&valuelen) == S_OK && type == WMDM_TYPE_DWORD)
+ {
+ switch(*(DWORD*)value) { // find out what it is...
+ case WMDM_FORMATCODE_ABSTRACTAUDIOVIDEOPLAYLIST:
+ case WMDM_FORMATCODE_WPLPLAYLIST:
+ case WMDM_FORMATCODE_M3UPLAYLIST:
+ case WMDM_FORMATCODE_MPLPLAYLIST:
+ case WMDM_FORMATCODE_ASXPLAYLIST:
+ case WMDM_FORMATCODE_PLSPLAYLIST:
+ foundPlaylist(store2,meta);
+ break;
+ case WMDM_FORMATCODE_ASF:
+ case WMDM_FORMATCODE_AVI:
+ case WMDM_FORMATCODE_MPEG:
+ case WMDM_FORMATCODE_WMV:
+ case WMDM_FORMATCODE_MP2:
+ case WMDM_FORMATCODE_3GP:
+ case WMDM_FORMATCODE_UNDEFINEDVIDEO:
+ foundSong(store2,meta,true);
+ break;
+ case WMDM_FORMATCODE_UNDEFINED:
+ { //ugh. nokiahack.
+ wchar_t * ext = wcsrchr(buf,'.');
+ if(!ext) break;
+ if(!_wcsicmp(ext,L".mp4") || !_wcsicmp(ext,L".m4a")) foundSong(store2,meta,false);
+ }
+ break;
+ case WMDM_FORMATCODE_AIFF:
+ case WMDM_FORMATCODE_WAVE:
+ case WMDM_FORMATCODE_MP3:
+ case WMDM_FORMATCODE_WMA:
+ case WMDM_FORMATCODE_OGG:
+ case WMDM_FORMATCODE_AAC:
+ case WMDM_FORMATCODE_MP4:
+ case WMDM_FORMATCODE_AUDIBLE:
+ case WMDM_FORMATCODE_FLAC:
+ case WMDM_FORMATCODE_UNDEFINEDAUDIO:
+ foundSong(store2,meta,false,0,0,0,alb,albmeta);
+ break;
+ }
+ } else {
+ wchar_t * ext = wcsrchr(buf,'.');
+ if(ext) {
+ bool m = noMetadata;
+ noMetadata = true;
+ if(!_wcsicmp(ext,L".mp3") || !_wcsicmp(ext,L".wma")) foundSong(store2,meta,false,0,artist,album);
+ else if(!_wcsicmp(ext,L".wmv") || !_wcsicmp(ext,L".avi")) foundSong(store2,meta,true,0,artist,album);
+ else if(!_wcsicmp(ext,L".asx") || !_wcsicmp(ext,L".pla")) foundPlaylist(store2,meta);
+ noMetadata = m;
+ }
+ }
+ meta->Release();
+ if(name) CoTaskMemFree(name);
+ if(value) CoTaskMemFree(value);
+ }
+ }
+ if(store2) store2->Release();
+ }
+
+ if(alb) alb->Release();
+ if(albmeta) albmeta->Release();
+}
+
+bool P4SDevice::songsEqual(songid_t a, songid_t b) {
+ wchar_t ba[1024] = {0};
+ wchar_t bb[1024] = {0};
+ getTrackTitle(a,ba,1024);
+ getTrackTitle(b,bb,1024);
+ if(wcscmp(ba,bb)) return false;
+ getTrackAlbum(a,ba,1024);
+ getTrackAlbum(b,bb,1024);
+ if(wcscmp(ba,bb)) return false;
+ getTrackArtist(a,ba,1024);
+ getTrackArtist(b,bb,1024);
+ if(wcscmp(ba,bb)) return false;
+ return true;
+}
+
+int P4SDevice::songsCmp(songid_t a, songid_t b) {
+ int q=0;
+ wchar_t ba[1024] = {0};
+ wchar_t bb[1024] = {0};
+ getTrackTitle(a,ba,1024);
+ getTrackTitle(b,bb,1024);
+ q=wcscmp(ba,bb); if(q) return q;
+ getTrackAlbum(a,ba,1024);
+ getTrackAlbum(b,bb,1024);
+ q=wcscmp(ba,bb); if(q) return q;
+ getTrackArtist(a,ba,1024);
+ getTrackArtist(b,bb,1024);
+ return wcscmp(ba,bb);
+}
+
+P4SDevice * sortDev;
+
+static int song_sortfunc(const void *elem1, const void *elem2) {
+ songid_t a = *(songid_t *)elem1;
+ songid_t b = *(songid_t *)elem2;
+ return sortDev->songsCmp(a,b);
+}
+
+extern IWMDRMDeviceApp * DRMDeviceApp;
+
+static songid_t BinaryChopFind(songid_t find,Playlist * mpl, P4SDevice * dev) {
+ sortDev = dev;
+ songid_t * ret = (songid_t*)bsearch(&find,mpl->songs.GetAll(),mpl->songs.GetSize(),sizeof(songid_t),song_sortfunc);
+ return ret?*ret:NULL;
+}
+
+P4SDevice::P4SDevice(IWMDMDevice3* pIDevice, bool noMetadata) : transcoder(NULL) {
+ error=0;
+ musicDir = L"Music";
+ videoDir = L"Video";
+ lastChange=NULL;
+ this->noMetadata = noMetadata;
+ if(DRMDeviceApp && DRMDeviceApp->SynchronizeLicenses(pIDevice,NULL,0,0) == S_OK)
+ {
+ //OutputDebugString(L"sync!");
+ }
+ playlistsDir=NULL;
+ transferQueueSize=0;
+ Playlist * mpl = new Playlist;
+ playlists.Add(mpl);
+
+ WMDevice = pIDevice;
+ if (NULL != WMDevice)
+ {
+ WMDevice->AddRef();
+ if (FAILED(WMDevice->GetName(name,100)))
+ name[0] = L'\0';
+ }
+ else
+ name[0] = L'\0';
+
+ // give loading indication to the user....
+ pmpDeviceLoading load;
+ load.dev = this;
+ load.UpdateCaption = NULL;
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)&load,PMP_IPC_DEVICELOADING);
+ if(load.UpdateCaption) {
+ wchar_t buf[200]=L"";
+ wsprintf(buf,WASABI_API_LNGSTRINGW(IDS_LOADING),name);
+ load.UpdateCaption(buf,load.context);
+ }
+ Load();
+}
+
+void P4SDevice::Load() {
+ Playlist * mpl = (Playlist*)playlists.Get(0);
+ HRESULT hr;
+ IWMDMEnumStorage * enstore=0;
+ IWMDMStorage * store0=0;
+ IWMDMStorage4 * store=0;
+ hr = WMDevice->EnumStorage(&enstore);
+ ULONG num;
+ if(!enstore) {delete this; return;}
+ hr = enstore->Next(1,&store0,&num);
+ if (SUCCEEDED(hr)) hr = store0->QueryInterface(&store);
+ if(store0) store0->Release();
+ else error=1;
+ if(enstore) enstore->Release();
+ else error=1;
+ if (SUCCEEDED(hr) && !error) {
+ wchar_t buf[100] = {0};
+ store->GetName(buf,100);
+ mpl->storage = store;
+ store->AddRef();
+ WMDM_STORAGE_ENUM_MODE mode = ENUM_MODE_RAW;
+ store->SetEnumPreference(&mode,0,NULL);
+
+ //traverseStorage(store);
+ IWMDMStorage * playlists;
+ if(store->GetStorage(L"Playlists",&playlists) == S_FALSE) {
+ if(store->GetStorage(L"My Playlists",&playlists) == S_FALSE)
+ {
+ playlists = NULL;
+ }
+ }
+ if(playlists)
+ {
+ traverseStorage(playlists);
+ playlists->QueryInterface(&playlistsDir);
+ playlists->Release();
+ }
+
+ IWMDMStorage * songs = NULL;
+ if(store->GetStorage(L"Music",&songs) == S_OK)
+ {
+ traverseStorage(songs);
+ songs->Release();
+ }
+ else if(store->GetStorage(L"My Music",&songs) == S_OK)
+ {
+ traverseStorage(songs);
+ songs->Release();
+ musicDir = L"My Music";
+ }
+ else if(store->GetStorage(L"Music Files",&songs) == S_OK)
+ {
+ traverseStorage(songs);
+ songs->Release();
+ musicDir = L"Music Files";
+ }
+ else { // create a music folder
+ IWMDMStorageControl3 * storeControl=NULL;
+ store->QueryInterface(&storeControl);
+ if(storeControl) {
+ IWMDMStorage * newdir=NULL;
+ IWMDMMetaData * meta=NULL;
+ store->CreateEmptyMetadataObject(&meta);
+ storeControl->Insert3(WMDM_MODE_BLOCK|WMDM_CONTENT_FOLDER,WMDM_FILE_ATTR_FOLDER,NULL,musicDir,NULL,NULL,meta,NULL,&newdir);
+ if(newdir) newdir->Release();
+ else error=1;
+ if(meta) meta->Release();
+ else error=1;
+ storeControl->Release();
+ } else error=1;
+ }
+
+ if(store->GetStorage(L"Video",&songs) == S_OK) { traverseStorage(songs); songs->Release(); supportsVideo=true; }
+ if(store->GetStorage(L"TV",&songs) == S_OK) { traverseStorage(songs); songs->Release(); supportsVideo=true; }
+
+ if(!playlists && !songs) traverseStorage(store);
+ }
+ if(!store) error=1;
+ if(error) {delete this; return;}
+ if(!playlistsDir) playlistsDir = GetOrCreateFolder(store,L"Playlists");
+ if(!playlistsDir) {delete this; return;}//MessageBox(plugin.hwndWinampParent,L"An error has occured whilst trying to initialise the playlists on your device.\nPlaylists will not work correctly.",L"Playlists Error",0);
+
+ sortDev = this;
+ qsort(mpl->songs.GetAll(),mpl->songs.GetSize(),sizeof(void*),song_sortfunc);
+
+ // Now to recombobulate the playlists (this SUCKS slightly less now)
+ for(int i=1; i<playlists.GetSize(); i++) {
+ Playlist * pl = (Playlist *)playlists.Get(i);
+ int l = pl->songs.GetSize();
+ for(int j=0; j<l; j++) {
+ songid_t plsong = (songid_t)pl->songs.Get(j);
+ songid_t mplsong = BinaryChopFind(plsong,mpl,this);
+ if(mplsong) pl->songs.Set(j,(void*)mplsong);
+ else { pl->songs.Del(j--); l--; }
+
+ Song * p = (Song *)plsong;
+ p->meta->Release();
+ p->storage->Release();
+ delete p;
+ }
+ }
+
+ requiresALB=false;
+ { // check for .alb support
+ WMDM_FORMAT_CAPABILITY formatCapList;
+ HRESULT hr = WMDevice->GetFormatCapability(WMDM_FORMATCODE_ABSTRACTAUDIOALBUM, &formatCapList);
+ bool size=false,data=false,format=false;
+ if(!FAILED(hr)) {
+ for(unsigned int i=0; i<formatCapList.nPropConfig; i++) {
+ WMDM_PROP_CONFIG formatConfig = formatCapList.pConfigs[i];
+ for(unsigned int j=0; j<formatConfig.nPropDesc; j++) {
+ if(!formatConfig.pPropDesc[j].pwszPropName) continue;
+ if(wcscmp(formatConfig.pPropDesc[j].pwszPropName,g_wszWMDMAlbumCoverSize)==0) size=true;
+ else if(wcscmp(formatConfig.pPropDesc[j].pwszPropName,g_wszWMDMAlbumCoverData)==0) data=true;
+ else if(wcscmp(formatConfig.pPropDesc[j].pwszPropName,g_wszWMDMAlbumCoverFormat)==0) format=true;
+ }
+ }
+ }
+ if(size && data && format) requiresALB=true;
+ FreeFormatCapability(formatCapList);
+ }
+
+ devices.Add(this);
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICECONNECTED);
+
+ //transcoder = NULL;
+ transcoder = (Transcoder*)SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)this,PMP_IPC_GET_TRANSCODER);
+ if(transcoder) {
+ if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MP3,WMDevice)))
+ transcoder->AddAcceptableFormat(L"mp3");
+ //transcoder->AddAcceptableFormat(L"wav");
+ if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_WMA,WMDevice)))
+ transcoder->AddAcceptableFormat(L"wma");
+ if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_ASF,WMDevice)))
+ transcoder->AddAcceptableFormat(L"asf");
+ if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_AVI,WMDevice)))
+ transcoder->AddAcceptableFormat(L"avi");
+ if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_OGG,WMDevice)))
+ transcoder->AddAcceptableFormat(L"ogg");
+ if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_FLAC,WMDevice)))
+ transcoder->AddAcceptableFormat(L"flac");
+ if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_AUDIBLE,WMDevice)))
+ transcoder->AddAcceptableFormat(L"aa");
+ if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MPEG,WMDevice))) {
+ transcoder->AddAcceptableFormat(L"mpeg");
+ transcoder->AddAcceptableFormat(L"mpg");
+ }
+ if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_WMV,WMDevice)))
+ transcoder->AddAcceptableFormat(L"wmv");
+ if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_3GP,WMDevice)))
+ transcoder->AddAcceptableFormat(L"3gp");
+ if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MP4,WMDevice))) {
+ transcoder->AddAcceptableFormat(L"mp4");
+ transcoder->AddAcceptableFormat(L"m4a");
+ }
+ if(noMetadata || SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_AAC,WMDevice))) {
+ transcoder->AddAcceptableFormat(L"m4a");
+ transcoder->AddAcceptableFormat(L"mp4");
+ transcoder->AddAcceptableFormat(L"aac");
+ }
+ }
+}
+
+static void commitPlaylist(Playlist * pl) {
+ int l = pl->songs.GetSize();
+ IWMDMStorage ** newOrder = (IWMDMStorage **)calloc(l, sizeof(IWMDMStorage *));
+ for(int j=0; j<l; j++) ((Song *)pl->songs.Get(j))->storage->QueryInterface(&newOrder[j]);
+ pl->storage->SetReferences(l, newOrder);
+ for(int i=0; i<l; i++) newOrder[i]->Release();
+ free(newOrder);
+ pl->modified = false;
+}
+
+P4SDevice::~P4SDevice() {
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
+ if(playlistsDir) playlistsDir->Release();
+ for(int i=1; i<playlists.GetSize(); i++) {
+ Playlist * pl = (Playlist*)playlists.Get(i);
+ if(pl->modified) commitPlaylist(pl);
+ pl->storage->Release();
+ pl->meta->Release();
+ }
+ if(playlists.GetSize()) {
+ Playlist * pl = (Playlist*)playlists.Get(0);
+ pl->storage->Release();
+ for(int j=0; j < pl->songs.GetSize(); j++) {
+ Song * s = (Song *)pl->songs.Get(j);
+ if (s)
+ {
+ if(s->modified) s->storage->SetMetadata(s->meta);
+ s->meta->Release();
+ s->storage->Release();
+ delete s;
+ }
+ }
+ }
+
+ for(int i=0; i<devices.GetSize(); i++) {
+ if(devices.Get(i) == (void*)this) {
+ devices.Del(i);
+ return;
+ }
+ }
+ WMDevice->Release();
+ if(transcoder) SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)transcoder,PMP_IPC_RELEASE_TRANSCODER);
+}
+
+ void P4SDevice::Close()
+ {
+ delete this;
+ }
+
+__int64 P4SDevice::getDeviceCapacityAvailable() {
+ static __int64 prev;
+ IWMDMStorageGlobals * sg = NULL;
+ if(!playlistsDir) return 0;
+ playlistsDir->GetStorageGlobals(&sg);
+ if(sg) {
+ ULARGE_INTEGER s;
+ sg->GetTotalFree(&s.LowPart,&s.HighPart);
+ sg->Release();
+ if(s.LowPart == 0 && s.HighPart == 0) return prev;
+ return prev = s.QuadPart;
+ }
+ return prev;
+}
+
+__int64 P4SDevice::getDeviceCapacityTotal() {
+ static __int64 prev;
+ IWMDMStorageGlobals * sg = NULL;
+ if(!playlistsDir) return 0;
+ playlistsDir->GetStorageGlobals(&sg);
+ if(sg) {
+ ULARGE_INTEGER s;
+ sg->GetTotalSize(&s.LowPart,&s.HighPart);
+ sg->Release();
+ if(s.LowPart == 0 && s.HighPart == 0) return prev;
+ return prev = s.QuadPart;
+ }
+ return prev;
+}
+
+void P4SDevice::deleteTrack(songid_t songid) {
+ lastChange=NULL;
+ Song * s = (Song*)songid;
+ IWMDMStorageControl3 * storeControl=NULL;
+ s->storage->QueryInterface(&storeControl);
+ if(!storeControl) return;
+ for(int i=0; i<playlists.GetSize(); i++) {
+ Playlist * pl = (Playlist *)playlists.Get(i);
+ int j = pl->songs.GetSize();
+ while(j-- > 0) if((Song *)pl->songs.Get(j) == s) { pl->songs.Del(j); pl->modified=true; }
+ }
+ if(storeControl->Delete(WMDM_MODE_BLOCK,NULL) != S_OK) return;
+ s->meta->Release();
+ s->storage->Release();
+ storeControl->Release();
+ delete s;
+}
+
+void P4SDevice::commitChanges() {
+ for(int i=1; i<playlists.GetSize(); i++) {
+ Playlist * pl = (Playlist*)playlists.Get(i);
+ if(pl->modified) commitPlaylist(pl);
+ }
+
+ Playlist * pl = (Playlist*)playlists.Get(0);
+ for(int j=0; j < pl->songs.GetSize(); j++) {
+ Song * s = (Song *)pl->songs.Get(j);
+ if(s->modified) {
+ s->storage->SetMetadata(s->meta);
+ s->meta->Release();
+ s->storage->GetMetadata(&s->meta);
+ s->modified = false;
+ }
+ }
+ lastChange=NULL;
+}
+
+static int fileSizeA(char * filename)
+{
+ FILE * fh = fopen(filename,"rb");
+ if(!fh) return -1;
+ fseek(fh,0,2); //seek to end;
+ int l = ftell(fh);
+ fclose(fh);
+ return l;
+}
+
+#define MKVALIDFN(x) { wchar_t * n = x; while(n && *n == L'.') *(n++)=L'_'; while(n && *n) { if(*n == L'|' || *n == L'\\' || *n == L'/' || *n == L'?' || *n == L'<' || *n == L'>' || *n == L':' || *n == L'*' || *n == L'"') *n=L'_'; n++; } n = x+wcslen(x)-1; while(n && *n==L'.' && n>=x) *(n--)=0; }
+
+static IWMDMStorage4* GetOrCreateFolder(IWMDMStorage4 * store, wchar_t * name, P4SDevice * dev, bool album, const itemRecordW * item) {
+ if(!name[0]) name=L"Blank";
+ MKVALIDFN(name);
+ if(!name[0]) name=L"Blank";
+ if(!store) return NULL;
+ IWMDMEnumStorage * enstore=NULL;
+ HRESULT hr = store->EnumStorage(&enstore);
+ IWMDMStorage * store0;
+ IWMDMStorage4 * store4;
+ ULONG num;
+ if(!enstore) return NULL;
+ enstore->Reset();
+ hr = enstore->Next(1,&store0,&num);
+ while(hr == S_OK) {
+ store4=NULL;
+ store0->QueryInterface(&store4);
+ store0->Release();
+ wchar_t buf[100] = {0};
+ store4->GetName(buf,100);
+ if(_wcsicmp(buf,name) == 0) {
+ return store4;
+ }
+ store4->Release();
+ hr = enstore->Next(1,&store0,&num);
+ }
+ if(enstore) enstore->Release();
+ // we must create it!
+ store0=store4=NULL;
+ IWMDMStorageControl3 * storeControl=NULL;
+ store->QueryInterface(&storeControl);
+ if(!storeControl) return NULL;
+ IWMDMMetaData * meta;
+ store->CreateEmptyMetadataObject(&meta);
+ storeControl->Insert3(WMDM_MODE_BLOCK|WMDM_CONTENT_FOLDER,WMDM_FILE_ATTR_FOLDER,NULL,name,NULL,NULL,meta,NULL,&store0);
+ meta->Release();
+ if(!store0) return NULL;
+ store0->QueryInterface(&store4);
+ storeControl->Release();
+ store0->Release();
+ store->Release();
+ if(album) {
+ wchar_t buffer[MAX_PATH];
+ IWMDMStorageControl3 * storeControl;
+ wsprintf(buffer,L"%s.alb",name);
+ store4->QueryInterface(&storeControl);
+ IWMDMStorage * newpl=NULL;
+ IWMDMStorage4 * newpl4=NULL;
+ IWMDMMetaData * meta=NULL;
+ store4->CreateEmptyMetadataObject(&meta);
+ if (meta)
+ {
+ DWORD formatCode = WMDM_FORMATCODE_ABSTRACTAUDIOALBUM;
+ meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMFormatCode,(BYTE*)&formatCode,sizeof(DWORD));
+ meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumTitle,(BYTE*)name,(wcslen(name)*2)+2);
+ meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumArtist,(BYTE*)((wchar_t*)item->albumartist),(wcslen(item->albumartist)*2)+2);
+ meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMTitle,(BYTE*)name,(wcslen(name)*2)+2);
+ meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAuthor,(BYTE*)((wchar_t*)item->artist),(wcslen(item->artist)*2)+2);
+ meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMGenre,(BYTE*)((wchar_t*)item->genre),(wcslen(item->genre)*2)+2);
+ storeControl->Insert3(WMDM_MODE_BLOCK | WMDM_CONTENT_FILE,0,NULL,buffer,NULL,NULL,meta,NULL,&newpl);
+ storeControl->Release();
+ if (newpl)
+ {
+ newpl->QueryInterface(&newpl4);
+ newpl->Release();
+ }
+ if (newpl4)
+ {
+ newpl4->SetReferences(0,NULL);
+ newpl4->SetMetadata(meta);
+ newpl4->Release();
+ }
+ meta->Release();
+ }
+ }
+ return store4;
+}
+
+// Disabled for 5.64
+// Fixes issues with exit failures and duplicates on transfer (view issue only) and other memory corruption issues
+/*typedef struct {
+ C_ItemList * playlists;
+ void * item;
+} addTrackStruct;
+
+void CALLBACK addTrack(ULONG_PTR dwParam) {
+ addTrackStruct * a = (addTrackStruct *) dwParam;
+ ((Playlist*)a->playlists->Get(0))->songs.Add(a->item);
+ delete a;
+}*/
+
+static void getTime(__time64_t value, _WMDMDATETIME * time) {
+ if(!time) return;
+ ZeroMemory(time,sizeof(_WMDMDATETIME));
+ struct tm * t = _localtime64(&value);
+ if(!t) return;
+ time->wYear = t->tm_year;
+ time->wMonth = t->tm_mon;
+ time->wDay = t->tm_mday;
+ time->wHour = t->tm_hour;
+ time->wMinute = t->tm_min;
+ time->wSecond = t->tm_sec;
+}
+
+static int atoi_nullok(char * str) {
+ if(str) return atoi(str);
+ return 0;
+}
+
+static IWMDMStorage * storefoo;
+
+#define PHASE_START 1
+#define PHASE_INPROGRESS 2
+#define PHASE_FINISH 3
+#define PHASE_DONE 4
+#define PHASE_ERROR 5
+
+extern CSecureChannelClient SAC;
+extern int SynchronousProcedureCall(void * p, ULONG_PTR dwParam);
+
+void P4SDevice::doTransfer(TransferItem * t) {
+ static wchar_t buf[256];
+ static IWMDMStorage4 * store;
+ static IWMDMStorageControl3 * control;
+
+ switch(t->phase) {
+ case PHASE_START:
+ {
+ bool video = false;
+ DWORD formatCode=0;
+ wchar_t * point = wcsrchr(t->file,L'.');
+ if(point) {
+ if(_wcsicmp(point,L".wma")==0) formatCode = WMDM_FORMATCODE_WMA;
+ else if(_wcsicmp(point,L".wav")==0) formatCode = WMDM_FORMATCODE_WAVE;
+ else if(_wcsicmp(point,L".ogg")==0) formatCode = WMDM_FORMATCODE_OGG;
+ else if(_wcsicmp(point,L".m4a")==0) formatCode = WMDM_FORMATCODE_MP4;
+ else if(_wcsicmp(point,L".aac")==0) formatCode = WMDM_FORMATCODE_AAC;
+ else if(_wcsicmp(point,L".aa")==0) formatCode = WMDM_FORMATCODE_AUDIBLE;
+ else if(_wcsicmp(point,L".flac")==0 || _wcsicmp(point,L".fla")==0) formatCode = WMDM_FORMATCODE_FLAC;
+ else if(_wcsicmp(point,L".asf")==0) { video=true; formatCode = WMDM_FORMATCODE_ASF; }
+ else if(_wcsicmp(point,L".avi")==0) { video=true; formatCode = WMDM_FORMATCODE_AVI; }
+ else if(_wcsicmp(point,L".mpg")==0) { video=true; formatCode = WMDM_FORMATCODE_MPEG; }
+ else if(_wcsicmp(point,L".mpeg")==0) { video=true; formatCode = WMDM_FORMATCODE_MPEG; }
+ else if(_wcsicmp(point,L".wmv")==0) { video=true; formatCode = WMDM_FORMATCODE_WMV; }
+ else if(_wcsicmp(point,L".m4v")==0) { video=true; formatCode = WMDM_FORMATCODE_MP4; }
+ else if(_wcsicmp(point,L".mp2")==0) { video=true; formatCode = WMDM_FORMATCODE_MP2; }
+ else if(_wcsicmp(point,L".mp4")==0) {
+ wchar_t buf[10]=L"0";
+ extendedFileInfoStructW m = {t->file,L"type",buf,10};
+ SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&m,IPC_GET_EXTENDED_FILE_INFOW);
+ formatCode = WMDM_FORMATCODE_MP4;
+ video = (buf[0]==L'1');
+ }
+ else formatCode = WMDM_FORMATCODE_MP3; // mp3 or whatever
+ }
+ t->video = video;
+
+ store = ((Playlist *)playlists.Get(0))->storage;
+ store->AddRef();
+
+ if(video) {
+ store = GetOrCreateFolder(store,videoDir,this);
+ if(_wcsicmp(t->track->artist,L"")) store = GetOrCreateFolder(store,t->track->artist);
+ } else {
+ store = GetOrCreateFolder(store,musicDir,this);
+ if(_wcsicmp(t->track->artist,L"")) store = GetOrCreateFolder(store,t->track->artist);
+ else store = GetOrCreateFolder(store,L"No Artist");
+ if(_wcsicmp(t->track->album,L"")) store = GetOrCreateFolder(store,t->track->album,this,requiresALB,t->track);
+ else store = GetOrCreateFolder(store,L"No Album");
+ }
+ /*
+ DWORD dw;
+ do {
+ WMDevice->GetStatus(&dw);
+ SleepEx(50,true);
+ } while(!(dw & WMDM_STATUS_READY));
+ */
+ if(!store) {
+ t->callback(t->callbackContext,WASABI_API_LNGSTRINGW(IDS_COUND_NOT_CREATE_FOLDER));
+ *(t->songid)=NULL;
+ t->phase=PHASE_ERROR;
+ return;
+ }
+
+ // create and fill in metadata...
+
+ HRESULT hr;
+ hr = store->CreateEmptyMetadataObject(&t->meta);
+ if(hr != S_OK) {
+ wchar_t buf[100] = {0};
+ wsprintf(buf,WASABI_API_LNGSTRINGW(IDS_COULD_NOT_CREATE_METADATA),hr);
+ t->callback(t->callbackContext,buf);
+ *(t->songid)=NULL;
+ t->phase=PHASE_ERROR;
+ return;
+ }
+ t->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMFormatCode,(BYTE*)&formatCode,sizeof(DWORD));
+ if(t->track->artist) t->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAuthor,(BYTE*)((wchar_t*)(t->track->artist)),(wcslen(t->track->artist)*2)+2);
+ if(t->track->albumartist) t->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumArtist,(BYTE*)((wchar_t*)(t->track->albumartist)),(wcslen(t->track->albumartist)*2)+2);
+ if(t->track->composer) t->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMComposer,(BYTE*)((wchar_t*)(t->track->composer)),(wcslen(t->track->composer)*2)+2);
+ if(t->track->album) t->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumTitle,(BYTE*)((wchar_t*)(t->track->album)),(wcslen(t->track->album)*2)+2);
+ if(t->track->genre) t->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMGenre,(BYTE*)((wchar_t*)(t->track->genre)),(wcslen(t->track->genre)*2)+2);
+ if(t->track->title) t->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMTitle,(BYTE*)((wchar_t*)(t->track->title)),(wcslen(t->track->title)*2)+2);
+ if(t->track->track> 0) t->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMTrack,(BYTE*)&t->track->track,sizeof(DWORD));
+ __int64 len = t->track->length;
+ len *= 10000000;
+ wchar_t buf2[256] = {0};
+ t->meta->AddItem(WMDM_TYPE_QWORD,g_wszWMDMDuration,(BYTE*)&len,sizeof(__int64));
+ int fs = fileSizeA(AutoChar(t->file));
+ len = fs;
+ t->meta->AddItem(WMDM_TYPE_QWORD,g_wszWMDMFileSize,(BYTE*)&len,sizeof(__int64));
+ wsprintf(buf2,L"%d",t->track->year);
+ if(t->track->year > 0) t->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMYear,(BYTE*)buf2,(wcslen(buf2)*2) + 2);
+ int v;
+ if (t->track->length)
+ {
+ v = 8*(fs/t->track->length); //atoi_nullok(getRecordExtendedItem(t->track,"BITRATE")) * 1000;
+ t->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMBitrate,(BYTE*)&v,sizeof(DWORD));
+ }
+ v = t->track->playcount;
+ t->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMPlayCount,(BYTE*)&v,sizeof(DWORD));
+ v = t->track->rating;
+ if(v>=0 && v<=5) t->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMUserRating,(BYTE*)&v,sizeof(DWORD));
+ _WMDMDATETIME time1={0}, time2={0};
+ getTime(t->track->lastplay,&time1);
+ t->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMUserLastPlayTime,(BYTE*)&time1,sizeof(DWORD));
+ getTime(t->track->lastupd,&time2);
+ t->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMLastModifiedDate,(BYTE*)&time2,sizeof(DWORD));
+
+ control = NULL;
+ store->QueryInterface(&control);
+ IWMDMStorage * newstore=NULL;
+
+ if(video) wsprintf(buf,L"%s%s",(wchar_t*)(t->track->title),(wchar_t*)(wcsrchr(t->track->filename,'.')));
+ else wsprintf(buf,L"%02d - %s%s",t->track->track,(wchar_t*)(t->track->title),(wchar_t*)(wcsrchr(t->track->filename,'.')));
+
+ if(video) wsprintf(buf,L"%s%s",(wchar_t*)(t->track->title),wcsrchr(t->file,L'.'));
+ else wsprintf(buf,L"%02d - %s%s",t->track->track,(wchar_t*)(t->track->title),wcsrchr(t->file,L'.'));
+ MKVALIDFN(buf);
+
+ if(!control) {
+ t->callback(t->callbackContext,WASABI_API_LNGSTRINGW(IDS_INCOMPATABLE_DEVICE));
+ *(t->songid)=NULL;
+ t->phase = PHASE_ERROR;
+ return;
+ }
+
+ t->phase = PHASE_INPROGRESS;
+ t->progress = new MyProgress(t);
+ storefoo = NULL;
+
+ hr = control->Insert3(WMDM_MODE_BLOCK|WMDM_MODE_TRANSFER_PROTECTED|WMDM_CONTENT_FILE|WMDM_STORAGECONTROL_INSERTAFTER,
+ WMDM_FILE_ATTR_FILE,
+ t->file,
+ buf,
+ NULL,
+ t->progress,
+ t->meta,
+ NULL,
+ &storefoo);
+ //OutputDebugString(L"finished insert");
+
+ if (FAILED(hr)) {
+ wchar_t buf1[100] = {0};
+ wsprintf(buf1,WASABI_API_LNGSTRINGW(IDS_ERROR_IN_INSERT),hr);
+ t->callback(t->callbackContext,buf1);
+ *(t->songid)=NULL;
+ t->phase = PHASE_ERROR;
+ return;
+ }
+ }
+ break;
+ case PHASE_FINISH:
+ //OutputDebugString(L"phase finish start");
+ {
+ /*
+ DWORD dw;
+ WMDevice->GetStatus(&dw);
+ while(!(dw == WMDM_STATUS_READY)) {
+ SleepEx(50,true);
+ WMDevice->GetStatus(&dw);
+ }
+ */
+ }
+
+ t->progress->Release();
+ control->Release();
+
+ if(storefoo) { /*OutputDebugString(L"storefoo");*/ storefoo->Release(); storefoo=NULL; }
+ if(store) {
+ IWMDMStorage * store0 = NULL;
+ store->GetStorage(buf,&store0);
+ store->Release();
+ if(store0) {
+ IWMDMStorage4 * store4 = NULL;
+ store0->QueryInterface(&store4);
+ if(store4) {
+ store4->AddRef();
+ store0->Release();
+ store4->SetMetadata(t->meta);
+ //t->meta->Release();
+ Song * song = new Song;
+ song->modified=false;
+ song->storage = store4;
+ song->meta = t->meta;
+ song->video = t->video;
+ //((Playlist*)playlists.Get(0))->songs.Add(song);
+
+ // Disabled for 5.64
+ // Fixes issues with exit failures and duplicates on transfer (view issue only) and other memory corruption issues
+/*
+ addTrackStruct * a = new addTrackStruct;
+ a->item=song;
+ a->playlists = &playlists;
+ //PostMessage(plugin.hwndPortablesParent,WM_USER+3,(WPARAM)addTrack,(LPARAM)a);
+ SynchronousProcedureCall((void*)addTrack,(ULONG_PTR)a);
+*/
+
+ *(t->songid) = (songid_t)song;
+ // sort out the album group...
+ if(t->track->album && requiresALB) {
+ IWMDMStorage * album0=NULL;
+ IWMDMStorage * parent=NULL;
+ IWMDMStorage4 * parent4=NULL;
+ IWMDMStorage4 * album4;
+ wchar_t buf[512] = {0};
+ wsprintf(buf,L"%s.alb",(wchar_t*)(t->track->album));
+ store4->GetParent(&parent);
+ if (parent)
+ {
+ parent->QueryInterface(&parent4);
+ parent->Release();
+ if (parent4)
+ {
+ parent4->GetStorage(buf,&album0);
+ parent4->Release();
+ if(album0) {
+ album0->QueryInterface(&album4);
+ album0->Release();
+ DWORD refc;
+ IWMDMStorage ** refs;
+ IWMDMStorage ** newrefs;
+ album4->GetReferences(&refc,&refs);
+ newrefs = (IWMDMStorage **)calloc((refc + 1), sizeof(void*));
+ for(DWORD i=0; i<refc; i++) newrefs[i] = refs[i];
+ newrefs[refc] = store4;
+ refc++;
+ album4->SetReferences(refc,newrefs);
+ refc--;
+ for(DWORD i=0; i<refc; i++) refs[i]->Release();
+ free(newrefs);
+ CoTaskMemFree(refs);
+ song->alb = album4;
+ album4->GetMetadata(&song->albmeta);
+ //album4->Release();
+
+ int w,h;
+ ARGB32 *bits;
+ if (AGAVE_API_ALBUMART->GetAlbumArt(t->file, L"cover", &w, &h, &bits) == ALBUMART_SUCCESS)
+ {
+ setArt((songid_t)song,bits,w,h);
+ WASABI_API_MEMMGR->sysFree(bits);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if(!*t->songid) t->callback(t->callbackContext,WASABI_API_LNGSTRINGW(IDS_UNSPECIFIED_ERROR));
+ t->phase = PHASE_DONE;
+ //OutputDebugString(L"phase finish finished");
+ break;
+ }
+}
+
+int P4SDevice::transferTrackToDevice(const itemRecordW * track,void * callbackContext,void (*callback)(void * callbackContext, wchar_t * status),songid_t * songid,int * killswitch) {
+ wchar_t file[2048] = {0};
+ StringCchCopy(file, ARRAYSIZE(file), track->filename);
+ bool deletefile = false;
+ if(transcoder) if(transcoder->ShouldTranscode(file)) {
+ wchar_t newfile[MAX_PATH] = {0};
+ wchar_t ext[10] = {0};
+ transcoder->CanTranscode(file,ext);
+ transcoder->GetTempFilePath(ext,newfile);
+ if(transcoder->TranscodeFile(file,newfile,killswitch,callback,callbackContext)) return -1;
+ StringCchCopy(file, ARRAYSIZE(file), newfile);
+ deletefile=true;
+ }
+
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_WAITING_FOR_OTHER_TRANSFERS));
+ EnterCriticalSection(&csTransfers); // only one transfer at once, globally :(
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_TRANSFERRING));
+ TransferItem t;
+ t.file = file;
+ t.track = track;
+ t.callback = callback;
+ t.callbackContext = callbackContext;
+ t.killswitch = killswitch;
+ t.songid = songid;
+ t.dev = this;
+ t.phase = PHASE_START;
+ t.pc = 0;
+ *songid = NULL;
+ this->doTransfer(&t); // do the transfer
+ if(t.phase == PHASE_FINISH) this->doTransfer(&t); // finish it, if needs be.
+
+ int ret = (*songid)?0:-1;
+ if(ret==0) callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_DONE));
+ trackRemovedFromTransferQueue(track);
+ LeaveCriticalSection(&csTransfers);
+ if(deletefile) _wunlink(file);
+ return ret;
+}
+
+bool extentionSupported(IWMDMDevice3* WMDevice, wchar_t * ext,bool aac_and_m4a_support, bool video_supported) {
+ if(!ext) return false;
+ bool supported=false;
+
+ if(!_wcsicmp(ext,L".mp3")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MP3,WMDevice));
+ else if(!_wcsicmp(ext,L".wma")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_WMA,WMDevice));
+ else if(!_wcsicmp(ext,L".wav")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_WAVE,WMDevice));
+ else if(!_wcsicmp(ext,L".aa")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_AUDIBLE,WMDevice));
+ else if(!_wcsicmp(ext,L".m4a") || !_wcsicmp(ext,L".aac")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_AAC,WMDevice)) || SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MP4,WMDevice));
+ else if(!_wcsicmp(ext,L".ogg")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_OGG,WMDevice));
+ else if(!_wcsicmp(ext,L".flac") || !_wcsicmp(ext,L".fla")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_FLAC,WMDevice));
+ else if(!_wcsicmp(ext,L".avi")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_AVI,WMDevice));
+ else if(!_wcsicmp(ext,L".mpg") || !_wcsicmp(ext,L".mpeg")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MPEG,WMDevice));
+ else if(!_wcsicmp(ext,L".asf")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_ASF,WMDevice));
+ else if(!_wcsicmp(ext,L".wmv")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_WMV,WMDevice));
+ else if(!_wcsicmp(ext,L".mp4")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MP4,WMDevice)) || SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_AAC,WMDevice));
+ else if(!_wcsicmp(ext,L".m4v")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MP4,WMDevice));
+ else if(!_wcsicmp(ext,L".mp2")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MP2,WMDevice));
+ else if(!_wcsicmp(ext,L".3gp")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_3GP,WMDevice));
+ else return false;
+
+ if(!supported) {
+ if(!_wcsicmp(ext,L".mp3") || !_wcsicmp(ext,L".wma") || !_wcsicmp(ext,L".wav")) supported=true;
+ if(aac_and_m4a_support && (!_wcsicmp(ext,L".m4a") || !_wcsicmp(ext,L".aac"))) supported=true;
+ if(video_supported && (!_wcsicmp(ext,L".asf") || !_wcsicmp(ext,L".avi") || !_wcsicmp(ext,L".mpeg") || !_wcsicmp(ext,L".mpg") || !_wcsicmp(ext,L".wmv"))) supported=true;
+ }
+ return supported;
+}
+/*
+bool extentionSupported(wchar_t * ext,bool aac_and_m4a_support) {
+ if(!ext) return false;
+ if(_wcsicmp(ext,L".mp3") && _wcsicmp(ext,L".wma") && _wcsicmp(ext,L".wav")
+ && (aac_and_m4a_support || (_wcsicmp(ext,L".m4a") && _wcsicmp(ext,L".aac")))
+ ) return false;
+ return true;
+}
+*/
+static __int64 fileSize(wchar_t * filename)
+{
+ WIN32_FIND_DATA f={0};
+ HANDLE h = FindFirstFileW(filename,&f);
+ if(h == INVALID_HANDLE_VALUE) return -1;
+ FindClose(h);
+ ULARGE_INTEGER i;
+ i.HighPart = f.nFileSizeHigh;
+ i.LowPart = f.nFileSizeLow;
+ return i.QuadPart;
+}
+
+int P4SDevice::trackAddedToTransferQueue(const itemRecordW * track) {
+ __int64 l;
+ if(transcoder && transcoder->ShouldTranscode(track->filename)) {
+ int k = transcoder->CanTranscode(track->filename);
+ if(k == -1) return -2;
+ if(k == 0) l = (__int64)fileSize(track->filename);
+ else l = (__int64)k;
+ } else {
+ wchar_t * ext = wcsrchr(track->filename,'.');
+ if(!extentionSupported(WMDevice,ext,noMetadata,supportsVideo)) return -2; // fucko: assumes all noMetadata devices are nokia (which is true for now)
+ l = (__int64)fileSize(track->filename);
+ }
+ __int64 test = l;
+ __int64 avail = getDeviceCapacityAvailable();
+ test += transferQueueSize;
+ //test += (__int64)3000000;
+ if(test > avail) return -1;
+ transferQueueSize += l;
+ return 0;
+}
+
+void P4SDevice::trackRemovedFromTransferQueue(const itemRecordW * track) {
+ __int64 l = (__int64)fileSize(track->filename);
+ if(transcoder && transcoder->ShouldTranscode(track->filename)) {
+ int k = transcoder->CanTranscode(track->filename);
+ if(k != -1 && k != 0) l = (__int64)k;
+ }
+ transferQueueSize -= l;
+}
+
+__int64 P4SDevice::getTrackSizeOnDevice(const itemRecordW * track) {
+ if(transcoder && transcoder->ShouldTranscode(track->filename)) {
+ int k = transcoder->CanTranscode(track->filename);
+ if(k != -1 && k != 0) return k;
+ }
+ wchar_t * ext = wcsrchr(track->filename,'.');
+ if(!extentionSupported(WMDevice,ext,noMetadata,supportsVideo)) return 0; // fucko: assumes all noMetadata devices are nokia (which is true for now)
+ return fileSize(track->filename);
+}
+
+int P4SDevice::getPlaylistCount() {
+ return playlists.GetSize();
+}
+
+static BYTE* GetMetadataItem(IWMDMMetaData *meta, const WCHAR * name) {
+ WMDM_TAG_DATATYPE type;
+ BYTE * value=NULL;
+ UINT len;
+ if(!meta) { return (BYTE*)""; } // OutputDebugString(L"no meta");
+ if((meta->QueryByName(name,&type,&value,&len)) != S_OK) { return NULL; /*value;*/ } //wchar_t buf[100]; wsprintf(buf,L"meta fail: %x %s",hr,name); OutputDebugString(buf);
+ return value;
+}
+
+static BYTE* GetMetadataItem(Song * song, const WCHAR * name) {
+ WMDM_TAG_DATATYPE type;
+ BYTE * value=NULL;
+ UINT len;
+ if(!song || !(song->meta)) { return (BYTE*)""; } // OutputDebugString(L"no meta");
+ if((song->meta->QueryByName(name,&type,&value,&len)) != S_OK) { return NULL; /*value;*/ } //wchar_t buf[100]; wsprintf(buf,L"meta fail: %x %s",hr,name); OutputDebugString(buf);
+ return value;
+}
+
+void P4SDevice::getPlaylistName(int playlistnumber, wchar_t * buf, int len)
+{
+ if (NULL == buf)
+ return;
+
+ if(playlistnumber == 0)
+ {
+ if (NULL == WMDevice)
+ buf[0] = L'\0';
+ else
+ {
+ HRESULT hr;
+ hr = WMDevice->GetName(buf, len);
+ if (FAILED(hr))
+ {
+ buf[0] = L'\0';
+ }
+ }
+ }
+ else
+ {
+ StringCchCopy(buf, len, ((Playlist *)playlists.Get(playlistnumber))->name);
+ }
+}
+
+int P4SDevice::getPlaylistLength(int playlistnumber) {
+ if(playlistnumber == -1) return 0;
+ return ((Playlist*)playlists.Get(playlistnumber))->songs.GetSize();
+}
+
+songid_t P4SDevice::getPlaylistTrack(int playlistnumber,int songnum) {
+ if(playlistnumber == -1) return NULL;
+ return (songid_t)((Playlist*)playlists.Get(playlistnumber))->songs.Get(songnum);
+}
+
+void P4SDevice::setPlaylistName(int playlistnumber, const wchar_t *buf) {
+ if(playlistnumber == -1) return;
+ IWMDMStorageControl3 * storeControl=NULL;
+ Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
+ lstrcpyn(pl->name,buf,128);
+ pl->storage->QueryInterface(&storeControl);
+ pl->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMTitle,(BYTE*)buf,(wcslen(buf)*2)+2);
+ pl->storage->SetMetadata(pl->meta);
+ wchar_t buffer[256] = {0};
+ wsprintf(buffer,L"%s.%s",buf,plext);
+ if(storeControl) {
+ storeControl->Rename(WMDM_MODE_BLOCK,buffer,NULL);
+ storeControl->Release();
+ }
+}
+
+int sortby;
+//Device * sortDev;
+
+#define SKIP_THE_AND_WHITESPACE(x) { while (!iswalnum(*x) && *x) x++; if (!_wcsnicmp(x,L"the ",4)) x+=4; while (*x == L' ') x++; }
+int STRCMP_NULLOK(const wchar_t *pa, const wchar_t *pb) {
+ if (!pa) pa=L"";
+ else SKIP_THE_AND_WHITESPACE(pa)
+ if (!pb) pb=L"";
+ else SKIP_THE_AND_WHITESPACE(pb)
+ return lstrcmpi(pa,pb);
+}
+#undef SKIP_THE_AND_WHITESPACE
+
+static int sortFunc(const void *elem1, const void *elem2)
+{
+ int use_by = sortby;
+ songid_t a=(songid_t)*(songid_t *)elem1;
+ songid_t b=(songid_t)*(songid_t *)elem2;
+
+#define RETIFNZ(v) if ((v)!=0) return v;
+
+ // this might be too slow, but it'd be nice
+ int x;
+ for (x = 0; x < 5; x ++)
+ {
+ if (use_by == SORTBY_TITLE) // title -> artist -> album -> disc -> track
+ {
+ wchar_t bufa[2048] = {0};
+ wchar_t bufb[2048] = {0};
+ sortDev->getTrackTitle(a,bufa,2048);
+ sortDev->getTrackTitle(b,bufb,2048);
+ int v=STRCMP_NULLOK(bufa,bufb);
+ RETIFNZ(v)
+ use_by=SORTBY_ARTIST;
+ }
+ else if (use_by == SORTBY_ARTIST) // artist -> album -> disc -> track -> title
+ {
+ wchar_t bufa[2048] = {0};
+ wchar_t bufb[2048] = {0};
+ sortDev->getTrackArtist(a,bufa,2048);
+ sortDev->getTrackArtist(b,bufb,2048);
+ int v=STRCMP_NULLOK(bufa,bufb);
+ RETIFNZ(v)
+ use_by=SORTBY_ALBUM;
+ }
+ else if (use_by == SORTBY_ALBUM) // album -> disc -> track -> title -> artist
+ {
+ wchar_t bufa[2048] = {0};
+ wchar_t bufb[2048] = {0};
+ sortDev->getTrackAlbum(a,bufa,2048);
+ sortDev->getTrackAlbum(b,bufb,2048);
+ int v=STRCMP_NULLOK(bufa,bufb);
+ RETIFNZ(v)
+ use_by=SORTBY_DISCNUM;
+ }
+ else if (use_by == SORTBY_DISCNUM) // disc -> track -> title -> artist -> album
+ {
+ int v1=sortDev->getTrackDiscNum(a);
+ int v2=sortDev->getTrackDiscNum(b);
+ if (v1<0)v1=0;
+ if (v2<0)v2=0;
+ RETIFNZ(v1-v2)
+ use_by=SORTBY_TRACKNUM;
+ }
+ else if (use_by == SORTBY_TRACKNUM) // track -> title -> artist -> album -> disc
+ {
+ int v1=sortDev->getTrackTrackNum(a);
+ int v2=sortDev->getTrackTrackNum(b);
+ if (v1<0)v1=0;
+ if (v2<0)v2=0;
+ RETIFNZ(v1-v2)
+ use_by=SORTBY_TITLE;
+ }
+ else if (use_by == SORTBY_GENRE) // genre -> artist -> album -> disc -> track
+ {
+ wchar_t bufa[2048] = {0};
+ wchar_t bufb[2048] = {0};
+ sortDev->getTrackGenre(a,bufa,2048);
+ sortDev->getTrackGenre(b,bufb,2048);
+ int v=STRCMP_NULLOK(bufa,bufb);
+ RETIFNZ(v)
+ use_by=SORTBY_ARTIST;
+ }
+ else if (use_by == SORTBY_PLAYCOUNT) // size -> artist -> album -> disc -> track
+ {
+ int v1=sortDev->getTrackPlayCount(a);
+ int v2=sortDev->getTrackPlayCount(b);
+ if (v1<0)v1=0;
+ if (v2<0)v2=0;
+ RETIFNZ(v1-v2)
+ use_by=SORTBY_ARTIST;
+ }
+ else if (use_by == SORTBY_RATING) // size -> artist -> album -> disc -> track
+ {
+ int v1=sortDev->getTrackRating(a);
+ int v2=sortDev->getTrackRating(b);
+ if (v1<0)v1=0;
+ if (v2<0)v2=0;
+ RETIFNZ(v1-v2)
+ use_by=SORTBY_ARTIST;
+ }
+ else if (use_by == SORTBY_LASTPLAYED)
+ {
+ __time64_t la = sortDev->getTrackLastPlayed(a);
+ __time64_t lb = sortDev->getTrackLastPlayed(b);
+ double t = difftime((time_t)la,(time_t)lb);
+ int v = t>0?1:(t<0?-1:0);
+ RETIFNZ(v)
+ use_by=SORTBY_ARTIST;
+ }
+ else break; // no sort order?
+ }
+
+ return 0;
+}
+
+void P4SDevice::sortPlaylist(int playlistnumber, int sortBy) {
+ if(playlistnumber == -1) return;
+ sortby = sortBy;
+ sortDev = this;
+ Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
+ qsort(pl->songs.GetAll(),pl->songs.GetSize(),sizeof(void*),sortFunc);
+ pl->modified = true;
+}
+
+void P4SDevice::playlistSwapItems(int playlistnumber, int posA, int posB) {
+ if(playlistnumber == -1) return;
+ Playlist * pl = (Playlist*)playlists.Get(playlistnumber);
+ if(posA >= pl->songs.GetSize() || posB >= pl->songs.GetSize()) return;
+ void * a = pl->songs.Get(posA);
+ void * b = pl->songs.Get(posB);
+ pl->songs.Set(posA,b);
+ pl->songs.Set(posB,a);
+ pl->modified=true;
+}
+
+void P4SDevice::addTrackToPlaylist(int playlistnumber, songid_t songid) {
+ if(playlistnumber == -1) return;
+ Playlist * pl = (Playlist*)playlists.Get(playlistnumber);
+ pl->songs.Add((void*)songid);
+ pl->modified=true;
+}
+
+void P4SDevice::removeTrackFromPlaylist(int playlistnumber, int songnum) {
+ if(playlistnumber == -1) return;
+ Playlist * pl = (Playlist*)playlists.Get(playlistnumber);
+ pl->songs.Del(songnum);
+ pl->modified=true;
+}
+
+void P4SDevice::deletePlaylist(int playlistnumber) {
+ if(playlistnumber == -1) return;
+ IWMDMStorageControl3 * storeControl;
+ Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
+ pl->storage->QueryInterface(&storeControl);
+
+ storeControl->Delete(WMDM_MODE_BLOCK,NULL);
+ pl->meta->Release();
+ pl->storage->Release();
+ playlists.Del(playlistnumber);
+
+ storeControl->Release();
+}
+
+int P4SDevice::newPlaylist(const wchar_t *name) {
+ IWMDMStorageControl3 * storeControl;
+ if(!playlistsDir) return -1;
+ playlistsDir->QueryInterface(&storeControl);
+ DWORD dw=WMDM_FORMATCODE_ABSTRACTAUDIOVIDEOPLAYLIST;
+ IWMDMMetaData* meta = NULL;
+ int ret = -1;
+ if (SUCCEEDED(playlistsDir->CreateEmptyMetadataObject(&meta)) && meta)
+ {
+ meta->AddItem(WMDM_TYPE_DWORD, g_wszWMDMFormatCode, (BYTE *)&dw, sizeof(dw));
+ meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMTitle,(BYTE*)name,(wcslen(name)*2)+2);
+ IWMDMStorage * newpl=NULL;
+ wchar_t buffer[MAX_PATH] = {0};
+ wsprintf(buffer,L"%s.%s",name,plext);
+ storeControl->Insert3(WMDM_MODE_BLOCK | WMDM_CONTENT_FILE,0,NULL,buffer,NULL,NULL,meta,NULL,&newpl);
+
+ if(newpl) {
+ IWMDMStorage4 * newpl4=NULL;
+ newpl->QueryInterface(&newpl4);
+ Playlist * pl = new Playlist;
+ lstrcpyn(pl->name,name,128);
+ pl->storage = newpl4;
+ pl->modified = false;
+ pl->meta = meta;
+ playlists.Add(pl);
+ ret = playlists.GetSize() - 1;
+ newpl->Release();
+ }
+ }
+ storeControl->Release();
+
+ return ret;
+}
+
+void P4SDevice::getTrackArtist(songid_t songid, wchar_t * buf, int len) {
+ buf[0]=0;
+ BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMAuthor);
+ if(b) { lstrcpyn(buf,(wchar_t*)b,len); CoTaskMemFree(b); }
+ if(noMetadata || !b) {
+ if(!buf[0]) { // guess based upon file path
+ Song *s = (Song *)songid;
+ if(s->artist) {lstrcpyn(buf,s->artist,len);
+ return;
+ }
+ IWMDMStorage * p = NULL;
+ if(s->storage->GetParent(&p) == S_OK) {
+ IWMDMStorage * p2 = NULL;
+ IWMDMStorage4 * p3 = NULL;
+ if (SUCCEEDED(p->QueryInterface(&p3))) {
+ if(p3->GetParent(&p2) == S_OK) {
+ p2->GetName(buf,len);
+ p2->Release();
+ }
+ p3->Release();
+ }
+ p->Release();
+ }
+ }
+}
+}
+
+void P4SDevice::getTrackAlbum(songid_t songid, wchar_t * buf, int len) {
+ buf[0]=0;
+ BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMAlbumTitle);
+ if(b) { lstrcpyn(buf,(wchar_t*)b,len); CoTaskMemFree(b); }
+ if(!b || noMetadata || ((Song*)songid)->video) {
+ if(!buf[0]) { // guess based upon file path
+ Song *s = (Song *)songid;
+ if(s->album) {lstrcpyn(buf,s->album,len); return;}
+ IWMDMStorage * p = NULL;
+ if(s->storage->GetParent(&p) == S_OK) {
+ p->GetName(buf,len);
+ p->Release();
+ }
+ }
+ }
+ if(buf[0] == L'~' && buf[1] == 0) buf[0]=0;
+}
+void P4SDevice::getTrackTitle(songid_t songid, wchar_t * buf, int len) {
+ buf[0]=0;
+ BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMTitle);
+ if(b) { lstrcpyn(buf,(wchar_t*)b,len); CoTaskMemFree(b); }
+ if(!b || noMetadata || ((Song*)songid)->video) {
+ if(!buf[0]) { // guess based upon file name
+ Song *s = (Song *)songid;
+ wchar_t buf2[256]=L"";
+ s->storage->GetName(buf2,256);
+ wchar_t * n = wcsrchr(buf2,L'-');
+ if(n) {
+ while(n && (*n == L'-' || *n == L' ' || *n == L'_' || *n == L'.')) n++;
+ lstrcpyn(buf,n,len);
+ } else lstrcpyn(buf,buf2,len);
+ }
+ wchar_t * ext = wcsrchr(buf,L'.');
+ if(ext) *ext=0;
+}
+}
+void P4SDevice::getTrackGenre(songid_t songid, wchar_t * buf, int len) {
+ buf[0]=0;
+ BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMGenre);
+ if(b) { lstrcpyn(buf,(wchar_t*)b,len); CoTaskMemFree(b); }
+}
+
+int P4SDevice::getTrackTrackNum(songid_t songid) {
+ BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMTrack);
+ int r = b?(int)*((DWORD*)b):0; if(b) CoTaskMemFree(b);
+ if(r) return r;
+ if(!b || noMetadata) { // guess based upon file name
+ Song *s = (Song *)songid;
+ wchar_t buf2[256]=L"";
+ s->storage->GetName(buf2,256);
+
+ wchar_t * n = buf2; //wcschr(buf2,L'-');
+ while(n) {
+ while((*n == L'-' || *n == L' ' || *n == L'_' || *n == L'.') && *n) n++;
+ if(!n) break;
+ int m=0; while(*(n+m)>=L'0' && *(n+m)<=L'9') m++;
+ if(m == 2) { *(n+m)=0; return _wtoi(n); }
+ n = wcschr(n,L'-');
+ }
+ /*
+ wchar_t * n = wcschr(buf2,L'-');
+ if(n) {
+ *(n--)=0;
+ while((*n == L'-' || *n == L' ' || *n == L'_' || *n == L'.') && n > buf2) *(n--)=0;
+ return _wtoi(buf2);
+ }
+ */
+ }
+ return 0;
+}
+
+int P4SDevice::getTrackYear(songid_t songid) {
+ BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMYear);
+ int r = b?_wtoi((wchar_t*)b):0; if(b) CoTaskMemFree(b); return r;
+}
+__int64 P4SDevice::getTrackSize(songid_t songid) {
+ BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMFileSize);
+ int r = b?(int)*((__int64*)b):0; if(b) CoTaskMemFree(b);
+ if(r) return r;
+ DWORD high, low;
+ ((Song *)songid)->storage->GetSize(&low,&high);
+ ULARGE_INTEGER u;
+ u.HighPart = high;
+ u.LowPart = low;
+ return u.QuadPart;
+}
+
+int P4SDevice::getTrackLength(songid_t songid) {
+ BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMDuration);
+ int r = b?(int)(*((__int64*)b)/10000):0; if(b) CoTaskMemFree(b); return r;
+}
+
+int P4SDevice::getTrackBitrate(songid_t songid) {
+ int len = getTrackLength(songid) / 8000;
+ return len?(int)(getTrackSize(songid)/1024) / len:0;
+}
+
+int P4SDevice::getTrackPlayCount(songid_t songid) {
+ BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMPlayCount);
+ int r = b?(int)*((DWORD*)b):0; if(b) CoTaskMemFree(b); return r;
+}
+
+int P4SDevice::getTrackRating(songid_t songid) {
+ BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMUserRating);
+ int r = b?(int)*((DWORD*)b):0; if(b) CoTaskMemFree(b); return r;
+}
+
+__time64_t P4SDevice::getTrackLastPlayed(songid_t songid) {
+ BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMUserLastPlayTime);
+ __time64_t r = b?wmdmDateTimeToUnixTime((_WMDMDATETIME *)b):0; if(b) CoTaskMemFree(b); return r;
+}
+
+__time64_t P4SDevice::getTrackLastUpdated(songid_t songid) {
+ BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMLastModifiedDate);
+ __time64_t r = b?wmdmDateTimeToUnixTime((_WMDMDATETIME *)b):0; if(b) CoTaskMemFree(b); return r;
+}
+
+void P4SDevice::getTrackAlbumArtist(songid_t songid, wchar_t * buf, int len) {
+ buf[0]=0;
+ BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMAlbumArtist);
+ if(b) { lstrcpyn(buf,(wchar_t*)b,len); CoTaskMemFree(b); }
+ if(!buf[0]) getTrackArtist(songid,buf,len);
+}
+
+void P4SDevice::getTrackComposer(songid_t songid, wchar_t * buf, int len) {
+ buf[0]=0;
+ BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMComposer);
+ if(b) { lstrcpyn(buf,(wchar_t*)b,len); CoTaskMemFree(b); }
+}
+
+int P4SDevice::getTrackType(songid_t songid) {
+ Song * s = (Song *)songid;
+ return s->video;
+}
+
+void P4SDevice::getTrackExtraInfo(songid_t songid, const wchar_t * field, wchar_t * buf, int len) {
+ if(!wcscmp(field,FIELD_EXTENSION)) {
+ Song * s = (Song *)songid;
+ wchar_t buf2[2048] = {0};
+ s->storage->GetName(buf2,2048);
+ wchar_t * ext = wcsrchr(buf2,L'.');
+ if(ext) { ext++; lstrcpyn(buf,ext,len); }
+ }
+}
+
+void P4SDevice::PreCommit(Song * s) {
+ if(!lastChange) lastChange = s;
+ else if(s != lastChange) {
+ if(lastChange->modified) {
+ lastChange->storage->SetMetadata(lastChange->meta);
+ lastChange->meta->Release();
+ lastChange->storage->GetMetadata(&lastChange->meta);
+ lastChange->modified = false;
+ }
+ lastChange = s;
+ }
+}
+
+void P4SDevice::setTrackArtist(songid_t songid, const wchar_t * value) {
+ ((Song*)songid)->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAuthor,(BYTE*)value,wcslen(value)*2+2);
+ ((Song*)songid)->modified=true;
+ PreCommit((Song*)songid);
+}
+
+void P4SDevice::setTrackAlbum(songid_t songid, const wchar_t * value) {
+ ((Song*)songid)->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumTitle,(BYTE*)value,wcslen(value)*2+2);
+ ((Song*)songid)->modified=true;
+ PreCommit((Song*)songid);
+}
+
+void P4SDevice::setTrackTitle(songid_t songid, const wchar_t * value) {
+ ((Song*)songid)->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMTitle,(BYTE*)value,wcslen(value)*2+2);
+ ((Song*)songid)->modified=true;
+ PreCommit((Song*)songid);
+}
+
+void P4SDevice::setTrackGenre(songid_t songid, const wchar_t * value) {
+ ((Song*)songid)->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMGenre,(BYTE*)value,wcslen(value)*2+2);
+ ((Song*)songid)->modified=true;
+ PreCommit((Song*)songid);
+}
+
+void P4SDevice::setTrackTrackNum(songid_t songid, int value) {
+ ((Song*)songid)->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMTrack,(BYTE*)&value,sizeof(DWORD));
+ ((Song*)songid)->modified=true;
+ PreCommit((Song*)songid);
+}
+
+void P4SDevice::setTrackYear(songid_t songid, int value) {
+ wchar_t buf[10] = {0}; wsprintf(buf,L"%d",value);
+ ((Song*)songid)->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMYear,(BYTE*)buf,wcslen(buf)*2+2);
+ ((Song*)songid)->modified=true;
+ PreCommit((Song*)songid);
+}
+
+void P4SDevice::setTrackPlayCount(songid_t songid, int value) {
+ ((Song*)songid)->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMPlayCount,(BYTE*)&value,sizeof(DWORD));
+ ((Song*)songid)->modified=true;
+ PreCommit((Song*)songid);
+}
+
+void P4SDevice::setTrackRating(songid_t songid, int value) {
+ ((Song*)songid)->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMUserRating,(BYTE*)&value,sizeof(DWORD));
+ ((Song*)songid)->modified=true;
+ PreCommit((Song*)songid);
+}
+
+void P4SDevice::setTrackLastPlayed(songid_t songid, __time64_t value) {
+ _WMDMDATETIME time={0};
+ getTime(value,&time);
+ ((Song*)songid)->meta->AddItem(WMDM_TYPE_DATE,g_wszWMDMUserLastPlayTime,(BYTE*)&time,sizeof(_WMDMDATETIME));
+ ((Song*)songid)->modified=true;
+ PreCommit((Song*)songid);
+}
+
+void P4SDevice::setTrackLastUpdated(songid_t songid, __time64_t value) {
+ _WMDMDATETIME time={0};
+ getTime(value,&time);
+ ((Song*)songid)->meta->AddItem(WMDM_TYPE_DATE,g_wszWMDMLastModifiedDate,(BYTE*)&time,sizeof(_WMDMDATETIME));
+ ((Song*)songid)->modified=true;
+ PreCommit((Song*)songid);
+}
+
+void P4SDevice::setTrackAlbumArtist(songid_t songid, const wchar_t * value) {
+ ((Song*)songid)->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumArtist,(BYTE*)value,wcslen(value)*2+2);
+ ((Song*)songid)->modified=true;
+ PreCommit((Song*)songid);
+}
+
+void P4SDevice::setTrackComposer(songid_t songid, const wchar_t * value) {
+ ((Song*)songid)->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMComposer,(BYTE*)value,wcslen(value)*2+2);
+ ((Song*)songid)->modified=true;
+ PreCommit((Song*)songid);
+}
+
+int P4SDevice::copyToHardDrive(songid_t s,wchar_t * path,void * callbackContext,void (*callback)(void * callbackContext, wchar_t * status),int * killswitch)
+{
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_WAITING));
+ EnterCriticalSection(&csTransfers);
+ Song * song = (Song*)s;
+ IWMDMStorageControl * control;
+ if (!SUCCEEDED(song->storage->QueryInterface(&control))) {
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_FAILED));
+ return -1;
+ }
+ wchar_t fn[2084] = {0};
+ wchar_t *ext = 0;
+ if(SUCCEEDED(song->storage->GetName(fn,2084)) && (ext=wcsrchr(fn,L'.'))!=0)
+ wcscat(path,ext);
+ int ret=-1;
+ callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_TRANSFERRING));
+ TransferItem t={0};
+ t.callback = callback;
+ t.callbackContext = callbackContext;
+ t.killswitch = killswitch;
+ t.progress = new MyProgress(&t);
+ if(SUCCEEDED(control->Read(WMDM_MODE_BLOCK | WMDM_CONTENT_FILE,path,t.progress,NULL))) ret=0;
+ control->Release();
+ t.progress->Release();
+ callback(callbackContext,WASABI_API_LNGSTRINGW((ret==0?IDS_DONE:IDS_FAILED)));
+ LeaveCriticalSection(&csTransfers);
+ return ret;
+}
+
+static IWMDMStorage4* getAlb(P4SDevice * dev, songid_t songid, bool create) {
+ wchar_t alb[1024] = {0};
+ dev->getTrackAlbum(songid,alb,1020);
+ StringCchCat(alb, ARRAYSIZE(alb), L".alb");
+ Song * song = (Song*)songid;
+ IWMDMStorage * album0=NULL;
+ IWMDMStorage * parent=NULL;
+ IWMDMStorage4 * parent4=NULL;
+ IWMDMStorage4 * album4=NULL;
+ song->storage->GetParent(&parent);
+ if (parent)
+ {
+ parent->QueryInterface(&parent4);
+ parent->Release();
+ if (parent4)
+ {
+ parent4->GetStorage(alb,&album0);
+ //parent4->Release();
+ if(album0) {
+ album0->QueryInterface(&album4);
+ album0->Release();
+ }
+ }
+ }
+ if(album4 || !create) { parent4->Release(); return album4; }
+ if(!parent4) return NULL;
+ // create my own
+ album0=0;
+ IWMDMStorageControl3 * storeControl=0;
+ parent4->QueryInterface(&storeControl);
+ if(storeControl) {
+ IWMDMMetaData * meta=0;
+ parent4->CreateEmptyMetadataObject(&meta);
+ if(meta) {
+ DWORD formatCode = WMDM_FORMATCODE_ABSTRACTAUDIOALBUM;
+ wchar_t album[256]=L"";
+ wchar_t artist[256]=L"";
+ wchar_t genre[256]=L"";
+ dev->getTrackAlbumArtist(songid,artist,256);
+ dev->getTrackAlbum(songid,album,256);
+ dev->getTrackGenre(songid,genre,256);
+ meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMFormatCode,(BYTE*)&formatCode,sizeof(DWORD));
+ meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumTitle,(BYTE*)album,(wcslen(album)*2)+2);
+ meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumArtist,(BYTE*)artist,(wcslen(artist)*2)+2);
+ meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMTitle,(BYTE*)album,(wcslen(album)*2)+2);
+ meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMGenre,(BYTE*)genre,(wcslen(genre)*2)+2);
+
+ storeControl->Insert3(WMDM_MODE_BLOCK | WMDM_CONTENT_FILE,0,NULL,alb,NULL,NULL,meta,NULL,&album0);
+ meta->Release();
+ }
+ storeControl->Release();
+ }
+ parent4->Release();
+ if(album0) {
+ album0->QueryInterface(&album4);
+ album0->Release();
+ return album4;
+ }
+ return NULL;
+}
+
+void P4SDevice::setArt(songid_t songid, void *buf, int w, int h) { //buf is in format ARGB32*
+ if(!songid) return;
+ Song * s = (Song *)songid;
+ IWMDMStorage4 * album = s->alb;
+ if(!album) {
+ album = getAlb(this,songid,true);
+ if(!album) return;
+ s->alb = album;
+ s->albmeta = NULL;
+ s->alb->GetMetadata(&s->albmeta);
+ if(!s->albmeta) return;
+ }
+
+ IWMDMMetaData *meta=s->albmeta;
+ if(!meta) return;
+ IWMDMMetaData *meta2 = ((Song*)songid)->meta;
+
+ if(meta || meta2) {
+ if(buf) {
+ SkinBitmap art((ARGB32*)buf,w,h);
+ w=h=120;
+ BltCanvas artc(w,h);
+ art.stretch(&artc,0,0,w,h);
+
+ const GUID JPEGwriteguid = { 0x7bc27468, 0x475, 0x4c0d, { 0xae, 0xed, 0xc, 0x51, 0x19, 0x5d, 0xc2, 0xea } };
+ svc_imageWriter* jpgWrite=NULL;
+ waServiceFactory *sf = plugin.service->service_getServiceByGuid(JPEGwriteguid);
+ if(sf) jpgWrite = (svc_imageWriter*)sf->getInterface();
+ if(jpgWrite) {
+ int length=0;
+ void *jpeg = jpgWrite->convert(artc.getBits(),32,w,h,&length);
+ if(jpeg) {
+ DWORD fmt = WMDM_FORMATCODE_IMAGE_EXIF; // this is the formatcode for jpeg, apparently.
+ if(meta) {
+ meta->AddItem(WMDM_TYPE_BINARY,g_wszWMDMAlbumCoverData,(BYTE*)jpeg,length);
+ meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverWidth,(BYTE*)&w,sizeof(DWORD));
+ meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverHeight,(BYTE*)&h,sizeof(DWORD));
+ meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverSize,(BYTE*)&length,sizeof(DWORD));
+ meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverFormat,(BYTE*)&fmt,sizeof(DWORD));
+ }
+ if(meta2) {
+ meta2->AddItem(WMDM_TYPE_BINARY,g_wszWMDMAlbumCoverData,(BYTE*)jpeg,length);
+ meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverWidth,(BYTE*)&w,sizeof(DWORD));
+ meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverHeight,(BYTE*)&h,sizeof(DWORD));
+ meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverSize,(BYTE*)&length,sizeof(DWORD));
+ meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverFormat,(BYTE*)&fmt,sizeof(DWORD));
+ }
+ WASABI_API_MEMMGR->sysFree(jpeg);
+ }
+ if (sf) sf->releaseInterface(jpgWrite);
+ }
+ } else { // remove art
+ if(meta) {
+ meta->AddItem(WMDM_TYPE_BINARY,g_wszWMDMAlbumCoverData,(BYTE*)0,0);
+ meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverWidth,(BYTE*)0,0);
+ meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverHeight,(BYTE*)0,0);
+ meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverSize,(BYTE*)0,0);
+ meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverFormat,(BYTE*)0,0);
+ }
+ if(meta2) {
+ meta2->AddItem(WMDM_TYPE_BINARY,g_wszWMDMAlbumCoverData,(BYTE*)0,0);
+ meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverWidth,(BYTE*)0,0);
+ meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverHeight,(BYTE*)0,0);
+ meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverSize,(BYTE*)0,0);
+ meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverFormat,(BYTE*)0,0);
+ }
+ }
+ if(meta) {
+ album->SetMetadata(meta);
+ }
+ }
+ ((Song*)songid)->modified=true;
+ PreCommit((Song*)songid);
+/*
+g_wszWMDMAlbumCoverData Album art JPEG byte blob WMDM_TYPE_BINARY BYTE*
+g_wszWMDMAlbumCoverDuration Album cover duration WMDM_TYPE_DWORD DWORD
+g_wszWMDMAlbumCoverFormat Album art format WMDM_TYPE_DWORD DWORD
+g_wszWMDMAlbumCoverHeight Album art height WMDM_TYPE_DWORD DWORD
+g_wszWMDMAlbumCoverSize Album art size WMDM_TYPE_DWORD DWORD
+g_wszWMDMAlbumCoverWidth Album art width WMDM_TYPE_DWORD DWORD
+*/
+}
+
+class Art {
+public:
+ Art(void * jpegData, int jpegDataLen, int w, int h) : jpegData(jpegData), jpegDataLen(jpegDataLen), w(w), h(h), data(0), resized(0) {
+ }
+ ~Art() {
+ CoTaskMemFree(jpegData);
+ if(data) WASABI_API_MEMMGR->sysFree(data); data=0;
+ }
+ ARGB32 * GetImage() {
+ if(data) return data;
+ const GUID JPEGguid = { 0xae04fb30, 0x53f5, 0x4032, { 0xbd, 0x29, 0x3, 0x2b, 0x87, 0xec, 0x34, 0x04 } };
+ svc_imageLoader* jpgLoad=NULL;
+ waServiceFactory *sf = plugin.service->service_getServiceByGuid(JPEGguid);
+ if(sf) jpgLoad = (svc_imageLoader*)sf->getInterface();
+ if(jpgLoad) {
+ data = jpgLoad->loadImage(jpegData,jpegDataLen,&w,&h);
+ if (sf) sf->releaseInterface(jpgLoad);
+ }
+ resized=0;
+ return data;
+ }
+ int resized;
+ void Resize(int width, int height) {
+ if(w == width && h == height) return;
+ if(resized) {
+ if(data) WASABI_API_MEMMGR->sysFree(data);
+ data=0;
+ resized=0;
+ }
+ GetImage();
+ if(!data) return;
+ SkinBitmap temp(data,w,h);
+ BltCanvas newImage(width,height);
+ temp.stretch(&newImage,0,0,width,height);
+ w=width;
+ h=height;
+ WASABI_API_MEMMGR->sysFree(data);
+ data = (ARGB32*)WASABI_API_MEMMGR->sysMalloc(w*h*sizeof(ARGB32));
+ memcpy(data,newImage.getBits(),w*h*sizeof(ARGB32));
+ resized=1;
+ }
+ int getWidth() {return w;}
+ int getHeight() {return h;}
+ int cmp(Art * art) {
+ if(art->jpegDataLen != jpegDataLen) return art->jpegDataLen - jpegDataLen;
+ return memcmp(art->jpegData,jpegData,jpegDataLen);
+ }
+protected:
+ void * jpegData;
+ int jpegDataLen;
+ int w,h;
+ ARGB32 *data;
+};
+
+pmpart_t P4SDevice::getArt(songid_t songid) {
+ if(!songid) return NULL;
+ Song* s = (Song*)songid;
+ WMDM_TAG_DATATYPE type;
+ BYTE * data=NULL;
+ UINT length=0;
+ IWMDMMetaData *meta = s->albmeta;
+ if(!meta) return NULL;
+
+ HRESULT hr = meta->QueryByName(g_wszWMDMAlbumCoverData,&type,&data,&length);
+
+ if(hr == S_OK && data && length) {
+ BYTE * b = GetMetadataItem(meta,g_wszWMDMAlbumCoverWidth);
+ int w = b?(int)*((DWORD*)b):0;
+ if(b) CoTaskMemFree(b);
+
+ b = GetMetadataItem(meta,g_wszWMDMAlbumCoverHeight);
+ int h = b?(int)*((DWORD*)b):0;
+ if(b) CoTaskMemFree(b);
+ //meta->Release();
+ if(!w) w=120; // this happens if the device doesn't store the w and h of the image.
+ if(!h) h=120; // but it's ok, cause the real values are in the jpeg data, and these can just be a guide.
+ return (pmpart_t) new Art(data,length,w,h);
+ }
+ //meta->Release();
+ if(data) CoTaskMemFree(data);
+ return NULL;
+}
+
+void P4SDevice::releaseArt(pmpart_t art) {
+ if(art) delete ((Art *)art);
+}
+
+int P4SDevice::drawArt(pmpart_t art0, HDC dc, int x, int y, int w, int h) {
+ Art* art = (Art*)art0;
+ if(!art) return 0;
+ ARGB32 * d = art->GetImage();
+ if(!d) return 0;
+ SkinBitmap(d, art->getWidth(), art->getHeight()).stretch(&DCCanvas(dc),x,y,w,h); // wrap into a SkinBitmap (no copying involved)
+ return 1;
+}
+
+void P4SDevice::getArtNaturalSize(pmpart_t art0, int *w, int *h) {
+ Art* art = (Art*)art0;
+ *w=art->getWidth();
+ *h=art->getWidth();
+ if(*w==0 || *h==0) *w=*h=120;
+}
+
+void P4SDevice::setArtNaturalSize(pmpart_t art0, int w, int h) {
+ Art* art = (Art*)art0;
+ art->Resize(w,h);
+}
+
+void P4SDevice::getArtData(pmpart_t art0, void* data) { // data ARGB32* is at natural size
+ Art* art = (Art*)art0;
+ int w,h;
+ getArtNaturalSize(art0,&w,&h);
+ setArtNaturalSize(art0,w,h);
+ ARGB32 * d = art->GetImage();
+ if(d) memcpy(data,d,w*h*sizeof(ARGB32));
+}
+
+bool P4SDevice::artIsEqual(pmpart_t a, pmpart_t b) {
+ if(!a || !b) return false;
+ return ((Art*)a)->cmp((Art*)b) == 0;
+}
+
+extern void checkForDevices();
+
+intptr_t P4SDevice::extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4) {
+ switch(param1) {
+ case DEVICE_SET_ICON: // icons
+ {
+ MLTREEIMAGE * i = (MLTREEIMAGE*)param2;
+ if(wcsstr(name,L"Zen")) {
+ i->hinst = plugin.hDllInstance;
+ i->resourceId = IDR_CREATIVE_ZEN_ICON;
+ } else if (wcsstr(name,L"Nokia")) {
+ i->hinst = plugin.hDllInstance;
+ i->resourceId = IDR_NOKIA_ICON;
+ }
+ break;
+ }
+ case DEVICE_SUPPORTED_METADATA:
+ return noMetadata ? 0x8f : (0xffef | (requiresALB?SUPPORTS_ALBUMART:0));
+ case DEVICE_DOES_NOT_SUPPORT_EDITING_METADATA:
+ return noMetadata ? 1 : 0;
+ case DEVICE_REFRESH:
+ {
+ bool nm = noMetadata;
+ IWMDMDevice3* d = WMDevice;
+ d->AddRef();
+ Close();
+ new P4SDevice(d,nm);
+ d->Release();
+ }
+ return 0;
+ case DEVICE_SUPPORTS_VIDEO:
+ return 1;
+ case DEVICE_GET_ICON:
+ {
+ if (param2 <= 16 && param3 <= 16)
+ {
+ int resourceId;
+ wchar_t *buffer;
+
+ if(wcsstr(name,L"Zen"))
+ resourceId = IDR_CREATIVE_ZEN_ICON;
+ else if (wcsstr(name,L"Nokia"))
+ resourceId = IDR_NOKIA_ICON;
+ else
+ resourceId = 0;
+
+ buffer = (wchar_t *)param4;
+ if (NULL != buffer &&
+ FALSE == FormatResProtocol(MAKEINTRESOURCE(resourceId), RT_RCDATA, buffer, 260))
+ {
+ buffer[0] = L'\0';
+ }
+ }
+ }
+ break;
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_p4s/P4SDevice.h b/Src/Plugins/Portable/pmp_p4s/P4SDevice.h
new file mode 100644
index 00000000..3c05cb8f
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/P4SDevice.h
@@ -0,0 +1,243 @@
+#ifndef _P4SDEVICE_H_
+#define _P4SDEVICE_H_
+
+#ifndef _UNICODE
+#define _UNICODE
+#endif
+
+#ifndef UNICODE
+#define UNICODE
+#endif
+
+#include <windows.h>
+#include <windowsx.h>
+#include <stdio.h>
+#include <tchar.h>
+#include <shlobj.h>
+#include "..\..\General\gen_ml/itemlist.h"
+#include "..\..\General\gen_ml/ml.h"
+#include "..\..\Library\ml_pmp/pmp.h"
+#include "..\..\Library\ml_pmp/transcoder.h"
+#include "../winamp/wa_ipc.h"
+#include "../winamp/ipc_pe.h"
+#include "../Agave/Language/api_language.h"
+#include <api/service/waServiceFactory.h>
+#include "resource1.h"
+
+#include <tataki/bitmap/bitmap.h>
+#include <tataki/canvas/bltcanvas.h>
+#include <api/service/svcs/svc_imgload.h>
+#include <api/service/svcs/svc_imgwrite.h>
+
+#include <api/memmgr/api_memmgr.h>
+extern api_memmgr *memoryManager;
+#define WASABI_API_MEMMGR memoryManager
+
+#include "../Agave/AlbumArt/api_albumart.h"
+extern api_albumart *albumArtApi;
+#define AGAVE_API_ALBUMART albumArtApi
+
+#include "../devices/api_devicemanager.h"
+extern api_devicemanager *deviceManagerApi;
+#define AGAVE_API_DEVICEMANAGER deviceManagerApi
+
+
+class P4SDevice;
+class MyProgress;
+class TransferItem;
+
+#ifndef __RPC__in
+#define __RPC__in
+#define __RPC__in_opt
+#define __RPC__in_ecount_full(x)
+#define __RPC__in_ecount_full_opt(x)
+#define __RPC__in_ecount_full_string(x)
+#define __RPC__inout
+#define __RPC__inout_opt
+#define __RPC__deref_opt_inout_opt
+#define __RPC__deref_inout_ecount_full_opt_string(x)
+#define __RPC__inout_ecount_full(x)
+#define __RPC__out
+#define __RPC__out_ecount_full(x)
+#define __RPC__out_ecount_full_string(x)
+#define __RPC__out_ecount_part(x,y)
+#define __RPC__deref_out_ecount_full_opt(x)
+#define __RPC__deref_out_opt_string
+#define __RPC__deref_out_opt
+#endif
+
+#include "WMDRMDeviceApp.h"
+#include "msWMDM.h" // Include headers for Windows Media Device Manager.
+#include "Sac.h" // Include authentication headers.
+#include "Scclient.h" // Include authentication client headers.
+#include "MyProgress.h"
+#include "resource1.h"
+
+extern PMPDevicePlugin plugin;
+
+class Playlist {
+public:
+ wchar_t name[128];
+ IWMDMStorage4 * storage;
+ C_ItemList songs;
+ IWMDMMetaData * meta;
+ bool modified;
+ Playlist() : storage(0),meta(0),modified(false){ name[0]=0; }
+};
+
+class Song {
+public:
+ IWMDMStorage4 * storage;
+ IWMDMMetaData * meta;
+ bool video;
+ bool modified;
+ wchar_t * artist, * album;
+ IWMDMStorage4 * alb;
+ IWMDMMetaData * albmeta;
+ Song() {artist=album=NULL; storage=0; meta=0; video = 0; modified = 0; alb=0; albmeta=0;}
+ virtual ~Song() {if(artist) free(artist); if(album) free(album); if(alb) alb->Release(); if(albmeta) albmeta->Release();}
+};
+
+class TransferItem {
+public:
+ int phase;
+ void * callbackContext;
+ void (*callback)(void * callbackContext, wchar_t * status);
+ wchar_t *file;
+ const itemRecordW * track;
+ songid_t * songid;
+ int * killswitch;
+ P4SDevice * dev;
+ IWMDMMetaData * meta;
+ IWMDMProgress * progress;
+ int pc;
+ bool video;
+};
+
+class P4SDevice : public Device {
+public:
+ bool requiresALB;
+ int error;
+ Transcoder * transcoder;
+ wchar_t *musicDir, *videoDir;
+ bool noMetadata, supportsVideo;
+ __int64 transferQueueSize;
+ C_ItemList playlists;
+ C_ItemList albfiles;
+ IWMDMStorage4 * playlistsDir;
+ wchar_t name[100];
+ IWMDMDevice3* WMDevice;
+ P4SDevice(IWMDMDevice3* pIDevice,bool noMetadata);
+ virtual void Load();
+ virtual ~P4SDevice();
+
+ void traverseStorage(IWMDMStorage * store, int level=0, wchar_t * artist=0, wchar_t * album=0);
+ void foundSong(IWMDMStorage4 * store, IWMDMMetaData * meta, bool video, int pl=0,wchar_t * artist=0, wchar_t * album=0, IWMDMStorage4 * alb=0, IWMDMMetaData * albmeta=0);
+ void foundPlaylist(IWMDMStorage4 * store, IWMDMMetaData * meta);
+ bool songsEqual(songid_t a, songid_t b);
+ int songsCmp(songid_t a, songid_t b);
+
+ virtual __int64 getDeviceCapacityAvailable(); // in bytes
+ virtual __int64 getDeviceCapacityTotal(); // in bytes
+
+ virtual void Eject(){Close();}; // if you ejected successfully, you MUST call plugin.deviceDisconnected(this) and delete this;
+ virtual void Close(); // save any changes, and call plugin.deviceDisconnected(this) AND delete this;
+
+ virtual void doTransfer(TransferItem * t);
+
+ // return the songid when transfer is finished.
+ // call the callback with a percentage and the number of bytes copied so far every so often (to update the GUI)
+ // return 0 for success, -1 for failed or cancelled
+ virtual int transferTrackToDevice(const itemRecordW * track, // the track to transfer
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
+ songid_t * songid, // fill in the songid when you are finished
+ int * killswitch // if this gets set to 1, the transfer has been cancelled by the user
+ );
+ virtual int trackAddedToTransferQueue(const itemRecordW * track); // return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
+ virtual void trackRemovedFromTransferQueue(const itemRecordW * track);
+ virtual __int64 getTrackSizeOnDevice(const itemRecordW * track); // return the amount of space taken up on the device by the track, or 0 for incompatable (usually the filesize, unless you are transcoding)
+
+ virtual void deleteTrack(songid_t songid); // physically remove from device. Be sure to remove it from all the playlists!
+
+ virtual void commitChanges(); // optional. Will be called at a good time to save changes
+
+ virtual int getPlaylistCount(); // always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
+ // PlaylistName(0) should return the name of the device.
+ virtual void getPlaylistName(int playlistnumber, wchar_t * buf, int len);
+ virtual int getPlaylistLength(int playlistnumber);
+ virtual songid_t getPlaylistTrack(int playlistnumber,int songnum); // returns a songid
+
+ virtual void setPlaylistName(int playlistnumber, const wchar_t *buf); // playlistnumber != 0!!
+ virtual void playlistSwapItems(int playlistnumber, int posA, int posB); // swap the songs at position posA and posB
+ virtual void sortPlaylist(int playlistnumber, int sortBy);
+ virtual void addTrackToPlaylist(int playlistnumber, songid_t songid); // adds songid to the end of the playlist
+ virtual void removeTrackFromPlaylist(int playlistnumber, int songnum); //where songnum is the position of the track in the playlist
+
+ virtual void deletePlaylist(int playlistnumber);
+ virtual int newPlaylist(const wchar_t * name); // create empty playlist, returns playlistnumber
+
+ virtual void getTrackArtist(songid_t songid, wchar_t * buf, int len);
+ virtual void getTrackAlbum(songid_t songid, wchar_t * buf, int len);
+ virtual void getTrackTitle(songid_t songid, wchar_t * buf, int len);
+ virtual int getTrackTrackNum(songid_t songid);
+ virtual int getTrackDiscNum(songid_t songid){return -1;}
+ virtual void getTrackGenre(songid_t songid, wchar_t * buf, int len);
+ virtual int getTrackYear(songid_t songid);
+ virtual __int64 getTrackSize(songid_t songid); // in bytes
+ virtual int getTrackLength(songid_t songid); // in millisecs
+ virtual int getTrackBitrate(songid_t songid); // in kbps
+ virtual int getTrackPlayCount(songid_t songid);
+ virtual int getTrackRating(songid_t songid); //0-5
+ virtual __time64_t getTrackLastPlayed(songid_t songid); // in unix time format
+ virtual __time64_t getTrackLastUpdated(songid_t songid); // in unix time format
+ virtual void getTrackAlbumArtist(songid_t songid, wchar_t * buf, int len);
+ virtual void getTrackComposer(songid_t songid, wchar_t * buf, int len);
+ virtual int getTrackType(songid_t songid);
+ virtual void getTrackExtraInfo(songid_t songid, const wchar_t *field, wchar_t * buf, int len);
+
+ Song * lastChange;
+ void PreCommit(Song * song);
+
+ // feel free to ignore any you don't support
+ virtual void setTrackArtist(songid_t songid, const wchar_t * value);
+ virtual void setTrackAlbum(songid_t songid, const wchar_t * value);
+ virtual void setTrackTitle(songid_t songid, const wchar_t * value);
+ virtual void setTrackTrackNum(songid_t songid, int value);
+ virtual void setTrackDiscNum(songid_t songid, int value){};
+ virtual void setTrackGenre(songid_t songid, const wchar_t * value);
+ virtual void setTrackYear(songid_t songid, int year);
+ virtual void setTrackPlayCount(songid_t songid, int value);
+ virtual void setTrackRating(songid_t songid, int value);
+ virtual void setTrackLastPlayed(songid_t songid, __time64_t value); // in unix time format
+ virtual void setTrackLastUpdated(songid_t songid, __time64_t value); // in unix time format
+ virtual void setTrackAlbumArtist(songid_t songid, const wchar_t * value);
+ virtual void setTrackComposer(songid_t songid, const wchar_t * value);
+ virtual void setTrackExtraInfo(songid_t songid, const wchar_t * field, const wchar_t * value) {}; //optional
+
+ virtual bool playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue){return false;}; // return false if unsupported
+
+ virtual intptr_t extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4);
+
+ virtual bool copyToHardDriveSupported() {return true;}
+
+ virtual __int64 songSizeOnHardDrive(songid_t song) {return getTrackSize(song);} // how big a song will be when copied back. Return -1 for not supported.
+
+ virtual int copyToHardDrive(songid_t song, // the song to copy
+ wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ ); // -1 for failed/not supported. 0 for success.
+
+ virtual void setArt(songid_t songid, void *buf, int w, int h); //buf is in format ARGB32*
+ virtual pmpart_t getArt(songid_t songid);
+ virtual void releaseArt(pmpart_t art);
+ virtual int drawArt(pmpart_t art, HDC dc, int x, int y, int w, int h);
+ virtual void getArtNaturalSize(pmpart_t art, int *w, int *h);
+ virtual void setArtNaturalSize(pmpart_t art, int w, int h);
+ virtual void getArtData(pmpart_t art, void* data); // data ARGB32* is at natural size
+ virtual bool artIsEqual(pmpart_t a, pmpart_t b);
+};
+
+#endif // _P4SDEVICE_H_ \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_p4s/WMDRMDeviceApp.h b/Src/Plugins/Portable/pmp_p4s/WMDRMDeviceApp.h
new file mode 100644
index 00000000..7f0968a4
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/WMDRMDeviceApp.h
@@ -0,0 +1,502 @@
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 6.00.0361 */
+/* at Tue Jan 10 22:44:12 2006
+ */
+/* Compiler settings for \Wmsdk\Wmfsdk95\Wmdm\idl\WMDRMDeviceApp.idl:
+ Oicf, W1, Zp8, env=Win32 (32b run)
+ protocol : dce , ms_ext, c_ext, robust
+ error checks: allocation ref bounds_check enum stub_data
+ VC __declspec() decoration level:
+ __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+ DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+//@@MIDL_FILE_HEADING( )
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __WMDRMDeviceApp_h__
+#define __WMDRMDeviceApp_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __IWMDRMDeviceApp_FWD_DEFINED__
+#define __IWMDRMDeviceApp_FWD_DEFINED__
+typedef interface IWMDRMDeviceApp IWMDRMDeviceApp;
+#endif /* __IWMDRMDeviceApp_FWD_DEFINED__ */
+
+
+#ifndef __IWMDRMDeviceApp2_FWD_DEFINED__
+#define __IWMDRMDeviceApp2_FWD_DEFINED__
+typedef interface IWMDRMDeviceApp2 IWMDRMDeviceApp2;
+#endif /* __IWMDRMDeviceApp2_FWD_DEFINED__ */
+
+
+#ifndef __WMDRMDeviceApp_FWD_DEFINED__
+#define __WMDRMDeviceApp_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class WMDRMDeviceApp WMDRMDeviceApp;
+#else
+typedef struct WMDRMDeviceApp WMDRMDeviceApp;
+#endif /* __cplusplus */
+
+#endif /* __WMDRMDeviceApp_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "oaidl.h"
+#include "ocidl.h"
+#include "mswmdm.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+void * __RPC_USER MIDL_user_allocate(size_t);
+void __RPC_USER MIDL_user_free( void * );
+
+/* interface __MIDL_itf_WMDRMDeviceApp_0000 */
+/* [local] */
+
+// WMDRM Device status flags
+#define WMDRM_DEVICE_ISWMDRM 0x00000001L
+#define WMDRM_DEVICE_NEEDCLOCK 0x00000002L
+#define WMDRM_DEVICE_REVOKED 0x00000004L
+#define WMDRM_CLIENT_NEEDINDIV 0x00000008L
+#define WMDRM_DEVICE_REFRESHCLOCK 0x00000010L
+// WMDRM Query Device flags
+#define WMDRM_QUERY_DEVICE_ISWMDRM 0x00000001L
+#define WMDRM_QUERY_DEVICE_CLOCKSTATUS 0x00000002L
+#define WMDRM_QUERY_DEVICE_ISREVOKED 0x00000004L
+#define WMDRM_QUERY_CLIENT_INDIVSTATUS 0x00000008L
+// ProcessMeterResponse flags
+#define WMDRM_METER_RESPONSE_ALL 0x00000000L
+#define WMDRM_METER_RESPONSE_PARTIAL 0x00000001L
+
+
+extern RPC_IF_HANDLE __MIDL_itf_WMDRMDeviceApp_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_WMDRMDeviceApp_0000_v0_0_s_ifspec;
+
+#ifndef __IWMDRMDeviceApp_INTERFACE_DEFINED__
+#define __IWMDRMDeviceApp_INTERFACE_DEFINED__
+
+/* interface IWMDRMDeviceApp */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDRMDeviceApp;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("93AFDB44-B1E1-411d-B89B-75AD4F97882B")
+ IWMDRMDeviceApp : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GenerateMeterChallenge(
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ BSTR bstrMeterCert,
+ /* [out] */ BSTR *pbstrMeterURL,
+ /* [out] */ BSTR *pbstrMeterData) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProcessMeterResponse(
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ BYTE *pbResponse,
+ /* [in] */ DWORD cbResponse,
+ /* [out] */ DWORD *pdwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE QueryDeviceStatus(
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [out] */ DWORD *pdwStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AcquireDeviceData(
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ IWMDMProgress3 *pProgressCallback,
+ /* [in] */ DWORD dwFlags,
+ /* [out] */ DWORD *pdwStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SynchronizeLicenses(
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ IWMDMProgress3 *pProgressCallback,
+ /* [in] */ DWORD cMinCountThreshold,
+ /* [in] */ DWORD cMinHoursThreshold) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDRMDeviceAppVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDRMDeviceApp * This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDRMDeviceApp * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDRMDeviceApp * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GenerateMeterChallenge )(
+ IWMDRMDeviceApp * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ BSTR bstrMeterCert,
+ /* [out] */ BSTR *pbstrMeterURL,
+ /* [out] */ BSTR *pbstrMeterData);
+
+ HRESULT ( STDMETHODCALLTYPE *ProcessMeterResponse )(
+ IWMDRMDeviceApp * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ BYTE *pbResponse,
+ /* [in] */ DWORD cbResponse,
+ /* [out] */ DWORD *pdwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *QueryDeviceStatus )(
+ IWMDRMDeviceApp * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [out] */ DWORD *pdwStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AcquireDeviceData )(
+ IWMDRMDeviceApp * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ IWMDMProgress3 *pProgressCallback,
+ /* [in] */ DWORD dwFlags,
+ /* [out] */ DWORD *pdwStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *SynchronizeLicenses )(
+ IWMDRMDeviceApp * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ IWMDMProgress3 *pProgressCallback,
+ /* [in] */ DWORD cMinCountThreshold,
+ /* [in] */ DWORD cMinHoursThreshold);
+
+ END_INTERFACE
+ } IWMDRMDeviceAppVtbl;
+
+ interface IWMDRMDeviceApp
+ {
+ CONST_VTBL struct IWMDRMDeviceAppVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDRMDeviceApp_QueryInterface(This,riid,ppvObject) \
+ (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define IWMDRMDeviceApp_AddRef(This) \
+ (This)->lpVtbl -> AddRef(This)
+
+#define IWMDRMDeviceApp_Release(This) \
+ (This)->lpVtbl -> Release(This)
+
+
+#define IWMDRMDeviceApp_GenerateMeterChallenge(This,pDevice,bstrMeterCert,pbstrMeterURL,pbstrMeterData) \
+ (This)->lpVtbl -> GenerateMeterChallenge(This,pDevice,bstrMeterCert,pbstrMeterURL,pbstrMeterData)
+
+#define IWMDRMDeviceApp_ProcessMeterResponse(This,pDevice,pbResponse,cbResponse,pdwFlags) \
+ (This)->lpVtbl -> ProcessMeterResponse(This,pDevice,pbResponse,cbResponse,pdwFlags)
+
+#define IWMDRMDeviceApp_QueryDeviceStatus(This,pDevice,pdwStatus) \
+ (This)->lpVtbl -> QueryDeviceStatus(This,pDevice,pdwStatus)
+
+#define IWMDRMDeviceApp_AcquireDeviceData(This,pDevice,pProgressCallback,dwFlags,pdwStatus) \
+ (This)->lpVtbl -> AcquireDeviceData(This,pDevice,pProgressCallback,dwFlags,pdwStatus)
+
+#define IWMDRMDeviceApp_SynchronizeLicenses(This,pDevice,pProgressCallback,cMinCountThreshold,cMinHoursThreshold) \
+ (This)->lpVtbl -> SynchronizeLicenses(This,pDevice,pProgressCallback,cMinCountThreshold,cMinHoursThreshold)
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+HRESULT STDMETHODCALLTYPE IWMDRMDeviceApp_GenerateMeterChallenge_Proxy(
+ IWMDRMDeviceApp * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ BSTR bstrMeterCert,
+ /* [out] */ BSTR *pbstrMeterURL,
+ /* [out] */ BSTR *pbstrMeterData);
+
+
+void __RPC_STUB IWMDRMDeviceApp_GenerateMeterChallenge_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IWMDRMDeviceApp_ProcessMeterResponse_Proxy(
+ IWMDRMDeviceApp * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ BYTE *pbResponse,
+ /* [in] */ DWORD cbResponse,
+ /* [out] */ DWORD *pdwFlags);
+
+
+void __RPC_STUB IWMDRMDeviceApp_ProcessMeterResponse_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IWMDRMDeviceApp_QueryDeviceStatus_Proxy(
+ IWMDRMDeviceApp * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [out] */ DWORD *pdwStatus);
+
+
+void __RPC_STUB IWMDRMDeviceApp_QueryDeviceStatus_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IWMDRMDeviceApp_AcquireDeviceData_Proxy(
+ IWMDRMDeviceApp * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ IWMDMProgress3 *pProgressCallback,
+ /* [in] */ DWORD dwFlags,
+ /* [out] */ DWORD *pdwStatus);
+
+
+void __RPC_STUB IWMDRMDeviceApp_AcquireDeviceData_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+HRESULT STDMETHODCALLTYPE IWMDRMDeviceApp_SynchronizeLicenses_Proxy(
+ IWMDRMDeviceApp * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ IWMDMProgress3 *pProgressCallback,
+ /* [in] */ DWORD cMinCountThreshold,
+ /* [in] */ DWORD cMinHoursThreshold);
+
+
+void __RPC_STUB IWMDRMDeviceApp_SynchronizeLicenses_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+
+#endif /* __IWMDRMDeviceApp_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDRMDeviceApp2_INTERFACE_DEFINED__
+#define __IWMDRMDeviceApp2_INTERFACE_DEFINED__
+
+/* interface IWMDRMDeviceApp2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDRMDeviceApp2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("600D6E55-DEA5-4e4c-9C3A-6BD642A45B9D")
+ IWMDRMDeviceApp2 : public IWMDRMDeviceApp
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE QueryDeviceStatus2(
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ DWORD dwFlags,
+ /* [out] */ DWORD *pdwStatus) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDRMDeviceApp2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDRMDeviceApp2 * This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDRMDeviceApp2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDRMDeviceApp2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GenerateMeterChallenge )(
+ IWMDRMDeviceApp2 * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ BSTR bstrMeterCert,
+ /* [out] */ BSTR *pbstrMeterURL,
+ /* [out] */ BSTR *pbstrMeterData);
+
+ HRESULT ( STDMETHODCALLTYPE *ProcessMeterResponse )(
+ IWMDRMDeviceApp2 * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ BYTE *pbResponse,
+ /* [in] */ DWORD cbResponse,
+ /* [out] */ DWORD *pdwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *QueryDeviceStatus )(
+ IWMDRMDeviceApp2 * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [out] */ DWORD *pdwStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AcquireDeviceData )(
+ IWMDRMDeviceApp2 * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ IWMDMProgress3 *pProgressCallback,
+ /* [in] */ DWORD dwFlags,
+ /* [out] */ DWORD *pdwStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *SynchronizeLicenses )(
+ IWMDRMDeviceApp2 * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ IWMDMProgress3 *pProgressCallback,
+ /* [in] */ DWORD cMinCountThreshold,
+ /* [in] */ DWORD cMinHoursThreshold);
+
+ HRESULT ( STDMETHODCALLTYPE *QueryDeviceStatus2 )(
+ IWMDRMDeviceApp2 * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ DWORD dwFlags,
+ /* [out] */ DWORD *pdwStatus);
+
+ END_INTERFACE
+ } IWMDRMDeviceApp2Vtbl;
+
+ interface IWMDRMDeviceApp2
+ {
+ CONST_VTBL struct IWMDRMDeviceApp2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDRMDeviceApp2_QueryInterface(This,riid,ppvObject) \
+ (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
+
+#define IWMDRMDeviceApp2_AddRef(This) \
+ (This)->lpVtbl -> AddRef(This)
+
+#define IWMDRMDeviceApp2_Release(This) \
+ (This)->lpVtbl -> Release(This)
+
+
+#define IWMDRMDeviceApp2_GenerateMeterChallenge(This,pDevice,bstrMeterCert,pbstrMeterURL,pbstrMeterData) \
+ (This)->lpVtbl -> GenerateMeterChallenge(This,pDevice,bstrMeterCert,pbstrMeterURL,pbstrMeterData)
+
+#define IWMDRMDeviceApp2_ProcessMeterResponse(This,pDevice,pbResponse,cbResponse,pdwFlags) \
+ (This)->lpVtbl -> ProcessMeterResponse(This,pDevice,pbResponse,cbResponse,pdwFlags)
+
+#define IWMDRMDeviceApp2_QueryDeviceStatus(This,pDevice,pdwStatus) \
+ (This)->lpVtbl -> QueryDeviceStatus(This,pDevice,pdwStatus)
+
+#define IWMDRMDeviceApp2_AcquireDeviceData(This,pDevice,pProgressCallback,dwFlags,pdwStatus) \
+ (This)->lpVtbl -> AcquireDeviceData(This,pDevice,pProgressCallback,dwFlags,pdwStatus)
+
+#define IWMDRMDeviceApp2_SynchronizeLicenses(This,pDevice,pProgressCallback,cMinCountThreshold,cMinHoursThreshold) \
+ (This)->lpVtbl -> SynchronizeLicenses(This,pDevice,pProgressCallback,cMinCountThreshold,cMinHoursThreshold)
+
+
+#define IWMDRMDeviceApp2_QueryDeviceStatus2(This,pDevice,dwFlags,pdwStatus) \
+ (This)->lpVtbl -> QueryDeviceStatus2(This,pDevice,dwFlags,pdwStatus)
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+HRESULT STDMETHODCALLTYPE IWMDRMDeviceApp2_QueryDeviceStatus2_Proxy(
+ IWMDRMDeviceApp2 * This,
+ /* [in] */ IWMDMDevice *pDevice,
+ /* [in] */ DWORD dwFlags,
+ /* [out] */ DWORD *pdwStatus);
+
+
+void __RPC_STUB IWMDRMDeviceApp2_QueryDeviceStatus2_Stub(
+ IRpcStubBuffer *This,
+ IRpcChannelBuffer *_pRpcChannelBuffer,
+ PRPC_MESSAGE _pRpcMessage,
+ DWORD *_pdwStubPhase);
+
+
+
+#endif /* __IWMDRMDeviceApp2_INTERFACE_DEFINED__ */
+
+
+
+#ifndef __WMDRMDeviceAppLib_LIBRARY_DEFINED__
+#define __WMDRMDeviceAppLib_LIBRARY_DEFINED__
+
+/* library WMDRMDeviceAppLib */
+/* [helpstring][version][uuid] */
+
+
+EXTERN_C const IID LIBID_WMDRMDeviceAppLib;
+
+EXTERN_C const CLSID CLSID_WMDRMDeviceApp;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("5C140836-43DE-11d3-847D-00C04F79DBC0")
+WMDRMDeviceApp;
+#endif
+#endif /* __WMDRMDeviceAppLib_LIBRARY_DEFINED__ */
+
+/* Additional Prototypes for ALL interfaces */
+
+unsigned long __RPC_USER BSTR_UserSize( unsigned long *, unsigned long , BSTR * );
+unsigned char * __RPC_USER BSTR_UserMarshal( unsigned long *, unsigned char *, BSTR * );
+unsigned char * __RPC_USER BSTR_UserUnmarshal(unsigned long *, unsigned char *, BSTR * );
+void __RPC_USER BSTR_UserFree( unsigned long *, BSTR * );
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/Src/Plugins/Portable/pmp_p4s/WMDRMDeviceApp_i.c b/Src/Plugins/Portable/pmp_p4s/WMDRMDeviceApp_i.c
new file mode 100644
index 00000000..8dddbc1e
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/WMDRMDeviceApp_i.c
@@ -0,0 +1,93 @@
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 6.00.0361 */
+/* at Tue Jan 10 22:44:12 2006
+ */
+/* Compiler settings for \Wmsdk\Wmfsdk95\Wmdm\idl\WMDRMDeviceApp.idl:
+ Oicf, W1, Zp8, env=Win32 (32b run)
+ protocol : dce , ms_ext, c_ext, robust
+ error checks: allocation ref bounds_check enum stub_data
+ VC __declspec() decoration level:
+ __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+ DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+//@@MIDL_FILE_HEADING( )
+
+#if !defined(_M_IA64) && !defined(_M_AMD64)
+
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, IID_IWMDRMDeviceApp,0x93AFDB44,0xB1E1,0x411d,0xB8,0x9B,0x75,0xAD,0x4F,0x97,0x88,0x2B);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDRMDeviceApp2,0x600D6E55,0xDEA5,0x4e4c,0x9C,0x3A,0x6B,0xD6,0x42,0xA4,0x5B,0x9D);
+
+
+MIDL_DEFINE_GUID(IID, LIBID_WMDRMDeviceAppLib,0x50BB7AB2,0x0498,0x450D,0xA2,0xC3,0x81,0xCC,0x17,0xFD,0x15,0x4D);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_WMDRMDeviceApp,0x5C140836,0x43DE,0x11d3,0x84,0x7D,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif /* !defined(_M_IA64) && !defined(_M_AMD64)*/
+
diff --git a/Src/Plugins/Portable/pmp_p4s/deviceprovider.cpp b/Src/Plugins/Portable/pmp_p4s/deviceprovider.cpp
new file mode 100644
index 00000000..d85c5205
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/deviceprovider.cpp
@@ -0,0 +1,285 @@
+#include "P4SDevice.h"
+#include "./deviceprovider.h"
+#include "../devices/api_devicemanager.h"
+#include "../nu/threadpool/api_threadpool.h"
+
+void checkForDevices(BOOL *killSwitch);
+BOOL
+QueueThreadFunction(api_threadpool::ThreadPoolFunc func, void *user, intptr_t id);
+
+DeviceProvider::DeviceProvider()
+ : ref(1), activity(0), manager(NULL), readyEvent(NULL), cancelDiscovery(FALSE)
+{
+ InitializeCriticalSection(&lock);
+}
+
+DeviceProvider::~DeviceProvider()
+{
+ CancelDiscovery();
+
+ if (NULL != readyEvent)
+ CloseHandle(readyEvent);
+
+ DeleteCriticalSection(&lock);
+}
+
+HRESULT DeviceProvider::CreateInstance(DeviceProvider **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = new DeviceProvider();
+
+ if (NULL == *instance)
+ return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t DeviceProvider::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t DeviceProvider::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int DeviceProvider::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object)
+ return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_DeviceProvider))
+ *object = static_cast<ifc_deviceprovider*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+void DeviceProvider::Lock()
+{
+ EnterCriticalSection(&lock);
+}
+
+void DeviceProvider::Unlock()
+{
+ LeaveCriticalSection(&lock);
+}
+
+DWORD DeviceProvider::DiscoveryThread()
+{
+ IncrementActivity();
+
+ if (FALSE == cancelDiscovery)
+ {
+ checkForDevices(&cancelDiscovery);
+ }
+
+ DecrementActivity();
+
+ Lock();
+
+ if (NULL != readyEvent)
+ SetEvent(readyEvent);
+
+ Unlock();
+
+ return 0;
+}
+
+static int DeviceProvider_DiscoveryThreadStarter(HANDLE handle, void *user, intptr_t id)
+{
+ DeviceProvider *self;
+ DWORD result;
+
+ self = (DeviceProvider*)user;
+
+ if (NULL != self)
+ result = self->DiscoveryThread();
+ else
+ result = -2;
+
+ return result;
+}
+
+HRESULT DeviceProvider::BeginDiscovery(api_devicemanager *manager)
+{
+ HRESULT hr;
+
+ Lock();
+
+ if (NULL != readyEvent &&
+ WAIT_TIMEOUT == WaitForSingleObject(readyEvent, 0))
+ {
+ hr = E_PENDING;
+ }
+ else
+ {
+ hr = S_OK;
+
+ if (NULL == readyEvent)
+ {
+ readyEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (NULL == readyEvent)
+ hr = E_FAIL;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ cancelDiscovery = FALSE;
+ ResetEvent(readyEvent);
+
+ if (FALSE == QueueThreadFunction(DeviceProvider_DiscoveryThreadStarter,
+ this, 0))
+ {
+ SetEvent(readyEvent);
+ hr = E_FAIL;
+ }
+ }
+ }
+
+ Unlock();
+
+ return hr;
+}
+
+HRESULT DeviceProvider::CancelDiscovery()
+{
+ HRESULT hr;
+
+ hr = S_FALSE;
+
+ Lock();
+
+ if (NULL != readyEvent)
+ {
+ cancelDiscovery = TRUE;
+ if (WAIT_OBJECT_0 == WaitForSingleObject(readyEvent, 0))
+ hr = S_OK;
+
+ cancelDiscovery = FALSE;
+ }
+
+ Unlock();
+
+ return hr;
+}
+
+HRESULT DeviceProvider::GetActive()
+{
+ HRESULT hr;
+
+ Lock();
+
+ if (0 != activity)
+ hr = S_OK;
+ else
+ hr = S_FALSE;
+
+ Unlock();
+
+ return hr;
+}
+
+HRESULT DeviceProvider::Register(api_devicemanager *manager)
+{
+ HRESULT hr;
+
+ if (NULL != this->manager)
+ return E_UNEXPECTED;
+
+ if (NULL == manager)
+ return E_POINTER;
+
+ hr = manager->RegisterProvider(this);
+ if (SUCCEEDED(hr))
+ {
+ this->manager = manager;
+ manager->AddRef();
+ }
+ return hr;
+}
+
+HRESULT DeviceProvider::Unregister()
+{
+ HRESULT hr;
+
+ if (NULL == manager)
+ return E_UNEXPECTED;
+
+ hr = manager->UnregisterProvider(this);
+ manager->Release();
+ manager = NULL;
+ return hr;
+}
+
+size_t DeviceProvider::IncrementActivity()
+{
+ size_t a;
+
+ Lock();
+
+ activity++;
+ if (1 == activity &&
+ NULL != manager)
+ {
+ manager->SetProviderActive(this, TRUE);
+ }
+
+ a = activity;
+
+ Unlock();
+
+ return a;
+}
+
+size_t DeviceProvider::DecrementActivity()
+{
+ size_t a;
+
+ Lock();
+
+ if (0 != activity)
+ {
+ activity--;
+ if (0 == activity &&
+ NULL != manager)
+ {
+ manager->SetProviderActive(this, FALSE);
+ }
+ }
+
+ a = activity;
+
+ Unlock();
+
+ return a;
+}
+
+#define CBCLASS DeviceProvider
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_BEGINDISCOVERY, BeginDiscovery)
+CB(API_CANCELDISCOVERY, CancelDiscovery)
+CB(API_GETACTIVE, GetActive)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_p4s/deviceprovider.h b/Src/Plugins/Portable/pmp_p4s/deviceprovider.h
new file mode 100644
index 00000000..af40a40d
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/deviceprovider.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <wtypes.h>
+#include "../devices/ifc_deviceprovider.h"
+#include "..\..\Library\ml_pmp/pmp.h"
+
+class DeviceProvider : public ifc_deviceprovider
+{
+protected:
+ DeviceProvider();
+ ~DeviceProvider();
+
+public:
+ static HRESULT CreateInstance(DeviceProvider **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_deviceprovider */
+ HRESULT BeginDiscovery(api_devicemanager *manager);
+ HRESULT CancelDiscovery();
+ HRESULT GetActive();
+
+public:
+ HRESULT Register(api_devicemanager *manager);
+ HRESULT Unregister();
+ size_t IncrementActivity();
+ size_t DecrementActivity();
+
+private:
+ void Lock();
+ void Unlock();
+ DWORD DiscoveryThread();
+ friend static int DeviceProvider_DiscoveryThreadStarter(HANDLE handle, void *user_data, intptr_t id);
+
+protected:
+ size_t ref;
+ size_t activity;
+ CRITICAL_SECTION lock;
+ api_devicemanager *manager;
+ HANDLE readyEvent;
+ BOOL cancelDiscovery;
+
+protected:
+ RECVS_DISPATCH;
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_p4s/key-sub-523.c b/Src/Plugins/Portable/pmp_p4s/key-sub-523.c
new file mode 100644
index 00000000..9e74d107
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/key-sub-523.c
@@ -0,0 +1,531 @@
+#include "wtypes.h"
+BYTE abPVK[4096] = {
+ 0x3E, 0x45, 0xEB, 0x7B, 0xC8, 0xE7, 0x19, 0x8D,
+ 0xFA, 0x55, 0xBF, 0x7B, 0xE8, 0x2E, 0xDE, 0xB2,
+ 0xBF, 0xD1, 0x2D, 0xA5, 0xEA, 0x0A, 0x04, 0xB0,
+ 0x03, 0x59, 0x26, 0x15, 0x78, 0xDC, 0xD1, 0x9F,
+ 0xCD, 0x58, 0xAC, 0x29, 0x01, 0x27, 0x24, 0x02,
+ 0xBE, 0xF4, 0xD6, 0xA3, 0xFE, 0x8D, 0xEF, 0xC8,
+ 0x47, 0xEE, 0x45, 0x99, 0xFF, 0xBC, 0x27, 0xA1,
+ 0xB9, 0x9E, 0xC4, 0xC5, 0xD5, 0xC3, 0xDC, 0x22,
+ 0x1A, 0x0A, 0xE5, 0xCF, 0xD8, 0x5F, 0x76, 0x62,
+ 0xE3, 0xC1, 0x7D, 0xB5, 0xFA, 0x66, 0x7C, 0x5E,
+ 0xB8, 0x85, 0x43, 0x70, 0x90, 0x4E, 0x37, 0x65,
+ 0x62, 0xDE, 0x60, 0xAA, 0xFB, 0x61, 0x4D, 0xF0,
+ 0x7A, 0x98, 0x49, 0x0B, 0x91, 0x57, 0xC8, 0x3E,
+ 0x5D, 0x07, 0x9C, 0x17, 0x3E, 0x7D, 0x4C, 0x63,
+ 0x3A, 0x05, 0x5C, 0x8B, 0x49, 0x05, 0xCA, 0xEA,
+ 0x4C, 0x8E, 0xA7, 0x75, 0xE5, 0xFA, 0x45, 0xCF,
+ 0x96, 0xD3, 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E,
+ 0x45, 0xEB, 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA,
+ 0x55, 0xBF, 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF,
+ 0xD1, 0x2D, 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03,
+ 0x59, 0x26, 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD,
+ 0x58, 0xAC, 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE,
+ 0xF4, 0xD6, 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47,
+ 0xEE, 0x45, 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9,
+ 0x9E, 0xC4, 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A,
+ 0x0A, 0xE5, 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3,
+ 0xC1, 0x7D, 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8,
+ 0x85, 0x43, 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62,
+ 0xDE, 0x60, 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A,
+ 0x98, 0x49, 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D,
+ 0x07, 0x9C, 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A,
+ 0x05, 0x5C, 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C,
+ 0x8E, 0xA7, 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96,
+ 0xD3, 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45,
+ 0xEB, 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55,
+ 0xBF, 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1,
+ 0x2D, 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59,
+ 0x26, 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58,
+ 0xAC, 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4,
+ 0xD6, 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE,
+ 0x45, 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E,
+ 0xC4, 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A, 0x0A,
+ 0xE5, 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1,
+ 0x7D, 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85,
+ 0x43, 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE,
+ 0x60, 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98,
+ 0x49, 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07,
+ 0x9C, 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05,
+ 0x5C, 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E,
+ 0xA7, 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3,
+ 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB,
+ 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55, 0xBF,
+ 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1, 0x2D,
+ 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59, 0x26,
+ 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58, 0xAC,
+ 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4, 0xD6,
+ 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE, 0x45,
+ 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E, 0xC4,
+ 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A, 0x0A, 0xE5,
+ 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1, 0x7D,
+ 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85, 0x43,
+ 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE, 0x60,
+ 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98, 0x49,
+ 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07, 0x9C,
+ 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05, 0x5C,
+ 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E, 0xA7,
+ 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3, 0x81,
+ 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB, 0x7B,
+ 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55, 0xBF, 0x7B,
+ 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1, 0x2D, 0xA5,
+ 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59, 0x26, 0x15,
+ 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58, 0xAC, 0x29,
+ 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4, 0xD6, 0xA3,
+ 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE, 0x45, 0x99,
+ 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E, 0xC4, 0xC5,
+ 0xD5, 0xC3, 0xDC, 0x22, 0x1A, 0x0A, 0xE5, 0xCF,
+ 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1, 0x7D, 0xB5,
+ 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85, 0x43, 0x70,
+ 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE, 0x60, 0xAA,
+ 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98, 0x49, 0x0B,
+ 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07, 0x9C, 0x17,
+ 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05, 0x5C, 0x8B,
+ 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E, 0xA7, 0x75,
+ 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3, 0x81, 0xEA,
+ 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB, 0x7B, 0xC8,
+ 0xE7, 0x19, 0x8D, 0xFA, 0x55, 0xBF, 0x7B, 0xE8,
+ 0x2E, 0xDE, 0xB2, 0xBF, 0xD1, 0x2D, 0xA5, 0xEA,
+ 0x0A, 0x04, 0xB0, 0x03, 0x59, 0x26, 0x15, 0x78,
+ 0xDC, 0xD1, 0x9F, 0xCD, 0x58, 0xAC, 0x29, 0x01,
+ 0x27, 0x24, 0x02, 0xBE, 0xF4, 0xD6, 0xA3, 0xFE,
+ 0x8D, 0xEF, 0xC8, 0x47, 0xEE, 0x45, 0x99, 0xFF,
+ 0xBC, 0x27, 0xA1, 0xB9, 0x9E, 0xC4, 0xC5, 0xD5,
+ 0xC3, 0xDC, 0x22, 0x1A, 0x0A, 0xE5, 0xCF, 0xD8,
+ 0x5F, 0x76, 0x62, 0xE3, 0xC1, 0x7D, 0xB5, 0xFA,
+ 0x66, 0x7C, 0x5E, 0xB8, 0x85, 0x43, 0x70, 0x90,
+ 0x4E, 0x37, 0x65, 0x62, 0xDE, 0x60, 0xAA, 0xFB,
+ 0x61, 0x4D, 0xF0, 0x7A, 0x98, 0x49, 0x0B, 0x91,
+ 0x57, 0xC8, 0x3E, 0x5D, 0x07, 0x9C, 0x17, 0x3E,
+ 0x7D, 0x4C, 0x63, 0x3A, 0x05, 0x5C, 0x8B, 0x49,
+ 0x05, 0xCA, 0xEA, 0x4C, 0x8E, 0xA7, 0x75, 0xE5,
+ 0xFA, 0x45, 0xCF, 0x96, 0xD3, 0x81, 0xEA, 0x61,
+ 0x48, 0x8F, 0x3E, 0x45, 0xEB, 0x7B, 0xC8, 0xE7,
+ 0x19, 0x8D, 0xFA, 0x55, 0xBF, 0x7B, 0xE8, 0x2E,
+ 0xDE, 0xB2, 0xBF, 0xD1, 0x2D, 0xA5, 0xEA, 0x0A,
+ 0x04, 0xB0, 0x03, 0x59, 0x26, 0x15, 0x78, 0xDC,
+ 0xD1, 0x9F, 0xCD, 0x58, 0xAC, 0x29, 0x01, 0x27,
+ 0x24, 0x02, 0xBE, 0xF4, 0xD6, 0xA3, 0xFE, 0x8D,
+ 0xEF, 0xC8, 0x47, 0xEE, 0x45, 0x99, 0xFF, 0xBC,
+ 0x27, 0xA1, 0xB9, 0x9E, 0xC4, 0xC5, 0xD5, 0xC3,
+ 0xDC, 0x22, 0x1A, 0x0A, 0xE5, 0xCF, 0xD8, 0x5F,
+ 0x76, 0x62, 0xE3, 0xC1, 0x7D, 0xB5, 0xFA, 0x66,
+ 0x7C, 0x5E, 0xB8, 0x85, 0x43, 0x70, 0x90, 0x4E,
+ 0x37, 0x65, 0x62, 0xDE, 0x60, 0xAA, 0xFB, 0x61,
+ 0x4D, 0xF0, 0x7A, 0x98, 0x49, 0x0B, 0x91, 0x57,
+ 0xC8, 0x3E, 0x5D, 0x07, 0x9C, 0x17, 0x3E, 0x7D,
+ 0x4C, 0x63, 0x3A, 0x05, 0x5C, 0x8B, 0x49, 0x05,
+ 0xCA, 0xEA, 0x4C, 0x8E, 0xA7, 0x75, 0xE5, 0xFA,
+ 0x45, 0xCF, 0x96, 0xD3, 0x81, 0xEA, 0x61, 0x48,
+ 0x8F, 0x3E, 0x45, 0xEB, 0x7B, 0xC8, 0xE7, 0x19,
+ 0x8D, 0xFA, 0x55, 0xBF, 0x7B, 0xE8, 0x2E, 0xDE,
+ 0xB2, 0xBF, 0xD1, 0x2D, 0xA5, 0xEA, 0x0A, 0x04,
+ 0xB0, 0x03, 0x59, 0x26, 0x15, 0x78, 0xDC, 0xD1,
+ 0x9F, 0xCD, 0x58, 0xAC, 0x29, 0x01, 0x27, 0x24,
+ 0x02, 0xBE, 0xF4, 0xD6, 0xA3, 0xFE, 0x8D, 0xEF,
+ 0xC8, 0x47, 0xEE, 0x45, 0x99, 0xFF, 0xBC, 0x27,
+ 0xA1, 0xB9, 0x9E, 0xC4, 0xC5, 0xD5, 0xC3, 0xDC,
+ 0x22, 0x1A, 0x0A, 0xE5, 0xCF, 0xD8, 0x5F, 0x76,
+ 0x62, 0xE3, 0xC1, 0x7D, 0xB5, 0xFA, 0x66, 0x7C,
+ 0x5E, 0xB8, 0x85, 0x43, 0x70, 0x90, 0x4E, 0x37,
+ 0x65, 0x62, 0xDE, 0x60, 0xAA, 0xFB, 0x61, 0x4D,
+ 0xF0, 0x7A, 0x98, 0x49, 0x0B, 0x91, 0x57, 0xC8,
+ 0x3E, 0x5D, 0x07, 0x9C, 0x17, 0x3E, 0x7D, 0x4C,
+ 0x63, 0x3A, 0x05, 0x5C, 0x8B, 0x49, 0x05, 0xCA,
+ 0xEA, 0x4C, 0x8E, 0xA7, 0x75, 0xE5, 0xFA, 0x45,
+ 0xCF, 0x96, 0xD3, 0x81, 0xEA, 0x61, 0x48, 0x8F,
+ 0x3E, 0x45, 0xEB, 0x7B, 0xC8, 0xE7, 0x19, 0x8D,
+ 0xFA, 0x55, 0xBF, 0x7B, 0xE8, 0x2E, 0xDE, 0xB2,
+ 0xBF, 0xD1, 0x2D, 0xA5, 0xEA, 0x0A, 0x04, 0xB0,
+ 0x03, 0x59, 0x26, 0x15, 0x78, 0xDC, 0xD1, 0x9F,
+ 0xCD, 0x58, 0xAC, 0x29, 0x01, 0x27, 0x24, 0x02,
+ 0xBE, 0xF4, 0xD6, 0xA3, 0xFE, 0x8D, 0xEF, 0xC8,
+ 0x47, 0xEE, 0x45, 0x99, 0xFF, 0xBC, 0x27, 0xA1,
+ 0xB9, 0x9E, 0xC4, 0xC5, 0xD5, 0xC3, 0xDC, 0x22,
+ 0x1A, 0x0A, 0xE5, 0xCF, 0xD8, 0x5F, 0x76, 0x62,
+ 0xE3, 0xC1, 0x7D, 0xB5, 0xFA, 0x66, 0x7C, 0x5E,
+ 0xB8, 0x85, 0x43, 0x70, 0x90, 0x4E, 0x37, 0x65,
+ 0x62, 0xDE, 0x60, 0xAA, 0xFB, 0x61, 0x4D, 0xF0,
+ 0x7A, 0x98, 0x49, 0x0B, 0x91, 0x57, 0xC8, 0x3E,
+ 0x5D, 0x07, 0x9C, 0x17, 0x3E, 0x7D, 0x4C, 0x63,
+ 0x3A, 0x05, 0x5C, 0x8B, 0x49, 0x05, 0xCA, 0xEA,
+ 0x4C, 0x8E, 0xA7, 0x75, 0xE5, 0xFA, 0x45, 0xCF,
+ 0x96, 0xD3, 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E,
+ 0x45, 0xEB, 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA,
+ 0x55, 0xBF, 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF,
+ 0xD1, 0x2D, 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03,
+ 0x59, 0x26, 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD,
+ 0x58, 0xAC, 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE,
+ 0xF4, 0xD6, 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47,
+ 0xEE, 0x45, 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9,
+ 0x9E, 0xC4, 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A,
+ 0x0A, 0xE5, 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3,
+ 0xC1, 0x7D, 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8,
+ 0x85, 0x43, 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62,
+ 0xDE, 0x60, 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A,
+ 0x98, 0x49, 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D,
+ 0x07, 0x9C, 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A,
+ 0x05, 0x5C, 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C,
+ 0x8E, 0xA7, 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96,
+ 0xD3, 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45,
+ 0xEB, 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55,
+ 0xBF, 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1,
+ 0x2D, 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59,
+ 0x26, 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58,
+ 0xAC, 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4,
+ 0xD6, 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE,
+ 0x45, 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E,
+ 0xC4, 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A, 0x0A,
+ 0xE5, 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1,
+ 0x7D, 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85,
+ 0x43, 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE,
+ 0x60, 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98,
+ 0x49, 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07,
+ 0x9C, 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05,
+ 0x5C, 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E,
+ 0xA7, 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3,
+ 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB,
+ 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55, 0xBF,
+ 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1, 0x2D,
+ 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59, 0x26,
+ 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58, 0xAC,
+ 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4, 0xD6,
+ 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE, 0x45,
+ 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E, 0xC4,
+ 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A, 0x0A, 0xE5,
+ 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1, 0x7D,
+ 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85, 0x43,
+ 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE, 0x60,
+ 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98, 0x49,
+ 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07, 0x9C,
+ 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05, 0x5C,
+ 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E, 0xA7,
+ 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3, 0x81,
+ 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB, 0x7B,
+ 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55, 0xBF, 0x7B,
+ 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1, 0x2D, 0xA5,
+ 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59, 0x26, 0x15,
+ 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58, 0xAC, 0x29,
+ 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4, 0xD6, 0xA3,
+ 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE, 0x45, 0x99,
+ 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E, 0xC4, 0xC5,
+ 0xD5, 0xC3, 0xDC, 0x22, 0x1A, 0x0A, 0xE5, 0xCF,
+ 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1, 0x7D, 0xB5,
+ 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85, 0x43, 0x70,
+ 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE, 0x60, 0xAA,
+ 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98, 0x49, 0x0B,
+ 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07, 0x9C, 0x17,
+ 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05, 0x5C, 0x8B,
+ 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E, 0xA7, 0x75,
+ 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3, 0x81, 0xEA,
+ 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB, 0x7B, 0xC8,
+ 0xE7, 0x19, 0x8D, 0xFA, 0x55, 0xBF, 0x7B, 0xE8,
+ 0x2E, 0xDE, 0xB2, 0xBF, 0xD1, 0x2D, 0xA5, 0xEA,
+ 0x0A, 0x04, 0xB0, 0x03, 0x59, 0x26, 0x15, 0x78,
+ 0xDC, 0xD1, 0x9F, 0xCD, 0x58, 0xAC, 0x29, 0x01,
+ 0x27, 0x24, 0x02, 0xBE, 0xF4, 0xD6, 0xA3, 0xFE,
+ 0x8D, 0xEF, 0xC8, 0x47, 0xEE, 0x45, 0x99, 0xFF,
+ 0xBC, 0x27, 0xA1, 0xB9, 0x9E, 0xC4, 0xC5, 0xD5,
+ 0x7D, 0xC3, 0xEB, 0x22, 0x1A, 0x0A, 0xE5, 0x57,
+ 0xCF, 0xA2, 0x5F, 0x76, 0x62, 0xE3, 0xC1, 0x7D,
+ 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85, 0x43,
+ 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE, 0x60,
+ 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98, 0x49,
+ 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x1A, 0x5D, 0xAF,
+ 0x9C, 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05,
+ 0x5C, 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E,
+ 0xA7, 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3,
+ 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB,
+ 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55, 0xBF,
+ 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1, 0x2D,
+ 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59, 0x26,
+ 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58, 0xAC,
+ 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4, 0xD6,
+ 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE, 0x45,
+ 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E, 0xC4,
+ 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A, 0x0A, 0xE5,
+ 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1, 0x7D,
+ 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85, 0x43,
+ 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE, 0x60,
+ 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98, 0x49,
+ 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07, 0x9C,
+ 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05, 0x5C,
+ 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E, 0xA7,
+ 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3, 0x81,
+ 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB, 0x7B,
+ 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55, 0xBF, 0x7B,
+ 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1, 0x2D, 0xA5,
+ 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59, 0x26, 0x15,
+ 0x78, 0xDC, 0xD1, 0x9F, 0x07, 0xCD, 0xD5, 0xAC,
+ 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4, 0xD6,
+ 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE, 0x45,
+ 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E, 0xC4,
+ 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A, 0x65, 0x0A,
+ 0x63, 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1,
+ 0x7D, 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85,
+ 0x43, 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE,
+ 0x60, 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98,
+ 0x49, 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07,
+ 0x9C, 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05,
+ 0x5C, 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E,
+ 0xA7, 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3,
+ 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB,
+ 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55, 0xBF,
+ 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1, 0x2D,
+ 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59, 0x26,
+ 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58, 0xAC,
+ 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4, 0xD6,
+ 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE, 0x45,
+ 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E, 0xC4,
+ 0xC5, 0xD5, 0xC3, 0x74, 0xDC, 0x10, 0x1A, 0x0A,
+ 0xE5, 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1,
+ 0x7D, 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85,
+ 0x43, 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE,
+ 0x60, 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98,
+ 0x49, 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07,
+ 0x9C, 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05,
+ 0x5C, 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E,
+ 0xA7, 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3,
+ 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB,
+ 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55, 0xBF,
+ 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1, 0x2D,
+ 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59, 0x26,
+ 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58, 0xAC,
+ 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4, 0xD6,
+ 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE, 0x45,
+ 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E, 0xC4,
+ 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A, 0x0A, 0xE5,
+ 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1, 0x7D,
+ 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85, 0x43,
+ 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE, 0x60,
+ 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98, 0x49,
+ 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07, 0x9C,
+ 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05, 0x5C,
+ 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E, 0xA7,
+ 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x70, 0x96, 0x57,
+ 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB,
+ 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55, 0xBF,
+ 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1, 0x2D,
+ 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59, 0x26,
+ 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58, 0xAC,
+ 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4, 0xD6,
+ 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE, 0x45,
+ 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E, 0xC4,
+ 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A, 0x0A, 0xE5,
+ 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1, 0x7D,
+ 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85, 0x43,
+ 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE, 0x60,
+ 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98, 0x49,
+ 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07, 0x9C,
+ 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05, 0x5C,
+ 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E, 0xA7,
+ 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3, 0x81,
+ 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB, 0x7B,
+ 0xC8, 0x2C, 0xE7, 0xFA, 0x8D, 0xFA, 0x55, 0xBF,
+ 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1, 0x2D,
+ 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59, 0x26,
+ 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58, 0xAC,
+ 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4, 0xD6,
+ 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE, 0x45,
+ 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E, 0xC4,
+ 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A, 0x0A, 0xE5,
+ 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1, 0x7D,
+ 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85, 0x43,
+ 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE, 0x60,
+ 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98, 0x49,
+ 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07, 0x9C,
+ 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05, 0x5C,
+ 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E, 0xA7,
+ 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3, 0x81,
+ 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB, 0x7B,
+ 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55, 0xBF, 0x7B,
+ 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1, 0x2D, 0xA5,
+ 0x51, 0xEA, 0xEA, 0x04, 0xB0, 0x03, 0x59, 0x26,
+ 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58, 0xAC,
+ 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4, 0xD6,
+ 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE, 0x45,
+ 0x99, 0xFF, 0xBC, 0x27, 0x6D, 0xA1, 0xA1, 0x9E,
+ 0xC4, 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A, 0x0A,
+ 0xE5, 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1,
+ 0x7D, 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85,
+ 0x43, 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE,
+ 0x60, 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98,
+ 0x49, 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07,
+ 0x9C, 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05,
+ 0x5C, 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E,
+ 0xA7, 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3,
+ 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB,
+ 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55, 0xBF,
+ 0x7B, 0x58, 0xE8, 0x8A, 0xDE, 0xB2, 0xBF, 0xD1,
+ 0x2D, 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59,
+ 0x26, 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58,
+ 0xAC, 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4,
+ 0xD6, 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE,
+ 0x45, 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E,
+ 0xC4, 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A, 0x0A,
+ 0xE5, 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1,
+ 0x7D, 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85,
+ 0x43, 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE,
+ 0x60, 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98,
+ 0x49, 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07,
+ 0x9C, 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05,
+ 0x5C, 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E,
+ 0xA7, 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3,
+ 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB,
+ 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55, 0xBF,
+ 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1, 0x2D,
+ 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59, 0x26,
+ 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58, 0xAC,
+ 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4, 0xD6,
+ 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE, 0x45,
+ 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E, 0xC4,
+ 0xC5, 0xD5, 0xC3, 0xDC, 0x72, 0x22, 0x0D, 0x0A,
+ 0xE5, 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1,
+ 0x7D, 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85,
+ 0x43, 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE,
+ 0x60, 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98,
+ 0x51, 0x49, 0xC9, 0x91, 0x57, 0xC8, 0x3E, 0x5D,
+ 0x07, 0x9C, 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A,
+ 0x05, 0x5C, 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C,
+ 0x8E, 0xA7, 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96,
+ 0xD3, 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45,
+ 0xEB, 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x55,
+ 0xBF, 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1,
+ 0x2D, 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59,
+ 0x26, 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58,
+ 0xAC, 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4,
+ 0xD6, 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE,
+ 0x45, 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E,
+ 0xC4, 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A, 0x0A,
+ 0xE5, 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3, 0xC1,
+ 0x7D, 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8, 0x85,
+ 0x43, 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62, 0xDE,
+ 0x60, 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A, 0x98,
+ 0x49, 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D, 0x07,
+ 0x9C, 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A, 0x05,
+ 0x5C, 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C, 0x8E,
+ 0xA7, 0x75, 0xE5, 0xFA, 0x45, 0xCF, 0x96, 0xD3,
+ 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E, 0x45, 0xEB,
+ 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA, 0x70, 0x55,
+ 0x70, 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF, 0xD1,
+ 0x2D, 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03, 0x59,
+ 0x26, 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD, 0x58,
+ 0xAC, 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE, 0xF4,
+ 0xD6, 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47, 0xEE,
+ 0x45, 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9, 0x9E,
+ 0x1E, 0xC4, 0xDA, 0xD5, 0xC3, 0xDC, 0x22, 0x1A,
+ 0x0A, 0xE5, 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3,
+ 0xC1, 0x7D, 0xB5, 0xFA, 0x66, 0x7C, 0x5E, 0xB8,
+ 0x85, 0x43, 0x70, 0x90, 0x4E, 0x37, 0x65, 0x62,
+ 0xDE, 0x60, 0xAA, 0xFB, 0x61, 0x4D, 0xF0, 0x7A,
+ 0x98, 0x49, 0x0B, 0x91, 0x57, 0xC8, 0x3E, 0x5D,
+ 0x07, 0x9C, 0x17, 0x3E, 0x7D, 0x4C, 0x63, 0x3A,
+ 0x05, 0x5C, 0x8B, 0x49, 0x05, 0xCA, 0xEA, 0x4C,
+ 0x76, 0x8E, 0x12, 0x75, 0xE5, 0xFA, 0x45, 0xCF,
+ 0x96, 0xD3, 0x81, 0xEA, 0x61, 0x48, 0x8F, 0x3E,
+ 0x45, 0xEB, 0x7B, 0xC8, 0xE7, 0x19, 0x8D, 0xFA,
+ 0x55, 0xBF, 0x7B, 0xE8, 0x2E, 0xDE, 0xB2, 0xBF,
+ 0xD1, 0x2D, 0xA5, 0xEA, 0x0A, 0x04, 0xB0, 0x03,
+ 0x59, 0x26, 0x15, 0x78, 0xDC, 0xD1, 0x9F, 0xCD,
+ 0x58, 0xAC, 0x29, 0x01, 0x27, 0x24, 0x02, 0xBE,
+ 0xF4, 0xD6, 0xA3, 0xFE, 0x8D, 0xEF, 0xC8, 0x47,
+ 0xEE, 0x45, 0x99, 0xFF, 0xBC, 0x27, 0xA1, 0xB9,
+ 0x9E, 0xC4, 0xC5, 0xD5, 0xC3, 0xDC, 0x22, 0x1A,
+ 0x0A, 0xE5, 0xCF, 0xD8, 0x5F, 0x76, 0x62, 0xE3,
+ 0xC1, 0x7D, 0xB5, 0x95, 0x32, 0x86, 0x72, 0x41,
+ 0x37, 0xC8, 0xCB, 0x9D, 0x31, 0xBE, 0x6C, 0xF7,
+ 0xB1, 0xCA, 0x62, 0x6B, 0x39, 0x3D, 0xF1, 0xA4,
+ 0x06, 0x1F, 0x2E, 0xC2, 0xCF, 0x96, 0xD5, 0x7F,
+ 0xEC, 0x5F, 0x4A, 0x8D, 0xDB, 0x0F, 0x60, 0x8B,
+ 0x1A, 0x36, 0xB8, 0x74, 0x54, 0xF1, 0x47, 0x96,
+ 0x04, 0xB5, 0xCB, 0xC7, 0x08, 0x5F, 0x55, 0xB5,
+ 0x84, 0x75, 0xA3, 0x70, 0x4E, 0xC2, 0xA7, 0x8A,
+ 0x9D, 0x7F, 0x6F, 0x0F, 0x9C, 0xE7, 0x09, 0x9F,
+ 0xE1, 0xAA, 0x61, 0x94, 0xAB, 0x0F, 0x81, 0xCF,
+ 0x7B, 0x56, 0x8D, 0xE1, 0x6D, 0x38, 0x3E, 0x57,
+ 0xA7, 0x61, 0xC5, 0x78, 0x6D, 0xBA, 0x53, 0xA1,
+ 0xA4, 0xE6, 0xDA, 0xFE, 0x0A, 0xDA, 0xA7, 0x2F,
+ 0xF9, 0xCA, 0xE4, 0x85, 0x21, 0x2B, 0x60, 0x96,
+ 0x42, 0xDF, 0x1E, 0x20, 0x69, 0x88, 0x54, 0xC5,
+ 0xDB, 0x8C, 0xB0, 0x39, 0x57, 0xD8, 0xFC, 0xA6,
+ 0xA3, 0xB6, 0x0A, 0xEF, 0xF8, 0x7E, 0x2F, 0x81,
+ 0xA9, 0xD6, 0x50, 0x1C, 0xB5, 0xD5, 0x57, 0x7B,
+ 0xF3, 0xBD, 0x22, 0x40, 0x18, 0x80, 0xA0, 0x43,
+ 0x14, 0x1D, 0xCF, 0x55, 0xAF, 0x24, 0x9F, 0xEE,
+ 0x35, 0xDB, 0x1F, 0x50, 0x07, 0x96, 0x50, 0xD1,
+ 0x01, 0x37, 0x14, 0xE7, 0xD3, 0xA1, 0xCA, 0xF4,
+ 0x75, 0xCF, 0xDE, 0x8D, 0x15, 0x6D, 0x4D, 0xF6,
+ 0x41, 0xA0, 0xF6, 0x62, 0x32, 0x4B, 0x78, 0xA8,
+ 0xC6, 0x62, 0x03, 0xA1, 0x10, 0xE2, 0xA3, 0x9B,
+ 0x24, 0xCB, 0x5A, 0xA8, 0x2D, 0x94, 0x96, 0x57,
+ 0x97, 0x71, 0xAE, 0x30, 0x2D, 0x31, 0x2B, 0xCC,
+ 0xF7, 0x3F, 0x09, 0x8F, 0x8C, 0x5F, 0xBE, 0x4C,
+ 0xB0, 0xEC, 0xA5, 0x38, 0xBB, 0xA7, 0x55, 0x9E,
+ 0x35, 0x89, 0xA3, 0x44, 0xE2, 0xEA, 0xEF, 0x1E,
+ 0x8C, 0x65, 0x83, 0x24, 0x28, 0x65, 0x8F, 0x4B,
+ 0x6B, 0x96, 0xDF, 0x0D, 0xCA, 0xB8, 0xB0, 0xB0,
+ 0xE0, 0xB0, 0x28, 0x6A, 0x57, 0x1E, 0xEA, 0xD4,
+ 0x06, 0x67, 0x1A, 0x8D, 0xFC, 0x53, 0x2A, 0xA9,
+ 0xE4, 0xAB, 0x2F, 0x61, 0x62, 0xA8, 0x64, 0xF6,
+ 0xE4, 0x95, 0xAA, 0x10, 0x19, 0x37, 0xB7, 0xDC,
+ 0xEC, 0xB5, 0x26, 0xD4, 0xED, 0xE4, 0x5E, 0xAD,
+ 0xF6, 0xFF, 0x14, 0x6A, 0x1A, 0xF5, 0x94, 0x80,
+ 0x39, 0x78, 0x1C, 0xC6, 0xC4, 0xD6, 0xC4, 0xDD,
+ 0x88, 0x4F, 0x66, 0x9D, 0xA4, 0x80, 0xA5, 0x0B,
+ 0xE7, 0x9C, 0x3F, 0x4A, 0x1A, 0x1B, 0x39, 0x82,
+ 0x45, 0x07, 0xF7, 0x24, 0x23, 0x9D, 0x21, 0x69,
+ 0x21, 0xB9, 0x06, 0xF5, 0x57, 0xBC, 0x17, 0xB1,
+ 0x3D, 0xB9, 0x11, 0xEB, 0xCD, 0x42, 0xF5, 0x3C,
+ 0xD6, 0x25, 0xAF, 0xDC, 0x4E, 0xEF, 0x7B, 0x30,
+ 0x7F, 0xAB, 0x39, 0xEF, 0x40, 0x6A, 0xFA, 0xAE,
+ 0x66, 0x2B, 0xE3, 0xAD, 0xC6, 0x31, 0x68, 0xF7,
+ 0x4B, 0x30, 0x37, 0x5A, 0x6C, 0x68, 0x75, 0x33,
+ 0xAB, 0xE8, 0x74, 0x9A, 0x37, 0xDF, 0x74, 0x62,
+ 0xE5, 0xBF, 0xE8, 0x48, 0xC5, 0x3C, 0xF7, 0xD2,
+ 0xA9, 0xF4, 0x9B, 0xDD, 0x79, 0x5E, 0xE9, 0xBB,
+ 0x87, 0xA7, 0xA7, 0x81, 0x73, 0xD8, 0x07, 0xCE,
+ 0x4C, 0x85, 0x7D, 0x37, 0x44, 0xB5, 0x16, 0x22,
+ 0xE4, 0x6B, 0x9C, 0xD1, 0xEB, 0x80, 0x90, 0x55,
+ 0xFB, 0xD7, 0xD7, 0x97, 0x70, 0x18, 0xC6, 0x5C,
+ 0x3E, 0x97, 0x65, 0x89, 0xEB, 0x95, 0x46, 0x41,
+ 0xC0, 0x3F, 0x8A, 0x41, 0x73, 0x8B, 0x55, 0x93,
+ 0x3F, 0x13, 0xB8, 0x32, 0x61, 0xCA, 0x40, 0x28,
+ 0x70, 0x1C, 0x28, 0x95, 0x2D, 0x27, 0x34, 0x59,
+ 0x07, 0x34, 0x7F, 0xAC, 0xD1, 0x57, 0x13, 0x5B,
+ 0x90, 0x13, 0x71, 0xE0, 0x65, 0x0B, 0x9C, 0x7F,
+ 0x71, 0x72, 0x6D, 0xA3, 0xD2, 0x1F, 0x19, 0xA5,
+ 0x16, 0x76, 0x77, 0x02, 0x46, 0x6C, 0x2D, 0xAF,
+ 0x13, 0x4B, 0x3B, 0xC8, 0x33, 0x35, 0xF5, 0x38,
+ 0x0D, 0xBA, 0xC8, 0x99, 0x68, 0x53, 0xEE, 0xE4,
+ 0xC5, 0x48, 0x1E, 0x15, 0xDA, 0xDF, 0x29, 0xAF,
+ 0xAD, 0x16, 0xAD, 0x74, 0x4E, 0x2A, 0xDA, 0x1A,
+ 0xEF, 0x66, 0x78, 0x95, 0x4D, 0x07, 0x30, 0xB6,
+ 0x41, 0x53, 0x44, 0x27, 0x3E, 0xE9, 0x48, 0xC7,
+ 0x3A, 0xF9, 0xD0, 0xAB, 0xF2, 0x9D, 0xDB, 0x7B,
+ 0xF3, 0x56, 0xF0, 0x48, 0xFC, 0x39, 0xA8, 0x53,
+ 0xA2, 0xC8, 0x8F, 0xD8, 0x12, 0x5B, 0x29, 0x78,
+ 0x49, 0xCA, 0x04, 0x65, 0xB4, 0xF3, 0xD1, 0x42,
+ 0x5D, 0x6F, 0x34, 0x44, 0x4D, 0x4C, 0x84, 0x7E,
+ 0xCF, 0x15, 0x21, 0x31, 0x8E, 0x35, 0x1B, 0x44,
+ 0xAA, 0xEE, 0x3B, 0xA2, 0x8C, 0xCC, 0x1C, 0x4E,
+ 0xD3, 0xFD, 0xD6, 0x41, 0x2D, 0x9F, 0xBC, 0x02,
+ 0xFB, 0x51, 0x5D, 0x42, 0x62, 0x37, 0x39, 0x8D,
+ 0x6D, 0x15, 0xFA, 0x8D, 0x0A, 0x89, 0x00, 0x14
+};
+BYTE abCert[100] = {
+ 0x00, 0x01, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
+ 0xFB, 0x05, 0xF0, 0xAC, 0x1C, 0x41, 0x84, 0xEC,
+ 0x64, 0xE5, 0xDB, 0x29, 0x03, 0x2C, 0xFA, 0x4D,
+ 0xA8, 0x95, 0xB7, 0x75, 0x9A, 0xA5, 0x31, 0xEE,
+ 0x2E, 0x5B, 0xF0, 0x49, 0x1B, 0x11, 0xD8, 0x27,
+ 0x8C, 0x82, 0x76, 0xF7, 0x61, 0x15, 0xB6, 0x2C,
+ 0xE7, 0xDB, 0x52, 0x12, 0x88, 0x64, 0xB9, 0x8F,
+ 0xB2, 0x13, 0x9C, 0x7C, 0xFE, 0x7C, 0xF4, 0x71,
+ 0x1F, 0x1E, 0xFA, 0x67, 0x03, 0x91, 0x43, 0xFC,
+ 0x7F, 0x96, 0x8E, 0xD2, 0xEE, 0xF4, 0xA2, 0x8A,
+ 0x89, 0xAA, 0xAA, 0x91, 0xA8, 0x19, 0xC3, 0x0A,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE8,
+ 0x00, 0x00, 0x02, 0x0B
+};
+//=======================================================
diff --git a/Src/Plugins/Portable/pmp_p4s/main.cpp b/Src/Plugins/Portable/pmp_p4s/main.cpp
new file mode 100644
index 00000000..0f467422
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/main.cpp
@@ -0,0 +1,571 @@
+//#define PLUGIN_NAME "Nullsoft PlaysForSure Plug-in"
+#define PLUGIN_VERSION L"0.99.1"
+
+//#define _WIN32_WINNT 0x0400
+#define _WIN32_DCOM
+#define INITGUID
+#include "P4SDevice.h"
+#include "..\..\General\gen_ml/itemlist.h"
+#include "key-sub-523.c" // This key is the authentication key.
+#include "mswmdm.h"
+#include "deviceprovider.h"
+#include "../nu/threadpool/api_threadpool.h"
+//#include "key.c"
+
+C_ItemList devices;
+
+// wasabi based services for localisation support
+api_language *WASABI_API_LNG = 0;
+HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
+api_memmgr *memoryManager=0;
+api_albumart *AGAVE_API_ALBUMART=0;
+api_threadpool *WASABI_API_THREADPOOL = 0;
+api_devicemanager *AGAVE_API_DEVICEMANAGER = 0;
+
+int init();
+void quit();
+intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3);
+
+PMPDevicePlugin plugin = {PMPHDR_VER,0,init,quit,MessageProc};
+
+void checkForDevices(BOOL *killSwitch);
+void gotDevice(IWMDMDevice* pIDevice);
+
+CRITICAL_SECTION csTransfers;
+
+static DeviceProvider *deviceProvider = NULL;
+
+static IWMDeviceManager3* pIdvMgr=NULL;
+static DWORD ConnectionNotificationCookie = 0;
+CSecureChannelClient SAC;
+IWMDRMDeviceApp * DRMDeviceApp = NULL;
+
+HANDLE killEvent = 0;
+
+static int ThreadInitFunc(HANDLE handle, void *user_data, intptr_t param);
+static int ThreadQuitFunc(HANDLE handle, void *user_data, intptr_t param);
+
+HANDLE hWinampThread=NULL;
+
+class MyNotification : public IWMDMNotification {
+public:
+ virtual HRESULT STDMETHODCALLTYPE WMDMMessage(DWORD dwMessageType, LPCWSTR pwszCanonicalName) {
+ switch(dwMessageType) {
+ case WMDM_MSG_DEVICE_ARRIVAL: // WMDM device has been plugged in
+ //OutputDebugString(L"Device arrived (IWMN)");
+ if (NULL == deviceProvider ||
+ FAILED(deviceProvider->BeginDiscovery(AGAVE_API_DEVICEMANAGER)))
+ {
+ checkForDevices(NULL);
+ }
+ break;
+ case WMDM_MSG_DEVICE_REMOVAL: // WMDM device has been removed
+ //OutputDebugString(L"Device removed (IWMN)");
+ for(int i=0; i<devices.GetSize(); i++) {
+ wchar_t devName[256] = {0};
+ ((P4SDevice *)devices.Get(i))->WMDevice->GetCanonicalName(devName,256);
+ if(wcscmp(pwszCanonicalName,devName) == 0) {
+ ((P4SDevice *)devices.Get(i))->Close();
+ }
+ }
+ break;
+ case WMDM_MSG_MEDIA_ARRIVAL: // Media has been inserted in WMDM device
+ WMDMMessage(WMDM_MSG_DEVICE_REMOVAL,pwszCanonicalName);
+ WMDMMessage(WMDM_MSG_DEVICE_ARRIVAL,pwszCanonicalName);
+ break;
+ case WMDM_MSG_MEDIA_REMOVAL: // Media is removed from WMDM device
+ WMDMMessage(WMDM_MSG_DEVICE_REMOVAL,pwszCanonicalName);
+ WMDMMessage(WMDM_MSG_DEVICE_ARRIVAL,pwszCanonicalName);
+ break;
+ }
+ return S_OK;
+ }
+ // COM shit
+ ULONG refs;
+ MyNotification() {refs=1;}
+ #define IMPLEMENTS(ifc) if (riid == IID_ ## ifc) { ++refs; *ppvObject = static_cast<ifc *>(this); return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,void __RPC_FAR *__RPC_FAR *ppvObject) {
+ IMPLEMENTS(IWMDMNotification);
+ IMPLEMENTS(IUnknown);
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+ virtual ULONG STDMETHODCALLTYPE AddRef() { return ++refs; }
+ virtual ULONG STDMETHODCALLTYPE Release() { int x = --refs; if(!x) delete this; return x; }
+ #undef IMPLEMENTS
+};
+
+IWMDMNotification * myNotify=NULL;
+
+
+template <class api_T>
+void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
+{
+ if (plugin.service)
+ {
+ waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
+ if (factory)
+ api_t = reinterpret_cast<api_T *>( factory->getInterface() );
+ }
+}
+
+template <class api_T>
+void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
+{
+ if (plugin.service && api_t)
+ {
+ waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
+ if (factory)
+ factory->releaseInterface(api_t);
+ }
+ api_t = NULL;
+}
+
+BOOL
+QueueThreadFunction(api_threadpool::ThreadPoolFunc func, void *user, intptr_t id)
+{
+ BOOL result;
+ ThreadID *thread;
+
+ if (NULL == WASABI_API_THREADPOOL)
+ return FALSE;
+
+ thread = WASABI_API_THREADPOOL->ReserveThread(api_threadpool::FLAG_REQUIRE_COM_MT);
+ if (NULL == thread)
+ return FALSE;
+
+ result = (0 == WASABI_API_THREADPOOL->RunFunction(thread, func, user, id,
+ api_threadpool::FLAG_REQUIRE_COM_MT));
+
+ WASABI_API_THREADPOOL->ReleaseThread(thread);
+
+ return result;
+}
+
+static int init2(BOOL runCheck)
+{
+ HRESULT hr;
+ IComponentAuthenticate* pICompAuth;
+
+ DWORD dwNumProtCount;
+ DWORD* pdwProt=NULL; // This will always be SAC_PROTOCOL_V1.
+
+ hr = CoCreateInstance(CLSID_MediaDevMgr, NULL, CLSCTX_ALL, IID_IComponentAuthenticate, (void **)&pICompAuth);
+
+ // After getting IComponentAuthenticate, the authentication progression follows.
+ if (SUCCEEDED(hr))
+ {
+ hr = SAC.SetCertificate(SAC_CERT_V1, (BYTE*) abCert, sizeof(abCert), (BYTE*) abPVK, sizeof(abPVK));
+ if (SUCCEEDED(hr))
+ {
+ // Set interface for Secure Authenticated Channel
+ // operations. The return value of this function is void.
+
+ SAC.SetInterface(pICompAuth);
+ hr = pICompAuth->SACGetProtocols(&pdwProt, &dwNumProtCount);
+ if (SUCCEEDED(hr))
+ SAC.Authenticate(*pdwProt); //SAC_PROTOCOL_V1
+ //if (SUCCEEDED(hr)) OutputDebugString(L"CSecureChannelClient.Authenticate succeeded\n");
+ }
+ if(pdwProt)
+ CoTaskMemFree(pdwProt);
+ // After authentication has succeeded, call QueryInterface to
+ // get IID_IWMDeviceManager.
+
+ if (FAILED(pICompAuth->QueryInterface(IID_IWMDeviceManager3, (void**)&pIdvMgr)))
+ pIdvMgr = NULL;
+
+ pICompAuth->Release();
+ pICompAuth = NULL;
+
+ if (NULL != pIdvMgr)
+ {
+ pIdvMgr->SetDeviceEnumPreference(ALLOW_OUTOFBAND_NOTIFICATION);
+ IConnectionPointContainer *pIcpc = NULL;
+ if (SUCCEEDED(pIdvMgr->QueryInterface(IID_IConnectionPointContainer,(void**)&pIcpc)))
+ {
+ IConnectionPoint * pICP=NULL;
+ if (SUCCEEDED(pIcpc->FindConnectionPoint(IID_IWMDMNotification,&pICP)))
+ {
+ myNotify = new MyNotification;
+
+ if (FAILED(pICP->Advise(myNotify, &ConnectionNotificationCookie)))
+ ConnectionNotificationCookie = 0;
+
+ pICP->Release();
+ }
+ pIcpc->Release();
+ pIcpc=0;
+ }
+ }
+ }
+
+ if (FALSE != runCheck)
+ checkForDevices(NULL);
+
+ return 0;
+}
+
+static void quit2()
+{
+ if(pIdvMgr)
+ {
+ if (0 != ConnectionNotificationCookie)
+ {
+ IConnectionPointContainer *pIcpc;
+ if (SUCCEEDED(pIdvMgr->QueryInterface(IID_IConnectionPointContainer,(void**)&pIcpc)))
+ {
+ IConnectionPoint * pICP;
+ if (SUCCEEDED(pIcpc->FindConnectionPoint(IID_IWMDMNotification,&pICP)))
+ {
+ pICP->Unadvise(ConnectionNotificationCookie);
+ ConnectionNotificationCookie = 0;
+ pICP->Release();
+ }
+ pIcpc->Release();
+ }
+ }
+ pIdvMgr->Release();
+ pIdvMgr = NULL;
+ }
+
+ if(myNotify)
+ {
+ myNotify->Release();
+ myNotify=0;
+ }
+
+ if(DRMDeviceApp)
+ {
+ DRMDeviceApp->Release();
+ DRMDeviceApp=0;
+ }
+}
+
+
+int init()
+{
+ CoInitialize(0);
+ // check OS version
+ OSVERSIONINFO osvi = {0};
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&osvi);
+ if(osvi.dwMajorVersion < 5) return -1;
+ if(osvi.dwMajorVersion == 5 && osvi.dwMinorVersion < 1) return -1;
+ hWinampThread = GetCurrentThread();
+ InitializeCriticalSection(&csTransfers);
+
+ Tataki::Init(plugin.service);
+
+ ServiceBuild(WASABI_API_LNG, languageApiGUID);
+ ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ ServiceBuild(WASABI_API_THREADPOOL, ThreadPoolGUID);
+ ServiceBuild(AGAVE_API_ALBUMART, albumArtGUID);
+ ServiceBuild(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
+
+ // need to have this initialised before we try to do anything with localisation features
+ WASABI_API_START_LANG(plugin.hDllInstance,PmpP4SLangGUID);
+
+ static wchar_t szDescription[256];
+ StringCchPrintfW(szDescription, ARRAYSIZE(szDescription),
+ WASABI_API_LNGSTRINGW(IDS_NULLSOFT_P4S_PLUGIN), PLUGIN_VERSION);
+ plugin.description = szDescription;
+
+ if (NULL != AGAVE_API_DEVICEMANAGER &&
+ NULL == deviceProvider)
+ {
+ if (SUCCEEDED(DeviceProvider::CreateInstance(&deviceProvider)) &&
+ FAILED(deviceProvider->Register(AGAVE_API_DEVICEMANAGER)))
+ {
+ deviceProvider->Release();
+ deviceProvider = NULL;
+ }
+ }
+
+ // set up thread
+ killEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
+
+ if (FALSE == QueueThreadFunction(ThreadInitFunc, NULL, (NULL == deviceProvider)))
+ init2(NULL == deviceProvider);
+
+ if (NULL != deviceProvider &&
+ FAILED(deviceProvider->BeginDiscovery(AGAVE_API_DEVICEMANAGER)))
+ {
+ checkForDevices(NULL);
+ }
+ return 0;
+}
+
+void quit()
+{
+ SetEvent(killEvent);
+
+ if (NULL != deviceProvider)
+ {
+ deviceProvider->Unregister();
+ deviceProvider->Release();
+ deviceProvider = NULL;
+ }
+
+ HANDLE doneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ if (FALSE != QueueThreadFunction(ThreadQuitFunc, doneEvent, 0))
+ WaitForSingleObject(doneEvent, INFINITE);
+ else
+ quit2();
+
+ CloseHandle(doneEvent);
+
+ CloseHandle(killEvent);
+ DeleteCriticalSection(&csTransfers);
+ Tataki::Quit();
+
+ ServiceRelease(WASABI_API_LNG, languageApiGUID);
+ ServiceRelease(WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ ServiceRelease(WASABI_API_THREADPOOL, ThreadPoolGUID);
+ ServiceRelease(AGAVE_API_ALBUMART, albumArtGUID);
+ ServiceRelease(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
+
+ CoUninitialize();
+}
+
+
+
+void newDeviceAvaliable(IWMDMDevice3* pIDevice)
+{
+ HRESULT hr;
+ DWORD dwTypeDev = 0;
+ wchar_t buffer[1024] = {0};
+
+ hr = pIDevice->GetType(&dwTypeDev);
+ if (SUCCEEDED(hr))
+ {
+ if(0 == (WMDM_DEVICE_TYPE_PLAYBACK & dwTypeDev))
+ {
+ return;
+
+ if (FAILED(pIDevice->GetName(buffer,ARRAYSIZE(buffer))))
+ buffer[0] = L'\0';
+
+ int l = wcslen(buffer);
+
+ if(l > 5 &&
+ buffer[l-5] == L' ' &&
+ buffer[l-4] == L'(' &&
+ buffer[l-2] == L':' &&
+ buffer[l-1] == L')')
+ {
+ return;
+ }
+ }
+
+ if(0 == (WMDM_DEVICE_TYPE_STORAGE & dwTypeDev))
+ return;
+ }
+ else
+ return;
+
+ // make sure it's not just a simple mass storage device (we have a separate plugin for this!)
+ PROPVARIANT protocol; // VARIANTs can kiss my ass
+ hr = pIDevice->GetProperty(g_wszWMDMDeviceProtocol, &protocol);
+ if (SUCCEEDED(hr))
+ {
+ bool isUsb = !!(*protocol.puuid == WMDM_DEVICE_PROTOCOL_MSC);
+ PropVariantClear(&protocol);
+ if (isUsb)
+ return;
+ }
+
+ if (SUCCEEDED(pIDevice->GetCanonicalName(buffer, ARRAYSIZE(buffer))))
+ {
+ wchar_t buffer2[ARRAYSIZE(buffer)] = {0};
+
+ for(int i=0; i < devices.GetSize(); i++)
+ {
+ P4SDevice *device = (P4SDevice*)devices.Get(i);
+ if (NULL != device &&
+ NULL != device->WMDevice &&
+ SUCCEEDED(device->WMDevice->GetCanonicalName(buffer2, ARRAYSIZE(buffer2))))
+ {
+ if(wcscmp(buffer, buffer2) == 0)
+ return;
+ }
+ }
+ }
+
+ if(!DRMDeviceApp)
+ CoCreateInstance(CLSID_WMDRMDeviceApp, NULL, CLSCTX_ALL, IID_IWMDRMDeviceApp, (void **)&DRMDeviceApp);
+
+ bool noMetadata;
+
+ if (0 == (WMDM_DEVICE_TYPE_PLAYBACK & dwTypeDev))
+ {
+ noMetadata = true;
+ }
+ else if (SUCCEEDED(pIDevice->GetManufacturer(buffer, ARRAYSIZE(buffer))) &&
+ NULL != wcsstr(buffer, L"Nokia"))
+ {
+ noMetadata = true;
+ }
+ else
+ noMetadata = false;
+
+ P4SDevice *dev = new P4SDevice(pIDevice,noMetadata);
+
+ //return dev;
+}
+
+void checkForDevices(BOOL *killSwitch)
+{
+ HRESULT hr = S_OK;
+ IWMDMEnumDevice* pIEnumDev;
+ IWMDMDevice* pIDeviceOld;
+ IWMDMDevice3* pIDevice = NULL;
+ unsigned long fetched;
+ if (!pIdvMgr)
+ return;
+
+ hr = pIdvMgr->EnumDevices2(&pIEnumDev); // Query for device enumerator.
+ if (SUCCEEDED(hr))
+ {
+ // If no device is found, S_FALSE is returned, which is still
+ // a success case. Do not use the SUCCEEDED macro.
+ while ((NULL == killSwitch || FALSE == *killSwitch) &&
+ S_OK == pIEnumDev->Next(1, &pIDeviceOld, &fetched))
+ {
+ if(SUCCEEDED(pIDeviceOld->QueryInterface(IID_IWMDMDevice3,(void**)&pIDevice)))
+ {
+ newDeviceAvaliable(pIDevice);
+ pIDevice->Release();
+ }
+ pIDeviceOld->Release();
+ }
+ // We should release this pointer but it appears to make winamp not shut down properly if we do.
+ // This function will only be called a small number of times, so I propose that we don't free it
+ // until this error can be better investigated. --will
+ pIEnumDev->Release();
+ }
+}
+
+
+static int ThreadInitFunc(HANDLE handle, void *user_data, intptr_t param)
+{
+ init2((BOOL)param);
+ return 0;
+}
+
+static int ThreadQuitFunc(HANDLE handle, void *user_data, intptr_t param)
+{
+ quit2();
+
+ if (NULL != user_data)
+ SetEvent((HANDLE)user_data);
+
+ return 0;
+}
+
+
+intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3) {
+ switch(msg) {
+ case PMP_DEVICECHANGE:
+ return 0;
+ case PMP_NO_CONFIG:
+ return TRUE;
+ case PMP_CONFIG:
+ return 0;
+ }
+ return 0;
+}
+
+typedef struct { ULONG_PTR param; void * proc; int state; CRITICAL_SECTION lock;} spc ;
+
+static VOID CALLBACK spc_caller(ULONG_PTR dwParam) {
+ spc * s = (spc*)dwParam;
+ if(!s) return;
+ EnterCriticalSection(&s->lock);
+ if(s->state == -1) { LeaveCriticalSection(&s->lock); DeleteCriticalSection(&s->lock); free(s); return; }
+ s->state = 2;
+ void (CALLBACK *p)(ULONG_PTR dwParam);
+ p = (void (CALLBACK *)(ULONG_PTR dwParam))s->proc;
+ if(p) p(s->param);
+ s->state=1;
+ LeaveCriticalSection(&s->lock);
+}
+
+// p must be of type void (CALLBACK *)(ULONG_PTR dwParam). Returns 0 for success.
+int SynchronousProcedureCall(void * p, ULONG_PTR dwParam) {
+ if(!p) return 1;
+ spc * s = (spc*)calloc(1, sizeof(spc));
+ InitializeCriticalSection(&s->lock);
+ s->param = dwParam;
+ s->proc = p;
+ s->state = 0;
+ if(!QueueUserAPC(spc_caller,hWinampThread,(ULONG_PTR)s)) { DeleteCriticalSection(&s->lock); free(s); return 1; } //failed
+ int i=0, state;
+ do {
+ SleepEx(10,true);
+ EnterCriticalSection(&s->lock);
+ state = s->state;
+ if(i++ == 100) {s->state = -1; return 1;}
+ LeaveCriticalSection(&s->lock);
+ }
+ while(state!=1);
+ DeleteCriticalSection(&s->lock);
+ free(s);
+ return 0;
+}
+
+
+BOOL FormatResProtocol(const wchar_t *resourceName, const wchar_t *resourceType, wchar_t *buffer, size_t bufferMax)
+{
+ unsigned long filenameLength;
+
+ if (NULL == resourceName)
+ return FALSE;
+
+ if (FAILED(StringCchCopyExW(buffer, bufferMax, L"res://", &buffer, &bufferMax, 0)))
+ return FALSE;
+
+ filenameLength = GetModuleFileNameW(plugin.hDllInstance, buffer, bufferMax);
+ if (0 == filenameLength || bufferMax == filenameLength)
+ return FALSE;
+
+ buffer += filenameLength;
+ bufferMax -= filenameLength;
+
+ if (NULL != resourceType)
+ {
+ if (FALSE != IS_INTRESOURCE(resourceType))
+ {
+ if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/#%d", (int)(INT_PTR)resourceType)))
+ return FALSE;
+ }
+ else
+ {
+ if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/%s", resourceType)))
+ return FALSE;
+ }
+ }
+
+ if (FALSE != IS_INTRESOURCE(resourceName))
+ {
+ if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/#%d", (int)(INT_PTR)resourceName)))
+ return FALSE;
+ }
+ else
+ {
+ if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/%s", resourceName)))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+extern "C" {
+ __declspec( dllexport ) PMPDevicePlugin * winampGetPMPDevicePlugin(){return &plugin;}
+ __declspec( dllexport ) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) {
+ int i = devices.GetSize();
+ while(i-- > 0) ((Device*)devices.Get(i))->Close();
+ return PMP_PLUGIN_UNINSTALL_NOW;
+ }
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_p4s/mssachlp.lib b/Src/Plugins/Portable/pmp_p4s/mssachlp.lib
new file mode 100644
index 00000000..041f12c3
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/mssachlp.lib
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_p4s/mswmdm.h b/Src/Plugins/Portable/pmp_p4s/mswmdm.h
new file mode 100644
index 00000000..a2b72f4d
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/mswmdm.h
@@ -0,0 +1,9913 @@
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 7.00.0498 */
+/* Compiler settings for mswmdm.idl:
+ Oicf, W1, Zp8, env=Win32 (32b run)
+ protocol : dce , ms_ext, c_ext, robust
+ error checks: allocation ref bounds_check enum stub_data
+ VC __declspec() decoration level:
+ __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+ DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+//@@MIDL_FILE_HEADING( )
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+/* verify that the <rpcsal.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCSAL_H_VERSION__
+#define __REQUIRED_RPCSAL_H_VERSION__ 100
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __mswmdm_h__
+#define __mswmdm_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __IWMDMMetaData_FWD_DEFINED__
+#define __IWMDMMetaData_FWD_DEFINED__
+typedef interface IWMDMMetaData IWMDMMetaData;
+#endif /* __IWMDMMetaData_FWD_DEFINED__ */
+
+
+#ifndef __IWMDeviceManager_FWD_DEFINED__
+#define __IWMDeviceManager_FWD_DEFINED__
+typedef interface IWMDeviceManager IWMDeviceManager;
+#endif /* __IWMDeviceManager_FWD_DEFINED__ */
+
+
+#ifndef __IWMDeviceManager2_FWD_DEFINED__
+#define __IWMDeviceManager2_FWD_DEFINED__
+typedef interface IWMDeviceManager2 IWMDeviceManager2;
+#endif /* __IWMDeviceManager2_FWD_DEFINED__ */
+
+
+#ifndef __IWMDeviceManager3_FWD_DEFINED__
+#define __IWMDeviceManager3_FWD_DEFINED__
+typedef interface IWMDeviceManager3 IWMDeviceManager3;
+#endif /* __IWMDeviceManager3_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMStorageGlobals_FWD_DEFINED__
+#define __IWMDMStorageGlobals_FWD_DEFINED__
+typedef interface IWMDMStorageGlobals IWMDMStorageGlobals;
+#endif /* __IWMDMStorageGlobals_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMStorage_FWD_DEFINED__
+#define __IWMDMStorage_FWD_DEFINED__
+typedef interface IWMDMStorage IWMDMStorage;
+#endif /* __IWMDMStorage_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMStorage2_FWD_DEFINED__
+#define __IWMDMStorage2_FWD_DEFINED__
+typedef interface IWMDMStorage2 IWMDMStorage2;
+#endif /* __IWMDMStorage2_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMStorage3_FWD_DEFINED__
+#define __IWMDMStorage3_FWD_DEFINED__
+typedef interface IWMDMStorage3 IWMDMStorage3;
+#endif /* __IWMDMStorage3_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMStorage4_FWD_DEFINED__
+#define __IWMDMStorage4_FWD_DEFINED__
+typedef interface IWMDMStorage4 IWMDMStorage4;
+#endif /* __IWMDMStorage4_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMOperation_FWD_DEFINED__
+#define __IWMDMOperation_FWD_DEFINED__
+typedef interface IWMDMOperation IWMDMOperation;
+#endif /* __IWMDMOperation_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMOperation2_FWD_DEFINED__
+#define __IWMDMOperation2_FWD_DEFINED__
+typedef interface IWMDMOperation2 IWMDMOperation2;
+#endif /* __IWMDMOperation2_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMOperation3_FWD_DEFINED__
+#define __IWMDMOperation3_FWD_DEFINED__
+typedef interface IWMDMOperation3 IWMDMOperation3;
+#endif /* __IWMDMOperation3_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMProgress_FWD_DEFINED__
+#define __IWMDMProgress_FWD_DEFINED__
+typedef interface IWMDMProgress IWMDMProgress;
+#endif /* __IWMDMProgress_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMProgress2_FWD_DEFINED__
+#define __IWMDMProgress2_FWD_DEFINED__
+typedef interface IWMDMProgress2 IWMDMProgress2;
+#endif /* __IWMDMProgress2_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMProgress3_FWD_DEFINED__
+#define __IWMDMProgress3_FWD_DEFINED__
+typedef interface IWMDMProgress3 IWMDMProgress3;
+#endif /* __IWMDMProgress3_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMDevice_FWD_DEFINED__
+#define __IWMDMDevice_FWD_DEFINED__
+typedef interface IWMDMDevice IWMDMDevice;
+#endif /* __IWMDMDevice_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMDevice2_FWD_DEFINED__
+#define __IWMDMDevice2_FWD_DEFINED__
+typedef interface IWMDMDevice2 IWMDMDevice2;
+#endif /* __IWMDMDevice2_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMDevice3_FWD_DEFINED__
+#define __IWMDMDevice3_FWD_DEFINED__
+typedef interface IWMDMDevice3 IWMDMDevice3;
+#endif /* __IWMDMDevice3_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMDeviceSession_FWD_DEFINED__
+#define __IWMDMDeviceSession_FWD_DEFINED__
+typedef interface IWMDMDeviceSession IWMDMDeviceSession;
+#endif /* __IWMDMDeviceSession_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMEnumDevice_FWD_DEFINED__
+#define __IWMDMEnumDevice_FWD_DEFINED__
+typedef interface IWMDMEnumDevice IWMDMEnumDevice;
+#endif /* __IWMDMEnumDevice_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMDeviceControl_FWD_DEFINED__
+#define __IWMDMDeviceControl_FWD_DEFINED__
+typedef interface IWMDMDeviceControl IWMDMDeviceControl;
+#endif /* __IWMDMDeviceControl_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMEnumStorage_FWD_DEFINED__
+#define __IWMDMEnumStorage_FWD_DEFINED__
+typedef interface IWMDMEnumStorage IWMDMEnumStorage;
+#endif /* __IWMDMEnumStorage_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMStorageControl_FWD_DEFINED__
+#define __IWMDMStorageControl_FWD_DEFINED__
+typedef interface IWMDMStorageControl IWMDMStorageControl;
+#endif /* __IWMDMStorageControl_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMStorageControl2_FWD_DEFINED__
+#define __IWMDMStorageControl2_FWD_DEFINED__
+typedef interface IWMDMStorageControl2 IWMDMStorageControl2;
+#endif /* __IWMDMStorageControl2_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMStorageControl3_FWD_DEFINED__
+#define __IWMDMStorageControl3_FWD_DEFINED__
+typedef interface IWMDMStorageControl3 IWMDMStorageControl3;
+#endif /* __IWMDMStorageControl3_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMObjectInfo_FWD_DEFINED__
+#define __IWMDMObjectInfo_FWD_DEFINED__
+typedef interface IWMDMObjectInfo IWMDMObjectInfo;
+#endif /* __IWMDMObjectInfo_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMRevoked_FWD_DEFINED__
+#define __IWMDMRevoked_FWD_DEFINED__
+typedef interface IWMDMRevoked IWMDMRevoked;
+#endif /* __IWMDMRevoked_FWD_DEFINED__ */
+
+
+#ifndef __IWMDMNotification_FWD_DEFINED__
+#define __IWMDMNotification_FWD_DEFINED__
+typedef interface IWMDMNotification IWMDMNotification;
+#endif /* __IWMDMNotification_FWD_DEFINED__ */
+
+
+#ifndef __IMDServiceProvider_FWD_DEFINED__
+#define __IMDServiceProvider_FWD_DEFINED__
+typedef interface IMDServiceProvider IMDServiceProvider;
+#endif /* __IMDServiceProvider_FWD_DEFINED__ */
+
+
+#ifndef __IMDServiceProvider2_FWD_DEFINED__
+#define __IMDServiceProvider2_FWD_DEFINED__
+typedef interface IMDServiceProvider2 IMDServiceProvider2;
+#endif /* __IMDServiceProvider2_FWD_DEFINED__ */
+
+
+#ifndef __IMDServiceProvider3_FWD_DEFINED__
+#define __IMDServiceProvider3_FWD_DEFINED__
+typedef interface IMDServiceProvider3 IMDServiceProvider3;
+#endif /* __IMDServiceProvider3_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPEnumDevice_FWD_DEFINED__
+#define __IMDSPEnumDevice_FWD_DEFINED__
+typedef interface IMDSPEnumDevice IMDSPEnumDevice;
+#endif /* __IMDSPEnumDevice_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPDevice_FWD_DEFINED__
+#define __IMDSPDevice_FWD_DEFINED__
+typedef interface IMDSPDevice IMDSPDevice;
+#endif /* __IMDSPDevice_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPDevice2_FWD_DEFINED__
+#define __IMDSPDevice2_FWD_DEFINED__
+typedef interface IMDSPDevice2 IMDSPDevice2;
+#endif /* __IMDSPDevice2_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPDevice3_FWD_DEFINED__
+#define __IMDSPDevice3_FWD_DEFINED__
+typedef interface IMDSPDevice3 IMDSPDevice3;
+#endif /* __IMDSPDevice3_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPDeviceControl_FWD_DEFINED__
+#define __IMDSPDeviceControl_FWD_DEFINED__
+typedef interface IMDSPDeviceControl IMDSPDeviceControl;
+#endif /* __IMDSPDeviceControl_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPEnumStorage_FWD_DEFINED__
+#define __IMDSPEnumStorage_FWD_DEFINED__
+typedef interface IMDSPEnumStorage IMDSPEnumStorage;
+#endif /* __IMDSPEnumStorage_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPStorage_FWD_DEFINED__
+#define __IMDSPStorage_FWD_DEFINED__
+typedef interface IMDSPStorage IMDSPStorage;
+#endif /* __IMDSPStorage_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPStorage2_FWD_DEFINED__
+#define __IMDSPStorage2_FWD_DEFINED__
+typedef interface IMDSPStorage2 IMDSPStorage2;
+#endif /* __IMDSPStorage2_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPStorage3_FWD_DEFINED__
+#define __IMDSPStorage3_FWD_DEFINED__
+typedef interface IMDSPStorage3 IMDSPStorage3;
+#endif /* __IMDSPStorage3_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPStorage4_FWD_DEFINED__
+#define __IMDSPStorage4_FWD_DEFINED__
+typedef interface IMDSPStorage4 IMDSPStorage4;
+#endif /* __IMDSPStorage4_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPStorageGlobals_FWD_DEFINED__
+#define __IMDSPStorageGlobals_FWD_DEFINED__
+typedef interface IMDSPStorageGlobals IMDSPStorageGlobals;
+#endif /* __IMDSPStorageGlobals_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPObjectInfo_FWD_DEFINED__
+#define __IMDSPObjectInfo_FWD_DEFINED__
+typedef interface IMDSPObjectInfo IMDSPObjectInfo;
+#endif /* __IMDSPObjectInfo_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPObject_FWD_DEFINED__
+#define __IMDSPObject_FWD_DEFINED__
+typedef interface IMDSPObject IMDSPObject;
+#endif /* __IMDSPObject_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPObject2_FWD_DEFINED__
+#define __IMDSPObject2_FWD_DEFINED__
+typedef interface IMDSPObject2 IMDSPObject2;
+#endif /* __IMDSPObject2_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPDirectTransfer_FWD_DEFINED__
+#define __IMDSPDirectTransfer_FWD_DEFINED__
+typedef interface IMDSPDirectTransfer IMDSPDirectTransfer;
+#endif /* __IMDSPDirectTransfer_FWD_DEFINED__ */
+
+
+#ifndef __IMDSPRevoked_FWD_DEFINED__
+#define __IMDSPRevoked_FWD_DEFINED__
+typedef interface IMDSPRevoked IMDSPRevoked;
+#endif /* __IMDSPRevoked_FWD_DEFINED__ */
+
+
+#ifndef __ISCPSecureAuthenticate_FWD_DEFINED__
+#define __ISCPSecureAuthenticate_FWD_DEFINED__
+typedef interface ISCPSecureAuthenticate ISCPSecureAuthenticate;
+#endif /* __ISCPSecureAuthenticate_FWD_DEFINED__ */
+
+
+#ifndef __ISCPSecureAuthenticate2_FWD_DEFINED__
+#define __ISCPSecureAuthenticate2_FWD_DEFINED__
+typedef interface ISCPSecureAuthenticate2 ISCPSecureAuthenticate2;
+#endif /* __ISCPSecureAuthenticate2_FWD_DEFINED__ */
+
+
+#ifndef __ISCPSecureQuery_FWD_DEFINED__
+#define __ISCPSecureQuery_FWD_DEFINED__
+typedef interface ISCPSecureQuery ISCPSecureQuery;
+#endif /* __ISCPSecureQuery_FWD_DEFINED__ */
+
+
+#ifndef __ISCPSecureQuery2_FWD_DEFINED__
+#define __ISCPSecureQuery2_FWD_DEFINED__
+typedef interface ISCPSecureQuery2 ISCPSecureQuery2;
+#endif /* __ISCPSecureQuery2_FWD_DEFINED__ */
+
+
+#ifndef __ISCPSecureExchange_FWD_DEFINED__
+#define __ISCPSecureExchange_FWD_DEFINED__
+typedef interface ISCPSecureExchange ISCPSecureExchange;
+#endif /* __ISCPSecureExchange_FWD_DEFINED__ */
+
+
+#ifndef __ISCPSecureExchange2_FWD_DEFINED__
+#define __ISCPSecureExchange2_FWD_DEFINED__
+typedef interface ISCPSecureExchange2 ISCPSecureExchange2;
+#endif /* __ISCPSecureExchange2_FWD_DEFINED__ */
+
+
+#ifndef __ISCPSecureExchange3_FWD_DEFINED__
+#define __ISCPSecureExchange3_FWD_DEFINED__
+typedef interface ISCPSecureExchange3 ISCPSecureExchange3;
+#endif /* __ISCPSecureExchange3_FWD_DEFINED__ */
+
+
+#ifndef __ISCPSession_FWD_DEFINED__
+#define __ISCPSession_FWD_DEFINED__
+typedef interface ISCPSession ISCPSession;
+#endif /* __ISCPSession_FWD_DEFINED__ */
+
+
+#ifndef __ISCPSecureQuery3_FWD_DEFINED__
+#define __ISCPSecureQuery3_FWD_DEFINED__
+typedef interface ISCPSecureQuery3 ISCPSecureQuery3;
+#endif /* __ISCPSecureQuery3_FWD_DEFINED__ */
+
+
+#ifndef __IComponentAuthenticate_FWD_DEFINED__
+#define __IComponentAuthenticate_FWD_DEFINED__
+typedef interface IComponentAuthenticate IComponentAuthenticate;
+#endif /* __IComponentAuthenticate_FWD_DEFINED__ */
+
+
+#ifndef __MediaDevMgrClassFactory_FWD_DEFINED__
+#define __MediaDevMgrClassFactory_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class MediaDevMgrClassFactory MediaDevMgrClassFactory;
+#else
+typedef struct MediaDevMgrClassFactory MediaDevMgrClassFactory;
+#endif /* __cplusplus */
+
+#endif /* __MediaDevMgrClassFactory_FWD_DEFINED__ */
+
+
+#ifndef __MediaDevMgr_FWD_DEFINED__
+#define __MediaDevMgr_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class MediaDevMgr MediaDevMgr;
+#else
+typedef struct MediaDevMgr MediaDevMgr;
+#endif /* __cplusplus */
+
+#endif /* __MediaDevMgr_FWD_DEFINED__ */
+
+
+#ifndef __WMDMDevice_FWD_DEFINED__
+#define __WMDMDevice_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class WMDMDevice WMDMDevice;
+#else
+typedef struct WMDMDevice WMDMDevice;
+#endif /* __cplusplus */
+
+#endif /* __WMDMDevice_FWD_DEFINED__ */
+
+
+#ifndef __WMDMStorage_FWD_DEFINED__
+#define __WMDMStorage_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class WMDMStorage WMDMStorage;
+#else
+typedef struct WMDMStorage WMDMStorage;
+#endif /* __cplusplus */
+
+#endif /* __WMDMStorage_FWD_DEFINED__ */
+
+
+#ifndef __WMDMStorageGlobal_FWD_DEFINED__
+#define __WMDMStorageGlobal_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class WMDMStorageGlobal WMDMStorageGlobal;
+#else
+typedef struct WMDMStorageGlobal WMDMStorageGlobal;
+#endif /* __cplusplus */
+
+#endif /* __WMDMStorageGlobal_FWD_DEFINED__ */
+
+
+#ifndef __WMDMDeviceEnum_FWD_DEFINED__
+#define __WMDMDeviceEnum_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class WMDMDeviceEnum WMDMDeviceEnum;
+#else
+typedef struct WMDMDeviceEnum WMDMDeviceEnum;
+#endif /* __cplusplus */
+
+#endif /* __WMDMDeviceEnum_FWD_DEFINED__ */
+
+
+#ifndef __WMDMStorageEnum_FWD_DEFINED__
+#define __WMDMStorageEnum_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class WMDMStorageEnum WMDMStorageEnum;
+#else
+typedef struct WMDMStorageEnum WMDMStorageEnum;
+#endif /* __cplusplus */
+
+#endif /* __WMDMStorageEnum_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "oaidl.h"
+#include "ocidl.h"
+#include "propidl.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_mswmdm_0000_0000 */
+/* [local] */
+
+#ifndef _DEFINE_WMDM_DEVICE_PROTOCOL_MTP
+#define _DEFINE_WMDM_DEVICE_PROTOCOL_MTP
+// {979E54E5-0AFC-4604-8D93-DC798A4BCF45}
+DEFINE_GUID(WMDM_DEVICE_PROTOCOL_MTP,
+0x979e54e5, 0xafc, 0x4604, 0x8d, 0x93, 0xdc, 0x79, 0x8a, 0x4b, 0xcf, 0x45);
+#endif
+#ifndef _DEFINE_WMDM_DEVICE_PROTOCOL_RAPI
+#define _DEFINE_WMDM_DEVICE_PROTOCOL_RAPI
+// {2A11ED91-8C8F-41e4-82D1-8386E003561C}
+DEFINE_GUID(WMDM_DEVICE_PROTOCOL_RAPI,
+0x2a11ed91, 0x8c8f, 0x41e4, 0x82, 0xd1, 0x83, 0x86, 0xe0, 0x3, 0x56, 0x1c);
+#endif
+#ifndef _DEFINE_WMDM_DEVICE_PROTOCOL_MSC
+#define _DEFINE_WMDM_DEVICE_PROTOCOL_MSC
+// {A4D2C26C-A881-44bb-BD5D-1F703C71F7A9}
+DEFINE_GUID(WMDM_DEVICE_PROTOCOL_MSC,
+0xa4d2c26c, 0xa881, 0x44bb, 0xbd, 0x5d, 0x1f, 0x70, 0x3c, 0x71, 0xf7, 0xa9);
+#endif
+#ifndef _DEFINE_WMDM_SERVICE_PROVIDER_VENDOR_MICROSOFT
+#define _DEFINE_WMDM_SERVICE_PROVIDER_VENDOR_MICROSOFT
+// {7DE8686D-78EE-43ea-A496-C625AC91CC5D}
+DEFINE_GUID(WMDM_SERVICE_PROVIDER_VENDOR_MICROSOFT,
+0x7de8686d, 0x78ee, 0x43ea, 0xa4, 0x96, 0xc6, 0x25, 0xac, 0x91, 0xcc, 0x5d);
+#endif
+typedef
+enum tagWMDM_TAG_DATATYPE
+ { WMDM_TYPE_DWORD = 0,
+ WMDM_TYPE_STRING = 1,
+ WMDM_TYPE_BINARY = 2,
+ WMDM_TYPE_BOOL = 3,
+ WMDM_TYPE_QWORD = 4,
+ WMDM_TYPE_WORD = 5,
+ WMDM_TYPE_GUID = 6,
+ WMDM_TYPE_DATE = 7
+ } WMDM_TAG_DATATYPE;
+
+typedef
+enum tagWMDM_SESSION_TYPE
+ { WMDM_SESSION_NONE = 0,
+ WMDM_SESSION_TRANSFER_TO_DEVICE = 0x1,
+ WMDM_SESSION_TRANSFER_FROM_DEVICE = 0x10,
+ WMDM_SESSION_DELETE = 0x100,
+ WMDM_SESSION_CUSTOM = 0x1000
+ } WMDM_SESSION_TYPE;
+
+typedef struct _tWAVEFORMATEX
+ {
+ WORD wFormatTag;
+ WORD nChannels;
+ DWORD nSamplesPerSec;
+ DWORD nAvgBytesPerSec;
+ WORD nBlockAlign;
+ WORD wBitsPerSample;
+ WORD cbSize;
+ } _WAVEFORMATEX;
+
+typedef struct _tagBITMAPINFOHEADER
+ {
+ DWORD biSize;
+ LONG biWidth;
+ LONG biHeight;
+ WORD biPlanes;
+ WORD biBitCount;
+ DWORD biCompression;
+ DWORD biSizeImage;
+ LONG biXPelsPerMeter;
+ LONG biYPelsPerMeter;
+ DWORD biClrUsed;
+ DWORD biClrImportant;
+ } _BITMAPINFOHEADER;
+
+typedef struct _tagVIDEOINFOHEADER
+ {
+ RECT rcSource;
+ RECT rcTarget;
+ DWORD dwBitRate;
+ DWORD dwBitErrorRate;
+ LONGLONG AvgTimePerFrame;
+ _BITMAPINFOHEADER bmiHeader;
+ } _VIDEOINFOHEADER;
+
+typedef struct _tagWMFILECAPABILITIES
+ {
+ LPWSTR pwszMimeType;
+ DWORD dwReserved;
+ } WMFILECAPABILITIES;
+
+typedef struct __OPAQUECOMMAND
+ {
+ GUID guidCommand;
+ DWORD dwDataLen;
+ BYTE *pData;
+ BYTE abMAC[ 20 ];
+ } OPAQUECOMMAND;
+
+#define WMDMID_LENGTH ( 128 )
+
+typedef struct __WMDMID
+ {
+ UINT cbSize;
+ DWORD dwVendorID;
+ BYTE pID[ 128 ];
+ UINT SerialNumberLength;
+ } WMDMID;
+
+typedef struct __WMDMID *PWMDMID;
+
+typedef struct _WMDMDATETIME
+ {
+ WORD wYear;
+ WORD wMonth;
+ WORD wDay;
+ WORD wHour;
+ WORD wMinute;
+ WORD wSecond;
+ } WMDMDATETIME;
+
+typedef struct _WMDMDATETIME *PWMDMDATETIME;
+
+typedef struct __WMDMRIGHTS
+ {
+ UINT cbSize;
+ DWORD dwContentType;
+ DWORD fuFlags;
+ DWORD fuRights;
+ DWORD dwAppSec;
+ DWORD dwPlaybackCount;
+ WMDMDATETIME ExpirationDate;
+ } WMDMRIGHTS;
+
+typedef struct __WMDMRIGHTS *PWMDMRIGHTS;
+
+typedef struct __WMDMMetadataView
+ {
+ WCHAR *pwszViewName;
+ UINT nDepth;
+ WCHAR **ppwszTags;
+ } WMDMMetadataView;
+
+typedef
+enum tagWMDM_STORAGE_ENUM_MODE
+ { ENUM_MODE_RAW = 0,
+ ENUM_MODE_USE_DEVICE_PREF = ( ENUM_MODE_RAW + 1 ) ,
+ ENUM_MODE_METADATA_VIEWS = ( ENUM_MODE_USE_DEVICE_PREF + 1 )
+ } WMDM_STORAGE_ENUM_MODE;
+
+typedef /* [v1_enum] */
+enum tagWMDM_FORMATCODE
+ { WMDM_FORMATCODE_NOTUSED = 0,
+ 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_3GP = 0xb984,
+ 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_MEDIA_CAST = 0xba0b,
+ 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_SECTION = 0xbe82
+ } WMDM_FORMATCODE;
+
+typedef /* [v1_enum] */
+enum _WMDM_ENUM_PROP_VALID_VALUES_FORM
+ { WMDM_ENUM_PROP_VALID_VALUES_ANY = 0,
+ WMDM_ENUM_PROP_VALID_VALUES_RANGE = ( WMDM_ENUM_PROP_VALID_VALUES_ANY + 1 ) ,
+ WMDM_ENUM_PROP_VALID_VALUES_ENUM = ( WMDM_ENUM_PROP_VALID_VALUES_RANGE + 1 )
+ } WMDM_ENUM_PROP_VALID_VALUES_FORM;
+
+typedef struct _WMDM_PROP_VALUES_RANGE
+ {
+ PROPVARIANT rangeMin;
+ PROPVARIANT rangeMax;
+ PROPVARIANT rangeStep;
+ } WMDM_PROP_VALUES_RANGE;
+
+typedef struct _WMDM_PROP_VALUES_ENUM
+ {
+ UINT cEnumValues;
+ PROPVARIANT *pValues;
+ } WMDM_PROP_VALUES_ENUM;
+
+typedef struct _WMDM_PROP_DESC
+ {
+ LPWSTR pwszPropName;
+ WMDM_ENUM_PROP_VALID_VALUES_FORM ValidValuesForm;
+ union
+ {
+ /* Empty union arm */
+ WMDM_PROP_VALUES_RANGE ValidValuesRange;
+ WMDM_PROP_VALUES_ENUM EnumeratedValidValues;
+ } ValidValues;
+ } WMDM_PROP_DESC;
+
+typedef struct _WMDM_PROP_CONFIG
+ {
+ UINT nPreference;
+ UINT nPropDesc;
+ WMDM_PROP_DESC *pPropDesc;
+ } WMDM_PROP_CONFIG;
+
+typedef struct _WMDM_FORMAT_CAPABILITY
+ {
+ UINT nPropConfig;
+ WMDM_PROP_CONFIG *pConfigs;
+ } WMDM_FORMAT_CAPABILITY;
+
+#define WMDM_MAC_LENGTH ( 8 )
+
+typedef
+enum tagWMDM_FIND_SCOPE
+ { WMDM_FIND_SCOPE_GLOBAL = 0,
+ WMDM_FIND_SCOPE_IMMEDIATE_CHILDREN = ( WMDM_FIND_SCOPE_GLOBAL + 1 )
+ } WMDM_FIND_SCOPE;
+
+// WMDM HRESULTS
+//
+//Success codes
+//
+#define WMDM_S_NOT_ALL_PROPERTIES_APPLIED 0x00045001L
+#define WMDM_S_NOT_ALL_PROPERTIES_RETRIEVED 0x00045002L
+//
+//Error codes
+//
+#define WMDM_E_BUSY 0x80045000L
+#define WMDM_E_INTERFACEDEAD 0x80045001L
+#define WMDM_E_INVALIDTYPE 0x80045002L
+#define WMDM_E_PROCESSFAILED 0x80045003L
+#define WMDM_E_NOTSUPPORTED 0x80045004L
+#define WMDM_E_NOTCERTIFIED 0x80045005L
+#define WMDM_E_NORIGHTS 0x80045006L
+#define WMDM_E_CALL_OUT_OF_SEQUENCE 0x80045007L
+#define WMDM_E_BUFFERTOOSMALL 0x80045008L
+#define WMDM_E_MOREDATA 0x80045009L
+#define WMDM_E_MAC_CHECK_FAILED 0x8004500AL
+#define WMDM_E_USER_CANCELLED 0x8004500BL
+#define WMDM_E_SDMI_TRIGGER 0x8004500CL
+#define WMDM_E_SDMI_NOMORECOPIES 0x8004500DL
+#define WMDM_E_REVOKED 0x8004500EL
+#define WMDM_E_LICENSE_NOTEXIST 0x8004500FL
+#define WMDM_E_INCORRECT_APPSEC 0x80045010L
+#define WMDM_E_INCORRECT_RIGHTS 0x80045011L
+#define WMDM_E_LICENSE_EXPIRED 0x80045012L
+#define WMDM_E_CANTOPEN_PMSN_SERVICE_PIPE 0x80045013L
+#define WMDM_E_TOO_MANY_SESSIONS 0x80045013L
+// Revocation Flags
+#define WMDM_WMDM_REVOKED 0x00000001
+#define WMDM_APP_REVOKED 0x00000002
+#define WMDM_SP_REVOKED 0x00000004
+#define WMDM_SCP_REVOKED 0x00000008
+// GetFormatSupport2 Flags
+#define WMDM_GET_FORMAT_SUPPORT_AUDIO 0x00000001
+#define WMDM_GET_FORMAT_SUPPORT_VIDEO 0x00000002
+#define WMDM_GET_FORMAT_SUPPORT_FILE 0x00000004
+// MDMRIGHTS Flags
+#define WMDM_RIGHTS_PLAYBACKCOUNT 0x00000001
+#define WMDM_RIGHTS_EXPIRATIONDATE 0x00000002
+#define WMDM_RIGHTS_GROUPID 0x00000004
+#define WMDM_RIGHTS_FREESERIALIDS 0x00000008
+#define WMDM_RIGHTS_NAMEDSERIALIDS 0x00000010
+// Device Type Flags
+#define WMDM_DEVICE_TYPE_PLAYBACK 0x00000001
+#define WMDM_DEVICE_TYPE_RECORD 0x00000002
+#define WMDM_DEVICE_TYPE_DECODE 0x00000004
+#define WMDM_DEVICE_TYPE_ENCODE 0x00000008
+#define WMDM_DEVICE_TYPE_STORAGE 0x00000010
+#define WMDM_DEVICE_TYPE_VIRTUAL 0x00000020
+#define WMDM_DEVICE_TYPE_SDMI 0x00000040
+#define WMDM_DEVICE_TYPE_NONSDMI 0x00000080
+#define WMDM_DEVICE_TYPE_NONREENTRANT 0x00000100
+#define WMDM_DEVICE_TYPE_FILELISTRESYNC 0x00000200
+#define WMDM_DEVICE_TYPE_VIEW_PREF_METADATAVIEW 0x00000400
+// Device Power Source Flags
+#define WMDM_POWER_CAP_BATTERY 0x00000001
+#define WMDM_POWER_CAP_EXTERNAL 0x00000002
+#define WMDM_POWER_IS_BATTERY 0x00000004
+#define WMDM_POWER_IS_EXTERNAL 0x00000008
+#define WMDM_POWER_PERCENT_AVAILABLE 0x00000010
+// Device Status Flags
+#define WMDM_STATUS_READY 0x00000001
+#define WMDM_STATUS_BUSY 0x00000002
+#define WMDM_STATUS_DEVICE_NOTPRESENT 0x00000004
+#define WMDM_STATUS_DEVICECONTROL_PLAYING 0x00000008
+#define WMDM_STATUS_DEVICECONTROL_RECORDING 0x00000010
+#define WMDM_STATUS_DEVICECONTROL_PAUSED 0x00000020
+#define WMDM_STATUS_DEVICECONTROL_REMOTE 0x00000040
+#define WMDM_STATUS_DEVICECONTROL_STREAM 0x00000080
+#define WMDM_STATUS_STORAGE_NOTPRESENT 0x00000100
+#define WMDM_STATUS_STORAGE_INITIALIZING 0x00000200
+#define WMDM_STATUS_STORAGE_BROKEN 0x00000400
+#define WMDM_STATUS_STORAGE_NOTSUPPORTED 0x00000800
+#define WMDM_STATUS_STORAGE_UNFORMATTED 0x00001000
+#define WMDM_STATUS_STORAGECONTROL_INSERTING 0x00002000
+#define WMDM_STATUS_STORAGECONTROL_DELETING 0x00004000
+#define WMDM_STATUS_STORAGECONTROL_APPENDING 0x00008000
+#define WMDM_STATUS_STORAGECONTROL_MOVING 0x00010000
+#define WMDM_STATUS_STORAGECONTROL_READING 0x00020000
+// Device Capabilities Flags
+#define WMDM_DEVICECAP_CANPLAY 0x00000001
+#define WMDM_DEVICECAP_CANSTREAMPLAY 0x00000002
+#define WMDM_DEVICECAP_CANRECORD 0x00000004
+#define WMDM_DEVICECAP_CANSTREAMRECORD 0x00000008
+#define WMDM_DEVICECAP_CANPAUSE 0x00000010
+#define WMDM_DEVICECAP_CANRESUME 0x00000020
+#define WMDM_DEVICECAP_CANSTOP 0x00000040
+#define WMDM_DEVICECAP_CANSEEK 0x00000080
+#define WMDM_DEVICECAP_HASSECURECLOCK 0x00000100
+// WMDM Seek Flags
+#define WMDM_SEEK_REMOTECONTROL 0x00000001
+#define WMDM_SEEK_STREAMINGAUDIO 0x00000002
+// Storage Attributes Flags
+#define WMDM_STORAGE_ATTR_FILESYSTEM 0x00000001
+#define WMDM_STORAGE_ATTR_REMOVABLE 0x00000002
+#define WMDM_STORAGE_ATTR_NONREMOVABLE 0x00000004
+#define WMDM_FILE_ATTR_FOLDER 0x00000008
+#define WMDM_FILE_ATTR_LINK 0x00000010
+#define WMDM_FILE_ATTR_FILE 0x00000020
+#define WMDM_FILE_ATTR_VIDEO 0x00000040
+#define WMDM_STORAGE_ATTR_CANEDITMETADATA 0x00000080
+#define WMDM_STORAGE_ATTR_FOLDERS 0x00000100
+#define WMDM_FILE_ATTR_AUDIO 0x00001000
+#define WMDM_FILE_ATTR_DATA 0x00002000
+#define WMDM_FILE_ATTR_CANPLAY 0x00004000
+#define WMDM_FILE_ATTR_CANDELETE 0x00008000
+#define WMDM_FILE_ATTR_CANMOVE 0x00010000
+#define WMDM_FILE_ATTR_CANRENAME 0x00020000
+#define WMDM_FILE_ATTR_CANREAD 0x00040000
+#define WMDM_FILE_ATTR_MUSIC 0x00080000
+#define WMDM_FILE_CREATE_OVERWRITE 0x00100000
+#define WMDM_FILE_ATTR_AUDIOBOOK 0x00200000
+#define WMDM_FILE_ATTR_HIDDEN 0x00400000
+#define WMDM_FILE_ATTR_SYSTEM 0x00800000
+#define WMDM_FILE_ATTR_READONLY 0x01000000
+#define WMDM_STORAGE_ATTR_HAS_FOLDERS 0x02000000
+#define WMDM_STORAGE_ATTR_HAS_FILES 0x04000000
+#define WMDM_STORAGE_IS_DEFAULT 0x08000000
+#define WMDM_STORAGE_CONTAINS_DEFAULT 0x10000000
+#define WMDM_STORAGE_ATTR_VIRTUAL 0x20000000
+// Storage Capabilities Flags
+#define WMDM_STORAGECAP_FOLDERSINROOT 0x00000001
+#define WMDM_STORAGECAP_FILESINROOT 0x00000002
+#define WMDM_STORAGECAP_FOLDERSINFOLDERS 0x00000004
+#define WMDM_STORAGECAP_FILESINFOLDERS 0x00000008
+#define WMDM_STORAGECAP_FOLDERLIMITEXISTS 0x00000010
+#define WMDM_STORAGECAP_FILELIMITEXISTS 0x00000020
+#define WMDM_STORAGECAP_NOT_INITIALIZABLE 0x00000040
+// WMDM Mode Flags
+#define WMDM_MODE_BLOCK 0x00000001
+#define WMDM_MODE_THREAD 0x00000002
+#define WMDM_CONTENT_FILE 0x00000004
+#define WMDM_CONTENT_FOLDER 0x00000008
+#define WMDM_CONTENT_OPERATIONINTERFACE 0x00000010
+#define WMDM_MODE_QUERY 0x00000020
+#define WMDM_MODE_PROGRESS 0x00000040
+#define WMDM_MODE_TRANSFER_PROTECTED 0x00000080
+#define WMDM_MODE_TRANSFER_UNPROTECTED 0x00000100
+#define WMDM_STORAGECONTROL_INSERTBEFORE 0x00000200
+#define WMDM_STORAGECONTROL_INSERTAFTER 0x00000400
+#define WMDM_STORAGECONTROL_INSERTINTO 0x00000800
+#define WMDM_MODE_RECURSIVE 0x00001000
+// WMDM Rights Flags
+// NON_SDMI = !SDMI_PROTECTED
+// SDMI = SDMI_VALIDATED
+#define WMDM_RIGHTS_PLAY_ON_PC 0x00000001
+#define WMDM_RIGHTS_COPY_TO_NON_SDMI_DEVICE 0x00000002
+#define WMDM_RIGHTS_COPY_TO_CD 0x00000008
+#define WMDM_RIGHTS_COPY_TO_SDMI_DEVICE 0x00000010
+// WMDM Seek Flags
+#define WMDM_SEEK_BEGIN 0x00000001
+#define WMDM_SEEK_CURRENT 0x00000002
+#define WMDM_SEEK_END 0x00000008
+// WMDM Device Enumeration Flags
+#define DO_NOT_VIRTUALIZE_STORAGES_AS_DEVICES 0x00000001
+#define ALLOW_OUTOFBAND_NOTIFICATION 0x00000002
+
+enum WMDMMessage
+ { WMDM_MSG_DEVICE_ARRIVAL = 0,
+ WMDM_MSG_DEVICE_REMOVAL = ( WMDM_MSG_DEVICE_ARRIVAL + 1 ) ,
+ WMDM_MSG_MEDIA_ARRIVAL = ( WMDM_MSG_DEVICE_REMOVAL + 1 ) ,
+ WMDM_MSG_MEDIA_REMOVAL = ( WMDM_MSG_MEDIA_ARRIVAL + 1 )
+ } ;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mswmdm_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mswmdm_0000_0000_v0_0_s_ifspec;
+
+#ifndef __IWMDMMetaData_INTERFACE_DEFINED__
+#define __IWMDMMetaData_INTERFACE_DEFINED__
+
+/* interface IWMDMMetaData */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMMetaData;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("EC3B0663-0951-460a-9A80-0DCEED3C043C")
+ IWMDMMetaData : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE AddItem(
+ /* [in] */ WMDM_TAG_DATATYPE Type,
+ /* [string][in] */ __RPC__in LPCWSTR pwszTagName,
+ /* [unique][size_is][in] */ __RPC__in_ecount_full_opt(iLength) BYTE *pValue,
+ /* [in] */ UINT iLength) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE QueryByName(
+ /* [string][in] */ __RPC__in LPCWSTR pwszTagName,
+ /* [out] */ __RPC__out WMDM_TAG_DATATYPE *pType,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pcbLength) BYTE **pValue,
+ /* [out] */ __RPC__out UINT *pcbLength) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE QueryByIndex(
+ /* [in] */ UINT iIndex,
+ /* [string][out] */ __RPC__deref_out_opt_string WCHAR **ppwszName,
+ /* [out] */ __RPC__out WMDM_TAG_DATATYPE *pType,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pcbLength) BYTE **ppValue,
+ /* [out] */ __RPC__out UINT *pcbLength) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetItemCount(
+ /* [out] */ __RPC__out UINT *iCount) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMMetaDataVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMMetaData * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMMetaData * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMMetaData * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AddItem )(
+ IWMDMMetaData * This,
+ /* [in] */ WMDM_TAG_DATATYPE Type,
+ /* [string][in] */ __RPC__in LPCWSTR pwszTagName,
+ /* [unique][size_is][in] */ __RPC__in_ecount_full_opt(iLength) BYTE *pValue,
+ /* [in] */ UINT iLength);
+
+ HRESULT ( STDMETHODCALLTYPE *QueryByName )(
+ IWMDMMetaData * This,
+ /* [string][in] */ __RPC__in LPCWSTR pwszTagName,
+ /* [out] */ __RPC__out WMDM_TAG_DATATYPE *pType,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pcbLength) BYTE **pValue,
+ /* [out] */ __RPC__out UINT *pcbLength);
+
+ HRESULT ( STDMETHODCALLTYPE *QueryByIndex )(
+ IWMDMMetaData * This,
+ /* [in] */ UINT iIndex,
+ /* [string][out] */ __RPC__deref_out_opt_string WCHAR **ppwszName,
+ /* [out] */ __RPC__out WMDM_TAG_DATATYPE *pType,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pcbLength) BYTE **ppValue,
+ /* [out] */ __RPC__out UINT *pcbLength);
+
+ HRESULT ( STDMETHODCALLTYPE *GetItemCount )(
+ IWMDMMetaData * This,
+ /* [out] */ __RPC__out UINT *iCount);
+
+ END_INTERFACE
+ } IWMDMMetaDataVtbl;
+
+ interface IWMDMMetaData
+ {
+ CONST_VTBL struct IWMDMMetaDataVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMMetaData_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMMetaData_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMMetaData_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMMetaData_AddItem(This,Type,pwszTagName,pValue,iLength) \
+ ( (This)->lpVtbl -> AddItem(This,Type,pwszTagName,pValue,iLength) )
+
+#define IWMDMMetaData_QueryByName(This,pwszTagName,pType,pValue,pcbLength) \
+ ( (This)->lpVtbl -> QueryByName(This,pwszTagName,pType,pValue,pcbLength) )
+
+#define IWMDMMetaData_QueryByIndex(This,iIndex,ppwszName,pType,ppValue,pcbLength) \
+ ( (This)->lpVtbl -> QueryByIndex(This,iIndex,ppwszName,pType,ppValue,pcbLength) )
+
+#define IWMDMMetaData_GetItemCount(This,iCount) \
+ ( (This)->lpVtbl -> GetItemCount(This,iCount) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMMetaData_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDeviceManager_INTERFACE_DEFINED__
+#define __IWMDeviceManager_INTERFACE_DEFINED__
+
+/* interface IWMDeviceManager */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDeviceManager;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A00-33ED-11d3-8470-00C04F79DBC0")
+ IWMDeviceManager : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetRevision(
+ /* [out] */ __RPC__out DWORD *pdwRevision) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceCount(
+ /* [out] */ __RPC__out DWORD *pdwCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumDevices(
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumDevice **ppEnumDevice) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDeviceManagerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDeviceManager * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDeviceManager * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDeviceManager * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRevision )(
+ IWMDeviceManager * This,
+ /* [out] */ __RPC__out DWORD *pdwRevision);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceCount )(
+ IWMDeviceManager * This,
+ /* [out] */ __RPC__out DWORD *pdwCount);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumDevices )(
+ IWMDeviceManager * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumDevice **ppEnumDevice);
+
+ END_INTERFACE
+ } IWMDeviceManagerVtbl;
+
+ interface IWMDeviceManager
+ {
+ CONST_VTBL struct IWMDeviceManagerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDeviceManager_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDeviceManager_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDeviceManager_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDeviceManager_GetRevision(This,pdwRevision) \
+ ( (This)->lpVtbl -> GetRevision(This,pdwRevision) )
+
+#define IWMDeviceManager_GetDeviceCount(This,pdwCount) \
+ ( (This)->lpVtbl -> GetDeviceCount(This,pdwCount) )
+
+#define IWMDeviceManager_EnumDevices(This,ppEnumDevice) \
+ ( (This)->lpVtbl -> EnumDevices(This,ppEnumDevice) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDeviceManager_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDeviceManager2_INTERFACE_DEFINED__
+#define __IWMDeviceManager2_INTERFACE_DEFINED__
+
+/* interface IWMDeviceManager2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDeviceManager2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("923E5249-8731-4c5b-9B1C-B8B60B6E46AF")
+ IWMDeviceManager2 : public IWMDeviceManager
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceFromCanonicalName(
+ /* [string][in] */ __RPC__in LPCWSTR pwszCanonicalName,
+ /* [out] */ __RPC__deref_out_opt IWMDMDevice **ppDevice) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumDevices2(
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumDevice **ppEnumDevice) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reinitialize( void) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDeviceManager2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDeviceManager2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDeviceManager2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDeviceManager2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRevision )(
+ IWMDeviceManager2 * This,
+ /* [out] */ __RPC__out DWORD *pdwRevision);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceCount )(
+ IWMDeviceManager2 * This,
+ /* [out] */ __RPC__out DWORD *pdwCount);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumDevices )(
+ IWMDeviceManager2 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumDevice **ppEnumDevice);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceFromCanonicalName )(
+ IWMDeviceManager2 * This,
+ /* [string][in] */ __RPC__in LPCWSTR pwszCanonicalName,
+ /* [out] */ __RPC__deref_out_opt IWMDMDevice **ppDevice);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumDevices2 )(
+ IWMDeviceManager2 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumDevice **ppEnumDevice);
+
+ HRESULT ( STDMETHODCALLTYPE *Reinitialize )(
+ IWMDeviceManager2 * This);
+
+ END_INTERFACE
+ } IWMDeviceManager2Vtbl;
+
+ interface IWMDeviceManager2
+ {
+ CONST_VTBL struct IWMDeviceManager2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDeviceManager2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDeviceManager2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDeviceManager2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDeviceManager2_GetRevision(This,pdwRevision) \
+ ( (This)->lpVtbl -> GetRevision(This,pdwRevision) )
+
+#define IWMDeviceManager2_GetDeviceCount(This,pdwCount) \
+ ( (This)->lpVtbl -> GetDeviceCount(This,pdwCount) )
+
+#define IWMDeviceManager2_EnumDevices(This,ppEnumDevice) \
+ ( (This)->lpVtbl -> EnumDevices(This,ppEnumDevice) )
+
+
+#define IWMDeviceManager2_GetDeviceFromCanonicalName(This,pwszCanonicalName,ppDevice) \
+ ( (This)->lpVtbl -> GetDeviceFromCanonicalName(This,pwszCanonicalName,ppDevice) )
+
+#define IWMDeviceManager2_EnumDevices2(This,ppEnumDevice) \
+ ( (This)->lpVtbl -> EnumDevices2(This,ppEnumDevice) )
+
+#define IWMDeviceManager2_Reinitialize(This) \
+ ( (This)->lpVtbl -> Reinitialize(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDeviceManager2_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDeviceManager3_INTERFACE_DEFINED__
+#define __IWMDeviceManager3_INTERFACE_DEFINED__
+
+/* interface IWMDeviceManager3 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDeviceManager3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("af185c41-100d-46ed-be2e-9ce8c44594ef")
+ IWMDeviceManager3 : public IWMDeviceManager2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetDeviceEnumPreference(
+ /* [in] */ DWORD dwEnumPref) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDeviceManager3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDeviceManager3 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDeviceManager3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDeviceManager3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRevision )(
+ IWMDeviceManager3 * This,
+ /* [out] */ __RPC__out DWORD *pdwRevision);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceCount )(
+ IWMDeviceManager3 * This,
+ /* [out] */ __RPC__out DWORD *pdwCount);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumDevices )(
+ IWMDeviceManager3 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumDevice **ppEnumDevice);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceFromCanonicalName )(
+ IWMDeviceManager3 * This,
+ /* [string][in] */ __RPC__in LPCWSTR pwszCanonicalName,
+ /* [out] */ __RPC__deref_out_opt IWMDMDevice **ppDevice);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumDevices2 )(
+ IWMDeviceManager3 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumDevice **ppEnumDevice);
+
+ HRESULT ( STDMETHODCALLTYPE *Reinitialize )(
+ IWMDeviceManager3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetDeviceEnumPreference )(
+ IWMDeviceManager3 * This,
+ /* [in] */ DWORD dwEnumPref);
+
+ END_INTERFACE
+ } IWMDeviceManager3Vtbl;
+
+ interface IWMDeviceManager3
+ {
+ CONST_VTBL struct IWMDeviceManager3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDeviceManager3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDeviceManager3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDeviceManager3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDeviceManager3_GetRevision(This,pdwRevision) \
+ ( (This)->lpVtbl -> GetRevision(This,pdwRevision) )
+
+#define IWMDeviceManager3_GetDeviceCount(This,pdwCount) \
+ ( (This)->lpVtbl -> GetDeviceCount(This,pdwCount) )
+
+#define IWMDeviceManager3_EnumDevices(This,ppEnumDevice) \
+ ( (This)->lpVtbl -> EnumDevices(This,ppEnumDevice) )
+
+
+#define IWMDeviceManager3_GetDeviceFromCanonicalName(This,pwszCanonicalName,ppDevice) \
+ ( (This)->lpVtbl -> GetDeviceFromCanonicalName(This,pwszCanonicalName,ppDevice) )
+
+#define IWMDeviceManager3_EnumDevices2(This,ppEnumDevice) \
+ ( (This)->lpVtbl -> EnumDevices2(This,ppEnumDevice) )
+
+#define IWMDeviceManager3_Reinitialize(This) \
+ ( (This)->lpVtbl -> Reinitialize(This) )
+
+
+#define IWMDeviceManager3_SetDeviceEnumPreference(This,dwEnumPref) \
+ ( (This)->lpVtbl -> SetDeviceEnumPreference(This,dwEnumPref) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDeviceManager3_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMStorageGlobals_INTERFACE_DEFINED__
+#define __IWMDMStorageGlobals_INTERFACE_DEFINED__
+
+/* interface IWMDMStorageGlobals */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMStorageGlobals;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A07-33ED-11d3-8470-00C04F79DBC0")
+ IWMDMStorageGlobals : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetCapabilities(
+ /* [out] */ __RPC__out DWORD *pdwCapabilities) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSerialNumber(
+ /* [out] */ __RPC__out PWMDMID pSerialNum,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTotalSize(
+ /* [out] */ __RPC__out DWORD *pdwTotalSizeLow,
+ /* [out] */ __RPC__out DWORD *pdwTotalSizeHigh) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTotalFree(
+ /* [out] */ __RPC__out DWORD *pdwFreeLow,
+ /* [out] */ __RPC__out DWORD *pdwFreeHigh) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTotalBad(
+ /* [out] */ __RPC__out DWORD *pdwBadLow,
+ /* [out] */ __RPC__out DWORD *pdwBadHigh) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStatus(
+ /* [out] */ __RPC__out DWORD *pdwStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Initialize(
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMStorageGlobalsVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMStorageGlobals * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMStorageGlobals * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMStorageGlobals * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCapabilities )(
+ IWMDMStorageGlobals * This,
+ /* [out] */ __RPC__out DWORD *pdwCapabilities);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSerialNumber )(
+ IWMDMStorageGlobals * This,
+ /* [out] */ __RPC__out PWMDMID pSerialNum,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTotalSize )(
+ IWMDMStorageGlobals * This,
+ /* [out] */ __RPC__out DWORD *pdwTotalSizeLow,
+ /* [out] */ __RPC__out DWORD *pdwTotalSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTotalFree )(
+ IWMDMStorageGlobals * This,
+ /* [out] */ __RPC__out DWORD *pdwFreeLow,
+ /* [out] */ __RPC__out DWORD *pdwFreeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTotalBad )(
+ IWMDMStorageGlobals * This,
+ /* [out] */ __RPC__out DWORD *pdwBadLow,
+ /* [out] */ __RPC__out DWORD *pdwBadHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStatus )(
+ IWMDMStorageGlobals * This,
+ /* [out] */ __RPC__out DWORD *pdwStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ IWMDMStorageGlobals * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ END_INTERFACE
+ } IWMDMStorageGlobalsVtbl;
+
+ interface IWMDMStorageGlobals
+ {
+ CONST_VTBL struct IWMDMStorageGlobalsVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMStorageGlobals_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMStorageGlobals_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMStorageGlobals_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMStorageGlobals_GetCapabilities(This,pdwCapabilities) \
+ ( (This)->lpVtbl -> GetCapabilities(This,pdwCapabilities) )
+
+#define IWMDMStorageGlobals_GetSerialNumber(This,pSerialNum,abMac) \
+ ( (This)->lpVtbl -> GetSerialNumber(This,pSerialNum,abMac) )
+
+#define IWMDMStorageGlobals_GetTotalSize(This,pdwTotalSizeLow,pdwTotalSizeHigh) \
+ ( (This)->lpVtbl -> GetTotalSize(This,pdwTotalSizeLow,pdwTotalSizeHigh) )
+
+#define IWMDMStorageGlobals_GetTotalFree(This,pdwFreeLow,pdwFreeHigh) \
+ ( (This)->lpVtbl -> GetTotalFree(This,pdwFreeLow,pdwFreeHigh) )
+
+#define IWMDMStorageGlobals_GetTotalBad(This,pdwBadLow,pdwBadHigh) \
+ ( (This)->lpVtbl -> GetTotalBad(This,pdwBadLow,pdwBadHigh) )
+
+#define IWMDMStorageGlobals_GetStatus(This,pdwStatus) \
+ ( (This)->lpVtbl -> GetStatus(This,pdwStatus) )
+
+#define IWMDMStorageGlobals_Initialize(This,fuMode,pProgress) \
+ ( (This)->lpVtbl -> Initialize(This,fuMode,pProgress) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMStorageGlobals_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMStorage_INTERFACE_DEFINED__
+#define __IWMDMStorage_INTERFACE_DEFINED__
+
+/* interface IWMDMStorage */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMStorage;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A06-33ED-11d3-8470-00C04F79DBC0")
+ IWMDMStorage : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetAttributes(
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStorageGlobals(
+ /* [out] */ __RPC__deref_out_opt IWMDMStorageGlobals **ppStorageGlobals) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAttributes(
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pFormat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDate(
+ /* [out] */ __RPC__out PWMDMDATETIME pDateTimeUTC) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSize(
+ /* [out] */ __RPC__out DWORD *pdwSizeLow,
+ /* [out] */ __RPC__out DWORD *pdwSizeHigh) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRights(
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumStorage(
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumStorage **pEnumStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SendOpaqueCommand(
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMStorageVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMStorage * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMStorage * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMStorage * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAttributes )(
+ IWMDMStorage * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorageGlobals )(
+ IWMDMStorage * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorageGlobals **ppStorageGlobals);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes )(
+ IWMDMStorage * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IWMDMStorage * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDate )(
+ IWMDMStorage * This,
+ /* [out] */ __RPC__out PWMDMDATETIME pDateTimeUTC);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ IWMDMStorage * This,
+ /* [out] */ __RPC__out DWORD *pdwSizeLow,
+ /* [out] */ __RPC__out DWORD *pdwSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRights )(
+ IWMDMStorage * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStorage )(
+ IWMDMStorage * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumStorage **pEnumStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *SendOpaqueCommand )(
+ IWMDMStorage * This,
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand);
+
+ END_INTERFACE
+ } IWMDMStorageVtbl;
+
+ interface IWMDMStorage
+ {
+ CONST_VTBL struct IWMDMStorageVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMStorage_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMStorage_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMStorage_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMStorage_SetAttributes(This,dwAttributes,pFormat) \
+ ( (This)->lpVtbl -> SetAttributes(This,dwAttributes,pFormat) )
+
+#define IWMDMStorage_GetStorageGlobals(This,ppStorageGlobals) \
+ ( (This)->lpVtbl -> GetStorageGlobals(This,ppStorageGlobals) )
+
+#define IWMDMStorage_GetAttributes(This,pdwAttributes,pFormat) \
+ ( (This)->lpVtbl -> GetAttributes(This,pdwAttributes,pFormat) )
+
+#define IWMDMStorage_GetName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetName(This,pwszName,nMaxChars) )
+
+#define IWMDMStorage_GetDate(This,pDateTimeUTC) \
+ ( (This)->lpVtbl -> GetDate(This,pDateTimeUTC) )
+
+#define IWMDMStorage_GetSize(This,pdwSizeLow,pdwSizeHigh) \
+ ( (This)->lpVtbl -> GetSize(This,pdwSizeLow,pdwSizeHigh) )
+
+#define IWMDMStorage_GetRights(This,ppRights,pnRightsCount,abMac) \
+ ( (This)->lpVtbl -> GetRights(This,ppRights,pnRightsCount,abMac) )
+
+#define IWMDMStorage_EnumStorage(This,pEnumStorage) \
+ ( (This)->lpVtbl -> EnumStorage(This,pEnumStorage) )
+
+#define IWMDMStorage_SendOpaqueCommand(This,pCommand) \
+ ( (This)->lpVtbl -> SendOpaqueCommand(This,pCommand) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMStorage_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMStorage2_INTERFACE_DEFINED__
+#define __IWMDMStorage2_INTERFACE_DEFINED__
+
+/* interface IWMDMStorage2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMStorage2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1ED5A144-5CD5-4683-9EFF-72CBDB2D9533")
+ IWMDMStorage2 : public IWMDMStorage
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetStorage(
+ /* [string][in] */ __RPC__in LPCWSTR pszStorageName,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAttributes2(
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ DWORD dwAttributesEx,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat,
+ /* [unique][in] */ __RPC__in_opt _VIDEOINFOHEADER *pVideoFormat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAttributes2(
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [out] */ __RPC__out DWORD *pdwAttributesEx,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][out][in] */ __RPC__inout_opt _VIDEOINFOHEADER *pVideoFormat) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMStorage2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMStorage2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMStorage2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMStorage2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAttributes )(
+ IWMDMStorage2 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorageGlobals )(
+ IWMDMStorage2 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorageGlobals **ppStorageGlobals);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes )(
+ IWMDMStorage2 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IWMDMStorage2 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDate )(
+ IWMDMStorage2 * This,
+ /* [out] */ __RPC__out PWMDMDATETIME pDateTimeUTC);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ IWMDMStorage2 * This,
+ /* [out] */ __RPC__out DWORD *pdwSizeLow,
+ /* [out] */ __RPC__out DWORD *pdwSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRights )(
+ IWMDMStorage2 * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStorage )(
+ IWMDMStorage2 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumStorage **pEnumStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *SendOpaqueCommand )(
+ IWMDMStorage2 * This,
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorage )(
+ IWMDMStorage2 * This,
+ /* [string][in] */ __RPC__in LPCWSTR pszStorageName,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAttributes2 )(
+ IWMDMStorage2 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ DWORD dwAttributesEx,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat,
+ /* [unique][in] */ __RPC__in_opt _VIDEOINFOHEADER *pVideoFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes2 )(
+ IWMDMStorage2 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [out] */ __RPC__out DWORD *pdwAttributesEx,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][out][in] */ __RPC__inout_opt _VIDEOINFOHEADER *pVideoFormat);
+
+ END_INTERFACE
+ } IWMDMStorage2Vtbl;
+
+ interface IWMDMStorage2
+ {
+ CONST_VTBL struct IWMDMStorage2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMStorage2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMStorage2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMStorage2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMStorage2_SetAttributes(This,dwAttributes,pFormat) \
+ ( (This)->lpVtbl -> SetAttributes(This,dwAttributes,pFormat) )
+
+#define IWMDMStorage2_GetStorageGlobals(This,ppStorageGlobals) \
+ ( (This)->lpVtbl -> GetStorageGlobals(This,ppStorageGlobals) )
+
+#define IWMDMStorage2_GetAttributes(This,pdwAttributes,pFormat) \
+ ( (This)->lpVtbl -> GetAttributes(This,pdwAttributes,pFormat) )
+
+#define IWMDMStorage2_GetName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetName(This,pwszName,nMaxChars) )
+
+#define IWMDMStorage2_GetDate(This,pDateTimeUTC) \
+ ( (This)->lpVtbl -> GetDate(This,pDateTimeUTC) )
+
+#define IWMDMStorage2_GetSize(This,pdwSizeLow,pdwSizeHigh) \
+ ( (This)->lpVtbl -> GetSize(This,pdwSizeLow,pdwSizeHigh) )
+
+#define IWMDMStorage2_GetRights(This,ppRights,pnRightsCount,abMac) \
+ ( (This)->lpVtbl -> GetRights(This,ppRights,pnRightsCount,abMac) )
+
+#define IWMDMStorage2_EnumStorage(This,pEnumStorage) \
+ ( (This)->lpVtbl -> EnumStorage(This,pEnumStorage) )
+
+#define IWMDMStorage2_SendOpaqueCommand(This,pCommand) \
+ ( (This)->lpVtbl -> SendOpaqueCommand(This,pCommand) )
+
+
+#define IWMDMStorage2_GetStorage(This,pszStorageName,ppStorage) \
+ ( (This)->lpVtbl -> GetStorage(This,pszStorageName,ppStorage) )
+
+#define IWMDMStorage2_SetAttributes2(This,dwAttributes,dwAttributesEx,pFormat,pVideoFormat) \
+ ( (This)->lpVtbl -> SetAttributes2(This,dwAttributes,dwAttributesEx,pFormat,pVideoFormat) )
+
+#define IWMDMStorage2_GetAttributes2(This,pdwAttributes,pdwAttributesEx,pAudioFormat,pVideoFormat) \
+ ( (This)->lpVtbl -> GetAttributes2(This,pdwAttributes,pdwAttributesEx,pAudioFormat,pVideoFormat) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMStorage2_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMStorage3_INTERFACE_DEFINED__
+#define __IWMDMStorage3_INTERFACE_DEFINED__
+
+/* interface IWMDMStorage3 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMStorage3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("97717EEA-926A-464e-96A4-247B0216026E")
+ IWMDMStorage3 : public IWMDMStorage2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetMetadata(
+ /* [out] */ __RPC__deref_out_opt IWMDMMetaData **ppMetadata) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetMetadata(
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pMetadata) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateEmptyMetadataObject(
+ /* [out] */ __RPC__deref_out_opt IWMDMMetaData **ppMetadata) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetEnumPreference(
+ /* [out][in] */ __RPC__inout WMDM_STORAGE_ENUM_MODE *pMode,
+ /* [in] */ DWORD nViews,
+ /* [unique][size_is][in] */ __RPC__in_ecount_full_opt(nViews) WMDMMetadataView *pViews) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMStorage3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMStorage3 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMStorage3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMStorage3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAttributes )(
+ IWMDMStorage3 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorageGlobals )(
+ IWMDMStorage3 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorageGlobals **ppStorageGlobals);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes )(
+ IWMDMStorage3 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IWMDMStorage3 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDate )(
+ IWMDMStorage3 * This,
+ /* [out] */ __RPC__out PWMDMDATETIME pDateTimeUTC);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ IWMDMStorage3 * This,
+ /* [out] */ __RPC__out DWORD *pdwSizeLow,
+ /* [out] */ __RPC__out DWORD *pdwSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRights )(
+ IWMDMStorage3 * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStorage )(
+ IWMDMStorage3 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumStorage **pEnumStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *SendOpaqueCommand )(
+ IWMDMStorage3 * This,
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorage )(
+ IWMDMStorage3 * This,
+ /* [string][in] */ __RPC__in LPCWSTR pszStorageName,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAttributes2 )(
+ IWMDMStorage3 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ DWORD dwAttributesEx,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat,
+ /* [unique][in] */ __RPC__in_opt _VIDEOINFOHEADER *pVideoFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes2 )(
+ IWMDMStorage3 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [out] */ __RPC__out DWORD *pdwAttributesEx,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][out][in] */ __RPC__inout_opt _VIDEOINFOHEADER *pVideoFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMetadata )(
+ IWMDMStorage3 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMMetaData **ppMetadata);
+
+ HRESULT ( STDMETHODCALLTYPE *SetMetadata )(
+ IWMDMStorage3 * This,
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pMetadata);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateEmptyMetadataObject )(
+ IWMDMStorage3 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMMetaData **ppMetadata);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnumPreference )(
+ IWMDMStorage3 * This,
+ /* [out][in] */ __RPC__inout WMDM_STORAGE_ENUM_MODE *pMode,
+ /* [in] */ DWORD nViews,
+ /* [unique][size_is][in] */ __RPC__in_ecount_full_opt(nViews) WMDMMetadataView *pViews);
+
+ END_INTERFACE
+ } IWMDMStorage3Vtbl;
+
+ interface IWMDMStorage3
+ {
+ CONST_VTBL struct IWMDMStorage3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMStorage3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMStorage3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMStorage3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMStorage3_SetAttributes(This,dwAttributes,pFormat) \
+ ( (This)->lpVtbl -> SetAttributes(This,dwAttributes,pFormat) )
+
+#define IWMDMStorage3_GetStorageGlobals(This,ppStorageGlobals) \
+ ( (This)->lpVtbl -> GetStorageGlobals(This,ppStorageGlobals) )
+
+#define IWMDMStorage3_GetAttributes(This,pdwAttributes,pFormat) \
+ ( (This)->lpVtbl -> GetAttributes(This,pdwAttributes,pFormat) )
+
+#define IWMDMStorage3_GetName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetName(This,pwszName,nMaxChars) )
+
+#define IWMDMStorage3_GetDate(This,pDateTimeUTC) \
+ ( (This)->lpVtbl -> GetDate(This,pDateTimeUTC) )
+
+#define IWMDMStorage3_GetSize(This,pdwSizeLow,pdwSizeHigh) \
+ ( (This)->lpVtbl -> GetSize(This,pdwSizeLow,pdwSizeHigh) )
+
+#define IWMDMStorage3_GetRights(This,ppRights,pnRightsCount,abMac) \
+ ( (This)->lpVtbl -> GetRights(This,ppRights,pnRightsCount,abMac) )
+
+#define IWMDMStorage3_EnumStorage(This,pEnumStorage) \
+ ( (This)->lpVtbl -> EnumStorage(This,pEnumStorage) )
+
+#define IWMDMStorage3_SendOpaqueCommand(This,pCommand) \
+ ( (This)->lpVtbl -> SendOpaqueCommand(This,pCommand) )
+
+
+#define IWMDMStorage3_GetStorage(This,pszStorageName,ppStorage) \
+ ( (This)->lpVtbl -> GetStorage(This,pszStorageName,ppStorage) )
+
+#define IWMDMStorage3_SetAttributes2(This,dwAttributes,dwAttributesEx,pFormat,pVideoFormat) \
+ ( (This)->lpVtbl -> SetAttributes2(This,dwAttributes,dwAttributesEx,pFormat,pVideoFormat) )
+
+#define IWMDMStorage3_GetAttributes2(This,pdwAttributes,pdwAttributesEx,pAudioFormat,pVideoFormat) \
+ ( (This)->lpVtbl -> GetAttributes2(This,pdwAttributes,pdwAttributesEx,pAudioFormat,pVideoFormat) )
+
+
+#define IWMDMStorage3_GetMetadata(This,ppMetadata) \
+ ( (This)->lpVtbl -> GetMetadata(This,ppMetadata) )
+
+#define IWMDMStorage3_SetMetadata(This,pMetadata) \
+ ( (This)->lpVtbl -> SetMetadata(This,pMetadata) )
+
+#define IWMDMStorage3_CreateEmptyMetadataObject(This,ppMetadata) \
+ ( (This)->lpVtbl -> CreateEmptyMetadataObject(This,ppMetadata) )
+
+#define IWMDMStorage3_SetEnumPreference(This,pMode,nViews,pViews) \
+ ( (This)->lpVtbl -> SetEnumPreference(This,pMode,nViews,pViews) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMStorage3_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMStorage4_INTERFACE_DEFINED__
+#define __IWMDMStorage4_INTERFACE_DEFINED__
+
+/* interface IWMDMStorage4 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMStorage4;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("c225bac5-a03a-40b8-9a23-91cf478c64a6")
+ IWMDMStorage4 : public IWMDMStorage3
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetReferences(
+ /* [in] */ DWORD dwRefs,
+ /* [size_is][unique][in] */ __RPC__in_ecount_full_opt(dwRefs) IWMDMStorage **ppIWMDMStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetReferences(
+ /* [out] */ __RPC__out DWORD *pdwRefs,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pdwRefs) IWMDMStorage ***pppIWMDMStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRightsWithProgress(
+ /* [in] */ __RPC__in_opt IWMDMProgress3 *pIProgressCallback,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSpecifiedMetadata(
+ /* [in] */ DWORD cProperties,
+ /* [size_is][in] */ __RPC__in_ecount_full(cProperties) LPCWSTR *ppwszPropNames,
+ /* [out] */ __RPC__deref_out_opt IWMDMMetaData **ppMetadata) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindStorage(
+ /* [in] */ WMDM_FIND_SCOPE findScope,
+ /* [in] */ __RPC__in LPCWSTR pwszUniqueID,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetParent(
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppStorage) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMStorage4Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMStorage4 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMStorage4 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMStorage4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAttributes )(
+ IWMDMStorage4 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorageGlobals )(
+ IWMDMStorage4 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorageGlobals **ppStorageGlobals);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes )(
+ IWMDMStorage4 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IWMDMStorage4 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDate )(
+ IWMDMStorage4 * This,
+ /* [out] */ __RPC__out PWMDMDATETIME pDateTimeUTC);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ IWMDMStorage4 * This,
+ /* [out] */ __RPC__out DWORD *pdwSizeLow,
+ /* [out] */ __RPC__out DWORD *pdwSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRights )(
+ IWMDMStorage4 * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStorage )(
+ IWMDMStorage4 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumStorage **pEnumStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *SendOpaqueCommand )(
+ IWMDMStorage4 * This,
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorage )(
+ IWMDMStorage4 * This,
+ /* [string][in] */ __RPC__in LPCWSTR pszStorageName,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAttributes2 )(
+ IWMDMStorage4 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ DWORD dwAttributesEx,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat,
+ /* [unique][in] */ __RPC__in_opt _VIDEOINFOHEADER *pVideoFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes2 )(
+ IWMDMStorage4 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [out] */ __RPC__out DWORD *pdwAttributesEx,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][out][in] */ __RPC__inout_opt _VIDEOINFOHEADER *pVideoFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMetadata )(
+ IWMDMStorage4 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMMetaData **ppMetadata);
+
+ HRESULT ( STDMETHODCALLTYPE *SetMetadata )(
+ IWMDMStorage4 * This,
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pMetadata);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateEmptyMetadataObject )(
+ IWMDMStorage4 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMMetaData **ppMetadata);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnumPreference )(
+ IWMDMStorage4 * This,
+ /* [out][in] */ __RPC__inout WMDM_STORAGE_ENUM_MODE *pMode,
+ /* [in] */ DWORD nViews,
+ /* [unique][size_is][in] */ __RPC__in_ecount_full_opt(nViews) WMDMMetadataView *pViews);
+
+ HRESULT ( STDMETHODCALLTYPE *SetReferences )(
+ IWMDMStorage4 * This,
+ /* [in] */ DWORD dwRefs,
+ /* [size_is][unique][in] */ __RPC__in_ecount_full_opt(dwRefs) IWMDMStorage **ppIWMDMStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReferences )(
+ IWMDMStorage4 * This,
+ /* [out] */ __RPC__out DWORD *pdwRefs,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pdwRefs) IWMDMStorage ***pppIWMDMStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRightsWithProgress )(
+ IWMDMStorage4 * This,
+ /* [in] */ __RPC__in_opt IWMDMProgress3 *pIProgressCallback,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSpecifiedMetadata )(
+ IWMDMStorage4 * This,
+ /* [in] */ DWORD cProperties,
+ /* [size_is][in] */ __RPC__in_ecount_full(cProperties) LPCWSTR *ppwszPropNames,
+ /* [out] */ __RPC__deref_out_opt IWMDMMetaData **ppMetadata);
+
+ HRESULT ( STDMETHODCALLTYPE *FindStorage )(
+ IWMDMStorage4 * This,
+ /* [in] */ WMDM_FIND_SCOPE findScope,
+ /* [in] */ __RPC__in LPCWSTR pwszUniqueID,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetParent )(
+ IWMDMStorage4 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppStorage);
+
+ END_INTERFACE
+ } IWMDMStorage4Vtbl;
+
+ interface IWMDMStorage4
+ {
+ CONST_VTBL struct IWMDMStorage4Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMStorage4_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMStorage4_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMStorage4_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMStorage4_SetAttributes(This,dwAttributes,pFormat) \
+ ( (This)->lpVtbl -> SetAttributes(This,dwAttributes,pFormat) )
+
+#define IWMDMStorage4_GetStorageGlobals(This,ppStorageGlobals) \
+ ( (This)->lpVtbl -> GetStorageGlobals(This,ppStorageGlobals) )
+
+#define IWMDMStorage4_GetAttributes(This,pdwAttributes,pFormat) \
+ ( (This)->lpVtbl -> GetAttributes(This,pdwAttributes,pFormat) )
+
+#define IWMDMStorage4_GetName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetName(This,pwszName,nMaxChars) )
+
+#define IWMDMStorage4_GetDate(This,pDateTimeUTC) \
+ ( (This)->lpVtbl -> GetDate(This,pDateTimeUTC) )
+
+#define IWMDMStorage4_GetSize(This,pdwSizeLow,pdwSizeHigh) \
+ ( (This)->lpVtbl -> GetSize(This,pdwSizeLow,pdwSizeHigh) )
+
+#define IWMDMStorage4_GetRights(This,ppRights,pnRightsCount,abMac) \
+ ( (This)->lpVtbl -> GetRights(This,ppRights,pnRightsCount,abMac) )
+
+#define IWMDMStorage4_EnumStorage(This,pEnumStorage) \
+ ( (This)->lpVtbl -> EnumStorage(This,pEnumStorage) )
+
+#define IWMDMStorage4_SendOpaqueCommand(This,pCommand) \
+ ( (This)->lpVtbl -> SendOpaqueCommand(This,pCommand) )
+
+
+#define IWMDMStorage4_GetStorage(This,pszStorageName,ppStorage) \
+ ( (This)->lpVtbl -> GetStorage(This,pszStorageName,ppStorage) )
+
+#define IWMDMStorage4_SetAttributes2(This,dwAttributes,dwAttributesEx,pFormat,pVideoFormat) \
+ ( (This)->lpVtbl -> SetAttributes2(This,dwAttributes,dwAttributesEx,pFormat,pVideoFormat) )
+
+#define IWMDMStorage4_GetAttributes2(This,pdwAttributes,pdwAttributesEx,pAudioFormat,pVideoFormat) \
+ ( (This)->lpVtbl -> GetAttributes2(This,pdwAttributes,pdwAttributesEx,pAudioFormat,pVideoFormat) )
+
+
+#define IWMDMStorage4_GetMetadata(This,ppMetadata) \
+ ( (This)->lpVtbl -> GetMetadata(This,ppMetadata) )
+
+#define IWMDMStorage4_SetMetadata(This,pMetadata) \
+ ( (This)->lpVtbl -> SetMetadata(This,pMetadata) )
+
+#define IWMDMStorage4_CreateEmptyMetadataObject(This,ppMetadata) \
+ ( (This)->lpVtbl -> CreateEmptyMetadataObject(This,ppMetadata) )
+
+#define IWMDMStorage4_SetEnumPreference(This,pMode,nViews,pViews) \
+ ( (This)->lpVtbl -> SetEnumPreference(This,pMode,nViews,pViews) )
+
+
+#define IWMDMStorage4_SetReferences(This,dwRefs,ppIWMDMStorage) \
+ ( (This)->lpVtbl -> SetReferences(This,dwRefs,ppIWMDMStorage) )
+
+#define IWMDMStorage4_GetReferences(This,pdwRefs,pppIWMDMStorage) \
+ ( (This)->lpVtbl -> GetReferences(This,pdwRefs,pppIWMDMStorage) )
+
+#define IWMDMStorage4_GetRightsWithProgress(This,pIProgressCallback,ppRights,pnRightsCount) \
+ ( (This)->lpVtbl -> GetRightsWithProgress(This,pIProgressCallback,ppRights,pnRightsCount) )
+
+#define IWMDMStorage4_GetSpecifiedMetadata(This,cProperties,ppwszPropNames,ppMetadata) \
+ ( (This)->lpVtbl -> GetSpecifiedMetadata(This,cProperties,ppwszPropNames,ppMetadata) )
+
+#define IWMDMStorage4_FindStorage(This,findScope,pwszUniqueID,ppStorage) \
+ ( (This)->lpVtbl -> FindStorage(This,findScope,pwszUniqueID,ppStorage) )
+
+#define IWMDMStorage4_GetParent(This,ppStorage) \
+ ( (This)->lpVtbl -> GetParent(This,ppStorage) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMStorage4_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMOperation_INTERFACE_DEFINED__
+#define __IWMDMOperation_INTERFACE_DEFINED__
+
+/* interface IWMDMOperation */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMOperation;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A0B-33ED-11d3-8470-00C04F79DBC0")
+ IWMDMOperation : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE BeginRead( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE BeginWrite( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObjectName(
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetObjectName(
+ /* [size_is][string][in] */ __RPC__in_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObjectAttributes(
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pFormat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetObjectAttributes(
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObjectTotalSize(
+ /* [out] */ __RPC__out DWORD *pdwSize,
+ /* [out] */ __RPC__out DWORD *pdwSizeHigh) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetObjectTotalSize(
+ /* [in] */ DWORD dwSize,
+ /* [in] */ DWORD dwSizeHigh) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE TransferObjectData(
+ /* [size_is][out][in] */ __RPC__inout_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE End(
+ /* [in] */ __RPC__in HRESULT *phCompletionCode,
+ /* [in] */ __RPC__in_opt IUnknown *pNewObject) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMOperationVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMOperation * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMOperation * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMOperation * This);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginRead )(
+ IWMDMOperation * This);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginWrite )(
+ IWMDMOperation * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectName )(
+ IWMDMOperation * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *SetObjectName )(
+ IWMDMOperation * This,
+ /* [size_is][string][in] */ __RPC__in_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectAttributes )(
+ IWMDMOperation * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *SetObjectAttributes )(
+ IWMDMOperation * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectTotalSize )(
+ IWMDMOperation * This,
+ /* [out] */ __RPC__out DWORD *pdwSize,
+ /* [out] */ __RPC__out DWORD *pdwSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *SetObjectTotalSize )(
+ IWMDMOperation * This,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ DWORD dwSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferObjectData )(
+ IWMDMOperation * This,
+ /* [size_is][out][in] */ __RPC__inout_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *End )(
+ IWMDMOperation * This,
+ /* [in] */ __RPC__in HRESULT *phCompletionCode,
+ /* [in] */ __RPC__in_opt IUnknown *pNewObject);
+
+ END_INTERFACE
+ } IWMDMOperationVtbl;
+
+ interface IWMDMOperation
+ {
+ CONST_VTBL struct IWMDMOperationVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMOperation_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMOperation_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMOperation_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMOperation_BeginRead(This) \
+ ( (This)->lpVtbl -> BeginRead(This) )
+
+#define IWMDMOperation_BeginWrite(This) \
+ ( (This)->lpVtbl -> BeginWrite(This) )
+
+#define IWMDMOperation_GetObjectName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetObjectName(This,pwszName,nMaxChars) )
+
+#define IWMDMOperation_SetObjectName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> SetObjectName(This,pwszName,nMaxChars) )
+
+#define IWMDMOperation_GetObjectAttributes(This,pdwAttributes,pFormat) \
+ ( (This)->lpVtbl -> GetObjectAttributes(This,pdwAttributes,pFormat) )
+
+#define IWMDMOperation_SetObjectAttributes(This,dwAttributes,pFormat) \
+ ( (This)->lpVtbl -> SetObjectAttributes(This,dwAttributes,pFormat) )
+
+#define IWMDMOperation_GetObjectTotalSize(This,pdwSize,pdwSizeHigh) \
+ ( (This)->lpVtbl -> GetObjectTotalSize(This,pdwSize,pdwSizeHigh) )
+
+#define IWMDMOperation_SetObjectTotalSize(This,dwSize,dwSizeHigh) \
+ ( (This)->lpVtbl -> SetObjectTotalSize(This,dwSize,dwSizeHigh) )
+
+#define IWMDMOperation_TransferObjectData(This,pData,pdwSize,abMac) \
+ ( (This)->lpVtbl -> TransferObjectData(This,pData,pdwSize,abMac) )
+
+#define IWMDMOperation_End(This,phCompletionCode,pNewObject) \
+ ( (This)->lpVtbl -> End(This,phCompletionCode,pNewObject) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMOperation_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMOperation2_INTERFACE_DEFINED__
+#define __IWMDMOperation2_INTERFACE_DEFINED__
+
+/* interface IWMDMOperation2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMOperation2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("33445B48-7DF7-425c-AD8F-0FC6D82F9F75")
+ IWMDMOperation2 : public IWMDMOperation
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetObjectAttributes2(
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ DWORD dwAttributesEx,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat,
+ /* [unique][in] */ __RPC__in_opt _VIDEOINFOHEADER *pVideoFormat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObjectAttributes2(
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [out] */ __RPC__out DWORD *pdwAttributesEx,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][out][in] */ __RPC__inout_opt _VIDEOINFOHEADER *pVideoFormat) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMOperation2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMOperation2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMOperation2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMOperation2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginRead )(
+ IWMDMOperation2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginWrite )(
+ IWMDMOperation2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectName )(
+ IWMDMOperation2 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *SetObjectName )(
+ IWMDMOperation2 * This,
+ /* [size_is][string][in] */ __RPC__in_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectAttributes )(
+ IWMDMOperation2 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *SetObjectAttributes )(
+ IWMDMOperation2 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectTotalSize )(
+ IWMDMOperation2 * This,
+ /* [out] */ __RPC__out DWORD *pdwSize,
+ /* [out] */ __RPC__out DWORD *pdwSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *SetObjectTotalSize )(
+ IWMDMOperation2 * This,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ DWORD dwSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferObjectData )(
+ IWMDMOperation2 * This,
+ /* [size_is][out][in] */ __RPC__inout_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *End )(
+ IWMDMOperation2 * This,
+ /* [in] */ __RPC__in HRESULT *phCompletionCode,
+ /* [in] */ __RPC__in_opt IUnknown *pNewObject);
+
+ HRESULT ( STDMETHODCALLTYPE *SetObjectAttributes2 )(
+ IWMDMOperation2 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ DWORD dwAttributesEx,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat,
+ /* [unique][in] */ __RPC__in_opt _VIDEOINFOHEADER *pVideoFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectAttributes2 )(
+ IWMDMOperation2 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [out] */ __RPC__out DWORD *pdwAttributesEx,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][out][in] */ __RPC__inout_opt _VIDEOINFOHEADER *pVideoFormat);
+
+ END_INTERFACE
+ } IWMDMOperation2Vtbl;
+
+ interface IWMDMOperation2
+ {
+ CONST_VTBL struct IWMDMOperation2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMOperation2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMOperation2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMOperation2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMOperation2_BeginRead(This) \
+ ( (This)->lpVtbl -> BeginRead(This) )
+
+#define IWMDMOperation2_BeginWrite(This) \
+ ( (This)->lpVtbl -> BeginWrite(This) )
+
+#define IWMDMOperation2_GetObjectName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetObjectName(This,pwszName,nMaxChars) )
+
+#define IWMDMOperation2_SetObjectName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> SetObjectName(This,pwszName,nMaxChars) )
+
+#define IWMDMOperation2_GetObjectAttributes(This,pdwAttributes,pFormat) \
+ ( (This)->lpVtbl -> GetObjectAttributes(This,pdwAttributes,pFormat) )
+
+#define IWMDMOperation2_SetObjectAttributes(This,dwAttributes,pFormat) \
+ ( (This)->lpVtbl -> SetObjectAttributes(This,dwAttributes,pFormat) )
+
+#define IWMDMOperation2_GetObjectTotalSize(This,pdwSize,pdwSizeHigh) \
+ ( (This)->lpVtbl -> GetObjectTotalSize(This,pdwSize,pdwSizeHigh) )
+
+#define IWMDMOperation2_SetObjectTotalSize(This,dwSize,dwSizeHigh) \
+ ( (This)->lpVtbl -> SetObjectTotalSize(This,dwSize,dwSizeHigh) )
+
+#define IWMDMOperation2_TransferObjectData(This,pData,pdwSize,abMac) \
+ ( (This)->lpVtbl -> TransferObjectData(This,pData,pdwSize,abMac) )
+
+#define IWMDMOperation2_End(This,phCompletionCode,pNewObject) \
+ ( (This)->lpVtbl -> End(This,phCompletionCode,pNewObject) )
+
+
+#define IWMDMOperation2_SetObjectAttributes2(This,dwAttributes,dwAttributesEx,pFormat,pVideoFormat) \
+ ( (This)->lpVtbl -> SetObjectAttributes2(This,dwAttributes,dwAttributesEx,pFormat,pVideoFormat) )
+
+#define IWMDMOperation2_GetObjectAttributes2(This,pdwAttributes,pdwAttributesEx,pAudioFormat,pVideoFormat) \
+ ( (This)->lpVtbl -> GetObjectAttributes2(This,pdwAttributes,pdwAttributesEx,pAudioFormat,pVideoFormat) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMOperation2_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMOperation3_INTERFACE_DEFINED__
+#define __IWMDMOperation3_INTERFACE_DEFINED__
+
+/* interface IWMDMOperation3 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMOperation3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("d1f9b46a-9ca8-46d8-9d0f-1ec9bae54919")
+ IWMDMOperation3 : public IWMDMOperation
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE TransferObjectDataOnClearChannel(
+ /* [size_is][out][in] */ __RPC__inout_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMOperation3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMOperation3 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMOperation3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMOperation3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginRead )(
+ IWMDMOperation3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginWrite )(
+ IWMDMOperation3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectName )(
+ IWMDMOperation3 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *SetObjectName )(
+ IWMDMOperation3 * This,
+ /* [size_is][string][in] */ __RPC__in_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectAttributes )(
+ IWMDMOperation3 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *SetObjectAttributes )(
+ IWMDMOperation3 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectTotalSize )(
+ IWMDMOperation3 * This,
+ /* [out] */ __RPC__out DWORD *pdwSize,
+ /* [out] */ __RPC__out DWORD *pdwSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *SetObjectTotalSize )(
+ IWMDMOperation3 * This,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ DWORD dwSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferObjectData )(
+ IWMDMOperation3 * This,
+ /* [size_is][out][in] */ __RPC__inout_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *End )(
+ IWMDMOperation3 * This,
+ /* [in] */ __RPC__in HRESULT *phCompletionCode,
+ /* [in] */ __RPC__in_opt IUnknown *pNewObject);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferObjectDataOnClearChannel )(
+ IWMDMOperation3 * This,
+ /* [size_is][out][in] */ __RPC__inout_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize);
+
+ END_INTERFACE
+ } IWMDMOperation3Vtbl;
+
+ interface IWMDMOperation3
+ {
+ CONST_VTBL struct IWMDMOperation3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMOperation3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMOperation3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMOperation3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMOperation3_BeginRead(This) \
+ ( (This)->lpVtbl -> BeginRead(This) )
+
+#define IWMDMOperation3_BeginWrite(This) \
+ ( (This)->lpVtbl -> BeginWrite(This) )
+
+#define IWMDMOperation3_GetObjectName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetObjectName(This,pwszName,nMaxChars) )
+
+#define IWMDMOperation3_SetObjectName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> SetObjectName(This,pwszName,nMaxChars) )
+
+#define IWMDMOperation3_GetObjectAttributes(This,pdwAttributes,pFormat) \
+ ( (This)->lpVtbl -> GetObjectAttributes(This,pdwAttributes,pFormat) )
+
+#define IWMDMOperation3_SetObjectAttributes(This,dwAttributes,pFormat) \
+ ( (This)->lpVtbl -> SetObjectAttributes(This,dwAttributes,pFormat) )
+
+#define IWMDMOperation3_GetObjectTotalSize(This,pdwSize,pdwSizeHigh) \
+ ( (This)->lpVtbl -> GetObjectTotalSize(This,pdwSize,pdwSizeHigh) )
+
+#define IWMDMOperation3_SetObjectTotalSize(This,dwSize,dwSizeHigh) \
+ ( (This)->lpVtbl -> SetObjectTotalSize(This,dwSize,dwSizeHigh) )
+
+#define IWMDMOperation3_TransferObjectData(This,pData,pdwSize,abMac) \
+ ( (This)->lpVtbl -> TransferObjectData(This,pData,pdwSize,abMac) )
+
+#define IWMDMOperation3_End(This,phCompletionCode,pNewObject) \
+ ( (This)->lpVtbl -> End(This,phCompletionCode,pNewObject) )
+
+
+#define IWMDMOperation3_TransferObjectDataOnClearChannel(This,pData,pdwSize) \
+ ( (This)->lpVtbl -> TransferObjectDataOnClearChannel(This,pData,pdwSize) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMOperation3_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMProgress_INTERFACE_DEFINED__
+#define __IWMDMProgress_INTERFACE_DEFINED__
+
+/* interface IWMDMProgress */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMProgress;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A0C-33ED-11d3-8470-00C04F79DBC0")
+ IWMDMProgress : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Begin(
+ /* [in] */ DWORD dwEstimatedTicks) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Progress(
+ /* [in] */ DWORD dwTranspiredTicks) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE End( void) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMProgressVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMProgress * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMProgress * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMProgress * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Begin )(
+ IWMDMProgress * This,
+ /* [in] */ DWORD dwEstimatedTicks);
+
+ HRESULT ( STDMETHODCALLTYPE *Progress )(
+ IWMDMProgress * This,
+ /* [in] */ DWORD dwTranspiredTicks);
+
+ HRESULT ( STDMETHODCALLTYPE *End )(
+ IWMDMProgress * This);
+
+ END_INTERFACE
+ } IWMDMProgressVtbl;
+
+ interface IWMDMProgress
+ {
+ CONST_VTBL struct IWMDMProgressVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMProgress_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMProgress_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMProgress_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMProgress_Begin(This,dwEstimatedTicks) \
+ ( (This)->lpVtbl -> Begin(This,dwEstimatedTicks) )
+
+#define IWMDMProgress_Progress(This,dwTranspiredTicks) \
+ ( (This)->lpVtbl -> Progress(This,dwTranspiredTicks) )
+
+#define IWMDMProgress_End(This) \
+ ( (This)->lpVtbl -> End(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMProgress_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMProgress2_INTERFACE_DEFINED__
+#define __IWMDMProgress2_INTERFACE_DEFINED__
+
+/* interface IWMDMProgress2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMProgress2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3A43F550-B383-4e92-B04A-E6BBC660FEFC")
+ IWMDMProgress2 : public IWMDMProgress
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE End2(
+ /* [in] */ HRESULT hrCompletionCode) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMProgress2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMProgress2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMProgress2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMProgress2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Begin )(
+ IWMDMProgress2 * This,
+ /* [in] */ DWORD dwEstimatedTicks);
+
+ HRESULT ( STDMETHODCALLTYPE *Progress )(
+ IWMDMProgress2 * This,
+ /* [in] */ DWORD dwTranspiredTicks);
+
+ HRESULT ( STDMETHODCALLTYPE *End )(
+ IWMDMProgress2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *End2 )(
+ IWMDMProgress2 * This,
+ /* [in] */ HRESULT hrCompletionCode);
+
+ END_INTERFACE
+ } IWMDMProgress2Vtbl;
+
+ interface IWMDMProgress2
+ {
+ CONST_VTBL struct IWMDMProgress2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMProgress2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMProgress2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMProgress2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMProgress2_Begin(This,dwEstimatedTicks) \
+ ( (This)->lpVtbl -> Begin(This,dwEstimatedTicks) )
+
+#define IWMDMProgress2_Progress(This,dwTranspiredTicks) \
+ ( (This)->lpVtbl -> Progress(This,dwTranspiredTicks) )
+
+#define IWMDMProgress2_End(This) \
+ ( (This)->lpVtbl -> End(This) )
+
+
+#define IWMDMProgress2_End2(This,hrCompletionCode) \
+ ( (This)->lpVtbl -> End2(This,hrCompletionCode) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMProgress2_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMProgress3_INTERFACE_DEFINED__
+#define __IWMDMProgress3_INTERFACE_DEFINED__
+
+/* interface IWMDMProgress3 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMProgress3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("21DE01CB-3BB4-4929-B21A-17AF3F80F658")
+ IWMDMProgress3 : public IWMDMProgress2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Begin3(
+ /* [in] */ GUID EventId,
+ /* [in] */ DWORD dwEstimatedTicks,
+ /* [unique][out][in] */ __RPC__inout_opt OPAQUECOMMAND *pContext) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Progress3(
+ /* [in] */ GUID EventId,
+ /* [in] */ DWORD dwTranspiredTicks,
+ /* [unique][out][in] */ __RPC__inout_opt OPAQUECOMMAND *pContext) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE End3(
+ /* [in] */ GUID EventId,
+ /* [in] */ HRESULT hrCompletionCode,
+ /* [unique][out][in] */ __RPC__inout_opt OPAQUECOMMAND *pContext) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMProgress3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMProgress3 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMProgress3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMProgress3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Begin )(
+ IWMDMProgress3 * This,
+ /* [in] */ DWORD dwEstimatedTicks);
+
+ HRESULT ( STDMETHODCALLTYPE *Progress )(
+ IWMDMProgress3 * This,
+ /* [in] */ DWORD dwTranspiredTicks);
+
+ HRESULT ( STDMETHODCALLTYPE *End )(
+ IWMDMProgress3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *End2 )(
+ IWMDMProgress3 * This,
+ /* [in] */ HRESULT hrCompletionCode);
+
+ HRESULT ( STDMETHODCALLTYPE *Begin3 )(
+ IWMDMProgress3 * This,
+ /* [in] */ GUID EventId,
+ /* [in] */ DWORD dwEstimatedTicks,
+ /* [unique][out][in] */ __RPC__inout_opt OPAQUECOMMAND *pContext);
+
+ HRESULT ( STDMETHODCALLTYPE *Progress3 )(
+ IWMDMProgress3 * This,
+ /* [in] */ GUID EventId,
+ /* [in] */ DWORD dwTranspiredTicks,
+ /* [unique][out][in] */ __RPC__inout_opt OPAQUECOMMAND *pContext);
+
+ HRESULT ( STDMETHODCALLTYPE *End3 )(
+ IWMDMProgress3 * This,
+ /* [in] */ GUID EventId,
+ /* [in] */ HRESULT hrCompletionCode,
+ /* [unique][out][in] */ __RPC__inout_opt OPAQUECOMMAND *pContext);
+
+ END_INTERFACE
+ } IWMDMProgress3Vtbl;
+
+ interface IWMDMProgress3
+ {
+ CONST_VTBL struct IWMDMProgress3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMProgress3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMProgress3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMProgress3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMProgress3_Begin(This,dwEstimatedTicks) \
+ ( (This)->lpVtbl -> Begin(This,dwEstimatedTicks) )
+
+#define IWMDMProgress3_Progress(This,dwTranspiredTicks) \
+ ( (This)->lpVtbl -> Progress(This,dwTranspiredTicks) )
+
+#define IWMDMProgress3_End(This) \
+ ( (This)->lpVtbl -> End(This) )
+
+
+#define IWMDMProgress3_End2(This,hrCompletionCode) \
+ ( (This)->lpVtbl -> End2(This,hrCompletionCode) )
+
+
+#define IWMDMProgress3_Begin3(This,EventId,dwEstimatedTicks,pContext) \
+ ( (This)->lpVtbl -> Begin3(This,EventId,dwEstimatedTicks,pContext) )
+
+#define IWMDMProgress3_Progress3(This,EventId,dwTranspiredTicks,pContext) \
+ ( (This)->lpVtbl -> Progress3(This,EventId,dwTranspiredTicks,pContext) )
+
+#define IWMDMProgress3_End3(This,EventId,hrCompletionCode,pContext) \
+ ( (This)->lpVtbl -> End3(This,EventId,hrCompletionCode,pContext) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMProgress3_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMDevice_INTERFACE_DEFINED__
+#define __IWMDMDevice_INTERFACE_DEFINED__
+
+/* interface IWMDMDevice */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMDevice;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A02-33ED-11d3-8470-00C04F79DBC0")
+ IWMDMDevice : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetManufacturer(
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVersion(
+ /* [out] */ __RPC__out DWORD *pdwVersion) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetType(
+ /* [out] */ __RPC__out DWORD *pdwType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSerialNumber(
+ /* [out] */ __RPC__out PWMDMID pSerialNumber,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPowerSource(
+ /* [out] */ __RPC__out DWORD *pdwPowerSource,
+ /* [out] */ __RPC__out DWORD *pdwPercentRemaining) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStatus(
+ /* [out] */ __RPC__out DWORD *pdwStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceIcon(
+ /* [out] */ __RPC__out ULONG *hIcon) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumStorage(
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumStorage **ppEnumStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFormatSupport(
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnFormatCount) _WAVEFORMATEX **ppFormatEx,
+ /* [out] */ __RPC__out UINT *pnFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnMimeTypeCount) LPWSTR **pppwszMimeType,
+ /* [out] */ __RPC__out UINT *pnMimeTypeCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SendOpaqueCommand(
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMDeviceVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMDevice * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMDevice * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMDevice * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IWMDMDevice * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManufacturer )(
+ IWMDMDevice * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVersion )(
+ IWMDMDevice * This,
+ /* [out] */ __RPC__out DWORD *pdwVersion);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ IWMDMDevice * This,
+ /* [out] */ __RPC__out DWORD *pdwType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSerialNumber )(
+ IWMDMDevice * This,
+ /* [out] */ __RPC__out PWMDMID pSerialNumber,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPowerSource )(
+ IWMDMDevice * This,
+ /* [out] */ __RPC__out DWORD *pdwPowerSource,
+ /* [out] */ __RPC__out DWORD *pdwPercentRemaining);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStatus )(
+ IWMDMDevice * This,
+ /* [out] */ __RPC__out DWORD *pdwStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceIcon )(
+ IWMDMDevice * This,
+ /* [out] */ __RPC__out ULONG *hIcon);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStorage )(
+ IWMDMDevice * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumStorage **ppEnumStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFormatSupport )(
+ IWMDMDevice * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnFormatCount) _WAVEFORMATEX **ppFormatEx,
+ /* [out] */ __RPC__out UINT *pnFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnMimeTypeCount) LPWSTR **pppwszMimeType,
+ /* [out] */ __RPC__out UINT *pnMimeTypeCount);
+
+ HRESULT ( STDMETHODCALLTYPE *SendOpaqueCommand )(
+ IWMDMDevice * This,
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand);
+
+ END_INTERFACE
+ } IWMDMDeviceVtbl;
+
+ interface IWMDMDevice
+ {
+ CONST_VTBL struct IWMDMDeviceVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMDevice_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMDevice_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMDevice_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMDevice_GetName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetName(This,pwszName,nMaxChars) )
+
+#define IWMDMDevice_GetManufacturer(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetManufacturer(This,pwszName,nMaxChars) )
+
+#define IWMDMDevice_GetVersion(This,pdwVersion) \
+ ( (This)->lpVtbl -> GetVersion(This,pdwVersion) )
+
+#define IWMDMDevice_GetType(This,pdwType) \
+ ( (This)->lpVtbl -> GetType(This,pdwType) )
+
+#define IWMDMDevice_GetSerialNumber(This,pSerialNumber,abMac) \
+ ( (This)->lpVtbl -> GetSerialNumber(This,pSerialNumber,abMac) )
+
+#define IWMDMDevice_GetPowerSource(This,pdwPowerSource,pdwPercentRemaining) \
+ ( (This)->lpVtbl -> GetPowerSource(This,pdwPowerSource,pdwPercentRemaining) )
+
+#define IWMDMDevice_GetStatus(This,pdwStatus) \
+ ( (This)->lpVtbl -> GetStatus(This,pdwStatus) )
+
+#define IWMDMDevice_GetDeviceIcon(This,hIcon) \
+ ( (This)->lpVtbl -> GetDeviceIcon(This,hIcon) )
+
+#define IWMDMDevice_EnumStorage(This,ppEnumStorage) \
+ ( (This)->lpVtbl -> EnumStorage(This,ppEnumStorage) )
+
+#define IWMDMDevice_GetFormatSupport(This,ppFormatEx,pnFormatCount,pppwszMimeType,pnMimeTypeCount) \
+ ( (This)->lpVtbl -> GetFormatSupport(This,ppFormatEx,pnFormatCount,pppwszMimeType,pnMimeTypeCount) )
+
+#define IWMDMDevice_SendOpaqueCommand(This,pCommand) \
+ ( (This)->lpVtbl -> SendOpaqueCommand(This,pCommand) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMDevice_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMDevice2_INTERFACE_DEFINED__
+#define __IWMDMDevice2_INTERFACE_DEFINED__
+
+/* interface IWMDMDevice2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMDevice2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("E34F3D37-9D67-4fc1-9252-62D28B2F8B55")
+ IWMDMDevice2 : public IWMDMDevice
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetStorage(
+ /* [string][in] */ __RPC__in LPCWSTR pszStorageName,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFormatSupport2(
+ /* [in] */ DWORD dwFlags,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnAudioFormatCount) _WAVEFORMATEX **ppAudioFormatEx,
+ /* [ref][out] */ __RPC__out UINT *pnAudioFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnVideoFormatCount) _VIDEOINFOHEADER **ppVideoFormatEx,
+ /* [ref][out] */ __RPC__out UINT *pnVideoFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnFileTypeCount) WMFILECAPABILITIES **ppFileType,
+ /* [ref][out] */ __RPC__out UINT *pnFileTypeCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSpecifyPropertyPages(
+ /* [ref][out] */ __RPC__deref_out_opt ISpecifyPropertyPages **ppSpecifyPropPages,
+ /* [size_is][size_is][ref][out] */ __RPC__deref_out_ecount_full_opt(*pcUnks) IUnknown ***pppUnknowns,
+ /* [ref][out] */ __RPC__out ULONG *pcUnks) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCanonicalName(
+ /* [size_is][out] */ __RPC__out_ecount_full(nMaxChars) LPWSTR pwszPnPName,
+ /* [in] */ UINT nMaxChars) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMDevice2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMDevice2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMDevice2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMDevice2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IWMDMDevice2 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManufacturer )(
+ IWMDMDevice2 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVersion )(
+ IWMDMDevice2 * This,
+ /* [out] */ __RPC__out DWORD *pdwVersion);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ IWMDMDevice2 * This,
+ /* [out] */ __RPC__out DWORD *pdwType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSerialNumber )(
+ IWMDMDevice2 * This,
+ /* [out] */ __RPC__out PWMDMID pSerialNumber,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPowerSource )(
+ IWMDMDevice2 * This,
+ /* [out] */ __RPC__out DWORD *pdwPowerSource,
+ /* [out] */ __RPC__out DWORD *pdwPercentRemaining);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStatus )(
+ IWMDMDevice2 * This,
+ /* [out] */ __RPC__out DWORD *pdwStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceIcon )(
+ IWMDMDevice2 * This,
+ /* [out] */ __RPC__out ULONG *hIcon);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStorage )(
+ IWMDMDevice2 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumStorage **ppEnumStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFormatSupport )(
+ IWMDMDevice2 * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnFormatCount) _WAVEFORMATEX **ppFormatEx,
+ /* [out] */ __RPC__out UINT *pnFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnMimeTypeCount) LPWSTR **pppwszMimeType,
+ /* [out] */ __RPC__out UINT *pnMimeTypeCount);
+
+ HRESULT ( STDMETHODCALLTYPE *SendOpaqueCommand )(
+ IWMDMDevice2 * This,
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorage )(
+ IWMDMDevice2 * This,
+ /* [string][in] */ __RPC__in LPCWSTR pszStorageName,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFormatSupport2 )(
+ IWMDMDevice2 * This,
+ /* [in] */ DWORD dwFlags,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnAudioFormatCount) _WAVEFORMATEX **ppAudioFormatEx,
+ /* [ref][out] */ __RPC__out UINT *pnAudioFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnVideoFormatCount) _VIDEOINFOHEADER **ppVideoFormatEx,
+ /* [ref][out] */ __RPC__out UINT *pnVideoFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnFileTypeCount) WMFILECAPABILITIES **ppFileType,
+ /* [ref][out] */ __RPC__out UINT *pnFileTypeCount);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSpecifyPropertyPages )(
+ IWMDMDevice2 * This,
+ /* [ref][out] */ __RPC__deref_out_opt ISpecifyPropertyPages **ppSpecifyPropPages,
+ /* [size_is][size_is][ref][out] */ __RPC__deref_out_ecount_full_opt(*pcUnks) IUnknown ***pppUnknowns,
+ /* [ref][out] */ __RPC__out ULONG *pcUnks);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCanonicalName )(
+ IWMDMDevice2 * This,
+ /* [size_is][out] */ __RPC__out_ecount_full(nMaxChars) LPWSTR pwszPnPName,
+ /* [in] */ UINT nMaxChars);
+
+ END_INTERFACE
+ } IWMDMDevice2Vtbl;
+
+ interface IWMDMDevice2
+ {
+ CONST_VTBL struct IWMDMDevice2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMDevice2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMDevice2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMDevice2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMDevice2_GetName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetName(This,pwszName,nMaxChars) )
+
+#define IWMDMDevice2_GetManufacturer(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetManufacturer(This,pwszName,nMaxChars) )
+
+#define IWMDMDevice2_GetVersion(This,pdwVersion) \
+ ( (This)->lpVtbl -> GetVersion(This,pdwVersion) )
+
+#define IWMDMDevice2_GetType(This,pdwType) \
+ ( (This)->lpVtbl -> GetType(This,pdwType) )
+
+#define IWMDMDevice2_GetSerialNumber(This,pSerialNumber,abMac) \
+ ( (This)->lpVtbl -> GetSerialNumber(This,pSerialNumber,abMac) )
+
+#define IWMDMDevice2_GetPowerSource(This,pdwPowerSource,pdwPercentRemaining) \
+ ( (This)->lpVtbl -> GetPowerSource(This,pdwPowerSource,pdwPercentRemaining) )
+
+#define IWMDMDevice2_GetStatus(This,pdwStatus) \
+ ( (This)->lpVtbl -> GetStatus(This,pdwStatus) )
+
+#define IWMDMDevice2_GetDeviceIcon(This,hIcon) \
+ ( (This)->lpVtbl -> GetDeviceIcon(This,hIcon) )
+
+#define IWMDMDevice2_EnumStorage(This,ppEnumStorage) \
+ ( (This)->lpVtbl -> EnumStorage(This,ppEnumStorage) )
+
+#define IWMDMDevice2_GetFormatSupport(This,ppFormatEx,pnFormatCount,pppwszMimeType,pnMimeTypeCount) \
+ ( (This)->lpVtbl -> GetFormatSupport(This,ppFormatEx,pnFormatCount,pppwszMimeType,pnMimeTypeCount) )
+
+#define IWMDMDevice2_SendOpaqueCommand(This,pCommand) \
+ ( (This)->lpVtbl -> SendOpaqueCommand(This,pCommand) )
+
+
+#define IWMDMDevice2_GetStorage(This,pszStorageName,ppStorage) \
+ ( (This)->lpVtbl -> GetStorage(This,pszStorageName,ppStorage) )
+
+#define IWMDMDevice2_GetFormatSupport2(This,dwFlags,ppAudioFormatEx,pnAudioFormatCount,ppVideoFormatEx,pnVideoFormatCount,ppFileType,pnFileTypeCount) \
+ ( (This)->lpVtbl -> GetFormatSupport2(This,dwFlags,ppAudioFormatEx,pnAudioFormatCount,ppVideoFormatEx,pnVideoFormatCount,ppFileType,pnFileTypeCount) )
+
+#define IWMDMDevice2_GetSpecifyPropertyPages(This,ppSpecifyPropPages,pppUnknowns,pcUnks) \
+ ( (This)->lpVtbl -> GetSpecifyPropertyPages(This,ppSpecifyPropPages,pppUnknowns,pcUnks) )
+
+#define IWMDMDevice2_GetCanonicalName(This,pwszPnPName,nMaxChars) \
+ ( (This)->lpVtbl -> GetCanonicalName(This,pwszPnPName,nMaxChars) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMDevice2_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMDevice3_INTERFACE_DEFINED__
+#define __IWMDMDevice3_INTERFACE_DEFINED__
+
+/* interface IWMDMDevice3 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMDevice3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("6c03e4fe-05db-4dda-9e3c-06233a6d5d65")
+ IWMDMDevice3 : public IWMDMDevice2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetProperty(
+ /* [in] */ __RPC__in LPCWSTR pwszPropName,
+ /* [out] */ __RPC__out PROPVARIANT *pValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetProperty(
+ /* [in] */ __RPC__in LPCWSTR pwszPropName,
+ /* [in] */ __RPC__in const PROPVARIANT *pValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFormatCapability(
+ /* [in] */ WMDM_FORMATCODE format,
+ /* [out] */ __RPC__out WMDM_FORMAT_CAPABILITY *pFormatSupport) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeviceIoControl(
+ /* [in] */ DWORD dwIoControlCode,
+ /* [size_is][in] */ __RPC__in_ecount_full(nInBufferSize) BYTE *lpInBuffer,
+ /* [in] */ DWORD nInBufferSize,
+ /* [size_is][out] */ __RPC__out_ecount_full(*pnOutBufferSize) BYTE *lpOutBuffer,
+ /* [out][in] */ __RPC__inout LPDWORD pnOutBufferSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindStorage(
+ /* [in] */ WMDM_FIND_SCOPE findScope,
+ /* [in] */ __RPC__in LPCWSTR pwszUniqueID,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppStorage) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMDevice3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMDevice3 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMDevice3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMDevice3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IWMDMDevice3 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManufacturer )(
+ IWMDMDevice3 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVersion )(
+ IWMDMDevice3 * This,
+ /* [out] */ __RPC__out DWORD *pdwVersion);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ IWMDMDevice3 * This,
+ /* [out] */ __RPC__out DWORD *pdwType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSerialNumber )(
+ IWMDMDevice3 * This,
+ /* [out] */ __RPC__out PWMDMID pSerialNumber,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPowerSource )(
+ IWMDMDevice3 * This,
+ /* [out] */ __RPC__out DWORD *pdwPowerSource,
+ /* [out] */ __RPC__out DWORD *pdwPercentRemaining);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStatus )(
+ IWMDMDevice3 * This,
+ /* [out] */ __RPC__out DWORD *pdwStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceIcon )(
+ IWMDMDevice3 * This,
+ /* [out] */ __RPC__out ULONG *hIcon);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStorage )(
+ IWMDMDevice3 * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumStorage **ppEnumStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFormatSupport )(
+ IWMDMDevice3 * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnFormatCount) _WAVEFORMATEX **ppFormatEx,
+ /* [out] */ __RPC__out UINT *pnFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnMimeTypeCount) LPWSTR **pppwszMimeType,
+ /* [out] */ __RPC__out UINT *pnMimeTypeCount);
+
+ HRESULT ( STDMETHODCALLTYPE *SendOpaqueCommand )(
+ IWMDMDevice3 * This,
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorage )(
+ IWMDMDevice3 * This,
+ /* [string][in] */ __RPC__in LPCWSTR pszStorageName,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFormatSupport2 )(
+ IWMDMDevice3 * This,
+ /* [in] */ DWORD dwFlags,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnAudioFormatCount) _WAVEFORMATEX **ppAudioFormatEx,
+ /* [ref][out] */ __RPC__out UINT *pnAudioFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnVideoFormatCount) _VIDEOINFOHEADER **ppVideoFormatEx,
+ /* [ref][out] */ __RPC__out UINT *pnVideoFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnFileTypeCount) WMFILECAPABILITIES **ppFileType,
+ /* [ref][out] */ __RPC__out UINT *pnFileTypeCount);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSpecifyPropertyPages )(
+ IWMDMDevice3 * This,
+ /* [ref][out] */ __RPC__deref_out_opt ISpecifyPropertyPages **ppSpecifyPropPages,
+ /* [size_is][size_is][ref][out] */ __RPC__deref_out_ecount_full_opt(*pcUnks) IUnknown ***pppUnknowns,
+ /* [ref][out] */ __RPC__out ULONG *pcUnks);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCanonicalName )(
+ IWMDMDevice3 * This,
+ /* [size_is][out] */ __RPC__out_ecount_full(nMaxChars) LPWSTR pwszPnPName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetProperty )(
+ IWMDMDevice3 * This,
+ /* [in] */ __RPC__in LPCWSTR pwszPropName,
+ /* [out] */ __RPC__out PROPVARIANT *pValue);
+
+ HRESULT ( STDMETHODCALLTYPE *SetProperty )(
+ IWMDMDevice3 * This,
+ /* [in] */ __RPC__in LPCWSTR pwszPropName,
+ /* [in] */ __RPC__in const PROPVARIANT *pValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFormatCapability )(
+ IWMDMDevice3 * This,
+ /* [in] */ WMDM_FORMATCODE format,
+ /* [out] */ __RPC__out WMDM_FORMAT_CAPABILITY *pFormatSupport);
+
+ HRESULT ( STDMETHODCALLTYPE *DeviceIoControl )(
+ IWMDMDevice3 * This,
+ /* [in] */ DWORD dwIoControlCode,
+ /* [size_is][in] */ __RPC__in_ecount_full(nInBufferSize) BYTE *lpInBuffer,
+ /* [in] */ DWORD nInBufferSize,
+ /* [size_is][out] */ __RPC__out_ecount_full(*pnOutBufferSize) BYTE *lpOutBuffer,
+ /* [out][in] */ __RPC__inout LPDWORD pnOutBufferSize);
+
+ HRESULT ( STDMETHODCALLTYPE *FindStorage )(
+ IWMDMDevice3 * This,
+ /* [in] */ WMDM_FIND_SCOPE findScope,
+ /* [in] */ __RPC__in LPCWSTR pwszUniqueID,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppStorage);
+
+ END_INTERFACE
+ } IWMDMDevice3Vtbl;
+
+ interface IWMDMDevice3
+ {
+ CONST_VTBL struct IWMDMDevice3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMDevice3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMDevice3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMDevice3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMDevice3_GetName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetName(This,pwszName,nMaxChars) )
+
+#define IWMDMDevice3_GetManufacturer(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetManufacturer(This,pwszName,nMaxChars) )
+
+#define IWMDMDevice3_GetVersion(This,pdwVersion) \
+ ( (This)->lpVtbl -> GetVersion(This,pdwVersion) )
+
+#define IWMDMDevice3_GetType(This,pdwType) \
+ ( (This)->lpVtbl -> GetType(This,pdwType) )
+
+#define IWMDMDevice3_GetSerialNumber(This,pSerialNumber,abMac) \
+ ( (This)->lpVtbl -> GetSerialNumber(This,pSerialNumber,abMac) )
+
+#define IWMDMDevice3_GetPowerSource(This,pdwPowerSource,pdwPercentRemaining) \
+ ( (This)->lpVtbl -> GetPowerSource(This,pdwPowerSource,pdwPercentRemaining) )
+
+#define IWMDMDevice3_GetStatus(This,pdwStatus) \
+ ( (This)->lpVtbl -> GetStatus(This,pdwStatus) )
+
+#define IWMDMDevice3_GetDeviceIcon(This,hIcon) \
+ ( (This)->lpVtbl -> GetDeviceIcon(This,hIcon) )
+
+#define IWMDMDevice3_EnumStorage(This,ppEnumStorage) \
+ ( (This)->lpVtbl -> EnumStorage(This,ppEnumStorage) )
+
+#define IWMDMDevice3_GetFormatSupport(This,ppFormatEx,pnFormatCount,pppwszMimeType,pnMimeTypeCount) \
+ ( (This)->lpVtbl -> GetFormatSupport(This,ppFormatEx,pnFormatCount,pppwszMimeType,pnMimeTypeCount) )
+
+#define IWMDMDevice3_SendOpaqueCommand(This,pCommand) \
+ ( (This)->lpVtbl -> SendOpaqueCommand(This,pCommand) )
+
+
+#define IWMDMDevice3_GetStorage(This,pszStorageName,ppStorage) \
+ ( (This)->lpVtbl -> GetStorage(This,pszStorageName,ppStorage) )
+
+#define IWMDMDevice3_GetFormatSupport2(This,dwFlags,ppAudioFormatEx,pnAudioFormatCount,ppVideoFormatEx,pnVideoFormatCount,ppFileType,pnFileTypeCount) \
+ ( (This)->lpVtbl -> GetFormatSupport2(This,dwFlags,ppAudioFormatEx,pnAudioFormatCount,ppVideoFormatEx,pnVideoFormatCount,ppFileType,pnFileTypeCount) )
+
+#define IWMDMDevice3_GetSpecifyPropertyPages(This,ppSpecifyPropPages,pppUnknowns,pcUnks) \
+ ( (This)->lpVtbl -> GetSpecifyPropertyPages(This,ppSpecifyPropPages,pppUnknowns,pcUnks) )
+
+#define IWMDMDevice3_GetCanonicalName(This,pwszPnPName,nMaxChars) \
+ ( (This)->lpVtbl -> GetCanonicalName(This,pwszPnPName,nMaxChars) )
+
+
+#define IWMDMDevice3_GetProperty(This,pwszPropName,pValue) \
+ ( (This)->lpVtbl -> GetProperty(This,pwszPropName,pValue) )
+
+#define IWMDMDevice3_SetProperty(This,pwszPropName,pValue) \
+ ( (This)->lpVtbl -> SetProperty(This,pwszPropName,pValue) )
+
+#define IWMDMDevice3_GetFormatCapability(This,format,pFormatSupport) \
+ ( (This)->lpVtbl -> GetFormatCapability(This,format,pFormatSupport) )
+
+#define IWMDMDevice3_DeviceIoControl(This,dwIoControlCode,lpInBuffer,nInBufferSize,lpOutBuffer,pnOutBufferSize) \
+ ( (This)->lpVtbl -> DeviceIoControl(This,dwIoControlCode,lpInBuffer,nInBufferSize,lpOutBuffer,pnOutBufferSize) )
+
+#define IWMDMDevice3_FindStorage(This,findScope,pwszUniqueID,ppStorage) \
+ ( (This)->lpVtbl -> FindStorage(This,findScope,pwszUniqueID,ppStorage) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMDevice3_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMDeviceSession_INTERFACE_DEFINED__
+#define __IWMDMDeviceSession_INTERFACE_DEFINED__
+
+/* interface IWMDMDeviceSession */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMDeviceSession;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("82af0a65-9d96-412c-83e5-3c43e4b06cc7")
+ IWMDMDeviceSession : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE BeginSession(
+ /* [in] */ WMDM_SESSION_TYPE type,
+ /* [unique][size_is][in] */ __RPC__in_ecount_full_opt(dwSizeCtx) BYTE *pCtx,
+ /* [in] */ DWORD dwSizeCtx) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndSession(
+ /* [in] */ WMDM_SESSION_TYPE type,
+ /* [unique][size_is][in] */ __RPC__in_ecount_full_opt(dwSizeCtx) BYTE *pCtx,
+ /* [in] */ DWORD dwSizeCtx) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMDeviceSessionVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMDeviceSession * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMDeviceSession * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMDeviceSession * This);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginSession )(
+ IWMDMDeviceSession * This,
+ /* [in] */ WMDM_SESSION_TYPE type,
+ /* [unique][size_is][in] */ __RPC__in_ecount_full_opt(dwSizeCtx) BYTE *pCtx,
+ /* [in] */ DWORD dwSizeCtx);
+
+ HRESULT ( STDMETHODCALLTYPE *EndSession )(
+ IWMDMDeviceSession * This,
+ /* [in] */ WMDM_SESSION_TYPE type,
+ /* [unique][size_is][in] */ __RPC__in_ecount_full_opt(dwSizeCtx) BYTE *pCtx,
+ /* [in] */ DWORD dwSizeCtx);
+
+ END_INTERFACE
+ } IWMDMDeviceSessionVtbl;
+
+ interface IWMDMDeviceSession
+ {
+ CONST_VTBL struct IWMDMDeviceSessionVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMDeviceSession_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMDeviceSession_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMDeviceSession_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMDeviceSession_BeginSession(This,type,pCtx,dwSizeCtx) \
+ ( (This)->lpVtbl -> BeginSession(This,type,pCtx,dwSizeCtx) )
+
+#define IWMDMDeviceSession_EndSession(This,type,pCtx,dwSizeCtx) \
+ ( (This)->lpVtbl -> EndSession(This,type,pCtx,dwSizeCtx) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMDeviceSession_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMEnumDevice_INTERFACE_DEFINED__
+#define __IWMDMEnumDevice_INTERFACE_DEFINED__
+
+/* interface IWMDMEnumDevice */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMEnumDevice;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A01-33ED-11d3-8470-00C04F79DBC0")
+ IWMDMEnumDevice : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(celt, *pceltFetched) IWMDMDevice **ppDevice,
+ /* [out] */ __RPC__out ULONG *pceltFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ ULONG celt,
+ /* [out] */ __RPC__out ULONG *pceltFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumDevice **ppEnumDevice) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMEnumDeviceVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMEnumDevice * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMEnumDevice * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMEnumDevice * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IWMDMEnumDevice * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(celt, *pceltFetched) IWMDMDevice **ppDevice,
+ /* [out] */ __RPC__out ULONG *pceltFetched);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ IWMDMEnumDevice * This,
+ /* [in] */ ULONG celt,
+ /* [out] */ __RPC__out ULONG *pceltFetched);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ IWMDMEnumDevice * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ IWMDMEnumDevice * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumDevice **ppEnumDevice);
+
+ END_INTERFACE
+ } IWMDMEnumDeviceVtbl;
+
+ interface IWMDMEnumDevice
+ {
+ CONST_VTBL struct IWMDMEnumDeviceVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMEnumDevice_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMEnumDevice_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMEnumDevice_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMEnumDevice_Next(This,celt,ppDevice,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,ppDevice,pceltFetched) )
+
+#define IWMDMEnumDevice_Skip(This,celt,pceltFetched) \
+ ( (This)->lpVtbl -> Skip(This,celt,pceltFetched) )
+
+#define IWMDMEnumDevice_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define IWMDMEnumDevice_Clone(This,ppEnumDevice) \
+ ( (This)->lpVtbl -> Clone(This,ppEnumDevice) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMEnumDevice_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMDeviceControl_INTERFACE_DEFINED__
+#define __IWMDMDeviceControl_INTERFACE_DEFINED__
+
+/* interface IWMDMDeviceControl */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMDeviceControl;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A04-33ED-11d3-8470-00C04F79DBC0")
+ IWMDMDeviceControl : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetStatus(
+ /* [out] */ __RPC__out DWORD *pdwStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCapabilities(
+ /* [out] */ __RPC__out DWORD *pdwCapabilitiesMask) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Play( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Record(
+ /* [in] */ __RPC__in _WAVEFORMATEX *pFormat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Pause( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Resume( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Stop( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Seek(
+ /* [in] */ UINT fuMode,
+ /* [in] */ int nOffset) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMDeviceControlVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMDeviceControl * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMDeviceControl * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMDeviceControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStatus )(
+ IWMDMDeviceControl * This,
+ /* [out] */ __RPC__out DWORD *pdwStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCapabilities )(
+ IWMDMDeviceControl * This,
+ /* [out] */ __RPC__out DWORD *pdwCapabilitiesMask);
+
+ HRESULT ( STDMETHODCALLTYPE *Play )(
+ IWMDMDeviceControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Record )(
+ IWMDMDeviceControl * This,
+ /* [in] */ __RPC__in _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *Pause )(
+ IWMDMDeviceControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Resume )(
+ IWMDMDeviceControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Stop )(
+ IWMDMDeviceControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Seek )(
+ IWMDMDeviceControl * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ int nOffset);
+
+ END_INTERFACE
+ } IWMDMDeviceControlVtbl;
+
+ interface IWMDMDeviceControl
+ {
+ CONST_VTBL struct IWMDMDeviceControlVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMDeviceControl_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMDeviceControl_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMDeviceControl_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMDeviceControl_GetStatus(This,pdwStatus) \
+ ( (This)->lpVtbl -> GetStatus(This,pdwStatus) )
+
+#define IWMDMDeviceControl_GetCapabilities(This,pdwCapabilitiesMask) \
+ ( (This)->lpVtbl -> GetCapabilities(This,pdwCapabilitiesMask) )
+
+#define IWMDMDeviceControl_Play(This) \
+ ( (This)->lpVtbl -> Play(This) )
+
+#define IWMDMDeviceControl_Record(This,pFormat) \
+ ( (This)->lpVtbl -> Record(This,pFormat) )
+
+#define IWMDMDeviceControl_Pause(This) \
+ ( (This)->lpVtbl -> Pause(This) )
+
+#define IWMDMDeviceControl_Resume(This) \
+ ( (This)->lpVtbl -> Resume(This) )
+
+#define IWMDMDeviceControl_Stop(This) \
+ ( (This)->lpVtbl -> Stop(This) )
+
+#define IWMDMDeviceControl_Seek(This,fuMode,nOffset) \
+ ( (This)->lpVtbl -> Seek(This,fuMode,nOffset) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMDeviceControl_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMEnumStorage_INTERFACE_DEFINED__
+#define __IWMDMEnumStorage_INTERFACE_DEFINED__
+
+/* interface IWMDMEnumStorage */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMEnumStorage;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A05-33ED-11d3-8470-00C04F79DBC0")
+ IWMDMEnumStorage : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(celt, *pceltFetched) IWMDMStorage **ppStorage,
+ /* [out] */ __RPC__out ULONG *pceltFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ ULONG celt,
+ /* [out] */ __RPC__out ULONG *pceltFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumStorage **ppEnumStorage) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMEnumStorageVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMEnumStorage * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMEnumStorage * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMEnumStorage * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IWMDMEnumStorage * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(celt, *pceltFetched) IWMDMStorage **ppStorage,
+ /* [out] */ __RPC__out ULONG *pceltFetched);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ IWMDMEnumStorage * This,
+ /* [in] */ ULONG celt,
+ /* [out] */ __RPC__out ULONG *pceltFetched);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ IWMDMEnumStorage * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ IWMDMEnumStorage * This,
+ /* [out] */ __RPC__deref_out_opt IWMDMEnumStorage **ppEnumStorage);
+
+ END_INTERFACE
+ } IWMDMEnumStorageVtbl;
+
+ interface IWMDMEnumStorage
+ {
+ CONST_VTBL struct IWMDMEnumStorageVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMEnumStorage_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMEnumStorage_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMEnumStorage_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMEnumStorage_Next(This,celt,ppStorage,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,ppStorage,pceltFetched) )
+
+#define IWMDMEnumStorage_Skip(This,celt,pceltFetched) \
+ ( (This)->lpVtbl -> Skip(This,celt,pceltFetched) )
+
+#define IWMDMEnumStorage_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define IWMDMEnumStorage_Clone(This,ppEnumStorage) \
+ ( (This)->lpVtbl -> Clone(This,ppEnumStorage) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMEnumStorage_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMStorageControl_INTERFACE_DEFINED__
+#define __IWMDMStorageControl_INTERFACE_DEFINED__
+
+/* interface IWMDMStorageControl */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMStorageControl;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A08-33ED-11d3-8470-00C04F79DBC0")
+ IWMDMStorageControl : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Insert(
+ /* [in] */ UINT fuMode,
+ /* [unique][in] */ __RPC__in_opt LPWSTR pwszFile,
+ /* [unique][in] */ __RPC__in_opt IWMDMOperation *pOperation,
+ /* [unique][in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppNewObject) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Delete(
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Rename(
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in LPWSTR pwszNewName,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Read(
+ /* [in] */ UINT fuMode,
+ /* [unique][in] */ __RPC__in_opt LPWSTR pwszFile,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [in] */ __RPC__in_opt IWMDMOperation *pOperation) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Move(
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMStorage *pTargetObject,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMStorageControlVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMStorageControl * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMStorageControl * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMStorageControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Insert )(
+ IWMDMStorageControl * This,
+ /* [in] */ UINT fuMode,
+ /* [unique][in] */ __RPC__in_opt LPWSTR pwszFile,
+ /* [unique][in] */ __RPC__in_opt IWMDMOperation *pOperation,
+ /* [unique][in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppNewObject);
+
+ HRESULT ( STDMETHODCALLTYPE *Delete )(
+ IWMDMStorageControl * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ HRESULT ( STDMETHODCALLTYPE *Rename )(
+ IWMDMStorageControl * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in LPWSTR pwszNewName,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ HRESULT ( STDMETHODCALLTYPE *Read )(
+ IWMDMStorageControl * This,
+ /* [in] */ UINT fuMode,
+ /* [unique][in] */ __RPC__in_opt LPWSTR pwszFile,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [in] */ __RPC__in_opt IWMDMOperation *pOperation);
+
+ HRESULT ( STDMETHODCALLTYPE *Move )(
+ IWMDMStorageControl * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMStorage *pTargetObject,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ END_INTERFACE
+ } IWMDMStorageControlVtbl;
+
+ interface IWMDMStorageControl
+ {
+ CONST_VTBL struct IWMDMStorageControlVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMStorageControl_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMStorageControl_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMStorageControl_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMStorageControl_Insert(This,fuMode,pwszFile,pOperation,pProgress,ppNewObject) \
+ ( (This)->lpVtbl -> Insert(This,fuMode,pwszFile,pOperation,pProgress,ppNewObject) )
+
+#define IWMDMStorageControl_Delete(This,fuMode,pProgress) \
+ ( (This)->lpVtbl -> Delete(This,fuMode,pProgress) )
+
+#define IWMDMStorageControl_Rename(This,fuMode,pwszNewName,pProgress) \
+ ( (This)->lpVtbl -> Rename(This,fuMode,pwszNewName,pProgress) )
+
+#define IWMDMStorageControl_Read(This,fuMode,pwszFile,pProgress,pOperation) \
+ ( (This)->lpVtbl -> Read(This,fuMode,pwszFile,pProgress,pOperation) )
+
+#define IWMDMStorageControl_Move(This,fuMode,pTargetObject,pProgress) \
+ ( (This)->lpVtbl -> Move(This,fuMode,pTargetObject,pProgress) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMStorageControl_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMStorageControl2_INTERFACE_DEFINED__
+#define __IWMDMStorageControl2_INTERFACE_DEFINED__
+
+/* interface IWMDMStorageControl2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMStorageControl2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("972C2E88-BD6C-4125-8E09-84F837E637B6")
+ IWMDMStorageControl2 : public IWMDMStorageControl
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Insert2(
+ /* [in] */ UINT fuMode,
+ /* [string][unique][in] */ __RPC__in_opt LPWSTR pwszFileSource,
+ /* [string][unique][in] */ __RPC__in_opt LPWSTR pwszFileDest,
+ /* [unique][in] */ __RPC__in_opt IWMDMOperation *pOperation,
+ /* [unique][in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [in] */ __RPC__in_opt IUnknown *pUnknown,
+ /* [unique][out][in] */ __RPC__deref_opt_inout_opt IWMDMStorage **ppNewObject) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMStorageControl2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMStorageControl2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMStorageControl2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMStorageControl2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Insert )(
+ IWMDMStorageControl2 * This,
+ /* [in] */ UINT fuMode,
+ /* [unique][in] */ __RPC__in_opt LPWSTR pwszFile,
+ /* [unique][in] */ __RPC__in_opt IWMDMOperation *pOperation,
+ /* [unique][in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppNewObject);
+
+ HRESULT ( STDMETHODCALLTYPE *Delete )(
+ IWMDMStorageControl2 * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ HRESULT ( STDMETHODCALLTYPE *Rename )(
+ IWMDMStorageControl2 * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in LPWSTR pwszNewName,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ HRESULT ( STDMETHODCALLTYPE *Read )(
+ IWMDMStorageControl2 * This,
+ /* [in] */ UINT fuMode,
+ /* [unique][in] */ __RPC__in_opt LPWSTR pwszFile,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [in] */ __RPC__in_opt IWMDMOperation *pOperation);
+
+ HRESULT ( STDMETHODCALLTYPE *Move )(
+ IWMDMStorageControl2 * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMStorage *pTargetObject,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ HRESULT ( STDMETHODCALLTYPE *Insert2 )(
+ IWMDMStorageControl2 * This,
+ /* [in] */ UINT fuMode,
+ /* [string][unique][in] */ __RPC__in_opt LPWSTR pwszFileSource,
+ /* [string][unique][in] */ __RPC__in_opt LPWSTR pwszFileDest,
+ /* [unique][in] */ __RPC__in_opt IWMDMOperation *pOperation,
+ /* [unique][in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [in] */ __RPC__in_opt IUnknown *pUnknown,
+ /* [unique][out][in] */ __RPC__deref_opt_inout_opt IWMDMStorage **ppNewObject);
+
+ END_INTERFACE
+ } IWMDMStorageControl2Vtbl;
+
+ interface IWMDMStorageControl2
+ {
+ CONST_VTBL struct IWMDMStorageControl2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMStorageControl2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMStorageControl2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMStorageControl2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMStorageControl2_Insert(This,fuMode,pwszFile,pOperation,pProgress,ppNewObject) \
+ ( (This)->lpVtbl -> Insert(This,fuMode,pwszFile,pOperation,pProgress,ppNewObject) )
+
+#define IWMDMStorageControl2_Delete(This,fuMode,pProgress) \
+ ( (This)->lpVtbl -> Delete(This,fuMode,pProgress) )
+
+#define IWMDMStorageControl2_Rename(This,fuMode,pwszNewName,pProgress) \
+ ( (This)->lpVtbl -> Rename(This,fuMode,pwszNewName,pProgress) )
+
+#define IWMDMStorageControl2_Read(This,fuMode,pwszFile,pProgress,pOperation) \
+ ( (This)->lpVtbl -> Read(This,fuMode,pwszFile,pProgress,pOperation) )
+
+#define IWMDMStorageControl2_Move(This,fuMode,pTargetObject,pProgress) \
+ ( (This)->lpVtbl -> Move(This,fuMode,pTargetObject,pProgress) )
+
+
+#define IWMDMStorageControl2_Insert2(This,fuMode,pwszFileSource,pwszFileDest,pOperation,pProgress,pUnknown,ppNewObject) \
+ ( (This)->lpVtbl -> Insert2(This,fuMode,pwszFileSource,pwszFileDest,pOperation,pProgress,pUnknown,ppNewObject) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMStorageControl2_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMStorageControl3_INTERFACE_DEFINED__
+#define __IWMDMStorageControl3_INTERFACE_DEFINED__
+
+/* interface IWMDMStorageControl3 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMStorageControl3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B3266365-D4F3-4696-8D53-BD27EC60993A")
+ IWMDMStorageControl3 : public IWMDMStorageControl2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Insert3(
+ /* [in] */ UINT fuMode,
+ /* [in] */ UINT fuType,
+ /* [string][unique][in] */ __RPC__in_opt LPWSTR pwszFileSource,
+ /* [string][unique][in] */ __RPC__in_opt LPWSTR pwszFileDest,
+ /* [unique][in] */ __RPC__in_opt IWMDMOperation *pOperation,
+ /* [unique][in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [unique][in] */ __RPC__in_opt IWMDMMetaData *pMetaData,
+ /* [in] */ __RPC__in_opt IUnknown *pUnknown,
+ /* [unique][out][in] */ __RPC__deref_opt_inout_opt IWMDMStorage **ppNewObject) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMStorageControl3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMStorageControl3 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMStorageControl3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMStorageControl3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Insert )(
+ IWMDMStorageControl3 * This,
+ /* [in] */ UINT fuMode,
+ /* [unique][in] */ __RPC__in_opt LPWSTR pwszFile,
+ /* [unique][in] */ __RPC__in_opt IWMDMOperation *pOperation,
+ /* [unique][in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [out] */ __RPC__deref_out_opt IWMDMStorage **ppNewObject);
+
+ HRESULT ( STDMETHODCALLTYPE *Delete )(
+ IWMDMStorageControl3 * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ HRESULT ( STDMETHODCALLTYPE *Rename )(
+ IWMDMStorageControl3 * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in LPWSTR pwszNewName,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ HRESULT ( STDMETHODCALLTYPE *Read )(
+ IWMDMStorageControl3 * This,
+ /* [in] */ UINT fuMode,
+ /* [unique][in] */ __RPC__in_opt LPWSTR pwszFile,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [in] */ __RPC__in_opt IWMDMOperation *pOperation);
+
+ HRESULT ( STDMETHODCALLTYPE *Move )(
+ IWMDMStorageControl3 * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMStorage *pTargetObject,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ HRESULT ( STDMETHODCALLTYPE *Insert2 )(
+ IWMDMStorageControl3 * This,
+ /* [in] */ UINT fuMode,
+ /* [string][unique][in] */ __RPC__in_opt LPWSTR pwszFileSource,
+ /* [string][unique][in] */ __RPC__in_opt LPWSTR pwszFileDest,
+ /* [unique][in] */ __RPC__in_opt IWMDMOperation *pOperation,
+ /* [unique][in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [in] */ __RPC__in_opt IUnknown *pUnknown,
+ /* [unique][out][in] */ __RPC__deref_opt_inout_opt IWMDMStorage **ppNewObject);
+
+ HRESULT ( STDMETHODCALLTYPE *Insert3 )(
+ IWMDMStorageControl3 * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ UINT fuType,
+ /* [string][unique][in] */ __RPC__in_opt LPWSTR pwszFileSource,
+ /* [string][unique][in] */ __RPC__in_opt LPWSTR pwszFileDest,
+ /* [unique][in] */ __RPC__in_opt IWMDMOperation *pOperation,
+ /* [unique][in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [unique][in] */ __RPC__in_opt IWMDMMetaData *pMetaData,
+ /* [in] */ __RPC__in_opt IUnknown *pUnknown,
+ /* [unique][out][in] */ __RPC__deref_opt_inout_opt IWMDMStorage **ppNewObject);
+
+ END_INTERFACE
+ } IWMDMStorageControl3Vtbl;
+
+ interface IWMDMStorageControl3
+ {
+ CONST_VTBL struct IWMDMStorageControl3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMStorageControl3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMStorageControl3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMStorageControl3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMStorageControl3_Insert(This,fuMode,pwszFile,pOperation,pProgress,ppNewObject) \
+ ( (This)->lpVtbl -> Insert(This,fuMode,pwszFile,pOperation,pProgress,ppNewObject) )
+
+#define IWMDMStorageControl3_Delete(This,fuMode,pProgress) \
+ ( (This)->lpVtbl -> Delete(This,fuMode,pProgress) )
+
+#define IWMDMStorageControl3_Rename(This,fuMode,pwszNewName,pProgress) \
+ ( (This)->lpVtbl -> Rename(This,fuMode,pwszNewName,pProgress) )
+
+#define IWMDMStorageControl3_Read(This,fuMode,pwszFile,pProgress,pOperation) \
+ ( (This)->lpVtbl -> Read(This,fuMode,pwszFile,pProgress,pOperation) )
+
+#define IWMDMStorageControl3_Move(This,fuMode,pTargetObject,pProgress) \
+ ( (This)->lpVtbl -> Move(This,fuMode,pTargetObject,pProgress) )
+
+
+#define IWMDMStorageControl3_Insert2(This,fuMode,pwszFileSource,pwszFileDest,pOperation,pProgress,pUnknown,ppNewObject) \
+ ( (This)->lpVtbl -> Insert2(This,fuMode,pwszFileSource,pwszFileDest,pOperation,pProgress,pUnknown,ppNewObject) )
+
+
+#define IWMDMStorageControl3_Insert3(This,fuMode,fuType,pwszFileSource,pwszFileDest,pOperation,pProgress,pMetaData,pUnknown,ppNewObject) \
+ ( (This)->lpVtbl -> Insert3(This,fuMode,fuType,pwszFileSource,pwszFileDest,pOperation,pProgress,pMetaData,pUnknown,ppNewObject) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMStorageControl3_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMObjectInfo_INTERFACE_DEFINED__
+#define __IWMDMObjectInfo_INTERFACE_DEFINED__
+
+/* interface IWMDMObjectInfo */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMObjectInfo;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A09-33ED-11d3-8470-00C04F79DBC0")
+ IWMDMObjectInfo : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetPlayLength(
+ /* [out] */ __RPC__out DWORD *pdwLength) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetPlayLength(
+ /* [in] */ DWORD dwLength) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPlayOffset(
+ /* [out] */ __RPC__out DWORD *pdwOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetPlayOffset(
+ /* [in] */ DWORD dwOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTotalLength(
+ /* [out] */ __RPC__out DWORD *pdwLength) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLastPlayPosition(
+ /* [out] */ __RPC__out DWORD *pdwLastPos) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLongestPlayPosition(
+ /* [out] */ __RPC__out DWORD *pdwLongestPos) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMObjectInfoVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMObjectInfo * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMObjectInfo * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMObjectInfo * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPlayLength )(
+ IWMDMObjectInfo * This,
+ /* [out] */ __RPC__out DWORD *pdwLength);
+
+ HRESULT ( STDMETHODCALLTYPE *SetPlayLength )(
+ IWMDMObjectInfo * This,
+ /* [in] */ DWORD dwLength);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPlayOffset )(
+ IWMDMObjectInfo * This,
+ /* [out] */ __RPC__out DWORD *pdwOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *SetPlayOffset )(
+ IWMDMObjectInfo * This,
+ /* [in] */ DWORD dwOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTotalLength )(
+ IWMDMObjectInfo * This,
+ /* [out] */ __RPC__out DWORD *pdwLength);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLastPlayPosition )(
+ IWMDMObjectInfo * This,
+ /* [out] */ __RPC__out DWORD *pdwLastPos);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLongestPlayPosition )(
+ IWMDMObjectInfo * This,
+ /* [out] */ __RPC__out DWORD *pdwLongestPos);
+
+ END_INTERFACE
+ } IWMDMObjectInfoVtbl;
+
+ interface IWMDMObjectInfo
+ {
+ CONST_VTBL struct IWMDMObjectInfoVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMObjectInfo_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMObjectInfo_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMObjectInfo_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMObjectInfo_GetPlayLength(This,pdwLength) \
+ ( (This)->lpVtbl -> GetPlayLength(This,pdwLength) )
+
+#define IWMDMObjectInfo_SetPlayLength(This,dwLength) \
+ ( (This)->lpVtbl -> SetPlayLength(This,dwLength) )
+
+#define IWMDMObjectInfo_GetPlayOffset(This,pdwOffset) \
+ ( (This)->lpVtbl -> GetPlayOffset(This,pdwOffset) )
+
+#define IWMDMObjectInfo_SetPlayOffset(This,dwOffset) \
+ ( (This)->lpVtbl -> SetPlayOffset(This,dwOffset) )
+
+#define IWMDMObjectInfo_GetTotalLength(This,pdwLength) \
+ ( (This)->lpVtbl -> GetTotalLength(This,pdwLength) )
+
+#define IWMDMObjectInfo_GetLastPlayPosition(This,pdwLastPos) \
+ ( (This)->lpVtbl -> GetLastPlayPosition(This,pdwLastPos) )
+
+#define IWMDMObjectInfo_GetLongestPlayPosition(This,pdwLongestPos) \
+ ( (This)->lpVtbl -> GetLongestPlayPosition(This,pdwLongestPos) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMObjectInfo_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMRevoked_INTERFACE_DEFINED__
+#define __IWMDMRevoked_INTERFACE_DEFINED__
+
+/* interface IWMDMRevoked */
+/* [ref][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMRevoked;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("EBECCEDB-88EE-4e55-B6A4-8D9F07D696AA")
+ IWMDMRevoked : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetRevocationURL(
+ /* [size_is][size_is][string][out][in] */ __RPC__deref_inout_ecount_full_opt_string(*pdwBufferLen) LPWSTR *ppwszRevocationURL,
+ /* [out][in] */ __RPC__inout DWORD *pdwBufferLen,
+ /* [out] */ __RPC__out DWORD *pdwRevokedBitFlag) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMRevokedVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMRevoked * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMRevoked * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMRevoked * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRevocationURL )(
+ IWMDMRevoked * This,
+ /* [size_is][size_is][string][out][in] */ __RPC__deref_inout_ecount_full_opt_string(*pdwBufferLen) LPWSTR *ppwszRevocationURL,
+ /* [out][in] */ __RPC__inout DWORD *pdwBufferLen,
+ /* [out] */ __RPC__out DWORD *pdwRevokedBitFlag);
+
+ END_INTERFACE
+ } IWMDMRevokedVtbl;
+
+ interface IWMDMRevoked
+ {
+ CONST_VTBL struct IWMDMRevokedVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMRevoked_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMRevoked_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMRevoked_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMRevoked_GetRevocationURL(This,ppwszRevocationURL,pdwBufferLen,pdwRevokedBitFlag) \
+ ( (This)->lpVtbl -> GetRevocationURL(This,ppwszRevocationURL,pdwBufferLen,pdwRevokedBitFlag) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMRevoked_INTERFACE_DEFINED__ */
+
+
+#ifndef __IWMDMNotification_INTERFACE_DEFINED__
+#define __IWMDMNotification_INTERFACE_DEFINED__
+
+/* interface IWMDMNotification */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IWMDMNotification;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3F5E95C0-0F43-4ed4-93D2-C89A45D59B81")
+ IWMDMNotification : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE WMDMMessage(
+ /* [in] */ DWORD dwMessageType,
+ /* [string][in] */ __RPC__in LPCWSTR pwszCanonicalName) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IWMDMNotificationVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IWMDMNotification * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IWMDMNotification * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IWMDMNotification * This);
+
+ HRESULT ( STDMETHODCALLTYPE *WMDMMessage )(
+ IWMDMNotification * This,
+ /* [in] */ DWORD dwMessageType,
+ /* [string][in] */ __RPC__in LPCWSTR pwszCanonicalName);
+
+ END_INTERFACE
+ } IWMDMNotificationVtbl;
+
+ interface IWMDMNotification
+ {
+ CONST_VTBL struct IWMDMNotificationVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IWMDMNotification_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IWMDMNotification_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IWMDMNotification_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IWMDMNotification_WMDMMessage(This,dwMessageType,pwszCanonicalName) \
+ ( (This)->lpVtbl -> WMDMMessage(This,dwMessageType,pwszCanonicalName) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IWMDMNotification_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mswmdm_0000_0028 */
+/* [local] */
+
+// WMDM constants for wellknown meta-data tags
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMFileName = L"WMDM/FileName";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMFormatCode = L"WMDM/FormatCode";
+//Type: WMDMDATETIME, WMDM_TAG_DATATYPE: WMDM_TYPE_DATETIME
+static const WCHAR *g_wszWMDMLastModifiedDate = L"WMDM/LastModifiedDate";
+//Type: WMDMDATETIME, WMDM_TAG_DATATYPE: WMDM_TYPE_DATETIME
+static const WCHAR *g_wszWMDMFileCreationDate = L"WMDM/FileCreationDate";
+//Type: QWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_QWORD
+static const WCHAR *g_wszWMDMFileSize = L"WMDM/FileSize";
+//Type: QWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_QWORD
+static const WCHAR *g_wszWMDMFileAttributes = L"WMDM/FileAttributes";
+//Format code: WAVE Format
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszAudioWAVECodec = L"WMDM/AudioWAVECodec";
+//Format code: FOURCC code
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszVideoFourCCCodec = L"WMDM/VideoFourCCCodec";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMTitle = L"WMDM/Title";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMAuthor = L"WMDM/Author";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMDescription = L"WMDM/Description";
+//Type: BOOL, WMDM_TAG_DATATYPE: WMDM_TYPE_BOOL
+static const WCHAR *g_wszWMDMIsProtected = L"WMDM/IsProtected";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMAlbumTitle = L"WMDM/AlbumTitle";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMAlbumArtist = L"WMDM/AlbumArtist";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMTrack = L"WMDM/Track";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMGenre = L"WMDM/Genre";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMTrackMood = L"WMDM/TrackMood";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMAlbumCoverFormat = L"WMDM/AlbumCoverFormat";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMAlbumCoverSize = L"WMDM/AlbumCoverSize";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMAlbumCoverHeight = L"WMDM/AlbumCoverHeight";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMAlbumCoverWidth = L"WMDM/AlbumCoverWidth";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMAlbumCoverDuration = L"WMDM/AlbumCoverDuration";
+//Type: BYTE*, WMDM_TAG_DATATYPE: WMDM_TYPE_BINARY
+static const WCHAR *g_wszWMDMAlbumCoverData = L"WMDM/AlbumCoverData";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMYear = L"WMDM/Year";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMComposer = L"WMDM/Composer";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMCodec = L"WMDM/Codec";
+static const WCHAR *g_wszWMDMDRMId = L"WMDM/DRMId";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMBitrate = L"WMDM/Bitrate";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMBitRateType = L"WMDM/BitRateType";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMSampleRate = L"WMDM/SampleRate";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMNumChannels = L"WMDM/NumChannels";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMBlockAlignment = L"WMDM/BlockAlignment";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMAudioBitDepth = L"WMDM/AudioBitDepth";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMTotalBitrate = L"WMDM/TotalBitrate";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMVideoBitrate = L"WMDM/VideoBitrate";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMFrameRate = L"WMDM/FrameRate";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMScanType = L"WMDM/ScanType";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMKeyFrameDistance = L"WMDM/KeyFrameDistance";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMBufferSize = L"WMDM/BufferSize";
+//Type: QWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_QWORD
+static const WCHAR *g_wszWMDMQualitySetting = L"WMDM/QualitySetting";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMEncodingProfile = L"WMDM/EncodingProfile";
+//Type: QWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_QWORD
+static const WCHAR *g_wszWMDMDuration = L"WMDM/Duration";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMAlbumArt = L"WMDM/AlbumArt";
+//Type: BOOL, WMDM_TAG_DATATYPE: WMDM_TYPE_BOOL
+static const WCHAR *g_wszWMDMBuyNow = L"WMDM/BuyNow";
+//Type: BOOL, WMDM_TAG_DATATYPE: WMDM_TYPE_BOOL
+static const WCHAR *g_wszWMDMNonConsumable = L"WMDM/NonConsumable";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMediaClassPrimaryID = L"WMDM/MediaClassPrimaryID";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMMediaClassSecondaryID = L"WMDM/MediaClassSecondaryID";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMUserEffectiveRating = L"WMDM/UserEffectiveRating";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMUserRating = L"WMDM/UserRating";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMUserRatingOnDevice = L"WMDM/UserRatingOnDevice";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMPlayCount = L"WMDM/PlayCount";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMDevicePlayCount = L"WMDM/DevicePlayCount";
+//Type: WMDMDATETIME, WMDM_TAG_DATATYPE: WMDM_TYPE_DATETIME
+static const WCHAR *g_wszWMDMAuthorDate = L"WMDM/AuthorDate";
+//Type: WMDMDATETIME, WMDM_TAG_DATATYPE: WMDM_TYPE_DATETIME
+static const WCHAR *g_wszWMDMUserLastPlayTime = L"WMDM/UserLastPlayTime";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMSubTitle = L"WMDM/SubTitle";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMSubTitleDescription = L"WMDM/SubTitleDescription";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMMediaCredits = L"WMDM/MediaCredits";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMMediaStationName = L"WMDM/MediaStationName";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMMediaOriginalChannel = L"WMDM/MediaOriginalChannel";
+//Type: WMDMDATETIME, WMDM_TAG_DATATYPE: WMDM_TYPE_DATETIME
+static const WCHAR *g_wszWMDMMediaOriginalBroadcastDateTime = L"WMDM/MediaOriginalBroadcastDateTime";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMProviderCopyright = L"WMDM/ProviderCopyright";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMSyncID = L"WMDM/SyncID";
+//Type: GUID, WMDM_TAG_DATATYPE: WMDM_TYPE_GUID
+static const WCHAR *g_wszWMDMPersistentUniqueID = L"WMDM/PersistentUniqueID";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMWidth = L"WMDM/Width";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMHeight = L"WMDM/Height";
+//Type: WMDMDATETIME, WMDM_TAG_DATATYPE: WMDM_TYPE_DATETIME
+static const WCHAR *g_wszWMDMSyncTime = L"WMDM/SyncTime";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMParentalRating = L"WMDM/ParentalRating";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMMetaGenre = L"WMDM/MetaGenre";
+//Type: BOOL, WMDM_TAG_DATATYPE: WMDM_TYPE_BOOL
+static const WCHAR *g_wszWMDMIsRepeat = L"WMDM/IsRepeat";
+// Device properties
+//PROPVARIANT vt = VT_BSTR | VT_ARRAY
+static const WCHAR *g_wszWMDMSupportedDeviceProperties = L"WMDM/SupportedDeviceProperties";
+//PROPVARIANT vt = VT_BSTR
+static const WCHAR *g_wszWMDMDeviceFriendlyName = L"WMDM/DeviceFriendlyName";
+//PROPVARIANT vt = VT_UI4 | VT_ARRAY
+static const WCHAR *g_wszWMDMFormatsSupported = L"WMDM/FormatsSupported";
+//PROPVARIANT vt = VT_BOOL
+static const WCHAR *g_wszWMDMFormatsSupportedAreOrdered = L"WMDM/FormatsSupportedAreOrdered";
+//PROPVARIANT vt = VT_BSTR
+static const WCHAR *g_wszWMDMSyncRelationshipID = L"WMDM/SyncRelationshipID";
+//PROPVARIANT vt = VT_BSTR
+static const WCHAR *g_wszWMDMDeviceModelName = L"WMDM/DeviceModelName";
+//PROPVARIANT vt = VT_BSTR
+static const WCHAR *g_wszWMDMDeviceFirmwareVersion = L"WMDM/DeviceFirmwareVersion";
+//PROPVARIANT vt = VT_BSTR
+static const WCHAR *g_wszWMDMDeviceVendorExtension = L"WMDM/DeviceVendorExtension";
+//PROPVARIANT vt = VT_CLSID
+static const WCHAR *g_wszWMDMDeviceProtocol = L"WMDM/DeviceProtocol";
+//PROPVARIANT vt = VT_CLSID
+static const WCHAR *g_wszWMDMDeviceServiceProviderVendor = L"WMDM/DeviceServiceProviderVendor";
+//PROPVARIANT vt = VT_BSTR
+static const WCHAR *g_wszWMDMDeviceRevocationInfo = L"WMDM/DeviceRevocationInfo";
+//PROPVARIANT vt = VT_BSTR
+static const WCHAR *g_wszWMDMCollectionID = L"WMDM/CollectionID";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMOwner = L"WMDM/Owner";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMEditor = L"WMDM/Editor";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMWebmaster = L"WMDM/Webmaster";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMSourceURL = L"WMDM/SourceURL";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMDestinationURL = L"WMDM/DestinationURL";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMCategory = L"WMDM/Category";
+//Type: QWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_QWORD
+static const WCHAR *g_wszWMDMTimeBookmark = L"WMDM/TimeBookmark";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMObjectBookmark = L"WMDM/ObjectBookmark";
+//Type: QWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_QWORD
+static const WCHAR *g_wszWMDMByteBookmark = L"WMDM/ByteBookmark";
+//Type: QWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_QWORD
+static const WCHAR *g_wszWMDMDataOffset = L"WMDM/DataOffset";
+//Type: QWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_QWORD
+static const WCHAR *g_wszWMDMDataLength = L"WMDM/DataLength";
+//Type: DWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_DWORD
+static const WCHAR *g_wszWMDMDataUnits = L"WMDM/DataUnits";
+//Type: QWORD, WMDM_TAG_DATATYPE: WMDM_TYPE_QWORD
+static const WCHAR *g_wszWMDMTimeToLive = L"WMDM/TimeToLive";
+//Type: LPCWSTR, WMDM_TAG_DATATYPE: WMDM_TYPE_STRING
+static const WCHAR *g_wszWMDMMediaGuid = L"WMDM/MediaGuid";
+//Type: BYTE*, WMDM_TAG_DATATYPE: WMDM_TYPE_BINARY
+static const WCHAR *g_wszWPDPassthroughPropertyValues = L"WPD/PassthroughPropertyValues";
+#define CCH_WMDM_PROPNAME(sz) (sizeof(sz)/sizeof(sz[0]))
+union WMDMDetermineMaxPropStringLen {
+WCHAR sz001[CCH_WMDM_PROPNAME(L"WMDM/DeviceFirmwareVersion")];
+WCHAR sz002[CCH_WMDM_PROPNAME(L"WMDM/SupportedDeviceProperties")];
+WCHAR sz003[CCH_WMDM_PROPNAME(L"WMDM/FileName")];
+WCHAR sz004[CCH_WMDM_PROPNAME(L"WMDM/FormatCode")];
+WCHAR sz005[CCH_WMDM_PROPNAME(L"WMDM/LastModifiedDate")];
+WCHAR sz006[CCH_WMDM_PROPNAME(L"WMDM/FileSize")];
+WCHAR sz007[CCH_WMDM_PROPNAME(L"WMDM/FileAttributes")];
+WCHAR sz008[CCH_WMDM_PROPNAME(L"WMDM/AudioWAVECodec")];
+WCHAR sz009[CCH_WMDM_PROPNAME(L"WMDM/VideoFourCCCodec")];
+WCHAR sz010[CCH_WMDM_PROPNAME(L"WMDM/Title")];
+WCHAR sz011[CCH_WMDM_PROPNAME(L"WMDM/Author")];
+WCHAR sz012[CCH_WMDM_PROPNAME(L"WMDM/Description")];
+WCHAR sz013[CCH_WMDM_PROPNAME(L"WMDM/IsProtected")];
+WCHAR sz014[CCH_WMDM_PROPNAME(L"WMDM/AlbumTitle")];
+WCHAR sz015[CCH_WMDM_PROPNAME(L"WMDM/AlbumArtist")];
+WCHAR sz016[CCH_WMDM_PROPNAME(L"WMDM/Track")];
+WCHAR sz017[CCH_WMDM_PROPNAME(L"WMDM/Genre")];
+WCHAR sz018[CCH_WMDM_PROPNAME(L"WMDM/TrackMood")];
+WCHAR sz019[CCH_WMDM_PROPNAME(L"WMDM/AlbumCoverFormat")];
+WCHAR sz020[CCH_WMDM_PROPNAME(L"WMDM/AlbumCoverSize")];
+WCHAR sz021[CCH_WMDM_PROPNAME(L"WMDM/AlbumCoverHeight")];
+WCHAR sz022[CCH_WMDM_PROPNAME(L"WMDM/AlbumCoverWidth")];
+WCHAR sz023[CCH_WMDM_PROPNAME(L"WMDM/AlbumCoverDuration")];
+WCHAR sz024[CCH_WMDM_PROPNAME(L"WMDM/AlbumCoverData")];
+WCHAR sz025[CCH_WMDM_PROPNAME(L"WMDM/Year")];
+WCHAR sz026[CCH_WMDM_PROPNAME(L"WMDM/Composer")];
+WCHAR sz027[CCH_WMDM_PROPNAME(L"WMDM/Codec")];
+WCHAR sz028[CCH_WMDM_PROPNAME(L"WMDM/DRMId")];
+WCHAR sz029[CCH_WMDM_PROPNAME(L"WMDM/Bitrate")];
+WCHAR sz030[CCH_WMDM_PROPNAME(L"WMDM/BitRateType")];
+WCHAR sz031[CCH_WMDM_PROPNAME(L"WMDM/SampleRate")];
+WCHAR sz032[CCH_WMDM_PROPNAME(L"WMDM/NumChannels")];
+WCHAR sz033[CCH_WMDM_PROPNAME(L"WMDM/BlockAlignment")];
+WCHAR sz034[CCH_WMDM_PROPNAME(L"WMDM/AudioBitDepth")];
+WCHAR sz035[CCH_WMDM_PROPNAME(L"WMDM/TotalBitrate")];
+WCHAR sz036[CCH_WMDM_PROPNAME(L"WMDM/VideoBitrate")];
+WCHAR sz037[CCH_WMDM_PROPNAME(L"WMDM/FrameRate")];
+WCHAR sz041[CCH_WMDM_PROPNAME(L"WMDM/ScanType")];
+WCHAR sz043[CCH_WMDM_PROPNAME(L"WMDM/KeyFrameDistance")];
+WCHAR sz044[CCH_WMDM_PROPNAME(L"WMDM/BufferSize")];
+WCHAR sz045[CCH_WMDM_PROPNAME(L"WMDM/QualitySetting")];
+WCHAR sz046[CCH_WMDM_PROPNAME(L"WMDM/Duration")];
+WCHAR sz047[CCH_WMDM_PROPNAME(L"WMDM/AlbumArt")];
+WCHAR sz048[CCH_WMDM_PROPNAME(L"WMDM/BuyNow")];
+WCHAR sz049[CCH_WMDM_PROPNAME(L"WMDM/MediaClassPrimaryID")];
+WCHAR sz050[CCH_WMDM_PROPNAME(L"WMDM/MediaClassSecondayID")];
+WCHAR sz051[CCH_WMDM_PROPNAME(L"WMDM/UserEffectiveRating")];
+WCHAR sz052[CCH_WMDM_PROPNAME(L"WMDM/UserRating")];
+WCHAR sz053[CCH_WMDM_PROPNAME(L"WMDM/UserRatingOnDevice")];
+WCHAR sz054[CCH_WMDM_PROPNAME(L"WMDM/PlayCount")];
+WCHAR sz055[CCH_WMDM_PROPNAME(L"WMDM/DevicePlayCount")];
+WCHAR sz056[CCH_WMDM_PROPNAME(L"WMDM/AuthorDate")];
+WCHAR sz057[CCH_WMDM_PROPNAME(L"WMDM/UserLastPlayTime")];
+WCHAR sz058[CCH_WMDM_PROPNAME(L"WMDM/SubTitle")];
+WCHAR sz059[CCH_WMDM_PROPNAME(L"WMDM/SubTitleDescription")];
+WCHAR sz060[CCH_WMDM_PROPNAME(L"WMDM/MediaCredits")];
+WCHAR sz061[CCH_WMDM_PROPNAME(L"WMDM/MediaStationName")];
+WCHAR sz062[CCH_WMDM_PROPNAME(L"WMDM/MediaOriginalChannel")];
+WCHAR sz063[CCH_WMDM_PROPNAME(L"WMDM/MediaOriginalBroadcastDateTime")];
+WCHAR sz064[CCH_WMDM_PROPNAME(L"WMDM/ProviderCopyright")];
+WCHAR sz065[CCH_WMDM_PROPNAME(L"WMDM/SyncID")];
+WCHAR sz066[CCH_WMDM_PROPNAME(L"WMDM/PersistentUniqueID")];
+WCHAR sz067[CCH_WMDM_PROPNAME(L"WMDM/Width")];
+WCHAR sz068[CCH_WMDM_PROPNAME(L"WMDM/Height")];
+WCHAR sz069[CCH_WMDM_PROPNAME(L"WMDM/SyncTime")];
+WCHAR sz070[CCH_WMDM_PROPNAME(L"WMDM/ParentalRating")];
+WCHAR sz071[CCH_WMDM_PROPNAME(L"WMDM/MetaGenre")];
+WCHAR sz072[CCH_WMDM_PROPNAME(L"WMDM/IsRepeat")];
+WCHAR sz073[CCH_WMDM_PROPNAME(L"WMDM/SupportedDeviceProperties")];
+WCHAR sz074[CCH_WMDM_PROPNAME(L"WMDM/DeviceFriendlyName")];
+WCHAR sz075[CCH_WMDM_PROPNAME(L"WMDM/FormatsSupported")];
+WCHAR sz076[CCH_WMDM_PROPNAME(L"WMDM/SyncRelationshipID")];
+WCHAR sz077[CCH_WMDM_PROPNAME(L"WMDM/DeviceModelName")];
+WCHAR sz078[CCH_WMDM_PROPNAME(L"WMDM/DeviceFirmwareVersion")];
+WCHAR sz079[CCH_WMDM_PROPNAME(L"WMDM/DeviceVendorExtension")];
+WCHAR sz080[CCH_WMDM_PROPNAME(L"WMDM/DeviceProtocol")];
+WCHAR sz081[CCH_WMDM_PROPNAME(L"WMDM/DeviceServiceProviderVendor")];
+WCHAR sz082[CCH_WMDM_PROPNAME(L"WMDM/EncodingProfile")];
+WCHAR sz083[CCH_WMDM_PROPNAME(L"WMDM/FormatsSupportedAreOrdered")];
+WCHAR sz084[CCH_WMDM_PROPNAME(L"WMDM/DeviceRevocationInfo")];
+WCHAR sz085[CCH_WMDM_PROPNAME(L"WMDM/CollectionID")];
+WCHAR sz086[CCH_WMDM_PROPNAME(L"WPD/PassthroughPropertyValues")];
+};
+#define WMDM_MAXLEN_PROPERTYNAME (sizeof(WMDMDetermineMaxPropStringLen)/sizeof(WCHAR))
+// Open Mode Flags
+#define MDSP_READ 0x00000001
+#define MDSP_WRITE 0x00000002
+// Seek Flags
+#define MDSP_SEEK_BOF 0x00000001
+#define MDSP_SEEK_CUR 0x00000002
+#define MDSP_SEEK_EOF 0x00000004
+
+
+
+
+
+
+
+
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mswmdm_0000_0028_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mswmdm_0000_0028_v0_0_s_ifspec;
+
+#ifndef __IMDServiceProvider_INTERFACE_DEFINED__
+#define __IMDServiceProvider_INTERFACE_DEFINED__
+
+/* interface IMDServiceProvider */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDServiceProvider;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A10-33ED-11d3-8470-00C04F79DBC0")
+ IMDServiceProvider : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceCount(
+ /* [out] */ __RPC__out DWORD *pdwCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumDevices(
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumDevice **ppEnumDevice) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDServiceProviderVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDServiceProvider * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDServiceProvider * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDServiceProvider * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceCount )(
+ IMDServiceProvider * This,
+ /* [out] */ __RPC__out DWORD *pdwCount);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumDevices )(
+ IMDServiceProvider * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumDevice **ppEnumDevice);
+
+ END_INTERFACE
+ } IMDServiceProviderVtbl;
+
+ interface IMDServiceProvider
+ {
+ CONST_VTBL struct IMDServiceProviderVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDServiceProvider_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDServiceProvider_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDServiceProvider_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDServiceProvider_GetDeviceCount(This,pdwCount) \
+ ( (This)->lpVtbl -> GetDeviceCount(This,pdwCount) )
+
+#define IMDServiceProvider_EnumDevices(This,ppEnumDevice) \
+ ( (This)->lpVtbl -> EnumDevices(This,ppEnumDevice) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDServiceProvider_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDServiceProvider2_INTERFACE_DEFINED__
+#define __IMDServiceProvider2_INTERFACE_DEFINED__
+
+/* interface IMDServiceProvider2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDServiceProvider2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B2FA24B7-CDA3-4694-9862-413AE1A34819")
+ IMDServiceProvider2 : public IMDServiceProvider
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CreateDevice(
+ /* [string][in] */ __RPC__in LPCWSTR pwszDevicePath,
+ /* [out] */ __RPC__out DWORD *pdwCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pdwCount) IMDSPDevice ***pppDeviceArray) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDServiceProvider2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDServiceProvider2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDServiceProvider2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDServiceProvider2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceCount )(
+ IMDServiceProvider2 * This,
+ /* [out] */ __RPC__out DWORD *pdwCount);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumDevices )(
+ IMDServiceProvider2 * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumDevice **ppEnumDevice);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateDevice )(
+ IMDServiceProvider2 * This,
+ /* [string][in] */ __RPC__in LPCWSTR pwszDevicePath,
+ /* [out] */ __RPC__out DWORD *pdwCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pdwCount) IMDSPDevice ***pppDeviceArray);
+
+ END_INTERFACE
+ } IMDServiceProvider2Vtbl;
+
+ interface IMDServiceProvider2
+ {
+ CONST_VTBL struct IMDServiceProvider2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDServiceProvider2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDServiceProvider2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDServiceProvider2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDServiceProvider2_GetDeviceCount(This,pdwCount) \
+ ( (This)->lpVtbl -> GetDeviceCount(This,pdwCount) )
+
+#define IMDServiceProvider2_EnumDevices(This,ppEnumDevice) \
+ ( (This)->lpVtbl -> EnumDevices(This,ppEnumDevice) )
+
+
+#define IMDServiceProvider2_CreateDevice(This,pwszDevicePath,pdwCount,pppDeviceArray) \
+ ( (This)->lpVtbl -> CreateDevice(This,pwszDevicePath,pdwCount,pppDeviceArray) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDServiceProvider2_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDServiceProvider3_INTERFACE_DEFINED__
+#define __IMDServiceProvider3_INTERFACE_DEFINED__
+
+/* interface IMDServiceProvider3 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDServiceProvider3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("4ed13ef3-a971-4d19-9f51-0e1826b2da57")
+ IMDServiceProvider3 : public IMDServiceProvider2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetDeviceEnumPreference(
+ /* [in] */ DWORD dwEnumPref) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDServiceProvider3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDServiceProvider3 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDServiceProvider3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDServiceProvider3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceCount )(
+ IMDServiceProvider3 * This,
+ /* [out] */ __RPC__out DWORD *pdwCount);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumDevices )(
+ IMDServiceProvider3 * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumDevice **ppEnumDevice);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateDevice )(
+ IMDServiceProvider3 * This,
+ /* [string][in] */ __RPC__in LPCWSTR pwszDevicePath,
+ /* [out] */ __RPC__out DWORD *pdwCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pdwCount) IMDSPDevice ***pppDeviceArray);
+
+ HRESULT ( STDMETHODCALLTYPE *SetDeviceEnumPreference )(
+ IMDServiceProvider3 * This,
+ /* [in] */ DWORD dwEnumPref);
+
+ END_INTERFACE
+ } IMDServiceProvider3Vtbl;
+
+ interface IMDServiceProvider3
+ {
+ CONST_VTBL struct IMDServiceProvider3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDServiceProvider3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDServiceProvider3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDServiceProvider3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDServiceProvider3_GetDeviceCount(This,pdwCount) \
+ ( (This)->lpVtbl -> GetDeviceCount(This,pdwCount) )
+
+#define IMDServiceProvider3_EnumDevices(This,ppEnumDevice) \
+ ( (This)->lpVtbl -> EnumDevices(This,ppEnumDevice) )
+
+
+#define IMDServiceProvider3_CreateDevice(This,pwszDevicePath,pdwCount,pppDeviceArray) \
+ ( (This)->lpVtbl -> CreateDevice(This,pwszDevicePath,pdwCount,pppDeviceArray) )
+
+
+#define IMDServiceProvider3_SetDeviceEnumPreference(This,dwEnumPref) \
+ ( (This)->lpVtbl -> SetDeviceEnumPreference(This,dwEnumPref) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDServiceProvider3_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPEnumDevice_INTERFACE_DEFINED__
+#define __IMDSPEnumDevice_INTERFACE_DEFINED__
+
+/* interface IMDSPEnumDevice */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPEnumDevice;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A11-33ED-11d3-8470-00C04F79DBC0")
+ IMDSPEnumDevice : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(celt, *pceltFetched) IMDSPDevice **ppDevice,
+ /* [out] */ __RPC__out ULONG *pceltFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ ULONG celt,
+ /* [out] */ __RPC__out ULONG *pceltFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumDevice **ppEnumDevice) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPEnumDeviceVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPEnumDevice * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPEnumDevice * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPEnumDevice * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IMDSPEnumDevice * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(celt, *pceltFetched) IMDSPDevice **ppDevice,
+ /* [out] */ __RPC__out ULONG *pceltFetched);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ IMDSPEnumDevice * This,
+ /* [in] */ ULONG celt,
+ /* [out] */ __RPC__out ULONG *pceltFetched);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ IMDSPEnumDevice * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ IMDSPEnumDevice * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumDevice **ppEnumDevice);
+
+ END_INTERFACE
+ } IMDSPEnumDeviceVtbl;
+
+ interface IMDSPEnumDevice
+ {
+ CONST_VTBL struct IMDSPEnumDeviceVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPEnumDevice_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPEnumDevice_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPEnumDevice_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPEnumDevice_Next(This,celt,ppDevice,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,ppDevice,pceltFetched) )
+
+#define IMDSPEnumDevice_Skip(This,celt,pceltFetched) \
+ ( (This)->lpVtbl -> Skip(This,celt,pceltFetched) )
+
+#define IMDSPEnumDevice_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define IMDSPEnumDevice_Clone(This,ppEnumDevice) \
+ ( (This)->lpVtbl -> Clone(This,ppEnumDevice) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPEnumDevice_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPDevice_INTERFACE_DEFINED__
+#define __IMDSPDevice_INTERFACE_DEFINED__
+
+/* interface IMDSPDevice */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPDevice;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A12-33ED-11d3-8470-00C04F79DBC0")
+ IMDSPDevice : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetManufacturer(
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVersion(
+ /* [out] */ __RPC__out DWORD *pdwVersion) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetType(
+ /* [out] */ __RPC__out DWORD *pdwType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSerialNumber(
+ /* [out] */ __RPC__out PWMDMID pSerialNumber,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPowerSource(
+ /* [out] */ __RPC__out DWORD *pdwPowerSource,
+ /* [out] */ __RPC__out DWORD *pdwPercentRemaining) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStatus(
+ /* [out] */ __RPC__out DWORD *pdwStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceIcon(
+ /* [out] */ __RPC__out ULONG *hIcon) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumStorage(
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumStorage **ppEnumStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFormatSupport(
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnFormatCount) _WAVEFORMATEX **pFormatEx,
+ /* [out] */ __RPC__out UINT *pnFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnMimeTypeCount) LPWSTR **pppwszMimeType,
+ /* [out] */ __RPC__out UINT *pnMimeTypeCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SendOpaqueCommand(
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPDeviceVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPDevice * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPDevice * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPDevice * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IMDSPDevice * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManufacturer )(
+ IMDSPDevice * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVersion )(
+ IMDSPDevice * This,
+ /* [out] */ __RPC__out DWORD *pdwVersion);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ IMDSPDevice * This,
+ /* [out] */ __RPC__out DWORD *pdwType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSerialNumber )(
+ IMDSPDevice * This,
+ /* [out] */ __RPC__out PWMDMID pSerialNumber,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPowerSource )(
+ IMDSPDevice * This,
+ /* [out] */ __RPC__out DWORD *pdwPowerSource,
+ /* [out] */ __RPC__out DWORD *pdwPercentRemaining);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStatus )(
+ IMDSPDevice * This,
+ /* [out] */ __RPC__out DWORD *pdwStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceIcon )(
+ IMDSPDevice * This,
+ /* [out] */ __RPC__out ULONG *hIcon);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStorage )(
+ IMDSPDevice * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumStorage **ppEnumStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFormatSupport )(
+ IMDSPDevice * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnFormatCount) _WAVEFORMATEX **pFormatEx,
+ /* [out] */ __RPC__out UINT *pnFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnMimeTypeCount) LPWSTR **pppwszMimeType,
+ /* [out] */ __RPC__out UINT *pnMimeTypeCount);
+
+ HRESULT ( STDMETHODCALLTYPE *SendOpaqueCommand )(
+ IMDSPDevice * This,
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand);
+
+ END_INTERFACE
+ } IMDSPDeviceVtbl;
+
+ interface IMDSPDevice
+ {
+ CONST_VTBL struct IMDSPDeviceVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPDevice_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPDevice_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPDevice_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPDevice_GetName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetName(This,pwszName,nMaxChars) )
+
+#define IMDSPDevice_GetManufacturer(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetManufacturer(This,pwszName,nMaxChars) )
+
+#define IMDSPDevice_GetVersion(This,pdwVersion) \
+ ( (This)->lpVtbl -> GetVersion(This,pdwVersion) )
+
+#define IMDSPDevice_GetType(This,pdwType) \
+ ( (This)->lpVtbl -> GetType(This,pdwType) )
+
+#define IMDSPDevice_GetSerialNumber(This,pSerialNumber,abMac) \
+ ( (This)->lpVtbl -> GetSerialNumber(This,pSerialNumber,abMac) )
+
+#define IMDSPDevice_GetPowerSource(This,pdwPowerSource,pdwPercentRemaining) \
+ ( (This)->lpVtbl -> GetPowerSource(This,pdwPowerSource,pdwPercentRemaining) )
+
+#define IMDSPDevice_GetStatus(This,pdwStatus) \
+ ( (This)->lpVtbl -> GetStatus(This,pdwStatus) )
+
+#define IMDSPDevice_GetDeviceIcon(This,hIcon) \
+ ( (This)->lpVtbl -> GetDeviceIcon(This,hIcon) )
+
+#define IMDSPDevice_EnumStorage(This,ppEnumStorage) \
+ ( (This)->lpVtbl -> EnumStorage(This,ppEnumStorage) )
+
+#define IMDSPDevice_GetFormatSupport(This,pFormatEx,pnFormatCount,pppwszMimeType,pnMimeTypeCount) \
+ ( (This)->lpVtbl -> GetFormatSupport(This,pFormatEx,pnFormatCount,pppwszMimeType,pnMimeTypeCount) )
+
+#define IMDSPDevice_SendOpaqueCommand(This,pCommand) \
+ ( (This)->lpVtbl -> SendOpaqueCommand(This,pCommand) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPDevice_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPDevice2_INTERFACE_DEFINED__
+#define __IMDSPDevice2_INTERFACE_DEFINED__
+
+/* interface IMDSPDevice2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPDevice2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("420D16AD-C97D-4e00-82AA-00E9F4335DDD")
+ IMDSPDevice2 : public IMDSPDevice
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetStorage(
+ /* [string][in] */ __RPC__in LPCWSTR pszStorageName,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFormatSupport2(
+ /* [in] */ DWORD dwFlags,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnAudioFormatCount) _WAVEFORMATEX **ppAudioFormatEx,
+ /* [ref][out] */ __RPC__out UINT *pnAudioFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnVideoFormatCount) _VIDEOINFOHEADER **ppVideoFormatEx,
+ /* [ref][out] */ __RPC__out UINT *pnVideoFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnFileTypeCount) WMFILECAPABILITIES **ppFileType,
+ /* [ref][out] */ __RPC__out UINT *pnFileTypeCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSpecifyPropertyPages(
+ /* [ref][out] */ __RPC__deref_out_opt ISpecifyPropertyPages **ppSpecifyPropPages,
+ /* [size_is][size_is][ref][out] */ __RPC__deref_out_ecount_full_opt(*pcUnks) IUnknown ***pppUnknowns,
+ /* [ref][out] */ __RPC__out ULONG *pcUnks) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCanonicalName(
+ /* [size_is][out] */ __RPC__out_ecount_full(nMaxChars) LPWSTR pwszPnPName,
+ /* [in] */ UINT nMaxChars) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPDevice2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPDevice2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPDevice2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPDevice2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IMDSPDevice2 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManufacturer )(
+ IMDSPDevice2 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVersion )(
+ IMDSPDevice2 * This,
+ /* [out] */ __RPC__out DWORD *pdwVersion);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ IMDSPDevice2 * This,
+ /* [out] */ __RPC__out DWORD *pdwType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSerialNumber )(
+ IMDSPDevice2 * This,
+ /* [out] */ __RPC__out PWMDMID pSerialNumber,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPowerSource )(
+ IMDSPDevice2 * This,
+ /* [out] */ __RPC__out DWORD *pdwPowerSource,
+ /* [out] */ __RPC__out DWORD *pdwPercentRemaining);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStatus )(
+ IMDSPDevice2 * This,
+ /* [out] */ __RPC__out DWORD *pdwStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceIcon )(
+ IMDSPDevice2 * This,
+ /* [out] */ __RPC__out ULONG *hIcon);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStorage )(
+ IMDSPDevice2 * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumStorage **ppEnumStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFormatSupport )(
+ IMDSPDevice2 * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnFormatCount) _WAVEFORMATEX **pFormatEx,
+ /* [out] */ __RPC__out UINT *pnFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnMimeTypeCount) LPWSTR **pppwszMimeType,
+ /* [out] */ __RPC__out UINT *pnMimeTypeCount);
+
+ HRESULT ( STDMETHODCALLTYPE *SendOpaqueCommand )(
+ IMDSPDevice2 * This,
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorage )(
+ IMDSPDevice2 * This,
+ /* [string][in] */ __RPC__in LPCWSTR pszStorageName,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFormatSupport2 )(
+ IMDSPDevice2 * This,
+ /* [in] */ DWORD dwFlags,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnAudioFormatCount) _WAVEFORMATEX **ppAudioFormatEx,
+ /* [ref][out] */ __RPC__out UINT *pnAudioFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnVideoFormatCount) _VIDEOINFOHEADER **ppVideoFormatEx,
+ /* [ref][out] */ __RPC__out UINT *pnVideoFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnFileTypeCount) WMFILECAPABILITIES **ppFileType,
+ /* [ref][out] */ __RPC__out UINT *pnFileTypeCount);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSpecifyPropertyPages )(
+ IMDSPDevice2 * This,
+ /* [ref][out] */ __RPC__deref_out_opt ISpecifyPropertyPages **ppSpecifyPropPages,
+ /* [size_is][size_is][ref][out] */ __RPC__deref_out_ecount_full_opt(*pcUnks) IUnknown ***pppUnknowns,
+ /* [ref][out] */ __RPC__out ULONG *pcUnks);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCanonicalName )(
+ IMDSPDevice2 * This,
+ /* [size_is][out] */ __RPC__out_ecount_full(nMaxChars) LPWSTR pwszPnPName,
+ /* [in] */ UINT nMaxChars);
+
+ END_INTERFACE
+ } IMDSPDevice2Vtbl;
+
+ interface IMDSPDevice2
+ {
+ CONST_VTBL struct IMDSPDevice2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPDevice2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPDevice2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPDevice2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPDevice2_GetName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetName(This,pwszName,nMaxChars) )
+
+#define IMDSPDevice2_GetManufacturer(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetManufacturer(This,pwszName,nMaxChars) )
+
+#define IMDSPDevice2_GetVersion(This,pdwVersion) \
+ ( (This)->lpVtbl -> GetVersion(This,pdwVersion) )
+
+#define IMDSPDevice2_GetType(This,pdwType) \
+ ( (This)->lpVtbl -> GetType(This,pdwType) )
+
+#define IMDSPDevice2_GetSerialNumber(This,pSerialNumber,abMac) \
+ ( (This)->lpVtbl -> GetSerialNumber(This,pSerialNumber,abMac) )
+
+#define IMDSPDevice2_GetPowerSource(This,pdwPowerSource,pdwPercentRemaining) \
+ ( (This)->lpVtbl -> GetPowerSource(This,pdwPowerSource,pdwPercentRemaining) )
+
+#define IMDSPDevice2_GetStatus(This,pdwStatus) \
+ ( (This)->lpVtbl -> GetStatus(This,pdwStatus) )
+
+#define IMDSPDevice2_GetDeviceIcon(This,hIcon) \
+ ( (This)->lpVtbl -> GetDeviceIcon(This,hIcon) )
+
+#define IMDSPDevice2_EnumStorage(This,ppEnumStorage) \
+ ( (This)->lpVtbl -> EnumStorage(This,ppEnumStorage) )
+
+#define IMDSPDevice2_GetFormatSupport(This,pFormatEx,pnFormatCount,pppwszMimeType,pnMimeTypeCount) \
+ ( (This)->lpVtbl -> GetFormatSupport(This,pFormatEx,pnFormatCount,pppwszMimeType,pnMimeTypeCount) )
+
+#define IMDSPDevice2_SendOpaqueCommand(This,pCommand) \
+ ( (This)->lpVtbl -> SendOpaqueCommand(This,pCommand) )
+
+
+#define IMDSPDevice2_GetStorage(This,pszStorageName,ppStorage) \
+ ( (This)->lpVtbl -> GetStorage(This,pszStorageName,ppStorage) )
+
+#define IMDSPDevice2_GetFormatSupport2(This,dwFlags,ppAudioFormatEx,pnAudioFormatCount,ppVideoFormatEx,pnVideoFormatCount,ppFileType,pnFileTypeCount) \
+ ( (This)->lpVtbl -> GetFormatSupport2(This,dwFlags,ppAudioFormatEx,pnAudioFormatCount,ppVideoFormatEx,pnVideoFormatCount,ppFileType,pnFileTypeCount) )
+
+#define IMDSPDevice2_GetSpecifyPropertyPages(This,ppSpecifyPropPages,pppUnknowns,pcUnks) \
+ ( (This)->lpVtbl -> GetSpecifyPropertyPages(This,ppSpecifyPropPages,pppUnknowns,pcUnks) )
+
+#define IMDSPDevice2_GetCanonicalName(This,pwszPnPName,nMaxChars) \
+ ( (This)->lpVtbl -> GetCanonicalName(This,pwszPnPName,nMaxChars) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPDevice2_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPDevice3_INTERFACE_DEFINED__
+#define __IMDSPDevice3_INTERFACE_DEFINED__
+
+/* interface IMDSPDevice3 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPDevice3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1a839845-fc55-487c-976f-ee38ac0e8c4e")
+ IMDSPDevice3 : public IMDSPDevice2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetProperty(
+ /* [in] */ __RPC__in LPCWSTR pwszPropName,
+ /* [out] */ __RPC__out PROPVARIANT *pValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetProperty(
+ /* [in] */ __RPC__in LPCWSTR pwszPropName,
+ /* [in] */ __RPC__in const PROPVARIANT *pValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFormatCapability(
+ /* [in] */ WMDM_FORMATCODE format,
+ /* [out] */ __RPC__out WMDM_FORMAT_CAPABILITY *pFormatSupport) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeviceIoControl(
+ /* [in] */ DWORD dwIoControlCode,
+ /* [size_is][in] */ __RPC__in_ecount_full(nInBufferSize) BYTE *lpInBuffer,
+ /* [in] */ DWORD nInBufferSize,
+ /* [size_is][out] */ __RPC__out_ecount_full(*pnOutBufferSize) BYTE *lpOutBuffer,
+ /* [out][in] */ __RPC__inout LPDWORD pnOutBufferSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindStorage(
+ /* [in] */ WMDM_FIND_SCOPE findScope,
+ /* [in] */ __RPC__in LPCWSTR pwszUniqueID,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppStorage) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPDevice3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPDevice3 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPDevice3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPDevice3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IMDSPDevice3 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManufacturer )(
+ IMDSPDevice3 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVersion )(
+ IMDSPDevice3 * This,
+ /* [out] */ __RPC__out DWORD *pdwVersion);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ IMDSPDevice3 * This,
+ /* [out] */ __RPC__out DWORD *pdwType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSerialNumber )(
+ IMDSPDevice3 * This,
+ /* [out] */ __RPC__out PWMDMID pSerialNumber,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPowerSource )(
+ IMDSPDevice3 * This,
+ /* [out] */ __RPC__out DWORD *pdwPowerSource,
+ /* [out] */ __RPC__out DWORD *pdwPercentRemaining);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStatus )(
+ IMDSPDevice3 * This,
+ /* [out] */ __RPC__out DWORD *pdwStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceIcon )(
+ IMDSPDevice3 * This,
+ /* [out] */ __RPC__out ULONG *hIcon);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStorage )(
+ IMDSPDevice3 * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumStorage **ppEnumStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFormatSupport )(
+ IMDSPDevice3 * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnFormatCount) _WAVEFORMATEX **pFormatEx,
+ /* [out] */ __RPC__out UINT *pnFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnMimeTypeCount) LPWSTR **pppwszMimeType,
+ /* [out] */ __RPC__out UINT *pnMimeTypeCount);
+
+ HRESULT ( STDMETHODCALLTYPE *SendOpaqueCommand )(
+ IMDSPDevice3 * This,
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorage )(
+ IMDSPDevice3 * This,
+ /* [string][in] */ __RPC__in LPCWSTR pszStorageName,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFormatSupport2 )(
+ IMDSPDevice3 * This,
+ /* [in] */ DWORD dwFlags,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnAudioFormatCount) _WAVEFORMATEX **ppAudioFormatEx,
+ /* [ref][out] */ __RPC__out UINT *pnAudioFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnVideoFormatCount) _VIDEOINFOHEADER **ppVideoFormatEx,
+ /* [ref][out] */ __RPC__out UINT *pnVideoFormatCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnFileTypeCount) WMFILECAPABILITIES **ppFileType,
+ /* [ref][out] */ __RPC__out UINT *pnFileTypeCount);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSpecifyPropertyPages )(
+ IMDSPDevice3 * This,
+ /* [ref][out] */ __RPC__deref_out_opt ISpecifyPropertyPages **ppSpecifyPropPages,
+ /* [size_is][size_is][ref][out] */ __RPC__deref_out_ecount_full_opt(*pcUnks) IUnknown ***pppUnknowns,
+ /* [ref][out] */ __RPC__out ULONG *pcUnks);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCanonicalName )(
+ IMDSPDevice3 * This,
+ /* [size_is][out] */ __RPC__out_ecount_full(nMaxChars) LPWSTR pwszPnPName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetProperty )(
+ IMDSPDevice3 * This,
+ /* [in] */ __RPC__in LPCWSTR pwszPropName,
+ /* [out] */ __RPC__out PROPVARIANT *pValue);
+
+ HRESULT ( STDMETHODCALLTYPE *SetProperty )(
+ IMDSPDevice3 * This,
+ /* [in] */ __RPC__in LPCWSTR pwszPropName,
+ /* [in] */ __RPC__in const PROPVARIANT *pValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFormatCapability )(
+ IMDSPDevice3 * This,
+ /* [in] */ WMDM_FORMATCODE format,
+ /* [out] */ __RPC__out WMDM_FORMAT_CAPABILITY *pFormatSupport);
+
+ HRESULT ( STDMETHODCALLTYPE *DeviceIoControl )(
+ IMDSPDevice3 * This,
+ /* [in] */ DWORD dwIoControlCode,
+ /* [size_is][in] */ __RPC__in_ecount_full(nInBufferSize) BYTE *lpInBuffer,
+ /* [in] */ DWORD nInBufferSize,
+ /* [size_is][out] */ __RPC__out_ecount_full(*pnOutBufferSize) BYTE *lpOutBuffer,
+ /* [out][in] */ __RPC__inout LPDWORD pnOutBufferSize);
+
+ HRESULT ( STDMETHODCALLTYPE *FindStorage )(
+ IMDSPDevice3 * This,
+ /* [in] */ WMDM_FIND_SCOPE findScope,
+ /* [in] */ __RPC__in LPCWSTR pwszUniqueID,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppStorage);
+
+ END_INTERFACE
+ } IMDSPDevice3Vtbl;
+
+ interface IMDSPDevice3
+ {
+ CONST_VTBL struct IMDSPDevice3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPDevice3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPDevice3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPDevice3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPDevice3_GetName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetName(This,pwszName,nMaxChars) )
+
+#define IMDSPDevice3_GetManufacturer(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetManufacturer(This,pwszName,nMaxChars) )
+
+#define IMDSPDevice3_GetVersion(This,pdwVersion) \
+ ( (This)->lpVtbl -> GetVersion(This,pdwVersion) )
+
+#define IMDSPDevice3_GetType(This,pdwType) \
+ ( (This)->lpVtbl -> GetType(This,pdwType) )
+
+#define IMDSPDevice3_GetSerialNumber(This,pSerialNumber,abMac) \
+ ( (This)->lpVtbl -> GetSerialNumber(This,pSerialNumber,abMac) )
+
+#define IMDSPDevice3_GetPowerSource(This,pdwPowerSource,pdwPercentRemaining) \
+ ( (This)->lpVtbl -> GetPowerSource(This,pdwPowerSource,pdwPercentRemaining) )
+
+#define IMDSPDevice3_GetStatus(This,pdwStatus) \
+ ( (This)->lpVtbl -> GetStatus(This,pdwStatus) )
+
+#define IMDSPDevice3_GetDeviceIcon(This,hIcon) \
+ ( (This)->lpVtbl -> GetDeviceIcon(This,hIcon) )
+
+#define IMDSPDevice3_EnumStorage(This,ppEnumStorage) \
+ ( (This)->lpVtbl -> EnumStorage(This,ppEnumStorage) )
+
+#define IMDSPDevice3_GetFormatSupport(This,pFormatEx,pnFormatCount,pppwszMimeType,pnMimeTypeCount) \
+ ( (This)->lpVtbl -> GetFormatSupport(This,pFormatEx,pnFormatCount,pppwszMimeType,pnMimeTypeCount) )
+
+#define IMDSPDevice3_SendOpaqueCommand(This,pCommand) \
+ ( (This)->lpVtbl -> SendOpaqueCommand(This,pCommand) )
+
+
+#define IMDSPDevice3_GetStorage(This,pszStorageName,ppStorage) \
+ ( (This)->lpVtbl -> GetStorage(This,pszStorageName,ppStorage) )
+
+#define IMDSPDevice3_GetFormatSupport2(This,dwFlags,ppAudioFormatEx,pnAudioFormatCount,ppVideoFormatEx,pnVideoFormatCount,ppFileType,pnFileTypeCount) \
+ ( (This)->lpVtbl -> GetFormatSupport2(This,dwFlags,ppAudioFormatEx,pnAudioFormatCount,ppVideoFormatEx,pnVideoFormatCount,ppFileType,pnFileTypeCount) )
+
+#define IMDSPDevice3_GetSpecifyPropertyPages(This,ppSpecifyPropPages,pppUnknowns,pcUnks) \
+ ( (This)->lpVtbl -> GetSpecifyPropertyPages(This,ppSpecifyPropPages,pppUnknowns,pcUnks) )
+
+#define IMDSPDevice3_GetCanonicalName(This,pwszPnPName,nMaxChars) \
+ ( (This)->lpVtbl -> GetCanonicalName(This,pwszPnPName,nMaxChars) )
+
+
+#define IMDSPDevice3_GetProperty(This,pwszPropName,pValue) \
+ ( (This)->lpVtbl -> GetProperty(This,pwszPropName,pValue) )
+
+#define IMDSPDevice3_SetProperty(This,pwszPropName,pValue) \
+ ( (This)->lpVtbl -> SetProperty(This,pwszPropName,pValue) )
+
+#define IMDSPDevice3_GetFormatCapability(This,format,pFormatSupport) \
+ ( (This)->lpVtbl -> GetFormatCapability(This,format,pFormatSupport) )
+
+#define IMDSPDevice3_DeviceIoControl(This,dwIoControlCode,lpInBuffer,nInBufferSize,lpOutBuffer,pnOutBufferSize) \
+ ( (This)->lpVtbl -> DeviceIoControl(This,dwIoControlCode,lpInBuffer,nInBufferSize,lpOutBuffer,pnOutBufferSize) )
+
+#define IMDSPDevice3_FindStorage(This,findScope,pwszUniqueID,ppStorage) \
+ ( (This)->lpVtbl -> FindStorage(This,findScope,pwszUniqueID,ppStorage) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPDevice3_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPDeviceControl_INTERFACE_DEFINED__
+#define __IMDSPDeviceControl_INTERFACE_DEFINED__
+
+/* interface IMDSPDeviceControl */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPDeviceControl;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A14-33ED-11d3-8470-00C04F79DBC0")
+ IMDSPDeviceControl : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetDCStatus(
+ /* [out] */ __RPC__out DWORD *pdwStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCapabilities(
+ /* [out] */ __RPC__out DWORD *pdwCapabilitiesMask) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Play( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Record(
+ /* [in] */ __RPC__in _WAVEFORMATEX *pFormat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Pause( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Resume( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Stop( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Seek(
+ /* [in] */ UINT fuMode,
+ /* [in] */ int nOffset) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPDeviceControlVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPDeviceControl * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPDeviceControl * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPDeviceControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDCStatus )(
+ IMDSPDeviceControl * This,
+ /* [out] */ __RPC__out DWORD *pdwStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCapabilities )(
+ IMDSPDeviceControl * This,
+ /* [out] */ __RPC__out DWORD *pdwCapabilitiesMask);
+
+ HRESULT ( STDMETHODCALLTYPE *Play )(
+ IMDSPDeviceControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Record )(
+ IMDSPDeviceControl * This,
+ /* [in] */ __RPC__in _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *Pause )(
+ IMDSPDeviceControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Resume )(
+ IMDSPDeviceControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Stop )(
+ IMDSPDeviceControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Seek )(
+ IMDSPDeviceControl * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ int nOffset);
+
+ END_INTERFACE
+ } IMDSPDeviceControlVtbl;
+
+ interface IMDSPDeviceControl
+ {
+ CONST_VTBL struct IMDSPDeviceControlVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPDeviceControl_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPDeviceControl_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPDeviceControl_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPDeviceControl_GetDCStatus(This,pdwStatus) \
+ ( (This)->lpVtbl -> GetDCStatus(This,pdwStatus) )
+
+#define IMDSPDeviceControl_GetCapabilities(This,pdwCapabilitiesMask) \
+ ( (This)->lpVtbl -> GetCapabilities(This,pdwCapabilitiesMask) )
+
+#define IMDSPDeviceControl_Play(This) \
+ ( (This)->lpVtbl -> Play(This) )
+
+#define IMDSPDeviceControl_Record(This,pFormat) \
+ ( (This)->lpVtbl -> Record(This,pFormat) )
+
+#define IMDSPDeviceControl_Pause(This) \
+ ( (This)->lpVtbl -> Pause(This) )
+
+#define IMDSPDeviceControl_Resume(This) \
+ ( (This)->lpVtbl -> Resume(This) )
+
+#define IMDSPDeviceControl_Stop(This) \
+ ( (This)->lpVtbl -> Stop(This) )
+
+#define IMDSPDeviceControl_Seek(This,fuMode,nOffset) \
+ ( (This)->lpVtbl -> Seek(This,fuMode,nOffset) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPDeviceControl_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPEnumStorage_INTERFACE_DEFINED__
+#define __IMDSPEnumStorage_INTERFACE_DEFINED__
+
+/* interface IMDSPEnumStorage */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPEnumStorage;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A15-33ED-11d3-8470-00C04F79DBC0")
+ IMDSPEnumStorage : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(celt, *pceltFetched) IMDSPStorage **ppStorage,
+ /* [out] */ __RPC__out ULONG *pceltFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ ULONG celt,
+ /* [out] */ __RPC__out ULONG *pceltFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumStorage **ppEnumStorage) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPEnumStorageVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPEnumStorage * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPEnumStorage * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPEnumStorage * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IMDSPEnumStorage * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(celt, *pceltFetched) IMDSPStorage **ppStorage,
+ /* [out] */ __RPC__out ULONG *pceltFetched);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ IMDSPEnumStorage * This,
+ /* [in] */ ULONG celt,
+ /* [out] */ __RPC__out ULONG *pceltFetched);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ IMDSPEnumStorage * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ IMDSPEnumStorage * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumStorage **ppEnumStorage);
+
+ END_INTERFACE
+ } IMDSPEnumStorageVtbl;
+
+ interface IMDSPEnumStorage
+ {
+ CONST_VTBL struct IMDSPEnumStorageVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPEnumStorage_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPEnumStorage_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPEnumStorage_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPEnumStorage_Next(This,celt,ppStorage,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,ppStorage,pceltFetched) )
+
+#define IMDSPEnumStorage_Skip(This,celt,pceltFetched) \
+ ( (This)->lpVtbl -> Skip(This,celt,pceltFetched) )
+
+#define IMDSPEnumStorage_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define IMDSPEnumStorage_Clone(This,ppEnumStorage) \
+ ( (This)->lpVtbl -> Clone(This,ppEnumStorage) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPEnumStorage_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPStorage_INTERFACE_DEFINED__
+#define __IMDSPStorage_INTERFACE_DEFINED__
+
+/* interface IMDSPStorage */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPStorage;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A16-33ED-11d3-8470-00C04F79DBC0")
+ IMDSPStorage : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetAttributes(
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStorageGlobals(
+ /* [out] */ __RPC__deref_out_opt IMDSPStorageGlobals **ppStorageGlobals) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAttributes(
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pFormat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDate(
+ /* [out] */ __RPC__out PWMDMDATETIME pDateTimeUTC) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSize(
+ /* [out] */ __RPC__out DWORD *pdwSizeLow,
+ /* [out] */ __RPC__out DWORD *pdwSizeHigh) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRights(
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateStorage(
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat,
+ /* [in] */ __RPC__in LPWSTR pwszName,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppNewStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumStorage(
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumStorage **ppEnumStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SendOpaqueCommand(
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPStorageVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPStorage * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPStorage * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPStorage * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAttributes )(
+ IMDSPStorage * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorageGlobals )(
+ IMDSPStorage * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorageGlobals **ppStorageGlobals);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes )(
+ IMDSPStorage * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IMDSPStorage * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDate )(
+ IMDSPStorage * This,
+ /* [out] */ __RPC__out PWMDMDATETIME pDateTimeUTC);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ IMDSPStorage * This,
+ /* [out] */ __RPC__out DWORD *pdwSizeLow,
+ /* [out] */ __RPC__out DWORD *pdwSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRights )(
+ IMDSPStorage * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStorage )(
+ IMDSPStorage * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat,
+ /* [in] */ __RPC__in LPWSTR pwszName,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppNewStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStorage )(
+ IMDSPStorage * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumStorage **ppEnumStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *SendOpaqueCommand )(
+ IMDSPStorage * This,
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand);
+
+ END_INTERFACE
+ } IMDSPStorageVtbl;
+
+ interface IMDSPStorage
+ {
+ CONST_VTBL struct IMDSPStorageVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPStorage_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPStorage_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPStorage_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPStorage_SetAttributes(This,dwAttributes,pFormat) \
+ ( (This)->lpVtbl -> SetAttributes(This,dwAttributes,pFormat) )
+
+#define IMDSPStorage_GetStorageGlobals(This,ppStorageGlobals) \
+ ( (This)->lpVtbl -> GetStorageGlobals(This,ppStorageGlobals) )
+
+#define IMDSPStorage_GetAttributes(This,pdwAttributes,pFormat) \
+ ( (This)->lpVtbl -> GetAttributes(This,pdwAttributes,pFormat) )
+
+#define IMDSPStorage_GetName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetName(This,pwszName,nMaxChars) )
+
+#define IMDSPStorage_GetDate(This,pDateTimeUTC) \
+ ( (This)->lpVtbl -> GetDate(This,pDateTimeUTC) )
+
+#define IMDSPStorage_GetSize(This,pdwSizeLow,pdwSizeHigh) \
+ ( (This)->lpVtbl -> GetSize(This,pdwSizeLow,pdwSizeHigh) )
+
+#define IMDSPStorage_GetRights(This,ppRights,pnRightsCount,abMac) \
+ ( (This)->lpVtbl -> GetRights(This,ppRights,pnRightsCount,abMac) )
+
+#define IMDSPStorage_CreateStorage(This,dwAttributes,pFormat,pwszName,ppNewStorage) \
+ ( (This)->lpVtbl -> CreateStorage(This,dwAttributes,pFormat,pwszName,ppNewStorage) )
+
+#define IMDSPStorage_EnumStorage(This,ppEnumStorage) \
+ ( (This)->lpVtbl -> EnumStorage(This,ppEnumStorage) )
+
+#define IMDSPStorage_SendOpaqueCommand(This,pCommand) \
+ ( (This)->lpVtbl -> SendOpaqueCommand(This,pCommand) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPStorage_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPStorage2_INTERFACE_DEFINED__
+#define __IMDSPStorage2_INTERFACE_DEFINED__
+
+/* interface IMDSPStorage2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPStorage2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("0A5E07A5-6454-4451-9C36-1C6AE7E2B1D6")
+ IMDSPStorage2 : public IMDSPStorage
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetStorage(
+ /* [string][in] */ __RPC__in LPCWSTR pszStorageName,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateStorage2(
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ DWORD dwAttributesEx,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][in] */ __RPC__in_opt _VIDEOINFOHEADER *pVideoFormat,
+ /* [in] */ __RPC__in LPWSTR pwszName,
+ /* [in] */ ULONGLONG qwFileSize,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppNewStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAttributes2(
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ DWORD dwAttributesEx,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][in] */ __RPC__in_opt _VIDEOINFOHEADER *pVideoFormat) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAttributes2(
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [out] */ __RPC__out DWORD *pdwAttributesEx,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][out][in] */ __RPC__inout_opt _VIDEOINFOHEADER *pVideoFormat) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPStorage2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPStorage2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPStorage2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPStorage2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAttributes )(
+ IMDSPStorage2 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorageGlobals )(
+ IMDSPStorage2 * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorageGlobals **ppStorageGlobals);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes )(
+ IMDSPStorage2 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IMDSPStorage2 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDate )(
+ IMDSPStorage2 * This,
+ /* [out] */ __RPC__out PWMDMDATETIME pDateTimeUTC);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ IMDSPStorage2 * This,
+ /* [out] */ __RPC__out DWORD *pdwSizeLow,
+ /* [out] */ __RPC__out DWORD *pdwSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRights )(
+ IMDSPStorage2 * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStorage )(
+ IMDSPStorage2 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat,
+ /* [in] */ __RPC__in LPWSTR pwszName,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppNewStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStorage )(
+ IMDSPStorage2 * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumStorage **ppEnumStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *SendOpaqueCommand )(
+ IMDSPStorage2 * This,
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorage )(
+ IMDSPStorage2 * This,
+ /* [string][in] */ __RPC__in LPCWSTR pszStorageName,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStorage2 )(
+ IMDSPStorage2 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ DWORD dwAttributesEx,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][in] */ __RPC__in_opt _VIDEOINFOHEADER *pVideoFormat,
+ /* [in] */ __RPC__in LPWSTR pwszName,
+ /* [in] */ ULONGLONG qwFileSize,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppNewStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAttributes2 )(
+ IMDSPStorage2 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ DWORD dwAttributesEx,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][in] */ __RPC__in_opt _VIDEOINFOHEADER *pVideoFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes2 )(
+ IMDSPStorage2 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [out] */ __RPC__out DWORD *pdwAttributesEx,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][out][in] */ __RPC__inout_opt _VIDEOINFOHEADER *pVideoFormat);
+
+ END_INTERFACE
+ } IMDSPStorage2Vtbl;
+
+ interface IMDSPStorage2
+ {
+ CONST_VTBL struct IMDSPStorage2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPStorage2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPStorage2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPStorage2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPStorage2_SetAttributes(This,dwAttributes,pFormat) \
+ ( (This)->lpVtbl -> SetAttributes(This,dwAttributes,pFormat) )
+
+#define IMDSPStorage2_GetStorageGlobals(This,ppStorageGlobals) \
+ ( (This)->lpVtbl -> GetStorageGlobals(This,ppStorageGlobals) )
+
+#define IMDSPStorage2_GetAttributes(This,pdwAttributes,pFormat) \
+ ( (This)->lpVtbl -> GetAttributes(This,pdwAttributes,pFormat) )
+
+#define IMDSPStorage2_GetName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetName(This,pwszName,nMaxChars) )
+
+#define IMDSPStorage2_GetDate(This,pDateTimeUTC) \
+ ( (This)->lpVtbl -> GetDate(This,pDateTimeUTC) )
+
+#define IMDSPStorage2_GetSize(This,pdwSizeLow,pdwSizeHigh) \
+ ( (This)->lpVtbl -> GetSize(This,pdwSizeLow,pdwSizeHigh) )
+
+#define IMDSPStorage2_GetRights(This,ppRights,pnRightsCount,abMac) \
+ ( (This)->lpVtbl -> GetRights(This,ppRights,pnRightsCount,abMac) )
+
+#define IMDSPStorage2_CreateStorage(This,dwAttributes,pFormat,pwszName,ppNewStorage) \
+ ( (This)->lpVtbl -> CreateStorage(This,dwAttributes,pFormat,pwszName,ppNewStorage) )
+
+#define IMDSPStorage2_EnumStorage(This,ppEnumStorage) \
+ ( (This)->lpVtbl -> EnumStorage(This,ppEnumStorage) )
+
+#define IMDSPStorage2_SendOpaqueCommand(This,pCommand) \
+ ( (This)->lpVtbl -> SendOpaqueCommand(This,pCommand) )
+
+
+#define IMDSPStorage2_GetStorage(This,pszStorageName,ppStorage) \
+ ( (This)->lpVtbl -> GetStorage(This,pszStorageName,ppStorage) )
+
+#define IMDSPStorage2_CreateStorage2(This,dwAttributes,dwAttributesEx,pAudioFormat,pVideoFormat,pwszName,qwFileSize,ppNewStorage) \
+ ( (This)->lpVtbl -> CreateStorage2(This,dwAttributes,dwAttributesEx,pAudioFormat,pVideoFormat,pwszName,qwFileSize,ppNewStorage) )
+
+#define IMDSPStorage2_SetAttributes2(This,dwAttributes,dwAttributesEx,pAudioFormat,pVideoFormat) \
+ ( (This)->lpVtbl -> SetAttributes2(This,dwAttributes,dwAttributesEx,pAudioFormat,pVideoFormat) )
+
+#define IMDSPStorage2_GetAttributes2(This,pdwAttributes,pdwAttributesEx,pAudioFormat,pVideoFormat) \
+ ( (This)->lpVtbl -> GetAttributes2(This,pdwAttributes,pdwAttributesEx,pAudioFormat,pVideoFormat) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPStorage2_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPStorage3_INTERFACE_DEFINED__
+#define __IMDSPStorage3_INTERFACE_DEFINED__
+
+/* interface IMDSPStorage3 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPStorage3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("6C669867-97ED-4a67-9706-1C5529D2A414")
+ IMDSPStorage3 : public IMDSPStorage2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetMetadata(
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pMetadata) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetMetadata(
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pMetadata) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPStorage3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPStorage3 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPStorage3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPStorage3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAttributes )(
+ IMDSPStorage3 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorageGlobals )(
+ IMDSPStorage3 * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorageGlobals **ppStorageGlobals);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes )(
+ IMDSPStorage3 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IMDSPStorage3 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDate )(
+ IMDSPStorage3 * This,
+ /* [out] */ __RPC__out PWMDMDATETIME pDateTimeUTC);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ IMDSPStorage3 * This,
+ /* [out] */ __RPC__out DWORD *pdwSizeLow,
+ /* [out] */ __RPC__out DWORD *pdwSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRights )(
+ IMDSPStorage3 * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStorage )(
+ IMDSPStorage3 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat,
+ /* [in] */ __RPC__in LPWSTR pwszName,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppNewStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStorage )(
+ IMDSPStorage3 * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumStorage **ppEnumStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *SendOpaqueCommand )(
+ IMDSPStorage3 * This,
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorage )(
+ IMDSPStorage3 * This,
+ /* [string][in] */ __RPC__in LPCWSTR pszStorageName,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStorage2 )(
+ IMDSPStorage3 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ DWORD dwAttributesEx,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][in] */ __RPC__in_opt _VIDEOINFOHEADER *pVideoFormat,
+ /* [in] */ __RPC__in LPWSTR pwszName,
+ /* [in] */ ULONGLONG qwFileSize,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppNewStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAttributes2 )(
+ IMDSPStorage3 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ DWORD dwAttributesEx,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][in] */ __RPC__in_opt _VIDEOINFOHEADER *pVideoFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes2 )(
+ IMDSPStorage3 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [out] */ __RPC__out DWORD *pdwAttributesEx,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][out][in] */ __RPC__inout_opt _VIDEOINFOHEADER *pVideoFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMetadata )(
+ IMDSPStorage3 * This,
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pMetadata);
+
+ HRESULT ( STDMETHODCALLTYPE *SetMetadata )(
+ IMDSPStorage3 * This,
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pMetadata);
+
+ END_INTERFACE
+ } IMDSPStorage3Vtbl;
+
+ interface IMDSPStorage3
+ {
+ CONST_VTBL struct IMDSPStorage3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPStorage3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPStorage3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPStorage3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPStorage3_SetAttributes(This,dwAttributes,pFormat) \
+ ( (This)->lpVtbl -> SetAttributes(This,dwAttributes,pFormat) )
+
+#define IMDSPStorage3_GetStorageGlobals(This,ppStorageGlobals) \
+ ( (This)->lpVtbl -> GetStorageGlobals(This,ppStorageGlobals) )
+
+#define IMDSPStorage3_GetAttributes(This,pdwAttributes,pFormat) \
+ ( (This)->lpVtbl -> GetAttributes(This,pdwAttributes,pFormat) )
+
+#define IMDSPStorage3_GetName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetName(This,pwszName,nMaxChars) )
+
+#define IMDSPStorage3_GetDate(This,pDateTimeUTC) \
+ ( (This)->lpVtbl -> GetDate(This,pDateTimeUTC) )
+
+#define IMDSPStorage3_GetSize(This,pdwSizeLow,pdwSizeHigh) \
+ ( (This)->lpVtbl -> GetSize(This,pdwSizeLow,pdwSizeHigh) )
+
+#define IMDSPStorage3_GetRights(This,ppRights,pnRightsCount,abMac) \
+ ( (This)->lpVtbl -> GetRights(This,ppRights,pnRightsCount,abMac) )
+
+#define IMDSPStorage3_CreateStorage(This,dwAttributes,pFormat,pwszName,ppNewStorage) \
+ ( (This)->lpVtbl -> CreateStorage(This,dwAttributes,pFormat,pwszName,ppNewStorage) )
+
+#define IMDSPStorage3_EnumStorage(This,ppEnumStorage) \
+ ( (This)->lpVtbl -> EnumStorage(This,ppEnumStorage) )
+
+#define IMDSPStorage3_SendOpaqueCommand(This,pCommand) \
+ ( (This)->lpVtbl -> SendOpaqueCommand(This,pCommand) )
+
+
+#define IMDSPStorage3_GetStorage(This,pszStorageName,ppStorage) \
+ ( (This)->lpVtbl -> GetStorage(This,pszStorageName,ppStorage) )
+
+#define IMDSPStorage3_CreateStorage2(This,dwAttributes,dwAttributesEx,pAudioFormat,pVideoFormat,pwszName,qwFileSize,ppNewStorage) \
+ ( (This)->lpVtbl -> CreateStorage2(This,dwAttributes,dwAttributesEx,pAudioFormat,pVideoFormat,pwszName,qwFileSize,ppNewStorage) )
+
+#define IMDSPStorage3_SetAttributes2(This,dwAttributes,dwAttributesEx,pAudioFormat,pVideoFormat) \
+ ( (This)->lpVtbl -> SetAttributes2(This,dwAttributes,dwAttributesEx,pAudioFormat,pVideoFormat) )
+
+#define IMDSPStorage3_GetAttributes2(This,pdwAttributes,pdwAttributesEx,pAudioFormat,pVideoFormat) \
+ ( (This)->lpVtbl -> GetAttributes2(This,pdwAttributes,pdwAttributesEx,pAudioFormat,pVideoFormat) )
+
+
+#define IMDSPStorage3_GetMetadata(This,pMetadata) \
+ ( (This)->lpVtbl -> GetMetadata(This,pMetadata) )
+
+#define IMDSPStorage3_SetMetadata(This,pMetadata) \
+ ( (This)->lpVtbl -> SetMetadata(This,pMetadata) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPStorage3_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPStorage4_INTERFACE_DEFINED__
+#define __IMDSPStorage4_INTERFACE_DEFINED__
+
+/* interface IMDSPStorage4 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPStorage4;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3133b2c4-515c-481b-b1ce-39327ecb4f74")
+ IMDSPStorage4 : public IMDSPStorage3
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetReferences(
+ /* [in] */ DWORD dwRefs,
+ /* [size_is][unique][in] */ __RPC__in_ecount_full_opt(dwRefs) IMDSPStorage **ppISPStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetReferences(
+ /* [out] */ __RPC__out DWORD *pdwRefs,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pdwRefs) IMDSPStorage ***pppISPStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateStorageWithMetadata(
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ __RPC__in LPCWSTR pwszName,
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pMetadata,
+ /* [in] */ ULONGLONG qwFileSize,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppNewStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSpecifiedMetadata(
+ /* [in] */ DWORD cProperties,
+ /* [size_is][in] */ __RPC__in_ecount_full(cProperties) LPCWSTR *ppwszPropNames,
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pMetadata) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindStorage(
+ /* [in] */ WMDM_FIND_SCOPE findScope,
+ /* [in] */ __RPC__in LPCWSTR pwszUniqueID,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppStorage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetParent(
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppStorage) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPStorage4Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPStorage4 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPStorage4 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPStorage4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAttributes )(
+ IMDSPStorage4 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorageGlobals )(
+ IMDSPStorage4 * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorageGlobals **ppStorageGlobals);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes )(
+ IMDSPStorage4 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IMDSPStorage4 * This,
+ /* [size_is][string][out] */ __RPC__out_ecount_full_string(nMaxChars) LPWSTR pwszName,
+ /* [in] */ UINT nMaxChars);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDate )(
+ IMDSPStorage4 * This,
+ /* [out] */ __RPC__out PWMDMDATETIME pDateTimeUTC);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ IMDSPStorage4 * This,
+ /* [out] */ __RPC__out DWORD *pdwSizeLow,
+ /* [out] */ __RPC__out DWORD *pdwSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRights )(
+ IMDSPStorage4 * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStorage )(
+ IMDSPStorage4 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pFormat,
+ /* [in] */ __RPC__in LPWSTR pwszName,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppNewStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStorage )(
+ IMDSPStorage4 * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPEnumStorage **ppEnumStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *SendOpaqueCommand )(
+ IMDSPStorage4 * This,
+ /* [out][in] */ __RPC__inout OPAQUECOMMAND *pCommand);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStorage )(
+ IMDSPStorage4 * This,
+ /* [string][in] */ __RPC__in LPCWSTR pszStorageName,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStorage2 )(
+ IMDSPStorage4 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ DWORD dwAttributesEx,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][in] */ __RPC__in_opt _VIDEOINFOHEADER *pVideoFormat,
+ /* [in] */ __RPC__in LPWSTR pwszName,
+ /* [in] */ ULONGLONG qwFileSize,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppNewStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAttributes2 )(
+ IMDSPStorage4 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ DWORD dwAttributesEx,
+ /* [unique][in] */ __RPC__in_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][in] */ __RPC__in_opt _VIDEOINFOHEADER *pVideoFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes2 )(
+ IMDSPStorage4 * This,
+ /* [out] */ __RPC__out DWORD *pdwAttributes,
+ /* [out] */ __RPC__out DWORD *pdwAttributesEx,
+ /* [unique][out][in] */ __RPC__inout_opt _WAVEFORMATEX *pAudioFormat,
+ /* [unique][out][in] */ __RPC__inout_opt _VIDEOINFOHEADER *pVideoFormat);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMetadata )(
+ IMDSPStorage4 * This,
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pMetadata);
+
+ HRESULT ( STDMETHODCALLTYPE *SetMetadata )(
+ IMDSPStorage4 * This,
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pMetadata);
+
+ HRESULT ( STDMETHODCALLTYPE *SetReferences )(
+ IMDSPStorage4 * This,
+ /* [in] */ DWORD dwRefs,
+ /* [size_is][unique][in] */ __RPC__in_ecount_full_opt(dwRefs) IMDSPStorage **ppISPStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReferences )(
+ IMDSPStorage4 * This,
+ /* [out] */ __RPC__out DWORD *pdwRefs,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pdwRefs) IMDSPStorage ***pppISPStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStorageWithMetadata )(
+ IMDSPStorage4 * This,
+ /* [in] */ DWORD dwAttributes,
+ /* [in] */ __RPC__in LPCWSTR pwszName,
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pMetadata,
+ /* [in] */ ULONGLONG qwFileSize,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppNewStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSpecifiedMetadata )(
+ IMDSPStorage4 * This,
+ /* [in] */ DWORD cProperties,
+ /* [size_is][in] */ __RPC__in_ecount_full(cProperties) LPCWSTR *ppwszPropNames,
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pMetadata);
+
+ HRESULT ( STDMETHODCALLTYPE *FindStorage )(
+ IMDSPStorage4 * This,
+ /* [in] */ WMDM_FIND_SCOPE findScope,
+ /* [in] */ __RPC__in LPCWSTR pwszUniqueID,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppStorage);
+
+ HRESULT ( STDMETHODCALLTYPE *GetParent )(
+ IMDSPStorage4 * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppStorage);
+
+ END_INTERFACE
+ } IMDSPStorage4Vtbl;
+
+ interface IMDSPStorage4
+ {
+ CONST_VTBL struct IMDSPStorage4Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPStorage4_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPStorage4_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPStorage4_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPStorage4_SetAttributes(This,dwAttributes,pFormat) \
+ ( (This)->lpVtbl -> SetAttributes(This,dwAttributes,pFormat) )
+
+#define IMDSPStorage4_GetStorageGlobals(This,ppStorageGlobals) \
+ ( (This)->lpVtbl -> GetStorageGlobals(This,ppStorageGlobals) )
+
+#define IMDSPStorage4_GetAttributes(This,pdwAttributes,pFormat) \
+ ( (This)->lpVtbl -> GetAttributes(This,pdwAttributes,pFormat) )
+
+#define IMDSPStorage4_GetName(This,pwszName,nMaxChars) \
+ ( (This)->lpVtbl -> GetName(This,pwszName,nMaxChars) )
+
+#define IMDSPStorage4_GetDate(This,pDateTimeUTC) \
+ ( (This)->lpVtbl -> GetDate(This,pDateTimeUTC) )
+
+#define IMDSPStorage4_GetSize(This,pdwSizeLow,pdwSizeHigh) \
+ ( (This)->lpVtbl -> GetSize(This,pdwSizeLow,pdwSizeHigh) )
+
+#define IMDSPStorage4_GetRights(This,ppRights,pnRightsCount,abMac) \
+ ( (This)->lpVtbl -> GetRights(This,ppRights,pnRightsCount,abMac) )
+
+#define IMDSPStorage4_CreateStorage(This,dwAttributes,pFormat,pwszName,ppNewStorage) \
+ ( (This)->lpVtbl -> CreateStorage(This,dwAttributes,pFormat,pwszName,ppNewStorage) )
+
+#define IMDSPStorage4_EnumStorage(This,ppEnumStorage) \
+ ( (This)->lpVtbl -> EnumStorage(This,ppEnumStorage) )
+
+#define IMDSPStorage4_SendOpaqueCommand(This,pCommand) \
+ ( (This)->lpVtbl -> SendOpaqueCommand(This,pCommand) )
+
+
+#define IMDSPStorage4_GetStorage(This,pszStorageName,ppStorage) \
+ ( (This)->lpVtbl -> GetStorage(This,pszStorageName,ppStorage) )
+
+#define IMDSPStorage4_CreateStorage2(This,dwAttributes,dwAttributesEx,pAudioFormat,pVideoFormat,pwszName,qwFileSize,ppNewStorage) \
+ ( (This)->lpVtbl -> CreateStorage2(This,dwAttributes,dwAttributesEx,pAudioFormat,pVideoFormat,pwszName,qwFileSize,ppNewStorage) )
+
+#define IMDSPStorage4_SetAttributes2(This,dwAttributes,dwAttributesEx,pAudioFormat,pVideoFormat) \
+ ( (This)->lpVtbl -> SetAttributes2(This,dwAttributes,dwAttributesEx,pAudioFormat,pVideoFormat) )
+
+#define IMDSPStorage4_GetAttributes2(This,pdwAttributes,pdwAttributesEx,pAudioFormat,pVideoFormat) \
+ ( (This)->lpVtbl -> GetAttributes2(This,pdwAttributes,pdwAttributesEx,pAudioFormat,pVideoFormat) )
+
+
+#define IMDSPStorage4_GetMetadata(This,pMetadata) \
+ ( (This)->lpVtbl -> GetMetadata(This,pMetadata) )
+
+#define IMDSPStorage4_SetMetadata(This,pMetadata) \
+ ( (This)->lpVtbl -> SetMetadata(This,pMetadata) )
+
+
+#define IMDSPStorage4_SetReferences(This,dwRefs,ppISPStorage) \
+ ( (This)->lpVtbl -> SetReferences(This,dwRefs,ppISPStorage) )
+
+#define IMDSPStorage4_GetReferences(This,pdwRefs,pppISPStorage) \
+ ( (This)->lpVtbl -> GetReferences(This,pdwRefs,pppISPStorage) )
+
+#define IMDSPStorage4_CreateStorageWithMetadata(This,dwAttributes,pwszName,pMetadata,qwFileSize,ppNewStorage) \
+ ( (This)->lpVtbl -> CreateStorageWithMetadata(This,dwAttributes,pwszName,pMetadata,qwFileSize,ppNewStorage) )
+
+#define IMDSPStorage4_GetSpecifiedMetadata(This,cProperties,ppwszPropNames,pMetadata) \
+ ( (This)->lpVtbl -> GetSpecifiedMetadata(This,cProperties,ppwszPropNames,pMetadata) )
+
+#define IMDSPStorage4_FindStorage(This,findScope,pwszUniqueID,ppStorage) \
+ ( (This)->lpVtbl -> FindStorage(This,findScope,pwszUniqueID,ppStorage) )
+
+#define IMDSPStorage4_GetParent(This,ppStorage) \
+ ( (This)->lpVtbl -> GetParent(This,ppStorage) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPStorage4_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPStorageGlobals_INTERFACE_DEFINED__
+#define __IMDSPStorageGlobals_INTERFACE_DEFINED__
+
+/* interface IMDSPStorageGlobals */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPStorageGlobals;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A17-33ED-11d3-8470-00C04F79DBC0")
+ IMDSPStorageGlobals : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetCapabilities(
+ /* [out] */ __RPC__out DWORD *pdwCapabilities) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSerialNumber(
+ /* [out] */ __RPC__out PWMDMID pSerialNum,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTotalSize(
+ /* [out] */ __RPC__out DWORD *pdwTotalSizeLow,
+ /* [out] */ __RPC__out DWORD *pdwTotalSizeHigh) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTotalFree(
+ /* [out] */ __RPC__out DWORD *pdwFreeLow,
+ /* [out] */ __RPC__out DWORD *pdwFreeHigh) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTotalBad(
+ /* [out] */ __RPC__out DWORD *pdwBadLow,
+ /* [out] */ __RPC__out DWORD *pdwBadHigh) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStatus(
+ /* [out] */ __RPC__out DWORD *pdwStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Initialize(
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDevice(
+ /* [out] */ __RPC__deref_out_opt IMDSPDevice **ppDevice) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRootStorage(
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppRoot) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPStorageGlobalsVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPStorageGlobals * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPStorageGlobals * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPStorageGlobals * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCapabilities )(
+ IMDSPStorageGlobals * This,
+ /* [out] */ __RPC__out DWORD *pdwCapabilities);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSerialNumber )(
+ IMDSPStorageGlobals * This,
+ /* [out] */ __RPC__out PWMDMID pSerialNum,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTotalSize )(
+ IMDSPStorageGlobals * This,
+ /* [out] */ __RPC__out DWORD *pdwTotalSizeLow,
+ /* [out] */ __RPC__out DWORD *pdwTotalSizeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTotalFree )(
+ IMDSPStorageGlobals * This,
+ /* [out] */ __RPC__out DWORD *pdwFreeLow,
+ /* [out] */ __RPC__out DWORD *pdwFreeHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTotalBad )(
+ IMDSPStorageGlobals * This,
+ /* [out] */ __RPC__out DWORD *pdwBadLow,
+ /* [out] */ __RPC__out DWORD *pdwBadHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStatus )(
+ IMDSPStorageGlobals * This,
+ /* [out] */ __RPC__out DWORD *pdwStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ IMDSPStorageGlobals * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDevice )(
+ IMDSPStorageGlobals * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPDevice **ppDevice);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRootStorage )(
+ IMDSPStorageGlobals * This,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppRoot);
+
+ END_INTERFACE
+ } IMDSPStorageGlobalsVtbl;
+
+ interface IMDSPStorageGlobals
+ {
+ CONST_VTBL struct IMDSPStorageGlobalsVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPStorageGlobals_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPStorageGlobals_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPStorageGlobals_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPStorageGlobals_GetCapabilities(This,pdwCapabilities) \
+ ( (This)->lpVtbl -> GetCapabilities(This,pdwCapabilities) )
+
+#define IMDSPStorageGlobals_GetSerialNumber(This,pSerialNum,abMac) \
+ ( (This)->lpVtbl -> GetSerialNumber(This,pSerialNum,abMac) )
+
+#define IMDSPStorageGlobals_GetTotalSize(This,pdwTotalSizeLow,pdwTotalSizeHigh) \
+ ( (This)->lpVtbl -> GetTotalSize(This,pdwTotalSizeLow,pdwTotalSizeHigh) )
+
+#define IMDSPStorageGlobals_GetTotalFree(This,pdwFreeLow,pdwFreeHigh) \
+ ( (This)->lpVtbl -> GetTotalFree(This,pdwFreeLow,pdwFreeHigh) )
+
+#define IMDSPStorageGlobals_GetTotalBad(This,pdwBadLow,pdwBadHigh) \
+ ( (This)->lpVtbl -> GetTotalBad(This,pdwBadLow,pdwBadHigh) )
+
+#define IMDSPStorageGlobals_GetStatus(This,pdwStatus) \
+ ( (This)->lpVtbl -> GetStatus(This,pdwStatus) )
+
+#define IMDSPStorageGlobals_Initialize(This,fuMode,pProgress) \
+ ( (This)->lpVtbl -> Initialize(This,fuMode,pProgress) )
+
+#define IMDSPStorageGlobals_GetDevice(This,ppDevice) \
+ ( (This)->lpVtbl -> GetDevice(This,ppDevice) )
+
+#define IMDSPStorageGlobals_GetRootStorage(This,ppRoot) \
+ ( (This)->lpVtbl -> GetRootStorage(This,ppRoot) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPStorageGlobals_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPObjectInfo_INTERFACE_DEFINED__
+#define __IMDSPObjectInfo_INTERFACE_DEFINED__
+
+/* interface IMDSPObjectInfo */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPObjectInfo;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A19-33ED-11d3-8470-00C04F79DBC0")
+ IMDSPObjectInfo : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetPlayLength(
+ /* [out] */ __RPC__out DWORD *pdwLength) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetPlayLength(
+ /* [in] */ DWORD dwLength) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPlayOffset(
+ /* [out] */ __RPC__out DWORD *pdwOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetPlayOffset(
+ /* [in] */ DWORD dwOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTotalLength(
+ /* [out] */ __RPC__out DWORD *pdwLength) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLastPlayPosition(
+ /* [out] */ __RPC__out DWORD *pdwLastPos) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLongestPlayPosition(
+ /* [out] */ __RPC__out DWORD *pdwLongestPos) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPObjectInfoVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPObjectInfo * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPObjectInfo * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPObjectInfo * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPlayLength )(
+ IMDSPObjectInfo * This,
+ /* [out] */ __RPC__out DWORD *pdwLength);
+
+ HRESULT ( STDMETHODCALLTYPE *SetPlayLength )(
+ IMDSPObjectInfo * This,
+ /* [in] */ DWORD dwLength);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPlayOffset )(
+ IMDSPObjectInfo * This,
+ /* [out] */ __RPC__out DWORD *pdwOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *SetPlayOffset )(
+ IMDSPObjectInfo * This,
+ /* [in] */ DWORD dwOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTotalLength )(
+ IMDSPObjectInfo * This,
+ /* [out] */ __RPC__out DWORD *pdwLength);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLastPlayPosition )(
+ IMDSPObjectInfo * This,
+ /* [out] */ __RPC__out DWORD *pdwLastPos);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLongestPlayPosition )(
+ IMDSPObjectInfo * This,
+ /* [out] */ __RPC__out DWORD *pdwLongestPos);
+
+ END_INTERFACE
+ } IMDSPObjectInfoVtbl;
+
+ interface IMDSPObjectInfo
+ {
+ CONST_VTBL struct IMDSPObjectInfoVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPObjectInfo_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPObjectInfo_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPObjectInfo_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPObjectInfo_GetPlayLength(This,pdwLength) \
+ ( (This)->lpVtbl -> GetPlayLength(This,pdwLength) )
+
+#define IMDSPObjectInfo_SetPlayLength(This,dwLength) \
+ ( (This)->lpVtbl -> SetPlayLength(This,dwLength) )
+
+#define IMDSPObjectInfo_GetPlayOffset(This,pdwOffset) \
+ ( (This)->lpVtbl -> GetPlayOffset(This,pdwOffset) )
+
+#define IMDSPObjectInfo_SetPlayOffset(This,dwOffset) \
+ ( (This)->lpVtbl -> SetPlayOffset(This,dwOffset) )
+
+#define IMDSPObjectInfo_GetTotalLength(This,pdwLength) \
+ ( (This)->lpVtbl -> GetTotalLength(This,pdwLength) )
+
+#define IMDSPObjectInfo_GetLastPlayPosition(This,pdwLastPos) \
+ ( (This)->lpVtbl -> GetLastPlayPosition(This,pdwLastPos) )
+
+#define IMDSPObjectInfo_GetLongestPlayPosition(This,pdwLongestPos) \
+ ( (This)->lpVtbl -> GetLongestPlayPosition(This,pdwLongestPos) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPObjectInfo_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPObject_INTERFACE_DEFINED__
+#define __IMDSPObject_INTERFACE_DEFINED__
+
+/* interface IMDSPObject */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPObject;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A18-33ED-11d3-8470-00C04F79DBC0")
+ IMDSPObject : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Open(
+ /* [in] */ UINT fuMode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Read(
+ /* [size_is][out] */ __RPC__out_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Write(
+ /* [size_is][in] */ __RPC__in_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Delete(
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Seek(
+ /* [in] */ UINT fuFlags,
+ /* [in] */ DWORD dwOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Rename(
+ /* [in] */ __RPC__in LPWSTR pwszNewName,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Move(
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [in] */ __RPC__in_opt IMDSPStorage *pTarget) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Close( void) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPObjectVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPObject * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPObject * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPObject * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Open )(
+ IMDSPObject * This,
+ /* [in] */ UINT fuMode);
+
+ HRESULT ( STDMETHODCALLTYPE *Read )(
+ IMDSPObject * This,
+ /* [size_is][out] */ __RPC__out_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Write )(
+ IMDSPObject * This,
+ /* [size_is][in] */ __RPC__in_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Delete )(
+ IMDSPObject * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ HRESULT ( STDMETHODCALLTYPE *Seek )(
+ IMDSPObject * This,
+ /* [in] */ UINT fuFlags,
+ /* [in] */ DWORD dwOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *Rename )(
+ IMDSPObject * This,
+ /* [in] */ __RPC__in LPWSTR pwszNewName,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ HRESULT ( STDMETHODCALLTYPE *Move )(
+ IMDSPObject * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [in] */ __RPC__in_opt IMDSPStorage *pTarget);
+
+ HRESULT ( STDMETHODCALLTYPE *Close )(
+ IMDSPObject * This);
+
+ END_INTERFACE
+ } IMDSPObjectVtbl;
+
+ interface IMDSPObject
+ {
+ CONST_VTBL struct IMDSPObjectVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPObject_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPObject_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPObject_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPObject_Open(This,fuMode) \
+ ( (This)->lpVtbl -> Open(This,fuMode) )
+
+#define IMDSPObject_Read(This,pData,pdwSize,abMac) \
+ ( (This)->lpVtbl -> Read(This,pData,pdwSize,abMac) )
+
+#define IMDSPObject_Write(This,pData,pdwSize,abMac) \
+ ( (This)->lpVtbl -> Write(This,pData,pdwSize,abMac) )
+
+#define IMDSPObject_Delete(This,fuMode,pProgress) \
+ ( (This)->lpVtbl -> Delete(This,fuMode,pProgress) )
+
+#define IMDSPObject_Seek(This,fuFlags,dwOffset) \
+ ( (This)->lpVtbl -> Seek(This,fuFlags,dwOffset) )
+
+#define IMDSPObject_Rename(This,pwszNewName,pProgress) \
+ ( (This)->lpVtbl -> Rename(This,pwszNewName,pProgress) )
+
+#define IMDSPObject_Move(This,fuMode,pProgress,pTarget) \
+ ( (This)->lpVtbl -> Move(This,fuMode,pProgress,pTarget) )
+
+#define IMDSPObject_Close(This) \
+ ( (This)->lpVtbl -> Close(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPObject_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPObject2_INTERFACE_DEFINED__
+#define __IMDSPObject2_INTERFACE_DEFINED__
+
+/* interface IMDSPObject2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPObject2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3f34cd3e-5907-4341-9af9-97f4187c3aa5")
+ IMDSPObject2 : public IMDSPObject
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ReadOnClearChannel(
+ /* [size_is][out] */ __RPC__out_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteOnClearChannel(
+ /* [size_is][in] */ __RPC__in_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPObject2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPObject2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPObject2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPObject2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Open )(
+ IMDSPObject2 * This,
+ /* [in] */ UINT fuMode);
+
+ HRESULT ( STDMETHODCALLTYPE *Read )(
+ IMDSPObject2 * This,
+ /* [size_is][out] */ __RPC__out_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Write )(
+ IMDSPObject2 * This,
+ /* [size_is][in] */ __RPC__in_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Delete )(
+ IMDSPObject2 * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ HRESULT ( STDMETHODCALLTYPE *Seek )(
+ IMDSPObject2 * This,
+ /* [in] */ UINT fuFlags,
+ /* [in] */ DWORD dwOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *Rename )(
+ IMDSPObject2 * This,
+ /* [in] */ __RPC__in LPWSTR pwszNewName,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress);
+
+ HRESULT ( STDMETHODCALLTYPE *Move )(
+ IMDSPObject2 * This,
+ /* [in] */ UINT fuMode,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pProgress,
+ /* [in] */ __RPC__in_opt IMDSPStorage *pTarget);
+
+ HRESULT ( STDMETHODCALLTYPE *Close )(
+ IMDSPObject2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ReadOnClearChannel )(
+ IMDSPObject2 * This,
+ /* [size_is][out] */ __RPC__out_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteOnClearChannel )(
+ IMDSPObject2 * This,
+ /* [size_is][in] */ __RPC__in_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize);
+
+ END_INTERFACE
+ } IMDSPObject2Vtbl;
+
+ interface IMDSPObject2
+ {
+ CONST_VTBL struct IMDSPObject2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPObject2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPObject2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPObject2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPObject2_Open(This,fuMode) \
+ ( (This)->lpVtbl -> Open(This,fuMode) )
+
+#define IMDSPObject2_Read(This,pData,pdwSize,abMac) \
+ ( (This)->lpVtbl -> Read(This,pData,pdwSize,abMac) )
+
+#define IMDSPObject2_Write(This,pData,pdwSize,abMac) \
+ ( (This)->lpVtbl -> Write(This,pData,pdwSize,abMac) )
+
+#define IMDSPObject2_Delete(This,fuMode,pProgress) \
+ ( (This)->lpVtbl -> Delete(This,fuMode,pProgress) )
+
+#define IMDSPObject2_Seek(This,fuFlags,dwOffset) \
+ ( (This)->lpVtbl -> Seek(This,fuFlags,dwOffset) )
+
+#define IMDSPObject2_Rename(This,pwszNewName,pProgress) \
+ ( (This)->lpVtbl -> Rename(This,pwszNewName,pProgress) )
+
+#define IMDSPObject2_Move(This,fuMode,pProgress,pTarget) \
+ ( (This)->lpVtbl -> Move(This,fuMode,pProgress,pTarget) )
+
+#define IMDSPObject2_Close(This) \
+ ( (This)->lpVtbl -> Close(This) )
+
+
+#define IMDSPObject2_ReadOnClearChannel(This,pData,pdwSize) \
+ ( (This)->lpVtbl -> ReadOnClearChannel(This,pData,pdwSize) )
+
+#define IMDSPObject2_WriteOnClearChannel(This,pData,pdwSize) \
+ ( (This)->lpVtbl -> WriteOnClearChannel(This,pData,pdwSize) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPObject2_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPDirectTransfer_INTERFACE_DEFINED__
+#define __IMDSPDirectTransfer_INTERFACE_DEFINED__
+
+/* interface IMDSPDirectTransfer */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPDirectTransfer;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("c2fe57a8-9304-478c-9ee4-47e397b912d7")
+ IMDSPDirectTransfer : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE TransferToDevice(
+ /* [string][unique][in] */ __RPC__in_opt LPCWSTR pwszSourceFilePath,
+ /* [in] */ __RPC__in_opt IWMDMOperation *pSourceOperation,
+ /* [in] */ UINT fuFlags,
+ /* [string][unique][in] */ __RPC__in_opt LPWSTR pwszDestinationName,
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pSourceMetaData,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pTransferProgress,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppNewObject) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPDirectTransferVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPDirectTransfer * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPDirectTransfer * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPDirectTransfer * This);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferToDevice )(
+ IMDSPDirectTransfer * This,
+ /* [string][unique][in] */ __RPC__in_opt LPCWSTR pwszSourceFilePath,
+ /* [in] */ __RPC__in_opt IWMDMOperation *pSourceOperation,
+ /* [in] */ UINT fuFlags,
+ /* [string][unique][in] */ __RPC__in_opt LPWSTR pwszDestinationName,
+ /* [in] */ __RPC__in_opt IWMDMMetaData *pSourceMetaData,
+ /* [in] */ __RPC__in_opt IWMDMProgress *pTransferProgress,
+ /* [out] */ __RPC__deref_out_opt IMDSPStorage **ppNewObject);
+
+ END_INTERFACE
+ } IMDSPDirectTransferVtbl;
+
+ interface IMDSPDirectTransfer
+ {
+ CONST_VTBL struct IMDSPDirectTransferVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPDirectTransfer_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPDirectTransfer_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPDirectTransfer_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPDirectTransfer_TransferToDevice(This,pwszSourceFilePath,pSourceOperation,fuFlags,pwszDestinationName,pSourceMetaData,pTransferProgress,ppNewObject) \
+ ( (This)->lpVtbl -> TransferToDevice(This,pwszSourceFilePath,pSourceOperation,fuFlags,pwszDestinationName,pSourceMetaData,pTransferProgress,ppNewObject) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPDirectTransfer_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMDSPRevoked_INTERFACE_DEFINED__
+#define __IMDSPRevoked_INTERFACE_DEFINED__
+
+/* interface IMDSPRevoked */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMDSPRevoked;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A4E8F2D4-3F31-464d-B53D-4FC335998184")
+ IMDSPRevoked : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetRevocationURL(
+ /* [size_is][size_is][string][out][in] */ __RPC__deref_inout_ecount_full_opt_string(*pdwBufferLen) LPWSTR *ppwszRevocationURL,
+ /* [out][in] */ __RPC__inout DWORD *pdwBufferLen) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IMDSPRevokedVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMDSPRevoked * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMDSPRevoked * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMDSPRevoked * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRevocationURL )(
+ IMDSPRevoked * This,
+ /* [size_is][size_is][string][out][in] */ __RPC__deref_inout_ecount_full_opt_string(*pdwBufferLen) LPWSTR *ppwszRevocationURL,
+ /* [out][in] */ __RPC__inout DWORD *pdwBufferLen);
+
+ END_INTERFACE
+ } IMDSPRevokedVtbl;
+
+ interface IMDSPRevoked
+ {
+ CONST_VTBL struct IMDSPRevokedVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMDSPRevoked_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMDSPRevoked_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMDSPRevoked_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMDSPRevoked_GetRevocationURL(This,ppwszRevocationURL,pdwBufferLen) \
+ ( (This)->lpVtbl -> GetRevocationURL(This,ppwszRevocationURL,pdwBufferLen) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMDSPRevoked_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mswmdm_0000_0047 */
+/* [local] */
+
+// SCP Data Flags
+#define WMDM_SCP_EXAMINE_EXTENSION 0x00000001L
+#define WMDM_SCP_EXAMINE_DATA 0x00000002L
+#define WMDM_SCP_DECIDE_DATA 0x00000008L
+#define WMDM_SCP_PROTECTED_OUTPUT 0x00000010L
+#define WMDM_SCP_UNPROTECTED_OUTPUT 0x00000020L
+#define WMDM_SCP_RIGHTS_DATA 0x00000040L
+// SCP Transfer Flags
+#define WMDM_SCP_TRANSFER_OBJECTDATA 0x00000020L
+#define WMDM_SCP_NO_MORE_CHANGES 0x00000040L
+// SCP DRMINFO Flags
+#define WMDM_SCP_DRMINFO_NOT_DRMPROTECTED 0x00000000L
+#define WMDM_SCP_DRMINFO_V1HEADER 0x00000001L
+#define WMDM_SCP_DRMINFO_V2HEADER 0x00000002L
+#ifndef _DEFINE_SCP_EVENTID
+#define _DEFINE_SCP_EVENTID
+// {86248CC9-4A59-43e2-9146-48A7F3F4140C}
+// this event ID is used when SCP is acquiring secure clock from server
+DEFINE_GUID(SCP_EVENTID_ACQSECURECLOCK,
+0x86248cc9, 0x4a59, 0x43e2, 0x91, 0x46, 0x48, 0xa7, 0xf3, 0xf4, 0x14, 0xc);
+//
+// {87A507C7-B469-4386-B976-D5D1CE538A6F}
+DEFINE_GUID(SCP_EVENTID_NEEDTOINDIV,
+0x87a507c7, 0xb469, 0x4386, 0xb9, 0x76, 0xd5, 0xd1, 0xce, 0x53, 0x8a, 0x6f);
+// this event ID is used to notify the player the version DRM header found in the content
+// {213DD287-41D2-432b-9E3F-3B4F7B3581DD}
+DEFINE_GUID(SCP_EVENTID_DRMINFO,
+0x213dd287, 0x41d2, 0x432b, 0x9e, 0x3f, 0x3b, 0x4f, 0x7b, 0x35, 0x81, 0xdd);
+// this parameter ID is used when notifying SCP_EVENTID_DRMINFO message
+// {41D0155D-7CC7-4217-ADA9-005074624DA4}
+DEFINE_GUID(SCP_PARAMID_DRMVERSION,
+0x41d0155d, 0x7cc7, 0x4217, 0xad, 0xa9, 0x00, 0x50, 0x74, 0x62, 0x4d, 0xa4);
+#endif
+
+
+
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mswmdm_0000_0047_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mswmdm_0000_0047_v0_0_s_ifspec;
+
+#ifndef __ISCPSecureAuthenticate_INTERFACE_DEFINED__
+#define __ISCPSecureAuthenticate_INTERFACE_DEFINED__
+
+/* interface ISCPSecureAuthenticate */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISCPSecureAuthenticate;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A0F-33ED-11d3-8470-00C04F79DBC0")
+ ISCPSecureAuthenticate : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetSecureQuery(
+ /* [out] */ __RPC__deref_out_opt ISCPSecureQuery **ppSecureQuery) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct ISCPSecureAuthenticateVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISCPSecureAuthenticate * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISCPSecureAuthenticate * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISCPSecureAuthenticate * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSecureQuery )(
+ ISCPSecureAuthenticate * This,
+ /* [out] */ __RPC__deref_out_opt ISCPSecureQuery **ppSecureQuery);
+
+ END_INTERFACE
+ } ISCPSecureAuthenticateVtbl;
+
+ interface ISCPSecureAuthenticate
+ {
+ CONST_VTBL struct ISCPSecureAuthenticateVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISCPSecureAuthenticate_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISCPSecureAuthenticate_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISCPSecureAuthenticate_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISCPSecureAuthenticate_GetSecureQuery(This,ppSecureQuery) \
+ ( (This)->lpVtbl -> GetSecureQuery(This,ppSecureQuery) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISCPSecureAuthenticate_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISCPSecureAuthenticate2_INTERFACE_DEFINED__
+#define __ISCPSecureAuthenticate2_INTERFACE_DEFINED__
+
+/* interface ISCPSecureAuthenticate2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISCPSecureAuthenticate2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B580CFAE-1672-47e2-ACAA-44BBECBCAE5B")
+ ISCPSecureAuthenticate2 : public ISCPSecureAuthenticate
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetSCPSession(
+ /* [out] */ __RPC__deref_out_opt ISCPSession **ppSCPSession) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct ISCPSecureAuthenticate2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISCPSecureAuthenticate2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISCPSecureAuthenticate2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISCPSecureAuthenticate2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSecureQuery )(
+ ISCPSecureAuthenticate2 * This,
+ /* [out] */ __RPC__deref_out_opt ISCPSecureQuery **ppSecureQuery);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSCPSession )(
+ ISCPSecureAuthenticate2 * This,
+ /* [out] */ __RPC__deref_out_opt ISCPSession **ppSCPSession);
+
+ END_INTERFACE
+ } ISCPSecureAuthenticate2Vtbl;
+
+ interface ISCPSecureAuthenticate2
+ {
+ CONST_VTBL struct ISCPSecureAuthenticate2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISCPSecureAuthenticate2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISCPSecureAuthenticate2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISCPSecureAuthenticate2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISCPSecureAuthenticate2_GetSecureQuery(This,ppSecureQuery) \
+ ( (This)->lpVtbl -> GetSecureQuery(This,ppSecureQuery) )
+
+
+#define ISCPSecureAuthenticate2_GetSCPSession(This,ppSCPSession) \
+ ( (This)->lpVtbl -> GetSCPSession(This,ppSCPSession) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISCPSecureAuthenticate2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISCPSecureQuery_INTERFACE_DEFINED__
+#define __ISCPSecureQuery_INTERFACE_DEFINED__
+
+/* interface ISCPSecureQuery */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISCPSecureQuery;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A0D-33ED-11d3-8470-00C04F79DBC0")
+ ISCPSecureQuery : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetDataDemands(
+ /* [out] */ __RPC__out UINT *pfuFlags,
+ /* [out] */ __RPC__out DWORD *pdwMinRightsData,
+ /* [out] */ __RPC__out DWORD *pdwMinExamineData,
+ /* [out] */ __RPC__out DWORD *pdwMinDecideData,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExamineData(
+ /* [in] */ UINT fuFlags,
+ /* [unique][string][in] */ __RPC__in_opt LPWSTR pwszExtension,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE MakeDecision(
+ /* [in] */ UINT fuFlags,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ DWORD dwAppSec,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStorageGlobals,
+ /* [out] */ __RPC__deref_out_opt ISCPSecureExchange **ppExchange,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRights(
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStgGlobals,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct ISCPSecureQueryVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISCPSecureQuery * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISCPSecureQuery * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISCPSecureQuery * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDataDemands )(
+ ISCPSecureQuery * This,
+ /* [out] */ __RPC__out UINT *pfuFlags,
+ /* [out] */ __RPC__out DWORD *pdwMinRightsData,
+ /* [out] */ __RPC__out DWORD *pdwMinExamineData,
+ /* [out] */ __RPC__out DWORD *pdwMinDecideData,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ExamineData )(
+ ISCPSecureQuery * This,
+ /* [in] */ UINT fuFlags,
+ /* [unique][string][in] */ __RPC__in_opt LPWSTR pwszExtension,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *MakeDecision )(
+ ISCPSecureQuery * This,
+ /* [in] */ UINT fuFlags,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ DWORD dwAppSec,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStorageGlobals,
+ /* [out] */ __RPC__deref_out_opt ISCPSecureExchange **ppExchange,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRights )(
+ ISCPSecureQuery * This,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStgGlobals,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ END_INTERFACE
+ } ISCPSecureQueryVtbl;
+
+ interface ISCPSecureQuery
+ {
+ CONST_VTBL struct ISCPSecureQueryVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISCPSecureQuery_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISCPSecureQuery_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISCPSecureQuery_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISCPSecureQuery_GetDataDemands(This,pfuFlags,pdwMinRightsData,pdwMinExamineData,pdwMinDecideData,abMac) \
+ ( (This)->lpVtbl -> GetDataDemands(This,pfuFlags,pdwMinRightsData,pdwMinExamineData,pdwMinDecideData,abMac) )
+
+#define ISCPSecureQuery_ExamineData(This,fuFlags,pwszExtension,pData,dwSize,abMac) \
+ ( (This)->lpVtbl -> ExamineData(This,fuFlags,pwszExtension,pData,dwSize,abMac) )
+
+#define ISCPSecureQuery_MakeDecision(This,fuFlags,pData,dwSize,dwAppSec,pbSPSessionKey,dwSessionKeyLen,pStorageGlobals,ppExchange,abMac) \
+ ( (This)->lpVtbl -> MakeDecision(This,fuFlags,pData,dwSize,dwAppSec,pbSPSessionKey,dwSessionKeyLen,pStorageGlobals,ppExchange,abMac) )
+
+#define ISCPSecureQuery_GetRights(This,pData,dwSize,pbSPSessionKey,dwSessionKeyLen,pStgGlobals,ppRights,pnRightsCount,abMac) \
+ ( (This)->lpVtbl -> GetRights(This,pData,dwSize,pbSPSessionKey,dwSessionKeyLen,pStgGlobals,ppRights,pnRightsCount,abMac) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISCPSecureQuery_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISCPSecureQuery2_INTERFACE_DEFINED__
+#define __ISCPSecureQuery2_INTERFACE_DEFINED__
+
+/* interface ISCPSecureQuery2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISCPSecureQuery2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("EBE17E25-4FD7-4632-AF46-6D93D4FCC72E")
+ ISCPSecureQuery2 : public ISCPSecureQuery
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE MakeDecision2(
+ /* [in] */ UINT fuFlags,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ DWORD dwAppSec,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStorageGlobals,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwAppCertAppLen) BYTE *pAppCertApp,
+ /* [in] */ DWORD dwAppCertAppLen,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwAppCertSPLen) BYTE *pAppCertSP,
+ /* [in] */ DWORD dwAppCertSPLen,
+ /* [size_is][size_is][string][out][in] */ __RPC__deref_inout_ecount_full_opt_string(*pdwRevocationURLLen) LPWSTR *pszRevocationURL,
+ /* [ref][out][in] */ __RPC__inout DWORD *pdwRevocationURLLen,
+ /* [out] */ __RPC__out DWORD *pdwRevocationBitFlag,
+ /* [unique][out][in] */ __RPC__inout_opt ULONGLONG *pqwFileSize,
+ /* [in] */ __RPC__in_opt IUnknown *pUnknown,
+ /* [out] */ __RPC__deref_out_opt ISCPSecureExchange **ppExchange,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct ISCPSecureQuery2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISCPSecureQuery2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISCPSecureQuery2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISCPSecureQuery2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDataDemands )(
+ ISCPSecureQuery2 * This,
+ /* [out] */ __RPC__out UINT *pfuFlags,
+ /* [out] */ __RPC__out DWORD *pdwMinRightsData,
+ /* [out] */ __RPC__out DWORD *pdwMinExamineData,
+ /* [out] */ __RPC__out DWORD *pdwMinDecideData,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ExamineData )(
+ ISCPSecureQuery2 * This,
+ /* [in] */ UINT fuFlags,
+ /* [unique][string][in] */ __RPC__in_opt LPWSTR pwszExtension,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *MakeDecision )(
+ ISCPSecureQuery2 * This,
+ /* [in] */ UINT fuFlags,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ DWORD dwAppSec,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStorageGlobals,
+ /* [out] */ __RPC__deref_out_opt ISCPSecureExchange **ppExchange,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRights )(
+ ISCPSecureQuery2 * This,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStgGlobals,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *MakeDecision2 )(
+ ISCPSecureQuery2 * This,
+ /* [in] */ UINT fuFlags,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ DWORD dwAppSec,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStorageGlobals,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwAppCertAppLen) BYTE *pAppCertApp,
+ /* [in] */ DWORD dwAppCertAppLen,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwAppCertSPLen) BYTE *pAppCertSP,
+ /* [in] */ DWORD dwAppCertSPLen,
+ /* [size_is][size_is][string][out][in] */ __RPC__deref_inout_ecount_full_opt_string(*pdwRevocationURLLen) LPWSTR *pszRevocationURL,
+ /* [ref][out][in] */ __RPC__inout DWORD *pdwRevocationURLLen,
+ /* [out] */ __RPC__out DWORD *pdwRevocationBitFlag,
+ /* [unique][out][in] */ __RPC__inout_opt ULONGLONG *pqwFileSize,
+ /* [in] */ __RPC__in_opt IUnknown *pUnknown,
+ /* [out] */ __RPC__deref_out_opt ISCPSecureExchange **ppExchange,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ END_INTERFACE
+ } ISCPSecureQuery2Vtbl;
+
+ interface ISCPSecureQuery2
+ {
+ CONST_VTBL struct ISCPSecureQuery2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISCPSecureQuery2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISCPSecureQuery2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISCPSecureQuery2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISCPSecureQuery2_GetDataDemands(This,pfuFlags,pdwMinRightsData,pdwMinExamineData,pdwMinDecideData,abMac) \
+ ( (This)->lpVtbl -> GetDataDemands(This,pfuFlags,pdwMinRightsData,pdwMinExamineData,pdwMinDecideData,abMac) )
+
+#define ISCPSecureQuery2_ExamineData(This,fuFlags,pwszExtension,pData,dwSize,abMac) \
+ ( (This)->lpVtbl -> ExamineData(This,fuFlags,pwszExtension,pData,dwSize,abMac) )
+
+#define ISCPSecureQuery2_MakeDecision(This,fuFlags,pData,dwSize,dwAppSec,pbSPSessionKey,dwSessionKeyLen,pStorageGlobals,ppExchange,abMac) \
+ ( (This)->lpVtbl -> MakeDecision(This,fuFlags,pData,dwSize,dwAppSec,pbSPSessionKey,dwSessionKeyLen,pStorageGlobals,ppExchange,abMac) )
+
+#define ISCPSecureQuery2_GetRights(This,pData,dwSize,pbSPSessionKey,dwSessionKeyLen,pStgGlobals,ppRights,pnRightsCount,abMac) \
+ ( (This)->lpVtbl -> GetRights(This,pData,dwSize,pbSPSessionKey,dwSessionKeyLen,pStgGlobals,ppRights,pnRightsCount,abMac) )
+
+
+#define ISCPSecureQuery2_MakeDecision2(This,fuFlags,pData,dwSize,dwAppSec,pbSPSessionKey,dwSessionKeyLen,pStorageGlobals,pAppCertApp,dwAppCertAppLen,pAppCertSP,dwAppCertSPLen,pszRevocationURL,pdwRevocationURLLen,pdwRevocationBitFlag,pqwFileSize,pUnknown,ppExchange,abMac) \
+ ( (This)->lpVtbl -> MakeDecision2(This,fuFlags,pData,dwSize,dwAppSec,pbSPSessionKey,dwSessionKeyLen,pStorageGlobals,pAppCertApp,dwAppCertAppLen,pAppCertSP,dwAppCertSPLen,pszRevocationURL,pdwRevocationURLLen,pdwRevocationBitFlag,pqwFileSize,pUnknown,ppExchange,abMac) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISCPSecureQuery2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISCPSecureExchange_INTERFACE_DEFINED__
+#define __ISCPSecureExchange_INTERFACE_DEFINED__
+
+/* interface ISCPSecureExchange */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISCPSecureExchange;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1DCB3A0E-33ED-11d3-8470-00C04F79DBC0")
+ ISCPSecureExchange : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE TransferContainerData(
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [out] */ __RPC__out UINT *pfuReadyFlags,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ObjectData(
+ /* [size_is][out] */ __RPC__out_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE TransferComplete( void) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct ISCPSecureExchangeVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISCPSecureExchange * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISCPSecureExchange * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISCPSecureExchange * This);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferContainerData )(
+ ISCPSecureExchange * This,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [out] */ __RPC__out UINT *pfuReadyFlags,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectData )(
+ ISCPSecureExchange * This,
+ /* [size_is][out] */ __RPC__out_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferComplete )(
+ ISCPSecureExchange * This);
+
+ END_INTERFACE
+ } ISCPSecureExchangeVtbl;
+
+ interface ISCPSecureExchange
+ {
+ CONST_VTBL struct ISCPSecureExchangeVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISCPSecureExchange_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISCPSecureExchange_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISCPSecureExchange_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISCPSecureExchange_TransferContainerData(This,pData,dwSize,pfuReadyFlags,abMac) \
+ ( (This)->lpVtbl -> TransferContainerData(This,pData,dwSize,pfuReadyFlags,abMac) )
+
+#define ISCPSecureExchange_ObjectData(This,pData,pdwSize,abMac) \
+ ( (This)->lpVtbl -> ObjectData(This,pData,pdwSize,abMac) )
+
+#define ISCPSecureExchange_TransferComplete(This) \
+ ( (This)->lpVtbl -> TransferComplete(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISCPSecureExchange_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISCPSecureExchange2_INTERFACE_DEFINED__
+#define __ISCPSecureExchange2_INTERFACE_DEFINED__
+
+/* interface ISCPSecureExchange2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISCPSecureExchange2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("6C62FC7B-2690-483F-9D44-0A20CB35577C")
+ ISCPSecureExchange2 : public ISCPSecureExchange
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE TransferContainerData2(
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ __RPC__in_opt IWMDMProgress3 *pProgressCallback,
+ /* [out] */ __RPC__out UINT *pfuReadyFlags,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct ISCPSecureExchange2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISCPSecureExchange2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISCPSecureExchange2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISCPSecureExchange2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferContainerData )(
+ ISCPSecureExchange2 * This,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [out] */ __RPC__out UINT *pfuReadyFlags,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectData )(
+ ISCPSecureExchange2 * This,
+ /* [size_is][out] */ __RPC__out_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferComplete )(
+ ISCPSecureExchange2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferContainerData2 )(
+ ISCPSecureExchange2 * This,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ __RPC__in_opt IWMDMProgress3 *pProgressCallback,
+ /* [out] */ __RPC__out UINT *pfuReadyFlags,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ END_INTERFACE
+ } ISCPSecureExchange2Vtbl;
+
+ interface ISCPSecureExchange2
+ {
+ CONST_VTBL struct ISCPSecureExchange2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISCPSecureExchange2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISCPSecureExchange2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISCPSecureExchange2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISCPSecureExchange2_TransferContainerData(This,pData,dwSize,pfuReadyFlags,abMac) \
+ ( (This)->lpVtbl -> TransferContainerData(This,pData,dwSize,pfuReadyFlags,abMac) )
+
+#define ISCPSecureExchange2_ObjectData(This,pData,pdwSize,abMac) \
+ ( (This)->lpVtbl -> ObjectData(This,pData,pdwSize,abMac) )
+
+#define ISCPSecureExchange2_TransferComplete(This) \
+ ( (This)->lpVtbl -> TransferComplete(This) )
+
+
+#define ISCPSecureExchange2_TransferContainerData2(This,pData,dwSize,pProgressCallback,pfuReadyFlags,abMac) \
+ ( (This)->lpVtbl -> TransferContainerData2(This,pData,dwSize,pProgressCallback,pfuReadyFlags,abMac) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISCPSecureExchange2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISCPSecureExchange3_INTERFACE_DEFINED__
+#define __ISCPSecureExchange3_INTERFACE_DEFINED__
+
+/* interface ISCPSecureExchange3 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISCPSecureExchange3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("ab4e77e4-8908-4b17-bd2a-b1dbe6dd69e1")
+ ISCPSecureExchange3 : public ISCPSecureExchange2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE TransferContainerDataOnClearChannel(
+ /* [in] */ __RPC__in_opt IMDSPDevice *pDevice,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ __RPC__in_opt IWMDMProgress3 *pProgressCallback,
+ /* [out] */ __RPC__out UINT *pfuReadyFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObjectDataOnClearChannel(
+ /* [in] */ __RPC__in_opt IMDSPDevice *pDevice,
+ /* [size_is][out] */ __RPC__out_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE TransferCompleteForDevice(
+ /* [in] */ __RPC__in_opt IMDSPDevice *pDevice) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct ISCPSecureExchange3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISCPSecureExchange3 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISCPSecureExchange3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISCPSecureExchange3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferContainerData )(
+ ISCPSecureExchange3 * This,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [out] */ __RPC__out UINT *pfuReadyFlags,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectData )(
+ ISCPSecureExchange3 * This,
+ /* [size_is][out] */ __RPC__out_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferComplete )(
+ ISCPSecureExchange3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferContainerData2 )(
+ ISCPSecureExchange3 * This,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ __RPC__in_opt IWMDMProgress3 *pProgressCallback,
+ /* [out] */ __RPC__out UINT *pfuReadyFlags,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferContainerDataOnClearChannel )(
+ ISCPSecureExchange3 * This,
+ /* [in] */ __RPC__in_opt IMDSPDevice *pDevice,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ __RPC__in_opt IWMDMProgress3 *pProgressCallback,
+ /* [out] */ __RPC__out UINT *pfuReadyFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectDataOnClearChannel )(
+ ISCPSecureExchange3 * This,
+ /* [in] */ __RPC__in_opt IMDSPDevice *pDevice,
+ /* [size_is][out] */ __RPC__out_ecount_full(*pdwSize) BYTE *pData,
+ /* [out][in] */ __RPC__inout DWORD *pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *TransferCompleteForDevice )(
+ ISCPSecureExchange3 * This,
+ /* [in] */ __RPC__in_opt IMDSPDevice *pDevice);
+
+ END_INTERFACE
+ } ISCPSecureExchange3Vtbl;
+
+ interface ISCPSecureExchange3
+ {
+ CONST_VTBL struct ISCPSecureExchange3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISCPSecureExchange3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISCPSecureExchange3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISCPSecureExchange3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISCPSecureExchange3_TransferContainerData(This,pData,dwSize,pfuReadyFlags,abMac) \
+ ( (This)->lpVtbl -> TransferContainerData(This,pData,dwSize,pfuReadyFlags,abMac) )
+
+#define ISCPSecureExchange3_ObjectData(This,pData,pdwSize,abMac) \
+ ( (This)->lpVtbl -> ObjectData(This,pData,pdwSize,abMac) )
+
+#define ISCPSecureExchange3_TransferComplete(This) \
+ ( (This)->lpVtbl -> TransferComplete(This) )
+
+
+#define ISCPSecureExchange3_TransferContainerData2(This,pData,dwSize,pProgressCallback,pfuReadyFlags,abMac) \
+ ( (This)->lpVtbl -> TransferContainerData2(This,pData,dwSize,pProgressCallback,pfuReadyFlags,abMac) )
+
+
+#define ISCPSecureExchange3_TransferContainerDataOnClearChannel(This,pDevice,pData,dwSize,pProgressCallback,pfuReadyFlags) \
+ ( (This)->lpVtbl -> TransferContainerDataOnClearChannel(This,pDevice,pData,dwSize,pProgressCallback,pfuReadyFlags) )
+
+#define ISCPSecureExchange3_GetObjectDataOnClearChannel(This,pDevice,pData,pdwSize) \
+ ( (This)->lpVtbl -> GetObjectDataOnClearChannel(This,pDevice,pData,pdwSize) )
+
+#define ISCPSecureExchange3_TransferCompleteForDevice(This,pDevice) \
+ ( (This)->lpVtbl -> TransferCompleteForDevice(This,pDevice) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISCPSecureExchange3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISCPSession_INTERFACE_DEFINED__
+#define __ISCPSession_INTERFACE_DEFINED__
+
+/* interface ISCPSession */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISCPSession;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("88a3e6ed-eee4-4619-bbb3-fd4fb62715d1")
+ ISCPSession : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE BeginSession(
+ /* [in] */ __RPC__in_opt IMDSPDevice *pIDevice,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSizeCtx) BYTE *pCtx,
+ /* [in] */ DWORD dwSizeCtx) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndSession(
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSizeCtx) BYTE *pCtx,
+ /* [in] */ DWORD dwSizeCtx) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSecureQuery(
+ /* [out] */ __RPC__deref_out_opt ISCPSecureQuery **ppSecureQuery) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct ISCPSessionVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISCPSession * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISCPSession * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISCPSession * This);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginSession )(
+ ISCPSession * This,
+ /* [in] */ __RPC__in_opt IMDSPDevice *pIDevice,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSizeCtx) BYTE *pCtx,
+ /* [in] */ DWORD dwSizeCtx);
+
+ HRESULT ( STDMETHODCALLTYPE *EndSession )(
+ ISCPSession * This,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSizeCtx) BYTE *pCtx,
+ /* [in] */ DWORD dwSizeCtx);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSecureQuery )(
+ ISCPSession * This,
+ /* [out] */ __RPC__deref_out_opt ISCPSecureQuery **ppSecureQuery);
+
+ END_INTERFACE
+ } ISCPSessionVtbl;
+
+ interface ISCPSession
+ {
+ CONST_VTBL struct ISCPSessionVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISCPSession_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISCPSession_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISCPSession_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISCPSession_BeginSession(This,pIDevice,pCtx,dwSizeCtx) \
+ ( (This)->lpVtbl -> BeginSession(This,pIDevice,pCtx,dwSizeCtx) )
+
+#define ISCPSession_EndSession(This,pCtx,dwSizeCtx) \
+ ( (This)->lpVtbl -> EndSession(This,pCtx,dwSizeCtx) )
+
+#define ISCPSession_GetSecureQuery(This,ppSecureQuery) \
+ ( (This)->lpVtbl -> GetSecureQuery(This,ppSecureQuery) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISCPSession_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISCPSecureQuery3_INTERFACE_DEFINED__
+#define __ISCPSecureQuery3_INTERFACE_DEFINED__
+
+/* interface ISCPSecureQuery3 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISCPSecureQuery3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B7EDD1A2-4DAB-484b-B3C5-AD39B8B4C0B1")
+ ISCPSecureQuery3 : public ISCPSecureQuery2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetRightsOnClearChannel(
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStgGlobals,
+ /* [in] */ __RPC__in_opt IWMDMProgress3 *pProgressCallback,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE MakeDecisionOnClearChannel(
+ /* [in] */ UINT fuFlags,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ DWORD dwAppSec,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStorageGlobals,
+ /* [in] */ __RPC__in_opt IWMDMProgress3 *pProgressCallback,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwAppCertAppLen) BYTE *pAppCertApp,
+ /* [in] */ DWORD dwAppCertAppLen,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwAppCertSPLen) BYTE *pAppCertSP,
+ /* [in] */ DWORD dwAppCertSPLen,
+ /* [size_is][size_is][string][out][in] */ __RPC__deref_inout_ecount_full_opt_string(*pdwRevocationURLLen) LPWSTR *pszRevocationURL,
+ /* [ref][out][in] */ __RPC__inout DWORD *pdwRevocationURLLen,
+ /* [out] */ __RPC__out DWORD *pdwRevocationBitFlag,
+ /* [unique][out][in] */ __RPC__inout_opt ULONGLONG *pqwFileSize,
+ /* [in] */ __RPC__in_opt IUnknown *pUnknown,
+ /* [out] */ __RPC__deref_out_opt ISCPSecureExchange **ppExchange) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct ISCPSecureQuery3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISCPSecureQuery3 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISCPSecureQuery3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISCPSecureQuery3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDataDemands )(
+ ISCPSecureQuery3 * This,
+ /* [out] */ __RPC__out UINT *pfuFlags,
+ /* [out] */ __RPC__out DWORD *pdwMinRightsData,
+ /* [out] */ __RPC__out DWORD *pdwMinExamineData,
+ /* [out] */ __RPC__out DWORD *pdwMinDecideData,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ExamineData )(
+ ISCPSecureQuery3 * This,
+ /* [in] */ UINT fuFlags,
+ /* [unique][string][in] */ __RPC__in_opt LPWSTR pwszExtension,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *MakeDecision )(
+ ISCPSecureQuery3 * This,
+ /* [in] */ UINT fuFlags,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ DWORD dwAppSec,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStorageGlobals,
+ /* [out] */ __RPC__deref_out_opt ISCPSecureExchange **ppExchange,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRights )(
+ ISCPSecureQuery3 * This,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStgGlobals,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *MakeDecision2 )(
+ ISCPSecureQuery3 * This,
+ /* [in] */ UINT fuFlags,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ DWORD dwAppSec,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStorageGlobals,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwAppCertAppLen) BYTE *pAppCertApp,
+ /* [in] */ DWORD dwAppCertAppLen,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwAppCertSPLen) BYTE *pAppCertSP,
+ /* [in] */ DWORD dwAppCertSPLen,
+ /* [size_is][size_is][string][out][in] */ __RPC__deref_inout_ecount_full_opt_string(*pdwRevocationURLLen) LPWSTR *pszRevocationURL,
+ /* [ref][out][in] */ __RPC__inout DWORD *pdwRevocationURLLen,
+ /* [out] */ __RPC__out DWORD *pdwRevocationBitFlag,
+ /* [unique][out][in] */ __RPC__inout_opt ULONGLONG *pqwFileSize,
+ /* [in] */ __RPC__in_opt IUnknown *pUnknown,
+ /* [out] */ __RPC__deref_out_opt ISCPSecureExchange **ppExchange,
+ /* [out][in] */ __RPC__inout_ecount_full(WMDM_MAC_LENGTH) BYTE abMac[ 8 ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRightsOnClearChannel )(
+ ISCPSecureQuery3 * This,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStgGlobals,
+ /* [in] */ __RPC__in_opt IWMDMProgress3 *pProgressCallback,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pnRightsCount) PWMDMRIGHTS *ppRights,
+ /* [out] */ __RPC__out UINT *pnRightsCount);
+
+ HRESULT ( STDMETHODCALLTYPE *MakeDecisionOnClearChannel )(
+ ISCPSecureQuery3 * This,
+ /* [in] */ UINT fuFlags,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSize) BYTE *pData,
+ /* [in] */ DWORD dwSize,
+ /* [in] */ DWORD dwAppSec,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwSessionKeyLen) BYTE *pbSPSessionKey,
+ /* [in] */ DWORD dwSessionKeyLen,
+ /* [in] */ __RPC__in_opt IMDSPStorageGlobals *pStorageGlobals,
+ /* [in] */ __RPC__in_opt IWMDMProgress3 *pProgressCallback,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwAppCertAppLen) BYTE *pAppCertApp,
+ /* [in] */ DWORD dwAppCertAppLen,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwAppCertSPLen) BYTE *pAppCertSP,
+ /* [in] */ DWORD dwAppCertSPLen,
+ /* [size_is][size_is][string][out][in] */ __RPC__deref_inout_ecount_full_opt_string(*pdwRevocationURLLen) LPWSTR *pszRevocationURL,
+ /* [ref][out][in] */ __RPC__inout DWORD *pdwRevocationURLLen,
+ /* [out] */ __RPC__out DWORD *pdwRevocationBitFlag,
+ /* [unique][out][in] */ __RPC__inout_opt ULONGLONG *pqwFileSize,
+ /* [in] */ __RPC__in_opt IUnknown *pUnknown,
+ /* [out] */ __RPC__deref_out_opt ISCPSecureExchange **ppExchange);
+
+ END_INTERFACE
+ } ISCPSecureQuery3Vtbl;
+
+ interface ISCPSecureQuery3
+ {
+ CONST_VTBL struct ISCPSecureQuery3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISCPSecureQuery3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISCPSecureQuery3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISCPSecureQuery3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISCPSecureQuery3_GetDataDemands(This,pfuFlags,pdwMinRightsData,pdwMinExamineData,pdwMinDecideData,abMac) \
+ ( (This)->lpVtbl -> GetDataDemands(This,pfuFlags,pdwMinRightsData,pdwMinExamineData,pdwMinDecideData,abMac) )
+
+#define ISCPSecureQuery3_ExamineData(This,fuFlags,pwszExtension,pData,dwSize,abMac) \
+ ( (This)->lpVtbl -> ExamineData(This,fuFlags,pwszExtension,pData,dwSize,abMac) )
+
+#define ISCPSecureQuery3_MakeDecision(This,fuFlags,pData,dwSize,dwAppSec,pbSPSessionKey,dwSessionKeyLen,pStorageGlobals,ppExchange,abMac) \
+ ( (This)->lpVtbl -> MakeDecision(This,fuFlags,pData,dwSize,dwAppSec,pbSPSessionKey,dwSessionKeyLen,pStorageGlobals,ppExchange,abMac) )
+
+#define ISCPSecureQuery3_GetRights(This,pData,dwSize,pbSPSessionKey,dwSessionKeyLen,pStgGlobals,ppRights,pnRightsCount,abMac) \
+ ( (This)->lpVtbl -> GetRights(This,pData,dwSize,pbSPSessionKey,dwSessionKeyLen,pStgGlobals,ppRights,pnRightsCount,abMac) )
+
+
+#define ISCPSecureQuery3_MakeDecision2(This,fuFlags,pData,dwSize,dwAppSec,pbSPSessionKey,dwSessionKeyLen,pStorageGlobals,pAppCertApp,dwAppCertAppLen,pAppCertSP,dwAppCertSPLen,pszRevocationURL,pdwRevocationURLLen,pdwRevocationBitFlag,pqwFileSize,pUnknown,ppExchange,abMac) \
+ ( (This)->lpVtbl -> MakeDecision2(This,fuFlags,pData,dwSize,dwAppSec,pbSPSessionKey,dwSessionKeyLen,pStorageGlobals,pAppCertApp,dwAppCertAppLen,pAppCertSP,dwAppCertSPLen,pszRevocationURL,pdwRevocationURLLen,pdwRevocationBitFlag,pqwFileSize,pUnknown,ppExchange,abMac) )
+
+
+#define ISCPSecureQuery3_GetRightsOnClearChannel(This,pData,dwSize,pbSPSessionKey,dwSessionKeyLen,pStgGlobals,pProgressCallback,ppRights,pnRightsCount) \
+ ( (This)->lpVtbl -> GetRightsOnClearChannel(This,pData,dwSize,pbSPSessionKey,dwSessionKeyLen,pStgGlobals,pProgressCallback,ppRights,pnRightsCount) )
+
+#define ISCPSecureQuery3_MakeDecisionOnClearChannel(This,fuFlags,pData,dwSize,dwAppSec,pbSPSessionKey,dwSessionKeyLen,pStorageGlobals,pProgressCallback,pAppCertApp,dwAppCertAppLen,pAppCertSP,dwAppCertSPLen,pszRevocationURL,pdwRevocationURLLen,pdwRevocationBitFlag,pqwFileSize,pUnknown,ppExchange) \
+ ( (This)->lpVtbl -> MakeDecisionOnClearChannel(This,fuFlags,pData,dwSize,dwAppSec,pbSPSessionKey,dwSessionKeyLen,pStorageGlobals,pProgressCallback,pAppCertApp,dwAppCertAppLen,pAppCertSP,dwAppCertSPLen,pszRevocationURL,pdwRevocationURLLen,pdwRevocationBitFlag,pqwFileSize,pUnknown,ppExchange) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISCPSecureQuery3_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mswmdm_0000_0056 */
+/* [local] */
+
+#define SAC_MAC_LEN 8
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mswmdm_0000_0056_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mswmdm_0000_0056_v0_0_s_ifspec;
+
+#ifndef __IComponentAuthenticate_INTERFACE_DEFINED__
+#define __IComponentAuthenticate_INTERFACE_DEFINED__
+
+/* interface IComponentAuthenticate */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IComponentAuthenticate;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A9889C00-6D2B-11d3-8496-00C04F79DBC0")
+ IComponentAuthenticate : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SACAuth(
+ /* [in] */ DWORD dwProtocolID,
+ /* [in] */ DWORD dwPass,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwDataInLen) BYTE *pbDataIn,
+ /* [in] */ DWORD dwDataInLen,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pdwDataOutLen) BYTE **ppbDataOut,
+ /* [out] */ __RPC__out DWORD *pdwDataOutLen) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SACGetProtocols(
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pdwProtocolCount) DWORD **ppdwProtocols,
+ /* [out] */ __RPC__out DWORD *pdwProtocolCount) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IComponentAuthenticateVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IComponentAuthenticate * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IComponentAuthenticate * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IComponentAuthenticate * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SACAuth )(
+ IComponentAuthenticate * This,
+ /* [in] */ DWORD dwProtocolID,
+ /* [in] */ DWORD dwPass,
+ /* [size_is][in] */ __RPC__in_ecount_full(dwDataInLen) BYTE *pbDataIn,
+ /* [in] */ DWORD dwDataInLen,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pdwDataOutLen) BYTE **ppbDataOut,
+ /* [out] */ __RPC__out DWORD *pdwDataOutLen);
+
+ HRESULT ( STDMETHODCALLTYPE *SACGetProtocols )(
+ IComponentAuthenticate * This,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pdwProtocolCount) DWORD **ppdwProtocols,
+ /* [out] */ __RPC__out DWORD *pdwProtocolCount);
+
+ END_INTERFACE
+ } IComponentAuthenticateVtbl;
+
+ interface IComponentAuthenticate
+ {
+ CONST_VTBL struct IComponentAuthenticateVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IComponentAuthenticate_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IComponentAuthenticate_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IComponentAuthenticate_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IComponentAuthenticate_SACAuth(This,dwProtocolID,dwPass,pbDataIn,dwDataInLen,ppbDataOut,pdwDataOutLen) \
+ ( (This)->lpVtbl -> SACAuth(This,dwProtocolID,dwPass,pbDataIn,dwDataInLen,ppbDataOut,pdwDataOutLen) )
+
+#define IComponentAuthenticate_SACGetProtocols(This,ppdwProtocols,pdwProtocolCount) \
+ ( (This)->lpVtbl -> SACGetProtocols(This,ppdwProtocols,pdwProtocolCount) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IComponentAuthenticate_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mswmdm_0000_0057 */
+/* [local] */
+
+const GUID EVENT_WMDM_CONTENT_TRANSFER = { 0x339C9BF4, 0xBCFE, 0x4ED8, { 0x94, 0xDF, 0xEA, 0xF8, 0xC2, 0x6A, 0xB6, 0x1B } };
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mswmdm_0000_0057_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mswmdm_0000_0057_v0_0_s_ifspec;
+
+
+#ifndef __MSWMDMLib_LIBRARY_DEFINED__
+#define __MSWMDMLib_LIBRARY_DEFINED__
+
+/* library MSWMDMLib */
+/* [helpstring][version][uuid] */
+
+
+EXTERN_C const IID LIBID_MSWMDMLib;
+
+EXTERN_C const CLSID CLSID_MediaDevMgrClassFactory;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("50040C1D-BDBF-4924-B873-F14D6C5BFD66")
+MediaDevMgrClassFactory;
+#endif
+
+EXTERN_C const CLSID CLSID_MediaDevMgr;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("25BAAD81-3560-11D3-8471-00C04F79DBC0")
+MediaDevMgr;
+#endif
+
+EXTERN_C const CLSID CLSID_WMDMDevice;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("807B3CDF-357A-11d3-8471-00C04F79DBC0")
+WMDMDevice;
+#endif
+
+EXTERN_C const CLSID CLSID_WMDMStorage;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("807B3CE0-357A-11d3-8471-00C04F79DBC0")
+WMDMStorage;
+#endif
+
+EXTERN_C const CLSID CLSID_WMDMStorageGlobal;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("807B3CE1-357A-11d3-8471-00C04F79DBC0")
+WMDMStorageGlobal;
+#endif
+
+EXTERN_C const CLSID CLSID_WMDMDeviceEnum;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("430E35AF-3971-11D3-8474-00C04F79DBC0")
+WMDMDeviceEnum;
+#endif
+
+EXTERN_C const CLSID CLSID_WMDMStorageEnum;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("EB401A3B-3AF7-11d3-8474-00C04F79DBC0")
+WMDMStorageEnum;
+#endif
+#endif /* __MSWMDMLib_LIBRARY_DEFINED__ */
+
+/* Additional Prototypes for ALL interfaces */
+
+unsigned long __RPC_USER BSTR_UserSize( unsigned long *, unsigned long , BSTR * );
+unsigned char * __RPC_USER BSTR_UserMarshal( unsigned long *, unsigned char *, BSTR * );
+unsigned char * __RPC_USER BSTR_UserUnmarshal(unsigned long *, unsigned char *, BSTR * );
+void __RPC_USER BSTR_UserFree( unsigned long *, BSTR * );
+
+unsigned long __RPC_USER LPSAFEARRAY_UserSize( unsigned long *, unsigned long , LPSAFEARRAY * );
+unsigned char * __RPC_USER LPSAFEARRAY_UserMarshal( unsigned long *, unsigned char *, LPSAFEARRAY * );
+unsigned char * __RPC_USER LPSAFEARRAY_UserUnmarshal(unsigned long *, unsigned char *, LPSAFEARRAY * );
+void __RPC_USER LPSAFEARRAY_UserFree( unsigned long *, LPSAFEARRAY * );
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/Src/Plugins/Portable/pmp_p4s/mswmdm_i.c b/Src/Plugins/Portable/pmp_p4s/mswmdm_i.c
new file mode 100644
index 00000000..6f05026a
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/mswmdm_i.c
@@ -0,0 +1,269 @@
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 7.00.0498 */
+/* Compiler settings for mswmdm.idl:
+ Oicf, W1, Zp8, env=Win32 (32b run)
+ protocol : dce , ms_ext, c_ext, robust
+ error checks: allocation ref bounds_check enum stub_data
+ VC __declspec() decoration level:
+ __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+ DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+//@@MIDL_FILE_HEADING( )
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMMetaData,0xEC3B0663,0x0951,0x460a,0x9A,0x80,0x0D,0xCE,0xED,0x3C,0x04,0x3C);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDeviceManager,0x1DCB3A00,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDeviceManager2,0x923E5249,0x8731,0x4c5b,0x9B,0x1C,0xB8,0xB6,0x0B,0x6E,0x46,0xAF);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDeviceManager3,0xaf185c41,0x100d,0x46ed,0xbe,0x2e,0x9c,0xe8,0xc4,0x45,0x94,0xef);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMStorageGlobals,0x1DCB3A07,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMStorage,0x1DCB3A06,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMStorage2,0x1ED5A144,0x5CD5,0x4683,0x9E,0xFF,0x72,0xCB,0xDB,0x2D,0x95,0x33);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMStorage3,0x97717EEA,0x926A,0x464e,0x96,0xA4,0x24,0x7B,0x02,0x16,0x02,0x6E);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMStorage4,0xc225bac5,0xa03a,0x40b8,0x9a,0x23,0x91,0xcf,0x47,0x8c,0x64,0xa6);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMOperation,0x1DCB3A0B,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMOperation2,0x33445B48,0x7DF7,0x425c,0xAD,0x8F,0x0F,0xC6,0xD8,0x2F,0x9F,0x75);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMOperation3,0xd1f9b46a,0x9ca8,0x46d8,0x9d,0x0f,0x1e,0xc9,0xba,0xe5,0x49,0x19);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMProgress,0x1DCB3A0C,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMProgress2,0x3A43F550,0xB383,0x4e92,0xB0,0x4A,0xE6,0xBB,0xC6,0x60,0xFE,0xFC);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMProgress3,0x21DE01CB,0x3BB4,0x4929,0xB2,0x1A,0x17,0xAF,0x3F,0x80,0xF6,0x58);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMDevice,0x1DCB3A02,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMDevice2,0xE34F3D37,0x9D67,0x4fc1,0x92,0x52,0x62,0xD2,0x8B,0x2F,0x8B,0x55);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMDevice3,0x6c03e4fe,0x05db,0x4dda,0x9e,0x3c,0x06,0x23,0x3a,0x6d,0x5d,0x65);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMDeviceSession,0x82af0a65,0x9d96,0x412c,0x83,0xe5,0x3c,0x43,0xe4,0xb0,0x6c,0xc7);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMEnumDevice,0x1DCB3A01,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMDeviceControl,0x1DCB3A04,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMEnumStorage,0x1DCB3A05,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMStorageControl,0x1DCB3A08,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMStorageControl2,0x972C2E88,0xBD6C,0x4125,0x8E,0x09,0x84,0xF8,0x37,0xE6,0x37,0xB6);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMStorageControl3,0xB3266365,0xD4F3,0x4696,0x8D,0x53,0xBD,0x27,0xEC,0x60,0x99,0x3A);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMObjectInfo,0x1DCB3A09,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMRevoked,0xEBECCEDB,0x88EE,0x4e55,0xB6,0xA4,0x8D,0x9F,0x07,0xD6,0x96,0xAA);
+
+
+MIDL_DEFINE_GUID(IID, IID_IWMDMNotification,0x3F5E95C0,0x0F43,0x4ed4,0x93,0xD2,0xC8,0x9A,0x45,0xD5,0x9B,0x81);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDServiceProvider,0x1DCB3A10,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDServiceProvider2,0xB2FA24B7,0xCDA3,0x4694,0x98,0x62,0x41,0x3A,0xE1,0xA3,0x48,0x19);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDServiceProvider3,0x4ed13ef3,0xa971,0x4d19,0x9f,0x51,0x0e,0x18,0x26,0xb2,0xda,0x57);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPEnumDevice,0x1DCB3A11,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPDevice,0x1DCB3A12,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPDevice2,0x420D16AD,0xC97D,0x4e00,0x82,0xAA,0x00,0xE9,0xF4,0x33,0x5D,0xDD);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPDevice3,0x1a839845,0xfc55,0x487c,0x97,0x6f,0xee,0x38,0xac,0x0e,0x8c,0x4e);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPDeviceControl,0x1DCB3A14,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPEnumStorage,0x1DCB3A15,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPStorage,0x1DCB3A16,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPStorage2,0x0A5E07A5,0x6454,0x4451,0x9C,0x36,0x1C,0x6A,0xE7,0xE2,0xB1,0xD6);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPStorage3,0x6C669867,0x97ED,0x4a67,0x97,0x06,0x1C,0x55,0x29,0xD2,0xA4,0x14);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPStorage4,0x3133b2c4,0x515c,0x481b,0xb1,0xce,0x39,0x32,0x7e,0xcb,0x4f,0x74);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPStorageGlobals,0x1DCB3A17,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPObjectInfo,0x1DCB3A19,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPObject,0x1DCB3A18,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPObject2,0x3f34cd3e,0x5907,0x4341,0x9a,0xf9,0x97,0xf4,0x18,0x7c,0x3a,0xa5);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPDirectTransfer,0xc2fe57a8,0x9304,0x478c,0x9e,0xe4,0x47,0xe3,0x97,0xb9,0x12,0xd7);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMDSPRevoked,0xA4E8F2D4,0x3F31,0x464d,0xB5,0x3D,0x4F,0xC3,0x35,0x99,0x81,0x84);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISCPSecureAuthenticate,0x1DCB3A0F,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISCPSecureAuthenticate2,0xB580CFAE,0x1672,0x47e2,0xAC,0xAA,0x44,0xBB,0xEC,0xBC,0xAE,0x5B);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISCPSecureQuery,0x1DCB3A0D,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISCPSecureQuery2,0xEBE17E25,0x4FD7,0x4632,0xAF,0x46,0x6D,0x93,0xD4,0xFC,0xC7,0x2E);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISCPSecureExchange,0x1DCB3A0E,0x33ED,0x11d3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISCPSecureExchange2,0x6C62FC7B,0x2690,0x483F,0x9D,0x44,0x0A,0x20,0xCB,0x35,0x57,0x7C);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISCPSecureExchange3,0xab4e77e4,0x8908,0x4b17,0xbd,0x2a,0xb1,0xdb,0xe6,0xdd,0x69,0xe1);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISCPSession,0x88a3e6ed,0xeee4,0x4619,0xbb,0xb3,0xfd,0x4f,0xb6,0x27,0x15,0xd1);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISCPSecureQuery3,0xB7EDD1A2,0x4DAB,0x484b,0xB3,0xC5,0xAD,0x39,0xB8,0xB4,0xC0,0xB1);
+
+
+MIDL_DEFINE_GUID(IID, IID_IComponentAuthenticate,0xA9889C00,0x6D2B,0x11d3,0x84,0x96,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, LIBID_MSWMDMLib,0x6EC6C744,0x355F,0x11D3,0x84,0x70,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_MediaDevMgrClassFactory,0x50040C1D,0xBDBF,0x4924,0xB8,0x73,0xF1,0x4D,0x6C,0x5B,0xFD,0x66);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_MediaDevMgr,0x25BAAD81,0x3560,0x11D3,0x84,0x71,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_WMDMDevice,0x807B3CDF,0x357A,0x11d3,0x84,0x71,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_WMDMStorage,0x807B3CE0,0x357A,0x11d3,0x84,0x71,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_WMDMStorageGlobal,0x807B3CE1,0x357A,0x11d3,0x84,0x71,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_WMDMDeviceEnum,0x430E35AF,0x3971,0x11D3,0x84,0x74,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_WMDMStorageEnum,0xEB401A3B,0x3AF7,0x11d3,0x84,0x74,0x00,0xC0,0x4F,0x79,0xDB,0xC0);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/Src/Plugins/Portable/pmp_p4s/pmp_p4s.rc b/Src/Plugins/Portable/pmp_p4s/pmp_p4s.rc
new file mode 100644
index 00000000..4c0344b6
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/pmp_p4s.rc
@@ -0,0 +1,91 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource1.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource1.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""version.rc2""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_NULLSOFT_P4S_PLUGIN "Nullsoft PlaysForSure Plug-in v%s"
+ 65535 "{01C3E74C-261E-45e2-AA30-ED4039DCD3A2}"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_TRANSFERRING_PERCENT "Transferring %d%%"
+ IDS_LOADING "Loading %s..."
+ IDS_COUND_NOT_CREATE_FOLDER "Error: Could not create folder on device"
+ IDS_COULD_NOT_CREATE_METADATA "Error: Could not create metadata: %x"
+ IDS_INCOMPATABLE_DEVICE "Incompatable device"
+ IDS_ERROR_IN_INSERT "Error in Insert: %x"
+ IDS_UNSPECIFIED_ERROR "Unspecified Error"
+ IDS_WAITING_FOR_OTHER_TRANSFERS "Waiting for other transfers to finish..."
+ IDS_TRANSFERRING "Transferring..."
+ IDS_DONE "Done"
+ IDS_WAITING "Waiting..."
+ IDS_FAILED "Failed"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc2"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/Plugins/Portable/pmp_p4s/pmp_p4s.vcxproj b/Src/Plugins/Portable/pmp_p4s/pmp_p4s.vcxproj
new file mode 100644
index 00000000..60109e81
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/pmp_p4s.vcxproj
@@ -0,0 +1,434 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>17.0</VCProjectVersion>
+ <ProjectGuid>{2EAD12FA-51FE-4AB6-A0C8-3952209AA81F}</ProjectGuid>
+ <RootNamespace>pmp_p4s</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <UseOfMfc>false</UseOfMfc>
+ <UseOfAtl>false</UseOfAtl>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <UseOfMfc>false</UseOfMfc>
+ <UseOfAtl>false</UseOfAtl>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <UseOfMfc>false</UseOfMfc>
+ <UseOfAtl>false</UseOfAtl>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <UseOfMfc>false</UseOfMfc>
+ <UseOfAtl>false</UseOfAtl>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>17.0.32505.173</_ProjectFileVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <LinkIncremental>false</LinkIncremental>
+ <GenerateManifest>false</GenerateManifest>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <GenerateManifest>false</GenerateManifest>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg">
+ <VcpkgEnableManifest>false</VcpkgEnableManifest>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Vcpkg">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Vcpkg">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>false</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>$(IntDir)$(TargetName).tlb</TypeLibraryName>
+ <HeaderFileName />
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\..\replicant;..\..\..\Wasabi;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;UNICODE;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MinimalRebuild>false</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeader />
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>sehupd.lib;mssachlp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <DelayLoadDLLs>tataki.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapExports>false</MapExports>
+ <BaseAddress>0x14C00000</BaseAddress>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention />
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>false</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TypeLibraryName>$(IntDir)$(TargetName).tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\..\replicant;..\..\..\Wasabi;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;UNICODE;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MinimalRebuild>false</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>sehupd.lib;mssachlp.lib;fmtd.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <DelayLoadDLLs>tataki.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapExports>false</MapExports>
+ <BaseAddress>0x14C00000</BaseAddress>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>..\..\..\external_dependencies\vcpkg\buildtrees\fmt\$(PlatformShortName)-windows-dbg;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>$(IntDir)$(TargetName).tlb</TypeLibraryName>
+ <HeaderFileName />
+ </Midl>
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\..\replicant;..\..\..\Wasabi;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ <PrecompiledHeader />
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>sehupd.lib;mssachlp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <DelayLoadDLLs>tataki.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TypeLibraryName>$(IntDir)$(TargetName).tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\..\replicant;..\..\..\Wasabi;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>sehupd.lib;mssachlp.lib;fmt.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <DelayLoadDLLs>tataki.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>..\..\..\external_dependencies\vcpkg\buildtrees\fmt\$(PlatformShortName)-windows-rel;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\tataki\tataki.vcxproj">
+ <Project>{255b68b5-7ef8-45ef-a675-2d6b88147909}</Project>
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Wasabi\bfc\bfc.vcxproj">
+ <Project>{d0ec862e-dddd-4f4f-934f-b75dc9062dc1}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
+ <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\WAT\WAT.vcxproj">
+ <Project>{c5714908-a71f-4644-bd95-aad8ee7914da}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\General\gen_ml\itemlist.cpp" />
+ <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp" />
+ <ClCompile Include="deviceprovider.cpp" />
+ <ClCompile Include="key-sub-523.c" />
+ <ClCompile Include="main.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;ML_ex_EXPORTS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;ML_ex_EXPORTS</PreprocessorDefinitions>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
+ <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;ML_ex_EXPORTS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;ML_ex_EXPORTS</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="MyProgress.cpp" />
+ <ClCompile Include="P4SDevice.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="mssachlp.lib" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\General\gen_ml\itemlist.h" />
+ <ClInclude Include="..\..\General\gen_ml\ml.h" />
+ <ClInclude Include="..\..\Library\ml_pmp\AutoChar.h" />
+ <ClInclude Include="..\..\Library\ml_pmp\AutoWide.h" />
+ <ClInclude Include="..\..\Library\ml_pmp\pmp.h" />
+ <ClInclude Include="deviceprovider.h" />
+ <ClInclude Include="mswmdm.h" />
+ <ClInclude Include="MyProgress.h" />
+ <ClInclude Include="P4SDevice.h" />
+ <ClInclude Include="resource1.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="resources\creativeZenIcon.png" />
+ <Image Include="resources\nokiaIcon.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="pmp_p4s.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_p4s/pmp_p4s.vcxproj.filters b/Src/Plugins/Portable/pmp_p4s/pmp_p4s.vcxproj.filters
new file mode 100644
index 00000000..0ee77cc5
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/pmp_p4s.vcxproj.filters
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{26c4de59-6800-4e2e-ae56-f878113f2e65}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{c6299fac-f519-4ddb-9e8d-125e8f8a9fd0}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{584fb53f-22c8-454e-b344-1b279c0f2448}</UniqueIdentifier>
+ <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>
+ </Filter>
+ <Filter Include="Image Files">
+ <UniqueIdentifier>{8d672363-3c3f-4b3c-abdf-fa0e9c29023d}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="deviceprovider.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="key-sub-523.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="MyProgress.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="P4SDevice.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\General\gen_ml\itemlist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="deviceprovider.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="mswmdm.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="MyProgress.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="P4SDevice.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource1.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\General\gen_ml\itemlist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\General\gen_ml\ml.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Library\ml_pmp\AutoChar.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Library\ml_pmp\AutoWide.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Library\ml_pmp\pmp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="resources\nokiaIcon.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resources\creativeZenIcon.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="pmp_p4s.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="mssachlp.lib">
+ <Filter>Resource Files</Filter>
+ </CustomBuild>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_p4s/resource1.h b/Src/Plugins/Portable/pmp_p4s/resource1.h
new file mode 100644
index 00000000..eebb7234
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/resource1.h
@@ -0,0 +1,31 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by pmp_p4s1.rc
+//
+#define IDS_TRANSFERRING_PERCENT 1
+#define IDS_LOADING 2
+#define IDS_COUND_NOT_CREATE_FOLDER 3
+#define IDS_COULD_NOT_CREATE_METADATA 4
+#define IDS_INCOMPATIBLE_DEVICE 5
+#define IDS_INCOMPATABLE_DEVICE 5
+#define IDS_ERROR_IN_INSERT 6
+#define IDS_UNSPECIFIED_ERROR 7
+#define IDS_WAITING_FOR_OTHER_TRANSFERS 8
+#define IDS_TRANSFERRING 9
+#define IDS_DONE 10
+#define IDS_WAITING 11
+#define IDS_FAILED 12
+#define IDR_CREATIVE_ZEN_ICON 102
+#define IDR_NOKIA_ICON 103
+#define IDS_NULLSOFT_P4S_PLUGIN 65534
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 107
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/Plugins/Portable/pmp_p4s/resources/creativeZenIcon.png b/Src/Plugins/Portable/pmp_p4s/resources/creativeZenIcon.png
new file mode 100644
index 00000000..7352c626
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/resources/creativeZenIcon.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_p4s/resources/nokiaIcon.png b/Src/Plugins/Portable/pmp_p4s/resources/nokiaIcon.png
new file mode 100644
index 00000000..b050357e
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/resources/nokiaIcon.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_p4s/sac.h b/Src/Plugins/Portable/pmp_p4s/sac.h
new file mode 100644
index 00000000..c1e3c267
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/sac.h
@@ -0,0 +1,26 @@
+//
+// Microsoft Windows Media Technologies
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+
+#ifndef __SAC_H__
+#define __SAC_H__
+
+typedef DWORD HMAC;
+
+#define RSA_KEY_LEN 64
+#define SAC_SESSION_KEYLEN 8
+
+#define SAC_PROTOCOL_WMDM 1
+#define SAC_PROTOCOL_V1 2
+
+#define SAC_CERT_X509 1
+#define SAC_CERT_V1 2
+
+typedef struct __MACINFO
+{
+ BOOL fUsed;
+ BYTE abMacState[36];
+} MACINFO;
+
+#endif //__SAC_H__ \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_p4s/scclient.h b/Src/Plugins/Portable/pmp_p4s/scclient.h
new file mode 100644
index 00000000..9a181e7b
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/scclient.h
@@ -0,0 +1,73 @@
+//
+// Microsoft Windows Media Technologies
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+
+#ifndef _CSECURECHANNELCLIENT_H_2AD99356_6FD2_11d3_8497_00C04F79DBC0
+#define _CSECURECHANNELCLIENT_H_2AD99356_6FD2_11d3_8497_00C04F79DBC0
+
+#include "wtypes.h"
+
+#ifdef USE_X509
+#include "rsa.h"
+#endif
+
+#ifdef USE_X509
+#include "x509cert.h"
+#endif
+
+#include "sac.h"
+
+class CSecureChannelClient
+{
+public:
+ CSecureChannelClient();
+ ~CSecureChannelClient();
+ HRESULT SetCertificate(DWORD dwFlags,
+ BYTE *pbAppCert,
+ DWORD dwCertLen,
+ BYTE *pbAppPVK,
+ DWORD dwPVKLen);
+ void SetInterface(IComponentAuthenticate *pComponentAuth);
+ HRESULT Authenticate(DWORD dwProtocolID);
+ HRESULT EncryptParam(BYTE *pbData,
+ DWORD dwDataLen);
+ HRESULT DecryptParam(BYTE *pbData,
+ DWORD dwDataLen);
+ HRESULT MACInit(HMAC *phMAC);
+ HRESULT MACUpdate(HMAC hMAC,
+ BYTE *pbData,
+ DWORD dwDataLen);
+ HRESULT MACFinal(HMAC hMAC,
+ BYTE abData[SAC_MAC_LEN]);
+ HRESULT GetAppSec(DWORD *pdwLocalAppSec, DWORD *pdwRemoteAppSec);
+ HRESULT SetSessionKey(BYTE *pbSPSessionKey);
+ HRESULT GetSessionKey(BYTE *pbSPSessionKey);
+ HRESULT GetRemoteAppCert(BYTE *pbAppCert, DWORD* pdwCertLen);
+ BOOL fIsAuthenticated();
+private:
+ BOOL m_fAuthenticated;
+ BYTE *m_pbAppCert;
+ DWORD m_dwCertLen;
+ BYTE *m_pbRemoteCert;
+ DWORD m_dwRemoteCertLen;
+ BYTE *m_pbAppPVK;
+ DWORD m_dwPVKLen;
+ BYTE *m_pbSessionKey;
+ DWORD m_dwSessionKeyLen;
+ BOOL m_TableInit;
+ unsigned long m_DesTable[32];
+ IComponentAuthenticate *m_pAuth;
+ DWORD m_dwCertFlags;
+#ifdef USE_X509
+ CX509Cert m_CertObj;
+#endif
+ MACINFO aMacInfo[20];
+ BYTE m_abMacKey[64];
+ BOOL m_fMacKeyInit;
+ CRITICAL_SECTION m_CS;
+ HRESULT Protocol1();
+ HRESULT Protocol2();
+};
+
+#endif // _CSECURECHANNELCLIENT_H_2AD99356-6FD2-11d3-8497-00C04F79DBC0 \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_p4s/sehupd.lib b/Src/Plugins/Portable/pmp_p4s/sehupd.lib
new file mode 100644
index 00000000..a9ebd938
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/sehupd.lib
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_p4s/version.rc2 b/Src/Plugins/Portable/pmp_p4s/version.rc2
new file mode 100644
index 00000000..cb0e4351
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/version.rc2
@@ -0,0 +1,39 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#include "../../../Winamp/buildType.h"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,99,1,0
+ PRODUCTVERSION WINAMP_PRODUCTVER
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Winamp SA"
+ VALUE "FileDescription", "Winamp Portable Device Plug-in"
+ VALUE "FileVersion", "0,99,1,0"
+ VALUE "InternalName", "Nullsoft PlaysForSure"
+ VALUE "LegalCopyright", "Copyright © 2006-2023 Winamp SA"
+ VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
+ VALUE "OriginalFilename", "pmp_p4s.dll"
+ VALUE "ProductName", "Winamp"
+ VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/Src/Plugins/Portable/pmp_p4s/wmdm.chm b/Src/Plugins/Portable/pmp_p4s/wmdm.chm
new file mode 100644
index 00000000..5b8bea70
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_p4s/wmdm.chm
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_usb/albumart.cpp b/Src/Plugins/Portable/pmp_usb/albumart.cpp
new file mode 100644
index 00000000..7d3a26a7
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/albumart.cpp
@@ -0,0 +1,58 @@
+#include "../../Library/ml_pmp/pmp.h"
+#include "api.h"
+#include "../agave/albumart/svc_albumartprovider.h"
+#include <api/service/waservicefactory.h>
+
+extern PMPDevicePlugin plugin;
+
+static svc_albumArtProvider *FindProvider(const wchar_t *filename, int providerType, waServiceFactory **factory)
+{
+ FOURCC albumartprovider = svc_albumArtProvider::getServiceType();
+ int n = (int)plugin.service->service_getNumServices(albumartprovider);
+ for (int i=0; i<n; i++)
+ {
+ waServiceFactory *sf = plugin.service->service_enumService(albumartprovider,i);
+ if (sf)
+ {
+ svc_albumArtProvider * provider = (svc_albumArtProvider*)sf->getInterface();
+ if (provider)
+ {
+ if (provider->ProviderType() == providerType && provider->IsMine(filename))
+ {
+ *factory = sf;
+ return provider;
+ }
+ sf->releaseInterface(provider);
+ }
+ }
+ }
+ return NULL;
+}
+
+void CopyAlbumArt(const wchar_t *source, const wchar_t *destination)
+{
+ size_t datalen = 0;
+ void *data = 0;
+ wchar_t *mimeType = 0;
+ waServiceFactory *destinationFactory = 0;
+ svc_albumArtProvider *destinationProvider = FindProvider(destination, ALBUMARTPROVIDER_TYPE_EMBEDDED, &destinationFactory);
+ if (destinationFactory)
+ {
+ /* First, look to see if there's already embedded album art */
+ if (destinationProvider->GetAlbumArtData(destination, L"cover", &data, &datalen, &mimeType) == ALBUMARTPROVIDER_SUCCESS && data && datalen)
+ {
+ destinationFactory->releaseInterface(destinationProvider);
+ WASABI_API_MEMMGR->sysFree(data);
+ WASABI_API_MEMMGR->sysFree(mimeType);
+ return;
+ }
+ else if (AGAVE_API_ALBUMART->GetAlbumArtData(source, L"cover", &data, &datalen, &mimeType) == ALBUMART_SUCCESS && data && datalen)
+ {
+ destinationProvider->SetAlbumArtData(destination, L"cover", data, datalen, mimeType);
+ WASABI_API_MEMMGR->sysFree(data);
+ WASABI_API_MEMMGR->sysFree(mimeType);
+
+ destinationFactory->releaseInterface(destinationProvider);
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_usb/api.cpp b/Src/Plugins/Portable/pmp_usb/api.cpp
new file mode 100644
index 00000000..8e5dcee4
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/api.cpp
@@ -0,0 +1,64 @@
+#include "../../Library/ml_pmp/pmp.h"
+#include "api.h"
+#include <api/service/waservicefactory.h>
+
+api_language *WASABI_API_LNG = 0;
+HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
+extern PMPDevicePlugin plugin;
+
+// Metadata service
+api_metadata *AGAVE_API_METADATA=0;
+api_playlistmanager *WASABI_API_PLAYLISTMNGR=0;
+api_albumart *AGAVE_API_ALBUMART=0;
+api_memmgr *WASABI_API_MEMMGR=0;
+api_application *WASABI_API_APP=0;
+api_threadpool *WASABI_API_THREADPOOL=0;
+api_devicemanager *AGAVE_API_DEVICEMANAGER = 0;
+
+
+template <class api_T>
+void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
+{
+ if (plugin.service)
+ {
+ waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
+ if (factory)
+ api_t = reinterpret_cast<api_T *>( factory->getInterface() );
+ }
+}
+
+template <class api_T>
+void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
+{
+ if (plugin.service && api_t)
+ {
+ waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
+ if (factory)
+ factory->releaseInterface(api_t);
+ }
+ api_t = NULL;
+}
+
+void WasabiInit()
+{
+ ServiceBuild(WASABI_API_LNG, languageApiGUID);
+ ServiceBuild(AGAVE_API_METADATA, api_metadataGUID);
+ ServiceBuild(WASABI_API_PLAYLISTMNGR, api_playlistmanagerGUID);
+ ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
+ ServiceBuild(AGAVE_API_ALBUMART, albumArtGUID);
+ ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ ServiceBuild(WASABI_API_THREADPOOL, ThreadPoolGUID);
+ ServiceBuild(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
+}
+
+void WasabiQuit()
+{
+ ServiceRelease(WASABI_API_LNG, languageApiGUID);
+ ServiceRelease(WASABI_API_PLAYLISTMNGR, api_playlistmanagerGUID);
+ ServiceRelease(WASABI_API_APP, applicationApiServiceGuid);
+ ServiceRelease(AGAVE_API_METADATA, api_metadataGUID);
+ ServiceRelease(AGAVE_API_ALBUMART, albumArtGUID);
+ ServiceRelease(WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ ServiceRelease(WASABI_API_THREADPOOL, ThreadPoolGUID);
+ ServiceRelease(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_usb/api.h b/Src/Plugins/Portable/pmp_usb/api.h
new file mode 100644
index 00000000..f7cfd662
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/api.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "../Agave/Language/api_language.h"
+
+#include "../Agave/Metadata/api_metadata.h"
+extern api_metadata *metadataApi;
+#define AGAVE_API_METADATA metadataApi
+
+#include "../playlist/api_playlistmanager.h"
+extern api_playlistmanager *playlistManagerApi;
+#define WASABI_API_PLAYLISTMNGR playlistManagerApi
+
+#include "../nu/threadpool/api_threadpool.h"
+extern api_threadpool *threadPoolApi;
+#define WASABI_API_THREADPOOL threadPoolApi
+
+#include "../Agave/AlbumArt/api_albumart.h"
+extern api_albumart *albumArtApi;
+#define AGAVE_API_ALBUMART albumArtApi
+
+#include <api/memmgr/api_memmgr.h>
+extern api_memmgr *memmgr;
+#define WASABI_API_MEMMGR memmgr
+
+#include <api/application/api_application.h>
+extern api_application *applicationApi;
+#define WASABI_API_APP applicationApi
+
+#include "../devices/api_devicemanager.h"
+extern api_devicemanager *deviceManagerApi;
+#define AGAVE_API_DEVICEMANAGER deviceManagerApi
+
+void WasabiInit();
+void WasabiQuit();
diff --git a/Src/Plugins/Portable/pmp_usb/deviceprovider.cpp b/Src/Plugins/Portable/pmp_usb/deviceprovider.cpp
new file mode 100644
index 00000000..05e73d21
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/deviceprovider.cpp
@@ -0,0 +1,343 @@
+#include "api.h"
+#include "./deviceprovider.h"
+#include "../devices/api_devicemanager.h"
+
+extern PMPDevicePlugin plugin;
+void connectDrive(wchar_t drive, bool checkSize, bool checkBlacklist);
+
+static size_t tlsIndex = (size_t)-1;
+
+static BOOL
+DiscoveryProvider_RegisterCancelSwitch(BOOL *cancelSwitch)
+{
+ if ((size_t)-1 != tlsIndex &&
+ NULL != WASABI_API_APP)
+ {
+ WASABI_API_APP->SetThreadStorage(tlsIndex, cancelSwitch);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static BOOL
+DiscoveryProvider_GetCancelSwitchOn()
+{
+ if ((size_t)-1 != tlsIndex &&
+ NULL != WASABI_API_APP)
+ {
+ BOOL *cancelSwitch = (BOOL*)WASABI_API_APP->GetThreadStorage(tlsIndex);
+ if (NULL != cancelSwitch &&
+ FALSE != *cancelSwitch)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+DeviceProvider_DriverEnumCb(wchar_t drive, unsigned int type)
+{
+ if (DRIVE_REMOVABLE == type &&
+ FALSE == DiscoveryProvider_GetCancelSwitchOn())
+ {
+ connectDrive(drive,true,true);
+ }
+}
+
+DeviceProvider::DeviceProvider()
+ : ref(1), activity(0), manager(NULL), readyEvent(NULL), cancelDiscovery(FALSE)
+{
+ InitializeCriticalSection(&lock);
+ enumerator = (ENUMDRIVES)SendMessageW(plugin.hwndPortablesParent,
+ WM_PMP_IPC, 0, PMP_IPC_ENUM_ACTIVE_DRIVES);
+}
+
+DeviceProvider::~DeviceProvider()
+{
+ CancelDiscovery();
+
+ if (NULL != readyEvent)
+ CloseHandle(readyEvent);
+
+ DeleteCriticalSection(&lock);
+}
+
+HRESULT DeviceProvider::CreateInstance(DeviceProvider **instance)
+{
+ if (NULL == instance)
+ return E_POINTER;
+
+ *instance = new DeviceProvider();
+
+ if (NULL == *instance)
+ return E_OUTOFMEMORY;
+
+ return S_OK;
+}
+
+size_t DeviceProvider::AddRef()
+{
+ return InterlockedIncrement((LONG*)&ref);
+}
+
+size_t DeviceProvider::Release()
+{
+ if (0 == ref)
+ return ref;
+
+ LONG r = InterlockedDecrement((LONG*)&ref);
+ if (0 == r)
+ delete(this);
+
+ return r;
+}
+
+int DeviceProvider::QueryInterface(GUID interface_guid, void **object)
+{
+ if (NULL == object)
+ return E_POINTER;
+
+ if (IsEqualIID(interface_guid, IFC_DeviceProvider))
+ *object = static_cast<ifc_deviceprovider*>(this);
+ else
+ {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+
+ if (NULL == *object)
+ return E_UNEXPECTED;
+
+ AddRef();
+ return S_OK;
+}
+
+void DeviceProvider::Lock()
+{
+ EnterCriticalSection(&lock);
+}
+
+void DeviceProvider::Unlock()
+{
+ LeaveCriticalSection(&lock);
+}
+
+DWORD DeviceProvider::DiscoveryThread()
+{
+ IncrementActivity();
+
+ if (NULL != enumerator &&
+ FALSE == cancelDiscovery)
+ {
+ DiscoveryProvider_RegisterCancelSwitch(&cancelDiscovery);
+
+ enumerator(DeviceProvider_DriverEnumCb);
+
+ DiscoveryProvider_RegisterCancelSwitch(NULL);
+ }
+
+ DecrementActivity();
+
+ Lock();
+
+ if (NULL != readyEvent)
+ SetEvent(readyEvent);
+
+ Unlock();
+
+
+ return 0;
+}
+
+static int DeviceProvider_DiscoveryThreadStarter(HANDLE handle, void *user, intptr_t id)
+{
+ DeviceProvider *self;
+ DWORD result;
+
+ self = (DeviceProvider*)user;
+
+ if (NULL != self)
+ result = self->DiscoveryThread();
+ else
+ result = -2;
+
+ return result;
+}
+
+HRESULT DeviceProvider::BeginDiscovery(api_devicemanager *manager)
+{
+ HRESULT hr;
+
+ if (NULL == enumerator)
+ return E_UNEXPECTED;
+
+ Lock();
+
+ if (NULL != readyEvent &&
+ WAIT_TIMEOUT == WaitForSingleObject(readyEvent, 0))
+ {
+ hr = E_PENDING;
+ }
+ else
+ {
+ hr = S_OK;
+
+ if (NULL == readyEvent)
+ {
+ readyEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (NULL == readyEvent)
+ hr = E_FAIL;
+ }
+
+ if ((size_t)-1 == tlsIndex &&
+ NULL != WASABI_API_APP)
+ {
+ tlsIndex = WASABI_API_APP->AllocateThreadStorage();
+ }
+
+ if (SUCCEEDED(hr))
+ {
+
+ cancelDiscovery = FALSE;
+ ResetEvent(readyEvent);
+
+ if (0 != WASABI_API_THREADPOOL->RunFunction(0, DeviceProvider_DiscoveryThreadStarter,
+ this, 0, api_threadpool::FLAG_LONG_EXECUTION))
+ {
+
+ SetEvent(readyEvent);
+ hr = E_FAIL;
+ }
+ }
+ }
+
+ Unlock();
+
+ return hr;
+}
+
+HRESULT DeviceProvider::CancelDiscovery()
+{
+ HRESULT hr;
+
+ hr = S_FALSE;
+
+ Lock();
+
+ if (NULL != readyEvent)
+ {
+ cancelDiscovery = TRUE;
+ if (WAIT_OBJECT_0 == WaitForSingleObject(readyEvent, 0))
+ hr = S_OK;
+
+ cancelDiscovery = FALSE;
+ }
+
+ Unlock();
+
+ return hr;
+}
+
+HRESULT DeviceProvider::GetActive()
+{
+ HRESULT hr;
+
+ Lock();
+
+ if (0 != activity)
+ hr = S_OK;
+ else
+ hr = S_FALSE;
+
+ Unlock();
+
+ return hr;
+}
+
+HRESULT DeviceProvider::Register(api_devicemanager *manager)
+{
+ HRESULT hr;
+
+ if (NULL != this->manager)
+ return E_UNEXPECTED;
+
+ if (NULL == manager)
+ return E_POINTER;
+
+ hr = manager->RegisterProvider(this);
+ if (SUCCEEDED(hr))
+ {
+ this->manager = manager;
+ manager->AddRef();
+ }
+ return hr;
+}
+
+HRESULT DeviceProvider::Unregister()
+{
+ HRESULT hr;
+
+ if (NULL == manager)
+ return E_UNEXPECTED;
+
+ hr = manager->UnregisterProvider(this);
+ manager->Release();
+ manager = NULL;
+ return hr;
+}
+
+size_t DeviceProvider::IncrementActivity()
+{
+ size_t a;
+
+ Lock();
+
+ activity++;
+ if (1 == activity &&
+ NULL != manager)
+ {
+ manager->SetProviderActive(this, TRUE);
+ }
+
+ a = activity;
+
+ Unlock();
+
+ return a;
+}
+
+size_t DeviceProvider::DecrementActivity()
+{
+ size_t a;
+
+ Lock();
+
+ if (0 != activity)
+ {
+ activity--;
+ if (0 == activity &&
+ NULL != manager)
+ {
+ manager->SetProviderActive(this, FALSE);
+ }
+ }
+
+ a = activity;
+
+ Unlock();
+
+ return a;
+}
+
+#define CBCLASS DeviceProvider
+START_DISPATCH;
+CB(ADDREF, AddRef)
+CB(RELEASE, Release)
+CB(QUERYINTERFACE, QueryInterface)
+CB(API_BEGINDISCOVERY, BeginDiscovery)
+CB(API_CANCELDISCOVERY, CancelDiscovery)
+CB(API_GETACTIVE, GetActive)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_usb/deviceprovider.h b/Src/Plugins/Portable/pmp_usb/deviceprovider.h
new file mode 100644
index 00000000..1f7e83ad
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/deviceprovider.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <wtypes.h>
+#include "../devices/ifc_deviceprovider.h"
+#include "../../Library/ml_pmp/pmp.h"
+
+class DeviceProvider : public ifc_deviceprovider
+{
+protected:
+ DeviceProvider();
+ ~DeviceProvider();
+
+public:
+ static HRESULT CreateInstance(DeviceProvider **instance);
+
+public:
+ /* Dispatchable */
+ size_t AddRef();
+ size_t Release();
+ int QueryInterface(GUID interface_guid, void **object);
+
+ /* ifc_deviceprovider */
+ HRESULT BeginDiscovery(api_devicemanager *manager);
+ HRESULT CancelDiscovery();
+ HRESULT GetActive();
+
+public:
+ HRESULT Register(api_devicemanager *manager);
+ HRESULT Unregister();
+
+ size_t IncrementActivity();
+ size_t DecrementActivity();
+
+private:
+ void Lock();
+ void Unlock();
+ DWORD DiscoveryThread();
+ friend static int DeviceProvider_DiscoveryThreadStarter(HANDLE handle, void *user_data, intptr_t id);
+
+protected:
+ size_t ref;
+ size_t activity;
+ CRITICAL_SECTION lock;
+ api_devicemanager *manager;
+ ENUMDRIVES enumerator;
+ HANDLE readyEvent;
+ BOOL cancelDiscovery;
+
+protected:
+ RECVS_DISPATCH;
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_usb/eject.cpp b/Src/Plugins/Portable/pmp_usb/eject.cpp
new file mode 100644
index 00000000..36e12240
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/eject.cpp
@@ -0,0 +1,135 @@
+// this file almost totally copied from MSDN
+
+#include <windows.h>
+#include <stdio.h>
+#include <winioctl.h>
+
+#define LOCK_TIMEOUT 3000 // 10 Seconds
+#define LOCK_RETRIES 20
+
+static HANDLE OpenVolume(TCHAR cDriveLetter)
+{
+ HANDLE hVolume;
+ UINT uDriveType;
+ wchar_t szVolumeName[8] = {0};
+ wchar_t szRootName[5] = {0};
+ DWORD dwAccessFlags;
+
+ wsprintf(szRootName, L"%c:\\", cDriveLetter);
+
+ uDriveType = GetDriveType(szRootName);
+ switch(uDriveType) {
+ case DRIVE_REMOVABLE:
+ dwAccessFlags = GENERIC_READ | GENERIC_WRITE;
+ break;
+ case DRIVE_CDROM:
+ dwAccessFlags = GENERIC_READ;
+ break;
+ default:
+ printf("Cannot eject. Drive type is incorrect.\n");
+ return INVALID_HANDLE_VALUE;
+ }
+
+ wsprintf(szVolumeName, L"\\\\.\\%c:", cDriveLetter);
+
+ hVolume = CreateFile( szVolumeName,
+ dwAccessFlags,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL );
+
+ if (hVolume == INVALID_HANDLE_VALUE)
+ printf("CreateFile error %d\n", GetLastError());
+ return hVolume;
+}
+
+static BOOL CloseVolume(HANDLE hVolume)
+{
+ return CloseHandle(hVolume);
+}
+
+static BOOL LockVolume(HANDLE hVolume)
+{
+ DWORD dwBytesReturned;
+ DWORD dwSleepAmount;
+ int nTryCount;
+
+ dwSleepAmount = LOCK_TIMEOUT / LOCK_RETRIES;
+
+ // Do this in a loop until a timeout period has expired
+ for (nTryCount = 0; nTryCount < LOCK_RETRIES; nTryCount++) {
+ if (DeviceIoControl(hVolume,
+ FSCTL_LOCK_VOLUME,
+ NULL, 0,
+ NULL, 0,
+ &dwBytesReturned,
+ NULL))
+ return TRUE;
+
+ Sleep(dwSleepAmount);
+ }
+ return FALSE;
+}
+
+static BOOL DismountVolume(HANDLE hVolume)
+{
+ DWORD dwBytesReturned;
+
+ return DeviceIoControl( hVolume,
+ FSCTL_DISMOUNT_VOLUME,
+ NULL, 0,
+ NULL, 0,
+ &dwBytesReturned,
+ NULL);
+}
+
+static BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPreventRemoval)
+{
+ DWORD dwBytesReturned;
+ PREVENT_MEDIA_REMOVAL PMRBuffer;
+
+ PMRBuffer.PreventMediaRemoval = fPreventRemoval;
+
+ return DeviceIoControl( hVolume,
+ IOCTL_STORAGE_MEDIA_REMOVAL,
+ &PMRBuffer, sizeof(PREVENT_MEDIA_REMOVAL),
+ NULL, 0,
+ &dwBytesReturned,
+ NULL);
+}
+
+static int AutoEjectVolume(HANDLE hVolume)
+{
+ DWORD dwBytesReturned;
+
+ return DeviceIoControl( hVolume,
+ IOCTL_STORAGE_EJECT_MEDIA,
+ NULL, 0,
+ NULL, 0,
+ &dwBytesReturned,
+ NULL);
+}
+
+BOOL EjectVolume(TCHAR cDriveLetter)
+{
+ BOOL fAutoEject = FALSE;
+ HANDLE hVolume = OpenVolume(cDriveLetter);
+ if (hVolume == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ // Lock and dismount the volume.
+ if (LockVolume(hVolume) && DismountVolume(hVolume)) {
+ // Set prevent removal to false and eject the volume.
+ if (PreventRemovalOfVolume(hVolume, FALSE) && AutoEjectVolume(hVolume))
+ fAutoEject = TRUE;
+ }
+
+ // Close the volume so other processes can use the drive.
+ if (!CloseVolume(hVolume))
+ return FALSE;
+
+ if (fAutoEject) return TRUE;
+ else return FALSE;
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_usb/filecopy.cpp b/Src/Plugins/Portable/pmp_usb/filecopy.cpp
new file mode 100644
index 00000000..aecf9422
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/filecopy.cpp
@@ -0,0 +1,67 @@
+#include "api.h"
+#include <windows.h>
+#include <stdio.h>
+#include <wchar.h>
+#include "resource.h"
+#include <strsafe.h>
+
+typedef struct CopyData
+{
+ void * callbackContext;
+ void (*callback)(void * callbackContext, wchar_t * status);
+} CopyData;
+
+DWORD CALLBACK CopyToIpodProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred,
+ LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred,
+ DWORD dwStreamNumber,
+ DWORD dwCallbackReason,
+ HANDLE hSourceFile, HANDLE hDestinationFile,
+ LPVOID lpData)
+{
+ CopyData *inst = (CopyData *)lpData;
+ if (inst && inst->callback)
+ {
+ wchar_t status[100] = {0};
+ wchar_t langtemp[100] = {0};
+ StringCbPrintf(status, sizeof(status), WASABI_API_LNGSTRINGW_BUF(IDS_TRANSFERING_PERCENT, langtemp, 100), (int)(100ULL * TotalBytesTransferred.QuadPart / (TotalFileSize.QuadPart)));
+ inst->callback(inst->callbackContext,status);
+ }
+ return PROGRESS_CONTINUE;
+}
+
+int CopyFile(const wchar_t *infile, const wchar_t *outfile, void * callbackContext, void (*callback)(void * callbackContext, wchar_t * status), int * killswitch)
+{
+ wchar_t langtemp[100] = {0};
+
+ CopyData c;
+ c.callback = callback;
+ c.callbackContext = callbackContext;
+
+ if (CopyFileEx(infile, outfile, CopyToIpodProgressRoutine, &c, killswitch,0))
+ {
+ if (callback)
+ {
+ callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_DONE, langtemp, 100));
+ }
+ return 0;
+ }
+ else
+ {
+ switch(GetLastError())
+ {
+ case ERROR_REQUEST_ABORTED:
+ DeleteFile(outfile);
+ if (callback)
+ {
+ callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_CANCELLED, langtemp, 100));
+ }
+
+ default:
+ if (callback)
+ {
+ callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_TRANSFER_FAILED, langtemp, 100));
+ }
+ }
+ return -1;
+ }
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_usb/main.cpp b/Src/Plugins/Portable/pmp_usb/main.cpp
new file mode 100644
index 00000000..19fb06d4
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/main.cpp
@@ -0,0 +1,547 @@
+#include "../../Library/ml_pmp/pmp.h"
+#include "../Winamp/wa_ipc.h"
+#include <vector>
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoLock.h"
+#include "api.h"
+#include "resource.h"
+#include "usbdevice.h"
+#include "deviceprovider.h"
+
+#include <devguid.h>
+#include <shlobj.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define PLUGIN_VERSION L"1.62"
+static int Init();
+static void Quit();
+static bool doRegisterForDevNotification(void);
+static intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3);
+
+extern PMPDevicePlugin plugin = {PMPHDR_VER,0,Init,Quit,MessageProc};
+
+bool loading_devices[26] = {0,};
+
+// start-usb
+static const wchar_t *winampini;
+static std::vector<HANDLE> loadingThreads;
+static std::vector<wchar_t*> blacklist;
+
+static HDEVNOTIFY hDevNotify;
+std::vector<USBDevice*> devices;
+HWND config;
+
+static DeviceProvider *deviceProvider = NULL;
+static UINT_PTR rescanTimer = 0;
+
+static void blacklistLoad() {
+ wchar_t keyname[64] = {0};
+ int l = GetPrivateProfileIntW(L"pmp_usb", L"blacklistnum", 0, winampini);
+ for(int i=l>100?l-100:0; i<l; i++) {
+ wchar_t buf[100] = {0};
+ StringCchPrintfW(keyname, 64, L"blacklist-%d", i);
+ GetPrivateProfileStringW(L"pmp_usb", keyname, L"", buf, 100, winampini);
+ if(buf[0])
+ {
+ blacklist.push_back(_wcsdup(buf));
+ }
+ }
+}
+
+static void blacklistSave() {
+ wchar_t buf[64] = {0};
+ StringCchPrintfW(buf, 64, L"%u", blacklist.size());
+ WritePrivateProfileStringW(L"pmp_usb", L"blacklistnum", buf, winampini);
+ for(size_t i=0; i<blacklist.size(); i++)
+ {
+ StringCchPrintfW(buf, 64, L"blacklist-%u", i);
+ WritePrivateProfileStringW(L"pmp_usb", buf, (const wchar_t*)blacklist.at(i), winampini);
+ }
+}
+
+static wchar_t *makeBlacklistString(wchar_t drive) {
+ wchar_t path[4]={drive,L":\\"};
+ wchar_t name[100]=L"";
+ wchar_t buf[FIELD_LENGTH]=L"";
+ DWORD serial=0;
+ UINT olderrmode=SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
+ GetVolumeInformation(path,name,100,&serial,NULL,NULL,NULL,0);
+
+ if(serial)
+ {
+ StringCchPrintf(buf, FIELD_LENGTH, L"s:%d",serial);
+ SetErrorMode(olderrmode);
+ return _wcsdup(buf);
+ }
+
+ {
+ ULARGE_INTEGER tfree={0,}, total={0,}, freeb={0,};
+ GetDiskFreeSpaceEx(path, &tfree, &total, &freeb);
+ StringCchPrintf(buf, FIELD_LENGTH, L"n:%s,%d,%d", name, total.HighPart, total.LowPart);
+ SetErrorMode(olderrmode);
+ return _wcsdup(buf);
+ }
+}
+
+static bool blacklistCheck(wchar_t drive) {
+ wchar_t *s = makeBlacklistString(drive);
+ if (s)
+ {
+ for(size_t i=0; i<blacklist.size(); i++)
+ {
+ if(!wcscmp(s,(wchar_t*)blacklist.at(i)))
+ {
+ free(s);
+ return true;
+ }
+ }
+ free(s);
+ }
+ return false;
+}
+
+// helpers
+static DWORD WINAPI ThreadFunc_Load(LPVOID lpParam) {
+ wchar_t drive = (wchar_t)(intptr_t)lpParam;
+ pmpDeviceLoading load;
+ Device * d = new USBDevice(drive,&load);
+ return 0;
+}
+
+static Nullsoft::Utility::LockGuard connect_guard;
+void connectDrive(wchar_t drive, bool checkSize=true, bool checkBlacklist=true)
+{
+ Nullsoft::Utility::AutoLock connect_lock(connect_guard);
+ // capitalize
+ if (drive >= 'a' && drive <= 'z')
+ drive = drive - 32;
+
+ // reject invalid drive letters
+ if (drive < 'A' || drive > 'Z')
+ return;
+
+ if(checkBlacklist && blacklistCheck(drive)) return;
+
+ // if device is taken already ignore
+ for (std::vector<USBDevice*>::const_iterator e = devices.begin(); e != devices.end(); e++)
+ {
+ if ((*e)->drive == drive)
+ return;
+ }
+
+ if (loading_devices[drive-'A'])
+ return;
+
+ loading_devices[drive-'A'] = true;
+
+ wchar_t path[4]=L"x:\\";
+ path[0]=drive;
+
+ if(checkSize)
+ {
+ ULARGE_INTEGER total;
+
+ if (0 == GetDiskFreeSpaceExW(path, NULL, &total, NULL) ||
+ total.HighPart == 0 && total.LowPart == 0)
+ {
+ loading_devices[drive-'A'] = false;
+ return;
+ }
+ }
+
+ // Ignore iPods...
+ // Check for a "iPod_Control" folder,
+ // if "iPod_Control" is present just bail and
+ // let the iPod plugin handle it
+ const wchar_t iPodDb[] = {drive,L":\\iPod_Control"};
+ WIN32_FIND_DATA ffd={0};
+ HANDLE h = FindFirstFile(iPodDb,&ffd);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ FindClose(h);
+
+ if (0 != (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ loading_devices[drive-'A'] = false;
+ return;
+ }
+ }
+
+ // Ignore androids too, have a specific pulgin to take care of android...
+ // Check for a "Android" folder,
+ // if "Android" is present just bail and
+ // let the pmp_android plugin handle it
+
+ const wchar_t androidTopLevelDir[] = {drive,L":\\Android"};
+
+ h = FindFirstFile(androidTopLevelDir, &ffd);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ FindClose(h);
+
+ if (0 != (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ loading_devices[drive-'A'] = false;
+ return;
+ }
+ }
+
+ //not an ipod, not an android
+ //do we know about the device already? is there a metadata.dat file ?
+ wchar_t cacheFile[FIELD_LENGTH] = {0};
+ StringCchPrintf(cacheFile, FIELD_LENGTH, L"%c:\\%s", drive, NDE_CACHE_DAT);
+
+ if (!PathFileExists(cacheFile))
+ {
+ // new device, never plugged in before
+ wchar_t drvname[100] = {0}, titleStr[128] = {0};
+ DWORD serial=0;
+ GetVolumeInformation(path,drvname,100,&serial,NULL,NULL,NULL,0);
+
+ wchar_t buf[1024] = {0};
+ StringCchPrintf(buf, ARRAYSIZE(buf), WASABI_API_LNGSTRINGW(IDS_REMOVEABLE_DRIVE_DETECTED),
+ drvname, towupper(drive));
+
+ if(MessageBox(plugin.hwndLibraryParent,buf,
+ WASABI_API_LNGSTRINGW_BUF(IDS_WINAMP_PMP_SUPPORT,titleStr,128),
+ MB_YESNO|MB_SETFOREGROUND|MB_SYSTEMMODAL|MB_TOPMOST) == IDNO)
+ {
+ wchar_t * bstr = makeBlacklistString(drive);
+ loading_devices[drive-'A'] = false;
+ if (bstr)
+ {
+ blacklist.push_back(bstr);
+ blacklistSave();
+ }
+ return;
+ }
+ }
+
+ DWORD dwThreadId;
+ HANDLE loadingThread = CreateThread(NULL, 0, ThreadFunc_Load, (LPVOID)(intptr_t)drive, 0, &dwThreadId);
+ if(NULL != loadingThread)
+ loadingThreads.push_back(loadingThread);
+ else
+ loading_devices[drive-'A'] = false;
+
+}
+
+static void autoDetectCallback(wchar_t drive,UINT type) {
+ if(type == DRIVE_REMOVABLE)
+ {
+ connectDrive(drive,true,true);
+ }
+}
+
+
+// end-usb
+static int Init()
+{
+ WasabiInit();
+
+ // start-usb
+ winampini = (const wchar_t*)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_GETINIFILEW);
+ // need to have this initialised before we try to do anything with localisation features
+ WASABI_API_START_LANG(plugin.hDllInstance,PmpUSBLangGUID);
+ // end-usb
+
+ static wchar_t szDescription[256];
+ StringCchPrintfW(szDescription, ARRAYSIZE(szDescription),
+ WASABI_API_LNGSTRINGW(IDS_NULLSOFT_USB_DEVICE_PLUGIN), PLUGIN_VERSION);
+ plugin.description = szDescription;
+
+ /** load up the backlist */
+ blacklistLoad();
+
+ if (NULL != AGAVE_API_DEVICEMANAGER &&
+ NULL == deviceProvider)
+ {
+ if (SUCCEEDED(DeviceProvider::CreateInstance(&deviceProvider)) &&
+ FAILED(deviceProvider->Register(AGAVE_API_DEVICEMANAGER)))
+ {
+ deviceProvider->Release();
+ deviceProvider = NULL;
+ }
+ }
+
+ /* Our device shows up as a normal drive */
+ if (NULL == deviceProvider ||
+ FAILED(deviceProvider->BeginDiscovery(AGAVE_API_DEVICEMANAGER)))
+ {
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)autoDetectCallback,PMP_IPC_ENUM_ACTIVE_DRIVES);
+ }
+ return 0;
+}
+
+static void Quit()
+{
+ if (NULL != deviceProvider)
+ {
+ deviceProvider->Unregister();
+ deviceProvider->Release();
+ deviceProvider = NULL;
+ }
+
+ WasabiQuit();
+ UnregisterDeviceNotification(hDevNotify);
+ USBDevice::CloseDatabase();
+}
+
+static wchar_t FirstDriveFromMask(ULONG *unitmask) {
+ char i;
+ ULONG adj = 0x1, mask = *unitmask;
+ for(i=0; i<26; ++i) {
+ if(mask & 0x1) {
+ *unitmask -= adj;
+ break;
+ }
+ adj = adj << 1;
+ mask = mask >> 1;
+ }
+ return (i+L'A');
+}
+
+static int GetNumberOfDrivesFromMask(ULONG unitmask) {
+ int count = 0;
+ for(int i=0; i<26; ++i)
+ {
+ if(unitmask & 0x1)
+ count++;
+
+ unitmask = unitmask >> 1;
+ }
+ return count;
+}
+
+
+static void CALLBACK RescanOnTimer(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ KillTimer(hwnd, idEvent);
+ if (idEvent == rescanTimer)
+ rescanTimer = 0;
+
+ if (NULL == deviceProvider ||
+ FAILED(deviceProvider->BeginDiscovery(AGAVE_API_DEVICEMANAGER)))
+ {
+ PostMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)autoDetectCallback,PMP_IPC_ENUM_ACTIVE_DRIVES);
+ }
+}
+
+int wmDeviceChange(WPARAM wParam, LPARAM lParam)
+{
+ UINT olderrmode=SetErrorMode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS);
+ if(wParam==DBT_DEVICEARRIVAL || wParam==DBT_DEVICEREMOVECOMPLETE)
+ { // something has been inserted or removed
+ PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
+ if(lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
+ { // its a volume
+ PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
+ if((!(lpdbv->dbcv_flags & DBTF_MEDIA) && !(lpdbv->dbcv_flags & DBTF_NET)))
+ { // its not a network drive or a CD/floppy, game on!
+ ULONG dbcv_unitmask = lpdbv->dbcv_unitmask;
+
+ // see just how many drives have been flagged on the action
+ // eg one usb drive could have multiple partitions that we handle
+ int count = GetNumberOfDrivesFromMask(dbcv_unitmask);
+ for(int j = 0; j < count; j++)
+ {
+ wchar_t drive = FirstDriveFromMask(&dbcv_unitmask);
+ if((wParam == DBT_DEVICEARRIVAL) && !blacklistCheck(drive))
+ { // connected
+ connectDrive(drive);
+ //send a message as if the user just selected a drive from the combo box, this way the fields are refreshed to the correct device's settings
+ SendMessage(config, WM_COMMAND,MAKEWPARAM(IDC_DRIVESELECT,CBN_SELCHANGE),0);
+ }
+ else
+ { // removal
+ for(size_t i=0; i < devices.size(); i++) {
+ USBDevice * d = (USBDevice*)devices.at(i);
+ if(d->drive == drive)
+ {
+ devices.erase(devices.begin() + i);
+ if(config) SendMessage(config,WM_USER,0,0); //refresh fields
+ if(config) SendMessage(config,WM_COMMAND, MAKEWPARAM(IDC_DRIVESELECT,CBN_SELCHANGE),0); //update to correct device change as if the user had clicked on the combo box themself
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)d,PMP_IPC_DEVICEDISCONNECTED);
+ delete d;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ rescanTimer = SetTimer(NULL, rescanTimer, 10000, RescanOnTimer);
+ }
+ SetErrorMode(olderrmode);
+ return 0;
+}
+
+static int IsDriveConnectedToPMP(wchar_t drive) {
+ for(size_t i = 0; i < devices.size(); i++)
+ {
+ if(((USBDevice*)devices.at(i))->drive == drive)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static INT_PTR CALLBACK config_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
+ switch(uMsg) {
+ case WM_INITDIALOG:
+ {
+ for(wchar_t d=L'A'; d<='Z'; d++) {
+ wchar_t drive[3] = {d,L':',0}, drv[4] = {d,L':','\\',0};
+ UINT uDriveType = GetDriveType(drv);
+ if(uDriveType == DRIVE_REMOVABLE || uDriveType == DRIVE_CDROM || uDriveType == DRIVE_FIXED) {
+ int position = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_ADDSTRING,0,(LPARAM)drive);
+ SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_SETITEMDATA,position,d);
+ }
+ }
+ SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_SETCURSEL,0,0);
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_COMBO_MANUALCONNECT,CBN_SELCHANGE),0);
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hwndDlg,0);
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_COMBO_MANUALCONNECT:
+ {
+ if(HIWORD(wParam)==CBN_SELCHANGE) {
+ int indx = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETCURSEL,0,0);
+ wchar_t drive = (wchar_t)SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETITEMDATA,indx,0);
+ if(indx >= 0)
+ {
+ int connected = IsDriveConnectedToPMP(drive), isblacklisted = blacklistCheck(drive);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALCONNECT), !connected && !isblacklisted);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALDISCONNECT), connected);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALBLACKLIST), TRUE);
+ SetDlgItemText(hwndDlg, IDC_MANUALBLACKLIST, WASABI_API_LNGSTRINGW(isblacklisted ? IDS_UNBLACKLIST_DRIVE : IDS_BLACKLIST_DRIVE));
+ }
+ }
+ }
+ break;
+ case IDC_MANUALCONNECT:
+ {
+ char titleStr[32] = {0};
+ if(MessageBoxA(hwndDlg, WASABI_API_LNGSTRING(IDS_MANUAL_CONNECT_PROMPT),
+ WASABI_API_LNGSTRING_BUF(IDS_WARNING,titleStr,32), MB_YESNO) == IDYES)
+ {
+ int indx = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETCURSEL,0,0);
+ wchar_t drive = (wchar_t)SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETITEMDATA,indx,0);
+ if(drive >= L'A' && drive <= L'Z') {
+ wchar_t *bl = makeBlacklistString(drive);
+ if (bl)
+ {
+ for(size_t i=0; i<blacklist.size(); i++)
+ {
+ if(!wcscmp(bl,(wchar_t*)blacklist.at(i)))
+ {
+ free(blacklist.at(i));
+ blacklist.erase(blacklist.begin() + i);
+ break;
+ }
+ }
+ free(bl);
+ }
+ connectDrive(drive,false);
+ // should do a better check here incase of failure, etc
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALCONNECT), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALDISCONNECT), TRUE);
+ }
+ }
+ }
+ break;
+ case IDC_MANUALDISCONNECT:
+ {
+ int indx = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETCURSEL,0,0);
+ wchar_t drive = (wchar_t)SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETITEMDATA,indx,0);
+ if(drive >= L'A' && drive <= L'Z') {
+ for(size_t i=0; i < devices.size(); i++) {
+ USBDevice * d = (USBDevice*)devices.at(i);
+ if(d->drive == drive)
+ {
+ devices.erase(devices.begin() + i);
+ if(config) SendMessage(config,WM_USER,0,0); //refresh fields
+ if(config) SendMessage(config,WM_COMMAND, MAKEWPARAM(IDC_DRIVESELECT,CBN_SELCHANGE),0); //update to correct device change as if the user had clicked on the combo box themself
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)d,PMP_IPC_DEVICEDISCONNECTED);
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_COMBO_MANUALCONNECT,CBN_SELCHANGE),0);
+ delete d;
+ }
+ }
+ }
+ }
+ break;
+ case IDC_MANUALBLACKLIST:
+ {
+ int indx = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETCURSEL,0,0);
+ wchar_t drive = (wchar_t)SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETITEMDATA,indx,0);
+ if(drive >= L'A' && drive <= L'Z') {
+ wchar_t *bl = makeBlacklistString(drive);
+ if (bl)
+ {
+ if(!blacklistCheck(drive)) {
+ blacklist.push_back(bl);
+ // see if we've got a connected drive and prompt to remove it or wait till restart
+ if(IsDriveConnectedToPMP(drive)) {
+ wchar_t title[96] = {0};
+ GetWindowText(hwndDlg, title, 96);
+ if(MessageBox(hwndDlg,WASABI_API_LNGSTRINGW(IDS_DRIVE_CONNECTED_DISCONNECT_Q),title,MB_YESNO)==IDYES){
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_MANUALDISCONNECT,0),0);
+ }
+ }
+ }
+ else {
+ for(size_t i=0; i < blacklist.size(); i++)
+ {
+ if(!wcscmp(bl,(wchar_t*)blacklist.at(i)))
+ {
+ free(blacklist.at(i));
+ blacklist.erase(blacklist.begin() + i);
+ break;
+ }
+ }
+ free(bl);
+ }
+ }
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_COMBO_MANUALCONNECT,CBN_SELCHANGE),0);
+ }
+ }
+ break;
+ case IDOK:
+ case IDCANCEL:
+ blacklistSave();
+ EndDialog(hwndDlg,0);
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+
+static intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3)
+{
+ switch(msg) {
+ case PMP_DEVICECHANGE:
+ return wmDeviceChange(param1,param2);
+ case PMP_CONFIG:
+ WASABI_API_DIALOGBOXW(IDD_CONFIG_GLOBAL,(HWND)param1,config_dialogProc);
+ return 1;
+ }
+ return 0;
+}
+
+extern "C" __declspec(dllexport) PMPDevicePlugin *winampGetPMPDevicePlugin()
+{
+ return &plugin;
+}
+
diff --git a/Src/Plugins/Portable/pmp_usb/pmp_usb2.rc b/Src/Plugins/Portable/pmp_usb/pmp_usb2.rc
new file mode 100644
index 00000000..2761cce4
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/pmp_usb2.rc
@@ -0,0 +1,209 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""version.rc2""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// PNG
+//
+
+IDR_PSP_ICON PNG "resources\\pspIcon.png"
+IDR_USB_ICON PNG "resources\\usbIcon.png"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_CONFIG DIALOGEX 0, 0, 264, 226
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "File Name Format",IDC_STATIC,7,10,56,8
+ EDITTEXT IDC_NAMEFORMAT,80,7,127,14,ES_AUTOHSCROLL
+ PUSHBUTTON "Format Help",IDC_FILENAMEHELP,211,7,46,14
+ LTEXT "Playlist Directory",IDC_STATIC,7,26,54,8
+ EDITTEXT IDC_PLDIR,80,24,128,14,ES_AUTOHSCROLL
+ PUSHBUTTON "Browse...",IDC_PLBROWSE,211,23,46,14
+ LTEXT "Supported Formats",IDC_STATIC,7,42,62,8
+ EDITTEXT IDC_SUPPORTEDFORMATS,80,40,128,14,ES_AUTOHSCROLL
+ PUSHBUTTON "Syntax Help",IDC_FORMATSHELP,211,40,46,14
+ LTEXT "Delete Empty Folders",IDC_STATIC,7,55,69,8
+ CONTROL "",IDC_PURGEFOLDERS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,80,56,8,8
+ PUSHBUTTON "Save and Rescan",IDC_RESCAN,7,71,66,14
+ PUSHBUTTON "Refresh Cache",IDC_REFRESHCACHE,79,71,66,14
+ GROUPBOX "Playlist Writing Options",IDC_STATIC,7,95,250,49
+ COMBOBOX IDC_PL_WRITE_COMBO,12,108,120,35,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Changing how Winamp saves its playlists may improve compatability with other portable devices.",IDC_STATIC,137,104,113,34
+ LTEXT "",IDC_PL_WRITE_EG,12,126,120,10
+END
+
+IDD_CONFIG_GLOBAL DIALOGEX 0, 0, 196, 90
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "USB Device Support Configuration"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Select the Drive to use from the available list below",IDC_STATIC,5,3,186,67
+ COMBOBOX IDC_COMBO_MANUALCONNECT,31,17,40,242,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Connect Drive",IDC_MANUALCONNECT,75,17,90,13
+ PUSHBUTTON "Disconnect Drive",IDC_MANUALDISCONNECT,75,34,90,13
+ PUSHBUTTON "Blacklist Drive",IDC_MANUALBLACKLIST,75,51,90,13
+ DEFPUSHBUTTON "Close",IDOK,75,73,45,13
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_CONFIG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 257
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 218
+ END
+
+ IDD_CONFIG_GLOBAL, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 191
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 86
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_NULLSOFT_USB_DEVICE_PLUGIN "Nullsoft USB Device Plug-in v%s"
+ 65535 "{E553C1A4-5DE2-4838-8000-FDF8DC377DD4}"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_CANNOT_OPEN_FILE "Cannot open file"
+ IDS_CANNOT_CREATE_FILE "Cannot create file"
+ IDS_TRANSFERING_PERCENT "Transferring %d%%"
+ IDS_CANCELLED "Cancelled"
+ IDS_DONE "Done"
+ IDS_TRANSFER_FAILED "Transfer failed"
+ IDS_REMOVEABLE_DRIVE_DETECTED
+ "Winamp has detected a removable drive, ""%s (%c:)"".\nIs this a portable music player that you want to manage with Winamp?"
+ IDS_WINAMP_PMP_SUPPORT "Winamp Portable Music Player Support"
+ IDS_MANUAL_CONNECT_PROMPT
+ "Manually connecting the wrong device could cause problems.\nPlease be sure that you have entered a valid USB device letter.\n\nAre you sure you wish to continue?"
+ IDS_WARNING "Warning"
+ IDS_LOADING_DRIVE_X "Loading Drive X:"
+ IDS_FAILED_TO_EJECT_DRIVE
+ "Failed to eject device. Is something else using it?"
+ IDS_ERROR "Error"
+ IDS_USB_DRIVE_X "USB Drive X:"
+ IDS_TRACK_IN_USE "Track is in use - Could not delete!"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_CACHE_UPDATED "Cache updated."
+ IDS_SUCCESS "Success"
+ IDS_FILENAME_FORMATTING_INFO
+ "You may enter a filename format string for your files.\nIt can contain \\ or / to delimit a path, and the following keywords:\n\n <Artist> - inserts the artist with the default capitalization\n <ARTIST> - inserts the artist in all uppercase\n <artist> - inserts the artist in all lowercase\n <Albumartist>/<ALBUMARTIST>/<albumartist> - inserts the album artist\n <Album>/<ALBUM>/<album> - inserts the album\n <year> - inserts the album year\n <Genre>/<GENRE>/<genre> - inserts the album genre\n <Title>/<TITLE>/<title> - inserts the track title\n <filename> - inserts the original filename (extension safe)\n <disc> - inserts the disc number\n #, ##, or ### - inserts the track number, with leading 0s if ## or ###\n\n For Example: E:\\Music\\<Artist>\\<Album>\\## - <Title>\n"
+ IDS_FILENAME_FORMAT_HELP "Filename Format Help"
+ IDS_SELECT_FOLDER_TO_LOAD_PLAYLISTS
+ "Please select a folder to load playlists from the device."
+ IDS_ERR_SELECTED_PATH_NOT_ON_DEVICE
+ "Error: selected path is not on device!"
+ IDS_SUPPORTED_FORMAT_INFO
+ "You may enter supported extensions in the form of\nextensions separated by semicolons.\n\nFor Example: mp3;wav;wma"
+ IDS_SUPPORTED_FORMAT_HELP "Supported Formats Help"
+ IDS_RESCAN_COMPLETE_SAVED "Rescan complete, device settings saved."
+ IDS_RESCAN_COMPLETE "Rescan complete"
+ IDS_ADVANCED "Advanced"
+ IDS_UNBLACKLIST_DRIVE "Un-blacklist Drive"
+ IDS_BLACKLIST_DRIVE "Blacklist Drive"
+ IDS_DRIVE_CONNECTED_DISCONNECT_Q
+ "The Drive you have selected to blacklist is currently connected and being managed.\n\nWould you like to disconnect the Drive now or you can wait until you restart Winamp."
+ IDS_SLASH_AT_START "Slash at start of paths (default)"
+ IDS_DOT_AT_START "Dot at start of paths"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_NO_SLASH_OR_DOT "No slash or dot at start"
+ IDS_EG_SLASH "e.g. \\path\\to\\file.mp3"
+ IDS_EG_DOT "e.g. .\\path\\to\\file.mp3"
+ IDS_EG_NEITHER "e.g. path\\to\\file.mp3"
+ IDS_DELAYLOAD_FAILURE "USB plug-in cannot load the database to write the cache file"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc2"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/Plugins/Portable/pmp_usb/pmp_usb2.sln b/Src/Plugins/Portable/pmp_usb/pmp_usb2.sln
new file mode 100644
index 00000000..c3806bbf
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/pmp_usb2.sln
@@ -0,0 +1,129 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29424.173
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmp_usb", "pmp_usb2.vcxproj", "{9AEE8DBD-D63A-41EC-8846-41208C23932B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27} = {57C90706-B25D-4ACA-9B33-95CDB2427C27}
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A} = {4D25C321-7F8B-424E-9899-D80A364BAF1A}
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1} = {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915} = {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}
+ {E105A0A2-7391-47C5-86AC-718003524C3D} = {E105A0A2-7391-47C5-86AC-718003524C3D}
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nde", "..\nde\nde.vcxproj", "{4D25C321-7F8B-424E-9899-D80A364BAF1A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nx", "..\replicant\nx\nx.vcxproj", "{57C90706-B25D-4ACA-9B33-95CDB2427C27}"
+ ProjectSection(ProjectDependencies) = postProject
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nu", "..\replicant\nu\nu.vcxproj", "{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jnetlib", "..\replicant\jnetlib\jnetlib.vcxproj", "{E105A0A2-7391-47C5-86AC-718003524C3D}"
+ ProjectSection(ProjectDependencies) = postProject
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\replicant\zlib\zlib.vcxproj", "{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tataki", "..\tataki\tataki.vcxproj", "{255B68B5-7EF8-45EF-A675-2D6B88147909}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bfc", "..\Wasabi\bfc\bfc.vcxproj", "{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsutil", "..\nsutil\nsutil.vcxproj", "{DABE6307-F8DD-416D-9DAC-673E2DECB73F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {9AEE8DBD-D63A-41EC-8846-41208C23932B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9AEE8DBD-D63A-41EC-8846-41208C23932B}.Debug|Win32.Build.0 = Debug|Win32
+ {9AEE8DBD-D63A-41EC-8846-41208C23932B}.Debug|x64.ActiveCfg = Debug|x64
+ {9AEE8DBD-D63A-41EC-8846-41208C23932B}.Debug|x64.Build.0 = Debug|x64
+ {9AEE8DBD-D63A-41EC-8846-41208C23932B}.Release|Win32.ActiveCfg = Release|Win32
+ {9AEE8DBD-D63A-41EC-8846-41208C23932B}.Release|Win32.Build.0 = Release|Win32
+ {9AEE8DBD-D63A-41EC-8846-41208C23932B}.Release|x64.ActiveCfg = Release|x64
+ {9AEE8DBD-D63A-41EC-8846-41208C23932B}.Release|x64.Build.0 = Release|x64
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|Win32.Build.0 = Debug|Win32
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|x64.ActiveCfg = Debug|x64
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|x64.Build.0 = Debug|x64
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|Win32.ActiveCfg = Release|Win32
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|Win32.Build.0 = Release|Win32
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|x64.ActiveCfg = Release|x64
+ {4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|x64.Build.0 = Release|x64
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.ActiveCfg = Debug|Win32
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.Build.0 = Debug|Win32
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.ActiveCfg = Debug|x64
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.Build.0 = Debug|x64
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.ActiveCfg = Release|Win32
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.Build.0 = Release|Win32
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.ActiveCfg = Release|x64
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.Build.0 = Release|x64
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.Build.0 = Debug|Win32
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.ActiveCfg = Debug|x64
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.Build.0 = Debug|x64
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.ActiveCfg = Release|Win32
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.Build.0 = Release|Win32
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.ActiveCfg = Release|x64
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.Build.0 = Release|x64
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.Build.0 = Debug|Win32
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.ActiveCfg = Debug|x64
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.Build.0 = Debug|x64
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.ActiveCfg = Release|Win32
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.Build.0 = Release|Win32
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.ActiveCfg = Release|x64
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.Build.0 = Release|x64
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.Build.0 = Debug|Win32
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.ActiveCfg = Debug|x64
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.Build.0 = Debug|x64
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.ActiveCfg = Release|Win32
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.Build.0 = Release|Win32
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.ActiveCfg = Release|x64
+ {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.Build.0 = Release|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|Win32.ActiveCfg = Debug|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|Win32.Build.0 = Debug|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|x64.ActiveCfg = Debug|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|x64.Build.0 = Debug|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|Win32.ActiveCfg = Release|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|Win32.Build.0 = Release|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|x64.ActiveCfg = Release|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|x64.Build.0 = Release|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.Build.0 = Debug|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.ActiveCfg = Debug|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.Build.0 = Debug|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.ActiveCfg = Release|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.Build.0 = Release|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.ActiveCfg = Release|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.Build.0 = Release|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.Build.0 = Debug|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.ActiveCfg = Debug|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.Build.0 = Debug|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.ActiveCfg = Release|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.Build.0 = Release|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.ActiveCfg = Release|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {FC646532-2050-40A5-A2AB-F699F1C071C4}
+ EndGlobalSection
+EndGlobal
diff --git a/Src/Plugins/Portable/pmp_usb/pmp_usb2.vcxproj b/Src/Plugins/Portable/pmp_usb/pmp_usb2.vcxproj
new file mode 100644
index 00000000..96c905e2
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/pmp_usb2.vcxproj
@@ -0,0 +1,340 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>pmp_usb</ProjectName>
+ <ProjectGuid>{9AEE8DBD-D63A-41EC-8846-41208C23932B}</ProjectGuid>
+ <RootNamespace>pmp_usb2</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg">
+ <VcpkgEnableManifest>false</VcpkgEnableManifest>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;..\..\..\Wasabi;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapExports>false</MapExports>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <SupportUnloadOfDelayLoadedDLL>true</SupportUnloadOfDelayLoadedDLL>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;..\..\..\Wasabi;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <DisableSpecificWarnings>4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>nde.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapExports>false</MapExports>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <SupportUnloadOfDelayLoadedDLL>true</SupportUnloadOfDelayLoadedDLL>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>.;..\..\..\Wasabi;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4995;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>nde.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>.;..\..\..\Wasabi;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4244;4995;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x040c</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>nde.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <MapFileName>$(IntDir)$(TargetName).map</MapFileName>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\..\nde\nde.vcxproj">
+ <Project>{4d25c321-7f8b-424e-9899-d80a364baf1a}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\tataki\tataki.vcxproj">
+ <Project>{255b68b5-7ef8-45ef-a675-2d6b88147909}</Project>
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
+ <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp" />
+ <ClCompile Include="albumart.cpp" />
+ <ClCompile Include="api.cpp" />
+ <ClCompile Include="deviceprovider.cpp" />
+ <ClCompile Include="eject.cpp" />
+ <ClCompile Include="filecopy.cpp" />
+ <ClCompile Include="main.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">WIN32;_DEBUG;_WINDOWS;_UNICODE;UNICODE;_USRDLL;ML_ex_EXPORTS</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">WIN64;_DEBUG;_WINDOWS;_UNICODE;UNICODE;_USRDLL;ML_ex_EXPORTS</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="usbdevice.cpp" />
+ <ClCompile Include="usbplaylist.cpp" />
+ <ClCompile Include="usbplaylistsaver.cpp" />
+ <ClCompile Include="utils.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\General\gen_ml\ml.h" />
+ <ClInclude Include="..\..\Library\ml_pmp\pmp.h" />
+ <ClInclude Include="api.h" />
+ <ClInclude Include="deviceprovider.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="usbdevice.h" />
+ <ClInclude Include="usbplaylist.h" />
+ <ClInclude Include="usbplaylistsaver.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="pmp_usb2.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="resources\pspIcon.png" />
+ <Image Include="resources\usbIcon.png" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_usb/pmp_usb2.vcxproj.filters b/Src/Plugins/Portable/pmp_usb/pmp_usb2.vcxproj.filters
new file mode 100644
index 00000000..c387fa9a
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/pmp_usb2.vcxproj.filters
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="usbplaylistsaver.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="usbplaylist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="usbdevice.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="filecopy.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="eject.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="deviceprovider.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="api.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="albumart.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\General\gen_ml\ml_lib.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="api.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="deviceprovider.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="usbplaylistsaver.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="usbplaylist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="usbdevice.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Library\ml_pmp\pmp.h" />
+ <ClInclude Include="..\..\General\gen_ml\ml.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="resources\usbIcon.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="resources\pspIcon.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{df4d6295-0341-413a-a69b-289485e8ac9b}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Ressource Files">
+ <UniqueIdentifier>{dd0483a1-4f48-4781-9440-bf945617ff32}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{f7ad4b77-838f-46fa-a4d5-e72746ad3a68}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Image Files">
+ <UniqueIdentifier>{4536af52-cfdf-4156-a936-f89abc7ee71a}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="pmp_usb2.rc">
+ <Filter>Ressource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_usb/resource.h b/Src/Plugins/Portable/pmp_usb/resource.h
new file mode 100644
index 00000000..5574f6f2
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/resource.h
@@ -0,0 +1,75 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by pmp_usb2.rc
+//
+#define IDS_CANNOT_OPEN_FILE 1
+#define IDS_CANNOT_CREATE_FILE 2
+#define IDS_TRANSFERING_PERCENT 3
+#define IDS_CANCELLED 4
+#define IDS_DONE 5
+#define IDS_TRANSFER_FAILED 6
+#define IDS_REMOVEABLE_DRIVE_DETECTED 7
+#define IDS_WINAMP_PMP_SUPPORT 8
+#define IDS_MANUAL_CONNECT_PROMPT 9
+#define IDS_WARNING 10
+#define IDS_LOADING_DRIVE_X 11
+#define IDS_FAILED_TO_EJECT_DRIVE 12
+#define IDS_ERROR 13
+#define IDS_STRING14 14
+#define IDS_USB_DRIVE_X 14
+#define IDS_TRACK_IN_USE 15
+#define IDS_CACHE_UPDATED 16
+#define IDS_SUCCESS 17
+#define IDS_FILENAME_FORMATTING_INFO 18
+#define IDS_FILENAME_FORMAT_HELP 19
+#define IDS_SELECT_FOLDER_TO_LOAD_PLAYLISTS 20
+#define IDS_ERR_SELECTED_PATH_NOT_ON_DEVICE 21
+#define IDS_SUPPORTED_FORMAT_INFO 22
+#define IDS_SUPPORTED_FORMAT_HELP 23
+#define IDS_RESCAN_COMPLETE_SAVED 24
+#define IDS_RESCAN_COMPLETE 25
+#define IDS_ADVANCED 26
+#define IDS_UNBLACKLIST_DRIVE 27
+#define IDS_BLACKLIST_DRIVE 28
+#define IDS_DRIVE_CONNECTED_DISCONNECT_Q 29
+#define IDS_SLASH_AT_START 30
+#define IDS_DOT_AT_START 31
+#define IDS_NO_SLASH_OR_DOT 32
+#define IDS_EG_SLASH 33
+#define IDS_EG_DOT 34
+#define IDS_STRING35 35
+#define IDS_EG_NEITHER 35
+#define IDS_DELAYLOAD_FAILURE 36
+#define IDD_CONFIG 102
+#define IDD_CONFIG_GLOBAL 105
+#define IDR_PSP_ICON 110
+#define IDB_PNG2 111
+#define IDR_USB_ICON 111
+#define IDC_PLDIR 1001
+#define IDC_NAMEFORMAT 1002
+#define IDC_SUPPORTEDFORMATS 1003
+#define IDC_DRIVESELECT 1004
+#define IDC_COMBO_MANUALCONNECT 1005
+#define IDC_MANUALCONNECT 1006
+#define IDC_MANUALDISCONNECT 1007
+#define IDC_MANUALBLACKLIST 1008
+#define IDC_REFRESHCACHE 1011
+#define IDC_FILENAMEHELP 1012
+#define IDC_PLBROWSE 1013
+#define IDC_FORMATSHELP 1014
+#define IDC_RESCAN 1015
+#define IDC_PURGEFOLDERS 1016
+#define IDC_PL_WRITE_COMBO 1017
+#define IDC_PL_WRITE_EG 1018
+#define IDS_NULLSOFT_USB_DEVICE_PLUGIN 65534
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 113
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1019
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/Plugins/Portable/pmp_usb/resources/pspIcon.png b/Src/Plugins/Portable/pmp_usb/resources/pspIcon.png
new file mode 100644
index 00000000..46ff4f30
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/resources/pspIcon.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_usb/resources/usbIcon.png b/Src/Plugins/Portable/pmp_usb/resources/usbIcon.png
new file mode 100644
index 00000000..763a3c2c
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/resources/usbIcon.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_usb/usbdevice.cpp b/Src/Plugins/Portable/pmp_usb/usbdevice.cpp
new file mode 100644
index 00000000..dae8057a
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/usbdevice.cpp
@@ -0,0 +1,1913 @@
+#include "usbdevice.h"
+#include "resource.h"
+#include "usbplaylist.h"
+#include "usbplaylistsaver.h"
+#include "api.h"
+#include "../winamp/wa_ipc.h"
+#include <tataki/bitmap/bitmap.h>
+#include <tataki/canvas/bltcanvas.h>
+#include <shlobj.h>
+#include <strsafe.h>
+#include <shlwapi.h>
+
+// from main.cpp
+extern PMPDevicePlugin plugin;
+extern std::vector<USBDevice*> devices;
+extern bool loading_devices[26];
+// from utils.cpp
+extern BOOL RecursiveCreateDirectory(wchar_t* buf);
+extern bool supportedFormat(wchar_t * file, wchar_t * supportedFormats);
+extern DeviceType detectDeviceType(wchar_t drive);
+extern __int64 fileSize(wchar_t * filename);
+extern void removebadchars(wchar_t *s);
+extern wchar_t * fixReplacementVars(wchar_t *str, int str_size, Device * dev, songid_t song);
+static INT_PTR CALLBACK prefs_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
+int CopyFile(const wchar_t *infile, const wchar_t *outfile, void * callbackContext, void (*callback)(void * callbackContext, wchar_t * status), int * killswitch);
+// called from ml_pmp
+extern BOOL EjectVolume(TCHAR cDriveLetter);
+void CopyAlbumArt(const wchar_t *source, const wchar_t *destination);
+
+__int64 USBDevice::getDeviceCapacityAvailable() // in bytes
+{
+ ULARGE_INTEGER tfree={0,}, total={0,}, freeb={0,};
+ wchar_t path[4]=L"x:\\";
+ path[0]=drive;
+ GetDiskFreeSpaceEx(path, &tfree, &total, &freeb);
+ return freeb.QuadPart;
+}
+
+// called from ml_pmp
+__int64 USBDevice::getDeviceCapacityTotal()
+{
+ // in bytes
+ ULARGE_INTEGER tfree={0,}, total={0,}, freeb={0,};
+ wchar_t path[4]=L"x:\\";
+ path[0]=drive;
+ GetDiskFreeSpaceEx(path, &tfree, &total, &freeb);
+ return total.QuadPart;
+}
+
+// called from ml_pmp
+void USBDevice::Eject()
+{
+ // if you ejected successfully, you MUST call PMP_IPC_DEVICEDISCONNECTED and delete this
+ for(size_t i=0; i < devices.size(); i++)
+ {
+ USBDevice *device = devices.at(i);
+ if (device == this)
+ {
+ if (EjectVolume(drive))
+ {
+ devices.erase(devices.begin() + i);
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
+ delete this;
+ break;
+ }
+ else
+ {
+ wchar_t titleStr[128] = {0};
+ MessageBox(plugin.hwndLibraryParent,WASABI_API_LNGSTRINGW(IDS_FAILED_TO_EJECT_DRIVE), WASABI_API_LNGSTRINGW_BUF(IDS_ERROR,titleStr,128),0);
+ break;
+ }
+ }
+ }
+}
+
+// called from ml_pmp
+void USBDevice::Close()
+{
+ // save any changes, and call PMP_IPC_DEVICEDISCONNECTED AND delete this
+ for(size_t i=0; i < devices.size(); i++)
+ {
+ if(((USBDevice*)devices.at(i)) == this)
+ {
+ devices.erase(devices.begin() + i);
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
+ delete this;
+ break;
+ }
+ }
+}
+
+// called from ml_pmp
+// return 0 for success, -1 for failed or cancelled
+int USBDevice::transferTrackToDevice(const itemRecordW * track, // the track to transfer
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void *callbackContext, wchar_t *status), // call this every so often so the GUI can be updated. Including when finished!
+ songid_t * songid, // fill in the songid when you are finished
+ int * killswitch) // if this gets set to anything other than zero, the transfer has been cancelled by the user
+{
+ wchar_t fn[MAX_PATH] = L"X:\\";
+ lstrcpyn(fn, songFormat, MAX_PATH);
+ fn[0] = drive;
+ wchar_t * src = track->filename;
+ wchar_t ext[10] = {0};
+ wchar_t *e = wcsrchr(src,L'.');
+ if (e) lstrcpyn(ext, e, 10);
+
+ bool transcodefile = false;
+ if (transcoder && transcoder->ShouldTranscode(src))
+ {
+ int r = transcoder->CanTranscode(src, ext);
+ if (r != 0 && r != -1) transcodefile = true;
+ }
+
+ UsbSong *s = new UsbSong();
+ lstrcpyn(s->filename, src, MAX_PATH); //this will get written over, but for now we have this so that the user can keep the old filename
+
+ fillMetaData(s); // TODO: benski> used cached info inside track (itemRecordW) if available
+ fixReplacementVars(fn, MAX_PATH, this, (songid_t)s);
+
+ StringCchCat(fn, MAX_PATH, ext); //place extension
+ StringCchCopy(s->filename, MAX_PATH, fn);
+
+ wchar_t * dir = wcsrchr(fn,L'\\');
+ wchar_t * dir2 = wcsrchr(fn,L'/');
+ wchar_t slash;
+ if (dir2 > dir)
+ {
+ dir = dir2;
+ slash=L'/';
+ }
+ else slash = L'\\';
+ if (dir) *dir = 0;
+ RecursiveCreateDirectory(fn);
+ if (dir) *dir = slash;
+ int r;
+ if (transcodefile)
+ {
+ r = transcoder->TranscodeFile(src, fn, killswitch, callback, callbackContext);
+ }
+ else
+ {
+ r = CopyFile(src, fn, callbackContext, callback, killswitch);
+ }
+
+ if (r == 0)
+ {
+ // TODO: benski> do we need to update any fields from the transcoded filed?
+ CopyAlbumArt(src, fn);
+ writeRecordToDB(s);
+ callback(callbackContext, WASABI_API_LNGSTRINGW(IDS_DONE));
+ *songid = (songid_t)s;
+ }
+ else
+ {
+ callback(callbackContext, WASABI_API_LNGSTRINGW(IDS_TRANSFER_FAILED));
+ delete s;
+ }
+ return r;
+}
+
+// called from ml_pmp
+int USBDevice::trackAddedToTransferQueue(const itemRecordW *track)
+{
+ // return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
+ __int64 k = getTrackSizeOnDevice(track);
+ if(!k) return -2;
+ __int64 l = (__int64)k;
+ __int64 avail = getDeviceCapacityAvailable();
+ __int64 cmp = transferQueueLength;
+ cmp += l;
+ if(cmp > avail) return -1;
+ else {
+ transferQueueLength += l;
+ return 0;
+ }
+}
+
+// called from ml_pmp
+void USBDevice::trackRemovedFromTransferQueue(const itemRecordW *track)
+{
+ transferQueueLength -= (__int64)getTrackSizeOnDevice(track);
+}
+
+// called from ml_pmp
+// return the amount of space that will be taken up on the device by the track (once it has been tranferred)
+// or 0 for incompatable. This is usually the filesize, unless you are transcoding. An estimate is acceptable.
+__int64 USBDevice::getTrackSizeOnDevice(const itemRecordW *track)
+{
+ if(transcoder) {
+ if(transcoder->ShouldTranscode(track->filename)) {
+ int k = transcoder->CanTranscode(track->filename);
+ if(k != -1 && k != 0) return k;
+ return 0;
+ } else return fileSize(track->filename);
+ } else {
+ if(!supportedFormat(track->filename,supportedFormats)) return 0;
+ return fileSize(track->filename);
+ }
+}
+
+// called from ml_pmp
+void USBDevice::deleteTrack(songid_t songid)
+{
+ // physically remove from device. Be sure to remove it from all the playlists!
+ UsbSong * s = (UsbSong*)songid;
+
+ //errno == 2 is ENOENT
+ if(!_wunlink(s->filename) || errno == 2) { //will continue delete if file was deleted successfully or file path does not exist in the first place (errno==2)
+ for(size_t i=0; i < usbPlaylists.size(); i++) {
+
+ USBPlaylist * pl = usbPlaylists.at(i);
+ size_t l = pl->songs.size();
+ while(l--)
+ {
+ if(((UsbSong*)pl->songs.at(l)) == s)
+ {
+ // remove the track and rewrite the playlist
+ removeTrackFromPlaylist((int)i, (int)l);
+ }
+ }
+
+ if(purgeFolders[0]=='1')
+ {
+ RemoveDirectory(s->filename);
+ }
+ }
+ delete (UsbSong*)songid;
+ } else {
+ char titleStr[32] = {0};
+ MessageBoxA(plugin.hwndLibraryParent,WASABI_API_LNGSTRING(IDS_TRACK_IN_USE),
+ WASABI_API_LNGSTRING_BUF(IDS_ERROR,titleStr,32),0);
+ }
+}
+
+// called from ml_pmp
+// optional. Will be called at a good time to save changes
+void USBDevice::commitChanges()
+{
+ //update cache
+ tag();
+ cacheUpToDate = true;
+ SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)0,IPC_WRITE_EXTENDED_FILE_INFO);
+}
+
+// called from ml_pmp
+int USBDevice::getPlaylistCount()
+{
+ // always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
+ return (int)usbPlaylists.size();
+}
+
+// called from ml_pmp
+// PlaylistName(0) should return the name of the device.
+void USBDevice::getPlaylistName(int playlistnumber, wchar_t *buf, int len)
+{
+ wchar_t * pathName = usbPlaylists.at(playlistnumber)->filename;
+ if(playlistnumber != 0)
+ {
+ if(pathName[0])
+ {
+ wchar_t * playlistName = PathFindFileNameW(pathName);
+ lstrcpyn(buf,playlistName,len);
+ PathRemoveExtension(buf);
+ }
+ }
+ else //playlist number = 0 -> this is the device
+ {
+ if(pathName[0])
+ { //if we have a custom device name
+ lstrcpyn(buf,pathName,len);
+ }
+ else
+ {
+ WASABI_API_LNGSTRINGW_BUF(IDS_USB_DRIVE_X,buf,len);
+ wchar_t * x = wcsrchr(buf,L'X');
+ if(x) *x = drive;
+ }
+ }
+}
+
+// called from ml_pmp
+int USBDevice::getPlaylistLength(int playlistnumber)
+{
+ return (int)usbPlaylists.at(playlistnumber)->songs.size();
+}
+
+// called from ml_pmp
+songid_t USBDevice::getPlaylistTrack(int playlistnumber,int songnum)
+{
+ // returns a songid
+ return (songid_t) usbPlaylists.at(playlistnumber)->songs.at(songnum);
+}
+
+// called from ml_pmp
+void USBDevice::setPlaylistName(int playlistnumber, const wchar_t *buf)
+{
+ // with playlistnumber==0, set the name of the device.
+ USBPlaylist * pl = usbPlaylists.at(playlistnumber);
+ if(playlistnumber==0)
+ {
+ WritePrivateProfileString(L"pmp_usb",L"customName",buf,iniFile);
+ lstrcpyn(pl->filename,buf,sizeof(pl->filename)/sizeof(wchar_t));
+ }
+ else
+ {
+ wchar_t currentFilename[MAX_PATH] = {0};
+ lstrcpynW(currentFilename, pl->filename, MAX_PATH);
+
+ wchar_t * newFilename = const_cast<wchar_t *>(buf);
+ if(wcslen(buf) >= MAX_PATH-1) newFilename[MAX_PATH-1]=0;
+ while(newFilename && *newFilename && *newFilename == L'.') newFilename++;
+ removebadchars(newFilename);
+ StringCchPrintf(pl->filename,MAX_PATH,L"%s\\%s.m3u",pldir,newFilename);
+ pl->filename[0]=drive;
+ MoveFile(currentFilename, pl->filename);
+
+ pl->dirty=true;
+ }
+}
+
+// called from ml_pmp
+void USBDevice::playlistSwapItems(int playlistnumber, int posA, int posB)
+{
+ // swap the songs at position posA and posB
+ USBPlaylist * pl = (USBPlaylist*)usbPlaylists.at(playlistnumber);
+ UsbSong* a = pl->songs.at(posA);
+ UsbSong* b = pl->songs.at(posB);
+ pl->songs.insert(pl->songs.begin() + posA, b);
+ pl->songs.erase(pl->songs.begin() + posA + 1);
+ pl->songs.insert(pl->songs.begin() + posB, a);
+ pl->songs.erase(pl->songs.begin() + posB + 1);
+ pl->dirty = true;
+}
+
+// called from ml_pmp
+void USBDevice::sortPlaylist(int playlistnumber, int sortBy)
+{
+// TODO: implement
+}
+
+// called from ml_pmp
+void USBDevice::addTrackToPlaylist(int playlistnumber, songid_t songid)
+{
+ // adds songid to the end of the playlist
+ UsbSong* song = (UsbSong *) songid;
+ USBPlaylist * pl = (USBPlaylist*)usbPlaylists.at(playlistnumber);
+ pl->songs.push_back(song);
+
+ pl->dirty=true;
+}
+
+// called from ml_pmp
+void USBDevice::removeTrackFromPlaylist(int playlistnumber, int songnum)
+{
+ //where songnum is the position of the track in the playlist
+ USBPlaylist * pl = (USBPlaylist*)usbPlaylists.at(playlistnumber);
+ pl->songs.erase(pl->songs.begin() + songnum);
+
+ pl->dirty=true;
+}
+
+// called from ml_pmp
+void USBDevice::deletePlaylist(int playlistnumber)
+{
+ USBPlaylist * pl = (USBPlaylist*)usbPlaylists.at(playlistnumber);
+ _wunlink(pl->filename);
+ usbPlaylists.erase(usbPlaylists.begin() + playlistnumber);
+ delete pl;
+}
+
+// called from ml_pmp
+int USBDevice::newPlaylist(const wchar_t *name)
+{
+ // create empty playlist, returns playlistnumber. -1 for failed.
+ wchar_t plname[MAX_PATH] = {0};
+ StringCchCopy(plname, MAX_PATH, name);
+ removebadchars(plname);
+ wchar_t buff[MAX_PATH] = {0};
+ StringCchPrintf(buff, MAX_PATH, L"%s\\%s.m3u",pldir,plname);
+
+ USBPlaylist * pl = new USBPlaylist(*this, buff, false);
+ pl->filename[0]=drive;
+
+ //Lets save the playlist right away
+ USBPlaylistSaver playlistSaver(pl->filename, L"autosaved", pl);
+ playlistSaver.Save();
+
+ usbPlaylists.push_back(pl);
+ return (int)usbPlaylists.size()-1;
+}
+
+// called from ml_pmp
+void USBDevice::getTrackArtist(songid_t songid, wchar_t *buf, int len)
+{
+ UsbSong* song = (UsbSong*)songid;
+ if (!song) return;
+
+ buf[0] = L'\0';
+ if(!loadedUpToDate)
+ {
+ this->fillMetaData(song);
+ }
+ StringCchCopy(buf, len, song->artist);
+}
+
+// called from ml_pmp
+void USBDevice::getTrackAlbum(songid_t songid, wchar_t *buf, int len)
+{
+ UsbSong* song = (UsbSong*)songid;
+ if (!song) return;
+
+ buf[0] = L'\0';
+ if(!loadedUpToDate)
+ {
+ this->fillMetaData(song);
+ }
+ StringCchCopy(buf, len, song->album);
+}
+
+// called from ml_pmp
+void USBDevice::getTrackTitle(songid_t songid, wchar_t *buf, int len)
+{
+ UsbSong* song = (UsbSong*)songid;
+ if (!song) return;
+
+ if(!loadedUpToDate)
+ {
+ this->fillMetaData(song);
+ }
+ StringCchCopy(buf, len, song->title);
+}
+
+// called from ml_pmp
+int USBDevice::getTrackTrackNum(songid_t songid)
+{
+ UsbSong* song = (UsbSong*)songid;
+ if (!song) return 0;
+
+ if(!loadedUpToDate)
+ {
+ this->fillMetaData(song);
+ }
+ return song->track;
+}
+
+// called from ml_pmp
+int USBDevice::getTrackDiscNum(songid_t songid)
+{
+ UsbSong* song = (UsbSong*)songid;
+ if (!song) return 0;
+
+ if(!loadedUpToDate)
+ {
+ this->fillMetaData(song);
+ }
+ return song->discnum;
+}
+
+// called from ml_pmp
+void USBDevice::getTrackGenre(songid_t songid, wchar_t * buf, int len)
+{
+ UsbSong* song = (UsbSong*)songid;
+ if (!song) return;
+
+ if(!loadedUpToDate)
+ {
+ this->fillMetaData(song);
+ }
+ StringCchCopy(buf, len, song->genre);
+}
+
+// called from ml_pmp
+int USBDevice::getTrackYear(songid_t songid)
+{
+ UsbSong* song = (UsbSong*)songid;
+ if (!song) return 0;
+
+ if(!loadedUpToDate)
+ {
+ this->fillMetaData(song);
+ }
+ return song->year;
+}
+
+// called from ml_pmp
+__int64 USBDevice::getTrackSize(songid_t songid)
+{
+ // in bytes
+ UsbSong* song = (UsbSong*)songid;
+ if (!song) return 0;
+
+ if(!loadedUpToDate)
+ {
+ this->fillMetaData(song);
+ }
+ return song->size;
+}
+
+// called from ml_pmp
+int USBDevice::getTrackLength(songid_t songid)
+{
+ // in millisecs
+ UsbSong* song = (UsbSong*)songid;
+ if (!song) return 0;
+
+ if(!loadedUpToDate)
+ {
+ this->fillMetaData(song);
+ }
+ return song->length;
+}
+
+// called from ml_pmp
+int USBDevice::getTrackBitrate(songid_t songid)
+{
+ // in kbps
+ UsbSong* song = (UsbSong*)songid;
+ if (!song) return 0;
+
+ if(!loadedUpToDate)
+ {
+ this->fillMetaData(song);
+ }
+ return song->bitrate;
+}
+
+// called from ml_pmp
+int USBDevice::getTrackPlayCount(songid_t songid)
+{
+ UsbSong* song = (UsbSong*)songid;
+ if (!song) return 0;
+
+ if(!loadedUpToDate)
+ {
+ this->fillMetaData(song);
+ }
+ return song->playcount;
+}
+
+// called from ml_pmp
+int USBDevice::getTrackRating(songid_t songid)
+{
+ //0-5
+// TODO: implement
+ return 0;
+}
+
+// called from ml_pmp
+__time64_t USBDevice::getTrackLastPlayed(songid_t songid)
+{
+ // in unix time format
+// TODO: implement
+ return 0;
+
+}
+
+// called from ml_pmp
+__time64_t USBDevice::getTrackLastUpdated(songid_t songid)
+{
+ // in unix time format
+// TODO: implement
+ return 0;
+}
+
+// called from ml_pmp
+void USBDevice::getTrackAlbumArtist(songid_t songid, wchar_t *buf, int len)
+{
+ UsbSong* song = (UsbSong*)songid;
+ if (!song) return;
+
+ if(!loadedUpToDate)
+ {
+ this->fillMetaData(song);
+ }
+ StringCchCopy(buf, len, song->albumartist);
+}
+
+// called from ml_pmp
+void USBDevice::getTrackPublisher(songid_t songid, wchar_t *buf, int len)
+{
+ UsbSong* song = (UsbSong*)songid;
+ if (!song) return;
+
+ if(!loadedUpToDate)
+ {
+ this->fillMetaData(song);
+ }
+ StringCchCopy(buf, len, song->publisher);
+}
+
+// called from ml_pmp
+void USBDevice::getTrackComposer(songid_t songid, wchar_t *buf, int len)
+{
+ UsbSong* song = (UsbSong*)songid;
+ if (!song) return;
+
+ if(!loadedUpToDate)
+ {
+ this->fillMetaData(song);
+ }
+ StringCchCopy(buf, len, song->composer);
+}
+
+// called from ml_pmp
+int USBDevice::getTrackType(songid_t songid)
+{
+// TODO: implement
+ return 0;
+}
+
+// called from ml_pmp
+void USBDevice::getTrackExtraInfo(songid_t songid, const wchar_t *field, wchar_t *buf, int len)
+{
+// TODO: implement
+//optional
+}
+
+// called from ml_pmp
+// feel free to ignore any you don't support
+void USBDevice::setTrackArtist(songid_t songid, const wchar_t *value)
+{
+ UsbSong *song = (UsbSong *) songid;
+ if (song)
+ {
+ updateTrackField(song, DEVICEVIEW_COL_ARTIST, value, FIELD_STRING);
+ StringCchCopy(song->artist, FIELD_LENGTH, value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"artist", value);
+ }
+}
+
+// called from ml_pmp
+void USBDevice::setTrackAlbum(songid_t songid, const wchar_t *value)
+{
+ UsbSong *song = (UsbSong *) songid;
+ if (song)
+ {
+ updateTrackField(song, DEVICEVIEW_COL_ALBUM, value, FIELD_STRING);
+ StringCchCopy(song->album, FIELD_LENGTH, value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"album", value);
+ }
+}
+
+// called from ml_pmp
+void USBDevice::setTrackTitle(songid_t songid, const wchar_t *value)
+{
+ UsbSong *song = (UsbSong *) songid;
+ if (song)
+ {
+ updateTrackField(song, DEVICEVIEW_COL_TITLE, value, FIELD_STRING);
+ StringCchCopy(song->title, FIELD_LENGTH, value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"title", value);
+ }
+}
+
+// called from ml_pmp
+void USBDevice::setTrackTrackNum(songid_t songid, int value)
+{
+ UsbSong *song = (UsbSong *) songid;
+
+ if (song)
+ {
+ wchar_t track[FIELD_LENGTH] = {0};
+ updateTrackField(song, DEVICEVIEW_COL_TRACK, &value, FIELD_INTEGER);
+ song->track = value;
+ StringCchPrintf(track, FIELD_LENGTH, L"%d", value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"track", track);
+ }
+}
+
+// called from ml_pmp
+void USBDevice::setTrackDiscNum(songid_t songid, int value)
+{
+ UsbSong *song = (UsbSong *) songid;
+
+ if (song)
+ {
+ wchar_t discNum[FIELD_LENGTH] = {0};
+ updateTrackField(song, DEVICEVIEW_COL_DISC_NUMBER, &value, FIELD_INTEGER);
+ song->discnum = value;
+ StringCchPrintf(discNum, FIELD_LENGTH, L"%d", value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"disc", discNum);
+ }
+}
+
+// called from ml_pmp
+void USBDevice::setTrackGenre(songid_t songid, const wchar_t *value)
+{
+ UsbSong *song = (UsbSong *) songid;
+ if (song)
+ {
+ updateTrackField(song, DEVICEVIEW_COL_GENRE, value, FIELD_STRING);
+ StringCchCopy(song->genre, FIELD_LENGTH, value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"genre", value);
+ }
+}
+
+// called from ml_pmp
+void USBDevice::setTrackYear(songid_t songid, int year)
+{
+ UsbSong *song = (UsbSong *) songid;
+
+ if (song)
+ {
+ wchar_t yearStr[FIELD_LENGTH] = {0};
+ updateTrackField(song, DEVICEVIEW_COL_YEAR, &year, FIELD_INTEGER);
+ song->year = year;
+ StringCchPrintf(yearStr, FIELD_LENGTH, L"%d", year);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"year", yearStr);
+ }
+}
+
+// called from ml_pmp
+void USBDevice::setTrackPlayCount(songid_t songid, int value)
+{
+ UsbSong *song = (UsbSong *) songid;
+
+ if (song)
+ {
+ wchar_t playCount[FIELD_LENGTH] = {0};
+ updateTrackField(song, DEVICEVIEW_COL_PLAY_COUNT, &value, FIELD_INTEGER);
+ song->playcount = value;
+ StringCchPrintf(playCount, FIELD_LENGTH, L"%d", value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"playcount", playCount);
+ }
+}
+
+// called from ml_pmp
+void USBDevice::setTrackRating(songid_t songid, int value)
+{
+ UsbSong *song = (UsbSong *) songid;
+
+ if (song)
+ {
+ wchar_t rating[FIELD_LENGTH] = {0};
+ updateTrackField(song, DEVICEVIEW_COL_PLAY_COUNT, &value, FIELD_INTEGER);
+ song->playcount = value;
+ StringCchPrintf(rating, FIELD_LENGTH, L"%d", value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"rating", rating);
+ }
+}
+
+// called from ml_pmp
+void USBDevice::setTrackLastPlayed(songid_t songid, __time64_t value)
+{
+// TODO: implement
+
+} // in unix time format
+
+// called from ml_pmp
+void USBDevice::setTrackLastUpdated(songid_t songid, __time64_t value)
+{
+// TODO: implement
+
+} // in unix time format
+
+// called from ml_pmp
+void USBDevice::setTrackAlbumArtist(songid_t songid, const wchar_t *value)
+{
+ UsbSong *song = (UsbSong *) songid;
+ if (song)
+ {
+ updateTrackField(song, DEVICEVIEW_COL_ALBUM_ARTIST, value, FIELD_STRING);
+ StringCchCopy(song->albumartist, FIELD_LENGTH, value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"albumartist", value);
+ }
+}
+
+// called from ml_pmp
+void USBDevice::setTrackPublisher(songid_t songid, const wchar_t *value)
+{
+ UsbSong *song = (UsbSong *) songid;
+ if (song)
+ {
+ updateTrackField(song, DEVICEVIEW_COL_PUBLISHER, value, FIELD_STRING);
+ StringCchCopy(song->publisher, FIELD_LENGTH, value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"publisher", value);
+ }
+}
+
+// called from ml_pmp
+void USBDevice::setTrackComposer(songid_t songid, const wchar_t *value)
+{
+ UsbSong *song = (UsbSong *) songid;
+ if (song)
+ {
+ updateTrackField(song, DEVICEVIEW_COL_COMPOSER, value, FIELD_STRING);
+ StringCchCopy(song->composer, FIELD_LENGTH, value);
+ AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"composer", value);
+ }
+}
+
+// called from ml_pmp
+void USBDevice::setTrackExtraInfo(songid_t songid, const wchar_t *field, const wchar_t *value)
+{
+// TODO: implement
+
+} //optional
+
+// called from ml_pmp
+bool USBDevice::playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue)
+{
+ // return false if unsupported
+ if(!enqueue) //clear playlist
+ {
+ SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_DELETE);
+ }
+
+ for(int i=0; i<listLength; i++)
+ {
+ UsbSong *curSong = (UsbSong*)songidList[i];
+
+ if (curSong)
+ {
+ enqueueFileWithMetaStructW s={0};
+ s.filename = _wcsdup(curSong->filename);
+ s.title = _wcsdup(curSong->title);
+ s.ext = NULL;
+ s.length = curSong->length/1000;
+
+ SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
+ }
+ else
+ {
+ char titleStr[32] = {0};
+ MessageBoxA(plugin.hwndWinampParent,WASABI_API_LNGSTRING(IDS_CANNOT_OPEN_FILE),
+ WASABI_API_LNGSTRING_BUF(IDS_ERROR,titleStr,32),0);
+ }
+ }
+
+ if(!enqueue)
+ {
+ //play item startPlaybackAt
+ SendMessage(plugin.hwndWinampParent,WM_WA_IPC,startPlaybackAt,IPC_SETPLAYLISTPOS);
+ SendMessage(plugin.hwndWinampParent,WM_COMMAND,40047,0); //stop
+ SendMessage(plugin.hwndWinampParent,WM_COMMAND,40045,0); //play
+ }
+ return true;
+}
+
+// called from ml_pmp
+intptr_t USBDevice::extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4)
+{
+ switch(param1)
+ {
+ case DEVICE_SET_ICON:
+ {
+ MLTREEIMAGE * i = (MLTREEIMAGE*)param2;
+ i->hinst = plugin.hDllInstance;
+ switch(devType)
+ {
+ case TYPE_PSP:
+ i->resourceId = IDR_PSP_ICON;
+ break;
+ default:
+ i->resourceId = IDR_USB_ICON;
+ break;
+ }
+ }
+ break;
+ case DEVICE_GET_ICON:
+ {
+ if (param2 <= 16 && param3 <= 16)
+ {
+ // TODO: get the name of the DLL at load time
+ StringCchPrintfW((wchar_t *)param4, 260, L"res://%s/PNG/#%u", L"pmp_usb.dll", (devType==TYPE_PSP)?IDR_PSP_ICON:IDR_USB_ICON);
+ }
+
+ }
+ break;
+
+ case DEVICE_SUPPORTED_METADATA:
+ {
+ intptr_t supported = SUPPORTS_ARTIST | SUPPORTS_ALBUM | SUPPORTS_TITLE | SUPPORTS_TRACKNUM | SUPPORTS_DISCNUM | SUPPORTS_GENRE |
+ SUPPORTS_YEAR | SUPPORTS_SIZE | SUPPORTS_LENGTH | SUPPORTS_BITRATE | SUPPORTS_LASTUPDATED | SUPPORTS_ALBUMARTIST |
+ SUPPORTS_COMPOSER | SUPPORTS_PUBLISHER | SUPPORTS_ALBUMART;
+ return supported;
+ }
+ break;
+
+ case DEVICE_CAN_RENAME_DEVICE:
+ return 1;
+
+ case DEVICE_GET_INI_FILE:
+ StringCchCopy((wchar_t*)param2, MAX_PATH, iniFile);
+ break;
+ case DEVICE_GET_PREFS_DIALOG:
+ if(param3 == 0)
+ {
+ pref_tab * p = (pref_tab *)param2;
+ p->hinst = WASABI_API_LNG_HINST;
+ p->dlg_proc = prefs_dialogProc;
+ p->res_id = IDD_CONFIG;
+ WASABI_API_LNGSTRINGW_BUF(IDS_ADVANCED,p->title,100);
+ }
+ break;
+ case DEVICE_DONE_SETTING:
+ UsbSong * song = (UsbSong *) param2;
+ AGAVE_API_METADATA->WriteExtendedFileInfo(song->filename);
+ return true;
+ break;
+ }
+ return false;
+}
+
+// called from ml_pmp
+bool USBDevice::copyToHardDriveSupported()
+{
+ return true;
+}
+
+// called from ml_pmp
+__int64 USBDevice::songSizeOnHardDrive(songid_t song)
+{
+ // how big a song will be when copied back. Return -1 for not supported.
+// TODO: implement
+ return 0;
+
+}
+
+// called from ml_pmp
+int USBDevice::copyToHardDrive(songid_t song, // the song to copy
+ wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ )
+{
+ // -1 for failed/not supported. 0 for success.
+ UsbSong* track = (UsbSong*)song;
+ wchar_t * ext = PathFindExtensionW(track->filename);
+ if(ext && (lstrlen(ext)<10)) StringCchCat(path,MAX_PATH, ext); // append correct extention
+ return CopyFile(track->filename,path,callbackContext, callback, killswitch);
+}
+
+// called from ml_pmp
+// art functions
+void USBDevice::setArt(songid_t songid, void *buf, int w, int h)
+{
+ //buf is in format ARGB32*
+ // TODO: implement
+}
+
+// called from ml_pmp
+pmpart_t USBDevice::getArt(songid_t songid)
+{
+ UsbSong *song = (UsbSong *)songid;
+ ARGB32 *bits;
+ int w, h;
+ if (AGAVE_API_ALBUMART && AGAVE_API_ALBUMART->GetAlbumArt(song->filename, L"cover", &w, &h, &bits) == ALBUMART_SUCCESS && bits)
+ {
+ return (pmpart_t) new USBArt(bits, w, h);
+ }
+ return 0;
+}
+
+// called from ml_pmp
+void USBDevice::releaseArt(pmpart_t art)
+{
+ USBArt *image = (USBArt *)art;
+ delete image;
+}
+
+// called from ml_pmp
+int USBDevice::drawArt(pmpart_t art, HDC dc, int x, int y, int w, int h)
+{
+ USBArt *image = (USBArt *)art;
+ if (image)
+ {
+ HQSkinBitmap temp(image->bits, image->w, image->h); // wrap into a SkinBitmap (no copying involved)
+ DCCanvas canvas(dc);
+ temp.stretch(&canvas,x,y,w,h);
+ return 1;
+ }
+ return 0;
+}
+
+// called from ml_pmp
+void USBDevice::getArtNaturalSize(pmpart_t art, int *w, int *h)
+{
+ // TODO: implement
+ USBArt *image = (USBArt *)art;
+ if (image)
+ {
+ *w = image->w;
+ *h = image->h;
+ }
+}
+
+// called from ml_pmp
+void USBDevice::setArtNaturalSize(pmpart_t art, int w, int h)
+{
+ // TODO: implement
+}
+
+// called from ml_pmp
+void USBDevice::getArtData(pmpart_t art, void* data)
+{
+ USBArt *image = (USBArt *)art;
+ if (image)
+ memcpy(data, image->bits, image->w*image->h*sizeof(ARGB32));
+ // data ARGB32* is at natural size
+}
+
+// called from ml_pmp
+bool USBDevice::artIsEqual(pmpart_t a, pmpart_t b)
+{
+ if (a == b)
+ return true;
+ // TODO: implement
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Initialize class statics
+nde_database_t USBDevice::discDB = 0;
+
+// The getter that returns the master playlist
+// the playlist vector always carries a master playlist
+USBPlaylist* USBDevice::getMasterPlaylist()
+{
+ for (std::vector<USBPlaylist*>::const_iterator e = usbPlaylists.begin(); e != usbPlaylists.end(); e++)
+ {
+ USBPlaylist* playlist = (*e);
+ if (playlist->isMaster()) return playlist;
+ }
+ return NULL;
+}
+
+// constructor
+USBDevice::USBDevice(wchar_t drive, pmpDeviceLoading * load): transcoder(NULL) {
+ deviceTable = 0;
+ StringCchPrintf(ndeDataFile, 100, L"%c:\\winamp_metadata.dat", drive);
+ StringCchPrintf(ndeIndexFile, 100, L"%c:\\winamp_metadata.idx", drive);
+ load->dev = this;
+ load->UpdateCaption = NULL;
+ //pass load to ml_pmp, ml updates load->UpdateCaption and context
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)load,PMP_IPC_DEVICELOADING);
+ if(load->UpdateCaption) {
+ wchar_t buf[100] = L"";
+ WASABI_API_LNGSTRINGW_BUF(IDS_LOADING_DRIVE_X,buf,100);
+ wchar_t * x = wcsrchr(buf,L'X');
+ if(x) *x = drive;
+ load->UpdateCaption(buf,load->context);
+ }
+
+ devType = detectDeviceType(drive);
+ // load settings
+ StringCchCopy(iniFile,MAX_PATH,L"x:\\pmp_usb.ini");
+ iniFile[0]=drive;
+
+ wchar_t customName[FIELD_LENGTH] = {0};
+ GetPrivateProfileString(L"pmp_usb",L"pldir",devType==TYPE_PSP?L"X:\\PSP\\MUSIC":L"X:",pldir,sizeof(pldir)/sizeof(wchar_t),iniFile);
+ GetPrivateProfileString(L"pmp_usb",L"songFormat",devType==TYPE_PSP?L"X:\\PSP\\MUSIC\\<Artist> - <Album>\\## - <Title>":L"X:\\<Artist>\\<Album>\\## - <Title>",songFormat,sizeof(songFormat)/sizeof(wchar_t),iniFile);
+ GetPrivateProfileString(L"pmp_usb",L"supportedFormats",L"mp3;wav;wma;m4a;aac;ogg;flac",supportedFormats,sizeof(supportedFormats)/sizeof(wchar_t),iniFile);
+ GetPrivateProfileString(L"pmp_usb",L"purgeFolders",L"1",purgeFolders,sizeof(purgeFolders)/sizeof(wchar_t),iniFile);
+ GetPrivateProfileString(L"pmp_usb",L"customName",devType==TYPE_PSP?L"Sony PSP":L"",customName,sizeof(customName)/sizeof(wchar_t),iniFile);
+ pl_write_mode = GetPrivateProfileInt(L"pmp_usb",L"pl_write_mode",0,iniFile);
+ pldir[0] = drive;
+ songFormat[0] = drive;
+
+ transferQueueLength = 0;
+ this->drive = drive;
+ USBPlaylist * mpl = new USBPlaylist(*this, customName, true);
+ usbPlaylists.push_back(mpl);
+ wchar_t * pl = _wcsdup(pldir);
+ pl[0] = drive;
+ RecursiveCreateDirectory(pl);
+ wchar_t root[3] = L"X:";
+ root[0] = drive;
+
+ openDeviceTable();
+
+ fileProbe(root);
+
+ // sort out and read playlists....
+ if (WASABI_API_PLAYLISTMNGR != NULL && WASABI_API_PLAYLISTMNGR != (api_playlistmanager *)1)
+ {
+ for (std::vector<USBPlaylist*>::const_iterator e = usbPlaylists.begin(); e != usbPlaylists.end(); e++)
+ {
+ USBPlaylist* playlist = (*e);
+ if (playlist && playlist->isMaster() == false)
+ {
+ WASABI_API_PLAYLISTMNGR->Load(playlist->getFilename(), playlist);
+ }
+ }
+ }
+
+ tag();
+ devices.push_back(this);
+ extern HWND config;
+ if(config) PostMessage(config,WM_USER,0,0);
+
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICECONNECTED);
+ setupTranscoder();
+ loading_devices[drive-'A']=false;
+}
+
+USBDevice::USBDevice() : transcoder(NULL), drive(0), devType(TYPE_OTHER), pl_write_mode(0), transferQueueLength(0), cacheUpToDate(false), loadedUpToDate(false)
+{
+ deviceTable = 0;
+ ZeroMemory(ndeDataFile, sizeof(ndeDataFile));
+ ZeroMemory(ndeIndexFile, sizeof(ndeIndexFile));
+
+ ZeroMemory(iniFile, sizeof(iniFile));
+ ZeroMemory(pldir, sizeof(pldir));
+ ZeroMemory(songFormat, sizeof(songFormat));
+ ZeroMemory(supportedFormats, sizeof(supportedFormats));
+ ZeroMemory(purgeFolders, sizeof(purgeFolders));
+}
+
+USBDevice::~USBDevice()
+{
+ closeDeviceTable();
+ if (transcoder) SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)transcoder,PMP_IPC_RELEASE_TRANSCODER);
+}
+
+//read files from device's folder 'indir'
+void USBDevice::fileProbe(wchar_t * indir) {
+ wchar_t dir[MAX_PATH] = {0};
+ WIN32_FIND_DATA FindFileData = {0};
+ StringCchPrintf(dir,MAX_PATH,L"%s\\*",indir);
+ HANDLE hFind = FindFirstFile(dir, &FindFileData);
+ if (hFind == INVALID_HANDLE_VALUE) return;
+ do {
+ if(wcscmp(FindFileData.cFileName,L".") && wcscmp(FindFileData.cFileName,L"..")) {
+ wchar_t fullfile[MAX_PATH] = {0};
+ StringCchPrintf(fullfile,MAX_PATH,L"%s\\%s",indir,FindFileData.cFileName);
+
+ if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //file is directory
+ {
+ fileProbe(fullfile); //call until we have found a file
+ }
+ else // found a file!
+ {
+ wchar_t * ext = wcsrchr(FindFileData.cFileName,'.');
+ if(!ext) continue; //no files with extensions in the directory
+ ext++;
+ if(!_wcsicmp(ext,L"m3u")) // its a playlist
+ {
+ USBPlaylist *playlist = new USBPlaylist(*this, fullfile, false);
+ usbPlaylists.push_back(playlist);
+ continue;
+ } //its a file
+ if(supportedFormat(fullfile,supportedFormats)) //check extension
+ {
+ UsbSong *s = new UsbSong();
+ lstrcpynW(s->filename, fullfile, MAX_PATH);
+ this->getMasterPlaylist()->songs.push_back(s); //add track to alltrack list (playlist 0)
+ }
+ }
+ }
+ } while(FindNextFile(hFind, &FindFileData) != 0);
+ FindClose(hFind);
+}
+
+int USBDevice::getFileInfoW(const wchar_t *filename, const wchar_t *metadata, wchar_t *dest, size_t len)
+{
+ dest[0]=0;
+ return AGAVE_API_METADATA->GetExtendedFileInfo(filename, metadata, dest, len);
+}
+
+// read all metadata from the metadata wasabi service
+void USBDevice::fillMetaData(UsbSong *t)
+{
+ if (!t->filled)
+ {
+ wchar_t tmp[1024] = {0};
+ if (getFileInfoW(t->filename,L"artist",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ StringCchCopyW(t->artist, FIELD_LENGTH, tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename,L"title",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ StringCchCopyW(t->title, FIELD_LENGTH, tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename,L"album",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ StringCchCopyW(t->album, FIELD_LENGTH, tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename,L"composer",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ StringCchCopyW(t->composer, FIELD_LENGTH, tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename,L"publisher",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ StringCchCopyW(t->publisher, FIELD_LENGTH, tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename,L"albumartist",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ StringCchCopyW(t->albumartist, FIELD_LENGTH, tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename, L"length",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ t->length = _wtoi(tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename, L"track",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ t->track = _wtoi(tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename, L"disc",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ t->discnum = _wtoi(tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename, L"genre",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ StringCchCopyW(t->genre, FIELD_LENGTH, tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename, L"year",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ if (!wcsstr(tmp,L"__") && !wcsstr(tmp,L"/") && !wcsstr(tmp,L"\\") && !wcsstr(tmp,L"."))
+ {
+ wchar_t *p = tmp;
+ while (p && *p)
+ {
+ if (*p == L'_') *p=L'0';
+ p++;
+ }
+ t->year = _wtoi(tmp);
+ t->filled = true;
+ }
+ }
+
+ if (getFileInfoW(t->filename, L"bitrate",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ t->bitrate = _wtoi(tmp);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename, L"size",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ t->size = _wtoi(tmp);
+ t->filled = true;
+ }
+ else
+ {
+ t->size = fileSize(t->filename);
+ t->filled = true;
+ }
+
+ if (getFileInfoW(t->filename, L"playcount",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
+ {
+ t->playcount = _wtoi(tmp);
+ t->filled = true;
+ }
+ }
+}
+
+int USBDevice::openDeviceDatabase()
+{
+ Nullsoft::Utility::AutoLock lock(dbcs);
+ if (!discDB)
+ {
+ discDB = NDE_CreateDatabase(plugin.hDllInstance);
+ }
+ return NDE_USB_SUCCESS;
+}
+
+void USBDevice::createDeviceFields()
+{
+ // create defaults
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_FILENAME, L"filename", FIELD_FILENAME);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_ARTIST, L"artist", FIELD_STRING);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_ALBUM, L"album", FIELD_STRING);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_TITLE, L"title", FIELD_STRING);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_GENRE, L"genre", FIELD_STRING);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_ALBUM_ARTIST, L"albumartist", FIELD_STRING);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_PUBLISHER, L"publisher", FIELD_STRING);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_COMPOSER, L"composer", FIELD_STRING);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_YEAR, L"year", FIELD_INTEGER);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_TRACK, L"track", FIELD_INTEGER);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_BITRATE, L"bitrate", FIELD_INTEGER);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_DISC_NUMBER, L"discnumber", FIELD_INTEGER);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_LENGTH, L"length", FIELD_INTEGER);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_SIZE, L"size", FIELD_INTEGER);
+ NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_PLAY_COUNT, L"playcount", FIELD_INTEGER);
+ NDE_Table_PostColumns(deviceTable);
+ NDE_Table_AddIndexByIDW(deviceTable, 0, L"filename");
+}
+
+int USBDevice::openDeviceTable() {
+ Nullsoft::Utility::AutoLock lock(dbcs);
+ int ret = openDeviceDatabase();
+ if (ret != NDE_USB_SUCCESS)
+ return ret;
+
+ if (!deviceTable)
+ {
+ deviceTable = NDE_Database_OpenTable(discDB, ndeDataFile, ndeIndexFile,NDE_OPEN_ALWAYS,NDE_CACHE);
+ if (deviceTable) {
+ createDeviceFields();
+ }
+ }
+ return deviceTable?NDE_USB_SUCCESS:NDE_USB_FAILURE;
+}
+
+void USBDevice::closeDeviceTable()
+{
+ if (deviceTable)
+ {
+ NDE_Table_Sync(deviceTable);
+ NDE_Database_CloseTable(discDB, deviceTable);
+ deviceTable=0;
+ }
+
+}
+
+void USBDevice::CloseDatabase()
+{
+ if (discDB)
+ NDE_DestroyDatabase(discDB);
+ discDB=0;
+}
+
+static void db_setFieldInt(nde_scanner_t s, unsigned char id, int data)
+{
+ nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
+ if (!f) f = NDE_Scanner_NewFieldByID(s, id);
+ NDE_IntegerField_SetValue(f, data);
+}
+
+static void db_setFieldString(nde_scanner_t s, unsigned char id, const wchar_t *data)
+{
+ nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
+ if (!f) f = NDE_Scanner_NewFieldByID(s, id);
+ NDE_StringField_SetString(f, data);
+}
+
+static void db_removeField(nde_scanner_t s, unsigned char id)
+{
+ nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
+ if (f)
+ {
+ NDE_Scanner_DeleteField(s, f);
+ }
+}
+
+static int db_getFieldInt(nde_scanner_t s, unsigned char id, int defaultVal)
+{
+ nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
+ if (f)
+ {
+ return NDE_IntegerField_GetValue(f);
+ }
+ else
+ {
+ return defaultVal;
+ }
+}
+
+static wchar_t* db_getFieldString(nde_scanner_t s, unsigned char id)
+{
+ nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
+ if (f)
+ {
+ return NDE_StringField_GetString(f);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void USBDevice::refreshNDECache(void) {
+ tag();
+ SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)0,IPC_WRITE_EXTENDED_FILE_INFO);
+}
+
+int filenamecmp(const wchar_t *f1, const wchar_t *f2)
+{
+ for (;;)
+ {
+ wchar_t c1 = *f1++;
+ wchar_t c2 = *f2++;
+ if (!c1 && !c2)
+ return 0;
+ if (!c1)
+ return -1;
+ if (!c2)
+ return 1;
+ c1 = towupper(c1);
+ c2 = towupper(c2);
+ if (c1 == '\\')
+ c1 = '/';
+ if (c2 == '\\')
+ c2 = '/';
+ if (c1 < c2)
+ return -1;
+ else if (c1 > c2)
+ return 1;
+ }
+}
+//
+UsbSong *USBDevice::findSongInMasterPlaylist(const wchar_t *songfn) {
+ USBPlaylist* mpl = this->getMasterPlaylist();
+ for (std::vector<UsbSong*>::const_iterator e = mpl->songs.begin(); e != mpl->songs.end(); e++)
+ {
+ if (filenamecmp(songfn, (*e)->filename) == 0) {
+ return (*e);
+ }
+ }
+ return NULL;
+}
+
+void USBDevice::tag(void)
+{
+ /**
+ loop thru the newly probed disk
+ check for updates on each of the songs
+ if there is an update or if metadata does not exist for the file, re-read the metadata
+ if there is no update and the song is found in the master playlist, just read from the db
+ */
+ USBPlaylist *mpl = this->getMasterPlaylist();
+ int top = (int)mpl->songs.size();
+
+ //first load in all songs data from ID3 - this is what we were trying to avoid
+ for(int i = 0; i < top; i++)
+ {
+ UsbSong *t = (UsbSong *)mpl->songs.at(i);
+
+ // now check if this song has changed
+ // check if the nde cache exists in the first place
+ if (songChanged(t))
+ {
+ this->fillMetaData(t);
+ // now since we've refreshed the metadata write to NDE
+ this->writeRecordToDB(t);
+ }
+ else
+ {
+ // read the record from NDE
+ if (this->readRecordFromDB(t) == false)
+ {
+ this->fillMetaData(t);
+ this->writeRecordToDB(t);
+ }
+ }
+ }
+
+ for (size_t i=0;i<usbPlaylists.size();i++)
+ {
+ USBPlaylist *pl = usbPlaylists[i];
+ if (pl->dirty)
+ {
+ // Lets delete the current playlist file
+ _wunlink(pl->filename);
+
+ USBPlaylistSaver playlistSaver(pl->filename, L"autosaved", pl);
+ playlistSaver.Save();
+ pl->dirty = false;
+ }
+ }
+
+ cacheUpToDate = true;
+ loadedUpToDate = true;
+}
+
+// check change in filetimes for the song
+bool USBDevice::songChanged(UsbSong* song)
+{
+ if (!song) return true;
+ if (!PathFileExists(ndeDataFile)) return true;
+
+ //For fLastAccess/LastWrite information, use GetFileAttributesEx
+ WIN32_FILE_ATTRIBUTE_DATA cacheFileInfo, tempInfo;
+ GetFileAttributesExW(ndeDataFile, GetFileExInfoStandard, (LPVOID)&cacheFileInfo);
+
+ if(song->filename)
+ {
+ GetFileAttributesExW(song->filename, GetFileExInfoStandard, (LPVOID)&tempInfo);
+ }
+ else
+ {
+ return true;
+ }
+
+ //cachetime - song time
+ if(CompareFileTime(&cacheFileInfo.ftLastWriteTime, &tempInfo.ftLastWriteTime) < 0)
+ {
+ return true;
+ }
+ return false;
+}
+
+// read metadata for a specific song from the NDE cache
+bool USBDevice::readRecordFromDB(UsbSong* song)
+{
+ if (!song) return false;
+
+ Nullsoft::Utility::AutoLock lock(dbcs);
+ openDeviceTable();
+ nde_scanner_t scanner = NDE_Table_CreateScanner(deviceTable);
+
+ if (NDE_Scanner_LocateFilename(scanner, DEVICEVIEW_COL_FILENAME, FIRST_RECORD, song->filename))
+ {
+ nde_field_t artist = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_ARTIST);
+ wchar_t* artistString = NDE_StringField_GetString(artist);
+ lstrcpyn(song->artist, artistString, FIELD_LENGTH);
+
+ nde_field_t album = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_ALBUM);
+ wchar_t* albumString = NDE_StringField_GetString(album);
+ lstrcpyn(song->album, albumString, FIELD_LENGTH);
+
+ nde_field_t albumArtist = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_ALBUM_ARTIST);
+ wchar_t* albumArtistString = NDE_StringField_GetString(albumArtist);
+ lstrcpyn(song->albumartist, albumArtistString, FIELD_LENGTH);
+
+ nde_field_t publisher = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_PUBLISHER);
+ wchar_t* publisherString = NDE_StringField_GetString(publisher);
+ lstrcpyn(song->publisher, publisherString, FIELD_LENGTH);
+
+ nde_field_t composer = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_COMPOSER);
+ wchar_t* composerString = NDE_StringField_GetString(composer);
+ lstrcpyn(song->composer, composerString, FIELD_LENGTH);
+
+ nde_field_t title = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_TITLE);
+ wchar_t* titleString = NDE_StringField_GetString(title);
+ lstrcpyn(song->title, titleString, FIELD_LENGTH);
+
+ nde_field_t genre = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_GENRE);
+ wchar_t* genreString = NDE_StringField_GetString(genre);
+ lstrcpyn(song->genre, genreString, FIELD_LENGTH);
+
+ nde_field_t track = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_TRACK);
+ int trackInt= NDE_IntegerField_GetValue(track);
+ song->track = trackInt;
+
+ nde_field_t year = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_YEAR);
+ int yearInt= NDE_IntegerField_GetValue(year);
+ song->year = yearInt;
+
+ nde_field_t discNumber = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_DISC_NUMBER);
+ int discNumberInt= NDE_IntegerField_GetValue(discNumber);
+ song->discnum = discNumberInt;
+
+ nde_field_t length = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_LENGTH);
+ int lengthInt= NDE_IntegerField_GetValue(length);
+ song->length = lengthInt;
+
+ nde_field_t bitrate = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_BITRATE);
+ int bitrateInt= NDE_IntegerField_GetValue(bitrate);
+ song->bitrate = bitrateInt;
+
+ nde_field_t size = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_SIZE);
+ int sizeInt= NDE_IntegerField_GetValue(size);
+ song->size = sizeInt;
+
+ nde_field_t playcount = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_PLAY_COUNT);
+ int playcountInt = NDE_IntegerField_GetValue(playcount);
+ song->playcount = playcountInt;
+ }
+ else
+ {
+ return false;
+ }
+
+ NDE_Table_DestroyScanner(deviceTable, scanner);
+ //closeDeviceTable();
+ return true;
+}
+
+
+
+// write a single record to the nde database
+void USBDevice::writeRecordToDB(UsbSong* songToPrint) {
+ Nullsoft::Utility::AutoLock lock(dbcs);
+ openDeviceTable();
+ nde_scanner_t s = NDE_Table_CreateScanner(deviceTable);
+
+ if (! NDE_Scanner_LocateFilename(s, DEVICEVIEW_COL_FILENAME, FIRST_RECORD, songToPrint->filename))
+ {
+ NDE_Scanner_New(s);
+ }
+
+ if (songToPrint->filename)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_FILENAME, songToPrint->filename);
+ }
+
+ if (songToPrint->artist)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_ARTIST, songToPrint->artist);
+ }
+
+ if (songToPrint->albumartist)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_ALBUM_ARTIST, songToPrint->albumartist);
+ }
+
+ if (songToPrint->publisher)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_PUBLISHER, songToPrint->publisher);
+ }
+
+ if (songToPrint->composer)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_COMPOSER, songToPrint->composer);
+ }
+
+ if (songToPrint->album)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_ALBUM, songToPrint->album);
+ }
+
+ if (songToPrint->title)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_TITLE, songToPrint->title);
+ }
+
+ if (songToPrint->genre)
+ {
+ db_setFieldString(s, DEVICEVIEW_COL_GENRE, songToPrint->genre);
+ }
+
+ if (songToPrint->year)
+ {
+ db_setFieldInt(s, DEVICEVIEW_COL_YEAR, songToPrint->year);
+ }
+
+ if (songToPrint->track)
+ {
+ db_setFieldInt(s, DEVICEVIEW_COL_TRACK, songToPrint->track);
+ }
+
+ if (songToPrint->bitrate)
+ {
+ db_setFieldInt(s, DEVICEVIEW_COL_BITRATE, songToPrint->bitrate);
+ }
+
+ if (songToPrint->discnum)
+ {
+ db_setFieldInt(s, DEVICEVIEW_COL_DISC_NUMBER, songToPrint->discnum);
+ }
+
+ if (songToPrint->length)
+ {
+ db_setFieldInt(s, DEVICEVIEW_COL_LENGTH, songToPrint->length);
+ }
+
+ if (songToPrint->size)
+ {
+ db_setFieldInt(s, DEVICEVIEW_COL_SIZE, (int)songToPrint->size);
+ }
+
+ if (songToPrint->playcount)
+ {
+ db_setFieldInt(s, DEVICEVIEW_COL_PLAY_COUNT, songToPrint->playcount);
+ }
+ NDE_Scanner_Post(s);
+ NDE_Table_DestroyScanner(deviceTable, s);
+ //NDE_Table_Sync(deviceTable);
+ //closeDeviceTable();
+}
+
+void USBDevice::setupTranscoder() {
+ if(transcoder) SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)transcoder,PMP_IPC_RELEASE_TRANSCODER);
+ transcoder = (Transcoder*)SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)this,PMP_IPC_GET_TRANSCODER);
+ if(!transcoder) return;
+
+ wchar_t * p = supportedFormats;
+ while(p && *p) {
+ wchar_t * np = wcschr(p,L';');
+ if(np) *np = 0;
+ transcoder->AddAcceptableFormat(p);
+ if(np) { *np = L';'; p=np+1; }
+ else return;
+ }
+}
+
+BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam)
+{
+ wchar_t cl[32] = {0};
+ GetClassNameW(hwnd, cl, ARRAYSIZE(cl));
+ if (!lstrcmpiW(cl, WC_TREEVIEW))
+ {
+ PostMessage(hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection(hwnd));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+wchar_t pldir[MAX_PATH] = {0};
+int CALLBACK WINAPI BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ if(uMsg == BFFM_INITIALIZED)
+ {
+ SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)pldir);
+
+ // this is not nice but it fixes the selection not working correctly on all OSes
+ EnumChildWindows(hwnd, browseEnumProc, 0);
+ }
+ return 0;
+}
+
+static INT_PTR CALLBACK prefs_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
+ static USBDevice * dev;
+ switch(uMsg) {
+ case WM_INITDIALOG:
+ {
+ prefsParam* p = (prefsParam*)lParam;
+ dev = (USBDevice*)p->dev;
+ p->config_tab_init(hwndDlg,p->parent);
+ SetDlgItemTextW(hwndDlg,IDC_NAMEFORMAT,dev->songFormat);
+ SetDlgItemTextW(hwndDlg,IDC_PLDIR,dev->pldir);
+ SetDlgItemTextW(hwndDlg,IDC_SUPPORTEDFORMATS,dev->supportedFormats);
+ if(dev->purgeFolders[0]=='1') CheckDlgButton(hwndDlg,IDC_PURGEFOLDERS,BST_CHECKED);
+ else CheckDlgButton(hwndDlg,IDC_PURGEFOLDERS,BST_UNCHECKED);
+
+ SendDlgItemMessageW(hwndDlg,IDC_PL_WRITE_COMBO,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_SLASH_AT_START));
+ SendDlgItemMessageW(hwndDlg,IDC_PL_WRITE_COMBO,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_DOT_AT_START));
+ SendDlgItemMessageW(hwndDlg,IDC_PL_WRITE_COMBO,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_NO_SLASH_OR_DOT));
+ SendDlgItemMessage(hwndDlg,IDC_PL_WRITE_COMBO,CB_SETCURSEL,dev->pl_write_mode,0);
+ SetDlgItemTextW(hwndDlg,IDC_PL_WRITE_EG,WASABI_API_LNGSTRINGW(IDS_EG_SLASH+dev->pl_write_mode));
+ }
+ break;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDC_NAMEFORMAT:
+ if(HIWORD(wParam)==EN_CHANGE)
+ {
+ GetDlgItemTextW(hwndDlg,IDC_NAMEFORMAT,dev->songFormat,sizeof(dev->songFormat)/sizeof(wchar_t));
+ WritePrivateProfileStringW(L"pmp_usb",L"songFormat",dev->songFormat,dev->iniFile);
+ }
+ break;
+
+ case IDC_PLDIR:
+ if(HIWORD(wParam)==EN_CHANGE)
+ {
+ GetDlgItemTextW(hwndDlg,IDC_PLDIR,dev->pldir,sizeof(dev->pldir)/sizeof(wchar_t));
+ WritePrivateProfileStringW(L"pmp_usb",L"pldir",dev->pldir,dev->iniFile);
+ }
+ break;
+
+ case IDC_SUPPORTEDFORMATS:
+ if(HIWORD(wParam)==EN_CHANGE)
+ {
+ GetDlgItemTextW(hwndDlg,IDC_SUPPORTEDFORMATS,dev->supportedFormats,sizeof(dev->supportedFormats)/sizeof(wchar_t));
+ WritePrivateProfileStringW(L"pmp_usb",L"supportedFormats",dev->supportedFormats,dev->iniFile);
+ }
+ break;
+
+ case IDC_REFRESHCACHE:
+ {
+ char titleStr[32] = {0};
+ dev->refreshNDECache();
+ MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_CACHE_UPDATED),
+ WASABI_API_LNGSTRING_BUF(IDS_SUCCESS,titleStr,32),MB_OK);
+ break;
+ }
+
+ case IDC_PL_WRITE_COMBO:
+ {
+ dev->pl_write_mode = (int)SendMessage((HWND)lParam,CB_GETCURSEL,0,0);
+ SetDlgItemTextW(hwndDlg,IDC_PL_WRITE_EG,WASABI_API_LNGSTRINGW(IDS_EG_SLASH+dev->pl_write_mode));
+
+ wchar_t tmp[16] = {0};
+ StringCchPrintf(tmp, 16, L"%d", dev->pl_write_mode);
+ WritePrivateProfileStringW(L"pmp_usb",L"pl_write_mode",tmp,dev->iniFile);
+ break;
+ }
+
+ case IDC_FILENAMEHELP:
+ {
+ char titleStr[64] = {0};
+ MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_FILENAME_FORMATTING_INFO),
+ WASABI_API_LNGSTRING_BUF(IDS_FILENAME_FORMAT_HELP,titleStr,64),MB_OK);
+ }
+ break;
+
+ case IDC_PLBROWSE:
+ {
+ wchar_t *tempWS;
+ BROWSEINFO bi = {0};
+ LPMALLOC lpm = 0;
+ wchar_t bffFileName[MAX_PATH] = {0};
+
+ bi.hwndOwner = hwndDlg;
+ bi.pszDisplayName = bffFileName;
+ bi.lpszTitle = WASABI_API_LNGSTRINGW(IDS_SELECT_FOLDER_TO_LOAD_PLAYLISTS);
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_EDITBOX | BIF_NEWDIALOGSTYLE;
+ bi.lpfn = BrowseCallbackProc;
+ lstrcpynW(pldir, dev->pldir, MAX_PATH);
+ LPITEMIDLIST iil = SHBrowseForFolder(&bi);
+ if(iil)
+ {
+ SHGetPathFromIDListW(iil,bffFileName);
+ SHGetMalloc(&lpm);
+ // path is now in bffFileName
+ }
+
+ tempWS = _wcsdup(bffFileName);
+ if(tempWS[0] == dev->drive)
+ {
+ lstrcpynW(dev->pldir, tempWS, MAX_PATH);
+ SetDlgItemText(hwndDlg,IDC_PLDIR,tempWS);
+ }
+ else
+ {
+ if(bffFileName[0] != 0) //dont print error if the user selected 'cancel'
+ {
+ char titleStr[32] = {0};
+ MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_ERR_SELECTED_PATH_NOT_ON_DEVICE),
+ WASABI_API_LNGSTRING_BUF(IDS_ERROR,titleStr,32), MB_OK);
+ }
+ }
+ free(tempWS);
+ }
+ break;
+
+ case IDC_FORMATSHELP:
+ {
+ char titleStr[64] = {0};
+ MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_SUPPORTED_FORMAT_INFO),
+ WASABI_API_LNGSTRING_BUF(IDS_SUPPORTED_FORMAT_HELP,titleStr,64),MB_OK);
+ }
+ break;
+
+ case IDC_PURGEFOLDERS:
+ {
+ StringCchCopy(dev->purgeFolders, ARRAYSIZE(dev->purgeFolders),
+ ((IsDlgButtonChecked(hwndDlg,IDC_PURGEFOLDERS) == BST_CHECKED) ? L"1" : L"0"));
+ WritePrivateProfileStringW(L"pmp_usb",L"purgeFolders",dev->purgeFolders,dev->iniFile);
+ }
+ break;
+
+ case IDC_RESCAN:
+ {
+ //update changes
+ SetFileAttributesW(dev->iniFile,FILE_ATTRIBUTE_HIDDEN);
+
+ wchar_t driveletter = dev->drive; //hold on to driveletter before it goes away
+ //disconnect
+ dev->Close();
+
+ //connect
+ pmpDeviceLoading load;
+ dev = new USBDevice(driveletter,&load);
+ char titleStr[64] = {0};
+ MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_RESCAN_COMPLETE_SAVED),
+ WASABI_API_LNGSTRING_BUF(IDS_RESCAN_COMPLETE,titleStr,64),MB_OK);
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+// update a track with new metadata (string)
+void USBDevice::updateTrackField(UsbSong* song, unsigned int col, const void* newValue, int fieldType)
+{
+ if (!song) return;
+
+ Nullsoft::Utility::AutoLock lock(dbcs);
+ openDeviceTable();
+ nde_scanner_t s = NDE_Table_CreateScanner(deviceTable);
+
+ if (NDE_Scanner_LocateFilename(s, DEVICEVIEW_COL_FILENAME, FIRST_RECORD, song->filename))
+ {
+ switch (fieldType)
+ {
+ case FIELD_STRING:
+ db_setFieldString(s, col, (wchar_t *)(newValue));
+ break;
+ case FIELD_INTEGER:
+ db_setFieldInt(s, col, *((int *)newValue));
+ default:
+ break;
+ }
+ }
+
+ NDE_Scanner_Post(s);
+ NDE_Table_DestroyScanner(deviceTable, s);
+ //NDE_Table_Sync(deviceTable);
+ //closeDeviceTable();
+}
+
+UsbSong::UsbSong() {
+ filename[0]=artist[0]=album[0]=title[0]=genre[0]=albumartist[0]=publisher[0]=composer[0]=0;
+ filled=year=track=length=discnum=bitrate=playcount=(int)(size=0);
+}
+
+USBArt::USBArt(ARGB32 *bits, int w, int h) :bits(bits), w(w), h(h)
+{
+}
+
+USBArt::~USBArt()
+{
+ if (bits)
+ WASABI_API_MEMMGR->sysFree(bits);
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_usb/usbdevice.h b/Src/Plugins/Portable/pmp_usb/usbdevice.h
new file mode 100644
index 00000000..adeb887e
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/usbdevice.h
@@ -0,0 +1,242 @@
+#pragma once
+#include <windows.h>
+#include <Dbt.h>
+
+#include "../../Library/ml_pmp/transcoder.h"
+#include "../../Library/ml_pmp/pmp.h"
+
+#include "../nde/nde_c.h"
+#include "../nu/AutoLock.h"
+
+#include <vector>
+
+#define NDE_CACHE_DAT L"winamp_metadata.dat"
+#define NDE_CACHE_IDX L"winamp_metadata.idx"
+
+//Filename="E:\Howling Bells - Into The Chaos.MP3"
+//Artist="Howling Bells"
+//Album="E:"
+//Title="Into The Chaos"
+//Genre=""
+//AlbumArtist=""
+//Publisher=""
+//Composer=""
+//Year="0"
+//Track="0"
+//Bitrate="0"
+//Playcount="0"
+//Discnum="0"
+//Length="0"
+//Size="7767879"
+enum
+{
+ NDE_USB_FAILURE=0,
+ NDE_USB_SUCCESS=1,
+};
+
+enum
+{
+ DEVICEVIEW_COL_FILENAME = 0,
+ DEVICEVIEW_COL_ARTIST=1,
+ DEVICEVIEW_COL_ALBUM=2,
+ DEVICEVIEW_COL_TITLE=3,
+ DEVICEVIEW_COL_GENRE=4,
+ DEVICEVIEW_COL_ALBUM_ARTIST=5,
+ DEVICEVIEW_COL_PUBLISHER=6,
+ DEVICEVIEW_COL_COMPOSER=7,
+ DEVICEVIEW_COL_YEAR=8,
+ DEVICEVIEW_COL_TRACK=9,
+ DEVICEVIEW_COL_BITRATE=10,
+ DEVICEVIEW_COL_DISC_NUMBER=11,
+ DEVICEVIEW_COL_LENGTH=12,
+ DEVICEVIEW_COL_SIZE=13,
+ DEVICEVIEW_COL_PLAY_COUNT=14,
+};
+
+#define TAG_CACHE L"winamp_metadata.dat"
+#define FIELD_LENGTH 1024
+
+class UsbSong {
+public:
+ UsbSong();
+ wchar_t filename[MAX_PATH];
+ wchar_t artist[FIELD_LENGTH];
+ wchar_t album[FIELD_LENGTH];
+ wchar_t title[FIELD_LENGTH];
+ wchar_t genre[FIELD_LENGTH];
+ wchar_t albumartist[FIELD_LENGTH];
+ wchar_t publisher[FIELD_LENGTH];
+ wchar_t composer[FIELD_LENGTH];
+ int year,track,length,discnum,bitrate,playcount;
+ __int64 size;
+ BOOL filled;
+ wchar_t ext[ 6 ];
+};
+
+enum DeviceType {
+ TYPE_OTHER,
+ TYPE_PSP,
+};
+
+class USBPlaylist;
+
+class USBDevice : public Device
+{
+public:
+ USBDevice(wchar_t drive, pmpDeviceLoading * load);
+ ~USBDevice();
+ USBDevice();
+ void fileProbe(wchar_t * indir);
+ void tag(void); //load ID3 tags from cache or mp3 file
+ void createDeviceFields();
+ int openDeviceDatabase();
+ int openDeviceTable();
+ void closeDeviceTable();
+ static void CloseDatabase();
+
+ void refreshNDECache(void);
+ void fillMetaData(UsbSong *s);
+ static int getFileInfoW(const wchar_t *filename, const wchar_t *metadata, wchar_t *dest, size_t len);
+ void setupTranscoder();
+ USBPlaylist* getMasterPlaylist();
+ UsbSong* findSongInMasterPlaylist(const wchar_t *songfn);
+ void writeRecordToDB(UsbSong* songToPrint);
+ //////////////////////////////////////////
+
+ virtual __int64 getDeviceCapacityAvailable(); // in bytes
+ virtual __int64 getDeviceCapacityTotal(); // in bytes
+
+ virtual void Eject(); // if you ejected successfully, you MUST call PMP_IPC_DEVICEDISCONNECTED and delete this;
+ virtual void Close(); // save any changes, and call PMP_IPC_DEVICEDISCONNECTED AND delete this;
+
+ // return 0 for success, -1 for failed or cancelled
+ virtual int transferTrackToDevice(const itemRecordW * track, // the track to transfer
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void *callbackContext, wchar_t *status), // call this every so often so the GUI can be updated. Including when finished!
+ songid_t * songid, // fill in the songid when you are finished
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ );
+ virtual int trackAddedToTransferQueue(const itemRecordW *track); // return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
+ virtual void trackRemovedFromTransferQueue(const itemRecordW *track);
+
+ // return the amount of space that will be taken up on the device by the track (once it has been tranferred)
+ // or 0 for incompatable. This is usually the filesize, unless you are transcoding. An estimate is acceptable.
+ virtual __int64 getTrackSizeOnDevice(const itemRecordW *track);
+
+ virtual void deleteTrack(songid_t songid); // physically remove from device. Be sure to remove it from all the playlists!
+
+ virtual void commitChanges(); // optional. Will be called at a good time to save changes
+
+ virtual int getPlaylistCount(); // always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
+ // PlaylistName(0) should return the name of the device.
+ virtual void getPlaylistName(int playlistnumber, wchar_t *buf, int len);
+ virtual int getPlaylistLength(int playlistnumber);
+ virtual songid_t getPlaylistTrack(int playlistnumber,int songnum); // returns a songid
+
+ virtual void setPlaylistName(int playlistnumber, const wchar_t *buf); // with playlistnumber==0, set the name of the device.
+ virtual void playlistSwapItems(int playlistnumber, int posA, int posB); // swap the songs at position posA and posB
+ virtual void sortPlaylist(int playlistnumber, int sortBy);
+ virtual void addTrackToPlaylist(int playlistnumber, songid_t songid); // adds songid to the end of the playlist
+ virtual void removeTrackFromPlaylist(int playlistnumber, int songnum); //where songnum is the position of the track in the playlist
+
+ virtual void deletePlaylist(int playlistnumber);
+ virtual int newPlaylist(const wchar_t *name); // create empty playlist, returns playlistnumber. -1 for failed.
+
+ virtual void getTrackArtist(songid_t songid, wchar_t *buf, int len);
+ virtual void getTrackAlbum(songid_t songid, wchar_t *buf, int len);
+ virtual void getTrackTitle(songid_t songid, wchar_t *buf, int len);
+ virtual int getTrackTrackNum(songid_t songid);
+ virtual int getTrackDiscNum(songid_t songid);
+ virtual void getTrackGenre(songid_t songid, wchar_t * buf, int len);
+ virtual int getTrackYear(songid_t songid);
+ virtual __int64 getTrackSize(songid_t songid); // in bytes
+ virtual int getTrackLength(songid_t songid); // in millisecs
+ virtual int getTrackBitrate(songid_t songid); // in kbps
+ virtual int getTrackPlayCount(songid_t songid);
+ virtual int getTrackRating(songid_t songid); //0-5
+ virtual __time64_t getTrackLastPlayed(songid_t songid); // in unix time format
+ virtual __time64_t getTrackLastUpdated(songid_t songid); // in unix time format
+ virtual void getTrackAlbumArtist(songid_t songid, wchar_t *buf, int len);
+ virtual void getTrackPublisher(songid_t songid, wchar_t *buf, int len);
+ virtual void getTrackComposer(songid_t songid, wchar_t *buf, int len);
+ virtual int getTrackType(songid_t songid);
+ virtual void getTrackExtraInfo(songid_t songid, const wchar_t *field, wchar_t *buf, int len) ; //optional
+
+ // feel free to ignore any you don't support
+ virtual void setTrackArtist(songid_t songid, const wchar_t *value);
+ virtual void setTrackAlbum(songid_t songid, const wchar_t *value);
+ virtual void setTrackTitle(songid_t songid, const wchar_t *value);
+ virtual void setTrackTrackNum(songid_t songid, int value);
+ virtual void setTrackDiscNum(songid_t songid, int value);
+ virtual void setTrackGenre(songid_t songid, const wchar_t *value);
+ virtual void setTrackYear(songid_t songid, int year);
+ virtual void setTrackPlayCount(songid_t songid, int value);
+ virtual void setTrackRating(songid_t songid, int value);
+ virtual void setTrackLastPlayed(songid_t songid, __time64_t value); // in unix time format
+ virtual void setTrackLastUpdated(songid_t songid, __time64_t value); // in unix time format
+ virtual void setTrackAlbumArtist(songid_t songid, const wchar_t *value);
+ virtual void setTrackPublisher(songid_t songid, const wchar_t *value);
+ virtual void setTrackComposer(songid_t songid, const wchar_t *value);
+ virtual void setTrackExtraInfo(songid_t songid, const wchar_t *field, const wchar_t *value) ; //optional
+
+ virtual bool playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue); // return false if unsupported
+
+ virtual intptr_t extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4);
+
+ virtual bool copyToHardDriveSupported();
+
+ virtual __int64 songSizeOnHardDrive(songid_t song); // how big a song will be when copied back. Return -1 for not supported.
+
+ virtual int copyToHardDrive(songid_t song, // the song to copy
+ wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ ); // -1 for failed/not supported. 0 for success.
+
+ // art functions
+ virtual void setArt(songid_t songid, void *buf, int w, int h); //buf is in format ARGB32*
+ virtual pmpart_t getArt(songid_t songid);
+ virtual void releaseArt(pmpart_t art);
+ virtual int drawArt(pmpart_t art, HDC dc, int x, int y, int w, int h);
+ virtual void getArtNaturalSize(pmpart_t art, int *w, int *h);
+ virtual void setArtNaturalSize(pmpart_t art, int w, int h);
+ virtual void getArtData(pmpart_t art, void* data); // data ARGB32* is at natural size
+ virtual bool artIsEqual(pmpart_t a, pmpart_t b);
+
+ // Additional attributes
+ Transcoder *transcoder;
+ wchar_t drive;
+ DeviceType devType;
+ wchar_t iniFile[MAX_PATH];
+ wchar_t pldir[MAX_PATH];
+ wchar_t songFormat[MAX_PATH];
+ wchar_t supportedFormats[MAX_PATH];
+ wchar_t purgeFolders[2];
+ int pl_write_mode; // used to determine how the playlists are stored
+ __int64 transferQueueLength;
+ std::vector<USBPlaylist*> usbPlaylists;
+ bool cacheUpToDate; //whether or not to output on device disconnect
+ bool loadedUpToDate; //whether or not songs in memory are tagged and correct
+
+ static nde_database_t discDB;
+ nde_table_t deviceTable;
+ Nullsoft::Utility::LockGuard dbcs;
+ wchar_t ndeDataFile[100];
+ wchar_t ndeIndexFile[100];
+
+private:
+ // update a track with new metadata (string)
+ void updateTrackField(UsbSong* song, unsigned int col, const void* newValue, int fieldType);
+ bool readRecordFromDB(UsbSong* song);
+ bool songChanged(UsbSong* song);
+};
+
+class USBArt
+{
+public:
+ USBArt(ARGB32 *bits, int w, int h);
+ ~USBArt();
+ ARGB32 *bits;
+ int w,h;
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_usb/usbplaylist.cpp b/Src/Plugins/Portable/pmp_usb/usbplaylist.cpp
new file mode 100644
index 00000000..5e3ffbe5
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/usbplaylist.cpp
@@ -0,0 +1,33 @@
+#include "./usbdevice.h"
+#include "./USBPlaylist.h"
+
+#include <shlwapi.h>
+#include <strsafe.h>
+
+// dtor
+// cleanup the memory allocated for the vector of songs
+USBPlaylist::~USBPlaylist()
+{
+}
+
+// this is the constructor that gets called
+USBPlaylist::USBPlaylist(USBDevice& d, LPCTSTR fileName, BOOL m)
+ : device(d), master(m), dirty(false)
+{
+ StringCbCopyW(filename, sizeof(filename), fileName);
+ StringCbCopyW(playlistName, sizeof(playlistName), PathFindFileName(fileName));
+ StringCbCopyW(playlistPath, sizeof(playlistName), fileName);
+ PathRemoveFileSpec(playlistPath);
+}
+
+
+int USBPlaylist::OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info)
+{
+ if (NULL != filename)
+ {
+ UsbSong* song = NULL;
+ song = device.findSongInMasterPlaylist(filename);
+ songs.push_back(song);
+ }
+ return ifc_playlistloadercallback::LOAD_CONTINUE;
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_usb/usbplaylist.h b/Src/Plugins/Portable/pmp_usb/usbplaylist.h
new file mode 100644
index 00000000..15ffec6e
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/usbplaylist.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <vector>
+#include "../playlist/ifc_playlistloadercallbackT.h"
+
+class USBDevice;
+class UsbSong;
+
+class USBPlaylist: public ifc_playlistloadercallbackT<USBPlaylist>
+{
+public:
+ USBPlaylist(USBDevice& d, LPCTSTR pszPlaylist, BOOL master);
+ ~USBPlaylist();
+
+public:
+ /*** ifc_playlistloadercallback ***/
+ int OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info);
+
+public:
+ // utility
+ BOOL isMaster() { return master; }
+ wchar_t* getFilename() { return filename; }
+
+public:
+ USBDevice &device;
+ wchar_t playlistName[MAX_PATH];
+ wchar_t playlistPath[MAX_PATH];
+ typedef std::vector<UsbSong*> SongList;
+ SongList songs;
+ wchar_t filename[MAX_PATH];
+ BOOL master;
+ BOOL dirty;
+};
+
+
diff --git a/Src/Plugins/Portable/pmp_usb/usbplaylistsaver.cpp b/Src/Plugins/Portable/pmp_usb/usbplaylistsaver.cpp
new file mode 100644
index 00000000..360e09e3
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/usbplaylistsaver.cpp
@@ -0,0 +1,74 @@
+#include "./usbplaylistsaver.h"
+#include "./usbplaylist.h"
+#include "./usbdevice.h"
+#include "./api.h"
+
+#include <strsafe.h>
+
+
+USBPlaylistSaver::USBPlaylistSaver(LPCTSTR iFilename, LPCTSTR iPlaylistName, USBPlaylist *iPlaylist)
+ : title((LPTSTR)iPlaylistName), filename((LPTSTR)iFilename), playlist(iPlaylist)
+{
+}
+
+USBPlaylistSaver::~USBPlaylistSaver()
+{
+}
+
+HRESULT USBPlaylistSaver::Save()
+{
+ INT result = WASABI_API_PLAYLISTMNGR->Save(filename, this);
+
+ return (PLAYLISTMANAGER_SUCCESS == result) ? S_OK : E_FAIL;
+}
+
+size_t USBPlaylistSaver::GetNumItems()
+{
+ return (size_t) playlist->songs.size();
+}
+
+size_t USBPlaylistSaver::GetItem(size_t item, wchar_t *filename, size_t filenameCch)
+{
+ UsbSong* song = (UsbSong *) playlist->songs.at(item);
+ if (!song) return 0;
+
+ HRESULT hr = StringCchCopyEx(filename, filenameCch, song->filename, NULL, NULL, STRSAFE_IGNORE_NULLS);
+ if (FAILED(hr))
+ *filename = L'\0';
+
+ return SUCCEEDED(hr);
+}
+
+size_t USBPlaylistSaver::GetItemTitle(size_t item, wchar_t *title, size_t titleCch)
+{
+ UsbSong* song = (UsbSong *) playlist->songs.at(item);
+ if (!song) return 0;
+
+ HRESULT hr = StringCchCopyEx(title, titleCch, song->title, NULL, NULL, STRSAFE_IGNORE_NULLS);
+ if (FAILED(hr))
+ *title = L'\0';
+
+ return SUCCEEDED(hr);
+}
+
+int USBPlaylistSaver::GetItemLengthMs(size_t item)
+{
+ UsbSong* song = (UsbSong *) playlist->songs.at(item);
+ if (!song) return 0;
+
+ return song->length ? song->length: -1;
+}
+
+size_t USBPlaylistSaver::GetItemExtendedInfo(size_t item, const wchar_t *metadata, wchar_t *info, size_t infoCch)
+{
+ return 0;
+}
+
+#define CBCLASS USBPlaylistSaver
+START_DISPATCH;
+CB(IFC_PLAYLIST_GETNUMITEMS, GetNumItems)
+CB(IFC_PLAYLIST_GETITEM, GetItem)
+CB(IFC_PLAYLIST_GETITEMTITLE, GetItemTitle)
+CB(IFC_PLAYLIST_GETITEMLENGTHMILLISECONDS, GetItemLengthMs)
+CB(IFC_PLAYLIST_GETITEMEXTENDEDINFO, GetItemExtendedInfo)
+END_DISPATCH; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_usb/usbplaylistsaver.h b/Src/Plugins/Portable/pmp_usb/usbplaylistsaver.h
new file mode 100644
index 00000000..a7a2e098
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/usbplaylistsaver.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <wtypes.h>
+#include "../playlist/ifc_playlist.h"
+
+class USBPlaylist;
+
+class USBPlaylistSaver : public ifc_playlist
+{
+
+public:
+ USBPlaylistSaver(LPCTSTR iFilename, LPCTSTR iTitle, USBPlaylist * iPlaylist);
+ virtual ~USBPlaylistSaver();
+
+public:
+ /*** ifc_playlist ***/
+ size_t GetNumItems();
+ size_t GetItem(size_t item, wchar_t *filename, size_t filenameCch);
+ size_t GetItemTitle(size_t item, wchar_t *title, size_t titleCch);
+ int GetItemLengthMs(size_t item); // TODO: maybe microsecond for better resolution?
+ size_t GetItemExtendedInfo(size_t item, const wchar_t *metadata, wchar_t *info, size_t infoCch);
+
+ HRESULT Save();
+protected:
+ RECVS_DISPATCH;
+
+protected:
+ LPTSTR title;
+ LPTSTR filename;
+ USBPlaylist *playlist;
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_usb/utils.cpp b/Src/Plugins/Portable/pmp_usb/utils.cpp
new file mode 100644
index 00000000..c2f582b6
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/utils.cpp
@@ -0,0 +1,355 @@
+#include <windows.h>
+#include "../../General/gen_ml/ml.h"
+#include "../../Library/ml_pmp/pmp.h"
+#include "USBDevice.h"
+#include <strsafe.h>
+#include <shlwapi.h>
+
+BOOL RecursiveCreateDirectory(wchar_t* buf1);
+__int64 fileSize(wchar_t * filename);
+bool supportedFormat(wchar_t * file, wchar_t * supportedFormats);
+DeviceType detectDeviceType(wchar_t drive);
+void removebadchars(wchar_t *s);
+wchar_t * FixReplacementVars(wchar_t *str, int str_size, Device * dev, songid_t song);
+
+void removebadchars(wchar_t *s) {
+ while (s && *s)
+ {
+ if (*s == L'?' || *s == L'/' || *s == L'\\' || *s == L':' || *s == L'*' || *s == L'\"' || *s == L'<' || *s == L'>' || *s == L'|')
+ *s = L'_';
+ s = CharNextW(s);
+ }
+}
+
+DeviceType detectDeviceType(wchar_t drive) {
+ // Check for device being a PSP
+ {
+ wchar_t memstickind[] = {drive, L":\\MEMSTICK.IND"};
+ FILE * f = _wfopen(memstickind,L"rb");
+ if(f) {
+ fclose(f);
+ WIN32_FIND_DATA FindFileData = {0};
+ wchar_t pspdir[] = {drive,L":\\PSP"};
+ HANDLE hFind = FindFirstFile(pspdir, &FindFileData);
+ if(hFind != INVALID_HANDLE_VALUE) {
+ FindClose(hFind);
+ if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ return TYPE_PSP;
+ }
+ }
+ }
+ // Cannot recognise device type
+ return TYPE_OTHER;
+}
+
+__int64 fileSize(wchar_t * filename)
+{
+ WIN32_FIND_DATA f={0};
+ HANDLE h = FindFirstFileW(filename,&f);
+ if(h == INVALID_HANDLE_VALUE) return -1;
+ FindClose(h);
+ ULARGE_INTEGER i;
+ i.HighPart = f.nFileSizeHigh;
+ i.LowPart = f.nFileSizeLow;
+ return i.QuadPart;
+}
+
+// RecursiveCreateDirectory: creates all non-existent folders in a path
+BOOL RecursiveCreateDirectory(wchar_t* buf1) {
+ wchar_t *p=buf1;
+ int errors = 0;
+ if (*p) {
+ p = PathSkipRoot(buf1);
+ if (!p) return true ;
+
+ wchar_t ch='c';
+ while (ch) {
+ while (p && *p != '\\' && *p) p = CharNext(p);
+ ch = (p ? *p : 0);
+ if (p) *p = 0;
+ int pp = (int)wcslen(buf1)-1;
+
+ while(buf1[pp] == '.' || buf1[pp] == ' ' ||
+ (buf1[pp] == '\\' && (buf1[pp-1] == '.' || buf1[pp-1] == ' ' || buf1[pp-1] == '/')) ||
+ buf1[pp] == '/' && buf1)
+ {
+ if(buf1[pp] == '\\')
+ {
+ buf1[pp-1] = '_';
+ pp -= 2;
+ } else {
+ buf1[pp] = '_';
+ pp--;
+ }
+ }
+
+ WIN32_FIND_DATA fd = {0};
+ // Avoid a "There is no disk in the drive" error box on empty removable drives
+ UINT prevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
+ HANDLE h = FindFirstFile(buf1,&fd);
+ SetErrorMode(prevErrorMode);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ if (!CreateDirectory(buf1,NULL)) errors++;
+ } else {
+ FindClose(h);
+ if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) errors++;
+ }
+ if (p) *p++ = ch;
+ }
+ }
+
+ return errors != 0;
+}
+
+bool supportedFormat(wchar_t * file, wchar_t * supportedFormats) {
+ wchar_t * ext = wcsrchr(file,'.');
+ if(!ext) return false;
+ ext++;
+ wchar_t * p = supportedFormats;
+ while(p && *p) {
+ bool ret=false;
+ wchar_t * np = wcschr(p,L';');
+ if(np) *np = 0;
+ if(!_wcsicmp(ext,p)) ret=true;
+ if(np) { *np = L';'; p=np+1; }
+ else return ret;
+ if(ret) return true;
+ }
+ return false;
+}
+
+// FixReplacementVars: replaces <Artist>, <Title>, <Album>, and #, ##, ##, with appropriate data
+// DOES NOT add a file extention!!
+wchar_t * fixReplacementVars(wchar_t *str, int str_size, Device * dev, songid_t song)
+{
+ #define ADD_STR(x) { x(song,outp,str_size-1-(outp-str)); removebadchars(outp); while (outp && *outp) outp++; }
+ #define ADD_STR_U(x) { x(song,outp,str_size-1-(outp-str)); removebadchars(outp); while (outp && *outp) { *outp=towupper(*outp); outp++; } }
+ #define ADD_STR_L(x) { x(song,outp,str_size-1-(outp-str)); removebadchars(outp); while (outp && *outp) { *outp=towlower(*outp); outp++; } }
+
+ wchar_t tmpsrc[4096] = {0};
+ lstrcpyn(tmpsrc,str,sizeof(tmpsrc)/sizeof(wchar_t)); //lstrcpyn is nice enough to make sure it's null terminated.
+
+ wchar_t *inp = tmpsrc;
+ wchar_t *outp = str;
+ int slash = 0;
+
+ while (inp && *inp && outp-str < str_size-2)
+ {
+ if (*inp == L'<')
+ {
+ if (!wcsncmp(inp,L"<TITLE>",7))
+ {
+ ADD_STR_U(dev->getTrackTitle);
+ inp+=7;
+ }
+ else if (!wcsncmp(inp,L"<title>",7))
+ {
+ ADD_STR_L(dev->getTrackTitle);
+ inp+=7;
+ }
+ else if (!_wcsnicmp(inp,L"<Title>",7))
+ {
+ ADD_STR(dev->getTrackTitle);
+ inp+=7;
+ }
+ else if (!wcsncmp(inp,L"<ALBUM>",7))
+ {
+ ADD_STR_U(dev->getTrackAlbum);
+ inp+=7;
+ }
+ else if (!wcsncmp(inp,L"<album>",7))
+ {
+ ADD_STR_L(dev->getTrackAlbum);
+ inp+=7;
+ }
+ else if (!_wcsnicmp(inp,L"<Album>",7))
+ {
+ ADD_STR(dev->getTrackAlbum);
+ inp+=7;
+ }
+ else if (!wcsncmp(inp,L"<GENRE>",7))
+ {
+ ADD_STR_U(dev->getTrackGenre);
+ inp+=7;
+ }
+ else if (!wcsncmp(inp,L"<genre>",7))
+ {
+ ADD_STR_L(dev->getTrackGenre);
+ inp+=7;
+ }
+ else if (!_wcsnicmp(inp,L"<Genre>",7))
+ {
+ ADD_STR(dev->getTrackGenre);
+ inp+=7;
+ }
+ else if (!wcsncmp(inp,L"<ARTIST>",8))
+ {
+ ADD_STR_U(dev->getTrackArtist);
+ inp+=8;
+ }
+ else if (!wcsncmp(inp,L"<artist>",8))
+ {
+ ADD_STR_L(dev->getTrackArtist);
+ inp+=8;
+ }
+ else if (!_wcsnicmp(inp,L"<Artist>",8))
+ {
+ ADD_STR(dev->getTrackArtist);
+ inp+=8;
+ }
+ else if (!wcsncmp(inp,L"<ALBUMARTIST>",13))
+ {
+ wchar_t temp[128] = {0};
+
+ dev->getTrackAlbumArtist(song, temp, 128);
+ if (temp[0] == 0)
+ dev->getTrackArtist(song, temp, 128);
+
+ lstrcpyn(outp,temp,str_size-1-(int)(outp-str));
+ removebadchars(outp);
+ while (outp && *outp) { *outp=towupper(*outp); outp++; }
+
+ inp+=13;
+ }
+ else if (!wcsncmp(inp,L"<albumartist>",13))
+ {
+ wchar_t temp[128] = {0};
+
+ dev->getTrackAlbumArtist(song, temp, 128);
+ if (temp[0] == 0)
+ dev->getTrackArtist(song, temp, 128);
+
+ lstrcpyn(outp,temp,str_size-1-(int)(outp-str));
+ removebadchars(outp);
+ while (outp && *outp) { *outp=towlower(*outp); outp++; }
+ inp+=13;
+ }
+ else if (!_wcsnicmp(inp,L"<Albumartist>",13))
+ {
+ wchar_t temp[128] = {0};
+
+ dev->getTrackAlbumArtist(song, temp, 128);
+ if (temp[0] == 0)
+ dev->getTrackArtist(song, temp, 128);
+
+ lstrcpyn(outp,temp,str_size-1-(int)(outp-str));
+ removebadchars(outp);
+ while (outp && *outp) outp++;
+ inp+=13;
+ }
+ else if (!_wcsnicmp(inp,L"<year>",6))
+ {
+ wchar_t year[64] = {0};
+ int y = dev->getTrackYear(song);
+ if (y) StringCchPrintf(year, ARRAYSIZE(year), L"%d", y);
+ lstrcpyn(outp,year,str_size-1-(int)(outp-str)); while (outp && *outp) outp++;
+ inp+=6;
+ }
+ else if (!_wcsnicmp(inp,L"<disc>",6))
+ {
+ wchar_t disc[16] = {0};
+ int d = dev->getTrackDiscNum(song);
+ if (d) StringCchPrintf(disc, ARRAYSIZE(disc), L"%d", d);
+ lstrcpyn(outp,disc,str_size-1-(int)(outp-str)); while (outp && *outp) outp++;
+ inp+=6;
+ }
+ else if (!_wcsnicmp(inp,L"<filename>",10))
+ {
+ wchar_t tfn[MAX_PATH], *ext, *fn;
+ StringCchCopy(tfn,MAX_PATH,((UsbSong*)song)->filename);
+ ext = wcsrchr(tfn, L'.');
+ *ext = 0; //kill extension since its added later
+ fn = wcsrchr(tfn, L'\\');
+ fn++;
+ lstrcpyn(outp,fn,str_size-1-(int)(outp-str));
+ while (outp && *outp) outp++;
+ inp+=10;
+ }
+ else
+ {
+ // use this to skip over unknown tags
+ while (inp && *inp && *inp != L'>') inp++;
+ if (inp) inp++;
+ }
+ }
+ else if (*inp == L'#')
+ {
+ int nd=0;
+ wchar_t tmp[64] = {0};
+ while (inp && *inp == L'#') nd++,inp++;
+ int track = dev->getTrackTrackNum(song);
+ if (!track)
+ {
+ while (inp && *inp == L' ') inp++;
+ while (inp && *inp == L'\\') inp++;
+ if (inp && (*inp == L'-' || *inp == L'.' || *inp == L'_')) // separator
+ {
+ inp++;
+ while (inp && *inp == L' ') inp++;
+ }
+ }
+ else
+ {
+ if (nd > 1)
+ {
+ wchar_t tmp2[32] = {0};
+ if (nd > 5) nd=5;
+ StringCchPrintf(tmp2, ARRAYSIZE(tmp2), L"%%%02dd",nd);
+ StringCchPrintf(tmp, ARRAYSIZE(tmp), tmp2,track);
+ }
+ else StringCchPrintf(tmp, ARRAYSIZE(tmp), L"%d",track);
+ }
+ lstrcpyn(outp,tmp,str_size-1-(int)(outp-str)); while (outp && *outp) outp++;
+ }
+ else
+ {
+ if (*inp == L'\\') slash += 1;
+ *outp++=*inp++;
+ }
+ }
+
+ if (outp) *outp = 0;
+
+ // if we end up with something like U:\\\ then this
+ // will set it to be just <filename> so it'll not
+ // end up making a load of bad files e.g. U:\.mp3
+ int out_len = lstrlen(str);
+ if (out_len)
+ {
+ if (out_len - 2 == slash)
+ {
+ outp = str + 3;
+ wchar_t tfn[MAX_PATH], *ext, *fn;
+ StringCchCopy(tfn,MAX_PATH,((UsbSong*)song)->filename);
+ ext = wcsrchr(tfn, L'.');
+ *ext = 0; //kill extension since its added later
+ fn = wcsrchr(tfn, L'\\');
+ fn++;
+ lstrcpyn(outp,fn,str_size-1-(int)(outp-str));
+ while (outp && *outp) outp++;
+ if (outp) *outp = 0;
+ }
+ }
+
+ inp=str;
+ outp=str;
+ wchar_t lastc=0;
+ while (inp && *inp)
+ {
+ wchar_t ch=*inp++;
+ if (ch == L'\t') ch=L' ';
+
+ if (ch == L' ' && (lastc == L' ' || lastc == L'\\' || lastc == L'/')) continue; // ignore space after slash, or another space
+
+ if ((ch == L'\\' || ch == L'/') && lastc == L' ') outp--; // if we have a space then slash, back up to write the slash where the space was
+ *outp++=ch;
+ lastc=ch;
+ }
+ if (outp) *outp=0;
+ #undef ADD_STR
+ #undef ADD_STR_L
+ #undef ADD_STR_U
+
+ return str;
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_usb/version.rc2 b/Src/Plugins/Portable/pmp_usb/version.rc2
new file mode 100644
index 00000000..e18d96dc
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_usb/version.rc2
@@ -0,0 +1,39 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#include "../../../Winamp/buildType.h"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,62,0,0
+ PRODUCTVERSION WINAMP_PRODUCTVER
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Winamp SA"
+ VALUE "FileDescription", "Winamp Portable Device Plug-in"
+ VALUE "FileVersion", "1,62,0,0"
+ VALUE "InternalName", "Nullsoft USB Device"
+ VALUE "LegalCopyright", "Copyright © 2006-2023 Winamp SA"
+ VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
+ VALUE "OriginalFilename", "pmp_usb.dll"
+ VALUE "ProductName", "Winamp"
+ VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/Src/Plugins/Portable/pmp_wifi/ConnectActivity.cpp b/Src/Plugins/Portable/pmp_wifi/ConnectActivity.cpp
new file mode 100644
index 00000000..37e94da4
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/ConnectActivity.cpp
@@ -0,0 +1,53 @@
+#include "ConnectActivity.h"
+#include "resource.h"
+#include "api.h"
+#include <strsafe.h>
+
+BOOL ConnectActivity::GetActive()
+{
+ return TRUE;
+}
+
+BOOL ConnectActivity::GetCancelable()
+{
+ return FALSE;
+}
+
+HRESULT ConnectActivity::GetProgress(unsigned int *percentCompleted)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT ConnectActivity::GetDisplayName(wchar_t *buffer, size_t bufferMax)
+{
+ if (NULL == buffer)
+ return E_POINTER;
+
+ WASABI_API_LNGSTRINGW_BUF(IDS_ACTIVITY_CONNECT, buffer, bufferMax);
+ return S_OK;
+}
+
+HRESULT ConnectActivity::GetStatus(wchar_t *buffer, size_t bufferMax)
+{
+ if (NULL == buffer)
+ return E_POINTER;
+
+ WASABI_API_LNGSTRINGW_BUF(IDS_ACTIVITY_CONNECT_DESC, buffer, bufferMax);
+ return S_OK;
+}
+
+HRESULT ConnectActivity::Cancel(HWND hostWindow)
+{
+ return E_NOTIMPL;
+}
+
+#define CBCLASS ConnectActivity
+START_DISPATCH;
+CB(API_GETACTIVE, GetActive);
+CB(API_GETCANCELABLE, GetCancelable);
+CB(API_GETPROGRESS, GetProgress);
+CB(API_GETDISPLAYNAME, GetDisplayName);
+CB(API_GETSTATUS, GetStatus);
+CB(API_CANCEL, Cancel);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/ConnectActivity.h b/Src/Plugins/Portable/pmp_wifi/ConnectActivity.h
new file mode 100644
index 00000000..620dc6ab
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/ConnectActivity.h
@@ -0,0 +1,16 @@
+#pragma once
+#include "../devices/ifc_deviceactivity.h"
+
+class ConnectActivity : public ifc_deviceactivity
+{
+public:
+ BOOL GetActive();
+ BOOL GetCancelable();
+ HRESULT GetProgress(unsigned int *percentCompleted);
+ HRESULT GetDisplayName(wchar_t *buffer, size_t bufferMax);
+ HRESULT GetStatus(wchar_t *buffer, size_t bufferMax);
+ HRESULT Cancel(HWND hostWindow);
+
+protected:
+ RECVS_DISPATCH;
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/InfoDownloader.cpp b/Src/Plugins/Portable/pmp_wifi/InfoDownloader.cpp
new file mode 100644
index 00000000..86bd941e
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/InfoDownloader.cpp
@@ -0,0 +1,201 @@
+#include "InfoDownloader.h"
+
+#include "api.h"
+#include "main.h"
+#include "images.h"
+#include "InfoDownloader.h"
+#include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
+#include <api/service/waServiceFactory.h>
+#include <strsafe.h>
+
+void OnInfoDownloadDone(InfoDownloader *_info);
+
+void DeviceInfo_Init(DeviceInfo *device_info)
+{
+ device_info->id=0;
+ device_info->modelInfo=NULL;
+ device_info->total_space=0;
+ device_info->used_space=0;
+ device_info->model[0]=0;
+ device_info->manufacturer[0]=0;
+ device_info->name[0]=0;
+ device_info->product[0]=0;
+}
+
+void DeviceInfo_Copy(DeviceInfo *dest, const DeviceInfo *source)
+{
+ dest->id=source->id;
+ dest->modelInfo=source->modelInfo;
+ dest->total_space=source->total_space;
+ dest->used_space=source->used_space;
+ StringCbCopy(dest->model, sizeof(dest->model), source->model);
+ StringCbCopy(dest->manufacturer, sizeof(dest->manufacturer), source->manufacturer);
+ StringCbCopy(dest->name, sizeof(dest->name), source->name);
+ StringCbCopy(dest->product, sizeof(dest->product), source->product);
+}
+
+
+DeviceXML::DeviceXML()
+{
+ DeviceInfo_Init(&device_info);
+}
+
+InfoXML::InfoXML(obj_xml *parser) : parser(parser)
+{
+ parser->xmlreader_registerCallback(L"info\fdevice", this);
+ parser->xmlreader_registerCallback(L"info\fspace", this);
+}
+
+InfoXML::~InfoXML()
+{
+ parser->xmlreader_unregisterCallback(this);
+}
+
+void DeviceXML::xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
+{
+ if (!wcscmp(xmltag, L"device"))
+ {
+ const wchar_t *value = params->getItemValue(L"id");
+ if (value)
+ device_info.id = _wcstoui64(value, 0, 16);
+
+ value = params->getItemValue(L"manufacturer");
+ if (value)
+ StringCbCopyW(device_info.manufacturer, sizeof(device_info.manufacturer), value);
+
+ value = params->getItemValue(L"model");
+ if (value)
+ StringCbCopyW(device_info.model, sizeof(device_info.model), value);
+
+ value = params->getItemValue(L"name");
+ if (value)
+ StringCbCopyW(device_info.name, sizeof(device_info.name), value);
+
+ value = params->getItemValue(L"product");
+ if (value)
+ StringCbCopyW(device_info.product, sizeof(device_info.product), value);
+
+ device_info.modelInfo = FindModelInfo(device_info.manufacturer, device_info.model, FALSE);
+ }
+ else if (!wcscmp(xmltag, L"space"))
+ {
+ const wchar_t *value = params->getItemValue(L"total");
+ if (value)
+ {
+ device_info.total_space = _wtoi64(value);
+ }
+
+ value = params->getItemValue(L"used");
+ if (value)
+ {
+ device_info.used_space = _wtoi64(value);
+ }
+ }
+}
+
+WifiDevice *InfoXML::CreateDevice(uint64_t device_id_check, const char *root_url)
+{
+ if (device_info.id == device_id_check)
+ {
+ return new WifiDevice(root_url, &device_info);
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------------------------------------------------------ */
+
+InfoDownloader::InfoDownloader(const char *_root_url, uint64_t id, Wasabi2::nx_string_t usn) : id(id)
+{
+ this->usn = NXStringRetain(usn);
+ root_url = strdup(_root_url);
+ done=0;
+ waServiceFactory *parserFactory = plugin.service->service_getServiceByGuid(obj_xmlGUID);
+ if (parserFactory)
+ parser = (obj_xml *)parserFactory->getInterface();
+
+ parser->xmlreader_setCaseSensitive();
+ info = new InfoXML(parser);
+ parser->xmlreader_open();
+}
+
+InfoDownloader::~InfoDownloader()
+{
+ NXStringRelease(usn);
+ waServiceFactory *parserFactory = plugin.service->service_getServiceByGuid(obj_xmlGUID);
+ if (parserFactory)
+ {
+ delete info;
+ parser->xmlreader_close();
+ parserFactory->releaseInterface(parser);
+ }
+ free(root_url);
+}
+
+void InfoDownloader::OnInit(DownloadToken token)
+{
+ if (done)
+ {
+ WAC_API_DOWNLOADMANAGER->CancelDownload(token);
+ return;
+ }
+
+ api_httpreceiver *jnet = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (jnet)
+ {
+ jnet->AddHeaderValue("X-Winamp-ID", winamp_id_str);
+ jnet->AddHeaderValue("X-Winamp-Name", winamp_name);
+ }
+}
+
+void InfoDownloader::OnData(DownloadToken token, void *data, size_t datalen)
+{
+ if (done)
+ {
+ WAC_API_DOWNLOADMANAGER->CancelDownload(token);
+ return;
+ }
+
+ if (parser->xmlreader_feed(data, datalen) != OBJ_XML_SUCCESS)
+ {
+ WAC_API_DOWNLOADMANAGER->CancelDownload(token);
+ }
+}
+
+void InfoDownloader::OnCancel(DownloadToken token)
+{
+ done=2;
+ OnInfoDownloadDone(this);
+}
+
+void InfoDownloader::OnError(DownloadToken token, int error)
+{
+ // TODO
+ done=2;
+ OnInfoDownloadDone(this);
+}
+
+void InfoDownloader::OnFinish(DownloadToken token)
+{
+ if (!done)
+ {
+ parser->xmlreader_feed(0, 0);
+ }
+
+ done=1;
+ OnInfoDownloadDone(this);
+ }
+
+bool InfoDownloader::Done(WifiDevice **out_device)
+{
+ if (done != 1)
+ return false;
+
+ *out_device = info->CreateDevice(id, root_url);
+
+ return true;
+}
+
+void InfoDownloader::Cancel()
+{
+ done=2;
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/InfoDownloader.h b/Src/Plugins/Portable/pmp_wifi/InfoDownloader.h
new file mode 100644
index 00000000..648d1976
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/InfoDownloader.h
@@ -0,0 +1,51 @@
+#pragma once
+#include "device.h"
+#include "../xml/obj_xml.h"
+#include "../Components/wac_downloadManager/DownloadCallbackT.h"
+#include "WifiDevice.h"
+#include "../xml/ifc_xmlreadercallbackT.h"
+#include "main.h"
+namespace Wasabi2
+{
+#include "nx/nxstring.h"
+}
+
+class DeviceXML : public ifc_xmlreadercallbackT<DeviceXML>
+{
+public:
+ DeviceXML();
+ void xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params);
+ DeviceInfo device_info;
+};
+
+class InfoXML : public DeviceXML
+{
+public:
+ InfoXML(obj_xml *parser);
+ ~InfoXML();
+ WifiDevice *CreateDevice(uint64_t device_id_check, const char *root_url);
+private:
+ obj_xml *parser;
+};
+
+class InfoDownloader : public DownloadCallbackT<InfoDownloader>
+{
+public:
+ InfoDownloader(const char *root_url, uint64_t id, Wasabi2::nx_string_t usn);
+ ~InfoDownloader();
+ void OnInit(DownloadToken token);
+ void OnData(DownloadToken token, void *data, size_t datalen);
+ void OnCancel(DownloadToken token);
+ void OnError(DownloadToken token, int error);
+ void OnFinish(DownloadToken token);
+ bool Done(WifiDevice **device);
+
+ void Cancel();
+ uint64_t id;
+ Wasabi2::nx_string_t usn;
+private:
+ char *root_url;
+ obj_xml *parser;
+ InfoXML *info;
+ volatile int done; // 1 for successfully done, 2 for cancelled/error
+};
diff --git a/Src/Plugins/Portable/pmp_wifi/ListenServer.cpp b/Src/Plugins/Portable/pmp_wifi/ListenServer.cpp
new file mode 100644
index 00000000..297b0d9e
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/ListenServer.cpp
@@ -0,0 +1,147 @@
+#include "api.h"
+#include "..\..\..\replicant\jnetlib\multicastlisten.h"
+#include "jnetlib/util.h"
+#include "InfoDownloader.h"
+#include "nu/AutoChar.h"
+#include <vector>
+#include "nu/AutoLock.h"
+
+namespace Wasabi2
+{
+ #include "ssdp/cb_ssdp.h"
+}
+
+#include <windows.h>
+
+static nu::LockGuard connections_guard;
+
+struct Connection
+{
+ Connection()
+ {
+ usn = 0;
+ location = 0;
+ device = 0;
+ downloader = 0;
+ }
+
+ Wasabi2::nx_string_t usn;
+ Wasabi2::nx_uri_t location;
+ WifiDevice *device;
+ InfoDownloader *downloader;
+};
+
+typedef std::vector<Connection> Connections;
+static Connections connections;
+static volatile int killswitch;
+
+static Connection &FindUSN(Wasabi2::nx_string_t usn)
+{
+ for (size_t i=0;i<connections.size();i++)
+ {
+ if (!Wasabi2::NXStringKeywordCompare(connections[i].usn, usn))
+ {
+ return connections[i];
+ }
+ }
+
+ Connection dummy;
+ dummy.usn = NXStringRetain(usn);
+ connections.push_back(dummy);
+
+ return connections[connections.size()-1];
+}
+
+class WAFAListener : public Wasabi2::cb_ssdp
+{
+ void WASABICALL SSDPCallback_OnServiceConnected(Wasabi2::nx_uri_t location, Wasabi2::nx_string_t type, Wasabi2::nx_string_t usn);
+ void WASABICALL SSDPCallback_OnServiceDisconnected(Wasabi2::nx_string_t usn);
+};
+
+void WAFAListener::SSDPCallback_OnServiceConnected(Wasabi2::nx_uri_t location, Wasabi2::nx_string_t type, Wasabi2::nx_string_t usn)
+{
+ if (!Wasabi2::NXStringKeywordCompareWithCString(type, "urn:nullsoft.com:device:Android:1"))
+ {
+ nu::AutoLock auto_lock(connections_guard);
+ Connection &connection = FindUSN(usn);
+ connection.location = Wasabi2::NXURIRetain(location);
+
+ uint64_t id = _wcstoui64(usn->string, 0, 16);
+ AutoChar cached_location(location->string);
+ InfoDownloader *downloader = new InfoDownloader(cached_location, id, usn);
+ connection.downloader = downloader;
+ WAC_API_DOWNLOADMANAGER->DownloadEx(cached_location, downloader, api_downloadManager::DOWNLOADEX_CALLBACK);
+ }
+}
+
+void WAFAListener::SSDPCallback_OnServiceDisconnected(Wasabi2::nx_string_t usn)
+{
+ nu::AutoLock auto_lock(connections_guard);
+ Connection &connection = FindUSN(usn);
+ if (connection.device)
+ {
+ connection.device->OnDisconnect();
+ connection.device->Release();
+ connection.device = 0;
+ }
+
+ if (connection.downloader)
+ {
+ connection.downloader->Cancel();
+ connection.downloader->Release();
+ connection.downloader = 0;
+ }
+}
+
+void OnInfoDownloadDone(InfoDownloader *_info)
+{
+ nu::AutoLock auto_lock(connections_guard);
+ Connection &connection = FindUSN(_info->usn);
+ WifiDevice *device = 0;
+ if (connection.downloader && connection.downloader->Done(&device))
+ {
+ connection.device = device;
+ connection.downloader->Release();
+ connection.downloader = 0;
+ }
+ else
+ {
+ if (connection.location)
+ {
+ // requeue download request, TODO: but might want to wait a bit
+ AutoChar cached_location(connection.location->string);
+ WAC_API_DOWNLOADMANAGER->DownloadEx(cached_location, connection.downloader, api_downloadManager::DOWNLOADEX_CALLBACK);
+ }
+ }
+}
+
+static WAFAListener wafa_ssdp_callback;
+
+void StartListenServer()
+{
+ if (REPLICANT_API_SSDP)
+ {
+ REPLICANT_API_SSDP->RegisterCallback(&wafa_ssdp_callback);
+ }
+}
+
+void StopListenServer()
+{
+ nu::AutoLock auto_lock(connections_guard);
+ for (size_t i=0;i<connections.size();i++)
+ {
+ NXStringRelease(connections[i].usn);
+ NXURIRelease(connections[i].location);
+
+ if (connections[i].downloader)
+ {
+ connections[i].downloader->Cancel();
+ connections[i].downloader->Release();
+ }
+
+ if (connections[i].device)
+ connections[i].device->Release();
+ }
+
+ connections.clear();
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/Pair.cpp b/Src/Plugins/Portable/pmp_wifi/Pair.cpp
new file mode 100644
index 00000000..6eac0e0d
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/Pair.cpp
@@ -0,0 +1,87 @@
+#include "Pair.h"
+#include "api.h"
+#include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
+#include "main.h"
+#include "WifiDevice.h"
+#include <strsafe.h>
+
+PairDownloader::PairDownloader(WifiDevice *device) : device(device)
+{
+ device->AddRef();
+}
+
+PairDownloader::~PairDownloader()
+{
+}
+
+void PairDownloader::OnInit(DownloadToken token)
+{
+ api_httpreceiver *jnet = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (jnet)
+ {
+ jnet->AddHeaderValue("X-Winamp-ID", winamp_id_str);
+ jnet->AddHeaderValue("X-Winamp-Name", winamp_name);
+ }
+}
+
+void PairDownloader::OnData(DownloadToken token, void *data, size_t datalen)
+{
+}
+
+void PairDownloader::OnCancel(DownloadToken token)
+{
+ device->OnConnectionFailed();
+ device->Release();
+ Release();
+}
+
+void PairDownloader::OnError(DownloadToken token, int error)
+{
+ api_httpreceiver *jnet = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (jnet)
+ {
+ jnet->getreplycode();
+ }
+ device->OnConnectionFailed();
+ device->Release();
+ Release();
+}
+
+void PairDownloader::OnFinish(DownloadToken token)
+{
+ api_httpreceiver *jnet = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (jnet)
+ {
+ if (jnet->getreplycode() == 202)
+ {
+ device->OnPaired();
+ device->Release();
+ Release();
+ return;
+ }
+ }
+ device->OnConnectionFailed();
+ device->Release();
+ Release();
+}
+
+bool IsPaired(uint64_t id)
+{
+ wchar_t pair_name[64] = {0};
+ StringCbPrintfW(pair_name, sizeof(pair_name), L"%016I64x", id);
+ if (GetPrivateProfileInt(L"pairs", pair_name, 0, inifile) == 0)
+ return false;
+
+ return true;
+}
+
+void SetPaired(uint64_t id, bool status)
+{
+ wchar_t pair_name[64] = {0};
+ StringCbPrintfW(pair_name, sizeof(pair_name), L"%016I64x", id);
+ if (status)
+ WritePrivateProfileString(L"pairs", pair_name, L"1", inifile);
+ else
+ WritePrivateProfileString(L"pairs", pair_name, L"0", inifile);
+
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/Pair.h b/Src/Plugins/Portable/pmp_wifi/Pair.h
new file mode 100644
index 00000000..ac2e5de8
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/Pair.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "../nu/refcount.h"
+#include "../Components/wac_downloadManager/DownloadCallbackT.h"
+
+class WifiDevice;
+
+class PairDownloader : public DownloadCallbackT<PairDownloader>
+{
+public:
+ PairDownloader(WifiDevice *device);
+ ~PairDownloader();
+
+ void OnInit(DownloadToken token);
+ void OnData(DownloadToken token, void *data, size_t datalen);
+ void OnCancel(DownloadToken token);
+ void OnError(DownloadToken token, int error);
+ void OnFinish(DownloadToken token);
+
+private:
+ WifiDevice *device;
+};
+
+bool IsPaired(uint64_t id);
+void SetPaired(uint64_t id, bool status); \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/PlaylistSync.cpp b/Src/Plugins/Portable/pmp_wifi/PlaylistSync.cpp
new file mode 100644
index 00000000..ae0ccffa
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/PlaylistSync.cpp
@@ -0,0 +1,150 @@
+#include "PlaylistSync.h"
+#include "api.h"
+#include "../nu/AutoUrl.h"
+#include "main.h"
+#include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
+#include <strsafe.h>
+
+/* classes and utility functions to notifying the device of playlist modifications */
+class SimpleCallback : public ifc_downloadManagerCallback
+{
+public:
+ void OnInit(DownloadToken token)
+ {
+ api_httpreceiver *jnet = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (jnet)
+ {
+ jnet->AddHeaderValue("X-Winamp-ID", winamp_id_str);
+ jnet->AddHeaderValue("X-Winamp-Name", winamp_name);
+ }
+ }
+
+ RECVS_DISPATCH;
+};
+
+#define CBCLASS SimpleCallback
+START_DISPATCH;
+VCB(IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit)
+END_DISPATCH;
+#undef CBCLASS
+
+class NewPlaylistCallback : public ifc_downloadManagerCallback
+{
+public:
+ NewPlaylistCallback()
+ {
+ event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ location=0;
+ }
+
+ ~NewPlaylistCallback()
+ {
+ CloseHandle(event);
+ free(location);
+ }
+
+ void OnInit(DownloadToken token)
+ {
+ api_httpreceiver *jnet = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (jnet)
+ {
+ jnet->AddHeaderValue("X-Winamp-ID", winamp_id_str);
+ jnet->AddHeaderValue("X-Winamp-Name", winamp_name);
+ }
+ }
+ void OnCancel(DownloadToken token)
+ {
+ SetEvent(event);
+ }
+ void OnError(DownloadToken token, int error)
+ {
+ SetEvent(event);
+ }
+ void OnFinish(DownloadToken token)
+ {
+ api_httpreceiver *jnet = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (jnet)
+ {
+ const char *jnet_location = jnet->getheader("Location");
+ if (jnet_location)
+ location = strdup(jnet_location);
+ }
+ SetEvent(event);
+ }
+ const char *Wait()
+ {
+ WaitForSingleObject(event, INFINITE);
+ return location;
+ }
+ HANDLE event;
+ char *location;
+ RECVS_DISPATCH;
+};
+
+#define CBCLASS NewPlaylistCallback
+START_DISPATCH;
+VCB(IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit)
+VCB(IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, OnCancel)
+VCB(IFC_DOWNLOADMANAGERCALLBACK_ONERROR, OnInit)
+VCB(IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, OnFinish)
+END_DISPATCH;
+#undef CBCLASS
+
+static SimpleCallback simple_callback;
+void Sync_AddToPlaylist(const char *root_url, const wchar_t *playlist_id, const wchar_t *song_id)
+{
+ if ( WAC_API_DOWNLOADMANAGER )
+ {
+ char url[1024] = {0};
+ StringCbPrintfA(url, sizeof(url), "%s/playlist?action=add&id=%s&songid=%s", root_url, AutoUrl(playlist_id), AutoUrl(song_id));
+ WAC_API_DOWNLOADMANAGER->DownloadEx(url, &simple_callback, api_downloadManager::DOWNLOADEX_BUFFER);
+ }
+}
+
+void Sync_RemoveFromPlaylist(const char *root_url, const wchar_t *playlist_id, const wchar_t *song_id)
+{
+ if ( WAC_API_DOWNLOADMANAGER )
+ {
+ char url[1024] = {0};
+ StringCbPrintfA(url, sizeof(url), "%s/playlist?action=remove&id=%s&songid=%s", root_url, AutoUrl(playlist_id), AutoUrl(song_id));
+ WAC_API_DOWNLOADMANAGER->DownloadEx(url, &simple_callback, api_downloadManager::DOWNLOADEX_BUFFER);
+ }
+}
+
+void Sync_DeletePlaylist(const char *root_url, const wchar_t *playlist_id)
+{
+ if ( WAC_API_DOWNLOADMANAGER )
+ {
+ char url[1024] = {0};
+ StringCbPrintfA(url, sizeof(url), "%s/playlist?action=delete&id=%s", root_url, AutoUrl(playlist_id));
+ WAC_API_DOWNLOADMANAGER->DownloadEx(url, &simple_callback, api_downloadManager::DOWNLOADEX_BUFFER);
+ }
+}
+
+WifiPlaylist *Sync_NewPlaylist(const char *root_url, const wchar_t *playlist_name)
+{
+ if ( WAC_API_DOWNLOADMANAGER )
+ {
+ NewPlaylistCallback new_playlist_callback;
+ char url[1024] = {0};
+ StringCbPrintfA(url, sizeof(url), "%s/playlist?action=new&name=%s", root_url, AutoUrl(playlist_name));
+ WAC_API_DOWNLOADMANAGER->DownloadEx(url, &new_playlist_callback, api_downloadManager::DOWNLOADEX_BUFFER);
+ const char *playlist_id = new_playlist_callback.Wait();
+ if (playlist_id)
+ {
+ return new WifiPlaylist(playlist_id, playlist_name);
+ }
+ }
+
+ return 0;
+}
+
+void Sync_RenamePlaylist(const char *root_url, const wchar_t *playlist_id, const wchar_t *playlist_name)
+{
+ if ( WAC_API_DOWNLOADMANAGER )
+ {
+ char url[ 1024 ] = { 0 };
+ StringCbPrintfA( url, sizeof( url ), "%s/playlist?action=rename&id=%s&name=%s", root_url, AutoUrl( playlist_id ), AutoUrl( playlist_name ) );
+ WAC_API_DOWNLOADMANAGER->DownloadEx( url, &simple_callback, api_downloadManager::DOWNLOADEX_BUFFER );
+ }
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/PlaylistSync.h b/Src/Plugins/Portable/pmp_wifi/PlaylistSync.h
new file mode 100644
index 00000000..5e716faa
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/PlaylistSync.h
@@ -0,0 +1,9 @@
+#pragma once
+#include "WifiPlaylist.h"
+/* classes and utility functions to notifying the device of playlist modifications */
+
+void Sync_AddToPlaylist(const char *root_url, const wchar_t *playlist_id, const wchar_t *song_id);
+void Sync_RemoveFromPlaylist(const char *root_url, const wchar_t *playlist_id, const wchar_t *song_id);
+void Sync_DeletePlaylist(const char *root_url, const wchar_t *playlist_id);
+WifiPlaylist *Sync_NewPlaylist(const char *root_url, const wchar_t *playlist_name);
+void Sync_RenamePlaylist(const char *root_url, const wchar_t *playlist_id, const wchar_t *playlist_name); \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/RenameDownloader.cpp b/Src/Plugins/Portable/pmp_wifi/RenameDownloader.cpp
new file mode 100644
index 00000000..4ace323f
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/RenameDownloader.cpp
@@ -0,0 +1,39 @@
+#include "RenameDownloader.h"
+#include "api.h"
+#include "../nu/AutoUrl.h"
+#include "main.h"
+#include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
+#include <strsafe.h>
+
+class PingCallback : public ifc_downloadManagerCallback
+{
+public:
+ void OnInit(DownloadToken token)
+ {
+ api_httpreceiver *jnet = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (jnet)
+ {
+ jnet->AddHeaderValue("X-Winamp-ID", winamp_id_str);
+ jnet->AddHeaderValue("X-Winamp-Name", winamp_name);
+ }
+ }
+
+ RECVS_DISPATCH;
+};
+
+#define CBCLASS PingCallback
+START_DISPATCH;
+VCB(IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit)
+END_DISPATCH;
+#undef CBCLASS
+
+static PingCallback ping_callback;
+void RenameDevice(const char *root_url, const wchar_t *new_name)
+{
+ if ( WAC_API_DOWNLOADMANAGER )
+ {
+ char url[1024] = {0};
+ StringCbPrintfA(url, sizeof(url), "%s/set?nick=%s", root_url, AutoUrl(new_name));
+ WAC_API_DOWNLOADMANAGER->DownloadEx(url, &ping_callback, api_downloadManager::DOWNLOADEX_BUFFER);
+ }
+}
diff --git a/Src/Plugins/Portable/pmp_wifi/RenameDownloader.h b/Src/Plugins/Portable/pmp_wifi/RenameDownloader.h
new file mode 100644
index 00000000..fe5b78cd
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/RenameDownloader.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void RenameDevice(const char *root_url, const wchar_t *new_name);
diff --git a/Src/Plugins/Portable/pmp_wifi/SongDownloader.cpp b/Src/Plugins/Portable/pmp_wifi/SongDownloader.cpp
new file mode 100644
index 00000000..f3003715
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/SongDownloader.cpp
@@ -0,0 +1,88 @@
+#include "api.h"
+#include "SongDownloader.h"
+#include "main.h"
+#include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
+#include <strsafe.h>
+
+SongDownloader::SongDownloader(const wchar_t *filename, HANDLE done_event, void (*callback)(void *callbackContext, wchar_t *status), void *context)
+: done_event(done_event), callback(callback), context(context)
+{
+ hFile = CreateFile(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
+ content_length=0;
+ bytes_downloaded=0;
+}
+
+SongDownloader::~SongDownloader()
+{
+ if (hFile != INVALID_HANDLE_VALUE)
+ CloseHandle(hFile);
+}
+
+void SongDownloader::OnInit(DownloadToken token)
+{
+ api_httpreceiver *jnet = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (jnet)
+ {
+ jnet->AddHeaderValue("X-Winamp-ID", winamp_id_str);
+ jnet->AddHeaderValue("X-Winamp-Name", winamp_name);
+ }
+}
+
+void SongDownloader::OnData(DownloadToken token, void *data, size_t datalen)
+{
+ if (!content_length)
+ {
+ api_httpreceiver *jnet = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (jnet)
+ {
+ const char *header = jnet->getheader("content-length");
+ if (header)
+ content_length = _strtoui64(header, 0, 10);
+ }
+ }
+ DWORD written = 0;
+ WriteFile(hFile, data, (DWORD)datalen, &written, 0);
+ bytes_downloaded+=written;
+ if (content_length && callback)
+ {
+ wchar_t status[128] = {0};
+ StringCbPrintf(status, sizeof(status), L"Transferring (%d%%)", (int)(100ULL * bytes_downloaded / content_length));
+ callback(context,status);
+ }
+}
+
+void SongDownloader::OnCancel(DownloadToken token)
+{
+ wchar_t status[128] = {0};
+
+ // TODO: lang pack
+ StringCbCopy(status, sizeof(status), L"Cancelled");
+ callback(context,status);
+
+ SetEvent(done_event);
+ this->Release();
+}
+
+void SongDownloader::OnError(DownloadToken token, int error)
+{
+ wchar_t status[128] = {0};
+
+ // TODO: lang pack
+ StringCbCopy(status, sizeof(status), L"Failed");
+ callback(context,status);
+
+ SetEvent(done_event);
+ this->Release();
+}
+
+void SongDownloader::OnFinish(DownloadToken token)
+{
+ wchar_t status[128] = {0};
+
+ // TODO: lang pack
+ StringCbCopy(status, sizeof(status), L"Done");
+ callback(context,status);
+
+ SetEvent(done_event);
+ this->Release();
+}
diff --git a/Src/Plugins/Portable/pmp_wifi/SongDownloader.h b/Src/Plugins/Portable/pmp_wifi/SongDownloader.h
new file mode 100644
index 00000000..947415f6
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/SongDownloader.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "../Components/wac_downloadManager/DownloadCallbackT.h"
+
+class SongDownloader : public DownloadCallbackT<SongDownloader>
+{
+public:
+ SongDownloader(const wchar_t *filename, HANDLE done_event, void (*callback)(void *callbackContext, wchar_t *status), void *context);
+ ~SongDownloader();
+
+ void OnInit(DownloadToken token);
+ void OnData(DownloadToken token, void *data, size_t datalen);
+ void OnCancel(DownloadToken token);
+ void OnError(DownloadToken token, int error);
+ void OnFinish(DownloadToken token);
+
+private:
+ void (*callback)(void *callbackContext, wchar_t *status);
+ void *context;
+ HANDLE hFile, done_event;
+ uint64_t content_length;
+ uint64_t bytes_downloaded;
+
+};
diff --git a/Src/Plugins/Portable/pmp_wifi/SongListDownloader.cpp b/Src/Plugins/Portable/pmp_wifi/SongListDownloader.cpp
new file mode 100644
index 00000000..7dbcc5e9
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/SongListDownloader.cpp
@@ -0,0 +1,178 @@
+#include "api.h"
+#include "main.h"
+#include "images.h"
+#include "SongListDownloader.h"
+#include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
+#include <api/service/waServiceFactory.h>
+#include <strsafe.h>
+
+WifiXML::WifiXML(obj_xml *parser) : parser(parser)
+{
+ wifi_track = 0;
+ wifi_playlist = 0;
+
+ parser->xmlreader_registerCallback(L"items", this);
+ parser->xmlreader_registerCallback(L"items\fdevice", &info_xml);
+ parser->xmlreader_registerCallback(L"items\fspace", &info_xml);
+ parser->xmlreader_registerCallback(L"items\fitem", this);
+ parser->xmlreader_registerCallback(L"items\fplaylist", this);
+ parser->xmlreader_registerCallback(L"items\fplaylist\fitem", this);
+
+ parser->xmlreader_registerCallback(L"items\fitem\fartist", &artist);
+ parser->xmlreader_registerCallback(L"items\fitem\falbum", &album);
+ parser->xmlreader_registerCallback(L"items\fitem\fcomposer", &composer);
+ parser->xmlreader_registerCallback(L"items\fitem\fduration", &duration);
+ parser->xmlreader_registerCallback(L"items\fitem\ftrack", &track);
+ parser->xmlreader_registerCallback(L"items\fitem\fyear", &year);
+ parser->xmlreader_registerCallback(L"items\fitem\fsize", &size);
+ parser->xmlreader_registerCallback(L"items\fitem\ftitle", &title);
+ parser->xmlreader_registerCallback(L"items\fitem\fmime", &mime_type);
+
+ parser->xmlreader_registerCallback(L"items\fplaylist\fitem\fartist", &artist);
+ parser->xmlreader_registerCallback(L"items\fplaylist\fitem\falbum", &album);
+ parser->xmlreader_registerCallback(L"items\fplaylist\fitem\fcomposer", &composer);
+ parser->xmlreader_registerCallback(L"items\fplaylist\fitem\fduration", &duration);
+ parser->xmlreader_registerCallback(L"items\fplaylist\fitem\ftrack", &track);
+ parser->xmlreader_registerCallback(L"items\fplaylist\fitem\fyear", &year);
+ parser->xmlreader_registerCallback(L"items\fplaylist\fitem\fsize", &size);
+ parser->xmlreader_registerCallback(L"items\fplaylist\fitem\ftitle", &title);
+ parser->xmlreader_registerCallback(L"items\fplaylist\fitem\fmime", &mime_type);
+ parser->xmlreader_registerCallback(L"items\fplaylist\fitem\fmodified", &modified);
+}
+
+WifiXML::~WifiXML()
+{
+ parser->xmlreader_unregisterCallback(this);
+ parser->xmlreader_unregisterCallback(&info_xml);
+
+ parser->xmlreader_unregisterCallback(&artist);
+ parser->xmlreader_unregisterCallback(&album);
+ parser->xmlreader_unregisterCallback(&composer);
+ parser->xmlreader_unregisterCallback(&duration);
+ parser->xmlreader_unregisterCallback(&track);
+ parser->xmlreader_unregisterCallback(&year);
+ parser->xmlreader_unregisterCallback(&size);
+ parser->xmlreader_unregisterCallback(&title);
+ parser->xmlreader_unregisterCallback(&mime_type);
+ parser->xmlreader_unregisterCallback(&modified);
+}
+
+void WifiXML::xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
+{
+ if (!wcscmp(xmltag, L"item"))
+ {
+ const wchar_t *value = params->getItemValue(L"id");
+ if (value)
+ {
+ wifi_track = new WifiTrack;
+ wifi_track->id = _wcsdup(value);
+ }
+ }
+ else if (!wcscmp(xmltag, L"playlist"))
+ {
+ const wchar_t *value = params->getItemValue(L"id");
+ const wchar_t *name = params->getItemValue(L"name");
+ if (value && name)
+ {
+ wifi_playlist = new WifiPlaylist;
+ wifi_playlist->id = _wcsdup(value);
+ wifi_playlist->name = _wcsdup(name);
+ }
+ }
+}
+
+void WifiXML::xmlReaderOnEndElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag)
+{
+ if (!wcscmp(xmltag, L"item") && wifi_track)
+ {
+ wifi_track->artist = _wcsdup(artist.GetString()); artist.Reset();
+ wifi_track->album = _wcsdup(album.GetString()); album.Reset();
+ wifi_track->composer = _wcsdup(composer.GetString()); composer.Reset();
+ wifi_track->duration = _wtoi(duration.GetString()); duration.Reset();
+ wifi_track->track = _wtoi(track.GetString()); track.Reset();
+ wifi_track->year = _wtoi(year.GetString()); year.Reset();
+ wifi_track->size = _wtoi(size.GetString()); size.Reset();
+ wifi_track->title = _wcsdup(title.GetString()); title.Reset();
+ wifi_track->mime_type = _wcsdup(mime_type.GetString()); mime_type.Reset();
+ wifi_track->last_updated = _wtoi64(modified.GetString()); modified.Reset();
+ if (wifi_playlist)
+ wifi_playlist->tracks.push_back(wifi_track);
+ else
+ tracks.push_back(wifi_track);
+ wifi_track=0;
+ }
+ else if (!wcscmp(xmltag, L"playlist") && wifi_playlist)
+ {
+ playlists.push_back(wifi_playlist);
+ wifi_playlist = 0;
+ }
+}
+
+/* ------------------------------------------------------------------------------------------------------------ */
+
+SongListDownloader::SongListDownloader(const char *root_url, WifiDevice *wifi_device) : root_url(root_url), wifi_device(wifi_device)
+{
+ device=0;
+ wifi_device->AddRef();
+ waServiceFactory *parserFactory = plugin.service->service_getServiceByGuid(obj_xmlGUID);
+ if (parserFactory)
+ parser = (obj_xml *)parserFactory->getInterface();
+
+ parser->xmlreader_setCaseSensitive();
+ wifi = new WifiXML(parser);
+ parser->xmlreader_open();
+}
+
+SongListDownloader::~SongListDownloader()
+{
+ waServiceFactory *parserFactory = plugin.service->service_getServiceByGuid(obj_xmlGUID);
+ if (parserFactory)
+ {
+ delete wifi;
+ parser->xmlreader_close();
+ parserFactory->releaseInterface(parser);
+ }
+}
+
+void SongListDownloader::OnInit(DownloadToken token)
+{
+ api_httpreceiver *jnet = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (jnet)
+ {
+ jnet->AddHeaderValue("X-Winamp-ID", winamp_id_str);
+ jnet->AddHeaderValue("X-Winamp-Name", winamp_name);
+ }
+}
+
+void SongListDownloader::OnData(DownloadToken token, void *data, size_t datalen)
+{
+ if (parser->xmlreader_feed(data, datalen) != OBJ_XML_SUCCESS)
+ {
+ WAC_API_DOWNLOADMANAGER->CancelDownload(token);
+ }
+}
+
+void SongListDownloader::OnCancel(DownloadToken token)
+{
+ wifi_device->OnConnectionFailed();
+ wifi_device->Release();
+ this->Release();
+}
+
+void SongListDownloader::OnError(DownloadToken token, int error)
+{
+ wifi_device->OnConnectionFailed();
+ wifi_device->Release();
+ this->Release();
+}
+
+void SongListDownloader::OnFinish(DownloadToken token)
+{
+ parser->xmlreader_feed(0, 0);
+ device = new TemplateDevice(wifi_device, root_url, &wifi->info_xml.device_info, &wifi->tracks, &wifi->playlists);
+ wifi_device->OnConnected(device);
+ wifi_device->Release();
+ PostMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)device,PMP_IPC_DEVICECONNECTED);
+
+ this->Release();
+}
diff --git a/Src/Plugins/Portable/pmp_wifi/SongListDownloader.h b/Src/Plugins/Portable/pmp_wifi/SongListDownloader.h
new file mode 100644
index 00000000..e5e9b350
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/SongListDownloader.h
@@ -0,0 +1,58 @@
+#pragma once
+#include "device.h"
+#include "../xml/obj_xml.h"
+#include "XMLString.h"
+#include "../Components/wac_downloadManager/DownloadCallbackT.h"
+#include "WifiDevice.h"
+#include "../xml/ifc_xmlreadercallbackT.h"
+#include "main.h"
+#include "InfoDownloader.h" // for InfoXML
+
+class WifiXML : public ifc_xmlreadercallbackT<WifiXML>
+{
+public:
+ WifiXML(obj_xml *parser);
+ ~WifiXML();
+
+public:
+ void xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params);
+ void xmlReaderOnEndElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag);
+
+ DeviceXML info_xml;
+ TemplateDevice::PlaylistsList playlists;
+ TemplateDevice::TrackList tracks;
+private:
+ obj_xml *parser;
+ TemplateDevice *device;
+ XMLString artist;
+ XMLString album;
+ XMLString composer;
+ XMLString duration;
+ XMLString track;
+ XMLString year;
+ XMLString size;
+ XMLString title;
+ XMLString mime_type;
+ XMLString modified;
+ WifiTrack *wifi_track;
+ WifiPlaylist *wifi_playlist;
+};
+
+class SongListDownloader : public DownloadCallbackT<SongListDownloader>
+{
+public:
+ SongListDownloader(const char *root_url, WifiDevice *wifi_device);
+ ~SongListDownloader();
+ void OnInit(DownloadToken token);
+ void OnData(DownloadToken token, void *data, size_t datalen);
+ void OnCancel(DownloadToken token);
+ void OnError(DownloadToken token, int error);
+ void OnFinish(DownloadToken token);
+
+private:
+ obj_xml *parser;
+ WifiXML *wifi;
+ TemplateDevice *device;
+ WifiDevice *wifi_device;
+ const char *root_url;
+};
diff --git a/Src/Plugins/Portable/pmp_wifi/WifiDevice.cpp b/Src/Plugins/Portable/pmp_wifi/WifiDevice.cpp
new file mode 100644
index 00000000..0b97b96e
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/WifiDevice.cpp
@@ -0,0 +1,269 @@
+#include "WifiDevice.h"
+#include "api.h"
+#include "device.h"
+#include "nu/ns_wc.h"
+#include "resource.h"
+#include "Pair.h"
+#include "images.h"
+#include "modelInfo.h"
+#include "SongListDownloader.h"
+#include <strsafe.h>
+
+WifiDevice::WifiDevice(const char *root_url, const DeviceInfo *in_device_info)
+: url(strdup(root_url))
+{
+ DeviceInfo_Copy(&device_info, in_device_info);
+ InitializeCriticalSection(&register_lock);
+ dead=0;
+ connect_active=false;
+ pmp_device=0;
+ StringCbPrintfA(id_string, sizeof(id_string), "%016I64x", device_info.id);
+ if (IsPaired(device_info.id))
+ {
+ char full_url[256] = {0};
+ StringCbPrintfA(full_url, sizeof(full_url), "%s/library", url);
+ WAC_API_DOWNLOADMANAGER->DownloadEx(full_url, new SongListDownloader(url, this), api_downloadManager::DOWNLOADEX_CALLBACK);
+ }
+ else
+ {
+ ifc_device *device = this;
+ AGAVE_API_DEVICEMANAGER->DeviceRegister(&device, 1);
+ }
+}
+
+WifiDevice::~WifiDevice()
+{
+ DeleteCriticalSection(&register_lock);
+}
+
+/* ifc_device stuff */
+int WifiDevice::QueryInterface(GUID interface_guid, void **object)
+{
+ if (interface_guid == IFC_Device)
+ {
+ AddRef();
+ *object = (ifc_device *)this;
+ return 0;
+ }
+ return 1;
+}
+
+const char *WifiDevice::GetName()
+{
+ return id_string;
+}
+
+HRESULT WifiDevice::GetDisplayName(wchar_t *buffer, size_t bufferSize)
+{
+ StringCchCopyW(buffer, bufferSize, device_info.name);
+ return 0;
+}
+
+const char *WifiDevice::GetType()
+{
+ return "portable";
+}
+
+const char *WifiDevice::GetConnection()
+{
+ return "wifi";
+}
+
+extern ifc_devicesupportedcommandenum *command_enum;
+extern ifc_devicesupportedcommandstore *command_store;
+extern ifc_deviceeventmanager *device_event_manager;
+
+HRESULT WifiDevice::EnumerateCommands(ifc_devicesupportedcommandenum **enumerator, DeviceCommandContext context)
+{
+ if (connect_active)
+ return E_NOTIMPL;
+
+ return command_store->Enumerate(enumerator);
+}
+
+HRESULT WifiDevice::SendCommand(const char *command, HWND hostWindow, ULONG_PTR param)
+{
+ if (!strcmp(command, "attach"))
+ {
+ return Attach(hostWindow);
+ }
+
+ return 0;
+}
+
+BOOL WifiDevice::GetAttached()
+{
+ return FALSE;
+}
+
+HRESULT WifiDevice::Attach(HWND hostWindow)
+{
+ if (!connect_active)
+ {
+ connect_active = true;
+ device_event_manager->Notify_ActivityStarted(this, &connect_activity);
+
+ char full_url[256] = {0};
+ StringCbPrintfA(full_url, sizeof(full_url), "%s/pair", url);
+ WAC_API_DOWNLOADMANAGER->DownloadEx(full_url, new PairDownloader(this), api_downloadManager::DOWNLOADEX_CALLBACK);
+ }
+
+ return S_OK;
+}
+
+HRESULT WifiDevice::Detach(HWND hostWindow)
+{
+ return S_OK;
+}
+
+HRESULT WifiDevice::Advise(ifc_deviceevent *handler)
+{
+ return device_event_manager->Advise(handler);
+}
+
+HRESULT WifiDevice::Unadvise(ifc_deviceevent *handler)
+{
+ return device_event_manager->Unadvise(handler);
+}
+
+HRESULT WifiDevice::GetIcon(wchar_t *buffer, size_t bufferSize, int width, int height)
+{
+ return ModelInfo_GetIconPath(device_info.modelInfo, width, height, buffer, bufferSize, TRUE);
+}
+
+void WifiDevice::OnPaired()
+{
+ char full_url[256] = {0};
+ StringCbPrintfA(full_url, sizeof(full_url), "%s/library", url);
+ WAC_API_DOWNLOADMANAGER->DownloadEx(full_url, new SongListDownloader(url, this), api_downloadManager::DOWNLOADEX_CALLBACK);
+ SetPaired(device_info.id, true);
+}
+
+void WifiDevice::OnConnected(TemplateDevice *device)
+{
+ EnterCriticalSection(&register_lock);
+ pmp_device = device;
+ connect_active = false;
+ device_event_manager->Notify_ActivityFinished(this, &connect_activity);
+ AGAVE_API_DEVICEMANAGER->DeviceUnregister(id_string);
+ // if we disconnected/timed out on the listen server while connecting, go ahead and close the device out
+ if (dead && pmp_device)
+ {
+ pmp_device->CloseAsync();
+ pmp_device = 0;
+ }
+ LeaveCriticalSection(&register_lock);
+}
+
+void WifiDevice::OnDisconnect()
+{
+ // TODO: might actually need a crit sec here
+ EnterCriticalSection(&register_lock);
+ dead=1;
+ if (pmp_device)
+ {
+ pmp_device->CloseAsync();
+ pmp_device = 0;
+ }
+ else
+ {
+ AGAVE_API_DEVICEMANAGER->DeviceUnregister(id_string);
+ }
+ LeaveCriticalSection(&register_lock);
+}
+
+void WifiDevice::OnConnectionFailed()
+{
+ EnterCriticalSection(&register_lock);
+ delete pmp_device;
+ pmp_device = 0;
+ ifc_device *device = NULL;
+ bool device_exist = false;
+
+ // see if we're already registered (e.g. we started in unpaired state)
+ if (AGAVE_API_DEVICEMANAGER->DeviceFind(id_string, &device) == S_OK)
+ {
+ if (device == this)
+ device_exist = true;
+
+ device->Release();
+ }
+
+ if (device_exist)
+ { // if we are, then notify about activity being done
+ connect_active = false;
+ device_event_manager->Notify_ActivityFinished(this, &connect_activity);
+ }
+ else if (!dead)
+ { // if we weren't registered, we thought we were paired but failed
+ device = this;
+ AGAVE_API_DEVICEMANAGER->DeviceRegister(&device, 1);
+ }
+
+
+ LeaveCriticalSection(&register_lock);
+}
+
+HRESULT WifiDevice::GetActivity(ifc_deviceactivity **activity)
+{
+ if (connect_active)
+ {
+ *activity = &connect_activity;
+ return S_OK;
+ }
+ else
+ {
+ return E_FAIL;
+ }
+}
+
+HRESULT WifiDevice::GetTotalSpace(uint64_t *size)
+{
+#if 0
+ if (device_info.total_space)
+ {
+ *size = device_info.total_space;
+ return S_OK;
+ }
+#endif
+ return E_NOTIMPL;
+}
+
+HRESULT WifiDevice::GetUsedSpace(uint64_t *size)
+{
+#if 0
+ if (device_info.used_space)
+ {
+ *size = device_info.used_space;
+ return S_OK;
+ }
+#endif
+ return E_NOTIMPL;
+}
+
+HRESULT WifiDevice::GetModel(wchar_t *buffer, size_t bufferSize)
+{
+ return ModelInfo_CopyDisplayName(device_info.modelInfo, buffer, bufferSize);
+}
+
+#define CBCLASS WifiDevice
+START_DISPATCH;
+CB(QUERYINTERFACE, QueryInterface);
+CB(API_GETNAME, GetName);
+CB(API_GETICON, GetIcon);
+CB(API_GETDISPLAYNAME, GetDisplayName);
+CB(API_GETTOTALSPACE, GetTotalSpace);
+CB(API_GETUSEDSPACE, GetUsedSpace);
+CB(API_GETTYPE, GetType);
+CB(API_GETCONNECTION, GetConnection);
+CB(API_ENUMERATECOMMANDS, EnumerateCommands);
+CB(API_SENDCOMMAND, SendCommand);
+CB(API_GETATTACHED, GetAttached);
+CB(API_ATTACH, Attach);
+CB(API_DETACH, Detach);
+CB(API_GETACTIVITY, GetActivity);
+CB(API_ADVISE, Advise);
+CB(API_UNADVISE, Unadvise);
+CB(API_GETMODEL, GetModel);
+REFERENCE_COUNTED;
+END_DISPATCH;
diff --git a/Src/Plugins/Portable/pmp_wifi/WifiDevice.h b/Src/Plugins/Portable/pmp_wifi/WifiDevice.h
new file mode 100644
index 00000000..a7065c6b
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/WifiDevice.h
@@ -0,0 +1,64 @@
+#pragma once
+#include <bfc/platform/types.h>
+#include "../devices/ifc_device.h"
+#include "device.h"
+#include "../nu/refcount.h"
+#include "ConnectActivity.h"
+#include "main.h"
+/* this one inherits from ifc_device (not Device from ml_pmp) and is used to manage
+ attaching/detaching, etc from the device view */
+class TemplateDevice;
+class WifiDevice : public Countable<ifc_device>
+{
+public:
+ WifiDevice(const char *root_url, const DeviceInfo *device_info);
+ ~WifiDevice();
+ /* --- ifc_device interface --- */
+ int QueryInterface(GUID interface_guid, void **object);
+ HRESULT GetDisplayName(wchar_t *buffer, size_t bufferSize);
+ const char *GetName();
+ HRESULT GetIcon(wchar_t *buffer, size_t bufferSize, int width, int height);
+ const char *GetType();
+ const char *GetConnection();
+
+ BOOL GetHidden();
+
+ HRESULT GetTotalSpace(uint64_t *size);
+ HRESULT GetUsedSpace(uint64_t *size);
+
+ BOOL GetAttached();
+ HRESULT Attach(HWND hostWindow);
+ HRESULT Detach(HWND hostWindow);
+
+ HRESULT EnumerateCommands(ifc_devicesupportedcommandenum **enumerator, DeviceCommandContext context);
+ HRESULT SendCommand(const char *command, HWND hostWindow, ULONG_PTR param);
+ HRESULT GetActiveCommand(char *buffer, size_t bufferSize);
+ HRESULT CancelCommand(const char *command, HWND hostWindow);
+ HRESULT GetCommandFlags(const char *command, DeviceCommandFlags *flags);
+
+ HRESULT Advise(ifc_deviceevent *handler);
+ HRESULT Unadvise(ifc_deviceevent *handler);
+
+ HWND CreateView(HWND parentWindow);
+ void SetNavigationItem(void *navigationItem);
+
+ void OnPaired();
+ void OnConnected(TemplateDevice *device);
+ void OnConnectionFailed();
+ void OnDisconnect();
+ HRESULT GetModel(wchar_t *buffer, size_t bufferSize);
+
+ HRESULT GetActivity(ifc_deviceactivity **activity);
+
+ REFERENCE_COUNT_IMPLEMENTATION;
+private:
+ DeviceInfo device_info;
+ RECVS_DISPATCH;
+ char id_string[32];
+ char *url;
+ TemplateDevice *pmp_device;
+ ConnectActivity connect_activity;
+ bool connect_active;
+ volatile int dead;
+ CRITICAL_SECTION register_lock;
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/WifiPlaylist.cpp b/Src/Plugins/Portable/pmp_wifi/WifiPlaylist.cpp
new file mode 100644
index 00000000..fc0e3264
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/WifiPlaylist.cpp
@@ -0,0 +1,104 @@
+#include "WifiPlaylist.h"
+#include "api.h"
+#include "nu/AutoWide.h"
+
+/* ---- WifiTrack ---- */
+WifiTrack::WifiTrack()
+{
+ last_updated=0;
+ id=0;
+ artist=0;
+ album=0;
+ composer=0;
+ duration=0;
+ track=0;
+ year=0;
+ size=0;
+ title=0;
+ mime_type=0;
+}
+
+WifiTrack::WifiTrack(const char *id, const itemRecordW *record, const wchar_t *filename)
+{
+ this->id=AutoWideDup(id);
+ artist=_wcsdup(record->artist);
+ album=_wcsdup(record->album);
+ composer=_wcsdup(record->composer);
+ duration=record->length;
+ track=record->track;
+ year=record->year;
+ size=record->filesize;
+ title=_wcsdup(record->title);
+ wchar_t mime[128] = {0};
+ if (AGAVE_API_METADATA->GetExtendedFileInfo(filename, L"mime", mime, 128) && mime[0])
+ {
+ mime_type=_wcsdup(mime);
+ }
+ else
+ {
+ mime_type=0;
+ }
+
+ last_updated=record->lastupd;
+}
+
+WifiTrack::WifiTrack(const WifiTrack &copy)
+{
+ id=_wcsdup(copy.id);
+ artist=_wcsdup(copy.artist);
+ album=_wcsdup(copy.album);
+ composer=_wcsdup(copy.composer);
+ duration=copy.duration;
+ track=copy.track;
+ year=copy.year;
+ size=copy.size;
+ title=_wcsdup(copy.title);
+ mime_type=_wcsdup(copy.mime_type);
+ last_updated=copy.last_updated;
+}
+
+WifiTrack::~WifiTrack()
+{
+ free(id);
+ free(artist);
+ free(album);
+ free(composer);
+ free(title);
+ free(mime_type);
+}
+
+
+/* ---- WifiPlaylist ---- */
+
+WifiPlaylist::WifiPlaylist()
+{
+ id=0;
+ name=0;
+}
+
+WifiPlaylist::WifiPlaylist(const char *id, const wchar_t *name)
+{
+ this->id = AutoWideDup(id);
+ this->name = _wcsdup(name);
+}
+
+WifiPlaylist::~WifiPlaylist()
+{
+ free(id);
+ free(name);
+ //tracks.deleteAll();
+ for (auto obj : tracks)
+ {
+ delete obj;
+ }
+ tracks.clear();
+}
+
+void WifiPlaylist::SetName(const wchar_t *new_name)
+{
+ if (name != new_name)
+ {
+ free(name);
+ name = _wcsdup(new_name);
+ }
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/WifiPlaylist.h b/Src/Plugins/Portable/pmp_wifi/WifiPlaylist.h
new file mode 100644
index 00000000..600428a5
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/WifiPlaylist.h
@@ -0,0 +1,36 @@
+#pragma once
+#include "../../General/gen_ml/ml.h" // for itemRecordW
+#include <vector>
+
+struct WifiTrack
+{
+ WifiTrack();
+ WifiTrack(const WifiTrack &copy);
+ ~WifiTrack();
+ WifiTrack(const char *id, const itemRecordW *record, const wchar_t *filename);
+ wchar_t *id;
+ wchar_t *artist;
+ wchar_t *album;
+ wchar_t *composer;
+ int duration;
+ int track;
+ int year;
+ int size;
+ wchar_t *title;
+ wchar_t *mime_type;
+ __time64_t last_updated;
+ wchar_t *ext;
+};
+
+class WifiPlaylist
+{
+public:
+ WifiPlaylist();
+ WifiPlaylist(const char *id, const wchar_t *name);
+ ~WifiPlaylist();
+ void SetName(const wchar_t *new_name);
+ typedef std::vector<WifiTrack*> TrackList;
+ TrackList tracks;
+ wchar_t *id;
+ wchar_t *name;
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/XMLString.cpp b/Src/Plugins/Portable/pmp_wifi/XMLString.cpp
new file mode 100644
index 00000000..a5d77b86
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/XMLString.cpp
@@ -0,0 +1,49 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+
+#include "XMLString.h"
+#include <strsafe.h>
+
+XMLString::XMLString()
+{
+ data[0]=0;
+}
+
+void XMLString::Reset()
+{
+ data[0]=0;
+}
+
+const wchar_t *XMLString::GetString()
+{
+ return data;
+}
+
+void XMLString::StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
+{
+ data[0]=0;
+}
+
+
+void XMLString::TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str)
+{
+ StringCchCatW(data, XMLSTRING_SIZE, str);
+}
+
+
+void XMLString::ManualSet(const wchar_t *string)
+{
+StringCchCatW(data, XMLSTRING_SIZE, string);
+}
+
+#define CBCLASS XMLString
+START_DISPATCH;
+VCB(ONSTARTELEMENT, StartTag)
+VCB(ONCHARDATA, TextHandler)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/XMLString.h b/Src/Plugins/Portable/pmp_wifi/XMLString.h
new file mode 100644
index 00000000..f4599022
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/XMLString.h
@@ -0,0 +1,28 @@
+#ifndef NULLSOFT_WINAMP_XMLSTRING_H
+#define NULLSOFT_WINAMP_XMLSTRING_H
+
+#include "../xml/ifc_xmlreadercallback.h"
+/*
+this one is an xml callback that just saves the last encountered string
+*/
+
+#define XMLSTRING_SIZE 1024
+class XMLString : public ifc_xmlreadercallback
+{
+public:
+ XMLString();
+ void Reset();
+ const wchar_t *GetString();
+ void ManualSet(const wchar_t *string);
+private:
+ /* XML callbacks */
+ void StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params);
+ void EndTag(const wchar_t *xmlpath, const wchar_t *xmltag);
+ void TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str);
+
+ wchar_t data[XMLSTRING_SIZE]; // for now, we'll make it dynamic later
+
+ RECVS_DISPATCH;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/api.cpp b/Src/Plugins/Portable/pmp_wifi/api.cpp
new file mode 100644
index 00000000..84a80717
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/api.cpp
@@ -0,0 +1,72 @@
+#include "../../Library/ml_pmp/pmp.h"
+#include "api.h"
+#include <api/service/waservicefactory.h>
+
+api_albumart *AGAVE_API_ALBUMART=0;
+api_language *WASABI_API_LNG = 0;
+api_application *WASABI_API_APP = 0;
+HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
+api_downloadManager *WAC_API_DOWNLOADMANAGER =0;
+api_config *AGAVE_API_CONFIG=0;
+api_devicemanager *AGAVE_API_DEVICEMANAGER = 0;
+api_metadata *AGAVE_API_METADATA=0;
+api_memmgr *WASABI_API_MEMMGR=0;
+Wasabi2::api_service *WASABI2_API_SVC=0;
+
+Wasabi2::api_ssdp *REPLICANT_API_SSDP=0;
+extern PMPDevicePlugin plugin;
+
+template <class api_T>
+void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
+{
+ if (plugin.service)
+ {
+ waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
+ if (factory)
+ api_t = reinterpret_cast<api_T *>( factory->getInterface() );
+ }
+}
+
+template <class api_T>
+void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
+{
+ if (plugin.service && api_t)
+ {
+ waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
+ if (factory)
+ factory->releaseInterface(api_t);
+ }
+ api_t = NULL;
+}
+
+void WasabiInit()
+{
+ ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
+ ServiceBuild(WASABI_API_LNG, languageApiGUID);
+ ServiceBuild( WAC_API_DOWNLOADMANAGER, DownloadManagerGUID);
+ ServiceBuild(AGAVE_API_CONFIG, AgaveConfigGUID);
+ ServiceBuild(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
+ ServiceBuild(AGAVE_API_ALBUMART, albumArtGUID);
+ ServiceBuild(AGAVE_API_METADATA, api_metadataGUID);
+ ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ ServiceBuild(WASABI2_API_SVC, Wasabi2::api_service::GetServiceGUID());
+ // need to have this initialised before we try to do anything with localisation features
+ // TODO: WASABI_API_START_LANG(plugin.hDllInstance,InAviLangGUID);
+ if (WASABI2_API_SVC)
+ WASABI2_API_SVC->GetService(&REPLICANT_API_SSDP);
+}
+
+void WasabiQuit()
+{
+ ServiceRelease(WASABI_API_APP, applicationApiServiceGuid);
+ ServiceRelease(WASABI_API_LNG, languageApiGUID);
+ ServiceRelease( WAC_API_DOWNLOADMANAGER, DownloadManagerGUID);
+ ServiceRelease(AGAVE_API_CONFIG, AgaveConfigGUID);
+ ServiceRelease(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
+ ServiceRelease(AGAVE_API_ALBUMART, albumArtGUID);
+ ServiceRelease(AGAVE_API_METADATA, api_metadataGUID);
+ ServiceRelease(WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ ServiceRelease(WASABI2_API_SVC, Wasabi2::api_service::GetServiceGUID());
+ if (REPLICANT_API_SSDP)
+ REPLICANT_API_SSDP->Release();
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/api.h b/Src/Plugins/Portable/pmp_wifi/api.h
new file mode 100644
index 00000000..9dcf8c20
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/api.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "../Agave/Language/api_language.h"
+
+#include <api/application/api_application.h>
+extern api_application *applicationApi;
+#define WASABI_API_APP applicationApi
+
+#include "../Components/wac_downloadManager/wac_downloadManager_api.h"
+
+#include "../Agave/Config/api_config.h"
+extern api_config *config;
+#define AGAVE_API_CONFIG config
+
+#include "../devices/api_devicemanager.h"
+extern api_devicemanager *deviceManagerApi;
+#define AGAVE_API_DEVICEMANAGER deviceManagerApi
+
+#include "../Agave/Metadata/api_metadata.h"
+extern api_metadata *metadataApi;
+#define AGAVE_API_METADATA metadataApi
+
+
+#include "../Agave/AlbumArt/api_albumart.h"
+extern api_albumart *albumArtApi;
+#define AGAVE_API_ALBUMART albumArtApi
+
+
+#include <api/memmgr/api_memmgr.h>
+extern api_memmgr *memmgr;
+#define WASABI_API_MEMMGR memmgr
+
+
+namespace Wasabi2
+{
+#include "service/api_service.h"
+#include "ssdp/api_ssdp.h"
+}
+
+extern Wasabi2::api_service *WASABI2_API_SVC;
+extern Wasabi2::api_ssdp *REPLICANT_API_SSDP;
+
+void WasabiInit();
+void WasabiQuit();
diff --git a/Src/Plugins/Portable/pmp_wifi/device.cpp b/Src/Plugins/Portable/pmp_wifi/device.cpp
new file mode 100644
index 00000000..c0acd3c2
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/device.cpp
@@ -0,0 +1,797 @@
+#include "main.h"
+#include "device.h"
+#include "XMLString.h"
+#include "api.h"
+#include "../xml/obj_xml.h"
+#include "../xml/ifc_xmlreaderparams.h"
+#include <api/service/waServiceFactory.h>
+#include "SongListDownloader.h"
+#include "SongDownloader.h"
+#include "RenameDownloader.h"
+#include "resource.h"
+#include "PlaylistSync.h"
+#include "nu/AutoWide.h"
+#include "images.h"
+#include <mmsystem.h> // for mmioFOURCC
+#include <strsafe.h>
+#include <shlwapi.h>
+
+TemplateDevice::TemplateDevice(WifiDevice *device, const char *root_url, DeviceInfo *in_device_info, TrackList *track_list, PlaylistsList *playlists_list)
+: url(strdup(root_url))
+{
+ DeviceInfo_Copy(&device_info, in_device_info);
+ //tracks.own(*track_list);
+ for (auto track : tracks)
+ {
+ delete track;
+ }
+ tracks.clear();
+ tracks.assign(track_list->begin(), track_list->end());
+ track_list->clear();
+
+
+ //playlists.own(*playlists_list);
+ for (auto playlist : playlists)
+ {
+ delete playlist;
+ }
+ playlists.clear();
+ playlists.assign(playlists_list->begin(), playlists_list->end());
+ playlists_list->clear();
+
+ transcoder=0;
+ transferQueueLength=0;
+
+ transcoder = (Transcoder*)SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)this,PMP_IPC_GET_TRANSCODER);
+ if(transcoder)
+ {
+ transcoder->AddAcceptableFormat(L"m4a");
+ transcoder->AddAcceptableFormat(L"mp3");
+ transcoder->AddAcceptableFormat(L"wav");
+ transcoder->AddAcceptableFormat(L"m4v");
+ transcoder->AddAcceptableFormat(L"mp4");
+ transcoder->AddAcceptableFormat(L"avi");
+ transcoder->AddAcceptableFormat(L"3gp");
+ transcoder->AddAcceptableFormat(L"mid");
+ transcoder->AddAcceptableFormat(L"ogg");
+ }
+}
+
+TemplateDevice::~TemplateDevice()
+{
+ free(url);
+
+ //tracks.deleteAll();
+ for (auto track : tracks)
+ {
+ delete track;
+ }
+ tracks.clear();
+
+ //playlists.deleteAll();
+ for (auto playlist : playlists)
+ {
+ delete playlist;
+ }
+ playlists.clear();
+
+ if (transcoder)
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)transcoder,PMP_IPC_RELEASE_TRANSCODER);
+ transcoder=0;
+
+}
+
+__int64 TemplateDevice::getDeviceCapacityAvailable() // in bytes
+{
+ return device_info.total_space - device_info.used_space;
+}
+
+__int64 TemplateDevice::getDeviceCapacityTotal()
+{
+ return device_info.total_space;
+}
+
+void TemplateDevice::Eject()
+{
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
+}
+
+void TemplateDevice::Close()
+{
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
+}
+
+void TemplateDevice::CloseAsync()
+{
+ PostMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
+}
+
+int PostFile(const char *url, const wchar_t *filename, const itemRecordW *track, obj_xml *parser, int *killswitch,
+ void (*callback)(void *callbackContext, wchar_t *status), void *context, char *new_item_id, size_t new_item_id_len);
+
+int PostAlbumArt(const char *url, const itemRecordW *track, obj_xml *parser, int *killswitch, void (*callback)(void *callbackContext, wchar_t *status), void *context);
+
+
+static int64_t FileSize64(const wchar_t * filename)
+{
+ WIN32_FIND_DATA f={0};
+ HANDLE h = FindFirstFileW(filename,&f);
+ if(h == INVALID_HANDLE_VALUE) return -1;
+ FindClose(h);
+ ULARGE_INTEGER i;
+ i.HighPart = f.nFileSizeHigh;
+ i.LowPart = f.nFileSizeLow;
+ return i.QuadPart;
+}
+
+// return 0 for success, -1 for failed or cancelled
+int TemplateDevice::transferTrackToDevice(const itemRecordW *track, // the track to transfer
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void *callbackContext, wchar_t *status), // call this every so often so the GUI can be updated. Including when finished!
+ songid_t * songid, // fill in the songid when you are finished
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ )
+{
+ wchar_t newfile[MAX_PATH] = {0};
+ wchar_t *filename = track->filename;
+ bool delete_file = false;
+ if(transcoder && transcoder->ShouldTranscode(track->filename))
+ {
+ wchar_t ext[10] = {0};
+ int r = transcoder->CanTranscode(track->filename, ext, track->length);
+ if(r != 0 && r != -1)
+ {
+ transcoder->GetTempFilePath(ext,newfile);
+ if(transcoder->TranscodeFile(track->filename,newfile,killswitch,callback,callbackContext)) return -1;
+ filename = newfile;
+ delete_file=true;
+ }
+ }
+
+ char new_item_id[512] = {0};
+ char upload_url[555] = {0};
+ StringCbPrintfA(upload_url, sizeof(upload_url), "%s/upload", url);
+ if (PostFile(upload_url, filename, track, 0, killswitch, callback, callbackContext, new_item_id, 512) == 0 && new_item_id[0])
+ {
+ StringCbPrintfA(upload_url, sizeof(upload_url), "%s/albumart/%s", url, new_item_id);
+ PostAlbumArt(upload_url, track, 0, killswitch, callback, callbackContext);
+ callback(callbackContext, WASABI_API_LNGSTRINGW(IDS_COMPLETED));
+ WifiTrack *new_track = new WifiTrack(new_item_id, track, filename);
+ *songid = (songid_t)new_track;
+ device_info.used_space += FileSize64(filename); // TODO: count album art also. or re-query for device info
+ if (delete_file)
+ DeleteFile(filename);
+ return 0;
+ }
+ else
+ {
+ callback(callbackContext, L"Failed");
+ if (delete_file)
+ DeleteFile(filename);
+ return -1;
+ }
+}
+
+
+int TemplateDevice::trackAddedToTransferQueue(const itemRecordW *track)
+{
+ // return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
+ __int64 l;
+ if(transcoder && transcoder->ShouldTranscode(track->filename))
+ {
+ int k = transcoder->CanTranscode(track->filename, 0, track->length);
+ if(k == -1) return -2;
+ if(k == 0) l = (__int64)FileSize64(track->filename);
+ else l = (__int64)k;
+ }
+ else
+ {
+ l = FileSize64(track->filename);
+ }
+ int64_t avail = getDeviceCapacityAvailable();
+ int64_t cmp = transferQueueLength;
+ cmp += l;
+ cmp += 3000000LL;
+
+ if(cmp > avail)
+ return -1;
+ else
+ {
+ transferQueueLength += l;
+ return 0;
+ }
+}
+
+void TemplateDevice::trackRemovedFromTransferQueue(const itemRecordW *track)
+{
+ int64_t l = FileSize64(track->filename);
+ if(transcoder && transcoder->ShouldTranscode(track->filename))
+ {
+ int k = transcoder->CanTranscode(track->filename, 0, track->length);
+ if(k != -1 && k != 0) l = (__int64)k;
+ }
+ transferQueueLength -= l;
+
+}
+
+// return the amount of space that will be taken up on the device by the track (once it has been tranferred)
+// or 0 for incompatable. This is usually the filesize, unless you are transcoding. An estimate is acceptable.
+__int64 TemplateDevice::getTrackSizeOnDevice(const itemRecordW *track)
+{
+ if(transcoder && transcoder->ShouldTranscode(track->filename))
+ {
+ int k = transcoder->CanTranscode(track->filename, 0, track->length);
+ if(k != -1 && k != 0) return k;
+ }
+ return track->filesize;
+}
+
+int HTTP_Delete(const char *url);
+void TemplateDevice::deleteTrack(songid_t songid)
+{
+ // physically remove from device. Be sure to remove it from all the playlists!
+ WifiTrack *track = (WifiTrack *)songid;
+ char delete_url[1024] = {0};
+ StringCbPrintfA(delete_url, sizeof(delete_url), "%s/file/%S", url, track->id);
+ HTTP_Delete(delete_url);
+again1:
+ for (WifiPlaylist::TrackList::iterator itr2=tracks.begin(); itr2 != tracks.end(); itr2++)
+ {
+ WifiTrack *trackitr = *itr2;
+ if (!wcscmp(trackitr->id, track->id))
+ {
+ tracks.erase(itr2);
+ if (trackitr != track)
+ delete trackitr;
+ goto again1; // iterator was invalidated
+ }
+ }
+
+ for (PlaylistsList::iterator itr=playlists.begin();itr!=playlists.end();itr++)
+ {
+ WifiPlaylist *playlist = *itr;
+again2:
+ for (WifiPlaylist::TrackList::iterator itr2=playlist->tracks.begin(); itr2 != playlist->tracks.end(); itr2++)
+ {
+ WifiTrack *trackitr = *itr2;
+ if (!wcscmp(trackitr->id, track->id))
+ {
+ playlist->tracks.erase(itr2);
+ if (trackitr != track)
+ delete trackitr;
+ goto again2; // iterator was invalidated
+ }
+ }
+ }
+ delete track;
+}
+
+
+void TemplateDevice::commitChanges()
+{
+ // optional. Will be called at a good time to save changes
+}
+
+int TemplateDevice::getPlaylistCount()
+{
+ // always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
+ return 1 + (int)playlists.size();
+}
+
+// PlaylistName(0) should return the name of the device.
+void TemplateDevice::getPlaylistName(int playlistnumber, wchar_t *buf, int len)
+{
+ if (playlistnumber == 0)
+ {
+ StringCchCopy(buf, len, device_info.name);
+ }
+ else
+ {
+ WifiPlaylist *playlist = playlists[playlistnumber-1];
+ StringCchCopy(buf, len, playlist->name);
+ }
+
+}
+int TemplateDevice::getPlaylistLength(int playlistnumber)
+{
+ if (playlistnumber == 0)
+ {
+ size_t size = tracks.size();
+ return (int)size;
+ }
+ else
+ {
+ WifiPlaylist *playlist = playlists[playlistnumber-1];
+ size_t size = playlist->tracks.size();
+ return (int)size;
+ }
+}
+
+songid_t TemplateDevice::getPlaylistTrack(int playlistnumber,int songnum)
+{
+ if (playlistnumber == 0)
+ {
+ WifiTrack *track = tracks[songnum];
+ return (songid_t)track;
+ }
+ else
+ {
+ WifiPlaylist *playlist = playlists[playlistnumber-1];
+ WifiTrack *track = playlist->tracks[songnum];
+ return (songid_t)track;
+ }
+
+}
+
+void TemplateDevice::setPlaylistName(int playlistnumber, const wchar_t *buf)
+{
+ if (playlistnumber == 0) // playlist 0 is the device itself
+ {
+ RenameDevice(url, buf);
+ StringCbCopy(device_info.name, sizeof(device_info.name), buf);
+ }
+ else
+ {
+ WifiPlaylist *playlist = playlists[playlistnumber-1];
+ playlist->SetName(buf);
+ Sync_RenamePlaylist(url, playlist->id, buf);
+ }
+}
+
+void TemplateDevice::playlistSwapItems(int playlistnumber, int posA, int posB)
+{
+ // swap the songs at position posA and posB
+ // TODO: implement
+}
+
+void TemplateDevice::sortPlaylist(int playlistnumber, int sortBy)
+{
+ // TODO: implement
+}
+
+void TemplateDevice::addTrackToPlaylist(int playlistnumber, songid_t songid)
+{
+ // adds songid to the end of the playlist
+ WifiTrack *track = (WifiTrack *)songid;
+ if (playlistnumber == 0)
+ {
+ tracks.push_back(track);
+ }
+ else
+ {
+ playlists[playlistnumber - 1]->tracks.push_back(new WifiTrack(*track));
+ Sync_AddToPlaylist(url, playlists[playlistnumber-1]->id, track->id);
+ }
+
+}
+
+void TemplateDevice::removeTrackFromPlaylist(int playlistnumber, int songnum)
+{
+ //where songnum is the position of the track in the playlist
+ if (playlistnumber == 0)
+ {
+ tracks.erase(tracks.begin() + songnum);
+ }
+ else
+ {
+ WifiPlaylist *playlist = playlists[playlistnumber-1];
+ WifiTrack *track = playlist->tracks[songnum];
+ Sync_RemoveFromPlaylist(url, playlist->id, track->id);
+ }
+}
+
+void TemplateDevice::deletePlaylist(int playlistnumber)
+{
+ if (playlistnumber == 0)
+ {
+ }
+ else
+ {
+ WifiPlaylist *playlist = playlists[playlistnumber-1];
+ Sync_DeletePlaylist(url, playlist->id);
+ playlists.erase(playlists.begin() + playlistnumber-1);
+ }
+}
+
+int TemplateDevice::newPlaylist(const wchar_t *name)
+{
+ // create empty playlist, returns playlistnumber. -1 for failed.
+ WifiPlaylist *new_playlist = Sync_NewPlaylist(url, name);
+ if (new_playlist)
+ {
+ playlists.push_back(new_playlist);
+ return (int)playlists.size();
+ }
+ return -1;
+}
+
+void TemplateDevice::getTrackArtist(songid_t songid, wchar_t *buf, int len)
+{
+ WifiTrack *track = (WifiTrack *)songid;
+ StringCchCopy(buf, len, track->artist);
+}
+
+void TemplateDevice::getTrackAlbum(songid_t songid, wchar_t *buf, int len)
+{
+ WifiTrack *track = (WifiTrack *)songid;
+ StringCchCopy(buf, len, track->album);
+}
+
+void TemplateDevice::getTrackTitle(songid_t songid, wchar_t *buf, int len)
+{
+ WifiTrack *track = (WifiTrack *)songid;
+ StringCchCopy(buf, len, track->title);
+}
+
+int TemplateDevice::getTrackTrackNum(songid_t songid)
+{
+ WifiTrack *track = (WifiTrack *)songid;
+ return track->track;
+}
+int TemplateDevice::getTrackDiscNum(songid_t songid)
+{
+ // TODO: implement
+ return 0;
+}
+void TemplateDevice::getTrackGenre(songid_t songid, wchar_t * buf, int len)
+{
+ buf[0]=0;
+}
+
+int TemplateDevice::getTrackYear(songid_t songid)
+{
+ WifiTrack *track = (WifiTrack *)songid;
+ return track->year;
+}
+
+__int64 TemplateDevice::getTrackSize(songid_t songid)
+{
+ WifiTrack *track = (WifiTrack *)songid;
+ return track->size;
+}
+
+int TemplateDevice::getTrackLength(songid_t songid)
+{
+ WifiTrack *track = (WifiTrack *)songid;
+ return track->duration;
+}
+
+int TemplateDevice::getTrackBitrate(songid_t songid)
+{
+ return 128;
+}
+
+int TemplateDevice::getTrackPlayCount(songid_t songid)
+{
+ return 0;
+}
+
+int TemplateDevice::getTrackRating(songid_t songid)
+{
+ return 0;
+}
+
+__time64_t TemplateDevice::getTrackLastPlayed(songid_t songid)
+{
+ return 0;
+}
+
+__time64_t TemplateDevice::getTrackLastUpdated(songid_t songid)
+{
+ WifiTrack *track = (WifiTrack *)songid;
+ return track->last_updated;
+}
+
+void TemplateDevice::getTrackAlbumArtist(songid_t songid, wchar_t *buf, int len)
+{
+ buf[0]=0;
+}
+
+void TemplateDevice::getTrackPublisher(songid_t songid, wchar_t *buf, int len)
+{
+ buf[0]=0;
+}
+
+void TemplateDevice::getTrackComposer(songid_t songid, wchar_t *buf, int len)
+{
+ WifiTrack *track = (WifiTrack *)songid;
+ StringCchCopy(buf, len, track->composer);
+}
+
+int TemplateDevice::getTrackType(songid_t songid)
+{
+ return 0;
+}
+void TemplateDevice::getTrackExtraInfo(songid_t songid, const wchar_t *field, wchar_t *buf, int len)
+{
+ // TODO: implement
+ //optional
+}
+
+// feel free to ignore any you don't support
+void TemplateDevice::setTrackArtist(songid_t songid, const wchar_t *value)
+{
+ // TODO: implement
+
+}
+void TemplateDevice::setTrackAlbum(songid_t songid, const wchar_t *value)
+{
+ // TODO: implement
+
+}
+void TemplateDevice::setTrackTitle(songid_t songid, const wchar_t *value)
+{
+ // TODO: implement
+
+}
+void TemplateDevice::setTrackTrackNum(songid_t songid, int value)
+{
+ // TODO: implement
+
+}
+void TemplateDevice::setTrackDiscNum(songid_t songid, int value)
+{
+ // TODO: implement
+
+}
+void TemplateDevice::setTrackGenre(songid_t songid, const wchar_t *value)
+{
+ // TODO: implement
+
+}
+void TemplateDevice::setTrackYear(songid_t songid, int year)
+{
+ // TODO: implement
+
+}
+void TemplateDevice::setTrackPlayCount(songid_t songid, int value)
+{
+ // TODO: implement
+
+}
+void TemplateDevice::setTrackRating(songid_t songid, int value)
+{
+ // TODO: implement
+
+}
+void TemplateDevice::setTrackLastPlayed(songid_t songid, __time64_t value)
+{
+ // TODO: implement
+
+} // in unix time format
+void TemplateDevice::setTrackLastUpdated(songid_t songid, __time64_t value)
+{
+ // TODO: implement
+
+} // in unix time format
+void TemplateDevice::setTrackAlbumArtist(songid_t songid, const wchar_t *value)
+{
+ // TODO: implement
+
+}
+void TemplateDevice::setTrackPublisher(songid_t songid, const wchar_t *value)
+{
+ // TODO: implement
+
+}
+void TemplateDevice::setTrackComposer(songid_t songid, const wchar_t *value)
+{
+ // TODO: implement
+
+}
+void TemplateDevice::setTrackExtraInfo(songid_t songid, const wchar_t *field, const wchar_t *value)
+{
+ // TODO: implement
+
+} //optional
+
+bool TemplateDevice::playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue)
+{
+ if(!enqueue) //clear playlist
+ {
+ SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_DELETE);
+ }
+
+ for(int i=0; i<listLength; i++)
+ {
+ WifiTrack*curSong = (WifiTrack *)songidList[i];
+
+ if (curSong)
+ {
+ wchar_t fn[1024] = {0};
+
+ if (curSong->mime_type && !_wcsicmp(curSong->mime_type, L"audio/mp4"))
+ StringCbPrintf(fn, sizeof(fn), L"%S/file/%s?=.m4a", url, curSong->id);
+ else if (curSong->mime_type && !_wcsicmp(curSong->mime_type, L"audio/x-ms-wma"))
+ StringCbPrintf(fn, sizeof(fn), L"%S/file/%s?=.wma", url, curSong->id);
+ else if (curSong->mime_type && (!_wcsicmp(curSong->mime_type, L"application/ogg") || !_wcsicmp(curSong->mime_type, L"audio/ogg")))
+ StringCbPrintf(fn, sizeof(fn), L"%S/file/%s?=.ogg", url, curSong->id);
+ else
+ StringCbPrintf(fn, sizeof(fn), L"%S/file/%s", url, curSong->id);
+ enqueueFileWithMetaStructW s={0};
+ s.filename = fn;
+ s.title = _wcsdup(curSong->title);
+ s.ext = NULL;
+ s.length = curSong->duration/1000;
+
+ SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
+ }
+ else
+ {
+ //char titleStr[32];
+ //MessageBoxA(plugin.hwndWinampParent,WASABI_API_LNGSTRING(IDS_CANNOT_OPEN_FILE),
+ // WASABI_API_LNGSTRING_BUF(IDS_ERROR,titleStr,32),0);
+ }
+ }
+
+ if(!enqueue)
+ {
+ //play item startPlaybackAt
+ SendMessage(plugin.hwndWinampParent,WM_WA_IPC,startPlaybackAt,IPC_SETPLAYLISTPOS);
+ SendMessage(plugin.hwndWinampParent,WM_COMMAND,40047,0); //stop
+ SendMessage(plugin.hwndWinampParent,WM_COMMAND,40045,0); //play
+ }
+ return true;
+}
+
+static const intptr_t encoder_blacklist[] =
+{
+ mmioFOURCC('W','M','A',' '),
+ mmioFOURCC('A','A','C','H'),
+ mmioFOURCC('A','A','C','P'),
+ mmioFOURCC('A','A','C','r'),
+ mmioFOURCC('F','L','A','C'),
+ mmioFOURCC('M','P','2',' '),
+ mmioFOURCC('A','D','T','S'),
+};
+
+
+intptr_t TemplateDevice::extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4)
+{
+ switch(param1)
+ {
+ case DEVICE_SET_ICON: // icons
+ {
+ MLTREEIMAGE * i = (MLTREEIMAGE*)param2;
+ const ModelInfo *modelInfo;
+ i->hinst = plugin.hDllInstance;
+
+ modelInfo = device_info.modelInfo;
+ if (NULL == modelInfo || NULL == modelInfo->smallIcon)
+ {
+ modelInfo = GetDefaultModelInfo();
+ if (NULL == modelInfo)
+ break;
+ }
+
+ i->resourceId = (int)(intptr_t)modelInfo->smallIcon;
+ }
+ break;
+ case DEVICE_CAN_RENAME_DEVICE:
+ return 1;
+ case DEVICE_GET_ICON:
+ ModelInfo_GetIconPath(device_info.modelInfo, (int)param2, (int)param3, (wchar_t*)param4, 260, TRUE);
+ break;
+ case DEVICE_GET_CONNECTION_TYPE:
+ {
+ const char **type = (const char **)param2;
+ *type = "WiFi";
+ return 1;
+ }
+ case DEVICE_SUPPORTS_PODCASTS:
+ return 1; // we don't support podcasts
+ case DEVICE_GET_MODEL:
+ ModelInfo_CopyDisplayName(device_info.modelInfo, (wchar_t*)param2, param3);
+ return 1;
+ case DEVICE_SUPPORTED_METADATA:
+ {
+ intptr_t supported = SUPPORTS_ARTIST | SUPPORTS_ALBUM | SUPPORTS_TITLE | SUPPORTS_TRACKNUM /*| SUPPORTS_DISCNUM | SUPPORTS_GENRE */|
+ SUPPORTS_YEAR | SUPPORTS_SIZE | SUPPORTS_LENGTH /*| SUPPORTS_BITRATE */| SUPPORTS_LASTUPDATED /*| SUPPORTS_ALBUMARTIST */|
+ SUPPORTS_COMPOSER /*| SUPPORTS_PUBLISHER | SUPPORTS_ALBUMART*/;
+ return supported;
+ }
+ break;
+ case DEVICE_VETO_ENCODER:
+ {
+ for (size_t i=0;i<sizeof(encoder_blacklist)/sizeof(*encoder_blacklist);i++)
+ {
+ if (param2 == encoder_blacklist[i])
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+
+ // TODO: implement more
+ return 0;
+}
+
+bool TemplateDevice::copyToHardDriveSupported()
+{
+ return true;
+}
+
+__int64 TemplateDevice::songSizeOnHardDrive(songid_t song)
+{
+ WifiTrack *track = (WifiTrack *)song;
+ return track->size;
+}
+
+int TemplateDevice::copyToHardDrive(songid_t song, // the song to copy
+ wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ )
+{
+ WifiTrack *track = (WifiTrack *)song;
+ char download_url[1024] = {0};
+ StringCbPrintfA(download_url, sizeof(download_url), "%s/file/%S", url, track->id);
+ HANDLE event = CreateEvent(0, FALSE, FALSE, 0);
+
+ if (!_wcsicmp(track->mime_type, L"audio/mpeg"))
+ wcsncat(path, L".mp3", MAX_PATH);
+ else if (!_wcsicmp(track->mime_type, L"audio/mp4"))
+ wcsncat(path, L".m4a", MAX_PATH);
+ else if (!_wcsicmp(track->mime_type, L"audio/x-ms-wma"))
+ wcsncat(path, L".wma", MAX_PATH);
+ else if (!_wcsicmp(track->mime_type, L"application/ogg") || !_wcsicmp(track->mime_type, L"audio/ogg") )
+ wcsncat(path, L".ogg", MAX_PATH);
+ // TODO: more
+
+ SongDownloader *song_downloader = new SongDownloader(path, event, callback, callbackContext);
+ song_downloader->AddRef();
+ WAC_API_DOWNLOADMANAGER->DownloadEx(download_url, song_downloader, api_downloadManager::DOWNLOADEX_CALLBACK);
+ WaitForSingleObject(event, INFINITE);
+ song_downloader->Release();
+ return 0; // TODO: check error code
+}
+
+// art functions
+void TemplateDevice::setArt(songid_t songid, void *buf, int w, int h)
+{
+ //buf is in format ARGB32*
+ // TODO: implement
+
+}
+
+pmpart_t TemplateDevice::getArt(songid_t songid)
+{
+ // TODO: implement
+ return 0;
+}
+
+void TemplateDevice::releaseArt(pmpart_t art)
+{
+ // TODO: implement
+
+}
+int TemplateDevice::drawArt(pmpart_t art, HDC dc, int x, int y, int w, int h)
+{
+ // TODO: implement
+ return 0;
+}
+
+void TemplateDevice::getArtNaturalSize(pmpart_t art, int *w, int *h)
+{
+ // TODO: implement
+
+}
+void TemplateDevice::setArtNaturalSize(pmpart_t art, int w, int h)
+{
+ // TODO: implement
+
+}
+void TemplateDevice::getArtData(pmpart_t art, void* data)
+{
+ // data ARGB32* is at natural size
+ // TODO: implement
+}
+
+bool TemplateDevice::artIsEqual(pmpart_t a, pmpart_t b)
+{
+ // TODO: implement
+ return false;
+}
+
diff --git a/Src/Plugins/Portable/pmp_wifi/device.h b/Src/Plugins/Portable/pmp_wifi/device.h
new file mode 100644
index 00000000..12a82087
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/device.h
@@ -0,0 +1,127 @@
+#pragma once
+#include "../../Library/ml_pmp/pmp.h"
+#include "../../Library/ml_pmp/transcoder.h"
+#include <vector>
+#include "WifiDevice.h"
+#include "WifiPlaylist.h"
+#include "main.h"
+#include <bfc/platform/types.h>
+
+class WifiDevice;
+class TemplateDevice : public Device
+{
+public:
+ typedef std::vector<WifiTrack*> TrackList;
+ typedef std::vector<WifiPlaylist*> PlaylistsList;
+ TemplateDevice(WifiDevice *device, const char *root_url, DeviceInfo *device_info, TemplateDevice::TrackList *track_list, TemplateDevice::PlaylistsList *playlists_list);
+ ~TemplateDevice();
+ virtual __int64 getDeviceCapacityAvailable(); // in bytes
+ virtual __int64 getDeviceCapacityTotal(); // in bytes
+
+ virtual void Eject(); // if you ejected successfully, you MUST call PMP_IPC_DEVICEDISCONNECTED and delete this;
+ virtual void Close(); // save any changes, and call PMP_IPC_DEVICEDISCONNECTED AND delete this;
+ void CloseAsync();
+
+ // return 0 for success, -1 for failed or cancelled
+ virtual int transferTrackToDevice(const itemRecordW * track, // the track to transfer
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void *callbackContext, wchar_t *status), // call this every so often so the GUI can be updated. Including when finished!
+ songid_t * songid, // fill in the songid when you are finished
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ );
+ virtual int trackAddedToTransferQueue(const itemRecordW *track); // return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
+ virtual void trackRemovedFromTransferQueue(const itemRecordW *track);
+
+ // return the amount of space that will be taken up on the device by the track (once it has been tranferred)
+ // or 0 for incompatable. This is usually the filesize, unless you are transcoding. An estimate is acceptable.
+ virtual __int64 getTrackSizeOnDevice(const itemRecordW *track);
+
+ virtual void deleteTrack(songid_t songid); // physically remove from device. Be sure to remove it from all the playlists!
+
+ virtual void commitChanges(); // optional. Will be called at a good time to save changes
+
+ virtual int getPlaylistCount(); // always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
+ // PlaylistName(0) should return the name of the device.
+ virtual void getPlaylistName(int playlistnumber, wchar_t *buf, int len);
+ virtual int getPlaylistLength(int playlistnumber);
+ virtual songid_t getPlaylistTrack(int playlistnumber,int songnum); // returns a songid
+
+ virtual void setPlaylistName(int playlistnumber, const wchar_t *buf); // with playlistnumber==0, set the name of the device.
+ virtual void playlistSwapItems(int playlistnumber, int posA, int posB); // swap the songs at position posA and posB
+ virtual void sortPlaylist(int playlistnumber, int sortBy);
+ virtual void addTrackToPlaylist(int playlistnumber, songid_t songid); // adds songid to the end of the playlist
+ virtual void removeTrackFromPlaylist(int playlistnumber, int songnum); //where songnum is the position of the track in the playlist
+
+ virtual void deletePlaylist(int playlistnumber);
+ virtual int newPlaylist(const wchar_t *name); // create empty playlist, returns playlistnumber. -1 for failed.
+
+ virtual void getTrackArtist(songid_t songid, wchar_t *buf, int len);
+ virtual void getTrackAlbum(songid_t songid, wchar_t *buf, int len);
+ virtual void getTrackTitle(songid_t songid, wchar_t *buf, int len);
+ virtual int getTrackTrackNum(songid_t songid);
+ virtual int getTrackDiscNum(songid_t songid);
+ virtual void getTrackGenre(songid_t songid, wchar_t * buf, int len);
+ virtual int getTrackYear(songid_t songid);
+ virtual __int64 getTrackSize(songid_t songid); // in bytes
+ virtual int getTrackLength(songid_t songid); // in millisecs
+ virtual int getTrackBitrate(songid_t songid); // in kbps
+ virtual int getTrackPlayCount(songid_t songid);
+ virtual int getTrackRating(songid_t songid); //0-5
+ virtual __time64_t getTrackLastPlayed(songid_t songid); // in unix time format
+ virtual __time64_t getTrackLastUpdated(songid_t songid); // in unix time format
+ virtual void getTrackAlbumArtist(songid_t songid, wchar_t *buf, int len);
+ virtual void getTrackPublisher(songid_t songid, wchar_t *buf, int len);
+ virtual void getTrackComposer(songid_t songid, wchar_t *buf, int len);
+ virtual int getTrackType(songid_t songid);
+ virtual void getTrackExtraInfo(songid_t songid, const wchar_t *field, wchar_t *buf, int len) ; //optional
+
+ // feel free to ignore any you don't support
+ virtual void setTrackArtist(songid_t songid, const wchar_t *value);
+ virtual void setTrackAlbum(songid_t songid, const wchar_t *value);
+ virtual void setTrackTitle(songid_t songid, const wchar_t *value);
+ virtual void setTrackTrackNum(songid_t songid, int value);
+ virtual void setTrackDiscNum(songid_t songid, int value);
+ virtual void setTrackGenre(songid_t songid, const wchar_t *value);
+ virtual void setTrackYear(songid_t songid, int year);
+ virtual void setTrackPlayCount(songid_t songid, int value);
+ virtual void setTrackRating(songid_t songid, int value);
+ virtual void setTrackLastPlayed(songid_t songid, __time64_t value); // in unix time format
+ virtual void setTrackLastUpdated(songid_t songid, __time64_t value); // in unix time format
+ virtual void setTrackAlbumArtist(songid_t songid, const wchar_t *value);
+ virtual void setTrackPublisher(songid_t songid, const wchar_t *value);
+ virtual void setTrackComposer(songid_t songid, const wchar_t *value);
+ virtual void setTrackExtraInfo(songid_t songid, const wchar_t *field, const wchar_t *value) ; //optional
+
+ virtual bool playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue); // return false if unsupported
+
+ virtual intptr_t extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4);
+
+ virtual bool copyToHardDriveSupported();
+
+ virtual __int64 songSizeOnHardDrive(songid_t song); // how big a song will be when copied back. Return -1 for not supported.
+
+ virtual int copyToHardDrive(songid_t song, // the song to copy
+ wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
+ void * callbackContext, //pass this to the callback
+ void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
+ int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
+ ); // -1 for failed/not supported. 0 for success.
+
+ // art functions
+ virtual void setArt(songid_t songid, void *buf, int w, int h); //buf is in format ARGB32*
+ virtual pmpart_t getArt(songid_t songid);
+ virtual void releaseArt(pmpart_t art);
+ virtual int drawArt(pmpart_t art, HDC dc, int x, int y, int w, int h);
+ virtual void getArtNaturalSize(pmpart_t art, int *w, int *h);
+ virtual void setArtNaturalSize(pmpart_t art, int w, int h);
+ virtual void getArtData(pmpart_t art, void* data); // data ARGB32* is at natural size
+ virtual bool artIsEqual(pmpart_t a, pmpart_t b);
+
+ PlaylistsList playlists;
+ TrackList tracks;
+ DeviceInfo device_info;
+ char *url;
+ int image16, image160;
+ Transcoder *transcoder;
+ int64_t transferQueueLength;
+}; \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/images.cpp b/Src/Plugins/Portable/pmp_wifi/images.cpp
new file mode 100644
index 00000000..6badb929
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/images.cpp
@@ -0,0 +1,72 @@
+#include "main.h"
+#include "images.h"
+#include "resource.h"
+#include <strsafe.h>
+
+static int small_images[] = { IDB_GENERIC_16, IDB_EVO_16, IDB_INCREDIBLE_16, IDB_NEXUSONE_16, IDB_DROID_16 };
+static int large_images[] = { IDB_GENERIC_160, IDB_EVO_160, IDB_INCREDIBLE_160, IDB_NEXUSONE_160, IDB_DROID_160 };
+int GetImageIndex(const wchar_t *manufacturer, const wchar_t *model)
+{
+ if (!wcscmp(manufacturer, L"HTC"))
+ {
+ if (!wcscmp(model, L"PC36100")) // evo
+ {
+ return 1;
+ }
+ else if (!wcscmp(model, L"ADR6300")) // incredible
+ {
+ return 2;
+ }
+ else if (!wcscmp(model, L"Nexus One"))
+ {
+ return 3;
+ }
+ }
+ else if (!wcscmp(manufacturer, L"motorola"))
+ {
+ if (!wcscmp(model, L"DROID2"))
+ {
+ return 4;
+ }
+ }
+
+ return 0;
+}
+
+void GetImagePath(int image_index, int width, int height, wchar_t *path, size_t path_cch)
+{
+ if (image_index < 0)
+ {
+ path[0]=0;
+ return;
+ }
+
+ if (width <= 16 && height <= 16)
+ {
+ if (image_index >= sizeof(small_images)/sizeof(small_images[0]))
+ {
+ path[0]=0;
+ return;
+ }
+ int resource = small_images[image_index];
+ FormatResProtocol(MAKEINTRESOURCE(resource), L"PNG", path, path_cch);
+ }
+ else
+ {
+ if (image_index >= sizeof(large_images)/sizeof(large_images[0]))
+ {
+ path[0]=0;
+ return;
+ }
+ int resource = large_images[image_index];
+ FormatResProtocol(MAKEINTRESOURCE(resource), L"PNG", path, path_cch);
+ }
+}
+
+int GetSmallImageID(int image_index)
+{
+ if (image_index < 0 || image_index >= sizeof(small_images)/sizeof(small_images[0]))
+ return IDB_GENERIC_16;
+
+ return small_images[image_index];
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/images.h b/Src/Plugins/Portable/pmp_wifi/images.h
new file mode 100644
index 00000000..39fd9e13
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/images.h
@@ -0,0 +1,5 @@
+#pragma once
+
+int GetImageIndex(const wchar_t *manufacturer, const wchar_t *model);
+void GetImagePath(int image_index, int width, int height, wchar_t *path, size_t path_cch);
+int GetSmallImageID(int image_index); \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/main.cpp b/Src/Plugins/Portable/pmp_wifi/main.cpp
new file mode 100644
index 00000000..6df15a76
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/main.cpp
@@ -0,0 +1,263 @@
+#include "../../Library/ml_pmp/pmp.h"
+#include "../Winamp/wa_ipc.h"
+#include "device.h"
+#include "api.h"
+#include "main.h"
+#include "nu/ns_wc.h"
+#include "resource.h"
+#include <shlwapi.h>
+#include <strsafe.h>
+
+#define PLUGIN_VERSION L"1.56"
+int winampVersion = 0;
+ifc_devicesupportedcommandenum *command_enum=0;
+ifc_devicesupportedcommandstore *command_store=0;
+ifc_deviceeventmanager *device_event_manager;
+char winamp_name[260] = {0};
+char winamp_id_str[40] = {0};
+wchar_t inifile[MAX_PATH] = {0};
+GUID winamp_id = GUID_NULL;
+static int Init();
+static void Quit();
+static intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3);
+
+PMPDevicePlugin plugin = {PMPHDR_VER,0,Init,Quit,MessageProc};
+void StartListenServer();
+
+
+BOOL FormatResProtocol(const wchar_t *resourceName, const wchar_t *resourceType, wchar_t *buffer, size_t bufferMax)
+{
+ unsigned long filenameLength;
+
+ if (NULL == resourceName)
+ return FALSE;
+
+ if (FAILED(StringCchCopyExW(buffer, bufferMax, L"res://", &buffer, &bufferMax, 0)))
+ return FALSE;
+
+ filenameLength = GetModuleFileNameW(plugin.hDllInstance, buffer, (DWORD)bufferMax);
+ if (0 == filenameLength || bufferMax == filenameLength)
+ return FALSE;
+
+ buffer += filenameLength;
+ bufferMax -= filenameLength;
+
+ if (NULL != resourceType)
+ {
+ if (FALSE != IS_INTRESOURCE(resourceType))
+ {
+ if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/#%d", (int)(INT_PTR)resourceType)))
+ return FALSE;
+ }
+ else
+ {
+ if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/%s", resourceType)))
+ return FALSE;
+ }
+ }
+
+ if (FALSE != IS_INTRESOURCE(resourceName))
+ {
+ if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/#%d", (int)(INT_PTR)resourceName)))
+ return FALSE;
+ }
+ else
+ {
+ if (FAILED(StringCchPrintfExW(buffer, bufferMax, &buffer, &bufferMax, 0, L"/%s", resourceName)))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+class WifiDeviceConnection : public ifc_deviceconnection
+{
+public:
+ WifiDeviceConnection()
+ {
+ }
+ const char *GetName()
+ {
+ return "wifi";
+ }
+
+ HRESULT GetIcon(wchar_t *buffer, size_t bufferMax, int width, int height)
+ {
+ if(FALSE == FormatResProtocol(MAKEINTRESOURCE(IDB_WIFI), L"PNG", buffer, bufferMax))
+ return E_FAIL;
+
+ return S_OK;
+ }
+
+ HRESULT GetDisplayName(wchar_t *buffer, size_t bufferMax)
+ {
+ if (NULL == buffer)
+ return E_POINTER;
+
+ WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_CONNECTION_WIFI, buffer, bufferMax);
+ return S_OK;
+ }
+protected:
+
+#define CBCLASS WifiDeviceConnection
+ START_DISPATCH_INLINE;
+ CB(API_GETNAME, GetName);
+ CB(API_GETICON, GetIcon);
+ CB(API_GETDISPLAYNAME, GetDisplayName);
+ END_DISPATCH;
+#undef CBCLASS
+};
+
+class AttachCommand : public ifc_devicecommand
+{
+public:
+ const char *GetName()
+ {
+ return "attach";
+ }
+
+ HRESULT GetIcon(wchar_t *buffer, size_t bufferMax, int width, int height)
+ {
+ int resourceId;
+
+ if (width <= 16 && height <= 16)
+ resourceId = IDB_ATTACH_16;
+ else
+ resourceId = IDB_ATTACH;
+
+ if(FALSE == FormatResProtocol(MAKEINTRESOURCE(resourceId), L"PNG", buffer, bufferMax))
+ return E_FAIL;
+
+ return S_OK;
+ }
+
+ HRESULT GetDisplayName(wchar_t *buffer, size_t bufferMax)
+ {
+ if (NULL == buffer)
+ return E_POINTER;
+
+ WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_CMD_ATTACH, buffer, bufferMax);
+ return S_OK;
+ }
+
+ HRESULT GetDescription(wchar_t *buffer, size_t bufferMax)
+ {
+ if (NULL == buffer)
+ return E_POINTER;
+
+ WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_CMD_ATTACH_DESC, buffer, bufferMax);
+ return S_OK;
+ }
+
+#define CBCLASS AttachCommand
+ START_DISPATCH_INLINE;
+ CB(API_GETNAME, GetName);
+ CB(API_GETICON, GetIcon);
+ CB(API_GETDISPLAYNAME, GetDisplayName);
+ CB(API_GETDESCRIPTION, GetDescription);
+ END_DISPATCH;
+#undef CBCLASS
+};
+
+class DeviceCommand : public Countable<ifc_devicesupportedcommand>
+{
+public:
+ DeviceCommand(const char *name, DeviceCommandFlags flags);
+
+public:
+ const char *GetName();
+ HRESULT GetFlags(DeviceCommandFlags *flags);
+ REFERENCE_COUNT_IMPLEMENTATION;
+
+public:
+ const char *name;
+ DeviceCommandFlags flags;
+RECVS_DISPATCH;
+};
+
+
+static AttachCommand attach_command;
+static WifiDeviceConnection wifi_connection;
+static int Init()
+{
+ winampVersion = (int)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETVERSION);
+ WasabiInit();
+
+ if (!AGAVE_API_DEVICEMANAGER)
+ return 1;
+ WASABI_API_APP->GetUserID(&winamp_id);
+ StringCbPrintfA(winamp_id_str, sizeof(winamp_id_str), "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", (int)winamp_id.Data1, (int)winamp_id.Data2, (int)winamp_id.Data3, (int)winamp_id.Data4[0], (int)winamp_id.Data4[1], (int)winamp_id.Data4[2], (int)winamp_id.Data4[3], (int)winamp_id.Data4[4], (int)winamp_id.Data4[5], (int)winamp_id.Data4[6], (int)winamp_id.Data4[7] );
+
+ wchar_t user_name[128] = {0};
+ wchar_t computer_name[128] = {0};
+ DWORD buffer_size_user = 128, buffer_size_computer=128;
+ if (GetUserNameW(user_name, &buffer_size_user) && GetComputerNameW(computer_name, &buffer_size_computer))
+ {
+ wchar_t winamp_name_utf16[260] = {0};
+ StringCbPrintfW(winamp_name_utf16, sizeof(winamp_name_utf16), L"%s (%s)", user_name, computer_name);
+ WideCharToMultiByteSZ(CP_UTF8, 0, winamp_name_utf16, -1, winamp_name, sizeof(winamp_name), 0, 0);
+ }
+ else
+ StringCbCopyA(winamp_name, sizeof(winamp_name), "Winamp");
+
+ const wchar_t *settings_path = WASABI_API_APP->path_getUserSettingsPath();
+ PathCombineW(inifile, settings_path, L"Plugins\\ml\\pmp_wifi.ini");
+
+ // need to have this initialized before we try to do anything with localization features
+ WASABI_API_START_LANG(plugin.hDllInstance,PmpWifiLangGUID);
+
+ static wchar_t szDescription[256];
+ StringCbPrintfW(szDescription, sizeof(szDescription),
+ WASABI_API_LNGSTRINGW(IDS_NULLSOFT_WIFI_DEVICE_PLUGIN), PLUGIN_VERSION);
+ plugin.description = szDescription;
+
+ if (AGAVE_API_DEVICEMANAGER)
+ {
+ ifc_devicecommand *command = &attach_command;
+ AGAVE_API_DEVICEMANAGER->CommandRegister(&command, 1);
+
+ ifc_deviceconnection *connection = &wifi_connection;
+ AGAVE_API_DEVICEMANAGER->ConnectionRegister(&connection, 1);
+
+
+ AGAVE_API_DEVICEMANAGER->CreateSupportedCommandStore(&command_store);
+ command_store->Add("attach", DeviceCommandFlag_Primary);
+
+ AGAVE_API_DEVICEMANAGER->CreateDeviceEventManager(&device_event_manager);
+ }
+ //AGAVE_API_DEVICEMANAGER->CreateSupportedCommandEnum(&command, 1, &command_enum);
+ /* TODO: Use this if your device shows up as a normal drive
+ SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)autoDetectCallback,PMP_IPC_ENUM_ACTIVE_DRIVES);
+ */
+ StartListenServer();
+ return 0;
+}
+
+static void Quit()
+{
+ StopListenServer();
+ WasabiQuit();
+}
+
+
+
+static intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3)
+{
+ switch(msg) {
+ case PMP_DEVICECHANGE:
+ // TODO: Implement
+ return 0;
+ case PMP_NO_CONFIG:
+ return TRUE;
+ case PMP_CONFIG:
+ // TODO: Implement (Egg: changed from 1 to 0, for now)
+ return 0;
+ }
+ return 0;
+}
+
+extern "C" __declspec(dllexport) PMPDevicePlugin *winampGetPMPDevicePlugin()
+{
+ return &plugin;
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/main.h b/Src/Plugins/Portable/pmp_wifi/main.h
new file mode 100644
index 00000000..b571a777
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/main.h
@@ -0,0 +1,30 @@
+#pragma once
+#include "../../Library/ml_pmp/pmp.h"
+#include "../Winamp/wa_ipc.h"
+#include <bfc/platform/types.h>
+#include "modelInfo.h"
+extern PMPDevicePlugin plugin;
+extern int winampVersion;
+extern GUID winamp_id;
+extern char winamp_id_str[40];
+extern char winamp_name[260];
+extern wchar_t inifile[MAX_PATH];
+void StopListenServer();
+BOOL FormatResProtocol(const wchar_t *resourceName, const wchar_t *resourceType, wchar_t *buffer, size_t bufferMax);
+
+
+// result from <device> XML data structure
+struct DeviceInfo
+{
+ uint64_t total_space, used_space;
+ uint64_t id;
+
+ wchar_t manufacturer[128];
+ wchar_t model[128];
+ wchar_t name[128];
+ wchar_t product[128];
+ const ModelInfo *modelInfo;
+};
+
+extern "C" void DeviceInfo_Init(DeviceInfo *device_info);
+extern "C" void DeviceInfo_Copy(DeviceInfo *dest, const DeviceInfo *source); \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/modelInfo.cpp b/Src/Plugins/Portable/pmp_wifi/modelInfo.cpp
new file mode 100644
index 00000000..72720c5c
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/modelInfo.cpp
@@ -0,0 +1,168 @@
+#include "main.h"
+#include "./modelInfo.h"
+#include "./api.h"
+#include "./resource.h"
+
+#include <strsafe.h>
+
+typedef struct ManufacturerInfo
+{
+ const wchar_t *name;
+ const ModelInfo *records;
+ size_t count;
+} ManufacturerInfo;
+
+#define MANUFACTURER(_name, _model_table)\
+{ (_name), (_model_table), ARRAYSIZE(_model_table) }
+
+#define MODEL(_name, _title_res_id, _small_icon_res_id, _large_icon_res_id)\
+{ (_name), MAKEINTRESOURCE(_title_res_id), MAKEINTRESOURCE(_small_icon_res_id), MAKEINTRESOURCE(_large_icon_res_id)}
+
+
+const struct ModelInfo HtcModelTable[] =
+{
+ MODEL(L"PC36100", IDS_DEVICE_MODEL_HTC_EVO, IDB_EVO_16, IDB_EVO_160),
+ MODEL(L"ADR6300", IDS_DEVICE_MODEL_HTC_INCREDIBLE, IDB_INCREDIBLE_16, IDB_INCREDIBLE_160),
+ MODEL(L"Nexus One", IDS_DEVICE_MODEL_HTC_NEXUS_ONE, IDB_NEXUSONE_16, IDB_NEXUSONE_160),
+ MODEL(L"Desire", IDS_DEVICE_MODEL_HTC_DESIRE, IDB_HTC_DESIRE_16, IDB_HTC_DESIRE_160),
+ MODEL(L"Wildfire", IDS_DEVICE_MODEL_HTC_WILDFIRE, 0, 0),
+ MODEL(L"Hero", IDS_DEVICE_MODEL_HTC_HERO, 0, 0),
+};
+
+const struct ModelInfo MotorolaModelTable[] =
+{
+ MODEL(L"Droid", IDS_DEVICE_MODEL_MOTOROLA_DROID, IDB_DROID_16, IDB_DROID_160),
+ MODEL(L"DROID2", IDS_DEVICE_MODEL_MOTOROLA_DROID2, IDB_DROID_16, IDB_DROID_160),
+ MODEL(L"DROIDX", IDS_DEVICE_MODEL_MOTOROLA_DROIDX, IDB_DROIDX_16, IDB_DROIDX_160),
+ MODEL(L"Milestone", IDS_DEVICE_MODEL_MOTOROLA_MILESTONE, IDB_DROID_16, IDB_DROID_160),
+ MODEL(L"DROIDX2", IDS_DEVICE_MODEL_MOTOROLA_DROIDX2, IDB_DROID_16, IDB_DROID_160),
+};
+
+const struct ModelInfo SamsungModelTable[] =
+{
+ MODEL(L"GT I9000", IDS_DEVICE_MODEL_SAMSUNG_GALAXY_S, 0, 0),
+};
+
+const static ManufacturerInfo ManufacturerTable[] =
+{
+ MANUFACTURER(L"HTC", HtcModelTable),
+ MANUFACTURER(L"motorola", MotorolaModelTable),
+ MANUFACTURER(L"samsung", SamsungModelTable),
+};
+
+const static ModelInfo defaultModel = { L"", L"", MAKEINTRESOURCE(IDB_GENERIC_16), MAKEINTRESOURCE(IDB_GENERIC_160)};
+
+const ModelInfo *
+FindModelInfo(const wchar_t *manufacturer, const wchar_t *model, BOOL allowDefault)
+{
+ if (NULL != manufacturer &&
+ NULL != model)
+ {
+ const ManufacturerInfo *manufacturerInfo;
+ size_t i;
+ unsigned long lcid;
+
+ lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
+
+ for (i = 0; i < ARRAYSIZE(ManufacturerTable); i++)
+ {
+ manufacturerInfo = &ManufacturerTable[i];
+ if (CSTR_EQUAL == CompareString(lcid, NORM_IGNORECASE, manufacturerInfo->name, -1, manufacturer, -1))
+ {
+ for (i = 0; i < manufacturerInfo->count; i++)
+ {
+ const ModelInfo *modelInfo = &manufacturerInfo->records[i];
+ if (CSTR_EQUAL == CompareString(lcid, NORM_IGNORECASE, modelInfo->name, -1, model, -1))
+ {
+ return modelInfo;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (FALSE != allowDefault)
+ return &defaultModel;
+
+ return NULL;
+}
+
+const ModelInfo*
+GetDefaultModelInfo()
+{
+ return &defaultModel;
+}
+
+HRESULT ModelInfo_CopyDisplayName(const ModelInfo *modelInfo, wchar_t *buffer, size_t bufferMax)
+{
+ if (NULL == modelInfo)
+ return E_INVALIDARG;
+
+ if (NULL == buffer)
+ return E_POINTER;
+
+ if (NULL == modelInfo->displayName)
+ return E_UNEXPECTED;
+
+
+ if (FALSE != IS_INTRESOURCE(modelInfo->displayName))
+ {
+ WASABI_API_LNGSTRINGW_BUF((int)(intptr_t)modelInfo->displayName, buffer, bufferMax);
+ return S_OK;
+ }
+
+ if (FAILED(StringCchCopy(buffer, bufferMax, modelInfo->displayName)))
+ return E_FAIL;
+
+ return S_OK;
+}
+
+const wchar_t *ModelInfo_GetIconName(const ModelInfo *modelInfo, int width, int height, BOOL allowDefault)
+{
+ if (NULL == modelInfo)
+ {
+ if (FALSE == allowDefault)
+ return NULL;
+
+ modelInfo = GetDefaultModelInfo();
+ if (NULL == modelInfo)
+ return NULL;
+ }
+
+ if (width <= 16 && height <= 16)
+ {
+ if (NULL == modelInfo->smallIcon &&
+ FALSE != allowDefault)
+ {
+ modelInfo = GetDefaultModelInfo();
+ if (NULL == modelInfo)
+ return NULL;
+ }
+ return modelInfo->smallIcon;
+ }
+
+ if (NULL == modelInfo->largeIcon &&
+ FALSE != allowDefault)
+ {
+ modelInfo = GetDefaultModelInfo();
+ if (NULL == modelInfo)
+ return NULL;
+ }
+
+ return modelInfo->largeIcon;
+}
+
+HRESULT ModelInfo_GetIconPath(const ModelInfo *modelInfo, int width, int height, wchar_t *buffer, size_t bufferMax, BOOL allowDefault)
+{
+ const wchar_t *iconName;
+
+ iconName = ModelInfo_GetIconName(modelInfo, width, height, allowDefault);
+ if (NULL == iconName)
+ return E_FAIL;
+
+ if (FALSE == FormatResProtocol(iconName, L"PNG", buffer, bufferMax))
+ return E_FAIL;
+
+ return S_OK;
+} \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/modelInfo.h b/Src/Plugins/Portable/pmp_wifi/modelInfo.h
new file mode 100644
index 00000000..6e3d3c53
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/modelInfo.h
@@ -0,0 +1,22 @@
+#pragma once
+
+typedef struct ModelInfo
+{
+ const wchar_t *name;
+ const wchar_t *displayName;
+ const wchar_t *smallIcon;
+ const wchar_t *largeIcon;
+} ModelInfo;
+
+
+const ModelInfo *GetDefaultModelInfo();
+const ModelInfo *FindModelInfo(const wchar_t *manufacturer, const wchar_t *model, BOOL allowDefault);
+
+/* helpers*/
+HRESULT ModelInfo_CopyDisplayName(const ModelInfo *modelInfo, wchar_t *buffer, size_t bufferMax);
+
+const wchar_t *ModelInfo_GetIconName(const ModelInfo *modelInfo, int width, int height, BOOL allowDefault);
+
+HRESULT ModelInfo_GetIconPath(const ModelInfo *modelInfo, int width, int height, wchar_t *buffer, size_t bufferMax, BOOL allowDefault);
+
+
diff --git a/Src/Plugins/Portable/pmp_wifi/pmp_wifi.rc b/Src/Plugins/Portable/pmp_wifi/pmp_wifi.rc
new file mode 100644
index 00000000..36b963e6
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/pmp_wifi.rc
@@ -0,0 +1,126 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""version.rc2""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// PNG
+//
+
+IDB_GENERIC_16 PNG "resources\\generic_drive_wifi_16.png"
+IDB_HTC_DESIRE_16 PNG "resources\\htc_desire_passion_bravo_16.png"
+IDB_EVO_16 PNG "resources\\htc_evo_4g_16.png"
+IDB_NEXUSONE_16 PNG "resources\\htc_nexus_one_16.png"
+IDB_DROID_16 PNG "resources\\motorola_droid_16.png"
+IDB_GENERIC_160 PNG "resources\\generic_android.png"
+IDB_HTC_DESIRE_160 PNG "resources\\htc_desire_passion_bravo.png"
+IDB_EVO_160 PNG "resources\\htc_evo_4g.png"
+IDB_DROID_160 PNG "resources\\motorola_droid.png"
+IDB_WIFI PNG "resources\\wifi.png"
+IDB_ATTACH PNG "resources\\attach.png"
+IDB_ATTACH_16 PNG "resources\\attach16.png"
+IDB_INCREDIBLE_160 PNG "resources\\htc_incredible.png"
+IDB_INCREDIBLE_16 PNG "resources\\htc_incredible_16.png"
+IDB_NEXUSONE_160 PNG "resources\\nexus_one.png"
+IDB_DROIDX_160 PNG "resources\\motorola_droid_x.png"
+IDB_DROIDX_16 PNG "resources\\motorola_droid_x_16.png"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_NULLSOFT_WIFI_DEVICE_PLUGIN "Nullsoft Wi-Fi Device Plug-in v%s"
+ 65535 "{3066887B-CA40-4683-897F-4416FE349D7E}"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_ACTIVITY_CONNECT "Connecting..."
+ IDS_ACTIVITY_CONNECT_DESC "Connecting device."
+ IDS_DEVICE_CONNECTION_WIFI "Wi-Fi"
+ IDS_DEVICE_CMD_ATTACH "&Attach"
+ IDS_DEVICE_CMD_ATTACH_DESC "Attach device to Winamp"
+ IDS_DEVICE_MODEL_HTC_EVO "HTC Evo 4G"
+ IDS_DEVICE_MODEL_HTC_INCREDIBLE "DROID INCREDIBLE by HTC"
+ IDS_DEVICE_MODEL_HTC_NEXUS_ONE "Google Nexus One"
+ IDS_DEVICE_MODEL_MOTOROLA_DROID2 "DROID 2 by Motorola"
+ IDS_DEVICE_MODEL_MOTOROLA_DROIDX "DROID X by Motorola"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_DEVICE_MODEL_MOTOROLA_DROID "DROID by Motorola"
+ IDS_DEVICE_MODEL_HTC_DESIRE "HTC Desire"
+ IDS_DEVICE_MODEL_SAMSUNG_GALAXY_S "Samsung Galaxy S"
+ IDS_DEVICE_MODEL_MOTOROLA_MILESTONE "Motorola Milestone"
+ IDS_DEVICE_MODEL_HTC_WILDFIRE "HTC Wildfire"
+ IDS_DEVICE_MODEL_HTC_HERO "HTC Hero"
+ IDS_CONNECTING "Connecting"
+ IDS_UPLOADING "Uploading (%d%%)"
+ IDS_COMPLETED "Completed"
+ IDS_DEVICE_MODEL_MOTOROLA_DROIDX2 "DROID X2 by Motorola"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc2"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/Plugins/Portable/pmp_wifi/pmp_wifi.sln b/Src/Plugins/Portable/pmp_wifi/pmp_wifi.sln
new file mode 100644
index 00000000..965cd264
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/pmp_wifi.sln
@@ -0,0 +1,83 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29509.3
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmp_wifi", "pmp_wifi.vcxproj", "{DD76E337-88AD-402E-ACC7-E33510A5AE43}"
+ ProjectSection(ProjectDependencies) = postProject
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27} = {57C90706-B25D-4ACA-9B33-95CDB2427C27}
+ {44AEBB50-1331-4F2E-8AEC-56C82DE16C11} = {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915} = {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}
+ {E105A0A2-7391-47C5-86AC-718003524C3D} = {E105A0A2-7391-47C5-86AC-718003524C3D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nx", "..\replicant\nx\nx.vcxproj", "{57C90706-B25D-4ACA-9B33-95CDB2427C27}"
+ ProjectSection(ProjectDependencies) = postProject
+ {44AEBB50-1331-4F2E-8AEC-56C82DE16C11} = {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nu", "..\replicant\nu\nu.vcxproj", "{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jnetlib", "..\replicant\jnetlib\jnetlib.vcxproj", "{E105A0A2-7391-47C5-86AC-718003524C3D}"
+ ProjectSection(ProjectDependencies) = postProject
+ {44AEBB50-1331-4F2E-8AEC-56C82DE16C11} = {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\replicant\zlib\zlib.vcxproj", "{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {DD76E337-88AD-402E-ACC7-E33510A5AE43}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DD76E337-88AD-402E-ACC7-E33510A5AE43}.Debug|Win32.Build.0 = Debug|Win32
+ {DD76E337-88AD-402E-ACC7-E33510A5AE43}.Debug|x64.ActiveCfg = Debug|x64
+ {DD76E337-88AD-402E-ACC7-E33510A5AE43}.Debug|x64.Build.0 = Debug|x64
+ {DD76E337-88AD-402E-ACC7-E33510A5AE43}.Release|Win32.ActiveCfg = Release|Win32
+ {DD76E337-88AD-402E-ACC7-E33510A5AE43}.Release|Win32.Build.0 = Release|Win32
+ {DD76E337-88AD-402E-ACC7-E33510A5AE43}.Release|x64.ActiveCfg = Release|x64
+ {DD76E337-88AD-402E-ACC7-E33510A5AE43}.Release|x64.Build.0 = Release|x64
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.ActiveCfg = Debug|Win32
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.Build.0 = Debug|Win32
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.ActiveCfg = Debug|x64
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.Build.0 = Debug|x64
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.ActiveCfg = Release|Win32
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.Build.0 = Release|Win32
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.ActiveCfg = Release|x64
+ {57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.Build.0 = Release|x64
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.Build.0 = Debug|Win32
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.ActiveCfg = Debug|x64
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.Build.0 = Debug|x64
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.ActiveCfg = Release|Win32
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.Build.0 = Release|Win32
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.ActiveCfg = Release|x64
+ {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.Build.0 = Release|x64
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.Build.0 = Debug|Win32
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.ActiveCfg = Debug|x64
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.Build.0 = Debug|x64
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.ActiveCfg = Release|Win32
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.Build.0 = Release|Win32
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.ActiveCfg = Release|x64
+ {E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.Build.0 = Release|x64
+ {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Debug|Win32.ActiveCfg = Debug|Win32
+ {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Debug|Win32.Build.0 = Debug|Win32
+ {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Debug|x64.ActiveCfg = Debug|x64
+ {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Debug|x64.Build.0 = Debug|x64
+ {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Release|Win32.ActiveCfg = Release|Win32
+ {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Release|Win32.Build.0 = Release|Win32
+ {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Release|x64.ActiveCfg = Release|x64
+ {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {C4E799C1-027B-487B-8E1A-31F2D26A1AFE}
+ EndGlobalSection
+EndGlobal
diff --git a/Src/Plugins/Portable/pmp_wifi/pmp_wifi.vcxproj b/Src/Plugins/Portable/pmp_wifi/pmp_wifi.vcxproj
new file mode 100644
index 00000000..a85823eb
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/pmp_wifi.vcxproj
@@ -0,0 +1,341 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{DD76E337-88AD-402E-ACC7-E33510A5AE43}</ProjectGuid>
+ <RootNamespace>pmp_wifi</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg">
+ <VcpkgEnableManifest>false</VcpkgEnableManifest>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\..\Wasabi;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;pmp_wifi_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>ws2_32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>nxlite.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\..\Wasabi;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;pmp_wifi_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>ws2_32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>nxlite.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\..\Wasabi;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;pmp_wifi_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <DisableSpecificWarnings>4018;4995;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>ws2_32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>nxlite.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>MinSpace</Optimization>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\..\Wasabi;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;pmp_wifi_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <DisableSpecificWarnings>4018;4995;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>ws2_32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>nxlite.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\..\replicant\jnetlib\asyncdns.cpp" />
+ <ClCompile Include="..\..\..\replicant\jnetlib\multicastlisten.cpp" />
+ <ClCompile Include="..\..\..\replicant\jnetlib\udpconnection.cpp" />
+ <ClCompile Include="..\..\..\replicant\jnetlib\util.cpp" />
+ <ClCompile Include="..\..\..\replicant\nu\RingBuffer.cpp" />
+ <ClCompile Include="api.cpp" />
+ <ClCompile Include="ConnectActivity.cpp" />
+ <ClCompile Include="device.cpp" />
+ <ClCompile Include="images.cpp" />
+ <ClCompile Include="InfoDownloader.cpp" />
+ <ClCompile Include="ListenServer.cpp" />
+ <ClCompile Include="main.cpp" />
+ <ClCompile Include="modelInfo.cpp" />
+ <ClCompile Include="Pair.cpp" />
+ <ClCompile Include="PlaylistSync.cpp" />
+ <ClCompile Include="post.cpp" />
+ <ClCompile Include="RenameDownloader.cpp" />
+ <ClCompile Include="SongDownloader.cpp" />
+ <ClCompile Include="SongListDownloader.cpp" />
+ <ClCompile Include="WifiDevice.cpp" />
+ <ClCompile Include="WifiPlaylist.cpp" />
+ <ClCompile Include="XMLString.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\..\replicant\jnetlib\asyncdns.h" />
+ <ClInclude Include="..\..\..\replicant\jnetlib\multicastlisten.h" />
+ <ClInclude Include="..\..\..\replicant\jnetlib\udpconnection.h" />
+ <ClInclude Include="..\..\..\replicant\jnetlib\util.h" />
+ <ClInclude Include="..\..\Library\ml_pmp\pmp.h" />
+ <ClInclude Include="..\..\..\replicant\nu\RingBuffer.h" />
+ <ClInclude Include="api.h" />
+ <ClInclude Include="ConnectActivity.h" />
+ <ClInclude Include="device.h" />
+ <ClInclude Include="InfoDownloader.h" />
+ <ClInclude Include="main.h" />
+ <ClInclude Include="modelInfo.h" />
+ <ClInclude Include="Pair.h" />
+ <ClInclude Include="PlaylistSync.h" />
+ <ClInclude Include="RenameDownloader.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="SongDownloader.h" />
+ <ClInclude Include="SongListDownloader.h" />
+ <ClInclude Include="WifiDevice.h" />
+ <ClInclude Include="WifiPlaylist.h" />
+ <ClInclude Include="XMLString.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="attach.png" />
+ <Image Include="attach16.png" />
+ <Image Include="generic_android.png" />
+ <Image Include="generic_drive_wifi_16.png" />
+ <Image Include="htc_desire_passion_bravo.png" />
+ <Image Include="htc_desire_passion_bravo_16.png" />
+ <Image Include="htc_evo_4g.png" />
+ <Image Include="htc_evo_4g_16.png" />
+ <Image Include="htc_hd2.png" />
+ <Image Include="htc_hd2_16.png" />
+ <Image Include="htc_incredible.png" />
+ <Image Include="htc_incredible_16.png" />
+ <Image Include="htc_nexus_one_16.png" />
+ <Image Include="motorola_droid.png" />
+ <Image Include="motorola_droid_16.png" />
+ <Image Include="motorola_droid_x.png" />
+ <Image Include="motorola_droid_x_16.png" />
+ <Image Include="nexus_one.png" />
+ <Image Include="wifi.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="pmp_wifi.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\General\gen_ml\gen_ml.vcxproj">
+ <Project>{9b212232-4908-49d2-8d6d-96555b1f701e}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Library\ml_pmp\ml_pmp.vcxproj">
+ <Project>{c524f141-87ca-491b-91d8-920248c9066e}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\replicant\nu\nu.vcxproj">
+ <Project>{f1f5cd60-0d5b-4cea-9eeb-2f87ff9aa915}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\replicant\nx\nx.vcxproj">
+ <Project>{57c90706-b25d-4aca-9b33-95cdb2427c27}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Wasabi\bfc\bfc.vcxproj">
+ <Project>{d0ec862e-dddd-4f4f-934f-b75dc9062dc1}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
+ <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/pmp_wifi.vcxproj.filters b/Src/Plugins/Portable/pmp_wifi/pmp_wifi.vcxproj.filters
new file mode 100644
index 00000000..ebb2023c
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/pmp_wifi.vcxproj.filters
@@ -0,0 +1,214 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="api.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ConnectActivity.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="device.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="images.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="InfoDownloader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ListenServer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="modelInfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Pair.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="XMLString.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="WifiPlaylist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="WifiDevice.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SongListDownloader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SongDownloader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="RenameDownloader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="post.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="PlaylistSync.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\replicant\jnetlib\asyncdns.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\replicant\jnetlib\multicastlisten.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\replicant\nu\RingBuffer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\replicant\jnetlib\udpconnection.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\replicant\jnetlib\util.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="api.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ConnectActivity.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="device.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="InfoDownloader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="modelInfo.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Pair.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="PlaylistSync.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="RenameDownloader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SongDownloader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SongListDownloader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="WifiDevice.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="WifiPlaylist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="XMLString.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\replicant\jnetlib\asyncdns.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\replicant\jnetlib\multicastlisten.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\Library\ml_pmp\pmp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\replicant\nu\RingBuffer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\replicant\jnetlib\udpconnection.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\replicant\jnetlib\util.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="attach.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="attach16.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="generic_android.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="generic_drive_wifi_16.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="htc_desire_passion_bravo.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="htc_desire_passion_bravo_16.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="htc_evo_4g.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="htc_evo_4g_16.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="htc_hd2.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="htc_hd2_16.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="htc_incredible.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="htc_incredible_16.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="htc_nexus_one_16.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="motorola_droid.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="motorola_droid_16.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="motorola_droid_x.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="motorola_droid_x_16.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="nexus_one.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ <Image Include="wifi.png">
+ <Filter>Image Files</Filter>
+ </Image>
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{0b5eaaf3-d36a-4b37-b20f-50ebc6c35a6f}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Ressource Files">
+ <UniqueIdentifier>{2f4cb2e1-34f6-44e9-bb88-ff40ce0f6e61}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{92dbab76-3096-4992-8074-7eabc2673267}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Image Files">
+ <UniqueIdentifier>{075a31ea-0a24-40e9-b4da-cc17b11a8459}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="pmp_wifi.rc">
+ <Filter>Ressource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Plugins/Portable/pmp_wifi/post.cpp b/Src/Plugins/Portable/pmp_wifi/post.cpp
new file mode 100644
index 00000000..3eb93dc2
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/post.cpp
@@ -0,0 +1,518 @@
+#include "main.h"
+#include "api.h"
+#include "resource.h"
+#include "../xml/obj_xml.h"
+#include "nu/AutoChar.h"
+#include "../nu/AutoUrl.h"
+#include "../nu/AutoHeader.h"
+#include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
+#include "../agave/albumart/svc_albumartprovider.h"
+#include <api/service/waservicefactory.h>
+#include <shlwapi.h>
+#include <strsafe.h>
+
+
+static const GUID internetConfigGroupGUID =
+{
+ 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c }
+};
+
+
+#define USER_AGENT_SIZE (10 /*User-Agent*/ + 2 /*: */ + 6 /*Winamp*/ + 1 /*/*/ + 1 /*5*/ + 3/*.21*/ + 1 /*Null*/)
+static void SetUserAgent(api_httpreceiver *http)
+{
+
+ char user_agent[USER_AGENT_SIZE] = {0};
+ int bigVer = ((winampVersion & 0x0000FF00) >> 12);
+ int smallVer = ((winampVersion & 0x000000FF));
+ StringCchPrintfA(user_agent, USER_AGENT_SIZE, "User-Agent: Winamp/%01x.%02x", bigVer, smallVer);
+ http->addheader(user_agent);
+}
+
+
+#define HTTP_BUFFER_SIZE 8192
+#define POST_BUFFER_SIZE (128*1024)
+
+
+int PostFile(const char *base_url, const wchar_t *filename, const itemRecordW *track, obj_xml *parser, int *killswitch,
+ void (*callback)(void *callbackContext, wchar_t *status), void *context, char *new_item_id, size_t new_item_id_len)
+{
+ //if (!parser)
+// return 1;
+ bool first=true;
+ char url[2048] = {0};
+ char *p_url=url;
+ size_t url_cch=sizeof(url)/sizeof(*url);
+ FILE *f = _wfopen(filename, L"rb");
+ if (!f)
+ return 1;
+ api_httpreceiver *http = 0;
+ waServiceFactory *sf = plugin.service->service_getServiceByGuid(httpreceiverGUID);
+ if (sf)
+ http = (api_httpreceiver *)sf->getInterface();
+
+ if (!http)
+ return 1;
+
+ int use_proxy = 1;
+ bool proxy80 = AGAVE_API_CONFIG->GetBool(internetConfigGroupGUID, L"proxy80", false);
+ if (proxy80 && strstr(url, ":") && (!strstr(url, ":80/") && strstr(url, ":80") != (url + strlen(url) - 3)))
+ use_proxy = 0;
+
+ const wchar_t *proxy = use_proxy?AGAVE_API_CONFIG->GetString(internetConfigGroupGUID, L"proxy", 0):0;
+
+ fseek(f, 0, SEEK_END);
+
+ size_t clen = ftell(f);
+ size_t transferred=0;
+ size_t total_clen = clen;
+ fseek(f, 0, SEEK_SET);
+
+ http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, (proxy && proxy[0]) ? (const char *)AutoChar(proxy) : NULL);
+ http->set_sendbufsize(POST_BUFFER_SIZE);
+ SetUserAgent(http);
+
+ char data[POST_BUFFER_SIZE] = {0};
+
+ StringCbCopyExA(p_url, url_cch, base_url, &p_url, &url_cch, 0);
+
+ StringCbPrintfA(data, sizeof(data), "Content-Length: %u", clen);
+ http->addheader(data);
+// http->addheader("Content-Type: application/octet-stream");
+
+ /* send metadata */
+ if (track->artist && track->artist[0])
+ {
+ if (first)
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?artist=%s", AutoUrl(track->artist));
+ else
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&artist=%s", AutoUrl(track->artist));
+ first=false;
+ }
+
+ if (track->title && track->title[0])
+ {
+ if (first)
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?title=%s", AutoUrl(track->title));
+ else
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&title=%s", AutoUrl(track->title));
+ first=false;
+ }
+
+ if (track->album && track->album[0])
+ {
+ if (first)
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?album=%s", AutoUrl(track->album));
+ else
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&album=%s", AutoUrl(track->album));
+ first=false;
+ }
+
+ if (track->composer && track->composer[0])
+ {
+ if (first)
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?composer=%s", AutoUrl(track->composer));
+ else
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&composer=%s", AutoUrl(track->composer));
+ first=false;
+ }
+
+ if (track->albumartist && track->albumartist[0])
+ {
+ if (first)
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?albumartist=%s", AutoUrl(track->albumartist));
+ else
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&albumartist=%s", AutoUrl(track->albumartist));
+ first=false;
+ }
+
+ if (track->genre && track->genre[0])
+ {
+ if (first)
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?genre=%s", AutoUrl(track->genre));
+ else
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&genre=%s", AutoUrl(track->genre));
+ first=false;
+ }
+
+ if (track->track > 0)
+ {
+ if (first)
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?track=%d", track->track);
+ else
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&track=%d", track->track);
+ first=false;
+ }
+
+ const wchar_t *ext = PathFindExtension(filename);
+ if (ext && ext[0])
+ {
+ if (ext[0] == '.') ext++;
+ if (ext[0])
+ {
+ if (first)
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "?extension=%s", AutoUrl(ext));
+ else
+ StringCbPrintfExA(p_url, url_cch, &p_url, &url_cch, 0, "&extension=%s", AutoUrl(ext));
+ first=false;
+ }
+ }
+
+
+ wchar_t mime_type[128] = {0};
+ if (AGAVE_API_METADATA->GetExtendedFileInfo(filename, L"mime", mime_type, 128) == 1 && mime_type[0])
+ {
+ http->AddHeaderValue("Content-Type", AutoHeader(mime_type));
+ }
+
+ http->AddHeaderValue("X-Winamp-ID", winamp_id_str);
+ http->AddHeaderValue("X-Winamp-Name", winamp_name);
+
+ http->AddHeaderValue("Expect", "100-continue");
+ /* connect */
+ callback(context, WASABI_API_LNGSTRINGW(IDS_CONNECTING));
+ http->connect(url, 0, "POST");
+
+ // spin and wait for a 100 response
+ for (;;)
+ {
+ Sleep(55);
+ if (*killswitch)
+ goto connection_failed;
+ int ret = http->run();
+ if (ret != HTTPRECEIVER_RUN_OK) // connection failed or closed
+ goto connection_failed;
+
+ int reply_code = http->getreplycode();
+ if (reply_code == 100)
+ break;
+ else if (reply_code)
+ goto connection_failed;
+ }
+
+
+ /* POST the data */
+ api_connection *connection = http->GetConnection();
+ if (connection)
+ {
+ if (http->run() == -1)
+ goto connection_failed;
+
+ while (clen)
+ {
+ int percent = MulDiv(100, (int)transferred, (int)total_clen);
+ wchar_t msg[128] = {0};
+ StringCbPrintfW(msg, sizeof(msg), WASABI_API_LNGSTRINGW(IDS_UPLOADING), percent);
+ callback(context, msg);
+ if (*killswitch)
+ goto connection_failed;
+ if (http->run() == -1)
+ goto connection_failed;
+
+ int connection_state = connection->get_state();
+ if (connection_state == CONNECTION_STATE_CLOSED || connection_state == CONNECTION_STATE_ERROR)
+ goto connection_failed;
+
+ size_t lengthToSend = min(clen, connection->GetSendBytesAvailable());
+ lengthToSend = min(lengthToSend, sizeof(data));
+
+ if (lengthToSend)
+ {
+ int bytes_read = (int)fread(data, 1, lengthToSend, f);
+ connection->send(data, bytes_read);
+ clen-=bytes_read;
+ transferred+=bytes_read;
+ }
+ else
+ {
+ Sleep(10);
+ }
+ }
+ int x;
+ while (x = (int)connection->GetSendBytesInQueue())
+ {
+ int connection_state = connection->get_state();
+ if (connection_state == CONNECTION_STATE_CLOSED || connection_state == CONNECTION_STATE_ERROR)
+ goto connection_failed;
+ Sleep(10);
+ if (*killswitch)
+ goto connection_failed;
+ if (http->run() == -1)
+ goto connection_failed;
+
+ }
+ }
+ fclose(f);
+ f=0;
+
+ /* retrieve reply */
+ int ret;
+ do
+ {
+ Sleep(55);
+ ret = http->run();
+ if (ret == -1) // connection failed
+ break;
+
+ // ---- check our reply code ----
+ int status = http->get_status();
+ switch (status)
+ {
+ case HTTPRECEIVER_STATUS_CONNECTING:
+ case HTTPRECEIVER_STATUS_READING_HEADERS:
+ break;
+
+ case HTTPRECEIVER_STATUS_READING_CONTENT:
+ {
+ const char *location = http->getheader("Location");
+ if (location)
+ StringCchCopyA(new_item_id, new_item_id_len, location);
+ else
+ new_item_id[0]=0;
+
+ sf->releaseInterface(http);
+ return 0;
+ }
+ break;
+ case HTTPRECEIVER_STATUS_ERROR:
+ default:
+ sf->releaseInterface(http);
+ return 1;
+ }
+ }
+ while (ret == HTTPRECEIVER_RUN_OK);
+
+
+connection_failed:
+ if (f)
+ fclose(f);
+ sf->releaseInterface(http);
+ return 1;
+}
+
+
+
+int PostAlbumArt(const char *url, const itemRecordW *track, obj_xml *parser, int *killswitch, void (*callback)(void *callbackContext, wchar_t *status), void *context)
+{
+
+ void *artData=0;
+ size_t datalen=0;
+ wchar_t *mimeType=0;
+ if (AGAVE_API_ALBUMART->GetAlbumArtData(track->filename, L"cover", &artData, &datalen, &mimeType) != ALBUMART_SUCCESS)
+ return 1;
+
+ api_httpreceiver *http = 0;
+ waServiceFactory *sf = plugin.service->service_getServiceByGuid(httpreceiverGUID);
+ if (sf)
+ http = (api_httpreceiver *)sf->getInterface();
+
+ if (!http)
+ return 1;
+
+ int use_proxy = 1;
+ bool proxy80 = AGAVE_API_CONFIG->GetBool(internetConfigGroupGUID, L"proxy80", false);
+ if (proxy80 && strstr(url, ":") && (!strstr(url, ":80/") && strstr(url, ":80") != (url + strlen(url) - 3)))
+ use_proxy = 0;
+
+ const wchar_t *proxy = use_proxy?AGAVE_API_CONFIG->GetString(internetConfigGroupGUID, L"proxy", 0):0;
+
+ uint8_t *artDataPtr=(uint8_t *)artData;
+ size_t clen = datalen;
+ size_t transferred=0;
+ size_t total_clen = datalen;
+
+ http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, (proxy && proxy[0]) ? (const char *)AutoChar(proxy) : NULL);
+ http->set_sendbufsize(POST_BUFFER_SIZE);
+ SetUserAgent(http);
+
+ char data[POST_BUFFER_SIZE] = {0};
+
+ StringCbPrintfA(data, sizeof(data), "Content-Length: %u", datalen);
+ http->addheader(data);
+ if (mimeType)
+ {
+ StringCbPrintfA(data, sizeof(data), "Content-Type: %s", AutoHeader(mimeType));
+ http->addheader(data);
+ }
+
+ http->AddHeaderValue("X-Winamp-ID", winamp_id_str);
+ http->AddHeaderValue("X-Winamp-Name", winamp_name);
+
+ /* connect */
+ http->AddHeaderValue("Expect", "100-continue");
+ callback(context, WASABI_API_LNGSTRINGW(IDS_CONNECTING));
+ http->connect(url, 0, "POST");
+
+ // spin and wait for a 100 response
+ for (;;)
+ {
+ Sleep(55);
+ int ret = http->run();
+ if (ret != HTTPRECEIVER_RUN_OK) // connection failed or closed
+ goto connection_failed;
+
+ if (*killswitch)
+ goto connection_failed;
+ int reply_code = http->getreplycode();
+ if (reply_code == 100)
+ break;
+ else if (reply_code)
+ goto connection_failed;
+ }
+
+ /* POST the data */
+ api_connection *connection = http->GetConnection();
+ if (connection)
+ {
+ if (http->run() == -1)
+ goto connection_failed;
+
+ while (clen)
+ {
+ int percent = MulDiv(100, (int)transferred, (int)total_clen);
+ wchar_t msg[128] = {0};
+ StringCbPrintfW(msg, sizeof(msg), L"Uploading Album Art (%d%%)", percent);
+ callback(context, msg);
+ if (*killswitch)
+ goto connection_failed;
+ if (http->run() == -1)
+ goto connection_failed;
+
+ int connection_state = connection->get_state();
+ if (connection_state == CONNECTION_STATE_CLOSED || connection_state == CONNECTION_STATE_ERROR)
+ goto connection_failed;
+
+ size_t lengthToSend = min(clen, connection->GetSendBytesAvailable());
+
+ if (lengthToSend)
+ {
+ connection->send(artDataPtr, (int)lengthToSend);
+ artDataPtr += lengthToSend;
+ clen-=lengthToSend;
+ transferred+=lengthToSend;
+ }
+ else
+ {
+ Sleep(10);
+ }
+ }
+ int x;
+ while (x = (int)connection->GetSendBytesInQueue())
+ {
+ int connection_state = connection->get_state();
+ if (connection_state == CONNECTION_STATE_CLOSED || connection_state == CONNECTION_STATE_ERROR)
+ goto connection_failed;
+ Sleep(10);
+ if (*killswitch)
+ goto connection_failed;
+ if (http->run() == -1)
+ goto connection_failed;
+
+ }
+ }
+
+ /* retrieve reply */
+ int ret;
+ do
+ {
+ Sleep(55);
+ ret = http->run();
+ if (ret == -1) // connection failed
+ break;
+
+ // ---- check our reply code ----
+ int status = http->get_status();
+ switch (status)
+ {
+ case HTTPRECEIVER_STATUS_CONNECTING:
+ case HTTPRECEIVER_STATUS_READING_HEADERS:
+ break;
+
+ case HTTPRECEIVER_STATUS_READING_CONTENT:
+ {
+ sf->releaseInterface(http);
+ WASABI_API_MEMMGR->sysFree(artData);
+ WASABI_API_MEMMGR->sysFree(mimeType);
+ return 0;
+ }
+ break;
+ case HTTPRECEIVER_STATUS_ERROR:
+ default:
+ sf->releaseInterface(http);
+ WASABI_API_MEMMGR->sysFree(artData);
+ WASABI_API_MEMMGR->sysFree(mimeType);
+ return 1;
+ }
+ }
+ while (ret == HTTPRECEIVER_RUN_OK);
+
+
+connection_failed:
+ WASABI_API_MEMMGR->sysFree(artData);
+ WASABI_API_MEMMGR->sysFree(mimeType);
+ sf->releaseInterface(http);
+ return 1;
+}
+
+
+int HTTP_Delete(const char *url)
+{
+ api_httpreceiver *http = 0;
+ waServiceFactory *sf = plugin.service->service_getServiceByGuid(httpreceiverGUID);
+ if (sf)
+ http = (api_httpreceiver *)sf->getInterface();
+
+ if (!http)
+ return 1;
+
+ int use_proxy = 1;
+ bool proxy80 = AGAVE_API_CONFIG->GetBool(internetConfigGroupGUID, L"proxy80", false);
+ if (proxy80 && strstr(url, ":") && (!strstr(url, ":80/") && strstr(url, ":80") != (url + strlen(url) - 3)))
+ use_proxy = 0;
+
+ const wchar_t *proxy = use_proxy?AGAVE_API_CONFIG->GetString(internetConfigGroupGUID, L"proxy", 0):0;
+
+ http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, (proxy && proxy[0]) ? (const char *)AutoChar(proxy) : NULL);
+ SetUserAgent(http);
+
+ http->AddHeaderValue("X-Winamp-ID", winamp_id_str);
+ http->AddHeaderValue("X-Winamp-Name", winamp_name);
+
+ /* connect */
+ http->connect(url, 0, "DELETE");
+
+ /* retrieve reply */
+ int ret;
+ do
+ {
+ Sleep(55);
+ ret = http->run();
+ if (ret == -1) // connection failed
+ break;
+
+ // ---- check our reply code ----
+ int status = http->get_status();
+ switch (status)
+ {
+ case HTTPRECEIVER_STATUS_CONNECTING:
+ case HTTPRECEIVER_STATUS_READING_HEADERS:
+ break;
+
+ case HTTPRECEIVER_STATUS_READING_CONTENT:
+ {
+ sf->releaseInterface(http);
+ return 0;
+ }
+ break;
+ case HTTPRECEIVER_STATUS_ERROR:
+ default:
+ sf->releaseInterface(http);
+ return 1;
+ }
+ }
+ while (ret == HTTPRECEIVER_RUN_OK);
+
+ sf->releaseInterface(http);
+ return 1;
+}
+
diff --git a/Src/Plugins/Portable/pmp_wifi/resource.h b/Src/Plugins/Portable/pmp_wifi/resource.h
new file mode 100644
index 00000000..dadd58d0
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resource.h
@@ -0,0 +1,65 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by pmp_wifi.rc
+//
+#define IDB_GENERIC_16 101
+#define IDB_PNG2 102
+#define IDB_HTC_DESIRE_16 102
+#define IDB_PNG3 103
+#define IDB_EVO16 103
+#define IDB_EVO_16 103
+#define IDB_PNG5 105
+#define IDB_NEXUSONE_16 105
+#define IDB_PNG6 106
+#define IDB_DROID_16 106
+#define IDB_GENERIC_160 107
+#define IDB_PNG7 108
+#define IDB_HTC_DESIRE_160 108
+#define IDB_PNG8 109
+#define IDB_EVO_160 109
+#define IDB_PNG10 111
+#define IDB_DROID_160 111
+#define IDB_PNG1 112
+#define IDB_WIFI 112
+#define IDB_ATTACH 113
+#define IDB_PNG11 114
+#define IDB_ATTACH_16 114
+#define IDB_PNG4 115
+#define IDB_INCREDIBLE_160 115
+#define IDB_INCREDIBLE_16 116
+#define IDB_NEXUSONE_160 117
+#define IDS_ACTIVITY_CONNECT 118
+#define IDS_ACTIVITY_CONNECT_DESC 119
+#define IDS_DEVICE_CONNECTION_WIFI 120
+#define IDS_DEVICE_CMD_ATTACH 121
+#define IDS_DEVICE_CMD_ATTACH_DESC 122
+#define IDS_DEVICE_MODEL_HTC_EVO 123
+#define IDS_DEVICE_MODEL_HTC_INCREDIBLE 124
+#define IDS_DEVICE_MODEL_HTC_NEXUS_ONE 125
+#define IDS_DEVICE_MODEL_MOTOROLA_DROID2 126
+#define IDS_DEVICE_MODEL_MOTOROLA_DROIDX 127
+#define IDS_DEVICE_MODEL_MOTOROLA_DROID 128
+#define IDS_DEVICE_MODEL_HTC_DESIRE 129
+#define IDS_DEVICE_MODEL_SAMSUNG_GALAXY_S 130
+#define IDB_DROIDX_160 130
+#define IDS_DEVICE_MODEL_MOTOROLA_MILESTONE 131
+#define IDB_PNG12 131
+#define IDB_DROIDX_16 131
+#define IDS_DEVICE_MODEL_HTC_WILDFIRE 132
+#define IDS_DEVICE_MODEL_HTC_HERO 133
+#define IDS_CONNECTING 134
+#define IDS_UPLOADING 135
+#define IDS_COMPLETED 136
+#define IDS_DEVICE_MODEL_MOTOROLA_DROIDX2 137
+#define IDS_NULLSOFT_WIFI_DEVICE_PLUGIN 65534
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 139
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/attach.png b/Src/Plugins/Portable/pmp_wifi/resources/attach.png
new file mode 100644
index 00000000..bb645908
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/attach.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/attach16.png b/Src/Plugins/Portable/pmp_wifi/resources/attach16.png
new file mode 100644
index 00000000..64f2e081
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/attach16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/generic_android.png b/Src/Plugins/Portable/pmp_wifi/resources/generic_android.png
new file mode 100644
index 00000000..bafdb3ce
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/generic_android.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/generic_drive_wifi_16.png b/Src/Plugins/Portable/pmp_wifi/resources/generic_drive_wifi_16.png
new file mode 100644
index 00000000..68f46c81
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/generic_drive_wifi_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/htc_desire_passion_bravo.png b/Src/Plugins/Portable/pmp_wifi/resources/htc_desire_passion_bravo.png
new file mode 100644
index 00000000..6125b39a
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/htc_desire_passion_bravo.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/htc_desire_passion_bravo_16.png b/Src/Plugins/Portable/pmp_wifi/resources/htc_desire_passion_bravo_16.png
new file mode 100644
index 00000000..58ed7340
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/htc_desire_passion_bravo_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/htc_evo_4g.png b/Src/Plugins/Portable/pmp_wifi/resources/htc_evo_4g.png
new file mode 100644
index 00000000..511c24fe
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/htc_evo_4g.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/htc_evo_4g_16.png b/Src/Plugins/Portable/pmp_wifi/resources/htc_evo_4g_16.png
new file mode 100644
index 00000000..d3f5c451
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/htc_evo_4g_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/htc_hd2.png b/Src/Plugins/Portable/pmp_wifi/resources/htc_hd2.png
new file mode 100644
index 00000000..fd1fb50d
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/htc_hd2.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/htc_hd2_16.png b/Src/Plugins/Portable/pmp_wifi/resources/htc_hd2_16.png
new file mode 100644
index 00000000..3b30603f
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/htc_hd2_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/htc_incredible.png b/Src/Plugins/Portable/pmp_wifi/resources/htc_incredible.png
new file mode 100644
index 00000000..dbe2ed94
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/htc_incredible.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/htc_incredible_16.png b/Src/Plugins/Portable/pmp_wifi/resources/htc_incredible_16.png
new file mode 100644
index 00000000..394ada27
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/htc_incredible_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/htc_nexus_one_16.png b/Src/Plugins/Portable/pmp_wifi/resources/htc_nexus_one_16.png
new file mode 100644
index 00000000..04728360
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/htc_nexus_one_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/motorola_droid.png b/Src/Plugins/Portable/pmp_wifi/resources/motorola_droid.png
new file mode 100644
index 00000000..14a90e8c
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/motorola_droid.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/motorola_droid_16.png b/Src/Plugins/Portable/pmp_wifi/resources/motorola_droid_16.png
new file mode 100644
index 00000000..87bbd832
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/motorola_droid_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/motorola_droid_x.png b/Src/Plugins/Portable/pmp_wifi/resources/motorola_droid_x.png
new file mode 100644
index 00000000..bc1d71c7
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/motorola_droid_x.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/motorola_droid_x_16.png b/Src/Plugins/Portable/pmp_wifi/resources/motorola_droid_x_16.png
new file mode 100644
index 00000000..6febb3d2
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/motorola_droid_x_16.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/nexus_one.png b/Src/Plugins/Portable/pmp_wifi/resources/nexus_one.png
new file mode 100644
index 00000000..439542c1
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/nexus_one.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/resources/wifi.png b/Src/Plugins/Portable/pmp_wifi/resources/wifi.png
new file mode 100644
index 00000000..682ced55
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/resources/wifi.png
Binary files differ
diff --git a/Src/Plugins/Portable/pmp_wifi/version.rc2 b/Src/Plugins/Portable/pmp_wifi/version.rc2
new file mode 100644
index 00000000..aaf33d2e
--- /dev/null
+++ b/Src/Plugins/Portable/pmp_wifi/version.rc2
@@ -0,0 +1,39 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#include "../../../Winamp/buildType.h"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,56,0,0
+ PRODUCTVERSION WINAMP_PRODUCTVER
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Winamp SA"
+ VALUE "FileDescription", "Winamp Portable Device Plug-in"
+ VALUE "FileVersion", "1,56,0,0"
+ VALUE "InternalName", "Nullsoft Wi-Fi Device"
+ VALUE "LegalCopyright", "Copyright © 2010-2023 Winamp SA"
+ VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
+ VALUE "OriginalFilename", "pmp_wifi.dll"
+ VALUE "ProductName", "Winamp"
+ VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END