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.

1427 lines
34 KiB

  1. // Upload.cpp : Implementation of CUpload
  2. #include "stdafx.h"
  3. #include "resource.h"
  4. #include "CompatUI.h"
  5. #include "shlobj.h"
  6. extern "C" {
  7. #include "shimdb.h"
  8. }
  9. #include "Upload.h"
  10. TCHAR szKeyDataFiles[] = TEXT("DataFiles");
  11. //
  12. // lives in util.cpp
  13. //
  14. BOOL
  15. GetExePathFromObject(
  16. LPCTSTR lpszPath, // path to an arbitrary object
  17. CComBSTR& bstrExePath
  18. );
  19. //
  20. // lives in proglist.cpp
  21. //
  22. wstring
  23. LoadResourceString(UINT nID);
  24. //
  25. // lives in ntutil.c
  26. //
  27. extern "C"
  28. BOOL
  29. WINAPI
  30. CheckFileLocation(
  31. LPCWSTR pwszDosPath,
  32. BOOL* pbRoot,
  33. BOOL* pbLeaf
  34. );
  35. //
  36. // conversion
  37. //
  38. BOOL VariantToBOOL(CComVariant& v)
  39. {
  40. if (SUCCEEDED(v.ChangeType(VT_BOOL))) {
  41. return v.boolVal;
  42. }
  43. return FALSE;
  44. }
  45. wstring VariantToStr(CComVariant& v)
  46. {
  47. wstring str;
  48. if (v.vt != VT_EMPTY && v.vt != VT_NULL) {
  49. if (SUCCEEDED(v.ChangeType(VT_BSTR))) {
  50. str = v.bstrVal;
  51. }
  52. }
  53. return str;
  54. }
  55. HRESULT StringToVariant(VARIANT* pv, const wstring& str)
  56. {
  57. HRESULT hr = E_FAIL;
  58. pv->vt = VT_NULL;
  59. pv->bstrVal = ::SysAllocString(str.c_str());
  60. if (pv->bstrVal == NULL) {
  61. hr = E_OUTOFMEMORY;
  62. } else {
  63. pv->vt = VT_BSTR;
  64. hr = S_OK;
  65. }
  66. return hr;
  67. }
  68. BOOL
  69. GetTempFile(
  70. LPCTSTR lpszPrefix,
  71. CComBSTR& bstrFile
  72. )
  73. {
  74. DWORD dwLength;
  75. TCHAR szBuffer[MAX_PATH];
  76. TCHAR szTempFile[MAX_PATH];
  77. dwLength = GetTempPath(CHARCOUNT(szBuffer), szBuffer);
  78. if (!dwLength || dwLength > CHARCOUNT(szBuffer)) {
  79. return FALSE;
  80. }
  81. //
  82. // we got directory, generate the file now
  83. //
  84. dwLength = GetTempFileName(szBuffer, lpszPrefix, 0, szTempFile);
  85. if (!dwLength) {
  86. return FALSE;
  87. }
  88. bstrFile = szTempFile;
  89. return TRUE;
  90. }
  91. wstring StrUpCase(wstring& wstr)
  92. {
  93. ctype<wchar_t> _ct;
  94. wstring::iterator iter;
  95. for (iter = wstr.begin(); iter != wstr.end(); ++iter) {
  96. (*iter) = _ct.toupper(*iter);
  97. }
  98. return wstr;
  99. }
  100. /////////////////////////////////////////////////////////////////////////////
  101. // CUpload
  102. BOOL CUpload::GetDataFilesKey(CComBSTR& bstrVal)
  103. {
  104. // STRVEC::iterator iter;
  105. MAPSTR2MFI::iterator iter;
  106. bstrVal.Empty();
  107. for (iter = m_DataFiles.begin(); iter != m_DataFiles.end(); ++iter) {
  108. if (bstrVal.Length()) {
  109. bstrVal.Append(TEXT("|"));
  110. }
  111. bstrVal.Append((*iter).second.strFileName.c_str());
  112. }
  113. return bstrVal.Length() != 0;
  114. }
  115. STDMETHODIMP CUpload::SetKey(BSTR pszKey, VARIANT* pvValue)
  116. {
  117. wstring strKey = pszKey;
  118. VARIANT vStr;
  119. HRESULT hr;
  120. HRESULT hrRet = S_OK;
  121. //
  122. // dwwin is case-sensitive
  123. //
  124. // StrUpCase(strKey);
  125. if (strKey == szKeyDataFiles) { // data files cannot be set directly
  126. return E_INVALIDARG;
  127. }
  128. VariantInit(&vStr);
  129. hr = VariantChangeType(&vStr, pvValue, 0, VT_BSTR);
  130. if (SUCCEEDED(hr)) {
  131. wstring strVal = vStr.bstrVal;
  132. m_mapManifest[strKey] = strVal;
  133. } else if (pvValue->vt == VT_NULL || pvValue->vt == VT_EMPTY) {
  134. m_mapManifest.erase(strKey);
  135. } else {
  136. hrRet = E_INVALIDARG;
  137. }
  138. VariantClear(&vStr);
  139. return hrRet;
  140. }
  141. STDMETHODIMP CUpload::GetKey(BSTR pszKey, VARIANT *pValue)
  142. {
  143. CComBSTR bstrVal;
  144. wstring strKey = pszKey;
  145. // StrUpCase(strKey);
  146. if (strKey == szKeyDataFiles) {
  147. //
  148. // data files -- handled separately
  149. //
  150. if (GetDataFilesKey(bstrVal)) {
  151. pValue->vt = VT_BSTR;
  152. pValue->bstrVal = bstrVal.Copy();
  153. } else {
  154. pValue->vt = VT_NULL;
  155. }
  156. } else {
  157. MAPSTR2STR::iterator iter = m_mapManifest.find(strKey);
  158. if (iter != m_mapManifest.end()) {
  159. bstrVal = (*iter).second.c_str();
  160. pValue->vt = VT_BSTR;
  161. pValue->bstrVal = bstrVal.Copy();
  162. } else {
  163. pValue->vt = VT_NULL;
  164. }
  165. }
  166. return S_OK;
  167. }
  168. #define DWWIN_HEADLESS_MODE 0x00000080
  169. BOOL CUpload::IsHeadlessMode(void)
  170. {
  171. CComVariant varFlags;
  172. HRESULT hr;
  173. BOOL bHeadless = FALSE;
  174. GetKey(TEXT("Flags"), &varFlags);
  175. hr = varFlags.ChangeType(VT_I4);
  176. if (SUCCEEDED(hr)) {
  177. bHeadless = !!(varFlags.lVal & DWWIN_HEADLESS_MODE);
  178. }
  179. return bHeadless;
  180. }
  181. /*
  182. DWORD CUpload::CountFiles(DWORD nLevel, LPCWSTR pszPath)
  183. {
  184. WIN32_FIND_DATA wfd;
  185. wstring strPath = pszPath;
  186. wstring::size_type nPos;
  187. HANDLE hFind = INVALID_HANDLE_VALUE;
  188. DWORD dwCount = 0;
  189. nPos = strPath.length();
  190. if (strPath[nPos-1] != TEXT('\\')) {
  191. strPath += TEXT('\\');
  192. ++nPos;
  193. }
  194. FindFirstFileExW(
  195. strPath += TEXT('*');
  196. hFind = FindFirstFile(strPath.c_str(), &wfd);
  197. if (hFind != INVALID_HANDLE_VALUE) {
  198. do {
  199. if (nLevel < 3 && wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  200. if (wcscmp(wfd.cFileName, TEXT(".")) && wcscmp(wfd.cFileName, TEXT(".."))) {
  201. strPath.replace(nPos, wstring::nPos, wfd.cFileName);
  202. dwCount += CountFiles(nLevel + 1, strPath.c_str());
  203. }
  204. } else { // file
  205. ++dwCount;
  206. }
  207. } while (FindNextFile(hFind, &wfd));
  208. FindClose(hFind);
  209. }
  210. return dwCount;
  211. }
  212. */
  213. BOOL CALLBACK CUpload::_GrabmiCallback(
  214. LPVOID lpvCallbackParam, // application-defined parameter
  215. LPCTSTR lpszRoot, // root directory path
  216. LPCTSTR lpszRelative, // relative path
  217. PATTRINFO pAttrInfo, // attributes
  218. LPCWSTR pwszXML // resulting xml
  219. )
  220. {
  221. GMEPARAMS* pParams = (GMEPARAMS*)lpvCallbackParam;
  222. CUpload* pT = pParams->first;
  223. IProgressDialog* ppd = pParams->second;
  224. if (ppd == NULL) {
  225. return TRUE;
  226. }
  227. ppd->SetLine(2, lpszRoot, TRUE, NULL);
  228. // ppd->SetLine(2, lpszRelative, TRUE, NULL);
  229. return !ppd->HasUserCancelled();
  230. }
  231. STDMETHODIMP CUpload::AddMatchingInfo(
  232. BSTR pszCommand,
  233. VARIANT vFilter,
  234. VARIANT vKey,
  235. VARIANT vDescription,
  236. VARIANT vProgress,
  237. BOOL *pbSuccess)
  238. {
  239. /* HANDLE hThread = NULL;
  240. DWORD dwExitCode = 0;
  241. DWORD dwWait;
  242. */
  243. CComVariant varFilter(vFilter);
  244. DWORD dwFilter = GRABMI_FILTER_NORMAL;
  245. wstring strKey;
  246. wstring strDescription;
  247. if (SUCCEEDED(varFilter.ChangeType(VT_I4))) {
  248. dwFilter = (DWORD)varFilter.lVal;
  249. }
  250. strKey = VariantToStr(CComVariant(vKey));
  251. strDescription = VariantToStr(CComVariant(vDescription));
  252. *pbSuccess = AddMatchingInfoInternal(::GetActiveWindow(),
  253. pszCommand,
  254. dwFilter,
  255. VariantToBOOL(CComVariant(vProgress)),
  256. strKey.empty() ? NULL : strKey.c_str(),
  257. strDescription.empty() ? NULL : strDescription.c_str());
  258. /*
  259. MITHREADPARAMBLK* pParam = new MITHREADPARAMBLK;
  260. CComVariant varFilter(vFilter);
  261. if (!pParam) {
  262. goto cleanup;
  263. }
  264. pParam->pThis = this;
  265. pParam->strCommand = pszCommand;
  266. pParam->hwndParent = ::GetActiveWindow();
  267. pParam->dwFilter = GRABMI_FILTER_NORMAL;
  268. if (SUCCEEDED(varFilter.ChangeType(VT_I4))) {
  269. pParam->dwFilter = (DWORD)varFilter.lVal;
  270. }
  271. pParam->bNoProgress = VariantToBOOL(CComVariant(vProgress));
  272. pParam->strKey = VariantToStr(CComVariant(vKey));
  273. pParam->strDescription = VariantToStr(CComVariant(vDescription));
  274. hThread = CreateThread(NULL,
  275. 0,
  276. (LPTHREAD_START_ROUTINE)_AddMatchingInfoThreadProc,
  277. (LPVOID)pParam,
  278. 0,
  279. NULL);
  280. if (!hThread) {
  281. goto cleanup;
  282. }
  283. dwWait = WaitForSingleObject(hThread, INFINITE);
  284. if (dwWait != WAIT_OBJECT_0) {
  285. goto cleanup;
  286. }
  287. GetExitCodeThread(hThread, &dwExitCode);
  288. cleanup:
  289. if (hThread) {
  290. CloseHandle(hThread);
  291. }
  292. *pbSuccess = !!dwExitCode;
  293. */
  294. return S_OK;
  295. }
  296. DWORD WINAPI
  297. CUpload::_AddMatchingInfoThreadProc(LPVOID lpvThis)
  298. {
  299. BOOL bSuccess;
  300. HRESULT hr;
  301. MITHREADPARAMBLK* pParam = (MITHREADPARAMBLK*)lpvThis;
  302. if (!pParam->bNoProgress) {
  303. hr = CoInitialize(NULL);
  304. if (!SUCCEEDED(hr)) {
  305. pParam->bNoProgress = TRUE;
  306. }
  307. }
  308. bSuccess = pParam->pThis->AddMatchingInfoInternal(::GetActiveWindow(),
  309. pParam->strCommand.c_str(),
  310. pParam->dwFilter,
  311. pParam->bNoProgress,
  312. pParam->strKey.empty() ? NULL : pParam->strKey.c_str(),
  313. pParam->strDescription.empty() ? NULL : pParam->strDescription.c_str());
  314. if (!pParam->bNoProgress) {
  315. CoUninitialize();
  316. }
  317. delete pParam;
  318. return bSuccess;
  319. }
  320. BOOL CUpload::AddMatchingInfoInternal(
  321. HWND hwndParent,
  322. LPCWSTR pszCommand,
  323. DWORD dwFilter,
  324. BOOL bNoProgress,
  325. LPCTSTR pszKey,
  326. LPCTSTR pszDescription)
  327. {
  328. CComBSTR bstrPath;
  329. CComBSTR bstrGrabmiFile;
  330. BOOL bSuccess = FALSE;
  331. IProgressDialog * ppd = NULL;
  332. HRESULT hr;
  333. GMEPARAMS GrabmiParams;
  334. MFI MatchingFileInfo;
  335. wstring strKey;
  336. UINT DriveType;
  337. BOOL bLeaf = NULL;
  338. BOOL bRoot = NULL;
  339. DWORD dwFilters[3];
  340. wstring Paths[3];
  341. int nDrive;
  342. DWORD nPasses = 1;
  343. wstring DriveRoot(TEXT("X:\\"));
  344. //
  345. // this is kinda dangerous, the way it works. We collect the info while yielding to the
  346. // creating process (due to the start dialog
  347. // so the calling window needs to be disabled -- or we need to trap doing something else
  348. // while we're collecting data
  349. //
  350. if (!::GetExePathFromObject(pszCommand, bstrPath)) {
  351. return FALSE;
  352. }
  353. //
  354. // bstrPath is exe path, create and grab matching info
  355. //
  356. if (!GetTempFile(TEXT("ACG"), bstrGrabmiFile)) {
  357. goto cleanup;
  358. }
  359. //
  360. // we are going to run grabmi!!!
  361. //
  362. //
  363. // prepare callback
  364. //
  365. if (!bNoProgress) {
  366. hr = CoCreateInstance(CLSID_ProgressDialog,
  367. NULL,
  368. CLSCTX_INPROC_SERVER,
  369. IID_IProgressDialog,
  370. (void **)&ppd);
  371. if (!SUCCEEDED(hr)) {
  372. ppd = NULL;
  373. }
  374. }
  375. //
  376. // check to see what happened to hr
  377. //
  378. if (ppd) {
  379. wstring strCaption;
  380. strCaption = LoadResourceString(IDS_COLLECTINGDATACAPTION);
  381. ppd->SetTitle(strCaption.c_str()); // Set the title of the dialog.
  382. ppd->SetAnimation (_Module.GetModuleInstance(), IDA_FINDANIM); // Set the animation to play.
  383. strCaption = LoadResourceString(IDS_WAITCLEANUP);
  384. ppd->SetCancelMsg (strCaption.c_str(), NULL); // Will only be displayed if Cancel
  385. strCaption = LoadResourceString(IDS_GRABMISTATUS_COLLECTING);
  386. ppd->SetLine(1, strCaption.c_str(), FALSE, NULL);
  387. ppd->StartProgressDialog(hwndParent,
  388. NULL,
  389. PROGDLG_NOPROGRESSBAR|
  390. PROGDLG_MODAL|
  391. PROGDLG_NOMINIMIZE|
  392. PROGDLG_NORMAL|
  393. PROGDLG_NOTIME,
  394. NULL); // Display and enable automatic estimated time remain
  395. }
  396. //
  397. // this is where we have to determine whether grabmi is a going to be running wild
  398. // Check the drive first to see whether it's removable media
  399. // cases : leaf node / root node
  400. // : system directory
  401. // : cd-rom
  402. // : temp directory
  403. // there could be many combinations
  404. //
  405. if (ppd) {
  406. wstring strCaption = LoadResourceString(IDS_CHECKING_FILES);
  407. ppd->SetLine(2, strCaption.c_str(), FALSE, NULL);
  408. }
  409. //
  410. // this is the default filter we shall use
  411. //
  412. dwFilters[0] = GRABMI_FILTER_PRIVACY;
  413. Paths [0] = bstrPath;
  414. nPasses = 1;
  415. //
  416. // determine if it's root/leaf node (could be both)
  417. //
  418. if (!CheckFileLocation(bstrPath, &bRoot, &bLeaf)) {
  419. // we cannot check the file's location
  420. goto GrabInformation;
  421. }
  422. DriveType = GetDriveTypeW(bstrPath); // this will give us *some* clue
  423. // rules:
  424. // cdrom and not root -- three passes
  425. // root - add current file
  426. //
  427. if (bRoot || DRIVE_REMOTE == DriveType) {
  428. dwFilters[0] |= GRABMI_FILTER_LIMITFILES;
  429. } else if (DRIVE_CDROM == DriveType) {
  430. nDrive = PathGetDriveNumber(bstrPath);
  431. if (nDrive >= 0) {
  432. dwFilters[0] |= GRABMI_FILTER_NOCLOSE|GRABMI_FILTER_APPEND;
  433. dwFilters[1] = GRABMI_FILTER_NORECURSE|GRABMI_FILTER_APPEND;
  434. Paths [1] = DriveRoot;
  435. Paths [1].at(0) = (WCHAR)(TEXT('A') + nDrive);
  436. nPasses = 2;
  437. }
  438. }
  439. if (bLeaf) {
  440. // we may want to do more here -- future dev
  441. ;
  442. }
  443. GrabInformation:
  444. //
  445. // set callback context
  446. //
  447. GrabmiParams.first = this;
  448. GrabmiParams.second = ppd;
  449. while (nPasses-- > 0) {
  450. if (SdbGrabMatchingInfoEx(Paths[nPasses].c_str(),
  451. dwFilters[nPasses],
  452. bstrGrabmiFile,
  453. _GrabmiCallback,
  454. (LPVOID)&GrabmiParams) == GMI_FAILED) {
  455. goto cleanup;
  456. }
  457. }
  458. //
  459. // figure out the key/description
  460. //
  461. if (pszDescription) {
  462. MatchingFileInfo.strDescription = pszDescription;
  463. }
  464. MatchingFileInfo.strFileName = bstrGrabmiFile;
  465. MatchingFileInfo.bOwn = TRUE; // we have generated this file
  466. //
  467. // key
  468. //
  469. if (pszKey == NULL) {
  470. strKey = MatchingFileInfo.strFileName;
  471. } else {
  472. strKey = pszKey;
  473. }
  474. StrUpCase(strKey);
  475. m_DataFiles[strKey] = MatchingFileInfo;
  476. // m_DataFiles.push_back(StrUpCase(wstring(bstrGrabmiFile)));
  477. //
  478. //
  479. //
  480. bSuccess = TRUE;
  481. cleanup:
  482. if (ppd) {
  483. ppd->StopProgressDialog();
  484. ppd->Release();
  485. }
  486. return bSuccess;
  487. }
  488. STDMETHODIMP CUpload::AddDataFile(
  489. BSTR pszDataFile,
  490. VARIANT vKey,
  491. VARIANT vDescription,
  492. VARIANT vOwn)
  493. {
  494. MFI MatchingFileInfo;
  495. wstring strKey = VariantToStr(CComVariant(vKey));
  496. BOOL bKeyFromName = FALSE;
  497. if (strKey.empty()) {
  498. strKey = pszDataFile;
  499. bKeyFromName = TRUE;
  500. }
  501. StrUpCase(strKey);
  502. if (m_DataFiles.find(strKey) != m_DataFiles.end() && !bKeyFromName) {
  503. CComBSTR bstrKey = strKey.c_str();
  504. RemoveDataFile(bstrKey);
  505. }
  506. MatchingFileInfo.strDescription = VariantToStr(CComVariant(vDescription));
  507. MatchingFileInfo.strFileName = pszDataFile;
  508. MatchingFileInfo.bOwn = VariantToBOOL(CComVariant(vOwn));
  509. m_DataFiles[strKey] = MatchingFileInfo;
  510. // m_DataFiles.push_back(StrUpCase(wstring(pszDataFile)));
  511. return S_OK;
  512. }
  513. STDMETHODIMP CUpload::RemoveDataFile(BSTR pszDataFile)
  514. {
  515. // STRVEC::iterator iter;
  516. MAPSTR2MFI::iterator iter;
  517. wstring strFileName;
  518. wstring strDataFile = pszDataFile;
  519. StrUpCase(strDataFile);
  520. iter = m_DataFiles.find(strDataFile);
  521. if (iter != m_DataFiles.end()) {
  522. if ((*iter).second.bOwn) {
  523. ::DeleteFile((*iter).second.strFileName.c_str());
  524. }
  525. m_DataFiles.erase(iter);
  526. }
  527. /*
  528. for (iter = m_DataFiles.begin(); iter != m_DataFiles.end(); ++iter) {
  529. if (*iter == strDataFile) {
  530. //
  531. // found it
  532. //
  533. m_DataFiles.erase(iter);
  534. break;
  535. }
  536. }
  537. */
  538. return S_OK;
  539. }
  540. STDMETHODIMP CUpload::CreateManifestFile(BOOL *pbSuccess)
  541. {
  542. //
  543. // manifest file creation code
  544. //
  545. HANDLE hFile = INVALID_HANDLE_VALUE;
  546. WCHAR UNICODE_MARKER[] = { (WCHAR)0xFEFF, L'\r', L'\n' };
  547. MAPSTR2STR::iterator iter;
  548. DWORD dwWritten;
  549. wstring strLine;
  550. CComBSTR bstrDataFiles;
  551. BOOL bResult;
  552. BOOL bSuccess = FALSE;
  553. if (!GetTempFile(TEXT("ACM"), m_bstrManifest)) {
  554. goto cleanup;
  555. }
  556. //
  557. // m_bstrManifest is our file
  558. //
  559. hFile = CreateFileW(m_bstrManifest,
  560. GENERIC_READ|GENERIC_WRITE,
  561. FILE_SHARE_READ,
  562. NULL,
  563. CREATE_ALWAYS,
  564. FILE_ATTRIBUTE_NORMAL,
  565. NULL);
  566. if (hFile == INVALID_HANDLE_VALUE) {
  567. goto cleanup;
  568. }
  569. bResult = WriteFile(hFile, UNICODE_MARKER, sizeof(UNICODE_MARKER), &dwWritten, NULL);
  570. if (!bResult) {
  571. goto cleanup;
  572. }
  573. //
  574. // done with the marker, now do the manifest strings
  575. //
  576. //
  577. for (iter = m_mapManifest.begin(); iter != m_mapManifest.end(); ++iter) {
  578. strLine = (*iter).first + TEXT('=') + (*iter).second + TEXT("\r\n");
  579. bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
  580. if (!bResult) {
  581. goto cleanup;
  582. }
  583. }
  584. //
  585. // done with the general stuff, do the data files
  586. //
  587. if (GetDataFilesKey(bstrDataFiles)) {
  588. strLine = wstring(szKeyDataFiles) + TEXT('=') + wstring(bstrDataFiles) + TEXT("\r\n");
  589. bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
  590. if (!bResult) {
  591. goto cleanup;
  592. }
  593. }
  594. bSuccess = TRUE;
  595. cleanup:
  596. if (hFile != INVALID_HANDLE_VALUE) {
  597. CloseHandle(hFile);
  598. }
  599. if (!bSuccess && m_bstrManifest.Length()) {
  600. DeleteFile(m_bstrManifest);
  601. m_bstrManifest.Empty();
  602. }
  603. *pbSuccess = bSuccess;
  604. return S_OK;
  605. }
  606. STDMETHODIMP CUpload::SendReport(BOOL *pbSuccess)
  607. {
  608. UINT uSize;
  609. TCHAR szSystemWindowsDirectory[MAX_PATH];
  610. wstring strDWCmd;
  611. wstring strDWPath;
  612. STARTUPINFO StartupInfo;
  613. PROCESS_INFORMATION ProcessInfo;
  614. DWORD dwWait;
  615. BOOL bSuccess = FALSE;
  616. BOOL bResult;
  617. DWORD dwExitCode;
  618. BOOL bTerminated = FALSE;
  619. DWORD dwTimeout = 10; // 10ms per ping
  620. //
  621. // Create Progress dialog
  622. //
  623. IProgressDialog * ppd = NULL;
  624. HRESULT hr;
  625. if (IsHeadlessMode()) {
  626. hr = CoCreateInstance(CLSID_ProgressDialog,
  627. NULL,
  628. CLSCTX_INPROC_SERVER,
  629. IID_IProgressDialog,
  630. (void **)&ppd);
  631. if (!SUCCEEDED(hr)) {
  632. ppd = NULL;
  633. }
  634. }
  635. //
  636. // check to see what happened to hr
  637. //
  638. if (ppd) {
  639. wstring strCaption;
  640. strCaption = LoadResourceString(IDS_SENDINGCAPTION);
  641. ppd->SetTitle(strCaption.c_str()); // Set the title of the dialog.
  642. ppd->SetAnimation (_Module.GetModuleInstance(), IDA_WATSONANIM); // Set the animation to play.
  643. strCaption = LoadResourceString(IDS_WAITCLEANUP);
  644. ppd->SetCancelMsg (strCaption.c_str(), NULL); // Will only be displayed if Cancel
  645. strCaption = LoadResourceString(IDS_LAUNCHINGDR);
  646. ppd->SetLine (1, strCaption.c_str(), FALSE, NULL);
  647. ppd->StartProgressDialog(::GetActiveWindow(),
  648. NULL,
  649. PROGDLG_NOPROGRESSBAR|
  650. PROGDLG_MODAL|
  651. PROGDLG_NOMINIMIZE|
  652. PROGDLG_NORMAL|
  653. PROGDLG_NOTIME,
  654. NULL); // Display and enable automatic estimated time remain
  655. }
  656. uSize = ::GetSystemWindowsDirectory(szSystemWindowsDirectory,
  657. CHARCOUNT(szSystemWindowsDirectory));
  658. if (uSize == 0 || uSize > CHARCOUNT(szSystemWindowsDirectory)) {
  659. goto cleanup;
  660. }
  661. strDWPath = szSystemWindowsDirectory;
  662. if (strDWPath.at(strDWPath.length() - 1) != TCHAR('\\')) {
  663. strDWPath.append(TEXT("\\"));
  664. }
  665. strDWPath += TEXT("system32\\dwwin.exe");
  666. strDWCmd = strDWPath + TEXT(" -d ") + (LPCWSTR)m_bstrManifest;
  667. ZeroMemory(&StartupInfo, sizeof(StartupInfo));
  668. StartupInfo.cb = sizeof(StartupInfo);
  669. ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
  670. bResult = CreateProcess(strDWPath.c_str(),
  671. (LPWSTR)strDWCmd.c_str(),
  672. NULL,
  673. NULL,
  674. FALSE,
  675. 0,
  676. NULL,
  677. NULL,
  678. &StartupInfo,
  679. &ProcessInfo);
  680. if (bResult) {
  681. //
  682. // recover an exit code please
  683. //
  684. if (ppd) {
  685. wstring strSending = LoadResourceString(IDS_SENDINGINFO);
  686. ppd->SetLine(1, strSending.c_str(), FALSE, NULL);
  687. }
  688. while(TRUE) {
  689. dwWait = WaitForSingleObject(ProcessInfo.hProcess, dwTimeout);
  690. if (dwWait == WAIT_OBJECT_0) {
  691. if (GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode)) {
  692. bSuccess = (dwExitCode == 0);
  693. } else {
  694. bSuccess = FALSE;
  695. }
  696. break;
  697. } else if (dwWait == WAIT_TIMEOUT) {
  698. //
  699. // check the cancel button
  700. //
  701. if (ppd && !bTerminated && ppd->HasUserCancelled()) {
  702. TerminateProcess(ProcessInfo.hProcess, (UINT)-1);
  703. bTerminated = TRUE;
  704. bSuccess = FALSE;
  705. dwTimeout = 1000; // wait a bit longer
  706. }
  707. } else { // object somehow became abandoned
  708. bSuccess = FALSE;
  709. break;
  710. }
  711. }
  712. }
  713. if (ppd) {
  714. wstring strCleaningUp = LoadResourceString(IDS_CLEANINGUP);
  715. ppd->SetLine(1, strCleaningUp.c_str(), FALSE, NULL);
  716. }
  717. cleanup:
  718. if (ProcessInfo.hThread) {
  719. CloseHandle(ProcessInfo.hThread);
  720. }
  721. if (ProcessInfo.hProcess) {
  722. CloseHandle(ProcessInfo.hProcess);
  723. }
  724. if (ppd) {
  725. ppd->StopProgressDialog();
  726. ppd->Release();
  727. }
  728. *pbSuccess = bSuccess;
  729. return S_OK;
  730. }
  731. wstring MakeXMLAttr(LPCTSTR lpszName, LPCTSTR lpszValue)
  732. {
  733. wstring str;
  734. wstring strVal;
  735. LPCTSTR pch;
  736. wstring::size_type nPos = 0;
  737. int nlen;
  738. if (NULL != lpszValue) {
  739. strVal = lpszValue;
  740. }
  741. // find and replace: all the instances of &quot; &amp; &lt; &gt;
  742. //
  743. while (nPos != wstring::npos && nPos < strVal.length()) {
  744. nPos = strVal.find_first_of(TEXT("&\"<>"), nPos);
  745. if (nPos == wstring::npos) {
  746. break;
  747. }
  748. switch(strVal.at(nPos)) {
  749. case TEXT('&'):
  750. pch = TEXT("&amp;");
  751. break;
  752. case TEXT('>'):
  753. pch = TEXT("&gt;");
  754. break;
  755. case TEXT('<'):
  756. pch = TEXT("&lt;");
  757. break;
  758. case TEXT('\"'):
  759. pch = TEXT("&quot;");
  760. break;
  761. default:
  762. // lunacy, we saw it -- and now it's gone
  763. pch = NULL;
  764. break;
  765. }
  766. if (pch) {
  767. strVal.replace(nPos, 1, pch); // one character
  768. nPos += _tcslen(pch);
  769. }
  770. }
  771. // once we got the string, assign
  772. str = lpszName;
  773. str += TEXT("=\"");
  774. str += strVal;
  775. str += TEXT("\"");
  776. return str;
  777. }
  778. wstring MakeXMLAttr(LPCTSTR lpszName, LONG lValue)
  779. {
  780. WCHAR szBuf[32];
  781. wstring str;
  782. swprintf(szBuf, TEXT("\"0x%lx\""), lValue);
  783. str = lpszName;
  784. str += TEXT("=");
  785. str += szBuf;
  786. return str;
  787. }
  788. wstring MakeXMLLayers(LPCTSTR lpszLayers)
  789. {
  790. wstring str;
  791. wstring strLayer;
  792. LPCTSTR pch, pbrk;
  793. //
  794. // partition the string
  795. //
  796. pch = lpszLayers;
  797. while (pch && *pch != TEXT('\0')) {
  798. pch += _tcsspn(pch, TEXT(" \t"));
  799. // check if we're not at the end
  800. if (*pch == TEXT('\0')) {
  801. break;
  802. }
  803. pbrk = _tcspbrk(pch, TEXT(" \t"));
  804. if (pbrk == NULL) {
  805. // from pch to the end of the string
  806. strLayer.assign(pch);
  807. } else {
  808. strLayer.assign(pch, (int)(pbrk-pch));
  809. }
  810. if (!str.empty()) {
  811. str += TEXT("\r\n");
  812. }
  813. str += TEXT(" "); // lead-in
  814. str += TEXT("<LAYER NAME=\"");
  815. str += strLayer;
  816. str += TEXT("\"/>");
  817. pch = pbrk;
  818. }
  819. return str;
  820. }
  821. STDMETHODIMP CUpload::AddDescriptionFile(
  822. BSTR pszApplicationName,
  823. BSTR pszApplicationPath,
  824. LONG lMediaType,
  825. BOOL bCompatSuccess,
  826. VARIANT* pvFixesApplied,
  827. VARIANT vKey,
  828. BOOL *pbSuccess
  829. )
  830. {
  831. //
  832. // manifest file creation code
  833. //
  834. HANDLE hFile = INVALID_HANDLE_VALUE;
  835. WCHAR UNICODE_MARKER[] = { (WCHAR)0xFEFF, L'\r', L'\n' };
  836. DWORD dwWritten;
  837. wstring strLine;
  838. CComBSTR bstrDescriptionFile;
  839. BOOL bResult;
  840. BOOL bSuccess = FALSE;
  841. WCHAR szBuf[32];
  842. VARIANT vFixes;
  843. MFI MatchingFileInfo;
  844. wstring strKey = VariantToStr(CComVariant(vKey));
  845. wstring strLayers;
  846. static TCHAR szTab[] = TEXT(" ");
  847. static TCHAR szCRTab[] = TEXT("\r\n ");
  848. VariantInit(&vFixes);
  849. if (!GetTempFile(TEXT("ACI"), bstrDescriptionFile)) {
  850. goto cleanup;
  851. }
  852. //
  853. // m_bstrManifest is our file
  854. //
  855. hFile = CreateFileW(bstrDescriptionFile,
  856. GENERIC_READ|GENERIC_WRITE,
  857. FILE_SHARE_READ,
  858. NULL,
  859. CREATE_ALWAYS,
  860. FILE_ATTRIBUTE_NORMAL,
  861. NULL);
  862. if (hFile == INVALID_HANDLE_VALUE) {
  863. goto cleanup;
  864. }
  865. bResult = WriteFile(hFile, UNICODE_MARKER, sizeof(UNICODE_MARKER), &dwWritten, NULL);
  866. if (!bResult) {
  867. goto cleanup;
  868. }
  869. // xml marker
  870. strLine = TEXT("<?xml version=\"1.0\" encoding=\"UTF-16\"?>\r\n");
  871. bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
  872. if (!bResult) {
  873. goto cleanup;
  874. }
  875. // compose compat wizard...
  876. strLine = TEXT("<CompatWizardResults");
  877. strLine += TEXT(' ');
  878. strLine += MakeXMLAttr(TEXT("ApplicationName"), pszApplicationName);
  879. strLine += szCRTab;
  880. strLine += MakeXMLAttr(TEXT("ApplicationPath"), pszApplicationPath);
  881. strLine += szCRTab;
  882. strLine += MakeXMLAttr(TEXT("MediaType"), lMediaType);
  883. strLine += szCRTab;
  884. strLine += MakeXMLAttr(TEXT("CompatibilityResult"), bCompatSuccess ? TEXT("Success") : TEXT("Failure"));
  885. strLine += TEXT(">\r\n");
  886. if (SUCCEEDED(VariantChangeType(&vFixes, pvFixesApplied, 0, VT_BSTR))) {
  887. strLayers = vFixes.bstrVal;
  888. }
  889. if (!strLayers.empty()) {
  890. //
  891. // parse the layers string and get all of them listed
  892. //
  893. strLine += MakeXMLLayers(strLayers.c_str());
  894. strLine += TEXT("\r\n");
  895. }
  896. strLine += TEXT("</CompatWizardResults>\r\n");
  897. // we are done generating data, write it all out
  898. bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
  899. if (!bResult) {
  900. goto cleanup;
  901. }
  902. /*
  903. //
  904. // after we get through the descriptions
  905. // write out data
  906. strLine = TEXT("[CompatWizardResults]\r\n");
  907. bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
  908. if (!bResult) {
  909. goto cleanup;
  910. }
  911. //
  912. // write out all the info
  913. //
  914. strLine = TEXT("ApplicationName=");
  915. strLine += pszApplicationName;
  916. strLine += TEXT("\r\n");
  917. bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
  918. if (!bResult) {
  919. goto cleanup;
  920. }
  921. strLine = TEXT("ApplicationPath=");
  922. strLine += pszApplicationPath;
  923. strLine += TEXT("\r\n");
  924. bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
  925. if (!bResult) {
  926. goto cleanup;
  927. }
  928. strLine = TEXT("MediaType=");
  929. _sntprintf(szBuf, CHARCOUNT(szBuf), TEXT("0x%lx"), lMediaType);
  930. strLine += szBuf;
  931. strLine += TEXT("\r\n");
  932. bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
  933. if (!bResult) {
  934. goto cleanup;
  935. }
  936. //
  937. // success
  938. //
  939. strLine = TEXT("CompatibilityResult=");
  940. strLine += bCompatSuccess ? TEXT("Success") : TEXT("Failure");
  941. strLine += TEXT("\r\n");
  942. bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
  943. if (!bResult) {
  944. goto cleanup;
  945. }
  946. //
  947. // fixes applied
  948. //
  949. strLine = TEXT("Layers=");
  950. if (!SUCCEEDED(VariantChangeType(&vFixes, pvFixesApplied, 0, VT_BSTR))) {
  951. strLine += TEXT("none");
  952. } else {
  953. strLine += vFixes.bstrVal;
  954. }
  955. strLine += TEXT("\r\n");
  956. bResult = WriteFile(hFile, strLine.c_str(), strLine.length() * sizeof(WCHAR), &dwWritten, NULL);
  957. if (!bResult) {
  958. goto cleanup;
  959. }
  960. */
  961. // standard file -- manifesto
  962. MatchingFileInfo.strDescription = TEXT("Application Compatibility Description File");
  963. MatchingFileInfo.strFileName = bstrDescriptionFile;
  964. MatchingFileInfo.bOwn = TRUE;
  965. //
  966. // key is the filename prefixed by ACI_c:\foo\bar.exe
  967. //
  968. if (strKey.empty()) {
  969. strKey = TEXT("ACI_");
  970. strKey += pszApplicationPath;
  971. }
  972. StrUpCase(strKey);
  973. m_DataFiles[strKey] = MatchingFileInfo;
  974. // m_DataFiles.push_back(StrUpCase(wstring(bstrDescriptionFile)));
  975. bSuccess = TRUE;
  976. cleanup:
  977. if (hFile != INVALID_HANDLE_VALUE) {
  978. CloseHandle(hFile);
  979. }
  980. if (!bSuccess && bstrDescriptionFile.Length()) {
  981. DeleteFile(bstrDescriptionFile);
  982. }
  983. *pbSuccess = bSuccess;
  984. VariantClear(&vFixes);
  985. return S_OK;
  986. }
  987. STDMETHODIMP CUpload::DeleteTempFiles()
  988. {
  989. // kill all the supplemental files
  990. // STRVEC::iterator iter;
  991. MAPSTR2MFI::iterator iter;
  992. for (iter = m_DataFiles.begin(); iter != m_DataFiles.end(); ++iter) {
  993. if ((*iter).second.bOwn) {
  994. ::DeleteFile((*iter).second.strFileName.c_str());
  995. }
  996. }
  997. m_DataFiles.clear();
  998. //
  999. // kill the manifest
  1000. //
  1001. if (m_bstrManifest.Length() > 0) {
  1002. ::DeleteFile((LPCTSTR)m_bstrManifest);
  1003. }
  1004. m_bstrManifest.Empty();
  1005. return S_OK;
  1006. }
  1007. VOID CUpload::ListTempFiles(wstring& str)
  1008. {
  1009. // STRVEC::iterator iter;
  1010. MAPSTR2MFI::iterator iter;
  1011. str = TEXT("");
  1012. for (iter = m_DataFiles.begin(); iter != m_DataFiles.end(); ++iter) {
  1013. if (!str.empty()) {
  1014. str += TEXT(";");
  1015. }
  1016. str += (*iter).second.strFileName.c_str();
  1017. }
  1018. /* // this will show the manifest file as well -- but I don't think we need to
  1019. // do this as the manifest is irrelevant
  1020. if (!str.empty()) {
  1021. str += TEXT("\r\n");
  1022. }
  1023. str += (LPCTSTR)m_bstrManifest;
  1024. */
  1025. }
  1026. STDMETHODIMP CUpload::ShowTempFiles()
  1027. {
  1028. TCHAR szMshtml[] = TEXT("mshtml.dll");
  1029. TCHAR szModuleFileName[MAX_PATH];
  1030. LPMONIKER pmk = NULL;
  1031. HRESULT hr;
  1032. CComVariant vargIn;
  1033. CComVariant vargOut;
  1034. DWORD dwLength;
  1035. TCHAR szUrl2[MAX_PATH];
  1036. wstring strURL = TEXT("res://");
  1037. wstring strArg;
  1038. SHOWHTMLDIALOGFN* pfnShowDlg = NULL;
  1039. HMODULE hMshtml = ::GetModuleHandle(szMshtml);
  1040. if (NULL == hMshtml) {
  1041. hMshtml = ::LoadLibrary(szMshtml);
  1042. if (NULL == hMshtml) {
  1043. goto cleanup;
  1044. }
  1045. }
  1046. pfnShowDlg = (SHOWHTMLDIALOGFN*)GetProcAddress(hMshtml,
  1047. "ShowHTMLDialog");
  1048. if (NULL == pfnShowDlg) {
  1049. goto cleanup;
  1050. }
  1051. dwLength = ::GetModuleFileName(_Module.GetModuleInstance(),
  1052. szModuleFileName,
  1053. CHARCOUNT(szModuleFileName));
  1054. if (dwLength == 0 || dwLength >= CHARCOUNT(szModuleFileName)) {
  1055. goto cleanup;
  1056. }
  1057. _sntprintf(szUrl2, CHARCOUNT(szUrl2),
  1058. TEXT("/#%d/%s"),
  1059. (int)PtrToInt(RT_HTML),
  1060. IDR_SHOWTEMPFILESDLG);
  1061. strURL += szModuleFileName;
  1062. strURL += szUrl2;
  1063. hr = CreateURLMoniker(NULL, strURL.c_str(), &pmk);
  1064. if (!SUCCEEDED(hr)) {
  1065. goto cleanup;
  1066. }
  1067. ListTempFiles(strArg);
  1068. // create argument In
  1069. vargIn = strArg.c_str();
  1070. pfnShowDlg(::GetActiveWindow(),
  1071. pmk,
  1072. &vargIn,
  1073. TEXT("center:yes"),
  1074. &vargOut);
  1075. cleanup:
  1076. if (NULL != pmk) {
  1077. pmk->Release();
  1078. }
  1079. return S_OK;
  1080. }
  1081. STDMETHODIMP CUpload::GetDataFile(VARIANT vKey, LONG InformationClass, VARIANT* pVal)
  1082. {
  1083. CComVariant varKey(vKey);
  1084. LONG lIndex;
  1085. MAPSTR2MFI::iterator iter;
  1086. wstring str;
  1087. HRESULT hr = S_OK;
  1088. pVal->vt = VT_NULL;
  1089. switch(InformationClass) {
  1090. case InfoClassCount:
  1091. // requested: counter
  1092. pVal->vt = VT_I4;
  1093. pVal->lVal = m_DataFiles.size();
  1094. break;
  1095. case InfoClassKey:
  1096. if (!SUCCEEDED(varKey.ChangeType(VT_I4))) {
  1097. break;
  1098. }
  1099. lIndex = varKey.lVal;
  1100. iter = m_DataFiles.begin();
  1101. while (iter != m_DataFiles.end() && lIndex > 0) {
  1102. ++iter;
  1103. --lIndex;
  1104. }
  1105. if (iter != m_DataFiles.end()) {
  1106. hr = StringToVariant(pVal, (*iter).first);
  1107. }
  1108. break;
  1109. case InfoClassFileName:
  1110. case InfoClassDescription:
  1111. if (SUCCEEDED(varKey.ChangeType(VT_I4))) {
  1112. lIndex = varKey.lVal;
  1113. iter = m_DataFiles.begin();
  1114. while (iter != m_DataFiles.end() && lIndex > 0) {
  1115. ++iter;
  1116. --lIndex;
  1117. }
  1118. } else if (SUCCEEDED(varKey.ChangeType(VT_BSTR))) {
  1119. str = varKey.bstrVal;
  1120. iter = m_DataFiles.find(str);
  1121. }
  1122. if (iter != m_DataFiles.end()) {
  1123. switch(InformationClass) {
  1124. case InfoClassFileName:
  1125. str = (*iter).second.strFileName;
  1126. break;
  1127. case InfoClassDescription:
  1128. str = (*iter).second.strDescription;
  1129. break;
  1130. }
  1131. hr = StringToVariant(pVal, str);
  1132. }
  1133. break;
  1134. default:
  1135. break;
  1136. }
  1137. return hr;
  1138. }