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.

907 lines
28 KiB

  1. //
  2. // Random stuff
  3. //
  4. //
  5. #include "priv.h"
  6. #include "exdisp.h"
  7. #include "mshtml.h"
  8. #include "htiframe.h"
  9. #include "util.h"
  10. #include "resource.h"
  11. #include "appwizid.h"
  12. #define CPP_FUNCTIONS
  13. #include <crtfree.h> // declare new, delete, etc.
  14. #define DATEFORMAT_MAX 40
  15. #include <shguidp.h>
  16. #include <ieguidp.h>
  17. // is this okay to do?
  18. #ifdef ENTERCRITICAL
  19. #undef ENTERCRITICAL
  20. #endif
  21. #ifdef LEAVECRITICAL
  22. #undef LEAVECRITICAL
  23. #endif
  24. #define ENTERCRITICAL
  25. #define LEAVECRITICAL
  26. #include "..\inc\uassist.cpp"
  27. // Prototype
  28. BOOL _IsARPAllowed(void);
  29. const VARIANT c_vaEmpty = {0};
  30. #define PVAREMPTY ((VARIANT*)&c_vaEmpty)
  31. STDAPI OpenAppMgr(HWND hwnd, int nPage)
  32. {
  33. HRESULT hres = E_FAIL;
  34. // Make sure we aren't restricted
  35. if (!_IsARPAllowed())
  36. {
  37. ShellMessageBox(g_hinst, hwnd, MAKEINTRESOURCE(IDS_RESTRICTION),
  38. MAKEINTRESOURCE(IDS_NAME), MB_OK | MB_ICONEXCLAMATION);
  39. }
  40. else if ((nPage >= 0) && (nPage < NUMSTARTPAGES))
  41. {
  42. ARP(hwnd, nPage);
  43. hres = S_OK;
  44. }
  45. return hres;
  46. }
  47. inline void StrFree(LPWSTR psz)
  48. {
  49. if (psz)
  50. SHFree(psz);
  51. }
  52. /*-------------------------------------------------------------------------
  53. Purpose: Clear the given app data structure. Frees any allocated fields.
  54. */
  55. void ClearAppInfoData(APPINFODATA * pdata)
  56. {
  57. if (pdata)
  58. {
  59. if (pdata->dwMask & AIM_DISPLAYNAME)
  60. StrFree(pdata->pszDisplayName);
  61. if (pdata->dwMask & AIM_VERSION)
  62. StrFree(pdata->pszVersion);
  63. if (pdata->dwMask & AIM_PUBLISHER)
  64. StrFree(pdata->pszPublisher);
  65. if (pdata->dwMask & AIM_PRODUCTID)
  66. StrFree(pdata->pszProductID);
  67. if (pdata->dwMask & AIM_REGISTEREDOWNER)
  68. StrFree(pdata->pszRegisteredOwner);
  69. if (pdata->dwMask & AIM_REGISTEREDCOMPANY)
  70. StrFree(pdata->pszRegisteredCompany);
  71. if (pdata->dwMask & AIM_LANGUAGE)
  72. StrFree(pdata->pszLanguage);
  73. if (pdata->dwMask & AIM_SUPPORTURL)
  74. StrFree(pdata->pszSupportUrl);
  75. if (pdata->dwMask & AIM_SUPPORTTELEPHONE)
  76. StrFree(pdata->pszSupportTelephone);
  77. if (pdata->dwMask & AIM_HELPLINK)
  78. StrFree(pdata->pszHelpLink);
  79. if (pdata->dwMask & AIM_INSTALLLOCATION)
  80. StrFree(pdata->pszInstallLocation);
  81. if (pdata->dwMask & AIM_INSTALLSOURCE)
  82. StrFree(pdata->pszInstallSource);
  83. if (pdata->dwMask & AIM_INSTALLDATE)
  84. StrFree(pdata->pszInstallDate);
  85. if (pdata->dwMask & AIM_CONTACT)
  86. StrFree(pdata->pszContact);
  87. if (pdata->dwMask & AIM_COMMENTS)
  88. StrFree(pdata->pszComments);
  89. if (pdata->dwMask & AIM_IMAGE)
  90. StrFree(pdata->pszImage);
  91. }
  92. }
  93. void ClearSlowAppInfo(SLOWAPPINFO * pdata)
  94. {
  95. if (pdata)
  96. {
  97. StrFree(pdata->pszImage);
  98. pdata->pszImage = NULL;
  99. }
  100. }
  101. // NOTE: Returns TRUE only if psaiNew has valid info and different from psaiOrig
  102. BOOL IsSlowAppInfoChanged(PSLOWAPPINFO psaiOrig, PSLOWAPPINFO psaiNew)
  103. {
  104. BOOL bRet = FALSE;
  105. ASSERT(psaiOrig && psaiNew);
  106. if (psaiNew)
  107. {
  108. // Compare size first
  109. if (psaiOrig == NULL)
  110. {
  111. bRet = TRUE;
  112. }
  113. else if (((__int64)psaiNew->ullSize > 0) && (psaiNew->ullSize != psaiOrig->ullSize))
  114. {
  115. bRet = TRUE;
  116. }
  117. // Now compare the file time
  118. else if (((0 != psaiNew->ftLastUsed.dwHighDateTime) &&
  119. (psaiOrig->ftLastUsed.dwHighDateTime != psaiNew->ftLastUsed.dwHighDateTime))
  120. || ((0 != psaiNew->ftLastUsed.dwLowDateTime) &&
  121. (psaiOrig->ftLastUsed.dwLowDateTime != psaiNew->ftLastUsed.dwLowDateTime)))
  122. {
  123. bRet = TRUE;
  124. }
  125. // Compare times used
  126. else if (psaiOrig->iTimesUsed != psaiNew->iTimesUsed)
  127. {
  128. bRet = TRUE;
  129. }
  130. // Compare the icon image
  131. else if ((psaiNew->pszImage != NULL) && (psaiOrig->pszImage != NULL) && lstrcmpi(psaiNew->pszImage, psaiOrig->pszImage))
  132. bRet = TRUE;
  133. }
  134. return bRet;
  135. }
  136. void ClearManagedApplication(MANAGEDAPPLICATION * pma)
  137. {
  138. if (pma)
  139. {
  140. if (pma->pszPackageName)
  141. LocalFree(pma->pszPackageName);
  142. if (pma->pszPublisher)
  143. LocalFree(pma->pszPublisher);
  144. if (pma->pszPolicyName)
  145. LocalFree(pma->pszPolicyName);
  146. if (pma->pszOwner)
  147. LocalFree(pma->pszOwner);
  148. if (pma->pszCompany)
  149. LocalFree(pma->pszCompany);
  150. if (pma->pszComments)
  151. LocalFree(pma->pszComments);
  152. if (pma->pszContact)
  153. LocalFree(pma->pszContact);
  154. }
  155. }
  156. /*-------------------------------------------------------------------------
  157. Purpose: Clear the given PUBAPPINFO data structure. Frees any allocated fields.
  158. */
  159. void ClearPubAppInfo(PUBAPPINFO * pdata)
  160. {
  161. if (pdata)
  162. {
  163. if ((pdata->dwMask & PAI_SOURCE) && pdata->pszSource)
  164. StrFree(pdata->pszSource);
  165. }
  166. }
  167. /*-------------------------------------------------------------------------
  168. Purpose: Frees a specific category structure
  169. */
  170. HRESULT ReleaseShellCategory(SHELLAPPCATEGORY * psac)
  171. {
  172. ASSERT(psac);
  173. if (psac->pszCategory)
  174. {
  175. SHFree(psac->pszCategory);
  176. psac->pszCategory = NULL;
  177. }
  178. return S_OK;
  179. }
  180. /*-------------------------------------------------------------------------
  181. Purpose: Frees the list of categories
  182. */
  183. HRESULT ReleaseShellCategoryList(SHELLAPPCATEGORYLIST * psacl)
  184. {
  185. UINT i;
  186. SHELLAPPCATEGORY * psac;
  187. ASSERT(psacl);
  188. psac = psacl->pCategory;
  189. for (i = 0; i < psacl->cCategories; i++, psac++)
  190. {
  191. ReleaseShellCategory(psac);
  192. }
  193. return S_OK;
  194. }
  195. #define MAX_INT64_SIZE 30 // 2^64 is less than 30 chars long
  196. #define MAX_COMMA_NUMBER_SIZE (MAX_INT64_SIZE + 10)
  197. #define MAX_COMMA_AS_K_SIZE (MAX_COMMA_NUMBER_SIZE + 10)
  198. #define HIDWORD(_qw) (DWORD)((_qw)>>32)
  199. #define LODWORD(_qw) (DWORD)(_qw)
  200. void Int64ToStr( _int64 n, LPTSTR lpBuffer)
  201. {
  202. TCHAR szTemp[MAX_INT64_SIZE];
  203. _int64 iChr;
  204. iChr = 0;
  205. do {
  206. szTemp[iChr++] = TEXT('0') + (TCHAR)(n % 10);
  207. n = n / 10;
  208. } while (n != 0);
  209. do {
  210. iChr--;
  211. *lpBuffer++ = szTemp[iChr];
  212. } while (iChr != 0);
  213. *lpBuffer++ = '\0';
  214. }
  215. // takes a DWORD add commas etc to it and puts the result in the buffer
  216. LPTSTR WINAPI AddCommas64(_int64 n, LPTSTR pszResult, UINT cchResult)
  217. {
  218. // FEATURE: We should pass in the lenght on pszResult buffer, we assume 40 will be enough
  219. TCHAR szTemp[MAX_COMMA_NUMBER_SIZE];
  220. TCHAR szSep[5];
  221. NUMBERFMT nfmt;
  222. nfmt.NumDigits=0;
  223. nfmt.LeadingZero=0;
  224. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szSep, ARRAYSIZE(szSep));
  225. nfmt.Grouping = StrToInt(szSep);
  226. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYSIZE(szSep));
  227. nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep;
  228. nfmt.NegativeOrder= 0;
  229. Int64ToStr(n, szTemp);
  230. // Should have passed in size
  231. if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt, pszResult, MAX_COMMA_NUMBER_SIZE) == 0)
  232. {
  233. StringCchCopy(pszResult, cchResult, szTemp);
  234. }
  235. return pszResult;
  236. }
  237. //
  238. // Add Peta 10^15 and Exa 10^18 to support 64-bit integers.
  239. //
  240. const short pwOrders[] = {IDS_BYTES, IDS_ORDERKB, IDS_ORDERMB,
  241. IDS_ORDERGB, IDS_ORDERTB, IDS_ORDERPB, IDS_ORDEREB};
  242. /* converts numbers into sort formats
  243. * 532 -> 523 bytes
  244. * 1340 -> 1.3KB
  245. * 23506 -> 23.5KB
  246. * -> 2.4MB
  247. * -> 5.2GB
  248. */
  249. LPTSTR WINAPI ShortSizeFormat64(__int64 dw64, LPTSTR szBuf)
  250. {
  251. int i;
  252. _int64 wInt;
  253. UINT wLen, wDec;
  254. TCHAR szTemp[MAX_COMMA_NUMBER_SIZE], szOrder[20], szFormat[5];
  255. if (dw64 < 1000)
  256. {
  257. StringCchPrintf(szTemp, ARRAYSIZE(szTemp), TEXT("%d"), LODWORD(dw64));
  258. i = 0;
  259. goto AddOrder;
  260. }
  261. for (i = 1; i<ARRAYSIZE(pwOrders)-1 && dw64 >= 1000L * 1024L; dw64 >>= 10, i++);
  262. /* do nothing */
  263. wInt = dw64 >> 10;
  264. AddCommas64(wInt, szTemp, ARRAYSIZE(szTemp));
  265. wLen = lstrlen(szTemp);
  266. if (wLen < 3)
  267. {
  268. wDec = LODWORD(dw64 - wInt * 1024L) * 1000 / 1024;
  269. // At this point, wDec should be between 0 and 1000
  270. // we want get the top one (or two) digits.
  271. wDec /= 10;
  272. if (wLen == 2)
  273. wDec /= 10;
  274. // Note that we need to set the format before getting the
  275. // intl char.
  276. StringCchCopy(szFormat, ARRAYSIZE(szFormat), TEXT("%02d"));
  277. szFormat[2] = TEXT('0') + 3 - wLen;
  278. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
  279. szTemp+wLen, ARRAYSIZE(szTemp)-wLen);
  280. wLen = lstrlen(szTemp);
  281. wLen += wsprintf(szTemp+wLen, szFormat, wDec);
  282. }
  283. AddOrder:
  284. LoadString(HINST_THISDLL, pwOrders[i], szOrder, ARRAYSIZE(szOrder));
  285. StringCchPrintf(szBuf, ARRAYSIZE(szBuf), szOrder, (LPTSTR)szTemp);
  286. return szBuf;
  287. }
  288. #define c_szUninstallPolicy L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Uninstall"
  289. /*-------------------------------------------------------------------------
  290. Purpose: Helper function for ARP's policy check
  291. */
  292. DWORD ARPGetRestricted(LPCWSTR pszPolicy)
  293. {
  294. return SHGetRestriction(NULL, TEXT("Uninstall"), pszPolicy);
  295. }
  296. /*-------------------------------------------------------------------------
  297. Purpose: Return a policy string value
  298. */
  299. void ARPGetPolicyString(LPCWSTR pszPolicy, LPWSTR pszBuf, int cch)
  300. {
  301. DWORD dwSize, dwType;
  302. *pszBuf = 0;
  303. // Check local machine first and let it override what the
  304. // HKCU policy has done.
  305. dwSize = cch * sizeof(WCHAR);
  306. if (ERROR_SUCCESS != SHGetValueW(HKEY_LOCAL_MACHINE,
  307. c_szUninstallPolicy, pszPolicy,
  308. &dwType, pszBuf, &dwSize))
  309. {
  310. // Check current user if we didn't find anything for the local machine.
  311. dwSize = cch * sizeof(WCHAR);
  312. SHGetValueW(HKEY_CURRENT_USER,
  313. c_szUninstallPolicy, pszPolicy,
  314. &dwType, pszBuf, &dwSize);
  315. }
  316. }
  317. /*-------------------------------------------------------------------------
  318. Purpose: Returns TRUE if it's okay to start ARP.
  319. */
  320. BOOL _IsARPAllowed(void)
  321. {
  322. // ARP is forbidden if the entire CPL is disabled
  323. if (ARPGetRestricted(L"NoAddRemovePrograms"))
  324. {
  325. return FALSE;
  326. }
  327. // ARP is permitted if there exists a non-restricted page.
  328. BOOL fAnyPages = !ARPGetRestricted(L"NoRemovePage") ||
  329. !ARPGetRestricted(L"NoAddPage") ||
  330. !ARPGetRestricted(L"NoWindowsSetupPage");
  331. // If we are not a server SKU, then also check the new page.
  332. if (!fAnyPages && !IsOS(OS_ANYSERVER))
  333. {
  334. fAnyPages = !ARPGetRestricted(L"NoChooseProgramsPage");
  335. }
  336. return fAnyPages;
  337. }
  338. /*-------------------------------------------------------------------------
  339. Purpose: Take the error message and give user feedback through messagebox
  340. */
  341. void _ARPErrorMessageBox(DWORD dwError)
  342. {
  343. TCHAR szErrorMsg[MAX_PATH];
  344. szErrorMsg[0] = 0;
  345. LPTSTR pszMsg = NULL;
  346. switch (dwError) {
  347. // The following error code cases are ignored.
  348. case ERROR_INSTALL_USEREXIT:
  349. case ERROR_SUCCESS_REBOOT_REQUIRED:
  350. case ERROR_SUCCESS_REBOOT_INITIATED:
  351. ASSERT(pszMsg == NULL);
  352. break;
  353. default:
  354. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0L, szErrorMsg,
  355. ARRAYSIZE(szErrorMsg), NULL);
  356. pszMsg = szErrorMsg;
  357. break;
  358. }
  359. if (pszMsg)
  360. {
  361. ShellMessageBox( g_hinst, NULL, pszMsg,
  362. MAKEINTRESOURCE( IDS_NAME ),
  363. MB_OK | MB_ICONEXCLAMATION);
  364. }
  365. }
  366. /*-------------------------------------------------------------------------
  367. Purpose: Format the SYSTEMTIME into the following format: "mm/dd/yy h:mm"
  368. */
  369. BOOL FormatSystemTimeString(LPSYSTEMTIME pst, LPTSTR pszStr, UINT cchStr)
  370. {
  371. BOOL bRet = FALSE;
  372. FILETIME ft = {0};
  373. if (SystemTimeToFileTime(pst, &ft))
  374. {
  375. DWORD dwFlags = FDTF_SHORTTIME | FDTF_SHORTDATE;
  376. bRet = SHFormatDateTime(&ft, &dwFlags, pszStr, cchStr);
  377. }
  378. return bRet;
  379. }
  380. /*-------------------------------------------------------------------------
  381. Purpose: Get the correct Date time format for specific locale
  382. */
  383. BOOL _GetLocaleDateTimeFormat(LPTSTR pszFormat, UINT cchFormat)
  384. {
  385. TCHAR szTime[DATEFORMAT_MAX];
  386. TCHAR szDate[DATEFORMAT_MAX];
  387. if (cchFormat >= (ARRAYSIZE(szTime) + ARRAYSIZE(szDate) + 2))
  388. {
  389. LCID lcid = LOCALE_USER_DEFAULT;
  390. if (GetLocaleInfo(lcid, LOCALE_STIMEFORMAT, szTime, ARRAYSIZE(szTime)) &&
  391. GetLocaleInfo(lcid, LOCALE_SSHORTDATE, szDate, ARRAYSIZE(szDate)))
  392. {
  393. StringCchPrintf(pszFormat, cchFormat, TEXT("%s %s"), szDate, szTime);
  394. return TRUE;
  395. }
  396. }
  397. return FALSE;
  398. }
  399. /*-------------------------------------------------------------------------
  400. Purpose: Compare two SYSTEMTIME data
  401. Returnes : 1 : st1 > st2
  402. 0 : st1 == st2
  403. -1: st1 < st2
  404. NOTE: We do not compare seconds since ARP does not need that much precision.
  405. */
  406. int CompareSystemTime(SYSTEMTIME *pst1, SYSTEMTIME *pst2)
  407. {
  408. int iRet;
  409. if (pst1->wYear < pst2->wYear)
  410. iRet = -1;
  411. else if (pst1->wYear > pst2->wYear)
  412. iRet = 1;
  413. else if (pst1->wMonth < pst2->wMonth)
  414. iRet = -1;
  415. else if (pst1->wMonth > pst2->wMonth)
  416. iRet = 1;
  417. else if (pst1->wDay < pst2->wDay)
  418. iRet = -1;
  419. else if (pst1->wDay > pst2->wDay)
  420. iRet = 1;
  421. else if (pst1->wHour < pst2->wHour)
  422. iRet = -1;
  423. else if (pst1->wHour > pst2->wHour)
  424. iRet = 1;
  425. else if (pst1->wMinute < pst2->wMinute)
  426. iRet = -1;
  427. else if (pst1->wMinute > pst2->wMinute)
  428. iRet = 1;
  429. // else if (pst1->wSecond < pst2->wSecond)
  430. // iRet = -1;
  431. // else if (pst1->wSecond > pst2->wSecond)
  432. // iRet = 1;
  433. else
  434. iRet = 0;
  435. return(iRet);
  436. }
  437. /*--------------------------------------------------------------------------
  438. Purpose: Window proc for the add later dialog box
  439. */
  440. BOOL_PTR CALLBACK AddLaterDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
  441. {
  442. switch (msg)
  443. {
  444. case WM_INITDIALOG:
  445. {
  446. PADDLATERDATA pald = (PADDLATERDATA)lp;
  447. // We should definitely have this (dli)
  448. ASSERT(pald);
  449. SYSTEMTIME stInit = {0};
  450. // Get the current local time
  451. GetLocalTime(&stInit);
  452. // Has this app already expired?
  453. if ((pald->dwMasks & ALD_EXPIRE) &&
  454. (CompareSystemTime(&pald->stExpire, &stInit) > 0))
  455. {
  456. // NO,
  457. // Assigned time does not make sense if the assigned time has already
  458. // passed
  459. if ((pald->dwMasks & ALD_ASSIGNED) &&
  460. (CompareSystemTime(&pald->stAssigned, &stInit) <= 0))
  461. pald->dwMasks &= ~ALD_ASSIGNED;
  462. // find the date/time picker window
  463. HWND hwndPicker = GetDlgItem(hDlg, IDC_PICKER);
  464. // always check "add later" radio button initially
  465. CheckDlgButton(hDlg, IDC_ADDLATER, BST_CHECKED);
  466. TCHAR szFormat[MAX_PATH];
  467. if (_GetLocaleDateTimeFormat(szFormat, ARRAYSIZE(szFormat)))
  468. {
  469. // set the locale date time format
  470. DateTime_SetFormat(hwndPicker, szFormat);
  471. // The new time can only be in the future, so set the current time
  472. // as the lower limit
  473. DateTime_SetRange(hwndPicker, GDTR_MIN, &stInit);
  474. // Do we have a schedule (in the future) already?
  475. // Schedule in the past means nothing
  476. if ((pald->dwMasks & ALD_SCHEDULE) &&
  477. (CompareSystemTime(&pald->stSchedule, &stInit) >= 0))
  478. {
  479. // Set our initial value to this schedule
  480. stInit = pald->stSchedule;
  481. }
  482. // Set the initial value in date/time picker
  483. DateTime_SetSystemtime(hwndPicker, GDT_VALID, &stInit);
  484. // Uncheck the SCHEDULE flag so that we know we don't have a new
  485. // schedule, yet
  486. pald->dwMasks &= ~ALD_SCHEDULE;
  487. SetWindowLongPtr(hDlg, DWLP_USER, lp);
  488. return TRUE;
  489. }
  490. }
  491. else
  492. {
  493. // Yes, it's expired, warn the user
  494. ShellMessageBox(g_hinst, hDlg, MAKEINTRESOURCE(IDS_EXPIRED),
  495. MAKEINTRESOURCE(IDS_NAME), MB_OK | MB_ICONEXCLAMATION);
  496. // Then end the dialog.
  497. EndDialog(hDlg, 0);
  498. }
  499. return FALSE;
  500. }
  501. break;
  502. case WM_COMMAND:
  503. switch (GET_WM_COMMAND_ID(wp, lp))
  504. {
  505. case IDC_ADDLATER:
  506. case IDC_UNSCHEDULE:
  507. {
  508. HWND hwndPicker = GetDlgItem(hDlg, IDC_PICKER);
  509. EnableWindow(hwndPicker, IsDlgButtonChecked(hDlg, IDC_ADDLATER));
  510. }
  511. break;
  512. case IDOK:
  513. {
  514. PADDLATERDATA pald = (PADDLATERDATA)GetWindowLongPtr(hDlg, DWLP_USER);
  515. // we did set window long ptr this should be there.
  516. ASSERT(pald);
  517. // did the user choose to add later?
  518. if (IsDlgButtonChecked(hDlg, IDC_ADDLATER))
  519. {
  520. // Yes
  521. // Let's find out if the time user has chosen is valid
  522. #define LATER_THAN_ASSIGNED_TIME 1
  523. #define LATER_THAN_EXPIRED_TIME 2
  524. int iStatus = 0;
  525. HWND hwndPicker = GetDlgItem(hDlg, IDC_PICKER);
  526. DateTime_GetSystemtime(hwndPicker, &pald->stSchedule);
  527. // Is this time later than the assigned time?
  528. if ((pald->dwMasks & ALD_ASSIGNED) &&
  529. (CompareSystemTime(&pald->stSchedule, &pald->stAssigned) > 0))
  530. iStatus = LATER_THAN_ASSIGNED_TIME;
  531. // Is this time later than the expired time?
  532. if ((pald->dwMasks & ALD_EXPIRE) &&
  533. (CompareSystemTime(&pald->stSchedule, &pald->stExpire) >= 0))
  534. iStatus = LATER_THAN_EXPIRED_TIME;
  535. // Is either of the above two cases TRUE?
  536. if (iStatus > 0)
  537. {
  538. TCHAR szDateTime[MAX_PATH];
  539. // Is the time user chose passed expired time or assigned?
  540. BOOL bExpired = (iStatus == LATER_THAN_EXPIRED_TIME);
  541. // Get the time string
  542. if (FormatSystemTimeString(bExpired ? &pald->stExpire : &pald->stAssigned,
  543. szDateTime, ARRAYSIZE(szDateTime)))
  544. {
  545. TCHAR szFinal[MAX_PATH * 2];
  546. TCHAR szWarn[MAX_PATH];
  547. LoadString(g_hinst, bExpired ? IDS_PASSEXPIRED : IDS_PASSASSIGNED,
  548. szWarn, ARRAYSIZE(szWarn));
  549. StringCchPrintf(szFinal, ARRAYSIZE(szFinal), szWarn, szDateTime, szDateTime);
  550. ShellMessageBox(g_hinst, hDlg, szFinal,
  551. MAKEINTRESOURCE(IDS_NAME), MB_OK | MB_ICONEXCLAMATION);
  552. }
  553. }
  554. else
  555. // No, we are okay to go
  556. pald->dwMasks |= ALD_SCHEDULE;
  557. }
  558. }
  559. //
  560. // fall through
  561. //
  562. case IDCANCEL:
  563. EndDialog(hDlg, (GET_WM_COMMAND_ID(wp, lp) == IDOK));
  564. break;
  565. default:
  566. return FALSE;
  567. }
  568. break;
  569. default:
  570. return FALSE;
  571. }
  572. return TRUE;
  573. }
  574. /*-------------------------------------------------------------------------
  575. Purpose: GetNewInstallTime
  576. Start up the Add Later dialog box to get the new install schedule
  577. (represented by a SYSTEMTIME data struct)
  578. */
  579. BOOL GetNewInstallTime(HWND hwndParent, PADDLATERDATA pal)
  580. {
  581. return (DialogBoxParam(g_hinst, MAKEINTRESOURCE(DLG_ADDLATER),
  582. hwndParent, AddLaterDlgProc, (LPARAM)pal) == IDOK);
  583. }
  584. // Take the name of the potential app folder and see if it ends with numbers or dots
  585. // if it does, let's separate the numbers and see if there is a match.
  586. // It's inspired by cases like Office8.0 or MSVC50 or Bookshelf98
  587. // NOTE: we can't use the key words without the numbers, it might lead to mistake
  588. // in case the user has two versions of the same software on one machine. (there might
  589. // be something we can do though, I am too tired to think about this now)
  590. void InsertSpaceBeforeVersion(LPCTSTR pszIn, LPTSTR pszOut)
  591. {
  592. ASSERT(IS_VALID_STRING_PTR(pszIn, -1));
  593. ASSERT(IS_VALID_STRING_PTR(pszOut, -1));
  594. // Copy the old string into the buffer
  595. lstrcpy(pszOut, pszIn);
  596. // Find the end of the string
  597. LPTSTR pszEnd = pszOut + lstrlen(pszOut);
  598. ASSERT(pszEnd > pszOut);
  599. // Go back until we can't see numbers or '.'
  600. LPTSTR pszLastChar = CharPrev(pszOut, pszEnd);
  601. LPTSTR pszPrev = pszLastChar;
  602. while ((pszPrev > pszOut) && (((*pszPrev <= TEXT('9')) && (*pszPrev >= TEXT('0'))) || (*pszPrev == TEXT('.'))))
  603. pszPrev = CharPrev(pszOut, pszPrev);
  604. // Did we find any numbers at the end?
  605. if ((pszPrev < pszLastChar) && IsCharAlphaNumeric(*pszPrev))
  606. {
  607. // Yes, let's stick a ' ' in between
  608. TCHAR szNumbers[MAX_PATH];
  609. StringCchCopy(szNumbers, ARRAYSIZE(szNumbers), ++pszPrev);
  610. *(pszPrev++) = TEXT(' ');
  611. lstrcpy(pszPrev, szNumbers);
  612. }
  613. }
  614. //
  615. // Basic sanity check on whether the app folder location is valid.
  616. // Return Value:
  617. // TRUE does not mean it is valid.
  618. // FALSE means it definitely is not valid.
  619. //
  620. BOOL IsValidAppFolderLocation(LPCTSTR pszFolder)
  621. {
  622. ASSERT(IS_VALID_STRING_PTR(pszFolder, -1));
  623. BOOL bRet = FALSE;
  624. if (!PathIsRoot(pszFolder) && PathFileExists(pszFolder) && PathIsDirectory(pszFolder))
  625. {
  626. TCHAR szPath[MAX_PATH];
  627. if (SUCCEEDED(StringCchCopy(szPath, ARRAYSIZE(szPath), pszFolder)) && PathStripToRoot(szPath))
  628. {
  629. bRet = (GetDriveType(szPath) == DRIVE_FIXED);
  630. }
  631. }
  632. return bRet;
  633. }
  634. EXTERN_C BOOL IsTerminalServicesRunning(void)
  635. {
  636. static int s_fIsTerminalServer = -1;
  637. if (s_fIsTerminalServer == -1)
  638. {
  639. BOOL TSAppServer;
  640. BOOL TSRemoteAdmin;
  641. OSVERSIONINFOEX osVersionInfo;
  642. DWORDLONG dwlConditionMask = 0;
  643. ZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX));
  644. osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  645. osVersionInfo.wSuiteMask = VER_SUITE_TERMINAL;
  646. VER_SET_CONDITION( dwlConditionMask, VER_SUITENAME, VER_AND );
  647. TSAppServer = (int)VerifyVersionInfo(&osVersionInfo, VER_SUITENAME, dwlConditionMask);
  648. ZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX));
  649. osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  650. osVersionInfo.wSuiteMask = VER_SUITE_SINGLEUSERTS;
  651. VER_SET_CONDITION( dwlConditionMask, VER_SUITENAME, VER_AND );
  652. TSRemoteAdmin = (int)VerifyVersionInfo(&osVersionInfo, VER_SUITENAME, dwlConditionMask);
  653. if ( !TSRemoteAdmin && TSAppServer )
  654. {
  655. s_fIsTerminalServer = TRUE;
  656. }
  657. else
  658. {
  659. // do not treat tsremoteadmin as TS machine from the application compatability point of view.
  660. s_fIsTerminalServer = FALSE;
  661. }
  662. }
  663. return s_fIsTerminalServer ? TRUE : FALSE;
  664. }
  665. // returns TRUE if pszFile is a local file and on a fixed drive
  666. BOOL PathIsLocalAndFixed(LPCTSTR pszFile)
  667. {
  668. if (!pszFile || !pszFile[0])
  669. return FALSE;
  670. if (PathIsUNC(pszFile))
  671. return FALSE;
  672. TCHAR szDrive[MAX_PATH];
  673. StringCchCopy(szDrive, ARRAYSIZE(szDrive), pszFile);
  674. if (PathStripToRoot(szDrive) && GetDriveType(szDrive) != DRIVE_FIXED)
  675. return FALSE;
  676. return TRUE;
  677. }
  678. // This function will duplicate an APPCATEGORYINFOLIST and allocate the new copy
  679. // using COM memory allocation functions
  680. STDAPI _DuplicateCategoryList(APPCATEGORYINFOLIST * pacl, APPCATEGORYINFOLIST * paclNew)
  681. {
  682. HRESULT hres = E_FAIL;
  683. ASSERT(pacl && paclNew);
  684. ZeroMemory(paclNew, SIZEOF(APPCATEGORYINFOLIST));
  685. if (pacl && (pacl->cCategory > 0) && pacl->pCategoryInfo)
  686. {
  687. DWORD dwDesiredSize = pacl->cCategory * SIZEOF(APPCATEGORYINFO);
  688. APPCATEGORYINFO * paci = pacl->pCategoryInfo;
  689. paclNew->pCategoryInfo = (APPCATEGORYINFO *)SHAlloc(dwDesiredSize);
  690. if (paclNew->pCategoryInfo)
  691. {
  692. UINT iCategory = 0;
  693. paclNew->cCategory = 0;
  694. APPCATEGORYINFO * paciNew = paclNew->pCategoryInfo;
  695. while (paci && (iCategory < pacl->cCategory))
  696. {
  697. if (paci->pszDescription)
  698. {
  699. hmemcpy(paciNew, paci, SIZEOF(APPCATEGORYINFO));
  700. if (FAILED(SHStrDup(paci->pszDescription, &(paciNew->pszDescription))))
  701. {
  702. // We may be out of memory, stop here.
  703. ZeroMemory(paciNew, SIZEOF(APPCATEGORYINFO));
  704. break;
  705. }
  706. paciNew++;
  707. paclNew->cCategory++;
  708. }
  709. iCategory++;
  710. paci++;
  711. }
  712. hres = S_OK;
  713. }
  714. else
  715. hres = E_OUTOFMEMORY;
  716. }
  717. return hres;
  718. }
  719. STDAPI _DestroyCategoryList(APPCATEGORYINFOLIST * pacl)
  720. {
  721. if (pacl && pacl->pCategoryInfo)
  722. {
  723. UINT iCategory = 0;
  724. APPCATEGORYINFO * paci = pacl->pCategoryInfo;
  725. while (paci && (iCategory < pacl->cCategory))
  726. {
  727. if (paci->pszDescription)
  728. {
  729. SHFree(paci->pszDescription);
  730. }
  731. iCategory++;
  732. paci++;
  733. }
  734. SHFree(pacl->pCategoryInfo);
  735. }
  736. return S_OK;
  737. }