1
0

main.cpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273
  1. #include "Main.h"
  2. #include "ReplayGain.h"
  3. #include "../nu/AutoChar.h"
  4. #include "../nu/MediaLibraryInterface.h"
  5. #include "./resource.h"
  6. #include "./settings.h"
  7. #include "./copyfiles.h"
  8. #include "../winamp/wa_ipc.h"
  9. //#include <primosdk.h>
  10. #include <shlwapi.h>
  11. #include <imapi.h>
  12. #include <imapierror.h>
  13. #include "../nu/ns_wc.h"
  14. #include <vector>
  15. #include <strsafe.h>
  16. #define VERSION_MAJOR 2
  17. #define VERSION_MINOR 0
  18. #ifndef ARRAYSIZE
  19. #define ARRAYSIZE(x) (sizeof(x)/sizeof(*x))
  20. #endif
  21. typedef struct _LISTENER
  22. {
  23. HWND hwnd;
  24. UINT uMsg;
  25. CHAR cLetter;
  26. } LISTENER;
  27. typedef struct _NAVITEMENUMPARAM
  28. {
  29. NAVITEMENUMPROC callback;
  30. LPARAM param;
  31. } NAVITEMENUMPARAM;
  32. typedef enum _BTNSTATE
  33. {
  34. BTNSTATE_NORMAL = 0,
  35. BTNSTATE_HILITED = 1,
  36. BTNSTATE_PRESSED = 2,
  37. BTNSTATE_DISABLED = 3,
  38. } BTNSTATE;
  39. #define ICON_SIZE_CX 14
  40. #define ICON_SIZE_CY 14
  41. #define NAVBUTTON_STATECHECK_DELAY 100
  42. static int Init();
  43. static void Quit();
  44. HNAVITEM hniMain = NULL;
  45. static LRESULT delay_ml_startup;
  46. static HMLIMGLST hmlilIcons = NULL;
  47. LARGE_INTEGER freq;
  48. #define NAVITEM_PREFIX L"_ml_disc_"
  49. #define NAVITEM_PREFIX_SIZE (sizeof(NAVITEM_PREFIX)/sizeof(wchar_t))
  50. #define NCS_EX_SHOWEJECT 0x0100
  51. C_Config *g_config, *g_view_metaconf = NULL;
  52. HMENU g_context_menus;
  53. prefsDlgRecW myPrefsItemCD = {0};
  54. INT_PTR imgIndex = 0;
  55. wchar_t randb[64] = {0};
  56. static wchar_t cdrip[64];
  57. static DWORD g_navStyle = NCS_FULLROWSELECT | NCS_SHOWICONS;
  58. static DWORD riphash = 0;
  59. static std::vector<LPARAM> driveList;
  60. static LISTENER activeListener = { NULL, 0, };
  61. static WNDPROC oldWinampWndProc = NULL;
  62. api_application *WASABI_API_APP = 0;
  63. api_stats *AGAVE_API_STATS = 0;
  64. // wasabi based services for localisation support
  65. api_language *WASABI_API_LNG = 0;
  66. HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
  67. static UINT uMsgBurnerNotify = 0;
  68. static UINT uMsgRipperNotify = 0;
  69. static UINT uMsgNavStyleUpdate = 0;
  70. static UINT uMsgCopyNotify = 0;
  71. static void CALLBACK Invoke_OnDriveManagerNotify(WORD wCode, INT_PTR param);
  72. static void Plugin_OnMLVisible(BOOL bVisible);
  73. void ShowHideRipBurnParent(void);
  74. static void DriveParam_RegisterDrive(DRIVE *drive)
  75. {
  76. LPARAM param;
  77. size_t index;
  78. param = (LPARAM)drive;
  79. if (NULL == param)
  80. return;
  81. index = driveList.size();
  82. while(index--)
  83. {
  84. if(param == driveList[index])
  85. return;
  86. }
  87. driveList.push_back(param);
  88. }
  89. static void DriveParam_UnregisterDrive(DRIVE *drive)
  90. {
  91. LPARAM param;
  92. size_t index;
  93. param = (LPARAM)drive;
  94. if (NULL == param)
  95. return;
  96. index = driveList.size();
  97. while(index--)
  98. {
  99. if(param == driveList[index])
  100. {
  101. driveList.erase(driveList.begin() + index);
  102. return;
  103. }
  104. }
  105. }
  106. static BOOL DriveParam_IsValid(LPARAM param)
  107. {
  108. if (param > 0x0000FFFF)
  109. {
  110. size_t index = driveList.size();
  111. while(index--)
  112. {
  113. if(param == driveList[index])
  114. return TRUE;
  115. }
  116. }
  117. return FALSE;
  118. }
  119. DRIVE *Plugin_GetDriveFromNavItem(HNAVITEM hItem)
  120. {
  121. NAVITEM item;
  122. if (!hItem) return NULL;
  123. item.cbSize = sizeof(NAVITEM);
  124. item.mask = NIMF_PARAM;
  125. item.hItem = hItem;
  126. return (MLNavItem_GetInfo(plugin.hwndLibraryParent, &item) && DriveParam_IsValid(item.lParam)) ?
  127. (DRIVE*)item.lParam : NULL;
  128. }
  129. HNAVITEM Plugin_GetNavItemFromLetter(CHAR cLetter)
  130. {
  131. NAVCTRLFINDPARAMS fp = {0};
  132. wchar_t invariant[32] = {0};
  133. if (S_OK == StringCchPrintfW(invariant, sizeof(invariant)/sizeof(wchar_t), L"%s%c", NAVITEM_PREFIX, cLetter))
  134. {
  135. fp.cchLength = -1;
  136. fp.pszName = invariant;
  137. fp.compFlags = NICF_INVARIANT;
  138. return MLNavCtrl_FindItemByName(plugin.hwndLibraryParent, &fp);
  139. }
  140. return NULL;
  141. }
  142. static BOOL CALLBACK EnumerateNavItemsCB(HNAVITEM hItem, LPARAM param)
  143. {
  144. DRIVE *pDrive = Plugin_GetDriveFromNavItem(hItem);
  145. return (pDrive) ? ((NAVITEMENUMPARAM*)param)->callback(hItem, pDrive, ((NAVITEMENUMPARAM*)param)->param) : TRUE;
  146. }
  147. BOOL Plugin_EnumerateNavItems(NAVITEMENUMPROC callback, LPARAM param)
  148. {
  149. NAVITEMENUMPARAM pluginenum;
  150. NAVCTRLENUMPARAMS navenum;
  151. if (!callback) return FALSE;
  152. pluginenum.callback = callback;
  153. pluginenum.param = param;
  154. navenum.hItemStart = hniMain;
  155. navenum.lParam = (LPARAM)&pluginenum;
  156. navenum.enumProc = EnumerateNavItemsCB;
  157. return MLNavCtrl_EnumItems(plugin.hwndLibraryParent, &navenum);
  158. }
  159. void Plugin_RegisterListener(HWND hwnd, UINT uMsg, CHAR cLetter)
  160. {
  161. activeListener.hwnd = hwnd;
  162. activeListener.uMsg = uMsg;
  163. activeListener.cLetter = cLetter;
  164. }
  165. void Plugin_UnregisterListener(HWND hwnd)
  166. {
  167. ZeroMemory(&activeListener, sizeof(LISTENER));
  168. }
  169. static BOOL CALLBACK EnumNavItems_OnUIChangeCB(HNAVITEM hItem, DRIVE *pDrive, LPARAM param)
  170. {
  171. if (pDrive) pDrive->textSize = 0;
  172. return TRUE;
  173. }
  174. static void UpdatedNavStyles(void)
  175. {
  176. g_navStyle = MLNavCtrl_GetStyle(plugin.hwndLibraryParent);
  177. if (0 != g_view_metaconf->ReadInt(TEXT("showeject"), 1)) g_navStyle |= NCS_EX_SHOWEJECT;
  178. }
  179. static BOOL CALLBACK EnumerateNavItemsRemoveCB(HNAVITEM hItem, DRIVE *pDrive, LPARAM param)
  180. {
  181. if(pDrive)
  182. {
  183. MLNavCtrl_DeleteItem(plugin.hwndLibraryParent,hItem);
  184. Plugin_EnumerateNavItems(EnumerateNavItemsRemoveCB, 0);
  185. }
  186. return TRUE;
  187. }
  188. static BOOL Plugin_QueryOkToQuit()
  189. {
  190. CHAR szLetters[24] = {0};
  191. INT c = DriveManager_GetDriveList(szLetters, ARRAYSIZE(szLetters));
  192. while(c-- > 0)
  193. {
  194. INT msgId;
  195. if (cdrip_isextracting(szLetters[c])) msgId = IDS_YOU_ARE_CURRENTLY_RIPPING_AUDIO_CD_MUST_CANCEL_TO_CLOSE_WINAMP;
  196. else if (MLDisc_IsDiscCopying(szLetters[c])) msgId = IDS_YOU_ARE_CURRENTLY_COPYING_DATA_CD_MUST_CANCEL_TO_CLOSE_WINAMP;
  197. else msgId = 0;
  198. if (msgId)
  199. {
  200. wchar_t buffer[512] = {0};
  201. StringCchPrintfW(buffer, 512, WASABI_API_LNGSTRINGW(msgId), szLetters[c]);
  202. MessageBoxW(plugin.hwndWinampParent, buffer, WASABI_API_LNGSTRINGW(IDS_NOTIFICATION),
  203. MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
  204. return FALSE;
  205. }
  206. }
  207. return TRUE;
  208. }
  209. LRESULT CALLBACK WinampWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  210. {
  211. if(uMsgNavStyleUpdate == uMsg)
  212. {
  213. if(!wParam)
  214. {
  215. UpdatedNavStyles();
  216. Plugin_EnumerateNavItems(EnumNavItems_OnUIChangeCB, 0);
  217. }
  218. else
  219. {
  220. Plugin_EnumerateNavItems(EnumerateNavItemsRemoveCB, 0);
  221. ShowHideRipBurnParent();
  222. DriveManager_Uninitialize(0);
  223. DriveManager_Initialize(Invoke_OnDriveManagerNotify, TRUE);
  224. Plugin_OnMLVisible((BOOL)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_IS_VISIBLE, 0));
  225. }
  226. }
  227. else if (uMsgBurnerNotify == uMsg) // burner broadcast message LOWORD(wParam) = drive letter, lParam = (BOOL)bStarted. if bStarted = TRUE - burning started, otherwise burning finished
  228. {
  229. if (0 == HIWORD(wParam))
  230. {
  231. DriveManager_SetDriveMode((CHAR)LOWORD(wParam), (0 != lParam) ? DM_MODE_BURNING : DM_MODE_READY);
  232. }
  233. }
  234. else if (uMsgRipperNotify == uMsg)
  235. {
  236. if (HIWORD(wParam)) // another instance of winamp quering
  237. {
  238. if (LOWORD(wParam) && cdrip_isextracting((CHAR)LOWORD(wParam))) SendNotifyMessage((HWND)lParam, uMsgRipperNotify, LOWORD(wParam), (LPARAM)TRUE);
  239. else
  240. {
  241. CHAR cLetter;
  242. cLetter = (CHAR)cdrip_isextracting(-1);
  243. if (cLetter) SendNotifyMessage((HWND)lParam, uMsgRipperNotify, cLetter, (LPARAM)TRUE);
  244. }
  245. }
  246. else
  247. {
  248. DriveManager_SetDriveMode((CHAR)LOWORD(wParam), (0 != lParam) ? DM_MODE_RIPPING : DM_MODE_READY);
  249. }
  250. }
  251. else if (uMsgCopyNotify == uMsg)
  252. {
  253. if (HIWORD(wParam))
  254. {
  255. if (LOWORD(wParam) && MLDisc_IsDiscCopying((CHAR)LOWORD(wParam))) SendNotifyMessage((HWND)lParam, uMsgCopyNotify, LOWORD(wParam), (LPARAM)TRUE);
  256. else
  257. {
  258. CHAR szLetters[24] = {0};
  259. INT c = DriveManager_GetDriveList(szLetters, ARRAYSIZE(szLetters));
  260. while(c-- > 0)
  261. {
  262. if (MLDisc_IsDiscCopying(szLetters[c]))
  263. SendNotifyMessage((HWND)lParam, uMsgCopyNotify, szLetters[c], (LPARAM)TRUE);
  264. }
  265. }
  266. }
  267. else
  268. {
  269. DriveManager_SetDriveMode((CHAR)LOWORD(wParam), (0 != lParam) ? DM_MODE_COPYING : DM_MODE_READY);
  270. }
  271. }
  272. else if (WM_WA_IPC == uMsg)
  273. {
  274. switch(lParam)
  275. {
  276. case IPC_SKIN_CHANGED:
  277. case IPC_CB_RESETFONT:
  278. UpdatedNavStyles();
  279. Plugin_EnumerateNavItems(EnumNavItems_OnUIChangeCB, 0);
  280. break;
  281. case IPC_FILE_TAG_MAY_HAVE_UPDATED:
  282. case IPC_FILE_TAG_MAY_HAVE_UPDATEDW:
  283. if (activeListener.hwnd) SendMessageW(activeListener.hwnd, activeListener.uMsg, (WPARAM)lParam, (LPARAM)wParam);
  284. break;
  285. }
  286. if(lParam == delay_ml_startup)
  287. {
  288. if(!wParam)
  289. {
  290. PostMessage(plugin.hwndWinampParent, WM_WA_IPC, 1, delay_ml_startup);
  291. }
  292. else if(wParam == 1)
  293. {
  294. // TODO: benski> temp-hack fix for now -- if (SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_IS_VISIBLE, 0))
  295. {
  296. DriveManager_Initialize(Invoke_OnDriveManagerNotify, TRUE);
  297. MLDisc_InitializeCopyData();
  298. DriveManager_Resume(TRUE);
  299. SendNotifyMessage(HWND_BROADCAST, uMsgBurnerNotify, MAKEWPARAM(0, 0xffff), (LPARAM)plugin.hwndWinampParent);
  300. SendNotifyMessage(HWND_BROADCAST, uMsgRipperNotify, MAKEWPARAM(0, 0xffff), (LPARAM)plugin.hwndWinampParent);
  301. SendNotifyMessage(HWND_BROADCAST, uMsgCopyNotify, MAKEWPARAM(0, 0xffff), (LPARAM)plugin.hwndWinampParent);
  302. }
  303. }
  304. }
  305. }
  306. return (oldWinampWndProc) ? CallWindowProcW(oldWinampWndProc, hwnd, uMsg, wParam, lParam) : DefWindowProc(hwnd, uMsg, wParam, lParam);
  307. }
  308. static DM_UNITINFO2_PARAM unitinfo;
  309. static char szDesc[1024];
  310. static DWORD szTypes[64];
  311. static void CALLBACK FreeParam(DM_NOTIFY_PARAM *phdr)
  312. {
  313. if (!phdr) return;
  314. switch(phdr->opCode)
  315. {
  316. case DMOP_TITLE:
  317. if (((DM_TITLE_PARAM*)phdr)->pszTitle) free(((DM_TITLE_PARAM*)phdr)->pszTitle);
  318. break;
  319. }
  320. free(phdr);
  321. }
  322. static void RegisterIcons()
  323. {
  324. MLIMAGELISTCREATE mlilCreate;
  325. MLIMAGESOURCE mlis;
  326. MLIMAGELISTITEM mlilItem;
  327. if (hmlilIcons) return;
  328. mlilCreate.cx = ICON_SIZE_CX;
  329. mlilCreate.cy = ICON_SIZE_CY;
  330. mlilCreate.cInitial = 5;
  331. mlilCreate.cGrow = 1;
  332. mlilCreate.cCacheSize = 3;
  333. mlilCreate.flags = MLILC_COLOR24;
  334. hmlilIcons = MLImageList_Create(plugin.hwndLibraryParent, &mlilCreate);
  335. if (!hmlilIcons) return;
  336. ZeroMemory(&mlilItem, sizeof(MLIMAGELISTITEM));
  337. mlilItem.cbSize = sizeof(MLIMAGELISTITEM);
  338. mlilItem.hmlil = hmlilIcons;
  339. mlilItem.filterUID = MLIF_FILTER1_UID;
  340. mlilItem.pmlImgSource = &mlis;
  341. ZeroMemory(&mlis, sizeof(MLIMAGESOURCE));
  342. mlis.cbSize = sizeof(MLIMAGESOURCE);
  343. mlis.type = SRC_TYPE_PNG;
  344. mlis.hInst = plugin.hDllInstance;
  345. mlis.lpszName = MAKEINTRESOURCEW(IDB_NAVITEM_CDROM);
  346. MLImageList_Add(plugin.hwndLibraryParent, &mlilItem);
  347. mlis.lpszName = MAKEINTRESOURCEW(IDB_EJECT_NORMAL);
  348. MLImageList_Add(plugin.hwndLibraryParent, &mlilItem);
  349. mlis.lpszName = MAKEINTRESOURCEW(IDB_EJECT_HILITED);
  350. MLImageList_Add(plugin.hwndLibraryParent, &mlilItem);
  351. mlis.lpszName = MAKEINTRESOURCEW(IDB_EJECT_PRESSED);
  352. MLImageList_Add(plugin.hwndLibraryParent, &mlilItem);
  353. mlis.lpszName = MAKEINTRESOURCEW(IDB_EJECT_DISABLED);
  354. MLImageList_Add(plugin.hwndLibraryParent, &mlilItem);
  355. }
  356. static BOOL UpdateTitle(CHAR cLetter, LPCWSTR pszTitle)
  357. {
  358. HNAVITEM hItem;
  359. NAVITEM item;
  360. DRIVE *pDrive;
  361. hItem = Plugin_GetNavItemFromLetter(cLetter);
  362. if (!hItem) return FALSE;
  363. pDrive = Plugin_GetDriveFromNavItem(hItem);
  364. if (!pDrive) return FALSE;
  365. if (S_OK != StringCchCopyW(pDrive->szTitle, sizeof(pDrive->szTitle)/sizeof(wchar_t), (pszTitle) ? pszTitle : L"")) return FALSE;
  366. pDrive->textSize = 0;
  367. item.cbSize = sizeof(NAVITEM);
  368. item.mask = NIMF_TEXT;
  369. item.hItem = hItem;
  370. item.pszText = pDrive->szTitle;
  371. return MLNavItem_SetInfo(plugin.hwndLibraryParent, &item);
  372. }
  373. static void QueryTitle(CHAR cLetter)
  374. {
  375. DM_TITLE_PARAM *pdtp;
  376. pdtp = (DM_TITLE_PARAM*)calloc(4, sizeof(DM_TITLE_PARAM));
  377. if (pdtp)
  378. {
  379. pdtp->header.callback = (INT_PTR)Invoke_OnDriveManagerNotify;
  380. pdtp->header.cLetter = cLetter;
  381. pdtp->header.uMsg = NULL;
  382. pdtp->header.fnFree = FreeParam;
  383. pdtp->cchTitle = 256;
  384. pdtp->pszTitle = (wchar_t*)calloc(pdtp->cchTitle, sizeof(wchar_t));
  385. DriveManager_QueryTitle(pdtp);
  386. }
  387. }
  388. static void Drive_OnAdded(CHAR cLetter)
  389. {
  390. wchar_t szInvariant[32] = {0};
  391. DRIVE *pDrive;
  392. NAVINSERTSTRUCT nis = {0};
  393. wchar_t szDriveType[32] = {0}, szDriveCap[64] = {0};
  394. pDrive = (DRIVE*)calloc(1, sizeof(DRIVE));
  395. if (!pDrive) return;
  396. StringCchPrintfW(szInvariant, sizeof(szInvariant)/sizeof(wchar_t), L"%s%c", NAVITEM_PREFIX, cLetter);
  397. pDrive->cLetter = cLetter;
  398. pDrive->cMode = DriveManager_GetDriveMode(cLetter);
  399. WASABI_API_LNGSTRINGW_BUF(IDS_CD, szDriveType, sizeof(szDriveType)/sizeof(wchar_t));
  400. WASABI_API_LNGSTRINGW_BUF(IDS_DRIVE_CAP, szDriveCap, sizeof(szDriveCap)/sizeof(wchar_t));
  401. StringCchPrintfW(pDrive->szTitle, sizeof(pDrive->szTitle)/sizeof(wchar_t), L"%s %s (%C:)", szDriveType, szDriveCap, (WCHAR)cLetter);
  402. if (NULL == hmlilIcons) RegisterIcons();
  403. ZeroMemory(&nis, sizeof(NAVINSERTSTRUCT));
  404. nis.hParent = hniMain;
  405. nis.item.cbSize = sizeof(NAVITEM);
  406. nis.item.pszText = pDrive->szTitle;
  407. nis.item.pszInvariant = szInvariant;
  408. nis.item.mask = NIMF_TEXT | NIMF_TEXTINVARIANT | NIMF_PARAM | NIMF_STYLE;
  409. nis.item.style = NIS_CUSTOMDRAW | NIS_WANTSETCURSOR | NIS_WANTHITTEST;
  410. nis.item.styleMask = nis.item.style;
  411. nis.item.lParam = (LPARAM)pDrive;
  412. if (NULL != MLNavCtrl_InsertItem(plugin.hwndLibraryParent, &nis))
  413. {
  414. DriveParam_RegisterDrive(pDrive);
  415. }
  416. }
  417. static void Drive_OnChanged(CHAR cLetter)
  418. {
  419. QueryTitle(cLetter);
  420. }
  421. static void Drive_OnRemoved(CHAR cLetter)
  422. {
  423. HNAVITEM hItem;
  424. hItem = Plugin_GetNavItemFromLetter(cLetter);
  425. if (hItem) MLNavCtrl_DeleteItem(plugin.hwndLibraryParent, hItem);
  426. if (riphash && (0xFF & (riphash >> 24)) == (UCHAR)cLetter) riphash = 0;
  427. }
  428. static void Drive_OnModeChanged(CHAR cLetter, CHAR cMode)
  429. {
  430. HNAVITEM hItem;
  431. DRIVE *pDrive;
  432. hItem = Plugin_GetNavItemFromLetter(cLetter);
  433. if (!hItem) return;
  434. pDrive = Plugin_GetDriveFromNavItem(hItem);
  435. if (pDrive)
  436. {
  437. NAVITEMINAVLIDATE inv;
  438. pDrive->cMode = cMode;
  439. inv.fErase = FALSE;
  440. inv.hItem = hItem;
  441. inv.prc = NULL;
  442. MLNavItem_Invalidate(plugin.hwndLibraryParent, &inv);
  443. }
  444. }
  445. static void Medium_OnAdded(CHAR cLetter)
  446. {
  447. if (riphash && (0xFF & (riphash >> 24)) == (UCHAR)cLetter) riphash = 0;
  448. QueryTitle(cLetter);
  449. }
  450. static void Medium_OnRemoved(CHAR cLetter)
  451. {
  452. if (riphash && (0xFF & (riphash >> 24)) == (UCHAR)cLetter) riphash = 0;
  453. QueryTitle(cLetter);
  454. }
  455. static void OnDriveMangerOpCompleted(DM_NOTIFY_PARAM *phdr)
  456. {
  457. switch(phdr->opCode)
  458. {
  459. case DMOP_TITLE:
  460. if (S_OK == phdr->result) UpdateTitle(phdr->cLetter, ((DM_TITLE_PARAM*)phdr)->pszTitle);
  461. break;
  462. }
  463. }
  464. static void CALLBACK OnDriveManagerNotify(ULONG_PTR param)
  465. {
  466. WORD code;
  467. CHAR cLetter;
  468. code = LOWORD(param);
  469. cLetter = (CHAR)(0xFF & HIWORD(param));
  470. switch(code)
  471. {
  472. case DMW_DRIVEADDED: Drive_OnAdded(cLetter); break;
  473. case DMW_DRIVEREMOVED: Drive_OnRemoved(cLetter); break;
  474. case DMW_DRIVECHANGED: Drive_OnChanged(cLetter); break;
  475. case DMW_MEDIUMARRIVED: Medium_OnAdded(cLetter); break;
  476. case DMW_MEDIUMREMOVED: Medium_OnRemoved(cLetter); break;
  477. case DMW_MODECHANGED: Drive_OnModeChanged(cLetter, ((CHAR)(HIWORD(param)>>8))); break;
  478. }
  479. if (activeListener.hwnd && (0 == activeListener.cLetter || cLetter == activeListener.cLetter))
  480. PostMessageW(activeListener.hwnd, activeListener.uMsg, (WPARAM)code, (LPARAM)HIWORD(param));
  481. }
  482. static void CALLBACK Invoke_OnDriveManagerNotify(WORD wCode, INT_PTR param)
  483. {
  484. switch(wCode)
  485. {
  486. case DMW_DRIVEADDED:
  487. case DMW_DRIVEREMOVED:
  488. case DMW_DRIVECHANGED:
  489. case DMW_MEDIUMARRIVED:
  490. case DMW_MEDIUMREMOVED:
  491. case DMW_MODECHANGED:
  492. if (GetCurrentThreadId() != GetWindowThreadProcessId(plugin.hwndLibraryParent, NULL))
  493. {
  494. HANDLE htWA = (WASABI_API_APP) ? WASABI_API_APP->main_getMainThreadHandle() : NULL;
  495. if (htWA)
  496. {
  497. QueueUserAPC(OnDriveManagerNotify, htWA, MAKELONG(wCode, (WORD)(param)));
  498. CloseHandle(htWA);
  499. }
  500. }
  501. else OnDriveManagerNotify(MAKELONG(wCode, (WORD)(param)));
  502. break;
  503. case DMW_OPCOMPLETED: OnDriveMangerOpCompleted((DM_NOTIFY_PARAM*)param); break;
  504. }
  505. }
  506. void ShowHideRipBurnParent(void)
  507. {
  508. BOOL bVal;
  509. if (S_OK == Settings_GetBool(C_GLOBAL, GF_SHOWPARENT, &bVal) && bVal)
  510. {
  511. if(!hniMain)
  512. {
  513. NAVINSERTSTRUCT nis;
  514. ZeroMemory(&nis, sizeof(NAVITEM));
  515. nis.item.cbSize = sizeof(NAVITEM);
  516. nis.item.pszText = WASABI_API_LNGSTRINGW_BUF(IDS_RIP_AND_BURN, randb,64);
  517. nis.item.pszInvariant = NAVITEM_PREFIX L"main";
  518. nis.item.mask = NIMF_TEXT | NIMF_STYLE | NIMF_TEXTINVARIANT | NIMF_PARAM;
  519. nis.item.style = NIS_HASCHILDREN;
  520. nis.item.styleMask = nis.item.style;
  521. nis.item.lParam = 0L;
  522. hniMain = MLNavCtrl_InsertItem(plugin.hwndLibraryParent, &nis);
  523. }
  524. }
  525. else
  526. {
  527. if(hniMain)
  528. {
  529. MLNavCtrl_DeleteItem(plugin.hwndLibraryParent,hniMain);
  530. }
  531. hniMain = NULL;
  532. }
  533. }
  534. int Init()
  535. {
  536. QueryPerformanceFrequency(&freq);
  537. // get the Application service
  538. waServiceFactory *sf = plugin.service->service_getServiceByGuid(applicationApiServiceGuid);
  539. if (sf) WASABI_API_APP = (api_application *)sf->getInterface();
  540. // loader so that we can get the localisation service api for use
  541. sf = plugin.service->service_getServiceByGuid(languageApiGUID);
  542. if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
  543. sf = plugin.service->service_getServiceByGuid(AnonymousStatsGUID);
  544. if (sf) AGAVE_API_STATS = reinterpret_cast<api_stats*>(sf->getInterface());
  545. // need to have this initialised before we try to do anything with localisation features
  546. WASABI_API_START_LANG(plugin.hDllInstance,MlDiscLangGUID);
  547. mediaLibrary.library = plugin.hwndLibraryParent;
  548. mediaLibrary.winamp = plugin.hwndWinampParent;
  549. mediaLibrary.instance = plugin.hDllInstance;
  550. static wchar_t szDescription[256];
  551. StringCchPrintf(szDescription, ARRAYSIZE(szDescription),
  552. WASABI_API_LNGSTRINGW(IDS_NULLSOFT_RIP_AND_BURN), VERSION_MAJOR, VERSION_MINOR);
  553. plugin.description = (char*)szDescription;
  554. // add to Winamp preferences
  555. myPrefsItemCD.dlgID = IDD_PREFSCDRIPFR;
  556. myPrefsItemCD.name = WASABI_API_LNGSTRINGW_BUF(IDS_CD_RIPPING,cdrip,64);
  557. myPrefsItemCD.proc = (void*)CDRipPrefsProc;
  558. myPrefsItemCD.hInst = WASABI_API_LNG_HINST;
  559. myPrefsItemCD.where = 6; // media library
  560. SENDWAIPC(plugin.hwndWinampParent, IPC_ADD_PREFS_DLGW, (WPARAM)&myPrefsItemCD);
  561. wchar_t szIniFile[MAX_PATH],
  562. *INI_DIR = (wchar_t*)SENDWAIPC(plugin.hwndWinampParent, IPC_GETINIDIRECTORYW, 0);
  563. PathCombine(szIniFile, INI_DIR, TEXT("Plugins\\gen_ml.ini"));
  564. g_config = new C_Config(szIniFile);
  565. PathCombine(szIniFile, INI_DIR, TEXT("Plugins\\ml\\cdrom.vmd"));
  566. g_view_metaconf = new C_Config(szIniFile);
  567. g_context_menus = WASABI_API_LOADMENU(IDR_CONTEXTMENUS);
  568. oldWinampWndProc = (WNDPROC)(LONG_PTR)SetWindowLongPtrW(plugin.hwndWinampParent, GWLP_WNDPROC, (LONG)(LONG_PTR)WinampWndProc);
  569. if (!uMsgBurnerNotify) uMsgBurnerNotify = RegisterWindowMessageA("WABURNER_BROADCAST_MSG");
  570. if (!uMsgRipperNotify) uMsgRipperNotify = RegisterWindowMessageA("WARIPPER_BROADCAST_MSG");
  571. if (!uMsgCopyNotify) uMsgCopyNotify = RegisterWindowMessageA("WACOPY_BROADCAST_MSG");
  572. if (!uMsgNavStyleUpdate) uMsgNavStyleUpdate = RegisterWindowMessageW(L"ripburn_nav_update");
  573. UpdatedNavStyles();
  574. ShowHideRipBurnParent();
  575. delay_ml_startup = SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"ml_disc_delay", IPC_REGISTER_WINAMP_IPCMESSAGE);
  576. PostMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, delay_ml_startup);
  577. return ML_INIT_SUCCESS;
  578. }
  579. void Quit()
  580. {
  581. DriveManager_Uninitialize(4000); // allow to wait for 4 sec.
  582. MLDisc_ReleaseCopyData();
  583. delete(g_view_metaconf);
  584. g_view_metaconf = 0;
  585. delete(g_config);
  586. g_config = NULL;
  587. if (rgThread)
  588. {
  589. QueueUserAPC(QuitThread, rgThread, 0);
  590. WaitForSingleObject(rgThread, INFINITE);
  591. CloseHandle(rgThread);
  592. rgThread = 0;
  593. }
  594. waServiceFactory *sf = plugin.service->service_getServiceByGuid(AnonymousStatsGUID);
  595. if (sf) sf->releaseInterface(AGAVE_API_STATS);
  596. }
  597. int getFileInfo(const char *filename, const char *metadata, char *dest, int len)
  598. {
  599. dest[0] = 0;
  600. extendedFileInfoStruct efis = { filename, metadata, dest, len, };
  601. return (int)(INT_PTR)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM) & efis, IPC_GET_EXTENDED_FILE_INFO); //will return 1 if wa2 supports this IPC call
  602. }
  603. int getFileInfoW(const wchar_t *filename, const wchar_t *metadata, wchar_t *dest, int len)
  604. {
  605. if (dest && len)
  606. dest[0] = 0;
  607. extendedFileInfoStructW efis = { filename, metadata, dest, len, };
  608. return (int)(INT_PTR)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&efis, IPC_GET_EXTENDED_FILE_INFOW); //will return 1 if wa2 supports this IPC call
  609. }
  610. void Plugin_ShowRippingPreferences(void)
  611. {
  612. SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&myPrefsItemCD, IPC_OPENPREFSTOPAGE);
  613. }
  614. BOOL Plugin_IsExtractScheduled(CHAR cLetter)
  615. {
  616. BOOL result;
  617. if (riphash && (0xFF & (riphash >> 24)) == (UCHAR)cLetter)
  618. {
  619. DWORD mediumSN;
  620. char devname[] = "X:\\";
  621. devname[0] = cLetter;
  622. result = (GetVolumeInformationA(devname, NULL, 0, &mediumSN, NULL, NULL, NULL, 0) && (0x00FFFFFF & riphash) == mediumSN);
  623. riphash = 0;
  624. }
  625. else result = FALSE;
  626. return result;
  627. }
  628. static int Root_OnContextMenu(HNAVITEM hItem, HWND hHost, POINTS pts)
  629. {
  630. HMENU hMenu = GetSubMenu(g_context_menus, 7);
  631. if (!hMenu) return 0;
  632. POINT pt;
  633. POINTSTOPOINT(pt, pts);
  634. if (-1 == pt.x || -1 == pt.y)
  635. {
  636. NAVITEMGETRECT itemRect;
  637. itemRect.fItem = FALSE;
  638. itemRect.hItem = hItem;
  639. if (MLNavItem_GetRect(plugin.hwndLibraryParent, &itemRect))
  640. {
  641. MapWindowPoints(hHost, HWND_DESKTOP, (POINT*)&itemRect.rc, 2);
  642. pt.x = itemRect.rc.left + 2;
  643. pt.y = itemRect.rc.top + 2;
  644. }
  645. }
  646. int r = Menu_TrackPopup(plugin.hwndLibraryParent, hMenu,
  647. TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_NONOTIFY,
  648. pt.x, pt.y, hHost, NULL);
  649. switch (r)
  650. {
  651. case ID_NAVIGATION_PREFERENCES: Plugin_ShowRippingPreferences(); return 1;
  652. case ID_NAVIGATION_HELP: SENDWAIPC(plugin.hwndWinampParent, IPC_OPEN_URL, L"https://help.winamp.com/hc/articles/8111574760468-CD-Ripping-with-Winamp"); return 1;
  653. break;
  654. }
  655. return 0;
  656. }
  657. static int Plugin_OnContextMenu(HNAVITEM hItem, HWND hHost, POINTS pts, CHAR cLetter)
  658. {
  659. HMENU hMenu = GetSubMenu(g_context_menus, 2);
  660. if (!hMenu) return 0;
  661. MENUITEMINFO mii = { sizeof(MENUITEMINFO), };
  662. mii.fMask = MIIM_STATE;
  663. if (GetMenuItemInfo(hMenu, ID_CDROMMENU_EJECTCD, FALSE, &mii))
  664. {
  665. mii.fState &= ~(MFS_ENABLED | MFS_DISABLED);
  666. mii.fState |= ((DM_MODE_READY == DriveManager_GetDriveMode(cLetter)) ? MFS_ENABLED : MFS_DISABLED);
  667. SetMenuItemInfo(hMenu, ID_CDROMMENU_EJECTCD, FALSE, &mii);
  668. }
  669. POINT pt;
  670. POINTSTOPOINT(pt, pts);
  671. if (-1 == pt.x || -1 == pt.y)
  672. {
  673. NAVITEMGETRECT itemRect;
  674. itemRect.fItem = FALSE;
  675. itemRect.hItem = hItem;
  676. if (MLNavItem_GetRect(plugin.hwndLibraryParent, &itemRect))
  677. {
  678. MapWindowPoints(hHost, HWND_DESKTOP, (POINT*)&itemRect.rc, 2);
  679. pt.x = itemRect.rc.left + 2;
  680. pt.y = itemRect.rc.top + 2;
  681. }
  682. }
  683. int r = Menu_TrackPopup(plugin.hwndLibraryParent, hMenu,
  684. TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_NONOTIFY,
  685. pt.x, pt.y, hHost, NULL);
  686. switch (r)
  687. {
  688. case ID_CDROMMENU_EXTRACT_CONFIGURE: Plugin_ShowRippingPreferences(); return 1;
  689. case ID_CDROMMENU_EXTRACT_HELP: SENDWAIPC(plugin.hwndWinampParent, IPC_OPEN_URL, L"https://help.winamp.com/hc/articles/8111574760468-CD-Ripping-with-Winamp"); return 1;
  690. case ID_CDROMMENU_PLAYALL:
  691. case ID_CDROMMENU_ENQUEUEALL:
  692. {
  693. int enq = r == ID_CDROMMENU_ENQUEUEALL;
  694. itemRecordList obj = {0, };
  695. saveCDToItemRecordList(cLetter, &obj, NULL);
  696. mlSendToWinampStruct p;
  697. p.type = ML_TYPE_CDTRACKS;
  698. p.enqueue = enq | 2;
  699. p.data = &obj;
  700. SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_SENDTOWINAMP, (WPARAM)&p);
  701. freeRecordList(&obj);
  702. }
  703. break;
  704. case ID_CDROMMENU_EXTRACT_EXTRACTALL:
  705. riphash = 0;
  706. if (hItem)
  707. {
  708. if (hItem == MLNavCtrl_GetSelection(plugin.hwndLibraryParent))
  709. {
  710. HWND hwnd = (HWND)SENDMLIPC(plugin.hwndLibraryParent, ML_IPC_GETCURRENTVIEW, 0);
  711. if (hwnd && SendMessageW(hwnd, WM_EXTRACTDISC, cLetter, 0)) break;
  712. }
  713. char devname[] = "X:\\";
  714. devname[0] = cLetter;
  715. if (!GetVolumeInformationA(devname, NULL, 0, &riphash, NULL, NULL, NULL, 0)) riphash = 0;
  716. if (riphash) riphash = ((0x00FFFFFF & riphash) | (cLetter << 24));
  717. MLNavItem_Select(plugin.hwndLibraryParent, hItem);
  718. }
  719. break;
  720. case ID_CDROMMENU_EJECTCD:
  721. {
  722. CHAR cMode;
  723. cMode = DriveManager_GetDriveMode(cLetter);
  724. if (DM_MODE_READY != cMode)
  725. {
  726. wchar_t title[32] = {0};
  727. MessageBox(plugin.hwndLibraryParent,
  728. WASABI_API_LNGSTRINGW((DM_MODE_RIPPING == cMode) ? IDS_ERROR_CD_RIP_IN_PROGRESS : IDS_ERROR_CD_BURN_IN_PROGRESS),
  729. WASABI_API_LNGSTRINGW_BUF(IDS_CD_EJECT,title,32), 0);
  730. return FALSE;
  731. }
  732. else DriveManager_Eject(cLetter, DM_EJECT_REMOVE);
  733. }
  734. break;
  735. }
  736. Sleep(100);
  737. MSG msg;
  738. while (PeekMessageW(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); //eat return
  739. return 0;
  740. }
  741. static DWORD resumeTick = 0; // this is cheating
  742. static void Plugin_OnMLVisible(BOOL bVisible)
  743. {
  744. if (bVisible)
  745. {
  746. DriveManager_Resume(TRUE);
  747. resumeTick = GetTickCount();
  748. SendNotifyMessage(HWND_BROADCAST, uMsgBurnerNotify, MAKEWPARAM(0, 0xffff), (LPARAM)plugin.hwndWinampParent);
  749. SendNotifyMessage(HWND_BROADCAST, uMsgRipperNotify, MAKEWPARAM(0, 0xffff), (LPARAM)plugin.hwndWinampParent);
  750. SendNotifyMessage(HWND_BROADCAST, uMsgCopyNotify, MAKEWPARAM(0, 0xffff), (LPARAM)plugin.hwndWinampParent);
  751. return;
  752. }
  753. else DriveManager_Suspend();
  754. }
  755. static HWND Plugin_OnViewCreate(HNAVITEM hItem, HWND hwndParent)
  756. {
  757. if (hItem == hniMain)
  758. {
  759. return WASABI_API_CREATEDIALOGW(IDD_VIEW_RIPBURN, hwndParent, view_ripburnDialogProc);
  760. }
  761. else
  762. {
  763. DRIVE *pDrive = Plugin_GetDriveFromNavItem(hItem);
  764. if (pDrive) return CreateContainerWindow(hwndParent, pDrive->cLetter, ((GetTickCount() - resumeTick) > 100));
  765. resumeTick = 0;
  766. }
  767. return NULL;
  768. }
  769. static BOOL Plugin_OnNavItemDelete(HNAVITEM hItem)
  770. {
  771. DRIVE *pDrive = Plugin_GetDriveFromNavItem(hItem);
  772. if (!pDrive) return FALSE;
  773. DriveParam_UnregisterDrive(pDrive);
  774. free(pDrive);
  775. return TRUE;
  776. }
  777. static BOOL Plugin_OnNavItemClick(HNAVITEM hItem, UINT nAction, HWND hwndParent)
  778. {
  779. return FALSE;
  780. }
  781. static INT Plugin_OnNavCustomDraw(HNAVITEM hItem, NAVITEMDRAW *pnicd, LPARAM lParam)
  782. {
  783. static INT indent = 0;
  784. DRIVE *pDrive;
  785. if (FALSE == DriveParam_IsValid(lParam))
  786. return FALSE;
  787. pDrive = (DRIVE*)lParam;
  788. if (0 == indent) indent = MLNavCtrl_GetIndent(plugin.hwndLibraryParent);
  789. switch(pnicd->drawStage)
  790. {
  791. case NIDS_PREPAINT:
  792. if (pnicd->prc->bottom > 0 && pnicd->prc->bottom > pnicd->prc->top)
  793. {
  794. HIMAGELIST himl;
  795. INT realIndex, l, t, r;
  796. MLIMAGELISTREALINDEX mlilRealIndex;
  797. himl = MLImageList_GetRealList(plugin.hwndLibraryParent, hmlilIcons);
  798. mlilRealIndex.cbSize = sizeof(MLIMAGELISTREALINDEX);
  799. mlilRealIndex.hmlil = hmlilIcons;
  800. mlilRealIndex.rgbBk = GetBkColor(pnicd->hdc);
  801. mlilRealIndex.rgbFg = GetTextColor(pnicd->hdc);
  802. t = pnicd->prc->top + (pnicd->prc->bottom - pnicd->prc->top - ICON_SIZE_CY)/2;
  803. l = pnicd->prc->left + (indent*pnicd->iLevel) + 3;
  804. r = pnicd->prc->right;
  805. mlilRealIndex.mlilIndex = 0;
  806. realIndex = ((NCS_SHOWICONS & g_navStyle) && himl && l < pnicd->prc->right) ?
  807. MLImageList_GetRealIndex(plugin.hwndLibraryParent, &mlilRealIndex) : -1;
  808. if (-1 != realIndex) // draw icon
  809. {
  810. if (ImageList_Draw(himl, realIndex, pnicd->hdc, l, t, ILD_NORMAL))
  811. {
  812. ExcludeClipRect(pnicd->hdc, l, t, l + ICON_SIZE_CX, t + ICON_SIZE_CY);
  813. l += (ICON_SIZE_CX + 5);
  814. }
  815. }
  816. pDrive->bEjectVisible = FALSE;
  817. mlilRealIndex.mlilIndex = 1 + ((DM_MODE_READY == pDrive->cMode) ? pDrive->nBtnState : BTNSTATE_DISABLED);
  818. realIndex = ((NCS_EX_SHOWEJECT & g_navStyle) && himl && (r - l) > (24 + 6 + ICON_SIZE_CX)) ?
  819. MLImageList_GetRealIndex(plugin.hwndLibraryParent, &mlilRealIndex) : -1;
  820. if (-1 != realIndex)
  821. {
  822. if (ImageList_Draw(himl, realIndex, pnicd->hdc, r - (ICON_SIZE_CX + 2), t, ILD_NORMAL))
  823. {
  824. r -= (ICON_SIZE_CX + 2);
  825. ExcludeClipRect(pnicd->hdc, r, t, r + ICON_SIZE_CX, t + ICON_SIZE_CY);
  826. r -= 4;
  827. pDrive->bEjectVisible = TRUE;
  828. }
  829. }
  830. if (*pDrive->szTitle && l < r)
  831. {
  832. RECT rt;
  833. INT textH, textW;
  834. COLORREF rgbOld(0), rgbBkOld(0);
  835. if (!pDrive->textSize || (pDrive->textOrigWidth > r-l-3 && pDrive->itemWidth > (pnicd->prc->right - pnicd->prc->left)) ||
  836. (LOWORD(pDrive->textSize) != pDrive->textOrigWidth && pDrive->itemWidth < (pnicd->prc->right - pnicd->prc->left)))
  837. {
  838. NAVITEM item;
  839. item.cbSize = sizeof(NAVITEM);
  840. item.mask = NIMF_TEXT;
  841. item.hItem = hItem;
  842. item.cchTextMax = sizeof(pDrive->szTitle)/sizeof(wchar_t);
  843. item.pszText = pDrive->szTitle;
  844. MLNavItem_GetInfo(plugin.hwndLibraryParent, &item);
  845. {
  846. if (pDrive->szTitle != item.pszText)
  847. {
  848. StringCchCopyW(pDrive->szTitle, sizeof(pDrive->szTitle)/sizeof(wchar_t), item.pszText);
  849. }
  850. if (!pDrive->textSize)
  851. {
  852. SetRect(&rt, 0, 0, 1, 1);
  853. DrawTextW(pnicd->hdc, pDrive->szTitle, -1, &rt, DT_SINGLELINE | DT_CALCRECT);
  854. pDrive->textOrigWidth = rt.right - rt.left;
  855. }
  856. SetRect(&rt, 0, 0, r - l - 3, 1);
  857. textH = DrawTextW(pnicd->hdc, pDrive->szTitle, -1, &rt, DT_SINGLELINE|DT_CALCRECT|DT_END_ELLIPSIS|DT_MODIFYSTRING);
  858. textW = rt.right - rt.left;
  859. pDrive->textSize = (DWORD)MAKELONG(textW, textH);
  860. }
  861. }
  862. else
  863. {
  864. textW = LOWORD(pDrive->textSize);
  865. textH = HIWORD(pDrive->textSize);
  866. }
  867. if (0 == (NCS_FULLROWSELECT & g_navStyle) && ((NIS_SELECTED | NIS_DROPHILITED) & pnicd->itemState))
  868. {
  869. rgbOld = SetTextColor(pnicd->hdc, pnicd->clrText);
  870. rgbBkOld = SetBkColor(pnicd->hdc, pnicd->clrTextBk);
  871. }
  872. if (r > (l + textW + 7)) r = l + textW + 7;
  873. SetRect(&rt, l, pnicd->prc->top, r, pnicd->prc->bottom);
  874. t = pnicd->prc->top + (pnicd->prc->bottom - pnicd->prc->top - textH)/2;
  875. ExtTextOutW(pnicd->hdc, rt.left + 2, t, ETO_CLIPPED | ETO_OPAQUE, &rt, pDrive->szTitle, lstrlenW(pDrive->szTitle), 0);
  876. if (0 == (NCS_FULLROWSELECT & g_navStyle) && (NIS_FOCUSED & pnicd->itemState) &&
  877. 0 == (0x1 /*UISF_HIDEFOCUS*/ & (INT)SendMessageW(MLNavCtrl_GetHWND(plugin.hwndLibraryParent), 0x129 /*WM_QUERYUISTATE*/, 0, 0L)))
  878. {
  879. DrawFocusRect(pnicd->hdc, &rt);
  880. }
  881. ExcludeClipRect(pnicd->hdc, rt.left, rt.top, rt.right, rt.bottom);
  882. if (0 == (NCS_FULLROWSELECT & g_navStyle) && ((NIS_SELECTED | NIS_DROPHILITED) & pnicd->itemState))
  883. {
  884. if (rgbOld != pnicd->clrText) SetTextColor(pnicd->hdc, rgbOld);
  885. if (rgbBkOld != pnicd->clrTextBk) SetBkColor(pnicd->hdc, rgbBkOld);
  886. }
  887. }
  888. pDrive->itemWidth = (WORD)(pnicd->prc->right - pnicd->prc->left);
  889. if (NCS_FULLROWSELECT & g_navStyle)
  890. {
  891. ExtTextOutW(pnicd->hdc, 0, 0, ETO_OPAQUE, pnicd->prc, L"", 0, 0);
  892. return NICDRF_SKIPDEFAULT;
  893. }
  894. else ExcludeClipRect(pnicd->hdc, pnicd->prc->left, pnicd->prc->top, pnicd->prc->right, pnicd->prc->bottom);
  895. }
  896. break;
  897. case NIDS_POSTPAINT:
  898. break;
  899. }
  900. return NICDRF_DODEFAULT;
  901. }
  902. static HNAVITEM hItemActive = NULL;
  903. static BOOL GetEjectBtnRect(HNAVITEM hItem, RECT *prc)
  904. {
  905. NAVITEMGETRECT navRect;
  906. navRect.fItem = FALSE;
  907. navRect.hItem = hItem;
  908. if (!hItem || !prc || !MLNavItem_GetRect(plugin.hwndLibraryParent, &navRect)) return FALSE;
  909. navRect.rc.right -= 2;
  910. navRect.rc.left = navRect.rc.right - ICON_SIZE_CX;
  911. navRect.rc.top += (navRect.rc.bottom - navRect.rc.top - ICON_SIZE_CY)/2;
  912. navRect.rc.bottom = navRect.rc.top + ICON_SIZE_CY;
  913. CopyRect(prc, &navRect.rc);
  914. return TRUE;
  915. }
  916. static INT_PTR Plugin_OnNavHitTest(HNAVITEM hItem, NAVHITTEST *pnavHitTest, LPARAM lParam)
  917. {
  918. DRIVE *pDrive;
  919. if (FALSE == DriveParam_IsValid(lParam))
  920. return FALSE;
  921. pDrive = (DRIVE*)lParam;
  922. if ((NAVHT_ONITEMRIGHT | NAVHT_ONITEM) & pnavHitTest->flags)
  923. {
  924. RECT rb;
  925. if (pDrive->bEjectVisible && GetEjectBtnRect(hItem, &rb) &&
  926. pnavHitTest->pt.x >= rb.left && pnavHitTest->pt.x <= rb.right &&
  927. pnavHitTest->pt.y >= rb.top && pnavHitTest->pt.y <= rb.bottom)
  928. {
  929. pnavHitTest->flags = NAVHT_NOWHERE;
  930. pnavHitTest->hItem = NULL;
  931. }
  932. }
  933. return 1;
  934. }
  935. static void CALLBACK NavButton_TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
  936. {
  937. DRIVE *pDrive;
  938. POINT pt;
  939. RECT rb;
  940. pDrive = (hItemActive) ? Plugin_GetDriveFromNavItem(hItemActive) : NULL;
  941. if (!pDrive || (BYTE)BTNSTATE_NORMAL == pDrive->nBtnState || !pDrive->bEjectVisible || !GetEjectBtnRect(hItemActive, &rb))
  942. {
  943. KillTimer(NULL, idEvent);
  944. return;
  945. }
  946. GetCursorPos(&pt);
  947. MapWindowPoints(HWND_DESKTOP, MLNavCtrl_GetHWND(plugin.hwndLibraryParent), &pt, 1);
  948. if (pt.x < rb.left || pt.x > rb.right || pt.y < rb.top || pt.y > rb.bottom)
  949. {
  950. NAVITEMINAVLIDATE inv;
  951. KillTimer(NULL, idEvent);
  952. inv.fErase = FALSE;
  953. inv.hItem = hItemActive;
  954. inv.prc = &rb;
  955. hItemActive = NULL;
  956. pDrive->nBtnState = BTNSTATE_NORMAL;
  957. MLNavItem_Invalidate(plugin.hwndLibraryParent, &inv);
  958. }
  959. }
  960. static INT_PTR Plugin_OnNavSetCursor(HNAVITEM hItem, LPARAM lParam)
  961. {
  962. POINT pt;
  963. DRIVE *pDrive;
  964. BYTE state;
  965. RECT rb;
  966. if (FALSE == DriveParam_IsValid(lParam))
  967. return FALSE;
  968. pDrive = (DRIVE*)lParam;
  969. if (DM_MODE_READY != pDrive->cMode || !pDrive->bEjectVisible || !GetEjectBtnRect(hItem, &rb)) return -1;
  970. GetCursorPos(&pt);
  971. MapWindowPoints(HWND_DESKTOP, MLNavCtrl_GetHWND(plugin.hwndLibraryParent), &pt, 1);
  972. if (pt.x >= rb.left && pt.x <= rb.right && pt.y >= rb.top && pt.y <= rb.bottom)
  973. {
  974. state = (BYTE)((0x8000 & GetAsyncKeyState( GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON)) ?
  975. BTNSTATE_PRESSED : BTNSTATE_HILITED);
  976. }
  977. else state = BTNSTATE_NORMAL;
  978. if (pDrive->nBtnState != state)
  979. {
  980. NAVITEMINAVLIDATE inv;
  981. if ((BYTE)BTNSTATE_PRESSED == pDrive->nBtnState && BTNSTATE_HILITED == state)
  982. {
  983. DriveManager_Eject(pDrive->cLetter, DM_EJECT_CHANGE);
  984. }
  985. if (pDrive->timerId)
  986. {
  987. KillTimer(NULL, pDrive->timerId);
  988. pDrive->timerId = 0;
  989. }
  990. if (hItemActive)
  991. {
  992. DRIVE *pDriveOld = Plugin_GetDriveFromNavItem(hItemActive);
  993. if (pDriveOld)
  994. {
  995. RECT rb2;
  996. if (pDriveOld->timerId)
  997. {
  998. KillTimer(NULL, pDriveOld->timerId);
  999. pDriveOld->timerId = NULL;
  1000. }
  1001. if ((BYTE)BTNSTATE_NORMAL != pDriveOld->nBtnState && GetEjectBtnRect(hItemActive, &rb2))
  1002. {
  1003. pDriveOld->nBtnState = BTNSTATE_NORMAL;
  1004. inv.fErase = FALSE;
  1005. inv.hItem = hItemActive;
  1006. inv.prc = &rb2;
  1007. MLNavItem_Invalidate(plugin.hwndLibraryParent, &inv);
  1008. }
  1009. hItemActive = NULL;
  1010. }
  1011. }
  1012. if (BTNSTATE_NORMAL != state)
  1013. {
  1014. hItemActive = hItem;
  1015. pDrive->timerId = SetTimer(NULL, 0, NAVBUTTON_STATECHECK_DELAY, NavButton_TimerProc);
  1016. }
  1017. pDrive->nBtnState = state;
  1018. inv.fErase = FALSE;
  1019. inv.hItem = hItem;
  1020. inv.prc = &rb;
  1021. MLNavItem_Invalidate(plugin.hwndLibraryParent, &inv);
  1022. }
  1023. return -1;
  1024. }
  1025. static BOOL Plugin_OnConfig(void)
  1026. {
  1027. SendMessageW(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&myPrefsItemCD, IPC_OPENPREFSTOPAGE);
  1028. return TRUE;
  1029. }
  1030. static INT_PTR pluginMessageProc(int msg, INT_PTR param1, INT_PTR param2, INT_PTR param3)
  1031. {
  1032. HNAVITEM hItem;
  1033. if (msg >= ML_MSG_TREE_BEGIN && msg <= ML_MSG_TREE_END)
  1034. {
  1035. hItem = (msg < ML_MSG_NAVIGATION_FIRST) ? MLNavCtrl_FindItemById(plugin.hwndLibraryParent, param1) : (HNAVITEM)param1;
  1036. if (!hItem) return 0;
  1037. } else hItem = NULL;
  1038. switch (msg)
  1039. {
  1040. case ML_MSG_TREE_ONCREATEVIEW: return (INT_PTR)Plugin_OnViewCreate(hItem, (HWND)param2);
  1041. case ML_MSG_NAVIGATION_ONDELETE: return (INT_PTR)Plugin_OnNavItemDelete(hItem);
  1042. case ML_MSG_NAVIGATION_ONCUSTOMDRAW: return (INT_PTR)Plugin_OnNavCustomDraw(hItem, (NAVITEMDRAW*)param2, (LPARAM)param3);
  1043. case ML_MSG_NAVIGATION_ONHITTEST: return (INT_PTR)Plugin_OnNavHitTest(hItem, (NAVHITTEST*)param2, (LPARAM)param3);
  1044. case ML_MSG_NAVIGATION_ONSETCURSOR: return (INT_PTR)Plugin_OnNavSetCursor(hItem, (LPARAM)param3);
  1045. case ML_MSG_NAVIGATION_CONTEXTMENU:
  1046. {
  1047. DRIVE *pDrive;
  1048. if (hniMain && (hItem == hniMain))
  1049. return Root_OnContextMenu(hItem, (HWND)param2, MAKEPOINTS(param3));
  1050. //Plugin Item
  1051. pDrive = Plugin_GetDriveFromNavItem(hItem);
  1052. if (pDrive)
  1053. return Plugin_OnContextMenu(hItem, (HWND)param2, MAKEPOINTS(param3), pDrive->cLetter);
  1054. return 0;
  1055. }
  1056. case ML_MSG_TREE_ONCLICK: return (INT_PTR)Plugin_OnNavItemClick(hItem, (UINT)param2, (HWND)param3);
  1057. case ML_MSG_CONFIG: return (INT_PTR)Plugin_OnConfig();
  1058. case ML_MSG_MLVISIBLE: Plugin_OnMLVisible((BOOL)param1); break;
  1059. case ML_MSG_NOTOKTOQUIT: if (!Plugin_QueryOkToQuit()) { return TRUE; } break;
  1060. }
  1061. return 0;
  1062. }
  1063. /////////////////////////////////////////////////////////////////////////////////
  1064. extern "C" winampMediaLibraryPlugin plugin =
  1065. {
  1066. MLHDR_VER,
  1067. "nullsoft(ml_disc.dll)",
  1068. Init,
  1069. Quit,
  1070. pluginMessageProc,
  1071. 0,
  1072. 0,
  1073. 0,
  1074. };
  1075. extern "C" __declspec(dllexport) winampMediaLibraryPlugin *winampGetMediaLibraryPlugin()
  1076. {
  1077. return &plugin;
  1078. }