setupRecord.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. #include "./main.h"
  2. #include "../api__ml_online.h"
  3. #include "./setupRecord.h"
  4. #include "./setupDetails.h"
  5. #include "./setupLog.h"
  6. #include "../resource.h"
  7. #include "./serviceHelper.h"
  8. #include "./serviceHost.h"
  9. #include <ifc_omservice.h>
  10. #include <ifc_omwebstorage.h>
  11. #include <ifc_omserviceenum.h>
  12. #include <ifc_omservicecopier.h>
  13. #include <wininet.h>
  14. #include <strsafe.h>
  15. #define RECORD_MARGINCX 6
  16. #define RECORD_MARGINCY 2
  17. #define CHECKBOX_MARGIN_RIGHT 2
  18. #define TEXT_OFFSET_LEFT 3
  19. #define TEXT_OFFSET_BOTTOM RECORD_MARGINCY
  20. #define TEXT_ALIGN (TA_LEFT | TA_BOTTOM)
  21. SetupRecord::SetupRecord(ifc_omservice *serviceToUse)
  22. : ref(1), service(serviceToUse), flags(0), async(NULL)
  23. {
  24. if (NULL != service)
  25. {
  26. if (S_OK == ServiceHelper_IsSubscribed(service))
  27. flags |= recordSelected;
  28. service->AddRef();
  29. }
  30. InitializeCriticalSection(&lock);
  31. }
  32. SetupRecord::~SetupRecord()
  33. {
  34. EnterCriticalSection(&lock);
  35. if (NULL != async)
  36. {
  37. ifc_omstorage *storage = NULL;
  38. HRESULT hr = OMSERVICEMNGR->QueryStorage(&SUID_OmStorageUrl, &storage);
  39. if (SUCCEEDED(hr) && storage != NULL)
  40. {
  41. storage->RequestAbort(async, TRUE);
  42. }
  43. async->Release();
  44. async = NULL;
  45. }
  46. if (NULL != service)
  47. service->Release();
  48. LeaveCriticalSection(&lock);
  49. DeleteCriticalSection(&lock);
  50. }
  51. SetupRecord *SetupRecord::CreateInstance(ifc_omservice *serviceToUse)
  52. {
  53. if (NULL == serviceToUse) return NULL;
  54. return new SetupRecord(serviceToUse);
  55. }
  56. ULONG SetupRecord::AddRef()
  57. {
  58. return InterlockedIncrement((LONG*)&ref);
  59. }
  60. ULONG SetupRecord::Release()
  61. {
  62. if (0 == ref)
  63. return ref;
  64. LONG r = InterlockedDecrement((LONG*)&ref);
  65. if (0 == r)
  66. delete(this);
  67. return r;
  68. }
  69. HRESULT SetupRecord::GetServiceName(LPWSTR pszBuffer, UINT cchBufferMax)
  70. {
  71. if (NULL == service) return E_UNEXPECTED;
  72. return service->GetName(pszBuffer, cchBufferMax);
  73. }
  74. HRESULT SetupRecord::GetDisplayName(LPWSTR pszBuffer, UINT cchBufferMax)
  75. {
  76. HRESULT hr = GetServiceName(pszBuffer, cchBufferMax);
  77. if (SUCCEEDED(hr) && L'\0' == *pszBuffer)
  78. {
  79. WASABI_API_LNGSTRINGW_BUF(IDS_DEFAULT_SERVICENAME, pszBuffer, cchBufferMax);
  80. DownloadDetails();
  81. }
  82. return hr;
  83. }
  84. HRESULT SetupRecord::DownloadDetails()
  85. {
  86. HRESULT hr;
  87. EnterCriticalSection(&lock);
  88. if (NULL == async && 0 == (recordDownloaded & flags))
  89. {
  90. WCHAR szUrl[INTERNET_MAX_URL_LENGTH] = {0};
  91. hr = ServiceHelper_GetDetailsUrl(szUrl, ARRAYSIZE(szUrl), service, FALSE);
  92. if (SUCCEEDED(hr))
  93. {
  94. ifc_omstorage *storage = NULL;
  95. hr = OMSERVICEMNGR->QueryStorage(&SUID_OmStorageUrl, &storage);
  96. if (SUCCEEDED(hr) && storage != NULL)
  97. {
  98. ServiceHost *serviceHost = NULL;
  99. if (FAILED(ServiceHost::GetCachedInstance(&serviceHost)))
  100. serviceHost = NULL;
  101. hr = storage->BeginLoad(szUrl, serviceHost, SetupRecord_ServiceDownloadedCallback, this, &async);
  102. storage->Release();
  103. if (NULL != serviceHost)
  104. serviceHost->Release();
  105. }
  106. }
  107. }
  108. else
  109. {
  110. hr = S_FALSE;
  111. }
  112. LeaveCriticalSection(&lock);
  113. return hr;
  114. }
  115. HRESULT SetupRecord::Save(SetupLog *log)
  116. {
  117. if (NULL == service) return E_POINTER;
  118. HRESULT hr = ServiceHelper_Subscribe(service, IsSelected(), SHF_SAVE);
  119. if (S_OK == hr)
  120. {
  121. if (NULL != log)
  122. {
  123. INT operation = (IsSelected()) ? SetupLog::opServiceAdded : SetupLog::opServiceRemoved;
  124. log->LogService(service, operation);
  125. }
  126. }
  127. return hr;
  128. }
  129. BOOL SetupRecord::IsModified()
  130. {
  131. if (NULL == service)
  132. return FALSE;
  133. if (S_OK == ServiceHelper_IsSubscribed(service) != (FALSE != IsSelected()))
  134. return TRUE;
  135. if (S_OK == ServiceHelper_IsModified(service))
  136. return TRUE;
  137. return FALSE;
  138. }
  139. BOOL SetupRecord::IsSelected()
  140. {
  141. return (0 != (recordSelected & flags));
  142. }
  143. void SetupRecord::SetSelected(BOOL fSelected)
  144. {
  145. if ((FALSE == fSelected) == !IsSelected())
  146. return;
  147. if (FALSE == fSelected)
  148. flags &= ~recordSelected;
  149. else
  150. flags |= recordSelected;
  151. }
  152. BOOL SetupRecord::AdjustCheckboxRect(SetupListbox *instance, RECT *prcItem)
  153. {
  154. SIZE checkSize;
  155. if (!instance->GetCheckboxMetrics(NULL, IsSelected(), 0, &checkSize))
  156. return FALSE;
  157. prcItem->left += RECORD_MARGINCX;
  158. prcItem->right = prcItem->left + checkSize.cx;
  159. if (checkSize.cy > (prcItem->bottom - prcItem->top))
  160. checkSize.cy = (prcItem->bottom - prcItem->top);
  161. prcItem->top += ((prcItem->bottom - prcItem->top) - checkSize.cy) / 2;
  162. prcItem->bottom = prcItem->top + checkSize.cy;
  163. return TRUE;
  164. }
  165. BOOL SetupRecord::MeasureItem(SetupListbox *instance, UINT *cx, UINT *cy)
  166. {
  167. HDC hdc = GetDCEx(instance->GetHwnd(), NULL, DCX_CACHE | DCX_NORESETATTRS);
  168. if (NULL == hdc) return FALSE;
  169. HFONT originalFont = (HFONT)SelectObject(hdc, instance->GetFont());
  170. SIZE checkSize;
  171. instance->GetCheckboxMetrics(hdc, IsSelected(), 0, &checkSize);
  172. if (NULL != cy)
  173. {
  174. *cy = 0;
  175. TEXTMETRIC tm = {0};
  176. if (GetTextMetrics(hdc, &tm))
  177. {
  178. *cy = tm.tmHeight + tm.tmExternalLeading;
  179. if (checkSize.cy > (INT)*cy) *cy = checkSize.cy;
  180. *cy += RECORD_MARGINCY*2;
  181. }
  182. }
  183. if (NULL != cx)
  184. {
  185. *cx = checkSize.cx;
  186. WCHAR szBuffer[128] = {0};
  187. if (SUCCEEDED(GetDisplayName(szBuffer, ARRAYSIZE(szBuffer))))
  188. {
  189. INT cchBuffer = lstrlenW(szBuffer);
  190. SIZE textSize;
  191. if (0 != cchBuffer && GetTextExtentPoint32(hdc, szBuffer, cchBuffer, &textSize))
  192. {
  193. *cx += textSize.cx;
  194. if (0 != checkSize.cx)
  195. *cx += CHECKBOX_MARGIN_RIGHT + RECORD_MARGINCX;
  196. }
  197. }
  198. if (0 != *cx) *cx += RECORD_MARGINCX*2;
  199. }
  200. SelectObject(hdc, originalFont);
  201. ReleaseDC(instance->GetHwnd(), hdc);
  202. return TRUE;
  203. }
  204. void SetupRecord::GetColors(HDC hdc, UINT state, COLORREF *rgbBkOut, COLORREF *rgbTextOut)
  205. {
  206. COLORREF rgbBk, rgbText;
  207. if (0 != (ODS_DISABLED & state))
  208. {
  209. rgbBk = GetBkColor(hdc);
  210. rgbText = GetSysColor(COLOR_GRAYTEXT);
  211. }
  212. else if (0 != (ODS_SELECTED & state))
  213. {
  214. if (0 == (ODS_INACTIVE & state))
  215. {
  216. rgbBk = GetSysColor(COLOR_HIGHLIGHT);
  217. rgbText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  218. }
  219. else
  220. {
  221. rgbBk = GetSysColor(COLOR_3DFACE);
  222. rgbText = GetTextColor(hdc);
  223. }
  224. }
  225. else
  226. {
  227. rgbBk = GetBkColor(hdc);
  228. rgbText = GetTextColor(hdc);
  229. }
  230. if (NULL != rgbBkOut) *rgbBkOut = rgbBk;
  231. if (NULL != rgbTextOut) *rgbTextOut = rgbText;
  232. }
  233. BOOL SetupRecord::DrawItem(SetupListbox *instance, HDC hdc, const RECT *prc, UINT state)
  234. {
  235. LONG paintLeft = prc->left + RECORD_MARGINCX;
  236. RECT partRect;
  237. UINT checkState = state & ~ODS_SELECTED;
  238. if (0 == (checkboxPressed & flags))
  239. {
  240. if (0 != (checkboxHighlighted & flags))
  241. checkState |= ODS_HOTLIGHT;
  242. }
  243. else
  244. {
  245. checkState |= ((0 != (checkboxHighlighted & flags)) ? ODS_SELECTED : ODS_HOTLIGHT);
  246. }
  247. HRGN backRgn, rgn;
  248. backRgn = CreateRectRgnIndirect(prc);
  249. rgn = CreateRectRgn(0,0,0,0);
  250. SetRectEmpty(&partRect);
  251. instance->GetCheckboxMetrics(hdc, IsSelected(), checkState, (((SIZE*)&partRect) + 1));
  252. INT space = (prc->bottom - prc->top) - (partRect.bottom- partRect.top);
  253. INT offsetY = space / 2 + space%2;
  254. if (offsetY < 0) offsetY = 0;
  255. OffsetRect(&partRect, paintLeft, prc->top + offsetY);
  256. if (instance->DrawCheckbox(hdc, IsSelected(), checkState, &partRect, prc))
  257. {
  258. paintLeft = partRect.right + CHECKBOX_MARGIN_RIGHT;
  259. if (SetRectRgn(rgn, partRect.left, partRect.top, partRect.right, partRect.bottom))
  260. CombineRgn(backRgn, backRgn, rgn, RGN_DIFF);
  261. }
  262. COLORREF rgbBk, rgbText;
  263. GetColors(hdc, state, &rgbBk, &rgbText);
  264. COLORREF origBk = SetBkColor(hdc, rgbBk);
  265. COLORREF origText = SetTextColor(hdc, rgbText);
  266. UINT textAlign = SetTextAlign(hdc, TEXT_ALIGN);
  267. WCHAR szBuffer[128] = {0};
  268. INT cchBuffer = 0;
  269. if (SUCCEEDED(GetDisplayName(szBuffer, ARRAYSIZE(szBuffer))))
  270. cchBuffer = lstrlenW(szBuffer);
  271. SetRect(&partRect, paintLeft, prc->top, prc->right, prc->bottom);
  272. if (ExtTextOut(hdc, partRect.left + TEXT_OFFSET_LEFT, partRect.bottom - TEXT_OFFSET_BOTTOM,
  273. ETO_OPAQUE | ETO_CLIPPED, &partRect, szBuffer, cchBuffer, NULL))
  274. {
  275. if (SetRectRgn(rgn, partRect.left, partRect.top, partRect.right, partRect.bottom))
  276. CombineRgn(backRgn, backRgn, rgn, RGN_DIFF);
  277. }
  278. if (ODS_FOCUS == ((ODS_FOCUS | 0x0200/*ODS_NOFOCUSRECT*/) & state))
  279. DrawFocusRect(hdc, &partRect);
  280. if (NULL != backRgn)
  281. {
  282. PaintRgn(hdc, backRgn);
  283. DeleteObject(backRgn);
  284. }
  285. if (NULL != rgn)
  286. DeleteObject(rgn);
  287. if (TEXT_ALIGN != textAlign) SetTextAlign(hdc, textAlign);
  288. if (origBk != rgbBk) SetBkColor(hdc, origBk);
  289. if (origText != rgbText) SetTextColor(hdc, origText);
  290. return TRUE;
  291. }
  292. INT_PTR SetupRecord::KeyToItem(SetupListbox *instance, const RECT *prcItem, INT vKey)
  293. {
  294. switch(vKey)
  295. {
  296. case VK_SPACE:
  297. InvertCheckbox(instance, prcItem);
  298. return -2;
  299. }
  300. return -1;
  301. }
  302. BOOL SetupRecord::MouseMove(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt)
  303. {
  304. RECT checkboxRect;
  305. BOOL fInvalidate = FALSE;
  306. CopyRect(&checkboxRect, prcItem);
  307. AdjustCheckboxRect(instance, &checkboxRect);
  308. if (prcItem->top <= pt.y && pt.y < prcItem->bottom &&
  309. checkboxRect.left <= pt.x && pt.x < checkboxRect.right)
  310. {
  311. if (0 == (checkboxHighlighted & flags))
  312. {
  313. flags |= checkboxHighlighted;
  314. fInvalidate = TRUE;
  315. }
  316. }
  317. else
  318. {
  319. if (0 != (checkboxHighlighted & flags))
  320. {
  321. flags &= ~checkboxHighlighted;
  322. fInvalidate = TRUE;
  323. }
  324. }
  325. if (FALSE != fInvalidate)
  326. instance->InvalidateRect(&checkboxRect, FALSE);
  327. return FALSE;
  328. }
  329. BOOL SetupRecord::MouseLeave(SetupListbox *instance, const RECT *prcItem)
  330. {
  331. if (0 != (checkboxHighlighted & flags))
  332. {
  333. flags &= ~checkboxHighlighted;
  334. RECT checkboxRect;
  335. CopyRect(&checkboxRect, prcItem);
  336. AdjustCheckboxRect(instance, &checkboxRect);
  337. instance->InvalidateRect(&checkboxRect, FALSE);
  338. }
  339. return FALSE;
  340. }
  341. BOOL SetupRecord::LButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt)
  342. {
  343. RECT checkboxRect;
  344. BOOL handled = FALSE;
  345. CopyRect(&checkboxRect, prcItem);
  346. AdjustCheckboxRect(instance, &checkboxRect);
  347. if (prcItem->top <= pt.y && pt.y < prcItem->bottom &&
  348. prcItem->left <= pt.x && pt.x < (checkboxRect.right + CHECKBOX_MARGIN_RIGHT))
  349. {
  350. handled = TRUE;
  351. if (checkboxRect.left <= pt.x && pt.x < checkboxRect.right)
  352. {
  353. flags |= (checkboxHighlighted | checkboxPressed);
  354. instance->SetCapture(this);
  355. instance->InvalidateRect(&checkboxRect, FALSE);
  356. }
  357. }
  358. return handled;
  359. }
  360. BOOL SetupRecord::LButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt)
  361. {
  362. RECT checkboxRect;
  363. BOOL handled = FALSE;
  364. CopyRect(&checkboxRect, prcItem);
  365. AdjustCheckboxRect(instance, &checkboxRect);
  366. if (0 != (checkboxPressed & flags))
  367. {
  368. flags &= ~checkboxPressed;
  369. if (this == instance->GetCapture())
  370. instance->ReleaseCapture();
  371. if (prcItem->top <= pt.y && pt.y < prcItem->bottom &&
  372. checkboxRect.left <= pt.x && pt.x < checkboxRect.right)
  373. {
  374. SetSelected(!IsSelected());
  375. handled = TRUE;
  376. }
  377. instance->InvalidateRect(&checkboxRect, FALSE);
  378. }
  379. return handled;
  380. }
  381. BOOL SetupRecord::LButtonDblClk(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt)
  382. {
  383. InvertCheckbox(instance, prcItem);
  384. return TRUE;
  385. }
  386. BOOL SetupRecord::RButtonDown(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt)
  387. {
  388. return FALSE;
  389. }
  390. BOOL SetupRecord::RButtonUp(SetupListbox *instance, const RECT *prcItem, UINT mouseFlags, POINT pt)
  391. {
  392. return FALSE;
  393. }
  394. void SetupRecord::CaptureChanged(SetupListbox *instance, const RECT *prcItem, SetupListboxItem *captured)
  395. {
  396. }
  397. void SetupRecord::InvertCheckbox(SetupListbox *instance, const RECT *prcItem)
  398. {
  399. SetSelected(!IsSelected());
  400. if (NULL != instance && NULL != prcItem)
  401. {
  402. RECT checkboxRect;
  403. CopyRect(&checkboxRect, prcItem);
  404. AdjustCheckboxRect(instance, &checkboxRect);
  405. instance->InvalidateRect(&checkboxRect, FALSE);
  406. }
  407. }
  408. HWND SetupRecord::CreateDetailsView(HWND hParent)
  409. {
  410. DownloadDetails();
  411. WCHAR szName[64] = {0};
  412. if (FALSE == GetUniqueName(szName, ARRAYSIZE(szName)))
  413. szName[0] = L'\0';
  414. return SetupDetails_CreateServiceView(hParent, szName, service);
  415. }
  416. BOOL SetupRecord::GetUniqueName(LPWSTR pszBuffer, UINT cchBufferMax)
  417. {
  418. if (NULL == pszBuffer ||
  419. FAILED(StringCchPrintf(pszBuffer, cchBufferMax, L"record_svc_%u", service->GetId())))
  420. {
  421. return FALSE;
  422. }
  423. return TRUE;
  424. }
  425. void SetupRecord::OnDownloadCompleted()
  426. {
  427. ifc_omstorage *storage = NULL;
  428. HRESULT hr = OMSERVICEMNGR->QueryStorage(&SUID_OmStorageUrl, &storage);
  429. if (SUCCEEDED(hr) && service != NULL)
  430. {
  431. ifc_omserviceenum *serviceEnum = NULL;
  432. hr = storage->EndLoad(async, &serviceEnum);
  433. if (SUCCEEDED(hr) && serviceEnum != NULL)
  434. {
  435. EnterCriticalSection(&lock);
  436. ifc_omservice *result = NULL;
  437. while(S_OK == serviceEnum->Next(1, &result, NULL))
  438. {
  439. if (result)
  440. {
  441. if (result->GetId() == service->GetId())
  442. {
  443. ifc_omservicecopier *copier;
  444. if (SUCCEEDED(result->QueryInterface(IFC_OmServiceCopier, (void**)&copier)))
  445. {
  446. copier->CopyTo(service, NULL);
  447. copier->Release();
  448. }
  449. result->Release();
  450. flags |= recordDownloaded;
  451. break;
  452. }
  453. else
  454. {
  455. result->Release();
  456. }
  457. }
  458. result = NULL;
  459. }
  460. LeaveCriticalSection(&lock);
  461. serviceEnum->Release();
  462. }
  463. storage->Release();
  464. }
  465. EnterCriticalSection(&lock);
  466. async->Release();
  467. async = NULL;
  468. LeaveCriticalSection(&lock);
  469. }
  470. void CALLBACK SetupRecord_ServiceDownloadedCallback(ifc_omstorageasync *result)
  471. {
  472. if (NULL == result) return;
  473. SetupRecord *record = NULL;
  474. if (SUCCEEDED(result->GetData((void**)&record)) && NULL != record)
  475. {
  476. record->OnDownloadCompleted();
  477. }
  478. }