1
0

setupPage.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. #include "./setupPage.h"
  2. #include "./setupListbox.h"
  3. #include "./setupGroupList.h"
  4. #include "./setupGroupFilter.h"
  5. #include "./setupListboxLabel.h"
  6. #include "../common.h"
  7. #include "../config.h"
  8. #include "../resource.h"
  9. #include "../api__ml_online.h"
  10. #include "./setupDetails.h"
  11. #include "./setupLog.h"
  12. #include "../../winamp/setup/svc_setup.h"
  13. #include <ifc_omservice.h>
  14. #include <ifc_omfilestorage.h>
  15. #include <ifc_omwebstorage.h>
  16. #include <windows.h>
  17. #include <strsafe.h>
  18. #include <vector>
  19. #define FEATURED_SERVICES_URL L"http://services.winamp.com/svc/default"
  20. #define IDC_DETAILS 10000
  21. typedef std::vector<ifc_omservice*> ServiceList;
  22. typedef std::vector<UINT> ServiceIdList;
  23. HWND SetupPage_CreateWindow(HWND hParent, SetupPage *page);
  24. static INT_PTR SetupPage_ModalLoop(HWND hwnd, HACCEL hAccel, HANDLE hCancel);
  25. struct AppendServiceToStringData
  26. {
  27. AppendServiceToStringData() : formatFirst(NULL), formatNext(NULL), cursor(NULL),
  28. remaining(0), inserted(0), result(S_OK) {}
  29. LPCWSTR formatFirst;
  30. LPCWSTR formatNext;
  31. LPWSTR cursor;
  32. size_t remaining;
  33. size_t inserted;
  34. HRESULT result;
  35. };
  36. static BOOL CALLBACK SetupPage_AppendServiceToStringCallback(UINT serviceId, void *data)
  37. {
  38. AppendServiceToStringData *param = (AppendServiceToStringData*)data;
  39. if (NULL == param) return FALSE;
  40. param->result = StringCchPrintfEx(param->cursor, param->remaining, &param->cursor, &param->remaining,
  41. STRSAFE_NULL_ON_FAILURE,
  42. ((0 == param->inserted) ? param->formatFirst : param->formatNext), serviceId);
  43. if (FAILED(param->result))
  44. return FALSE;
  45. param->inserted++;
  46. return TRUE;
  47. }
  48. static BOOL CALLBACK SetupPage_AppendServiceIdCallback(UINT serviceId, void *data)
  49. {
  50. ServiceIdList *list = (ServiceIdList*)data;
  51. if (NULL == list) return FALSE;
  52. list->push_back(serviceId);
  53. return TRUE;
  54. }
  55. static HRESULT SetupPage_GetFeaturedServicesUrl(LPWSTR pszBuffer, UINT cchBufferMax)
  56. {
  57. LPWSTR cursor = pszBuffer;
  58. size_t remaining = cchBufferMax;
  59. HRESULT hr = StringCchCopyEx(cursor, remaining, FEATURED_SERVICES_URL, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  60. if (FAILED(hr))
  61. return hr;
  62. AppendServiceToStringData param;
  63. param.cursor = cursor;
  64. param.remaining = remaining;
  65. param.formatFirst = L"?svc_ids=%u";
  66. param.formatNext = L",%u";
  67. param.inserted = 0;
  68. param.result = S_OK;
  69. hr = Config_ReadServiceIdList("Setup", "featuredExtra", ',', SetupPage_AppendServiceToStringCallback, &param);
  70. if (SUCCEEDED(hr))
  71. hr = param.result;
  72. return hr;
  73. }
  74. SetupPage* SetupPage::CreateInstance()
  75. {
  76. SetupPage *instance = new SetupPage();
  77. return instance;
  78. }
  79. SetupPage::SetupPage()
  80. : ref(1), hwnd(NULL), name(NULL), title(NULL),
  81. groupList(NULL), completeEvent(NULL),
  82. servicesInitialized(FALSE)
  83. {
  84. WasabiApi_AddRef();
  85. SetupDetails_Initialize();
  86. }
  87. SetupPage::~SetupPage()
  88. {
  89. if (NULL != name)
  90. {
  91. Plugin_FreeString(name);
  92. name = NULL;
  93. }
  94. if (NULL != title)
  95. {
  96. Plugin_FreeString(title);
  97. title = NULL;
  98. }
  99. if (NULL != groupList)
  100. {
  101. groupList->Release();
  102. groupList = NULL;
  103. }
  104. if (NULL != completeEvent)
  105. {
  106. CloseHandle(completeEvent);
  107. completeEvent = NULL;
  108. }
  109. SetupDetails_Uninitialize();
  110. if (FALSE != servicesInitialized)
  111. {
  112. if (NULL != OMBROWSERMNGR)
  113. OMBROWSERMNGR->Finish();
  114. }
  115. WasabiApi_Release();
  116. }
  117. size_t SetupPage::AddRef()
  118. {
  119. return InterlockedIncrement((LONG*)&ref);
  120. }
  121. size_t SetupPage::Release()
  122. {
  123. if (0 == ref)
  124. return ref;
  125. LONG r = InterlockedDecrement((LONG*)&ref);
  126. if (0 == r)
  127. delete(this);
  128. return r;
  129. }
  130. int SetupPage::QueryInterface(GUID interface_guid, void **object)
  131. {
  132. if (NULL == object) return E_POINTER;
  133. return E_NOTIMPL;
  134. }
  135. HRESULT SetupPage::GetName(bool bShort, const wchar_t **pszName)
  136. {
  137. InitializeServices();
  138. if (false == bShort)
  139. {
  140. if (NULL == title)
  141. {
  142. WCHAR szBuffer[128] = {0};
  143. WASABI_API_LNGSTRINGW_BUF(IDS_SETUPPAGE_TITLE, szBuffer, ARRAYSIZE(szBuffer));
  144. title = Plugin_CopyString(szBuffer);
  145. }
  146. *pszName = title;
  147. }
  148. else
  149. {
  150. if (NULL == name)
  151. {
  152. WCHAR szBuffer[128] = {0};
  153. WASABI_API_LNGSTRINGW_BUF(IDS_ONLINE_SERVICES, szBuffer, ARRAYSIZE(szBuffer));
  154. name = Plugin_CopyString(szBuffer);
  155. }
  156. *pszName = name;
  157. }
  158. return S_OK;
  159. }
  160. HRESULT SetupPage::Save(HWND hwndText)
  161. {
  162. if (NULL == groupList)
  163. return S_OK;
  164. SetupLog *log = SetupLog::Open();
  165. HRESULT hr = groupList->Save(log);
  166. if (NULL != log)
  167. {
  168. log->Save();
  169. log->Release();
  170. }
  171. return hr;
  172. }
  173. HRESULT SetupPage::Revert(void)
  174. {
  175. HRESULT hr(S_OK);
  176. if (NULL != groupList)
  177. {
  178. groupList->Release();
  179. groupList = NULL;
  180. }
  181. return hr;
  182. }
  183. HRESULT SetupPage::IsDirty(void)
  184. {
  185. return (NULL != groupList && groupList->IsModified()) ? S_OK : S_FALSE;
  186. }
  187. HRESULT SetupPage::Validate(void)
  188. {
  189. return S_OK;
  190. }
  191. HRESULT SetupPage::InitializeServices()
  192. {
  193. if (FALSE != servicesInitialized)
  194. return S_FALSE;
  195. HWND hWinamp = NULL;
  196. svc_setup *setupSvc = QueryWasabiInterface(svc_setup, UID_SVC_SETUP);
  197. if (NULL == setupSvc) return E_UNEXPECTED;
  198. HRESULT hr = setupSvc->GetWinampWnd(&hWinamp);
  199. ReleaseWasabiInterface(UID_SVC_SETUP, setupSvc);
  200. if (SUCCEEDED(hr))
  201. {
  202. hr = WasabiApi_LoadDefaults();
  203. if (SUCCEEDED(hr))
  204. {
  205. if (NULL != OMBROWSERMNGR &&
  206. NULL != OMSERVICEMNGR &&
  207. NULL != OMUTILITY)
  208. {
  209. hr = OMBROWSERMNGR->Initialize(NULL, hWinamp);
  210. }
  211. else
  212. hr = E_UNEXPECTED;
  213. if (SUCCEEDED(hr))
  214. servicesInitialized = TRUE;
  215. }
  216. }
  217. return hr;
  218. }
  219. HRESULT SetupPage::CreateView(HWND hParent, HWND *phwnd)
  220. {
  221. if (NULL == phwnd)
  222. return E_INVALIDARG;
  223. if (FAILED(InitializeServices()))
  224. {
  225. *phwnd = NULL;
  226. return E_FAIL;
  227. }
  228. *phwnd = SetupPage_CreateWindow(hParent, this);
  229. return (NULL == phwnd) ? E_FAIL : S_OK;
  230. }
  231. BOOL SetupPage::UpdateListAsync(INT groupId)
  232. {
  233. if (NULL == hwnd)
  234. return FALSE;
  235. return PostMessage(hwnd, SPM_UPDATELIST, (WPARAM)groupId, NULL);
  236. }
  237. BOOL SetupPage::AttachWindow(HWND hAttach)
  238. {
  239. hwnd = hAttach;
  240. if (NULL == completeEvent)
  241. completeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  242. if (NULL == groupList)
  243. {
  244. groupList = SetupGroupList::CreateInstance();
  245. if (NULL != groupList)
  246. {
  247. WCHAR szBuffer[4096] = {0};
  248. SetupPage_GetFeaturedServicesUrl(szBuffer, ARRAYSIZE(szBuffer));
  249. SetupGroup *group = SetupGroup::CreateInstance(ID_FEATUREDGROUP, MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATURED),
  250. szBuffer, &SUID_OmStorageUrl, &FUID_SetupFeaturedGroupFilter,
  251. SetupGroup::styleSortAlphabetically | SetupGroup::styleDefaultSubscribed | SetupGroup::styleSaveAll);
  252. if (NULL != group)
  253. {
  254. group->SetLongName(MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATUREDLONG));
  255. group->SetDescription(MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATURED_DESC));
  256. groupList->AddGroup(group);
  257. group->RequestReload();
  258. group->Release();
  259. }
  260. group = SetupGroup::CreateInstance(ID_KNOWNGROUP, MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWN),
  261. L"*.ini", &SUID_OmStorageIni, &FUID_SetupKnownGroupFilter,
  262. SetupGroup::styleSortAlphabetically);
  263. if (NULL != group)
  264. {
  265. group->SetLongName(MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWNLONG));
  266. group->SetDescription(MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWN_DESC));
  267. group->RequestReload();
  268. groupList->AddGroup(group);
  269. group->Release();
  270. }
  271. }
  272. }
  273. if (NULL != groupList)
  274. groupList->SetPageWnd(hwnd);
  275. HWND hList = GetDlgItem(hwnd, IDC_SERVICELIST);
  276. if (NULL != hList)
  277. {
  278. SetupListbox *listbox;
  279. if (SUCCEEDED(SetupListbox::CreateInstance(hList, groupList, &listbox)))
  280. {
  281. }
  282. ListboxSelectionChanged();
  283. }
  284. return TRUE;
  285. }
  286. void SetupPage::DetachWindow()
  287. {
  288. hwnd = NULL;
  289. if (NULL != groupList)
  290. {
  291. groupList->SetPageWnd(NULL);
  292. }
  293. }
  294. HRESULT SetupPage_AppendUnselectedServices(LPCSTR pszSection, LPCSTR pszKey, SetupGroup *group)
  295. {
  296. size_t index = group->GetRecordCount();
  297. size_t filterIndex, filterSize;
  298. ServiceIdList list;
  299. Config_ReadServiceIdList(pszSection, pszKey, ',', SetupPage_AppendServiceIdCallback, &list);
  300. filterSize = list.size();
  301. while(index--)
  302. {
  303. SetupRecord *record = group->GetRecord(index);
  304. if (NULL == record || FALSE != record->IsSelected()) continue;
  305. ifc_omservice *service = record->GetService();
  306. if (NULL == service) continue;
  307. UINT serviceId = service->GetId();
  308. for(filterIndex = 0; filterIndex < filterSize; filterIndex++)
  309. {
  310. if (list[filterIndex] == serviceId)
  311. break;
  312. }
  313. if (filterIndex == filterSize)
  314. list.push_back(serviceId);
  315. }
  316. if (0 != list.size())
  317. {
  318. size_t bufferAlloc = (list.size() * 11) * sizeof(CHAR);
  319. LPSTR buffer = Plugin_MallocAnsiString(bufferAlloc);
  320. if (NULL != buffer)
  321. {
  322. filterSize = list.size();
  323. LPSTR cursor = buffer;
  324. size_t remaining = bufferAlloc;
  325. for(index = 0; index < filterSize; index++)
  326. {
  327. if (FAILED(StringCchPrintfExA(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE,
  328. ((0 == index) ? "%u" : ",%u"), list[index])))
  329. {
  330. break;
  331. }
  332. }
  333. Config_WriteStr(pszSection, pszKey, buffer);
  334. Plugin_FreeAnsiString(buffer);
  335. }
  336. }
  337. else
  338. Config_WriteStr(pszSection, pszKey, NULL);
  339. return S_OK;
  340. }
  341. HRESULT SetupPage::Execute(HWND hwndText)
  342. {
  343. SetupGroup *group = NULL;
  344. SetupLog *log = SetupLog::Open();
  345. WCHAR szBuffer[128] = {0};
  346. if (FAILED(InitializeServices()))
  347. return E_FAIL;
  348. if (NULL == groupList)
  349. {
  350. groupList = SetupGroupList::CreateInstance();
  351. if (NULL == groupList) return E_UNEXPECTED;
  352. }
  353. if (S_OK != groupList->FindGroupById(ID_FEATUREDGROUP, &group) && group != NULL)
  354. {
  355. WCHAR szBuffer[4096] = {0};
  356. SetupPage_GetFeaturedServicesUrl(szBuffer, ARRAYSIZE(szBuffer));
  357. group = SetupGroup::CreateInstance(ID_FEATUREDGROUP, MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATURED),
  358. szBuffer, &SUID_OmStorageUrl, &FUID_SetupFeaturedGroupFilter,
  359. SetupGroup::styleDefaultSubscribed | SetupGroup::styleSaveAll);
  360. if (NULL != group)
  361. {
  362. group->SetLongName(MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATUREDLONG));
  363. group->SetDescription(MAKEINTRESOURCE(IDS_SERVICEGROUP_FEATURED_DESC));
  364. groupList->AddGroup(group);
  365. group->RequestReload();
  366. }
  367. }
  368. if (NULL == completeEvent)
  369. completeEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  370. if (NULL != group)
  371. {
  372. if (SUCCEEDED(group->SignalLoadCompleted(completeEvent)))
  373. {
  374. WASABI_API_LNGSTRINGW_BUF(IDS_DOWNLOADSERVICE_JOB, szBuffer, ARRAYSIZE(szBuffer));
  375. SetWindowText(hwndText, szBuffer);
  376. SetupPage_ModalLoop(hwndText, NULL, completeEvent);
  377. }
  378. WASABI_API_LNGSTRINGW_BUF(IDS_SAVESERVICE_JOB, szBuffer, ARRAYSIZE(szBuffer));
  379. SetWindowText(hwndText, szBuffer);
  380. group->Save(log);
  381. SetupPage_AppendUnselectedServices("Setup", "featuredHistory", group);
  382. group->Release();
  383. group = NULL;
  384. }
  385. // ensure that promotions are subscribed
  386. if (S_OK != groupList->FindGroupById(ID_KNOWNGROUP, &group) && group != NULL)
  387. {
  388. group = SetupGroup::CreateInstance(ID_KNOWNGROUP, MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWN),
  389. L"*.ini", &SUID_OmStorageIni, &FUID_SetupKnownGroupFilter,
  390. SetupGroup::styleSortAlphabetically);
  391. if (NULL != group)
  392. {
  393. group->SetLongName(MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWNLONG));
  394. group->SetDescription(MAKEINTRESOURCE(IDS_SERVICEGROUP_KNOWN_DESC));
  395. group->RequestReload();
  396. groupList->AddGroup(group);
  397. }
  398. }
  399. if (NULL != group)
  400. {
  401. WASABI_API_LNGSTRINGW_BUF(IDS_SAVESERVICE_JOB, szBuffer, ARRAYSIZE(szBuffer));
  402. SetWindowText(hwndText, szBuffer);
  403. ResetEvent(completeEvent);
  404. if (SUCCEEDED(group->SignalLoadCompleted(completeEvent)))
  405. SetupPage_ModalLoop(hwndText, NULL, completeEvent);
  406. group->Save(log);
  407. group->Release();
  408. group = NULL;
  409. }
  410. if (NULL != log)
  411. {
  412. WASABI_API_LNGSTRINGW_BUF(IDS_REGISTERINGSERVICE_JOB, szBuffer, ARRAYSIZE(szBuffer));
  413. SetWindowText(hwndText, szBuffer);
  414. ResetEvent(completeEvent);
  415. log->Send(completeEvent);
  416. SetupPage_ModalLoop(hwndText, NULL, completeEvent);
  417. log->Release();
  418. }
  419. SetupLog::Erase();
  420. Config_WriteStr("Setup", "featuredExtra", NULL); // delete promo offer
  421. return S_OK;
  422. }
  423. HRESULT SetupPage::Cancel(HWND hwndText)
  424. {
  425. if (NULL != completeEvent)
  426. SetEvent(completeEvent);
  427. return S_OK;
  428. }
  429. HRESULT SetupPage::IsCancelSupported(void)
  430. {
  431. return S_OK;
  432. }
  433. void SetupPage::ListboxSelectionChanged()
  434. {
  435. if (NULL == hwnd) return;
  436. HWND hList = GetDlgItem(hwnd, IDC_SERVICELIST);
  437. if (NULL == hList) return;
  438. SetupListboxItem *item = NULL;
  439. INT iSelection = (INT)SendMessage(hList, LB_GETCURSEL, 0, 0L);
  440. if (LB_ERR == iSelection ||
  441. FAILED(groupList->FindListboxItem(iSelection, &item)))
  442. {
  443. item = NULL;
  444. }
  445. HWND hDiscard = GetDlgItem(hwnd, IDC_DETAILS);
  446. if (NULL != hDiscard)
  447. {
  448. WCHAR szPanel[64] = {0}, szItem[64] = {0};
  449. if (FALSE != SetupDetails_GetUniqueName(hDiscard, szPanel, ARRAYSIZE(szPanel)) &&
  450. FALSE != item->GetUniqueName(szItem, ARRAYSIZE(szItem)) &&
  451. CSTR_EQUAL == CompareString(CSTR_INVARIANT, 0, szPanel, - 1, szItem, -1))
  452. {
  453. return;
  454. }
  455. }
  456. HWND hDetails = (NULL != item) ? item->CreateDetailsView(hwnd) : NULL;
  457. if (NULL != hDiscard)
  458. {
  459. SetWindowLongPtr(hDiscard, GWL_STYLE, GetWindowLongPtr(hDiscard, GWL_STYLE) & ~WS_VISIBLE);
  460. }
  461. if (NULL != hDetails)
  462. {
  463. HWND hPlaceholder = GetDlgItem(hwnd, IDC_PLACEHOLDER);
  464. if (NULL != hPlaceholder)
  465. {
  466. RECT windowRect;
  467. if (GetWindowRect(hPlaceholder, &windowRect))
  468. {
  469. MapWindowPoints(HWND_DESKTOP,hwnd, (POINT*)&windowRect,2);
  470. SetWindowPos(hDetails, NULL, windowRect.left, windowRect.top,
  471. windowRect.right - windowRect.left, windowRect.bottom - windowRect.top,
  472. SWP_NOACTIVATE | SWP_NOZORDER);
  473. }
  474. SetWindowLongPtr(hDetails, GWLP_ID, IDC_DETAILS);
  475. ShowWindow(hDetails, SW_SHOWNA);
  476. RedrawWindow(hDetails, NULL, NULL, RDW_ERASENOW |RDW_UPDATENOW | RDW_ALLCHILDREN);
  477. }
  478. }
  479. if (NULL != hDiscard)
  480. {
  481. DestroyWindow(hDiscard);
  482. }
  483. }
  484. static INT_PTR SetupPage_ModalLoop(HWND hwnd, HACCEL hAccel, HANDLE hCancel)
  485. {
  486. MSG msg = {0};
  487. HWND hParent = NULL;
  488. while (NULL != (hParent = GetAncestor(hwnd, GA_PARENT)))
  489. {
  490. hwnd = hParent;
  491. }
  492. if (NULL == hwnd)
  493. return 0;
  494. for (;;)
  495. {
  496. DWORD status = MsgWaitForMultipleObjectsEx(1, &hCancel, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
  497. if (WAIT_OBJECT_0 == status)
  498. {
  499. return 0;
  500. }
  501. else if ((WAIT_OBJECT_0 + 1)== status)
  502. {
  503. while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
  504. {
  505. //if (!CallMsgFilter(&msg, MSGF_DIALOGBOX))
  506. {
  507. if (msg.message == WM_QUIT)
  508. {
  509. PostQuitMessage((INT)msg.wParam);
  510. return msg.wParam;
  511. }
  512. if (!TranslateAcceleratorW(hwnd, hAccel, &msg) &&
  513. !IsDialogMessageW(hwnd, &msg))
  514. {
  515. TranslateMessage(&msg);
  516. DispatchMessageW(&msg);
  517. }
  518. }
  519. }
  520. }
  521. }
  522. return 0;
  523. }
  524. #define CBCLASS SetupPage
  525. START_MULTIPATCH;
  526. START_PATCH(MPIID_SETUPPAGE)
  527. M_CB(MPIID_SETUPPAGE, ifc_setuppage, ADDREF, AddRef);
  528. M_CB(MPIID_SETUPPAGE, ifc_setuppage, RELEASE, Release);
  529. M_CB(MPIID_SETUPPAGE, ifc_setuppage, QUERYINTERFACE, QueryInterface);
  530. M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_GET_NAME, GetName);
  531. M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_CREATEVIEW, CreateView);
  532. M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_SAVE, Save);
  533. M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_REVERT, Revert);
  534. M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_ISDIRTY, IsDirty);
  535. M_CB(MPIID_SETUPPAGE, ifc_setuppage, API_SETUPPAGE_VALIDATE, Validate);
  536. NEXT_PATCH(MPIID_SETUPJOB)
  537. M_CB(MPIID_SETUPJOB, ifc_setupjob, ADDREF, AddRef);
  538. M_CB(MPIID_SETUPJOB, ifc_setupjob, RELEASE, Release);
  539. M_CB(MPIID_SETUPJOB, ifc_setupjob, QUERYINTERFACE, QueryInterface);
  540. M_CB(MPIID_SETUPJOB, ifc_setupjob, API_SETUPJOB_EXECUTE, Execute);
  541. M_CB(MPIID_SETUPJOB, ifc_setupjob, API_SETUPJOB_CANCEL, Cancel);
  542. M_CB(MPIID_SETUPJOB, ifc_setupjob, API_SETUPJOB_ISCANCELSUPPORTED, IsCancelSupported);
  543. END_PATCH
  544. END_MULTIPATCH;
  545. #undef CBCLASS