Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

647 lines
17 KiB

  1. //
  2. // dll.cpp
  3. //
  4. #include <iostream.h>
  5. #include <objbase.h>
  6. #include <shlwapi.h>
  7. #include <shlwapip.h>
  8. #include <shlobj.h>
  9. #include "cowsite.h"
  10. #include "Iface.h" // Interface declarations
  11. #include "Registry.h" // Registry helper functions
  12. #include "migutil.h"
  13. #include "migeng.h"
  14. #include "migtask.h"
  15. #include "migoobe.h"
  16. // DLL functions, declared in dll.cpp
  17. STDAPI DllAddRef();
  18. STDAPI DllRelease();
  19. extern HMODULE g_hModule;
  20. ///////////////////////////////////////////////////////////
  21. //
  22. // Global variables
  23. //
  24. ///////////////////////////////////////////////////////////
  25. //
  26. // Component
  27. //
  28. //
  29. // Constructor
  30. //
  31. CMigWizEngine::CMigWizEngine() : m_cRef(1), m_fCancelled(TRUE), m_fUserApplying(FALSE), m_fInBackgroundThread(FALSE)
  32. {
  33. DllAddRef();
  34. }
  35. //
  36. // Destructor
  37. //
  38. CMigWizEngine::~CMigWizEngine()
  39. {
  40. DllRelease();
  41. }
  42. //
  43. // IUnknown implementation
  44. //
  45. STDMETHODIMP CMigWizEngine::QueryInterface(REFIID riid, void **ppv)
  46. {
  47. static const QITAB qit[] = {
  48. QITABENT(CMigWizEngine, IObjectWithSite),
  49. QITABENT(CMigWizEngine, IMigrationWizardAuto),
  50. { 0 },
  51. };
  52. return QISearch(this, qit, riid, ppv);
  53. }
  54. STDMETHODIMP_(ULONG) CMigWizEngine::AddRef()
  55. {
  56. return InterlockedIncrement(&m_cRef);
  57. }
  58. STDMETHODIMP_(ULONG) CMigWizEngine::Release()
  59. {
  60. if (InterlockedDecrement(&m_cRef) == 0)
  61. {
  62. delete this;
  63. return 0;
  64. }
  65. return m_cRef;
  66. }
  67. ///////////////////////////////////////////////////////////
  68. STDMETHODIMP CMigWizEngine::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** ppITypeInfo)
  69. {
  70. return E_NOTIMPL;
  71. }
  72. STDMETHODIMP CMigWizEngine::GetIDsOfNames(REFIID /*riid */, LPOLESTR* rgszNames,
  73. UINT cNames, LCID lcid, DISPID* rgdispid)
  74. {
  75. return E_NOTIMPL;
  76. }
  77. STDMETHODIMP CMigWizEngine::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams,
  78. VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr)
  79. {
  80. return E_NOTIMPL;
  81. }
  82. STDMETHODIMP CMigWizEngine::GetTypeInfoCount(UINT* pctinfo)
  83. {
  84. return E_NOTIMPL;
  85. }
  86. ///////////////////////////////////////////////////////////
  87. HRESULT CMigWizEngine::_FireEvent (LPVOID lpParam, int iDISPID, DISPPARAMS* pdisp)
  88. {
  89. HRESULT hr = E_FAIL;
  90. IDispatch* pDispatch = (IDispatch*)lpParam;
  91. if (pDispatch)
  92. {
  93. VARIANT varResult;
  94. DISPPARAMS disp = { NULL, NULL, 0, 0};
  95. if (pdisp == NULL)
  96. {
  97. pdisp = &disp;
  98. }
  99. hr = pDispatch->Invoke(iDISPID, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, pdisp, &varResult, NULL, NULL);
  100. }
  101. return hr;
  102. }
  103. HRESULT CMigWizEngine::_GetIDispatchStream(IStream** ppStream)
  104. {
  105. HRESULT hr = E_FAIL;
  106. BOOL fDone = FALSE;
  107. if (_punkSite)
  108. {
  109. IConnectionPointContainer* pCPC;
  110. hr = _punkSite->QueryInterface(IID_PPV_ARG(IConnectionPointContainer, &pCPC)); // get the connect point container
  111. if (SUCCEEDED(hr))
  112. {
  113. IEnumConnectionPoints* pEnum;
  114. hr = pCPC->EnumConnectionPoints(&pEnum); // get all the connection points
  115. if (SUCCEEDED(hr))
  116. {
  117. IConnectionPoint* pcp;
  118. while (!fDone)
  119. {
  120. ULONG cpcp = 1;
  121. if (FAILED(pEnum->Next(1, &pcp, &cpcp)) || 0 == cpcp)
  122. {
  123. break;
  124. }
  125. else
  126. {
  127. IID iidInterface;
  128. if (SUCCEEDED ( pcp->GetConnectionInterface(&iidInterface) && // get only the connection point for DMigrationWizardAutoEvents
  129. (DIID_DMigrationWizardAutoEvents == iidInterface)))
  130. {
  131. // now fire the event for all listeners on this connection point
  132. IEnumConnections* pEnumConnections;
  133. if (SUCCEEDED(pcp->EnumConnections(&pEnumConnections)))
  134. {
  135. CONNECTDATA rgcd[1];
  136. ULONG ccd;
  137. while (!fDone)
  138. {
  139. if (FAILED(pEnumConnections->Next(ARRAYSIZE(rgcd), rgcd, &ccd)) || ccd == 0)
  140. {
  141. break;
  142. }
  143. else if (rgcd[0].pUnk)
  144. {
  145. IDispatch* pDispatch;
  146. if (SUCCEEDED(rgcd[0].pUnk->QueryInterface(IID_PPV_ARG(IDispatch, &pDispatch))))
  147. {
  148. if (SUCCEEDED(CoMarshalInterThreadInterfaceInStream(IID_IDispatch, pDispatch, ppStream)))
  149. {
  150. fDone = TRUE;
  151. hr = S_OK;
  152. }
  153. pDispatch->Release();
  154. }
  155. rgcd[0].pUnk->Release();
  156. }
  157. }
  158. pEnumConnections->Release();
  159. }
  160. }
  161. pcp->Release();
  162. }
  163. }
  164. pEnum->Release();
  165. }
  166. pCPC->Release();
  167. }
  168. }
  169. return hr;
  170. }
  171. HRESULT CMigWizEngine::_FireProgress(LPVOID lpParam, BSTR pszMsg, int iDone, int iTotal)
  172. {
  173. VARIANTARG rgvarg[3];
  174. VARIANT varResult;
  175. VariantClear(&varResult);
  176. HRESULT hr = E_OUTOFMEMORY;
  177. DISPPARAMS disp = { rgvarg, NULL, ARRAYSIZE(rgvarg), 0};
  178. rgvarg[0].vt = VT_BSTR;
  179. rgvarg[0].bstrVal = SysAllocString(pszMsg);
  180. if (rgvarg[0].bstrVal)
  181. {
  182. rgvarg[1].vt = VT_I4;
  183. rgvarg[1].lVal = iDone;
  184. rgvarg[2].vt = VT_I4;
  185. rgvarg[2].lVal = iTotal;
  186. hr = _FireEvent(lpParam, 1, &disp);
  187. SysFreeString(rgvarg[0].bstrVal);
  188. }
  189. return hr;
  190. }
  191. HRESULT CMigWizEngine::_FireComplete(LPVOID lpParam, BSTR pszMsg)
  192. {
  193. VARIANTARG rgvarg[1];
  194. DISPPARAMS disp = { rgvarg, NULL, ARRAYSIZE(rgvarg), 0};
  195. rgvarg[0].vt = VT_BSTR;
  196. rgvarg[0].bstrVal = SysAllocString(pszMsg);
  197. if (rgvarg[0].bstrVal)
  198. {
  199. _FireEvent(lpParam, 2, &disp);
  200. SysFreeString(rgvarg[0].bstrVal);
  201. }
  202. return S_OK;
  203. }
  204. typedef struct {
  205. IDispatch* pDispatch;
  206. CMigWizEngine* pengine;
  207. } PROGRESSCALLBACKSTRUCT;
  208. UINT ProgressCallback (LPVOID lpParam, UINT ui1, UINT ui2)
  209. {
  210. PROGRESSCALLBACKSTRUCT* ppcs = (PROGRESSCALLBACKSTRUCT*)lpParam;
  211. ppcs->pengine->_FireProgress((LPVOID)(ppcs->pDispatch), SZ_MIGWIZPROGRESS_OK, ui1, ui2);
  212. return 0;
  213. }
  214. #define SZ_OOBEMODE TEXT("OOBEMODE")
  215. HRESULT CMigWizEngine::_CreateToolDiskThreadWorker ()
  216. {
  217. HRESULT hr = E_FAIL;
  218. BOOL fNoDisk = FALSE;
  219. IDispatch* pDispatch;
  220. hr = CoGetInterfaceAndReleaseStream(m_pDispatchStream, IID_PPV_ARG(IDispatch, &pDispatch));
  221. if (SUCCEEDED(hr))
  222. {
  223. // copy the INF
  224. CHAR szDrivePathA[MAX_PATH];
  225. if (SUCCEEDED(_SHUnicodeToAnsi(m_pszDrivePath, szDrivePathA, ARRAYSIZE(szDrivePathA))))
  226. {
  227. CHAR szFilesPathA[MAX_PATH];
  228. if (SUCCEEDED(_SHUnicodeToAnsi(m_pszFilesPath, szFilesPathA, ARRAYSIZE(szFilesPathA))))
  229. {
  230. CHAR szManifestPathA[MAX_PATH];
  231. if (SUCCEEDED(_SHUnicodeToAnsi(m_pszManifestPath, szManifestPathA, ARRAYSIZE(szManifestPathA))))
  232. {
  233. PROGRESSCALLBACKSTRUCT pcs;
  234. pcs.pDispatch = pDispatch;
  235. pDispatch->AddRef();
  236. pcs.pengine = this;
  237. this->AddRef();
  238. if (SUCCEEDED(_CopyInfToDisk(szDrivePathA, szFilesPathA, szManifestPathA,
  239. ProgressCallback, (LPVOID)&pcs, NULL, NULL, g_hModule, &m_fCancelled, &fNoDisk)))
  240. {
  241. if (!m_fCancelled)
  242. {
  243. hr = S_OK;
  244. IStream* pStream = NULL;
  245. TCHAR szPath[MAX_PATH];
  246. lstrcpy(szPath, szDrivePathA);
  247. PathAppend(szPath, TEXT("oobemode.dat"));
  248. if (SUCCEEDED(SHCreateStreamOnFile(szPath, STGM_WRITE | STGM_CREATE, &pStream)))
  249. {
  250. pStream->Write(SZ_OOBEMODE, sizeof(TCHAR) * (ARRAYSIZE(SZ_OOBEMODE) - 1), NULL);
  251. pStream->Release();
  252. }
  253. }
  254. }
  255. pDispatch->Release();
  256. this->Release();
  257. }
  258. }
  259. }
  260. m_fInBackgroundThread = FALSE;
  261. if (m_fCancelled)
  262. {
  263. _FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_CANCEL);
  264. }
  265. else if (fNoDisk)
  266. {
  267. _FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_NODISK);
  268. }
  269. else if (SUCCEEDED(hr))
  270. {
  271. _FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_OK);
  272. }
  273. else
  274. {
  275. _FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_FAIL);
  276. }
  277. }
  278. m_fCancelled = TRUE;
  279. SysFreeString(m_pszDrivePath);
  280. SysFreeString(m_pszFilesPath);
  281. SysFreeString(m_pszManifestPath);
  282. if (pDispatch)
  283. {
  284. pDispatch->Release();
  285. }
  286. Release();
  287. return 0;
  288. }
  289. DWORD WINAPI CMigWizEngine::_CreateToolDiskThread (LPVOID lpParam)
  290. {
  291. if (lpParam)
  292. {
  293. ((CMigWizEngine*)lpParam)->_CreateToolDiskThreadWorker();
  294. }
  295. return 0;
  296. }
  297. STDMETHODIMP CMigWizEngine::CreateToolDisk(BSTR pszDrivePath, BSTR pszFilesPath, BSTR pszManifestPath)
  298. {
  299. HRESULT hr = S_OK; // we always want to return S_OK
  300. if (!m_fInBackgroundThread)
  301. {
  302. m_fInBackgroundThread = TRUE;
  303. hr = S_OK;
  304. IStream* pDispatchStream;
  305. hr = _GetIDispatchStream(&pDispatchStream);
  306. if (SUCCEEDED(hr))
  307. {
  308. m_pszDrivePath = SysAllocString(pszDrivePath);
  309. m_pszFilesPath = SysAllocString(pszFilesPath);
  310. m_pszManifestPath = SysAllocString(pszManifestPath);
  311. if (m_pszDrivePath && m_pszFilesPath && m_pszManifestPath)
  312. {
  313. m_fCancelled = FALSE;
  314. m_pDispatchStream = pDispatchStream;
  315. m_pDispatchStream->AddRef();
  316. AddRef();
  317. if (!SHCreateThread(_CreateToolDiskThread, this, (CTF_COINIT | CTF_PROCESS_REF | CTF_FREELIBANDEXIT), NULL))
  318. {
  319. Release();
  320. }
  321. }
  322. else
  323. {
  324. hr = E_OUTOFMEMORY;
  325. SysFreeString(pszDrivePath); // SysFreeString doesn't mind being passed NULL
  326. SysFreeString(pszFilesPath);
  327. SysFreeString(pszManifestPath);
  328. }
  329. pDispatchStream->Release();
  330. }
  331. }
  332. return hr;
  333. }
  334. BOOL g_fApplyDiskNotFound;
  335. ULONG_PTR MessageCallback (UINT uiMsg, ULONG_PTR pArg)
  336. {
  337. PRMEDIA_EXTRADATA extraData;
  338. switch (uiMsg) {
  339. case TRANSPORTMESSAGE_SIZE_SAVED:
  340. return TRUE;
  341. case TRANSPORTMESSAGE_RMEDIA_LOAD:
  342. extraData = (PRMEDIA_EXTRADATA) pArg;
  343. if (!extraData) {
  344. return TRUE;
  345. } else {
  346. if (extraData->MediaNumber == 1) {
  347. switch (extraData->LastError) {
  348. case RMEDIA_ERR_NOERROR:
  349. return TRUE;
  350. break;
  351. case RMEDIA_ERR_WRONGMEDIA:
  352. g_fApplyDiskNotFound = TRUE;
  353. return FALSE;
  354. break;
  355. case RMEDIA_ERR_DISKFULL:
  356. return FALSE;
  357. break;
  358. case RMEDIA_ERR_WRITEPROTECT:
  359. return FALSE;
  360. break;
  361. case RMEDIA_ERR_NOTREADY:
  362. return FALSE;
  363. break;
  364. case RMEDIA_ERR_CRITICAL:
  365. return FALSE;
  366. break;
  367. default:
  368. return TRUE;
  369. }
  370. } else {
  371. switch (extraData->LastError) {
  372. case RMEDIA_ERR_NOERROR:
  373. return TRUE;
  374. break;
  375. case RMEDIA_ERR_WRONGMEDIA:
  376. g_fApplyDiskNotFound = TRUE;
  377. return FALSE;
  378. break;
  379. case RMEDIA_ERR_DISKFULL:
  380. return FALSE;
  381. break;
  382. case RMEDIA_ERR_WRITEPROTECT:
  383. return FALSE;
  384. break;
  385. case RMEDIA_ERR_NOTREADY:
  386. return FALSE;
  387. break;
  388. case RMEDIA_ERR_CRITICAL:
  389. return FALSE;
  390. break;
  391. default:
  392. return TRUE;
  393. }
  394. }
  395. }
  396. }
  397. return APPRESPONSE_SUCCESS;
  398. }
  399. #define PHASEWIDTH_APPLY_TRANSPORT 1000
  400. #define PHASEWIDTH_APPLY_ANALYSIS 1000
  401. #define PHASEWIDTH_APPLY_APPLY 1000
  402. #define PHASEWIDTH_APPLY_TOTAL (PHASEWIDTH_APPLY_TRANSPORT + PHASEWIDTH_APPLY_ANALYSIS + PHASEWIDTH_APPLY_APPLY)
  403. typedef struct {
  404. CMigWizEngine* pEngine;
  405. IDispatch* pDispatch;
  406. } APPLYPROGRESSCALLBACKSTRUCT;
  407. VOID WINAPI ApplyProgressCallback (MIG_PROGRESSPHASE Phase, MIG_PROGRESSSTATE State, UINT uiWorkDone, UINT uiTotalWork, ULONG_PTR pArg)
  408. {
  409. INT iWork = 0;
  410. INT iPhaseWidth = 0;
  411. INT iTotal = PHASEWIDTH_APPLY_TOTAL;
  412. APPLYPROGRESSCALLBACKSTRUCT* papcs = (APPLYPROGRESSCALLBACKSTRUCT*)pArg;
  413. switch (Phase)
  414. {
  415. case MIG_TRANSPORT_PHASE:
  416. iWork = 0;
  417. iPhaseWidth = PHASEWIDTH_APPLY_TRANSPORT;
  418. break;
  419. case MIG_ANALYSIS_PHASE:
  420. iWork = PHASEWIDTH_APPLY_TRANSPORT;
  421. iPhaseWidth = PHASEWIDTH_APPLY_ANALYSIS;
  422. break;
  423. case MIG_APPLY_PHASE:
  424. iWork = PHASEWIDTH_APPLY_TRANSPORT + PHASEWIDTH_APPLY_ANALYSIS;
  425. iPhaseWidth = PHASEWIDTH_APPLY_APPLY;
  426. break;
  427. }
  428. if (State == MIG_END_PHASE)
  429. {
  430. iWork += iPhaseWidth;
  431. }
  432. else if (uiTotalWork && uiWorkDone)
  433. {
  434. iWork += (iPhaseWidth * uiWorkDone) / uiTotalWork;
  435. }
  436. if (papcs && papcs->pEngine && papcs->pDispatch)
  437. {
  438. papcs->pEngine->_FireProgress(papcs->pDispatch, L"", iWork, iTotal);
  439. }
  440. }
  441. HRESULT CMigWizEngine::_ApplySettingsThreadWorker ()
  442. {
  443. HRESULT hr = E_OUTOFMEMORY;
  444. g_fApplyDiskNotFound = FALSE; // set up
  445. IDispatch* pDispatch;
  446. hr = CoGetInterfaceAndReleaseStream(m_pDispatchStream, IID_PPV_ARG(IDispatch, &pDispatch));
  447. if (SUCCEEDED(hr))
  448. {
  449. APPLYPROGRESSCALLBACKSTRUCT apcs;
  450. apcs.pEngine = this;
  451. apcs.pEngine->AddRef();
  452. apcs.pDispatch = pDispatch;
  453. apcs.pDispatch->AddRef();
  454. if (SUCCEEDED(hr))
  455. {
  456. TCHAR szFloppyPath[4] = TEXT("A:\\");
  457. szFloppyPath[0] += (TCHAR)_GetFloppyNumber(TRUE);
  458. hr = _DoApply(szFloppyPath, NULL, NULL, &m_fCancelled, ApplyProgressCallback, (ULONG_PTR)&apcs);
  459. }
  460. apcs.pEngine->Release();
  461. apcs.pDispatch->Release();
  462. m_fInBackgroundThread = FALSE;
  463. if (m_fCancelled)
  464. {
  465. _FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_CANCEL);
  466. }
  467. else if (g_fApplyDiskNotFound)
  468. {
  469. _FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_NODISK);
  470. }
  471. else if (SUCCEEDED(hr))
  472. {
  473. _FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_OK);
  474. }
  475. else
  476. {
  477. _FireComplete((LPVOID)pDispatch, SZ_MIGWIZCOMPLETE_FAIL);
  478. }
  479. }
  480. m_fCancelled = TRUE;
  481. m_fUserApplying = FALSE;
  482. Release();
  483. return hr;
  484. }
  485. DWORD WINAPI CMigWizEngine::_ApplySettingsThread (LPVOID lpParam)
  486. {
  487. if (lpParam)
  488. {
  489. ((CMigWizEngine*)lpParam)->_ApplySettingsThreadWorker();
  490. }
  491. return 0;
  492. }
  493. STDMETHODIMP CMigWizEngine::ApplySettings(BSTR pszMigwizFiles)
  494. {
  495. HRESULT hr = E_FAIL;
  496. if (!m_fInBackgroundThread)
  497. {
  498. m_fInBackgroundThread = TRUE;
  499. hr = S_OK;
  500. m_fUserApplying = TRUE;
  501. IStream* pDispatchStream;
  502. hr = _GetIDispatchStream(&pDispatchStream);
  503. if (SUCCEEDED(hr))
  504. {
  505. m_fCancelled = FALSE;
  506. CHAR szMigwizPathA[MAX_PATH];
  507. if (SUCCEEDED(_SHUnicodeToAnsi(pszMigwizFiles, szMigwizPathA, ARRAYSIZE(szMigwizPathA))))
  508. {
  509. hr = Engine_Initialize(szMigwizPathA, FALSE, FALSE, TEXT("OOBE"), MessageCallback, NULL);
  510. m_pDispatchStream = pDispatchStream;
  511. m_pDispatchStream->AddRef();
  512. AddRef();
  513. if (!SHCreateThread(_ApplySettingsThread, this, (CTF_COINIT | CTF_PROCESS_REF | CTF_FREELIBANDEXIT), NULL))
  514. {
  515. Release();
  516. }
  517. }
  518. else
  519. {
  520. hr = E_FAIL;
  521. }
  522. pDispatchStream->Release();
  523. }
  524. }
  525. return hr;
  526. }
  527. STDMETHODIMP CMigWizEngine::Cancel()
  528. {
  529. HRESULT hr = S_OK;
  530. m_fCancelled = TRUE;
  531. if (m_fUserApplying)
  532. {
  533. Engine_Cancel();
  534. }
  535. return hr;
  536. }