1
0

cddbui.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. #include "main.h"
  2. #include ".\cddbui.h"
  3. #include ".\cddb.h"
  4. #include "api__in_cdda.h"
  5. #include ".\resource.h"
  6. #include "..\winamp\wa_ipc.h"
  7. #include <api/application/api_application.h>
  8. #include <shobjidl.h>
  9. #include <commctrl.h>
  10. #include <strsafe.h>
  11. #include "cddbcontrolwinamp.tlh"
  12. #define PROP_PRGDLG L"PRGDLG"
  13. #define TIMER_PROGRESS_DESTROY_ID 1978
  14. #define TIMER_PROGRESS_DESTROY_ELAPSE 250
  15. #define TIMER_PROGRESS_ANIMATE_ID 1980
  16. #define TIMER_PROGRESS_ANIMATE_ELAPSE 65
  17. #define MODAL_EXIT 0
  18. #define MODAL_ACTIVE 1
  19. #define MODAL_DESTROY 2
  20. #define ICON_OFFSET_X 12
  21. #define ICON_OFFSET_Y 12
  22. #define DIALOG_HEIGHT_NORMAL 66
  23. #define DIALOG_HEIGHT_EXTENDED 160
  24. #ifndef IDC_HAND
  25. #define IDC_HAND MAKEINTRESOURCE(32649)
  26. #endif //IDC_HAND
  27. typedef struct _PROGRESSICON
  28. {
  29. HINSTANCE hInstance;
  30. LONG resId;
  31. RECT rc;
  32. LONG frames;
  33. LONG step;
  34. HBITMAP hbmp;
  35. } PROGRESSICON;
  36. typedef struct _PROGRESSDLG
  37. {
  38. PROGRESSICON icon;
  39. UINT uState;
  40. DWORD dwAutoClose;
  41. CDDBDLG_ONBTNCLICK OnAbort;
  42. CDDBDLG_ONBTNCLICK OnButton1;
  43. BSTR Btn1Data;
  44. BSTR AbortData;
  45. WORD Modal;
  46. HRESULT rCode;
  47. HANDLE user;
  48. } PROGRESSDLG;
  49. static HFONT hFont = NULL;
  50. static LONG fontRef = 0;
  51. static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  52. static void CALLBACK ProgressDlg_OnTimer(HWND hwnd, UINT uMsg, UINT_PTR evntId, DWORD dwTime);
  53. static void InvalidateLogo(HWND hwnd, PROGRESSICON *pIcon);
  54. static BOOL EndProgressDialog(HWND hwnd);
  55. #define GET_DATA(__hwnd) ((PROGRESSDLG*)GetPropW((__hwnd), PROP_PRGDLG))
  56. static wchar_t szText1[256];
  57. static wchar_t szText2[256];
  58. #define GET_SAFE_LANGSTRING(__str, __buff, __cch) ((__str) ? (IS_INTRESOURCE(__str) ? WASABI_API_LNGSTRINGW_BUF((UINT)(UINT_PTR)(__str), (__buff), (__cch)) : (__str)) : L"")
  59. #define GET_SAFE_LANGSTRING1(__str) GET_SAFE_LANGSTRING((__str), (szText1), (sizeof(szText1)/sizeof(wchar_t)))
  60. #define GET_SAFE_LANGSTRING2(__str) GET_SAFE_LANGSTRING((__str), (szText2), (sizeof(szText2)/sizeof(wchar_t)))
  61. typedef struct _ENUMWND_DATAPACK
  62. {
  63. HWND host;
  64. HWND *list;
  65. INT index;
  66. INT count;
  67. UINT flags;
  68. BOOL found;
  69. } ENUMWND_DATAPACK;
  70. HWND CddbProgressDlg_Create(HWND hwndParent, INT nCmdShow)
  71. {
  72. HWND hdlg = WASABI_API_CREATEDIALOGPARAMW(IDD_CDDB_PROGRESS, NULL, DialogProc, 0L);
  73. if (hdlg && SW_HIDE != nCmdShow) ShowWindow(hdlg, SW_HIDE);
  74. return hdlg;
  75. }
  76. BOOL CddbProgressDlg_Initialize(HWND hwnd, LPCWSTR pszCaption, CDDBDLG_ONBTNCLICK fnOnAbort, BSTR bstrAbortUser)
  77. {
  78. HWND hwndCtrl;
  79. PROGRESSDLG *pDlg;
  80. if(!hwnd || !IsWindow(hwnd)) return FALSE;
  81. pDlg = GET_DATA(hwnd);
  82. if (!pDlg) return FALSE;
  83. KillTimer(hwnd, TIMER_PROGRESS_ANIMATE_ID);
  84. pDlg->OnAbort = (fnOnAbort) ? fnOnAbort : NULL;
  85. if (pDlg->AbortData) SysFreeString(pDlg->AbortData);
  86. pDlg->AbortData = (bstrAbortUser) ? SysAllocString(bstrAbortUser) : NULL;
  87. SetDlgItemTextW(hwnd, IDC_LBL_CAPTION, GET_SAFE_LANGSTRING1(pszCaption));
  88. SetDlgItemTextW(hwnd, IDC_LBL_STATUS, L"");
  89. if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_LBL_REASON)))
  90. {
  91. ShowWindow(hwndCtrl, SW_HIDE);
  92. SetWindowTextW(hwndCtrl, L"");
  93. }
  94. if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_PRG_STATUS)))
  95. {
  96. ShowWindow(hwndCtrl, SW_HIDE);
  97. SendMessageW(hwndCtrl, PBM_SETPOS, (WPARAM)0, (LPARAM)0L);
  98. }
  99. if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDCANCEL)))
  100. {
  101. SetWindowTextW(hwndCtrl, GET_SAFE_LANGSTRING1(MAKEINTRESOURCEW((fnOnAbort) ? IDS_ABORT : IDS_CLOSE)));
  102. EnableWindow(hwndCtrl, (NULL != fnOnAbort));
  103. }
  104. if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_LV_EXT)))
  105. {
  106. SendMessageW(hwndCtrl, LVM_DELETEALLITEMS, 0, 0L);
  107. }
  108. pDlg->icon.step = 0;
  109. InvalidateLogo(hwnd, &pDlg->icon);
  110. SetTimer(hwnd, TIMER_PROGRESS_ANIMATE_ID, TIMER_PROGRESS_ANIMATE_ELAPSE, ProgressDlg_OnTimer);
  111. pDlg->uState = STATE_ACTIVE;
  112. return TRUE;
  113. }
  114. BOOL CddbProgressDlg_Completed(HWND hwnd, LPCWSTR pszResult, LPCWSTR pszReason, DWORD nAutoCloseDelay, HRESULT rCode)
  115. {
  116. PROGRESSDLG *pDlg;
  117. if(!hwnd || !IsWindow(hwnd)) return FALSE;
  118. pDlg = GET_DATA(hwnd);
  119. if (!pDlg) return FALSE;
  120. KillTimer(hwnd, TIMER_PROGRESS_ANIMATE_ID);
  121. pDlg->uState = STATE_COMPLETED;
  122. pDlg->rCode = rCode;
  123. if (AUTOCLOSE_NOW == nAutoCloseDelay)
  124. {
  125. EndProgressDialog(hwnd);
  126. }
  127. else
  128. {
  129. HWND hwndCtrl;
  130. SetDlgItemTextW(hwnd, IDC_LBL_STATUS, GET_SAFE_LANGSTRING1(pszResult));
  131. if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_PRG_STATUS)))
  132. {
  133. ShowWindow(hwndCtrl, SW_HIDE);
  134. SendMessageW(hwndCtrl, PBM_SETPOS, (WPARAM)0, (LPARAM)0L);
  135. }
  136. if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_LBL_REASON)))
  137. {
  138. SetWindowTextW(hwndCtrl, GET_SAFE_LANGSTRING1(pszReason));
  139. ShowWindow(hwndCtrl, SW_SHOWNORMAL);
  140. }
  141. if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDCANCEL)))
  142. {
  143. if (AUTOCLOSE_NEVER != nAutoCloseDelay)
  144. {
  145. INT time = nAutoCloseDelay/1000 + (((nAutoCloseDelay%1000)>500) ? 1 : 0);
  146. if (time)
  147. {
  148. wchar_t szText[128] = {0};
  149. StringCchPrintfW(szText, sizeof(szText)/sizeof(wchar_t), L"%s (%d)", GET_SAFE_LANGSTRING1(MAKEINTRESOURCEW(IDS_CLOSE)),time);
  150. SetDlgItemTextW(hwnd, IDCANCEL, szText);
  151. }
  152. else SetWindowText(hwndCtrl, GET_SAFE_LANGSTRING1(MAKEINTRESOURCEW(IDS_CLOSE)));
  153. }
  154. else SetWindowText(hwndCtrl, GET_SAFE_LANGSTRING1(MAKEINTRESOURCEW(IDS_CLOSE)));
  155. EnableWindow(hwndCtrl, TRUE);
  156. }
  157. pDlg->icon.step = pDlg->icon.frames - 1;
  158. InvalidateLogo(hwnd, &pDlg->icon);
  159. if (AUTOCLOSE_NEVER != nAutoCloseDelay)
  160. {
  161. pDlg->dwAutoClose = GetTickCount() + nAutoCloseDelay;
  162. return (0 != SetTimer(hwnd, TIMER_PROGRESS_DESTROY_ID, TIMER_PROGRESS_DESTROY_ELAPSE, ProgressDlg_OnTimer));
  163. }
  164. }
  165. return TRUE;
  166. }
  167. BOOL CddbProgressDlg_SetStatus(HWND hwnd, LPCWSTR pszStatus, INT nPercentCompleted)
  168. {
  169. BOOL br(TRUE);
  170. HWND hwndCtrl;
  171. if (!hwnd || !IsWindow(hwnd)) return FALSE;
  172. if (pszStatus && !SetDlgItemTextW(hwnd, IDC_LBL_STATUS, GET_SAFE_LANGSTRING1(pszStatus))) br = FALSE;
  173. hwndCtrl = GetDlgItem(hwnd, IDC_PRG_STATUS);
  174. if (hwndCtrl)
  175. {
  176. if (nPercentCompleted > 100) nPercentCompleted = 100;
  177. if (nPercentCompleted < 0) ShowWindow(hwndCtrl, SW_HIDE);
  178. else
  179. {
  180. SendMessageW(hwndCtrl, PBM_SETPOS, (WPARAM)nPercentCompleted, (LPARAM)0L);
  181. ShowWindow(hwndCtrl, SW_SHOWNA);
  182. }
  183. }
  184. return br;
  185. }
  186. UINT CddbProgressDlg_GetState(HWND hwnd)
  187. {
  188. PROGRESSDLG *pDlg;
  189. if(!hwnd || !IsWindow(hwnd)) return STATE_INACTIVE;
  190. pDlg = GET_DATA(hwnd);
  191. return (pDlg) ? pDlg->uState : STATE_INACTIVE;
  192. }
  193. BOOL CddbProgressDlg_EnableAbortButton(HWND hwnd, BOOL bEnable)
  194. {
  195. HWND hwndBtn;
  196. if(!hwnd || !IsWindow(hwnd)) return FALSE;
  197. if (NULL == (hwndBtn = GetDlgItem(hwnd, IDCANCEL))) return FALSE;
  198. return EnableWindow(hwndBtn, bEnable);
  199. }
  200. BOOL CddbProgressDlg_ShowButton1(HWND hwnd, LPCWSTR pszCaption, CDDBDLG_ONBTNCLICK fnOnButton1, BSTR bstrUser)
  201. {
  202. PROGRESSDLG *pDlg;
  203. HWND hwndBtn;
  204. if(!hwnd || !IsWindow(hwnd)) return FALSE;
  205. pDlg = GET_DATA(hwnd);
  206. if (!pDlg) return FALSE;
  207. if (NULL == (hwndBtn = GetDlgItem(hwnd, IDC_BUTTON1))) return FALSE;
  208. if (pDlg->Btn1Data) SysFreeString(pDlg->Btn1Data);
  209. if(pszCaption && fnOnButton1)
  210. {
  211. SetWindowTextW(hwndBtn, GET_SAFE_LANGSTRING1(pszCaption));
  212. ShowWindow(hwndBtn, SW_SHOWNORMAL);
  213. pDlg->OnButton1 = fnOnButton1;
  214. pDlg->Btn1Data = (bstrUser) ? SysAllocString(bstrUser) : NULL;
  215. SendMessageW(hwnd, WM_NEXTDLGCTL, (WPARAM)TRUE, (LPARAM)hwndBtn);
  216. }
  217. else
  218. {
  219. ShowWindow(hwndBtn, SW_HIDE);
  220. pDlg->OnButton1 = NULL;
  221. pDlg->Btn1Data = NULL;
  222. }
  223. return TRUE;
  224. }
  225. BOOL CddbProgressDlg_ShowInTaskbar(HWND hwnd, BOOL bShow)
  226. {
  227. HRESULT hr;
  228. ITaskbarList *pTaskbar;
  229. if(!hwnd || !IsWindow(hwnd)) return FALSE;
  230. hr = CoCreateInstance(CLSID_TaskbarList,0, CLSCTX_INPROC_SERVER, IID_ITaskbarList, (void**)&pTaskbar);
  231. if(SUCCEEDED(hr))
  232. {
  233. hr = pTaskbar->HrInit();
  234. if (SUCCEEDED(hr))
  235. {
  236. if (bShow)
  237. {
  238. hr = pTaskbar->AddTab(hwnd);
  239. pTaskbar->ActivateTab(hwnd);
  240. }
  241. else pTaskbar->DeleteTab(hwnd);
  242. }
  243. pTaskbar->Release();
  244. }
  245. return (S_OK == hr);
  246. }
  247. BOOL CddbProgressDlg_SetExtendedMode(HWND hwnd, BOOL bEnable)
  248. {
  249. RECT rc;
  250. HWND hwndCtrl;
  251. INT height;
  252. if(!hwnd || !IsWindow(hwnd)) return FALSE;
  253. GetWindowRect(hwnd, &rc);
  254. RECT rw;
  255. GetClientRect(hwnd, &rw);
  256. height = (rc.bottom - rc.top) - (rw.bottom - rw.top);
  257. SetRect(&rw, 0, 0, 1, (bEnable) ? DIALOG_HEIGHT_EXTENDED : DIALOG_HEIGHT_NORMAL);
  258. MapDialogRect(hwnd, &rw);
  259. height += rw.bottom;
  260. if (height == rc.bottom - rc.top) return TRUE;
  261. if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_BUTTON1)))
  262. {
  263. GetWindowRect(hwndCtrl, &rw);
  264. MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
  265. SetWindowPos(hwndCtrl, NULL, rw.left, rw.top + (height - (rc.bottom - rc.top)), 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
  266. }
  267. if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDCANCEL)))
  268. {
  269. GetWindowRect(hwndCtrl, &rw);
  270. MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
  271. SetWindowPos(hwndCtrl, NULL, rw.left, rw.top + (height - (rc.bottom - rc.top)), 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
  272. }
  273. if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_LV_EXT)))
  274. {
  275. PROGRESSDLG *pDlg;
  276. INT listBottom;
  277. GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rw);
  278. MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 1);
  279. listBottom = rw.top - MulDiv(4, HIWORD(GetDialogBaseUnits()), 8);
  280. pDlg = GET_DATA(hwnd);
  281. if (pDlg)
  282. {
  283. GetWindowRect(hwndCtrl, &rw);
  284. MapWindowPoints(HWND_DESKTOP, hwnd, (POINT*)&rw, 2);
  285. INT listTop = ICON_OFFSET_Y * 2 + (pDlg->icon.rc.bottom - pDlg->icon.rc.top);
  286. SetWindowPos(hwndCtrl, NULL, ICON_OFFSET_X, listTop, rc.right - rc.left - ICON_OFFSET_X*2, listBottom - listTop, SWP_NOACTIVATE | SWP_NOZORDER);
  287. ShowWindow(hwndCtrl, (bEnable) ? SW_SHOW : SW_HIDE);
  288. }
  289. }
  290. SetWindowPos(hwnd, NULL, 0, 0, rc.right - rc.left, height, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
  291. return TRUE;
  292. }
  293. BOOL CddbProgressDlg_AddRecord(HWND hwnd, LPCWSTR pszArtist, LPCWSTR pszTitle, LPCWSTR pszLanguage)
  294. {
  295. HWND hwndList;
  296. LVITEMW item;
  297. INT index;
  298. if(!hwnd || !IsWindow(hwnd)) return FALSE;
  299. hwndList = GetDlgItem(hwnd, IDC_LV_EXT);
  300. if (!hwndList) return FALSE;
  301. item.mask = LVIF_TEXT;
  302. item.iItem = 0xFFFF;
  303. item.iSubItem = 0;
  304. item.pszText = GET_SAFE_LANGSTRING1(pszArtist);
  305. index = (INT)SendMessageW(hwndList, LVM_INSERTITEMW, 0, (LPARAM)&item);
  306. if (-1 == index) return FALSE;
  307. if (0 == index)
  308. {
  309. item.state = LVIS_FOCUSED | LVIS_SELECTED;
  310. item.stateMask = item.state;
  311. SendMessageW(hwndList, LVM_SETITEMSTATE, (WPARAM)index, (LPARAM)&item);
  312. }
  313. item.iItem = index;
  314. item.mask = LVIF_TEXT;
  315. item.iSubItem = 1;
  316. item.pszText = GET_SAFE_LANGSTRING1(pszTitle);;
  317. SendMessageW(hwndList, LVM_SETITEMW, 0, (LPARAM)&item);
  318. item.iItem = index;
  319. item.mask = LVIF_TEXT;
  320. item.iSubItem = 2;
  321. item.pszText = GET_SAFE_LANGSTRING1(pszLanguage);;
  322. SendMessageW(hwndList, LVM_SETITEMW, 0, (LPARAM)&item);
  323. return TRUE;
  324. }
  325. #define HOOK_MAX_DATA 12
  326. typedef struct _HOOKDATA
  327. {
  328. HHOOK handle;
  329. int ref;
  330. HWND modalList[HOOK_MAX_DATA];
  331. } HOOKDATA;
  332. static HOOKDATA g_hook = { NULL, 0};
  333. static LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)
  334. {
  335. MOUSEHOOKSTRUCT *pMouse = (MOUSEHOOKSTRUCT*)lParam;
  336. switch(wParam)
  337. {
  338. case WM_NCLBUTTONDOWN:
  339. case WM_NCLBUTTONDBLCLK:
  340. case WM_NCRBUTTONDOWN:
  341. case WM_NCRBUTTONDBLCLK:
  342. case WM_NCMBUTTONDOWN:
  343. case WM_NCMBUTTONDBLCLK:
  344. if (FALSE == IsWindowEnabled(pMouse->hwnd))
  345. {
  346. for(int i = g_hook.ref - 1; i > -1 ; i--)
  347. {
  348. HWND hwndOwner = GetWindow(g_hook.modalList[i], GW_OWNER);
  349. if (hwndOwner == pMouse->hwnd || hwndOwner == GetWindow(pMouse->hwnd, GW_OWNER))
  350. {
  351. DWORD style = GetWindowLongPtrW(g_hook.modalList[i], GWL_STYLE);
  352. if (0 != (WS_VISIBLE & style) && 0 == (WS_DISABLED & style))
  353. {
  354. HWND hwndTest = GetForegroundWindow();
  355. if (hwndTest == g_hook.modalList[i])
  356. {
  357. FLASHWINFO flash;
  358. flash.hwnd = g_hook.modalList[i];
  359. flash.cbSize = sizeof(FLASHWINFO);
  360. flash.dwFlags = FLASHW_CAPTION;
  361. flash.uCount = 2;
  362. flash.dwTimeout = 100;
  363. FlashWindowEx(&flash);
  364. MessageBeep(MB_OK);
  365. }
  366. else SetForegroundWindow(g_hook.modalList[i]);
  367. return CallNextHookEx(g_hook.handle, code, wParam, lParam);
  368. }
  369. }
  370. }
  371. }
  372. break;
  373. }
  374. return CallNextHookEx(g_hook.handle, code, wParam, lParam);
  375. }
  376. static void AddModalHook(HWND hdlg)
  377. {
  378. if (!hdlg) return;
  379. if (!g_hook.handle)
  380. {
  381. ZeroMemory(&g_hook, sizeof(HOOKDATA));
  382. g_hook.handle = SetWindowsHookEx(WH_MOUSE, HookProc, line.hDllInstance, NULL);
  383. if (!g_hook.handle) return;
  384. }
  385. if (HOOK_MAX_DATA == (g_hook.ref - 1)) return;
  386. g_hook.modalList[g_hook.ref] = hdlg;
  387. g_hook.ref++;
  388. return;
  389. }
  390. static void ReleaseModalHook(HWND hdlg)
  391. {
  392. if (!hdlg) return;
  393. for (int i = 0; i < g_hook.ref; i++)
  394. {
  395. if (g_hook.modalList[i] == hdlg)
  396. {
  397. if (i != g_hook.ref -1) MoveMemory(&g_hook.modalList[i], &g_hook.modalList[i + 1], (g_hook.ref - i -1)*sizeof(HWND));
  398. g_hook.ref--;
  399. if (!g_hook.ref)
  400. {
  401. UnhookWindowsHookEx(g_hook.handle);
  402. ZeroMemory(&g_hook, sizeof(HOOKDATA));
  403. }
  404. return;
  405. }
  406. }
  407. return ;
  408. }
  409. HRESULT CddbProgressDlg_DoModal(HWND hwnd, RECT *prc)
  410. {
  411. MSG msg;
  412. HWND hwndOwner;
  413. PROGRESSDLG *pDlg;
  414. HRESULT rCode;
  415. HWND disabledList[32] = {0};
  416. if(!hwnd || !IsWindow(hwnd)) return E_INVALIDARG;
  417. pDlg = GET_DATA(hwnd);
  418. if (!pDlg || MODAL_ACTIVE == pDlg->Modal) return E_POINTER;
  419. pDlg->Modal = MODAL_ACTIVE;
  420. hwndOwner = GetParent(hwnd);
  421. if (hwndOwner == GetDesktopWindow()) hwndOwner = NULL;
  422. if (hwndOwner != line.hMainWindow &&
  423. hwndOwner == (HWND)SendMessageW(line.hMainWindow, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT))
  424. {
  425. hwndOwner = line.hMainWindow;
  426. }
  427. DWORD mineTID, parentTID;
  428. mineTID = GetWindowThreadProcessId(hwnd, NULL);
  429. parentTID = (hwndOwner) ? GetWindowThreadProcessId(hwndOwner, NULL) : mineTID;
  430. if (hwndOwner)
  431. {
  432. HWND *p;
  433. if (mineTID != parentTID) AttachThreadInput(parentTID, mineTID, TRUE);
  434. p = disabledList;
  435. if (IsWindowEnabled(hwndOwner))
  436. {
  437. *p = hwndOwner;
  438. p++;
  439. }
  440. FindAllOwnedWindows(hwndOwner, p, sizeof(disabledList)/sizeof(HWND) - (INT)(p - disabledList), FINDWND_ONLY_ENABLED);
  441. for (p = disabledList; *p != NULL; p++) { if (hwnd != *p) EnableWindow(*p, FALSE); }
  442. }
  443. AddModalHook(hwnd);
  444. msg.message = WM_NULL;
  445. while(MODAL_ACTIVE == pDlg->Modal)
  446. {
  447. if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
  448. {
  449. if (msg.message == WM_QUIT) break;
  450. else if (!CallMsgFilter(&msg, MSGF_DIALOGBOX) &&
  451. !IsDialogMessage(hwnd, &msg))
  452. {
  453. TranslateMessage(&msg);
  454. DispatchMessage(&msg);
  455. }
  456. }
  457. else if (MODAL_ACTIVE == pDlg->Modal) WaitMessage();
  458. }
  459. ReleaseModalHook(hwnd);
  460. rCode = pDlg->rCode;
  461. if (msg.message == WM_QUIT) PostQuitMessage((int)msg.wParam);
  462. if (hwndOwner)
  463. {
  464. if (mineTID != parentTID) AttachThreadInput(parentTID, mineTID, FALSE);
  465. for (HWND *p = disabledList; *p != NULL; p++) { if (hwnd != *p) EnableWindow(*p, TRUE); }
  466. SetActiveWindow(hwndOwner);
  467. }
  468. if (prc && !GetWindowRect(hwnd, prc)) SetRect(prc, 0, 0, 0,0);
  469. if(MODAL_EXIT != pDlg->Modal) DestroyWindow(hwnd);
  470. return rCode;
  471. }
  472. BOOL CddbProgressDlg_ExitModal(HWND hwnd, HRESULT rCode, BOOL bDesroy)
  473. {
  474. PROGRESSDLG *pDlg;
  475. if(!hwnd || !IsWindow(hwnd)) return FALSE;
  476. pDlg = GET_DATA(hwnd);
  477. if (!pDlg) return FALSE;
  478. if (MODAL_ACTIVE == pDlg->Modal)
  479. {
  480. pDlg->Modal = (bDesroy) ? MODAL_DESTROY : MODAL_EXIT;
  481. pDlg->rCode = rCode;
  482. PostMessageW(hwnd, WM_NULL, 0, 0);
  483. }
  484. return TRUE;
  485. }
  486. BOOL CddbProgressDlg_IsModal(HWND hwnd)
  487. {
  488. PROGRESSDLG *pDlg;
  489. if(!hwnd || !IsWindow(hwnd)) return FALSE;
  490. pDlg = GET_DATA(hwnd);
  491. return (pDlg && (MODAL_ACTIVE == pDlg->Modal));
  492. }
  493. INT CddbProgressDlg_GetSelRecordIndex(HWND hwnd)
  494. {
  495. HWND hwndList;
  496. if(!hwnd || !IsWindow(hwnd)) return -1;
  497. hwndList = GetDlgItem(hwnd, IDC_LV_EXT);
  498. if (!hwndList) return -1;
  499. return (INT)(INT_PTR)SendMessageW(hwndList, LVM_GETNEXTITEM, -1, (LPARAM)(LVNI_SELECTED | LVNI_FOCUSED));
  500. }
  501. BOOL CddbProgressDlg_SetUserData(HWND hwnd, HANDLE user)
  502. {
  503. PROGRESSDLG *pDlg;
  504. if(!hwnd || !IsWindow(hwnd)) return FALSE;
  505. pDlg = GET_DATA(hwnd);
  506. if (!pDlg) return FALSE;
  507. pDlg->user = user;
  508. return TRUE;
  509. }
  510. HANDLE CddbProgressDlg_GetUserData(HWND hwnd)
  511. {
  512. PROGRESSDLG *pDlg;
  513. if(!hwnd || !IsWindow(hwnd)) return NULL;
  514. pDlg = GET_DATA(hwnd);
  515. return (pDlg) ? pDlg->user : NULL;
  516. }
  517. static void InvalidateLogo(HWND hwnd, PROGRESSICON *pIcon)
  518. {
  519. RECT rc;
  520. SetRect(&rc, ICON_OFFSET_X, ICON_OFFSET_Y,
  521. ICON_OFFSET_X + (pIcon->rc.right - pIcon->rc.left),
  522. ICON_OFFSET_Y + (pIcon->rc.bottom - pIcon->rc.top));
  523. InvalidateRect(hwnd, &rc, TRUE);
  524. }
  525. static BOOL EnableWindowTheme(HWND hwnd, BOOL bEnable)
  526. {
  527. static HMODULE hModule = NULL;
  528. static BOOL firstTime = TRUE;
  529. static HRESULT (WINAPI *__setwintheme)(HWND, LPCWSTR, LPCWSTR) = NULL;
  530. if (!hModule)
  531. {
  532. if (!firstTime) return FALSE;
  533. firstTime = FALSE;
  534. hModule = LoadLibraryW(L"UxTheme.dll");
  535. if (!hModule) return FALSE;
  536. __setwintheme = (HRESULT (WINAPI *)(HWND, LPCWSTR, LPCWSTR))GetProcAddress(hModule, "SetWindowTheme");
  537. if (!__setwintheme)
  538. {
  539. FreeLibrary(hModule);
  540. hModule = NULL;
  541. return FALSE;
  542. }
  543. }
  544. return (S_OK == __setwintheme(hwnd, NULL, ((bEnable) ? NULL : L"")));
  545. }
  546. static HRESULT InitializeProgressIcon(PROGRESSICON *pIcon)
  547. {
  548. HRESULT hr;
  549. LONG/*_PTR*/ lVal; // benski> windows 64 isn't supported by gracenote
  550. ICddbUIOptions *pUIOptions;
  551. if (!pIcon) return E_INVALIDARG;
  552. ZeroMemory(pIcon, sizeof(PROGRESSICON));
  553. hr = Cddb_GetIUIOptions((void**)&pUIOptions);
  554. if (FAILED(hr)) return hr;
  555. hr = pUIOptions->GetCurrent(UI_DISP_PROGRESS);
  556. if (SUCCEEDED(hr))
  557. {
  558. if (SUCCEEDED(pUIOptions->get_ResourceHINSTANCE(&lVal))) pIcon->hInstance = (HINSTANCE)lVal;
  559. if (SUCCEEDED(pUIOptions->get_Left(&lVal))) pIcon->rc.left = (LONG)lVal;
  560. if (SUCCEEDED(pUIOptions->get_Top(&lVal))) pIcon->rc.top = (LONG)lVal;
  561. if (SUCCEEDED(pUIOptions->get_Right(&lVal))) pIcon->rc.right = (LONG)lVal;
  562. if (SUCCEEDED(pUIOptions->get_Bottom(&lVal))) pIcon->rc.bottom = (LONG)lVal;
  563. pUIOptions->get_ProgressResourceID(&pIcon->resId);
  564. pUIOptions->get_Frames(&pIcon->frames);
  565. }
  566. pUIOptions->Release();
  567. return hr;
  568. }
  569. static BOOL AnimateProgressIcon(HDC hdc, INT x, INT y, PROGRESSICON *pIcon)
  570. {
  571. INT w, h;
  572. HDC hdcDst;
  573. HBITMAP bmpOld;
  574. if (!hdc || !pIcon) return FALSE;
  575. if (!pIcon->hbmp)
  576. {
  577. if (pIcon->hInstance && pIcon->resId)
  578. {
  579. pIcon->hbmp = (HBITMAP)LoadImageW(pIcon->hInstance, MAKEINTRESOURCEW(pIcon->resId),
  580. IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE);
  581. }
  582. if (!pIcon->hbmp) return FALSE;
  583. }
  584. hdcDst = CreateCompatibleDC(hdc);
  585. bmpOld = (HBITMAP)SelectObject(hdcDst, pIcon->hbmp);
  586. w = pIcon->rc.right - pIcon->rc.left;
  587. h = pIcon->rc.bottom - pIcon->rc.top;
  588. BitBlt(hdc, x, y, w, h, hdcDst, pIcon->rc.left + (pIcon->step * w), pIcon->rc.top, SRCCOPY);
  589. SelectObject(hdcDst, bmpOld);
  590. DeleteDC(hdcDst);
  591. return TRUE;
  592. }
  593. static void CALLBACK ProgressDlg_OnTimer(HWND hwnd, UINT uMsg, UINT_PTR evntId, DWORD dwTime)
  594. {
  595. PROGRESSDLG *pDlg;
  596. pDlg = GET_DATA(hwnd);
  597. if (!pDlg) return;
  598. DWORD tclose;
  599. switch(evntId)
  600. {
  601. case TIMER_PROGRESS_ANIMATE_ID:
  602. InvalidateLogo(hwnd, &pDlg->icon);
  603. if (++pDlg->icon.step >= pDlg->icon.frames)
  604. {
  605. KillTimer(hwnd, evntId);
  606. pDlg->icon.step = pDlg->icon.frames - 1;
  607. }
  608. break;
  609. case TIMER_PROGRESS_DESTROY_ID:
  610. tclose = pDlg->dwAutoClose;
  611. if (dwTime >= tclose)
  612. {
  613. KillTimer(hwnd, evntId);
  614. EndProgressDialog(hwnd);
  615. }
  616. else
  617. {
  618. wchar_t szText[128] = {0};
  619. tclose = (tclose - dwTime)/1000 + ((((tclose - dwTime)%1000) > 500) ? 1 : 0);
  620. StringCchPrintfW(szText, sizeof(szText)/sizeof(wchar_t), L"%s (%d)", GET_SAFE_LANGSTRING1(MAKEINTRESOURCEW(IDS_CLOSE)), tclose);
  621. SetDlgItemTextW(hwnd, IDCANCEL, szText);
  622. }
  623. break;
  624. }
  625. }
  626. static BOOL EndProgressDialog(HWND hwnd)
  627. {
  628. PROGRESSDLG *pDlg;
  629. pDlg = GET_DATA(hwnd);
  630. if (!pDlg) return FALSE;
  631. if (MODAL_ACTIVE == pDlg->Modal)
  632. {
  633. pDlg->Modal = MODAL_DESTROY;
  634. PostMessageW(hwnd, WM_NULL, 0, 0);
  635. }
  636. else
  637. {
  638. DestroyWindow(hwnd);
  639. }
  640. return TRUE;
  641. }
  642. static INT_PTR ProgressDlg_OnDialogInit(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  643. {
  644. HWND hwndCtrl;
  645. PROGRESSDLG *pDlg(NULL);
  646. pDlg = (PROGRESSDLG*)calloc(1, sizeof(PROGRESSDLG));
  647. if (pDlg)
  648. {
  649. pDlg->uState = STATE_INACTIVE;
  650. if ((FAILED(InitializeProgressIcon(&pDlg->icon)) || !SetPropW(hwnd, PROP_PRGDLG, pDlg)))
  651. {
  652. free(pDlg);
  653. pDlg = NULL;
  654. DestroyWindow(hwnd);
  655. return TRUE;
  656. }
  657. }
  658. hwndCtrl = GetDlgItem(hwnd, IDC_PRG_STATUS);
  659. if (hwndCtrl)
  660. {
  661. RECT rc;
  662. EnableWindowTheme(hwndCtrl, FALSE);
  663. SetWindowLongPtrW(hwndCtrl, GWL_EXSTYLE, GetWindowLongPtrW(hwndCtrl, GWL_EXSTYLE) & ~WS_EX_STATICEDGE);
  664. GetWindowRect(hwndCtrl, &rc);
  665. SetWindowPos(hwndCtrl, NULL, 0, 0, rc.right - rc.left, 3, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
  666. SendMessageW(hwndCtrl, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
  667. SendMessageW(hwndCtrl, PBM_SETPOS, 0, 0L);
  668. SendMessageW(hwndCtrl, PBM_SETSTEP, 1, 0L);
  669. SendMessageW(hwndCtrl, PBM_SETBARCOLOR, 0, (LPARAM)GetSysColor(COLOR_WINDOW));
  670. SendMessageW(hwndCtrl, PBM_SETBKCOLOR, 0, (LPARAM)GetSysColor(COLOR_WINDOWTEXT));
  671. }
  672. hwndCtrl = GetDlgItem(hwnd, IDC_LBL_STATUS);
  673. if(hwndCtrl)
  674. {
  675. if (!hFont)
  676. {
  677. HFONT hf;
  678. LOGFONT lf;
  679. hf = (HFONT)SendMessageW(hwndCtrl, WM_GETFONT, 0, 0L);
  680. if (hf) hf = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
  681. if (hf && GetObject(hf, sizeof(LOGFONT), &lf))
  682. {
  683. HDC hdc = GetDC(hwndCtrl);
  684. lf.lfHeight = (hdc) ? -MulDiv(7, GetDeviceCaps(hdc, LOGPIXELSY), 72) : -9;
  685. lf.lfWeight = FW_THIN;
  686. lf.lfQuality = PROOF_QUALITY;
  687. StringCchCopy(lf.lfFaceName, sizeof(lf.lfFaceName)/sizeof(*lf.lfFaceName), L"Arial");
  688. hFont = CreateFontIndirect(&lf);
  689. if (hdc) ReleaseDC(hwnd, hdc);
  690. }
  691. }
  692. if (hFont)
  693. {
  694. SendMessageW(hwndCtrl, WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE);
  695. SendDlgItemMessageW(hwnd, IDC_LBL_REASON, WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE);
  696. fontRef++;
  697. }
  698. }
  699. if (NULL != (hwndCtrl = GetDlgItem(hwnd, IDC_LV_EXT)))
  700. {
  701. DWORD exstyle = LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP;
  702. SendMessageW(hwndCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, exstyle, exstyle);
  703. LVCOLUMNW column;
  704. column.mask = LVCF_WIDTH | LVCF_TEXT;
  705. column.cx = 120;
  706. column.pszText = L"Artist";
  707. SendMessageW(hwndCtrl, LVM_INSERTCOLUMNW, (WPARAM)0xEFFF, (LPARAM)&column);
  708. column.cx = 160;
  709. column.pszText = L"Album";
  710. SendMessageW(hwndCtrl, LVM_INSERTCOLUMNW, (WPARAM)0xEFFF, (LPARAM)&column);
  711. column.cx = 40;
  712. column.pszText = L"Language";
  713. SendMessageW(hwndCtrl, LVM_INSERTCOLUMNW, (WPARAM)0xEFFF, (LPARAM)&column);
  714. }
  715. return TRUE;
  716. }
  717. static void ProgressDlg_OnDestroy(HWND hwnd)
  718. {
  719. PROGRESSDLG *pDlg;
  720. pDlg = GET_DATA(hwnd);
  721. if (pDlg)
  722. {
  723. RemovePropW(hwnd, PROP_PRGDLG);
  724. if (pDlg->icon.hbmp) DeleteObject(pDlg->icon.hbmp);
  725. if (pDlg->Btn1Data) SysFreeString(pDlg->Btn1Data);
  726. if (pDlg->AbortData) SysFreeString(pDlg->AbortData);
  727. free(pDlg);
  728. pDlg = NULL;
  729. }
  730. if (fontRef && 0 == --fontRef)
  731. {
  732. DeleteObject(hFont);
  733. hFont = NULL;
  734. }
  735. }
  736. static void ProgressDlg_OnCommand(HWND hwnd, WORD ctrlId, WORD evntId, HWND hwndCtrl)
  737. {
  738. PROGRESSDLG *pDlg;
  739. pDlg = GET_DATA(hwnd);
  740. if (!pDlg) return;
  741. switch(ctrlId)
  742. {
  743. case IDCANCEL:
  744. pDlg->rCode = S_FALSE;
  745. switch(pDlg->uState)
  746. {
  747. case STATE_ACTIVE:
  748. if (!pDlg->OnAbort) return;
  749. SetWindowTextW(hwndCtrl, WASABI_API_LNGSTRINGW(IDS_ABORTING));
  750. EnableWindow(hwndCtrl, FALSE);
  751. pDlg->uState = STATE_ABORTING;
  752. pDlg->OnAbort(hwnd, pDlg->AbortData);
  753. return;
  754. case STATE_ABORTING: return; // don't do anything
  755. }
  756. ;
  757. EndProgressDialog(hwnd);
  758. break;
  759. case IDC_BUTTON1:
  760. if (BN_CLICKED == evntId)
  761. {
  762. if (pDlg->OnButton1) pDlg->OnButton1(hwnd, pDlg->Btn1Data);
  763. }
  764. break;
  765. }
  766. }
  767. static void ProgressDlg_OnErase(HWND hwnd, HDC hdc)
  768. {
  769. PROGRESSDLG *pDlg;
  770. if (NULL != (pDlg = GET_DATA(hwnd)))
  771. {
  772. RECT rc;
  773. SetRect(&rc, ICON_OFFSET_X, ICON_OFFSET_Y,
  774. ICON_OFFSET_X + (pDlg->icon.rc.right - pDlg->icon.rc.left),
  775. ICON_OFFSET_Y + (pDlg->icon.rc.bottom - pDlg->icon.rc.top));
  776. if (RectVisible(hdc, &rc))
  777. {
  778. if (AnimateProgressIcon(hdc, ICON_OFFSET_X, ICON_OFFSET_Y, &pDlg->icon))
  779. ExcludeClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
  780. }
  781. }
  782. }
  783. static void ProgressDlg_OnLButtonDown(HWND hwnd, DWORD wKey, POINTS pts)
  784. {
  785. PROGRESSDLG *pDlg = GET_DATA(hwnd);
  786. if (pDlg)
  787. {
  788. POINT pt;
  789. RECT rc;
  790. POINTSTOPOINT(pt, pts);
  791. SetRect(&rc, ICON_OFFSET_X, ICON_OFFSET_Y,
  792. ICON_OFFSET_X + (pDlg->icon.rc.right - pDlg->icon.rc.left),
  793. ICON_OFFSET_Y + (pDlg->icon.rc.bottom - pDlg->icon.rc.top));
  794. if (PtInRect(&rc, pt)) SendMessageW(line.hMainWindow, WM_WA_IPC, (WPARAM)L"http://www.cddb.com/", IPC_OPEN_URL);
  795. }
  796. }
  797. static INT_PTR ProgressDlg_OnSetCursor(HWND hwnd, HWND hwndCursor, WORD htCode, WORD msgId)
  798. {
  799. PROGRESSDLG *pDlg = GET_DATA(hwnd);
  800. if (pDlg)
  801. {
  802. RECT rc;
  803. POINT pt;
  804. GetCursorPos(&pt);
  805. MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);
  806. SetRect(&rc, ICON_OFFSET_X, ICON_OFFSET_Y,
  807. ICON_OFFSET_X + (pDlg->icon.rc.right - pDlg->icon.rc.left),
  808. ICON_OFFSET_Y + (pDlg->icon.rc.bottom - pDlg->icon.rc.top));
  809. if (PtInRect(&rc, pt)) return (NULL != SetCursor(LoadCursor(NULL, IDC_HAND)));
  810. }
  811. return FALSE;
  812. }
  813. static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  814. {
  815. switch (uMsg)
  816. {
  817. case WM_INITDIALOG: return ProgressDlg_OnDialogInit(hwndDlg, (HWND)wParam, lParam);
  818. case WM_DESTROY: ProgressDlg_OnDestroy(hwndDlg); break;
  819. case WM_COMMAND: ProgressDlg_OnCommand(hwndDlg, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); break;
  820. case WM_ERASEBKGND: ProgressDlg_OnErase(hwndDlg, (HDC)wParam); break;
  821. case WM_LBUTTONDOWN: ProgressDlg_OnLButtonDown(hwndDlg, (DWORD)wParam, MAKEPOINTS(lParam)); break;
  822. case WM_SETCURSOR: return ProgressDlg_OnSetCursor(hwndDlg, (HWND)wParam, LOWORD(lParam), HIWORD(lParam));
  823. }
  824. return 0;
  825. }
  826. static BOOL CALLBACK EnumWnd_OnNextWindow(HWND hwnd, LPARAM lParam)
  827. {
  828. ENUMWND_DATAPACK *pData = (ENUMWND_DATAPACK*)lParam;
  829. if (!pData) return FALSE;
  830. if (!pData->found)
  831. {
  832. if (pData->host == hwnd) pData->found = TRUE;
  833. // return TRUE;
  834. }
  835. ULONG_PTR style = GetWindowLongPtrW(hwnd, GWL_STYLE);
  836. if (0 == (WS_CHILD & style) &&
  837. (0 == (FINDWND_ONLY_VISIBLE & pData->flags) || (WS_VISIBLE & style)) &&
  838. (0 == (FINDWND_ONLY_ENABLED & pData->flags) || 0 == (WS_DISABLED & style)))
  839. {
  840. HWND hwndOwner = GetWindow(hwnd, GW_OWNER);
  841. if (pData->host == hwndOwner)
  842. {
  843. if (pData->index == pData->count) return FALSE; ///
  844. pData->list[pData->index] = hwnd;
  845. pData->index++;
  846. }
  847. }
  848. return TRUE;
  849. }
  850. BOOL FindAllOwnedWindows(HWND hwndHost, HWND *hwndList, INT cList, UINT flags)
  851. {
  852. BOOL br;
  853. ENUMWND_DATAPACK data;
  854. ZeroMemory(&data, sizeof(ENUMWND_DATAPACK));
  855. if (!hwndHost || !hwndList) return FALSE;
  856. data.host = hwndHost;
  857. data.list = hwndList;
  858. data.count = cList;
  859. data.flags = flags;
  860. data.list[0] = NULL;
  861. br = EnumWindows(EnumWnd_OnNextWindow, (LPARAM)&data);
  862. data.list[data.index] = NULL;
  863. return br;
  864. }