Leaked source code of windows server 2003
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.

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