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.

4226 lines
126 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #include <oleauto.h>
  4. #include <stdio.h>
  5. //
  6. // use the same name as the Win9x upgrade report
  7. //
  8. #define S_APPCOMPAT_DATABASE_FILE TEXT("compdata\\drvmain.chm")
  9. #define S_APPCOMPAT_TEXT_FILE TEXT("compdata\\drvmain.inf")
  10. #define DRVCOMPAT_FIELD_IDENTIFIER TEXT('*')
  11. #define S_QFE_TARGET_FILENAME TEXT("qfelist.htm")
  12. #define S_QFE_TEMPLATE_FILE TEXT("compdata\\qfelist.htm")
  13. #ifdef UNICODE
  14. #define S_SP_TEMPLATE \
  15. "<P><B>%S</B></P>\r\n"
  16. #define S_QFE_LINK_TEMPLATE \
  17. "<P>"\
  18. "<A HREF=\"http://support.microsoft.com/support/misc/kblookup.asp?id=%lu\" TARGET=\"_new\">"\
  19. "%S</A>"\
  20. "</P>\r\n"
  21. #else
  22. #define S_SP_TEMPLATE \
  23. "<P><B>%s</B></P>\r\n"
  24. #define S_QFE_LINK_TEMPLATE \
  25. "<P>"\
  26. "<A HREF=\"http://support.microsoft.com/support/misc/kblookup.asp?id=%lu\" TARGET=\"_new\">"\
  27. "%s</A>"\
  28. "</P>\r\n"
  29. #endif
  30. typedef struct {
  31. PVOID Text;
  32. BOOL Unicode;
  33. } COMPAT_TEXT_PARAMS, *PCOMPAT_TEXT_PARAMS;
  34. LIST_ENTRY CompatibilityData;
  35. DWORD CompatibilityCount;
  36. DWORD IncompatibilityStopsInstallation = FALSE;
  37. DWORD GlobalCompFlags;
  38. //
  39. // we use poor global variable instead of changing the COMPATIBILITY_CONTEXT
  40. // structure, which would require a recompile of all the compatibility dlls.
  41. // eventually this should move into that structure (and the structure should also have
  42. // a Size member so we can version it in the future.)
  43. //
  44. //
  45. DWORD PerCompatDllFlags;
  46. BOOL AnyNt5CompatDlls = FALSE;
  47. BOOL
  48. SaveCompatibilityData(
  49. IN LPCTSTR FileName,
  50. IN BOOL IncludeHiddenItems
  51. );
  52. BOOL
  53. ProcessLine (
  54. IN DWORD CompatFlags
  55. );
  56. WNDPROC OldEditProc;
  57. LRESULT
  58. CALLBACK
  59. TextEditSubProc(
  60. IN HWND hwnd,
  61. IN UINT msg,
  62. IN WPARAM wParam,
  63. IN LPARAM lParam
  64. )
  65. {
  66. //
  67. // For setsel messages, make start and end the same.
  68. //
  69. if ((msg == EM_SETSEL) && ((LPARAM)wParam != lParam)) {
  70. lParam = wParam;
  71. }
  72. return CallWindowProc( OldEditProc, hwnd, msg, wParam, lParam );
  73. }
  74. BOOL
  75. SetTextInDialog(
  76. HWND hwnd,
  77. PCOMPAT_TEXT_PARAMS Params
  78. )
  79. {
  80. OldEditProc = (WNDPROC) GetWindowLongPtr( hwnd, GWLP_WNDPROC );
  81. SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG_PTR)TextEditSubProc );
  82. #ifdef UNICODE
  83. if (Params->Unicode) {
  84. SendMessageW (hwnd, WM_SETTEXT, 0, (LPARAM)Params->Text);
  85. } else {
  86. SendMessageA (hwnd, WM_SETTEXT, 0, (LPARAM)Params->Text);
  87. }
  88. #else
  89. MYASSERT (!Params->Unicode);
  90. if (Params->Unicode) {
  91. return FALSE;
  92. }
  93. SendMessageA (hwnd, WM_SETTEXT, 0, (LPARAM)Params->Text);
  94. #endif
  95. return TRUE;
  96. }
  97. INT_PTR
  98. CALLBACK
  99. CompatibilityTextDlgProc(
  100. HWND hwndDlg,
  101. UINT uMsg,
  102. WPARAM wParam,
  103. LPARAM lParam
  104. )
  105. {
  106. switch(uMsg) {
  107. case WM_INITDIALOG:
  108. SetTextInDialog( GetDlgItem( hwndDlg, IDC_TEXT ), (PCOMPAT_TEXT_PARAMS) lParam );
  109. break;
  110. case WM_COMMAND:
  111. if (wParam == IDOK) {
  112. EndDialog( hwndDlg, IDOK );
  113. }
  114. break;
  115. case WM_CTLCOLOREDIT:
  116. SetBkColor( (HDC)wParam, GetSysColor(COLOR_BTNFACE));
  117. return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
  118. break;
  119. case WM_CLOSE:
  120. EndDialog (hwndDlg, IDOK);
  121. break;
  122. }
  123. return 0;
  124. }
  125. BOOL
  126. LaunchIE4Instance(
  127. LPWSTR szResourceURL
  128. );
  129. BOOL
  130. LaunchIE3Instance(
  131. LPWSTR szResourceURL
  132. );
  133. BOOL
  134. pGetDisplayInfo (
  135. IN PCTSTR Source,
  136. OUT PTSTR UrlName,
  137. IN DWORD UrlChars
  138. )
  139. {
  140. TCHAR filePath[MAX_PATH];
  141. BOOL b = TRUE;
  142. if (!Source || !*Source) {
  143. return FALSE;
  144. }
  145. if (*Source == DRVCOMPAT_FIELD_IDENTIFIER) {
  146. if (FindPathToWinnt32File (S_APPCOMPAT_DATABASE_FILE, filePath, MAX_PATH)) {
  147. if(_sntprintf (UrlName, UrlChars, TEXT("mk:@msitstore:%s::/%s"), filePath, Source + 1) < 0){
  148. UrlName[UrlChars - 1] = '\0';
  149. DebugLog(Winnt32LogError,
  150. TEXT("pGetDisplayInfo: UrlName(%s) has been truncated."),
  151. 0,
  152. UrlName);
  153. }
  154. } else {
  155. DebugLog (Winnt32LogError,
  156. TEXT("Compatibility data file \"%1\" not found"),
  157. 0,
  158. S_APPCOMPAT_DATABASE_FILE
  159. );
  160. b = FALSE;
  161. }
  162. } else {
  163. if (FindPathToWinnt32File (Source, filePath, MAX_PATH)) {
  164. if(_sntprintf (UrlName, UrlChars, TEXT("file://%s"), filePath) < 0){
  165. UrlName[UrlChars - 1] = '\0';
  166. DebugLog(Winnt32LogError,
  167. TEXT("pGetDisplayInfo: UrlName(%s) has been truncated."),
  168. 0,
  169. UrlName);
  170. }
  171. } else {
  172. DebugLog (Winnt32LogError,
  173. TEXT("Compatibility data file \"%1\" not found"),
  174. 0,
  175. Source
  176. );
  177. b = FALSE;
  178. }
  179. }
  180. return b;
  181. }
  182. BOOL
  183. pGetText (
  184. IN PCTSTR TextSource,
  185. OUT PVOID* Text,
  186. OUT PBOOL Unicode
  187. )
  188. {
  189. TCHAR filePath[MAX_PATH];
  190. DWORD FileSize;
  191. HANDLE FileHandle;
  192. HANDLE MappingHandle;
  193. PVOID BaseAddress;
  194. HINF infAppCompat;
  195. INFCONTEXT ic;
  196. BOOL bValid;
  197. DWORD totalSize;
  198. INT size;
  199. PTSTR data, current;
  200. PSTR text;
  201. BOOL b = FALSE;
  202. if (!TextSource || !*TextSource) {
  203. return FALSE;
  204. }
  205. if (*TextSource == DRVCOMPAT_FIELD_IDENTIFIER) {
  206. if (FindPathToWinnt32File (S_APPCOMPAT_TEXT_FILE, filePath, MAX_PATH)) {
  207. infAppCompat = SetupapiOpenInfFile (filePath, NULL, INF_STYLE_WIN4, NULL);
  208. if (infAppCompat != INVALID_HANDLE_VALUE) {
  209. bValid = TRUE;
  210. totalSize = 0;
  211. data = NULL;
  212. if (SetupapiFindFirstLine (infAppCompat, TextSource + 1, NULL, &ic)) {
  213. do {
  214. if (!SetupapiGetStringField (&ic, 1, NULL, 0, &FileSize)) {
  215. bValid = FALSE;
  216. break;
  217. }
  218. totalSize += FileSize + 2 - 1;
  219. } while (SetupapiFindNextLine (&ic, &ic));
  220. }
  221. if (bValid && totalSize > 0) {
  222. totalSize++;
  223. data = (PTSTR) MALLOC (totalSize * sizeof (TCHAR));
  224. if (data) {
  225. current = data;
  226. size = totalSize;
  227. if (SetupapiFindFirstLine (infAppCompat, TextSource + 1, NULL, &ic)) {
  228. do {
  229. if (!SetupapiGetStringField (&ic, 1, current, size, NULL)) {
  230. bValid = FALSE;
  231. break;
  232. }
  233. lstrcat (current, TEXT("\r\n"));
  234. size -= lstrlen (current);
  235. MYASSERT(size >= 0);
  236. current = _tcschr (current, 0);
  237. } while (SetupapiFindNextLine (&ic, &ic));
  238. }
  239. }
  240. }
  241. SetupapiCloseInfFile (infAppCompat);
  242. if (bValid) {
  243. if (data) {
  244. *Text = data;
  245. #ifdef UNICODE
  246. *Unicode = TRUE;
  247. #else
  248. *Unicode = FALSE;
  249. #endif
  250. b = TRUE;
  251. }
  252. } else {
  253. FREE (data);
  254. }
  255. }
  256. if (!b) {
  257. DebugLog (
  258. Winnt32LogError,
  259. TEXT("Unable to read section [%1] from \"%2\""),
  260. 0,
  261. TextSource + 1,
  262. filePath
  263. );
  264. }
  265. } else {
  266. DebugLog (Winnt32LogError,
  267. TEXT("Compatibility data file \"%1\" not found"),
  268. 0,
  269. S_APPCOMPAT_DATABASE_FILE
  270. );
  271. }
  272. } else {
  273. if (FindPathToWinnt32File (TextSource, filePath, MAX_PATH)) {
  274. if (MapFileForRead (filePath, &FileSize, &FileHandle, &MappingHandle, &BaseAddress) == ERROR_SUCCESS) {
  275. text = (PSTR) MALLOC (FileSize + 1);
  276. if (text) {
  277. CopyMemory (text, BaseAddress, FileSize);
  278. text[FileSize] = '\0';
  279. *Text = text;
  280. *Unicode = FALSE;
  281. b = TRUE;
  282. }
  283. UnmapFile (MappingHandle, BaseAddress);
  284. CloseHandle (FileHandle);
  285. }
  286. } else {
  287. DebugLog (Winnt32LogError,
  288. TEXT("Compatibility data file \"%1\" not found"),
  289. 0,
  290. TextSource
  291. );
  292. }
  293. }
  294. return b;
  295. }
  296. VOID
  297. pShowDetails (
  298. IN HWND Hdlg,
  299. IN PCOMPATIBILITY_DATA CompData
  300. )
  301. {
  302. TCHAR urlName[2 * MAX_PATH];
  303. PWSTR Url;
  304. INT i;
  305. PVOID textDescription = NULL;
  306. BOOL bUnicode;
  307. BOOL UseText = FALSE;
  308. //
  309. // We check to see if the pointer as well as its contents are valid. If the contents are Null then we try
  310. // the txt file before we decide to not do anything.
  311. //
  312. if (pGetDisplayInfo (CompData->HtmlName, urlName, 2 * MAX_PATH)) {
  313. i = _tcslen( urlName );
  314. Url = (LPWSTR)SysAllocStringLen( NULL, i );
  315. if( Url ) {
  316. #ifdef UNICODE
  317. wcscpy( Url, urlName );
  318. #else
  319. MultiByteToWideChar( CP_ACP, 0, urlName, -1, Url, i);
  320. #endif
  321. if (!LaunchIE4Instance(Url)) {
  322. // If we don't have IE4 or better, display text
  323. UseText = TRUE;
  324. }
  325. SysFreeString( Url );
  326. }
  327. } else if( CheckUpgradeOnly ) {
  328. TCHAR Caption[512];
  329. //
  330. // If we don't have a URL, and we're only checking
  331. // the ability to upgrade, then this is probably
  332. // an item from a message box that's been redirected
  333. // to the compability list. Just display a message
  334. // box with the full text.
  335. //
  336. if(!LoadString(hInst, AppTitleStringId, Caption, ARRAYSIZE(Caption))){
  337. Caption[0] = 0;
  338. }
  339. MessageBox( Hdlg,
  340. CompData->Description,
  341. Caption,
  342. MB_OK | MB_ICONWARNING );
  343. } else {
  344. UseText = TRUE;
  345. }
  346. if (UseText) {
  347. if (pGetText (CompData->TextName, &textDescription, &bUnicode)) {
  348. COMPAT_TEXT_PARAMS params;
  349. MYASSERT(textDescription);
  350. params.Text = textDescription;
  351. params.Unicode = bUnicode;
  352. DialogBoxParam(
  353. hInst,
  354. MAKEINTRESOURCE(IDD_COMPATIBILITY_TEXT),
  355. NULL,
  356. CompatibilityTextDlgProc,
  357. (LPARAM)&params
  358. );
  359. FREE (textDescription);
  360. } else {
  361. TCHAR Heading[512];
  362. PTSTR Message;
  363. //
  364. // When there is no txt name present, as last resort we put up this message
  365. //
  366. if(!LoadString(hInst, AppTitleStringId, Heading, ARRAYSIZE(Heading))) {
  367. Heading[0] = 0;
  368. }
  369. if (FormatMessage (
  370. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  371. hInst,
  372. MSG_NO_DETAILS,
  373. 0,
  374. (LPTSTR)&Message,
  375. 0,
  376. NULL
  377. )) {
  378. MessageBox (Hdlg, Message, Heading, MB_OK | MB_ICONWARNING);
  379. LocalFree ((HLOCAL)Message);
  380. }
  381. }
  382. }
  383. }
  384. BOOL
  385. CompatibilityWizPage(
  386. IN HWND hdlg,
  387. IN UINT msg,
  388. IN WPARAM wParam,
  389. IN LPARAM lParam
  390. )
  391. {
  392. TCHAR FullPath[MAX_PATH+8], *t;
  393. LPWSTR Url;
  394. BOOL b = FALSE;
  395. DWORD i;
  396. PCOMPATIBILITY_DATA CompData;
  397. DWORD Index;
  398. static int CurrentSelectionIndex=0;
  399. static DWORD Count = 0;
  400. LV_ITEM lvi = {0};
  401. HWND TmpHwnd;
  402. static BOOL WarningsPresent = FALSE;
  403. static BOOL ErrorsPresent = FALSE;
  404. static BOOL CheckUpgradeNoItems = TRUE;
  405. PPAGE_RUNTIME_DATA WizPage = (PPAGE_RUNTIME_DATA)GetWindowLongPtr(hdlg,DWLP_USER);
  406. TCHAR Buffer1[MAX_PATH] = {0};
  407. switch(msg) {
  408. case WM_INITDIALOG:
  409. if( CheckUpgradeOnly ) {
  410. TCHAR Desc_String[512];
  411. PLIST_ENTRY Next;
  412. PPAGE_RUNTIME_DATA WizPage = (PPAGE_RUNTIME_DATA)GetWindowLongPtr(hdlg,DWLP_USER);
  413. //
  414. // Fix up the subtitle and buttons for Checkupgradeonly.
  415. //
  416. SetDlgItemText(hdlg,IDT_SUBTITLE,(PTSTR)TEXT("") );
  417. //
  418. // If we're doing a CheckUpgradeOnly, then
  419. // we've been sending error popups to the compatibility
  420. // list. It doesn't look like there were any problems or
  421. // incompatibilities. We'll put in an "everything's okay"
  422. // message.
  423. //
  424. Next = CompatibilityData.Flink;
  425. if (Next) {
  426. while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
  427. CompData = CONTAINING_RECORD( Next, COMPATIBILITY_DATA, ListEntry );
  428. Next = CompData->ListEntry.Flink;
  429. if( (!(CompData->Flags & COMPFLAG_HIDE)) && ProcessLine( CompData->Flags)) {
  430. CheckUpgradeNoItems = FALSE;
  431. }
  432. }
  433. }
  434. if( CheckUpgradeNoItems ){
  435. if (!ISNT()) {
  436. break;
  437. }
  438. if (!CompatibilityData.Flink) {
  439. InitializeListHead (&CompatibilityData);
  440. }
  441. CompData = (PCOMPATIBILITY_DATA) MALLOC( sizeof(COMPATIBILITY_DATA) );
  442. if (CompData == NULL) {
  443. return 0;
  444. }
  445. ZeroMemory(CompData,sizeof(COMPATIBILITY_DATA));
  446. if(!LoadString(hInst, IDS_COMPAT_NOPROBLEMS, Desc_String, ARRAYSIZE(Desc_String))){
  447. CompData->Description = 0;
  448. }
  449. else{
  450. CompData->Description = DupString(Desc_String);
  451. }
  452. CompData->Flags = 0;
  453. InsertTailList( &CompatibilityData, &CompData->ListEntry );
  454. CompatibilityCount++;
  455. }
  456. }
  457. if (CompatibilityCount) {
  458. HWND hList = GetDlgItem( hdlg, IDC_ROOT_LIST );
  459. PLIST_ENTRY Next;
  460. HIMAGELIST himl;
  461. HICON hIcon;
  462. LV_COLUMN lvc = {0};
  463. RECT rc;
  464. GetClientRect( hList, &rc );
  465. lvc.mask = LVCF_WIDTH;
  466. lvc.cx = rc.right - rc.left - 16;
  467. ListView_InsertColumn( hList, 0, &lvc );
  468. Next = CompatibilityData.Flink;
  469. if (Next) {
  470. himl = ImageList_Create( GetSystemMetrics(SM_CXSMICON),
  471. GetSystemMetrics(SM_CXSMICON),
  472. ILC_COLOR,
  473. 2,
  474. 0 );
  475. ListView_SetImageList( hList, himl, LVSIL_SMALL );
  476. hIcon = LoadIcon( NULL, IDI_HAND );
  477. ImageList_AddIcon( himl, hIcon );
  478. hIcon = LoadIcon( NULL, IDI_EXCLAMATION );
  479. ImageList_AddIcon( himl, hIcon );
  480. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  481. lvi.state = 0;
  482. lvi.stateMask = 0;
  483. lvi.iItem = 0;
  484. while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
  485. CompData = CONTAINING_RECORD( Next, COMPATIBILITY_DATA, ListEntry );
  486. Next = CompData->ListEntry.Flink;
  487. if (ProcessLine( CompData->Flags)) {
  488. AnyNt5CompatDlls = TRUE;
  489. } else {
  490. goto NextIteration;
  491. }
  492. if ((CompData->Flags & COMPFLAG_HIDE) == 0) {
  493. //
  494. // Add the icon.
  495. //
  496. if( himl ) {
  497. if (ISNT() && CheckUpgradeOnly && CheckUpgradeNoItems) {
  498. lvi.iImage = -1;
  499. WarningsPresent = TRUE;
  500. } else {
  501. if( CompData->Flags & COMPFLAG_STOPINSTALL ) {
  502. lvi.iImage = 0;
  503. ErrorsPresent = TRUE;
  504. } else {
  505. lvi.iImage = 1;
  506. WarningsPresent = TRUE;
  507. }
  508. }
  509. }
  510. //
  511. // And the text...
  512. //
  513. lvi.pszText = (LPTSTR)CompData->Description;
  514. lvi.lParam = (LPARAM)CompData;
  515. if (ListView_InsertItem( hList, &lvi ) != -1) {
  516. lvi.iItem++;
  517. }
  518. Count += 1;
  519. }
  520. //
  521. // Log the items...
  522. //
  523. DebugLog( Winnt32LogInformation,
  524. CompData->Description,
  525. 0 );
  526. DebugLog( Winnt32LogInformation,
  527. TEXT("\r\n"),
  528. 0 );
  529. NextIteration:
  530. NOTHING;
  531. }
  532. }
  533. // If we have an item then make it the default selection
  534. if( ErrorsPresent || WarningsPresent ){
  535. SetFocus( hList );
  536. ListView_SetItemState( hList,
  537. 0,
  538. LVIS_SELECTED | LVIS_FOCUSED,
  539. LVIS_SELECTED | LVIS_FOCUSED);
  540. CurrentSelectionIndex = 0;
  541. lvi.mask = LVIF_PARAM;
  542. lvi.iItem = 0;
  543. lvi.iSubItem = 0;
  544. ListView_GetItem( GetDlgItem( hdlg, IDC_ROOT_LIST ), &lvi );
  545. CompData = (PCOMPATIBILITY_DATA)lvi.lParam;
  546. TmpHwnd = GetDlgItem( hdlg, IDC_HAVE_DISK );
  547. if (CompData->Flags & COMPFLAG_USE_HAVEDISK)
  548. UnHideWindow( TmpHwnd );
  549. else
  550. HideWindow( TmpHwnd );
  551. }
  552. }
  553. break;
  554. case WM_NOTIFY:
  555. {
  556. LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
  557. if( (pnmv->hdr.code == LVN_ITEMCHANGED) ) {
  558. Index = ListView_GetNextItem( GetDlgItem( hdlg, IDC_ROOT_LIST ),
  559. (int)-1,
  560. (UINT) (LVNI_ALL | LVNI_SELECTED | LVNI_FOCUSED) );
  561. if( (Index != LB_ERR) && (pnmv->iItem != CurrentSelectionIndex)) {
  562. CurrentSelectionIndex = Index;
  563. //
  564. // Select the item, and see if we need
  565. // to display the "have disk" button.
  566. //
  567. lvi.mask = LVIF_PARAM;
  568. lvi.iItem = Index;
  569. lvi.iSubItem = 0;
  570. ListView_GetItem( GetDlgItem( hdlg, IDC_ROOT_LIST ), &lvi );
  571. CompData = (PCOMPATIBILITY_DATA)lvi.lParam;
  572. TmpHwnd = GetDlgItem( hdlg, IDC_HAVE_DISK );
  573. HideWindow( TmpHwnd );
  574. // Always set the Details button
  575. TmpHwnd = GetDlgItem( hdlg, IDC_DETAILS );
  576. EnableWindow( TmpHwnd, TRUE );
  577. if (CompData->Flags & COMPFLAG_USE_HAVEDISK) {
  578. TmpHwnd = GetDlgItem( hdlg, IDC_HAVE_DISK );
  579. UnHideWindow( TmpHwnd );
  580. }
  581. InvalidateRect( GetParent(hdlg), NULL, FALSE );
  582. }else if((Index != LB_ERR) && (pnmv->uNewState == (LVIS_SELECTED|LVIS_FOCUSED))){
  583. //Transition from nothing selected to previous selection
  584. TmpHwnd = GetDlgItem( hdlg, IDC_DETAILS );
  585. EnableWindow( TmpHwnd, TRUE );
  586. }else if( Index == LB_ERR){
  587. // Disable the "Details" button as nothing is selected
  588. TmpHwnd = GetDlgItem( hdlg, IDC_DETAILS );
  589. EnableWindow( TmpHwnd, FALSE );
  590. }
  591. }
  592. }
  593. break;
  594. case WM_COMMAND:
  595. if ((LOWORD(wParam) == IDC_HAVE_DISK) && (HIWORD(wParam) == BN_CLICKED)) {
  596. Index = ListView_GetNextItem( GetDlgItem( hdlg, IDC_ROOT_LIST ),
  597. (int)-1,
  598. (UINT) (LVNI_ALL | LVNI_SELECTED) );
  599. if( Index != LB_ERR ) {
  600. //
  601. // Select the item, and see if we need
  602. // to display the "have disk" button.
  603. //
  604. lvi.mask = LVIF_PARAM;
  605. lvi.iItem = Index;
  606. lvi.iSubItem = 0;
  607. ListView_GetItem( GetDlgItem( hdlg, IDC_ROOT_LIST ), &lvi );
  608. CompData = (PCOMPATIBILITY_DATA)lvi.lParam;
  609. __try {
  610. i = CompData->CompHaveDisk(hdlg,CompData->SaveValue);
  611. } __except(EXCEPTION_EXECUTE_HANDLER) {
  612. i = GetExceptionCode();
  613. }
  614. if (i == 0) {
  615. ListView_DeleteItem( GetDlgItem( hdlg, IDC_ROOT_LIST ), Index );
  616. RemoveEntryList( &CompData->ListEntry );
  617. CompatibilityCount -= 1;
  618. } else {
  619. MessageBoxFromMessageWithSystem(
  620. hdlg,
  621. i,
  622. AppTitleStringId,
  623. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  624. CompData->hModDll
  625. );
  626. }
  627. }
  628. break;
  629. }
  630. if ((LOWORD(wParam) == IDC_DETAILS) && (HIWORD(wParam) == BN_CLICKED)) {
  631. TCHAR filePath[MAX_PATH];
  632. Index = ListView_GetNextItem( GetDlgItem( hdlg, IDC_ROOT_LIST ),
  633. (int)-1,
  634. (UINT) (LVNI_ALL | LVNI_SELECTED) );
  635. if (Index == LB_ERR) {
  636. return FALSE;
  637. }
  638. //
  639. // Select the item, and see if we need
  640. // to display the "have disk" button.
  641. //
  642. lvi.mask = LVIF_PARAM;
  643. lvi.iItem = Index;
  644. lvi.iSubItem = 0;
  645. if (!ListView_GetItem( GetDlgItem( hdlg, IDC_ROOT_LIST ), &lvi )) {
  646. break;
  647. }
  648. CompData = (PCOMPATIBILITY_DATA)lvi.lParam;
  649. pShowDetails (hdlg, CompData);
  650. SetFocus( GetDlgItem( hdlg, IDC_ROOT_LIST ) );
  651. ListView_SetItemState( GetDlgItem( hdlg, IDC_ROOT_LIST ),Index, LVIS_SELECTED, LVIS_SELECTED);
  652. break;
  653. }
  654. if ((LOWORD(wParam) == IDC_SAVE_AS) && (HIWORD(wParam) == BN_CLICKED)) {
  655. OPENFILENAME ofn;
  656. TCHAR Buffer[MAX_PATH + ARRAYSIZE(TEXT(".txt"))] = {0};
  657. TCHAR File_Type[MAX_PATH];
  658. BOOL SaveFlag;
  659. //
  660. // Initialize OPENFILENAME
  661. //
  662. ZeroMemory( &ofn, sizeof(OPENFILENAME));
  663. ofn.lStructSize = sizeof(OPENFILENAME);
  664. ofn.hwndOwner = hdlg;
  665. ofn.lpstrFile = Buffer;
  666. ofn.nMaxFile = ARRAYSIZE(Buffer);
  667. if(!LoadString(hInst, IDS_DEFAULT_COMPATIBILITY_REPORT_NAME, Buffer, ARRAYSIZE(Buffer))){
  668. Buffer[0] = '\0';
  669. MYASSERT(FALSE);
  670. }
  671. if(LoadString(hInst, IDS_FILE_MASK_TYPES, File_Type, ARRAYSIZE(File_Type))){
  672. lstrcpy((File_Type+lstrlen(File_Type)+1), TEXT("*.txt\0"));
  673. File_Type[lstrlen(File_Type)+7]='\0'; //We need to terminate the pair of strings with double null termination
  674. ofn.lpstrFilter = File_Type;
  675. }
  676. else{
  677. File_Type[0] = '\0';
  678. MYASSERT(FALSE);
  679. }
  680. // Force to begin in %windir%
  681. MyGetWindowsDirectory( Buffer1, MAX_PATH );
  682. ofn.lpstrInitialDir = Buffer1;
  683. ofn.Flags = OFN_NOCHANGEDIR | // leave the CWD unchanged
  684. OFN_EXPLORER |
  685. OFN_OVERWRITEPROMPT |
  686. OFN_HIDEREADONLY;
  687. // Let user select disk or directory
  688. SaveFlag = GetSaveFileName( &ofn );
  689. if( SaveFlag ) {
  690. //
  691. // Save it...
  692. //
  693. PTSTR p;
  694. p=_tcsrchr(ofn.lpstrFile,'.');
  695. if( !p || (p && lstrcmpi(p, TEXT(".txt")))){
  696. lstrcat(ofn.lpstrFile, TEXT(".txt"));
  697. }
  698. SaveCompatibilityData( ofn.lpstrFile, FALSE);
  699. } else {
  700. i = CommDlgExtendedError();
  701. }
  702. break;
  703. }
  704. break;
  705. case WMX_ACTIVATEPAGE:
  706. if (wParam) {
  707. if (ISNT ()) {
  708. MyGetWindowsDirectory (Buffer1, MAX_PATH);
  709. if(_sntprintf(FullPath,
  710. ARRAYSIZE(FullPath),
  711. TEXT("%s\\%s"),
  712. Buffer1,
  713. S_DEFAULT_NT_COMPAT_FILENAME) < 0){
  714. FullPath[ARRAYSIZE(FullPath) - 1] = '\0';
  715. DebugLog(Winnt32LogError,
  716. TEXT("CompatibilityWizPage: FullPath(%s) has been truncated."),
  717. 0,
  718. FullPath);
  719. }
  720. SaveCompatibilityData (FullPath, TRUE);
  721. }
  722. CHECKUPGRADEONLY_Q();
  723. if( CheckUpgradeOnly ) {
  724. //
  725. // Fix up the buttons for Checkupgradeonly.
  726. //
  727. PropSheet_SetWizButtons( GetParent(hdlg), (WizPage->CommonData.Buttons | PSWIZB_FINISH) );
  728. EnableWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),FALSE);
  729. ShowWindow(GetDlgItem(GetParent(hdlg),IDCANCEL),SW_HIDE);
  730. }
  731. if(ISNT() && OsVersion.dwMajorVersion == 5 ){
  732. if (!AnyNt5CompatDlls) {
  733. //
  734. // sanity check
  735. //
  736. MYASSERT (!IncompatibilityStopsInstallation);
  737. return FALSE;
  738. }
  739. }
  740. if (Count) {
  741. //
  742. // only need this page if there are incompatibities
  743. //
  744. if( (!CheckUpgradeOnly) && (UnattendedOperation) && (ErrorsPresent == FALSE) ) {
  745. //
  746. // We're doing an unattended upgrade, and there are
  747. // only warnings. Blow past the page.
  748. //
  749. b = FALSE;
  750. }
  751. else{
  752. TCHAR Text[512] = {'\0'};
  753. int iResult = 1;
  754. //
  755. // Customize the look of the page, depending on
  756. // what we have to display. 3 cases are possible:
  757. // 1. Warnings only (services we'll stop).
  758. // 2. Errors only (items that will prevent installation).
  759. // 3. combination of 1. and 2.
  760. //
  761. if( (CheckUpgradeOnly == TRUE) && (CheckUpgradeNoItems == TRUE) ) {
  762. iResult = LoadString(hInst, IDS_COMPAT_CHECKUPGRADE, Text, ARRAYSIZE(Text));
  763. } else if( (WarningsPresent == TRUE) && (ErrorsPresent == TRUE) ) {
  764. iResult = LoadString(hInst, IDS_COMPAT_ERR_WRN, Text, ARRAYSIZE(Text));
  765. } else if( WarningsPresent == TRUE ) {
  766. iResult = LoadString(hInst, IDS_COMPAT_WRN, Text, ARRAYSIZE(Text));
  767. } else if( ErrorsPresent == TRUE ) {
  768. iResult = LoadString(hInst, IDS_COMPAT_ERR, Text, ARRAYSIZE(Text));
  769. }
  770. MYASSERT(iResult);
  771. SetDlgItemText(hdlg,IDC_INTRO_TEXT,Text);
  772. b = TRUE;
  773. if (BatchMode || (CheckUpgradeOnly && UnattendSwitchSpecified)) {
  774. //
  775. // don't stop on this page in batch mode
  776. //
  777. UNATTENDED(PSBTN_NEXT);
  778. }
  779. else
  780. {
  781. // Stop the bill board and show the wizard again.
  782. SendMessage(GetParent (hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  783. }
  784. }
  785. }
  786. if (!b) {
  787. //
  788. // sanity check
  789. //
  790. MYASSERT (!IncompatibilityStopsInstallation);
  791. }
  792. } else {
  793. b = TRUE;
  794. }
  795. break;
  796. case WMX_NEXTBUTTON:
  797. if (IncompatibilityStopsInstallation) {
  798. SaveMessageForSMS( MSG_INCOMPATIBILITIES );
  799. // Send the ID of the page we wish to advance to
  800. *((LONG *)lParam) = IDD_CLEANING;
  801. }
  802. break;
  803. default:
  804. break;
  805. }
  806. return(b);
  807. }
  808. BOOL
  809. ProcessLine (
  810. IN DWORD CompatFlags
  811. )
  812. {
  813. DWORD currentVersion;
  814. if (ISNT()) {
  815. //return (OsVersion.dwMajorVersion < 5) || (CompatFlags & COMPFLAG_ALLOWNT5COMPAT);
  816. switch (OsVersionNumber) {
  817. case 400:
  818. return ( !(CompatFlags & COMPFLAG_SKIPNT40CHECK));
  819. case 500:
  820. return ( !(CompatFlags & COMPFLAG_SKIPNT50CHECK));
  821. case 501: // version 5.1
  822. return ( !(CompatFlags & COMPFLAG_SKIPNT51CHECK));
  823. case 502: // version 5.2
  824. return ( !(CompatFlags & COMPFLAG_SKIPNT52CHECK));
  825. default:
  826. return TRUE;
  827. }
  828. }
  829. return TRUE;
  830. }
  831. DWORD
  832. ProcessRegistryLine(
  833. LPVOID InfHandle,
  834. LPTSTR SectionName,
  835. DWORD Index
  836. )
  837. {
  838. LONG Error;
  839. HKEY hKey;
  840. DWORD Size, Reg_Type;
  841. LPBYTE Buffer;
  842. PCOMPATIBILITY_DATA CompData;
  843. LPCTSTR RegKey;
  844. LPCTSTR RegValue;
  845. LPCTSTR RegValueExpect;
  846. LPCTSTR Flags;
  847. TCHAR Value[20];
  848. PCTSTR Data;
  849. DWORD compatFlags = 0;
  850. BOOL bFail;
  851. //
  852. // first check if this line should be processed on NT5
  853. //
  854. Flags = InfGetFieldByIndex( InfHandle, SectionName, Index, 9 );
  855. if( Flags ){
  856. StringToInt ( Flags, &compatFlags);
  857. }
  858. if (!ProcessLine (compatFlags)) {
  859. return 0;
  860. }
  861. RegKey = InfGetFieldByIndex( InfHandle, SectionName, Index, 1 );
  862. RegValue = InfGetFieldByIndex( InfHandle, SectionName, Index, 2 );
  863. RegValueExpect = InfGetFieldByIndex( InfHandle, SectionName, Index, 3 );
  864. //
  865. // open the reg key
  866. //
  867. Error = RegOpenKeyEx(
  868. HKEY_LOCAL_MACHINE,
  869. RegKey,
  870. 0,
  871. KEY_READ,
  872. &hKey
  873. );
  874. if( Error != ERROR_SUCCESS ) {
  875. //
  876. // bogus reg key
  877. //
  878. return 0;
  879. }
  880. //
  881. // find out how much data there is
  882. //
  883. Error = RegQueryValueEx(
  884. hKey,
  885. RegValue,
  886. NULL,
  887. &Reg_Type,
  888. NULL,
  889. &Size
  890. );
  891. if( Error == ERROR_SUCCESS ) {
  892. //
  893. // allocate the buffer
  894. //
  895. Buffer = (LPBYTE) MALLOC( Size );
  896. if (Buffer == NULL) {
  897. RegCloseKey( hKey );
  898. return 0;
  899. }
  900. //
  901. // read the data
  902. //
  903. Error = RegQueryValueEx(
  904. hKey,
  905. RegValue,
  906. NULL,
  907. NULL,
  908. Buffer,
  909. &Size
  910. );
  911. RegCloseKey( hKey );
  912. if( Error != ERROR_SUCCESS ) {
  913. FREE( Buffer );
  914. return 0;
  915. }
  916. if( Reg_Type == REG_DWORD ){
  917. _itot( *(DWORD*)Buffer, Value, 10 );
  918. Data = Value;
  919. } else {
  920. Data = (PCTSTR)Buffer;
  921. }
  922. bFail = RegValueExpect && *RegValueExpect && (lstrcmp( RegValueExpect, Data ) != 0);
  923. FREE( Buffer );
  924. if (bFail) {
  925. return 0;
  926. }
  927. } else {
  928. RegCloseKey( hKey );
  929. if (RegValue && *RegValue) {
  930. return 0;
  931. }
  932. if (Error != ERROR_FILE_NOT_FOUND) {
  933. return 0;
  934. }
  935. if (RegValueExpect && *RegValueExpect) {
  936. return 0;
  937. }
  938. }
  939. CompData = (PCOMPATIBILITY_DATA) MALLOC( sizeof(COMPATIBILITY_DATA) );
  940. if (CompData == NULL) {
  941. return 0;
  942. }
  943. ZeroMemory(CompData,sizeof(COMPATIBILITY_DATA));
  944. CompData->Type = TEXT('r');
  945. CompData->RegKey = InfGetFieldByIndex( InfHandle, SectionName, Index, 1 );
  946. CompData->RegValue = InfGetFieldByIndex( InfHandle, SectionName, Index, 2 );
  947. CompData->RegValueExpect = InfGetFieldByIndex( InfHandle, SectionName, Index, 3 );
  948. CompData->HtmlName = InfGetFieldByIndex( InfHandle, SectionName, Index, 4 );
  949. CompData->TextName = InfGetFieldByIndex( InfHandle, SectionName, Index, 5 );
  950. if (!(CompData->TextName && *CompData->TextName)) {
  951. CompData->TextName = CompData->HtmlName;
  952. }
  953. CompData->Description = InfGetFieldByIndex( InfHandle, SectionName, Index, 6 );
  954. CompData->InfName = InfGetFieldByIndex( InfHandle, SectionName, Index, 7 );
  955. CompData->InfSection = InfGetFieldByIndex( InfHandle, SectionName, Index, 8 );
  956. CompData->Flags = compatFlags | GlobalCompFlags;
  957. InsertTailList( &CompatibilityData, &CompData->ListEntry );
  958. return 1;
  959. }
  960. DWORD
  961. ProcessServiceLine(
  962. LPVOID InfHandle,
  963. LPTSTR SectionName,
  964. DWORD Index,
  965. BOOL SetCheckedFlag
  966. )
  967. {
  968. TCHAR KeyName[MAX_PATH];
  969. LONG Error;
  970. HKEY hKey;
  971. PCOMPATIBILITY_DATA CompData;
  972. LPCTSTR ServiceName;
  973. LPDWORD RegData;
  974. DWORD Value;
  975. DWORD ValueSize;
  976. LPCTSTR FileName, FileVer, Flags;
  977. LPCTSTR linkDateStr, binProdVerStr;
  978. DWORD compatFlags = 0;
  979. Flags = InfGetFieldByIndex( InfHandle, SectionName, Index, 7 );
  980. if( Flags ){
  981. StringToInt ( Flags, &compatFlags);
  982. }
  983. //
  984. // first check if this line should be processed on NT5
  985. //
  986. if (!ProcessLine (compatFlags)) {
  987. return 0;
  988. }
  989. ServiceName = InfGetFieldByIndex( InfHandle, SectionName, Index, 1 );
  990. BuildPath (KeyName, TEXT("SYSTEM\\CurrentControlSet\\Services"), ServiceName);
  991. //
  992. // get an open key to the services database
  993. //
  994. Error = RegOpenKeyEx(
  995. HKEY_LOCAL_MACHINE,
  996. KeyName,
  997. 0,
  998. KEY_READ | KEY_WRITE,
  999. &hKey
  1000. );
  1001. if( Error != ERROR_SUCCESS ) {
  1002. return 0;
  1003. }
  1004. //
  1005. // We'll ceate a key here so that others will know that we've
  1006. // already checked this service. We'll remove it later. We
  1007. // don't care about error codes here because this is only used
  1008. // as a safety net for checks that may come after us.
  1009. //
  1010. if( SetCheckedFlag ) {
  1011. Value = 1;
  1012. RegSetValueEx( hKey,
  1013. TEXT("SetupChecked"),
  1014. 0,
  1015. REG_DWORD,
  1016. (CONST BYTE *)&Value,
  1017. sizeof(DWORD) );
  1018. } else {
  1019. //
  1020. // The user has asked us to simply remove these 'checked' flags
  1021. // from the services that we've examined.
  1022. //
  1023. RegDeleteValue( hKey,
  1024. TEXT("SetupChecked") );
  1025. RegCloseKey( hKey );
  1026. return 0;
  1027. }
  1028. //
  1029. // Check the start value of our target service.
  1030. //
  1031. ValueSize = sizeof(Value);
  1032. Error = RegQueryValueEx(
  1033. hKey,
  1034. TEXT("Start"),
  1035. NULL,
  1036. NULL,
  1037. (LPBYTE)&Value,
  1038. &ValueSize
  1039. );
  1040. if( Error != ERROR_SUCCESS){
  1041. Value = (DWORD)-1;
  1042. }
  1043. RegCloseKey( hKey );
  1044. // Have to check for the contents being NULL as InfGetFieldByIndex returns
  1045. // a valid pointer holding NULL if the field is blank. Also we need to go on in that case
  1046. // to look for Flags.
  1047. FileName = InfGetFieldByIndex( InfHandle, SectionName, Index, 5 );
  1048. FileVer = InfGetFieldByIndex( InfHandle, SectionName, Index, 6 );
  1049. if(FileName && *FileName) {
  1050. linkDateStr = InfGetFieldByIndex( InfHandle, SectionName, Index, 10);
  1051. binProdVerStr = InfGetFieldByIndex( InfHandle, SectionName, Index, 11);
  1052. if (!CheckForFileVersionEx ( FileName, FileVer, binProdVerStr, linkDateStr))
  1053. return 0;
  1054. }
  1055. RegData = (LPDWORD)MALLOC( sizeof(DWORD) );
  1056. if (RegData == NULL) {
  1057. return 0;
  1058. }
  1059. CompData = (PCOMPATIBILITY_DATA) MALLOC( sizeof(COMPATIBILITY_DATA) );
  1060. if (CompData == NULL) {
  1061. FREE(RegData);
  1062. return 0;
  1063. }
  1064. ZeroMemory(CompData,sizeof(COMPATIBILITY_DATA));
  1065. CompData->Type = TEXT('s');
  1066. CompData->Flags = compatFlags;
  1067. CompData->ServiceName = InfGetFieldByIndex( InfHandle, SectionName, Index, 1 );
  1068. CompData->HtmlName = InfGetFieldByIndex( InfHandle, SectionName, Index, 2 );
  1069. CompData->TextName = InfGetFieldByIndex( InfHandle, SectionName, Index, 3 );
  1070. if (!(CompData->TextName && *CompData->TextName)) {
  1071. CompData->TextName = CompData->HtmlName;
  1072. }
  1073. CompData->Description = InfGetFieldByIndex( InfHandle, SectionName, Index, 4 );
  1074. CompData->RegKeyName = DupString( KeyName );
  1075. CompData->RegValName = DupString( TEXT("Start") );
  1076. RegData[0] = SERVICE_DISABLED;
  1077. CompData->RegValData = RegData;
  1078. CompData->RegValDataSize = sizeof(DWORD);
  1079. CompData->Flags |= GlobalCompFlags;
  1080. CompData->InfName = InfGetFieldByIndex( InfHandle, SectionName, Index, 8 );
  1081. CompData->InfSection = InfGetFieldByIndex( InfHandle, SectionName, Index, 9 );
  1082. if( Value == SERVICE_DISABLED) {
  1083. // Let's not block installation since we didn't before and doesn't need to be now either.
  1084. CompData->Flags &= ~COMPFLAG_STOPINSTALL;
  1085. // Don't display any warnings since they can't do anything about it.
  1086. CompData->Flags |= COMPFLAG_HIDE;
  1087. }
  1088. InsertTailList( &CompatibilityData, &CompData->ListEntry );
  1089. return 1;
  1090. }
  1091. DWORD
  1092. ProcessTextModeLine(
  1093. LPVOID InfHandle,
  1094. LPTSTR SectionName,
  1095. DWORD Index
  1096. )
  1097. {
  1098. //
  1099. // Format of line:
  1100. // 0, 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8
  1101. // t,"fullpath","version.minor","html","text",%stringid%,flags,linkdate,binprodversion
  1102. //
  1103. PCOMPATIBILITY_DATA CompData;
  1104. LPCTSTR FileName;
  1105. LPCTSTR Flags;
  1106. LPCTSTR FileVer;
  1107. DWORD CompatFlags = 0;
  1108. //
  1109. // The only thing we need to start is the file name.
  1110. //
  1111. FileName = InfGetFieldByIndex(InfHandle, SectionName, Index, 1);
  1112. //
  1113. // If there was a filename, then see if its version and whatnot actually
  1114. // match
  1115. //
  1116. if ( FileName && *FileName )
  1117. {
  1118. LPCTSTR linkDateStr, binProdVerStr;
  1119. FileVer = InfGetFieldByIndex(InfHandle, SectionName, Index, 2);
  1120. linkDateStr = InfGetFieldByIndex(InfHandle, SectionName, Index, 7);
  1121. binProdVerStr = InfGetFieldByIndex(InfHandle, SectionName, Index, 8);
  1122. if ( !CheckForFileVersionEx( FileName, FileVer, binProdVerStr, linkDateStr ) )
  1123. return 0;
  1124. }
  1125. else
  1126. {
  1127. return 0;
  1128. }
  1129. Flags = InfGetFieldByIndex(InfHandle, SectionName, Index, 6);
  1130. if ( Flags != NULL ){
  1131. StringToInt(Flags, &CompatFlags);
  1132. }
  1133. CompData = (PCOMPATIBILITY_DATA)MALLOC(sizeof(COMPATIBILITY_DATA));
  1134. if ( CompData == NULL )
  1135. return 0;
  1136. //
  1137. // Now fill out the compdata structure
  1138. //
  1139. ZeroMemory(CompData, sizeof(*CompData));
  1140. CompData->FileName = FileName;
  1141. CompData->FileVer = FileVer;
  1142. CompData->HtmlName = InfGetFieldByIndex(InfHandle, SectionName, Index, 3);
  1143. CompData->TextName = InfGetFieldByIndex(InfHandle, SectionName, Index, 4);
  1144. if ( ( CompData->TextName == NULL ) || !CompData->TextName[0] )
  1145. CompData->TextName = CompData->HtmlName;
  1146. CompData->Description = InfGetFieldByIndex(InfHandle, SectionName, Index, 5);
  1147. //
  1148. CompData->Flags = CompatFlags | GlobalCompFlags | COMPFLAG_HIDE;
  1149. CompData->Type = TEXT('t');
  1150. InsertTailList(&CompatibilityData, &CompData->ListEntry);
  1151. return 1;
  1152. }
  1153. DWORD
  1154. ProcessFileLine(
  1155. LPVOID InfHandle,
  1156. LPTSTR SectionName,
  1157. DWORD Index
  1158. )
  1159. {
  1160. PCOMPATIBILITY_DATA CompData;
  1161. LPCTSTR FileName;
  1162. LPCTSTR FileVer;
  1163. LPCTSTR Flags;
  1164. LPCTSTR linkDateStr, binProdVerStr;
  1165. DWORD compatFlags = 0;
  1166. //
  1167. // first check if this line should be processed on NT5
  1168. //
  1169. Flags = InfGetFieldByIndex( InfHandle, SectionName, Index, 8);
  1170. if( Flags ){
  1171. StringToInt ( Flags, &compatFlags);
  1172. }
  1173. if (!ProcessLine (compatFlags)) {
  1174. return 0;
  1175. }
  1176. FileName = InfGetFieldByIndex( InfHandle, SectionName, Index, 1 );
  1177. FileVer = InfGetFieldByIndex( InfHandle, SectionName, Index, 2 );
  1178. if( FileName && *FileName ){
  1179. linkDateStr = InfGetFieldByIndex( InfHandle, SectionName, Index, 9);
  1180. binProdVerStr = InfGetFieldByIndex( InfHandle, SectionName, Index, 10);
  1181. if (!CheckForFileVersionEx ( FileName, FileVer, binProdVerStr, linkDateStr)) {
  1182. return 0;
  1183. }
  1184. }else{
  1185. return 0;
  1186. }
  1187. CompData = (PCOMPATIBILITY_DATA) MALLOC( sizeof(COMPATIBILITY_DATA) );
  1188. if (CompData == NULL) {
  1189. return 0;
  1190. }
  1191. ZeroMemory(CompData,sizeof(COMPATIBILITY_DATA));
  1192. CompData->Type = TEXT('f');
  1193. CompData->FileName = InfGetFieldByIndex( InfHandle, SectionName, Index, 1 );
  1194. CompData->FileVer = InfGetFieldByIndex( InfHandle, SectionName, Index, 2 );
  1195. CompData->HtmlName = InfGetFieldByIndex( InfHandle, SectionName, Index, 3 );
  1196. CompData->TextName = InfGetFieldByIndex( InfHandle, SectionName, Index, 4 );
  1197. if (!(CompData->TextName && *CompData->TextName)) {
  1198. CompData->TextName = CompData->HtmlName;
  1199. }
  1200. CompData->Description = InfGetFieldByIndex( InfHandle, SectionName, Index, 5 );
  1201. CompData->InfName = InfGetFieldByIndex( InfHandle, SectionName, Index, 6 );
  1202. CompData->InfSection = InfGetFieldByIndex( InfHandle, SectionName, Index, 7 );
  1203. CompData->Flags = compatFlags | GlobalCompFlags;
  1204. InsertTailList( &CompatibilityData, &CompData->ListEntry );
  1205. return 1;
  1206. }
  1207. BOOL
  1208. CompatibilityCallback(
  1209. PCOMPATIBILITY_ENTRY CompEntry,
  1210. PCOMPATIBILITY_CONTEXT CompContext
  1211. )
  1212. {
  1213. PCOMPATIBILITY_DATA CompData;
  1214. //
  1215. // parameter validation
  1216. //
  1217. if (CompEntry->Description == NULL || CompEntry->Description[0] == 0) {
  1218. //
  1219. // who did this?
  1220. //
  1221. MYASSERT (FALSE);
  1222. SetLastError( COMP_ERR_DESC_MISSING );
  1223. return FALSE;
  1224. }
  1225. if (CompEntry->TextName == NULL || CompEntry->TextName[0] ==0) {
  1226. //
  1227. // who did this?
  1228. //
  1229. MYASSERT (FALSE);
  1230. SetLastError( COMP_ERR_TEXTNAME_MISSING );
  1231. return FALSE;
  1232. }
  1233. if (CompEntry->RegKeyName) {
  1234. if (CompEntry->RegValName == NULL) {
  1235. //
  1236. // who did this?
  1237. //
  1238. MYASSERT (FALSE);
  1239. SetLastError( COMP_ERR_REGVALNAME_MISSING );
  1240. return FALSE;
  1241. }
  1242. if (CompEntry->RegValData == NULL) {
  1243. //
  1244. // who did this?
  1245. //
  1246. MYASSERT (FALSE);
  1247. SetLastError( COMP_ERR_REGVALDATA_MISSING );
  1248. return FALSE;
  1249. }
  1250. }
  1251. if (CompEntry->InfName) {
  1252. if (CompEntry->InfSection == NULL) {
  1253. //
  1254. // who did this?
  1255. //
  1256. MYASSERT (FALSE);
  1257. SetLastError( COMP_ERR_INFSECTION_MISSING );
  1258. return FALSE;
  1259. }
  1260. }
  1261. //
  1262. // allocate the compatibility structure
  1263. //
  1264. CompData = (PCOMPATIBILITY_DATA) MALLOC( sizeof(COMPATIBILITY_DATA) );
  1265. if (CompData == NULL) {
  1266. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1267. return FALSE;
  1268. }
  1269. ZeroMemory(CompData, sizeof(COMPATIBILITY_DATA));
  1270. //
  1271. // save the sata
  1272. //
  1273. CompData->Description = DupString( CompEntry->Description );
  1274. CompData->HtmlName = CompEntry->HtmlName ? DupString( CompEntry->HtmlName ) : NULL;
  1275. CompData->TextName = DupString( CompEntry->TextName );
  1276. CompData->SaveValue = CompEntry->SaveValue;
  1277. CompData->Flags = CompEntry->Flags;
  1278. CompData->Flags |= PerCompatDllFlags;
  1279. CompData->Flags |= GlobalCompFlags;
  1280. CompData->CompHaveDisk = CompContext->CompHaveDisk;
  1281. CompData->hModDll = CompContext->hModDll;
  1282. if (CompEntry->RegKeyName) {
  1283. CompData->RegKeyName = DupString( CompEntry->RegKeyName );
  1284. CompData->RegValName = DupString( CompEntry->RegValName );
  1285. CompData->RegValDataSize = CompEntry->RegValDataSize;
  1286. CompData->RegValData = MALLOC(CompEntry->RegValDataSize);
  1287. if (CompData->RegValData) {
  1288. CopyMemory( CompData->RegValData, CompEntry->RegValData, CompEntry->RegValDataSize );
  1289. }
  1290. }
  1291. if (CompEntry->InfName){
  1292. CompData->InfName = DupString( CompEntry->InfName );
  1293. CompData->InfSection = DupString( CompEntry->InfSection );
  1294. }
  1295. InsertTailList( &CompatibilityData, &CompData->ListEntry );
  1296. CompContext->Count += 1;
  1297. return TRUE;
  1298. }
  1299. DWORD
  1300. ProcessDLLLine(
  1301. LPVOID InfHandle,
  1302. LPTSTR SectionName,
  1303. DWORD Index
  1304. )
  1305. {
  1306. TCHAR Buffer[MAX_PATH];
  1307. TCHAR FullPath[MAX_PATH];
  1308. HMODULE hMod;
  1309. CHAR CompCheckEntryPoint[MAX_PATH] = {'\0'};
  1310. CHAR HaveDiskEntryPoint[MAX_PATH] = {'\0'};
  1311. PCOMPAIBILITYCHECK CompCheck;
  1312. PCOMPAIBILITYHAVEDISK CompHaveDisk;
  1313. LPTSTR DllName;
  1314. LPTSTR CompCheckEntryPointW;
  1315. LPTSTR HaveDiskEntryPointW;
  1316. LPTSTR ProcessOnCleanInstall;
  1317. LPTSTR Flags;
  1318. COMPATIBILITY_CONTEXT CompContext;
  1319. BOOL Rslt;
  1320. DWORD Status;
  1321. DWORD compatFlags = 0;
  1322. PerCompatDllFlags = 0;
  1323. DllName = (LPTSTR)InfGetFieldByIndex( InfHandle, SectionName, Index, 1 );
  1324. if (!DllName)
  1325. return 0;
  1326. CompCheckEntryPointW = (LPTSTR)InfGetFieldByIndex( InfHandle, SectionName, Index, 2 );
  1327. HaveDiskEntryPointW = (LPTSTR)InfGetFieldByIndex( InfHandle, SectionName, Index, 3 );
  1328. if((HaveDiskEntryPointW != NULL) && (lstrlen(HaveDiskEntryPointW) == 0)) {
  1329. //
  1330. // If HaveDiskEntryPointW points to an empty string, then make it NULL.
  1331. // This is necessary because since this field is optional, the user may have specified
  1332. // it in dosnet.inf as ,, and in this case the winnt32 parser will translate the info in
  1333. // filed as an empty string.
  1334. //
  1335. HaveDiskEntryPointW = NULL;
  1336. }
  1337. ProcessOnCleanInstall = (LPTSTR)InfGetFieldByIndex( InfHandle, SectionName, Index, 4 );
  1338. if( !Upgrade &&
  1339. ((ProcessOnCleanInstall == NULL) ||
  1340. (lstrlen( ProcessOnCleanInstall ) == 0) ||
  1341. (_ttoi(ProcessOnCleanInstall) == 0))
  1342. ) {
  1343. //
  1344. // On clean install, we don't process the dll if 'ProcessOnCleanInstall' was not
  1345. // specified, or if it was specified as 0.
  1346. //
  1347. return 0;
  1348. }
  1349. Flags = (LPTSTR)InfGetFieldByIndex( InfHandle, SectionName, Index, 5 );
  1350. if( Flags ){
  1351. //check return value
  1352. StringToInt ( Flags, &compatFlags);
  1353. }
  1354. PerCompatDllFlags = compatFlags;
  1355. if (!ExpandEnvironmentStrings(DllName, Buffer, ARRAYSIZE(Buffer))) {
  1356. return 0;
  1357. }
  1358. if (!FindPathToWinnt32File (Buffer, FullPath, MAX_PATH) ||
  1359. !(hMod = LoadLibrary (FullPath))) {
  1360. return 0;
  1361. }
  1362. #ifdef UNICODE
  1363. WideCharToMultiByte(
  1364. CP_ACP,
  1365. 0,
  1366. CompCheckEntryPointW,
  1367. -1,
  1368. CompCheckEntryPoint,
  1369. sizeof(CompCheckEntryPoint),
  1370. NULL,
  1371. NULL
  1372. );
  1373. if (HaveDiskEntryPointW) {
  1374. WideCharToMultiByte(
  1375. CP_ACP,
  1376. 0,
  1377. HaveDiskEntryPointW,
  1378. -1,
  1379. HaveDiskEntryPoint,
  1380. sizeof(HaveDiskEntryPoint),
  1381. NULL,
  1382. NULL
  1383. );
  1384. }
  1385. #else
  1386. if(lstrlen(CompCheckEntryPointW) < ARRAYSIZE(CompCheckEntryPoint)){
  1387. lstrcpy( CompCheckEntryPoint, CompCheckEntryPointW );
  1388. }
  1389. else{
  1390. MYASSERT(FALSE);
  1391. }
  1392. if (HaveDiskEntryPointW && lstrlen(HaveDiskEntryPointW) < ARRAYSIZE(HaveDiskEntryPoint)) {
  1393. lstrcpy( HaveDiskEntryPoint, HaveDiskEntryPointW );
  1394. }
  1395. else{
  1396. MYASSERT(lstrlen(HaveDiskEntryPointW) < ARRAYSIZE(HaveDiskEntryPoint));
  1397. }
  1398. #endif
  1399. CompCheck = (PCOMPAIBILITYCHECK) GetProcAddress( hMod, CompCheckEntryPoint );
  1400. if (CompCheck == NULL) {
  1401. FreeLibrary( hMod );
  1402. return 0;
  1403. }
  1404. if (HaveDiskEntryPointW) {
  1405. CompHaveDisk = (PCOMPAIBILITYHAVEDISK) GetProcAddress( hMod, HaveDiskEntryPoint );
  1406. if (CompHaveDisk == NULL) {
  1407. FreeLibrary( hMod );
  1408. return 0;
  1409. }
  1410. }
  1411. CompContext.Count = 0;
  1412. CompContext.CompHaveDisk = CompHaveDisk;
  1413. CompContext.hModDll = hMod;
  1414. if ( !ProcessLine( compatFlags )) {
  1415. Rslt = FALSE;
  1416. } else {
  1417. __try {
  1418. Rslt = CompCheck( (PCOMPAIBILITYCALLBACK)CompatibilityCallback, (LPVOID)&CompContext );
  1419. } __except(EXCEPTION_EXECUTE_HANDLER) {
  1420. Status = GetExceptionCode();
  1421. Rslt = FALSE;
  1422. }
  1423. }
  1424. PerCompatDllFlags = 0;
  1425. if (!Rslt) {
  1426. FreeLibrary( hMod );
  1427. return 0;
  1428. }
  1429. if (CompContext.Count == 0) {
  1430. FreeLibrary( hMod );
  1431. }
  1432. return CompContext.Count;
  1433. }
  1434. DWORD
  1435. ProcessCompatibilitySection(
  1436. LPVOID InfHandle,
  1437. LPTSTR SectionName
  1438. )
  1439. {
  1440. DWORD LineCount;
  1441. DWORD Count;
  1442. DWORD i;
  1443. LPCTSTR Type;
  1444. DWORD Good;
  1445. //
  1446. // get the section count, zero means bail out
  1447. //
  1448. LineCount = InfGetSectionLineCount( InfHandle, SectionName );
  1449. if (LineCount == 0 || LineCount == 0xffffffff) {
  1450. return 0;
  1451. }
  1452. for (i=0,Count=0; i<LineCount; i++) {
  1453. Type = InfGetFieldByIndex( InfHandle, SectionName, i, 0 );
  1454. if (Type == NULL) {
  1455. continue;
  1456. }
  1457. //
  1458. // On clean install we only process dll line.
  1459. // (We need to process the line that checks for unsupported architectures)
  1460. //
  1461. if( !Upgrade && ( _totlower(Type[0]) != TEXT('d') ) ) {
  1462. continue;
  1463. }
  1464. switch (_totlower(Type[0])) {
  1465. case TEXT('r'):
  1466. //
  1467. // registry value
  1468. //
  1469. Count += ProcessRegistryLine( InfHandle, SectionName, i );
  1470. break;
  1471. case TEXT('s'):
  1472. //
  1473. // service or driver
  1474. //
  1475. Count += ProcessServiceLine( InfHandle, SectionName, i, TRUE );
  1476. break;
  1477. case TEXT('f'):
  1478. //
  1479. // presence of a file
  1480. //
  1481. Count += ProcessFileLine( InfHandle, SectionName, i );
  1482. break;
  1483. case TEXT('d'):
  1484. //
  1485. // run an external dll
  1486. //
  1487. Count += ProcessDLLLine( InfHandle, SectionName, i );
  1488. break;
  1489. case TEXT('t'):
  1490. //
  1491. // Textmode should know to overwrite this file
  1492. //
  1493. Count += ProcessTextModeLine( InfHandle, SectionName, i );
  1494. break;
  1495. default:
  1496. break;
  1497. }
  1498. }
  1499. return Count;
  1500. }
  1501. VOID
  1502. RemoveCompatibilityServiceEntries(
  1503. LPVOID InfHandle,
  1504. LPTSTR SectionName
  1505. )
  1506. {
  1507. DWORD LineCount;
  1508. DWORD Count;
  1509. DWORD i;
  1510. LPCTSTR Type;
  1511. DWORD Good;
  1512. //
  1513. // get the section count, zero means bail out
  1514. //
  1515. LineCount = InfGetSectionLineCount( InfHandle, SectionName );
  1516. if (LineCount == 0 || LineCount == 0xffffffff) {
  1517. return;
  1518. }
  1519. for (i=0,Count=0; i<LineCount; i++) {
  1520. Type = InfGetFieldByIndex( InfHandle, SectionName, i, 0 );
  1521. if (Type == NULL) {
  1522. continue;
  1523. }
  1524. //
  1525. // On clean install we only process dll line.
  1526. // (We need to process the line that checks for unsupported architectures)
  1527. //
  1528. if( !Upgrade && ( _totlower(Type[0]) != TEXT('d') ) ) {
  1529. continue;
  1530. }
  1531. switch (_totlower(Type[0])) {
  1532. case TEXT('s'):
  1533. //
  1534. // service or driver
  1535. //
  1536. Count += ProcessServiceLine( InfHandle, SectionName, i, FALSE );
  1537. break;
  1538. default:
  1539. break;
  1540. }
  1541. }
  1542. }
  1543. //
  1544. // HACKHACK - NT4's explorer.exe will fail to properly process runonce values
  1545. // whose value name is > 31 characters. We call this function to
  1546. // workaround this NT4 bug. It basically truncates any value names
  1547. // so that explorer will process and delete them.
  1548. //
  1549. void FixRunOnceForNT4(DWORD dwNumValues)
  1550. {
  1551. HKEY hkRunOnce;
  1552. int iValueNumber = 20; // start this at 20 to minimize chance of name collision.
  1553. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1554. TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"),
  1555. 0,
  1556. MAXIMUM_ALLOWED,
  1557. &hkRunOnce) == ERROR_SUCCESS)
  1558. {
  1559. TCHAR szValueName[MAX_PATH];
  1560. TCHAR szValueContents[MAX_PATH * 3]; // big enough to hold a large regsvr32 command
  1561. DWORD dwValueIndex = 0;
  1562. DWORD dwSanityCheck = 0;
  1563. DWORD dwNameSize = MAX_PATH;
  1564. DWORD dwValueSize = sizeof(szValueContents);
  1565. DWORD dwType;
  1566. while (RegEnumValue(hkRunOnce,
  1567. dwValueIndex,
  1568. szValueName,
  1569. &dwNameSize,
  1570. NULL,
  1571. &dwType,
  1572. (LPBYTE)szValueContents,
  1573. &dwValueSize) == ERROR_SUCCESS)
  1574. {
  1575. // increment our counters
  1576. dwValueIndex++;
  1577. dwSanityCheck++;
  1578. // reset these for the next RegEnumValue call
  1579. dwNameSize = MAX_PATH;
  1580. dwValueSize = sizeof(szValueContents);
  1581. if ((dwType == REG_SZ) && (lstrlen(szValueName) > 31))
  1582. {
  1583. TCHAR szNewValueName[32];
  1584. TCHAR szTemp[32];
  1585. // we have a value name that is too big for NT4's explorer.exe,
  1586. // so we need to truncate to 10 characters and add a number on the
  1587. // end to insure that it is unique.
  1588. lstrcpyn(szTemp, szValueName, 10);
  1589. wsprintf(szNewValueName, TEXT("%s%d"), szTemp, iValueNumber++);
  1590. RegDeleteValue(hkRunOnce, szValueName);
  1591. RegSetValueEx(hkRunOnce,
  1592. szNewValueName,
  1593. 0,
  1594. REG_SZ,
  1595. (LPBYTE)szValueContents,
  1596. (lstrlen(szValueContents) + 1) * sizeof(TCHAR));
  1597. // backup our regenum index to be sure we don't miss a value (since we are adding/deleteing
  1598. // values during the enumeration, its kinda messy)
  1599. dwValueIndex--;
  1600. }
  1601. if (dwSanityCheck > (2 * dwNumValues))
  1602. {
  1603. // something has gone terribly wrong, we have looped in RegEnumValue *way* to
  1604. // many times!
  1605. break;
  1606. }
  1607. }
  1608. RegCloseKey(hkRunOnce);
  1609. }
  1610. }
  1611. VOID
  1612. pSetWarningFlag (
  1613. VOID
  1614. )
  1615. {
  1616. LONG Error;
  1617. HKEY setupKey;
  1618. Error = RegOpenKeyEx (
  1619. HKEY_LOCAL_MACHINE,
  1620. TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup"),
  1621. 0,
  1622. KEY_ALL_ACCESS,
  1623. &setupKey
  1624. );
  1625. RegSetValueEx (
  1626. setupKey,
  1627. S_WINNT32_WARNING,
  1628. 0,
  1629. REG_SZ,
  1630. (PBYTE) TEXT(""), // value is all that matters, data is irrelevant
  1631. sizeof (TCHAR)
  1632. );
  1633. RegCloseKey (setupKey);
  1634. Error = RegOpenKeyEx (
  1635. HKEY_LOCAL_MACHINE,
  1636. TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"),
  1637. 0,
  1638. KEY_ALL_ACCESS,
  1639. &setupKey
  1640. );
  1641. RegSetValueEx (
  1642. setupKey,
  1643. S_WINNT32_WARNING,
  1644. 0,
  1645. REG_SZ,
  1646. (PBYTE) TEXT(""),
  1647. sizeof (TEXT(""))
  1648. );
  1649. RegCloseKey (setupKey);
  1650. }
  1651. BOOL
  1652. pRebootAfterWarning (
  1653. VOID
  1654. )
  1655. {
  1656. LONG Error;
  1657. HKEY hKey;
  1658. HKEY setupKey;
  1659. DWORD dataSize;
  1660. TCHAR textBuffer[512];
  1661. BOOL result = FALSE;
  1662. //
  1663. // Did we provide a warning?
  1664. //
  1665. Error = RegOpenKeyEx (
  1666. HKEY_LOCAL_MACHINE,
  1667. TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup"),
  1668. 0,
  1669. KEY_ALL_ACCESS,
  1670. &setupKey
  1671. );
  1672. if (Error != ERROR_SUCCESS) {
  1673. return FALSE;
  1674. }
  1675. dataSize = sizeof (textBuffer);
  1676. Error = RegQueryValueEx (
  1677. setupKey,
  1678. S_WINNT32_WARNING,
  1679. NULL,
  1680. NULL,
  1681. (PBYTE) textBuffer,
  1682. &dataSize
  1683. );
  1684. if (Error == ERROR_SUCCESS) {
  1685. //
  1686. // Warning was issued. Did user reboot as instructed? If they
  1687. // did, then the RunOnce entry should be gone. Otherwise, we
  1688. // will not provide the warning again if someone keeps
  1689. // putting junk in RunOnce.
  1690. //
  1691. Error = RegOpenKeyEx (
  1692. HKEY_LOCAL_MACHINE,
  1693. TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"),
  1694. 0,
  1695. KEY_ALL_ACCESS,
  1696. &hKey
  1697. );
  1698. if (Error == ERROR_SUCCESS) {
  1699. dataSize = sizeof (textBuffer);
  1700. Error = RegQueryValueEx (
  1701. hKey,
  1702. S_WINNT32_WARNING,
  1703. NULL,
  1704. NULL,
  1705. (PBYTE) textBuffer,
  1706. &dataSize
  1707. );
  1708. if (Error != ERROR_SUCCESS) {
  1709. //
  1710. // yes, they did reboot, our value is gone from RunOnce
  1711. //
  1712. result = TRUE;
  1713. //
  1714. // also clean up the other value
  1715. //
  1716. RegDeleteValue (setupKey, S_WINNT32_WARNING);
  1717. }
  1718. RegCloseKey (hKey);
  1719. }
  1720. }
  1721. RegCloseKey (setupKey);
  1722. return result;
  1723. }
  1724. BOOL
  1725. pCheckForPendingRunOnce (
  1726. VOID
  1727. )
  1728. {
  1729. LONG Error;
  1730. HKEY hKey = NULL;
  1731. HKEY setupKey = NULL;
  1732. DWORD dataSize;
  1733. BOOL result = FALSE;
  1734. TCHAR textBuffer[512];
  1735. TCHAR exeBuffer[512];
  1736. DWORD exeBufferSize;
  1737. DWORD type;
  1738. DWORD valueNumber;
  1739. BOOL foundValues = FALSE;
  1740. INF_ENUM e;
  1741. BOOL warningIssued = FALSE;
  1742. BOOL ignore;
  1743. __try {
  1744. //
  1745. // Open regisry keys.
  1746. //
  1747. // ISSUE: Should this be expanded to include HKCU?
  1748. //
  1749. Error = RegOpenKeyEx (
  1750. HKEY_LOCAL_MACHINE,
  1751. TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"),
  1752. 0,
  1753. KEY_ALL_ACCESS,
  1754. &hKey
  1755. );
  1756. if (Error != ERROR_SUCCESS) {
  1757. //
  1758. // no RunOnce key [this should exist in all cases]
  1759. //
  1760. __leave;
  1761. }
  1762. //
  1763. // Check if there are any RunOnce
  1764. // entries present. Skip excluded entries.
  1765. //
  1766. // NOTE: We restrict the loop to 10000, in line with existing code that
  1767. // is protecting itself from enumerations that never end on NT
  1768. // 4. It is not clear this is needed, but 10000 should be high
  1769. // enough to take care of this risk without introducing other
  1770. // problems.
  1771. //
  1772. if (!foundValues) {
  1773. for (valueNumber = 0 ; valueNumber < 10000 ; valueNumber++) {
  1774. dataSize = ARRAYSIZE(textBuffer);
  1775. exeBufferSize = sizeof (exeBuffer);
  1776. Error = RegEnumValue (
  1777. hKey,
  1778. valueNumber,
  1779. textBuffer,
  1780. &dataSize,
  1781. NULL,
  1782. &type,
  1783. (PBYTE) exeBuffer,
  1784. &exeBufferSize
  1785. );
  1786. if (Error == ERROR_NO_MORE_ITEMS) {
  1787. break;
  1788. }
  1789. if (Error == ERROR_SUCCESS) {
  1790. //
  1791. // Test registry value against pattern list
  1792. //
  1793. ignore = FALSE;
  1794. if (EnumFirstInfLine (&e, MainInf, TEXT("RunOnceExclusions.Value"))) {
  1795. do {
  1796. if (IsPatternMatch (e.FieldZeroData, textBuffer)) {
  1797. AbortInfLineEnum (&e);
  1798. ignore = TRUE;
  1799. break;
  1800. }
  1801. } while (EnumNextInfLine (&e));
  1802. }
  1803. if (ignore) {
  1804. continue;
  1805. }
  1806. //
  1807. // Test command line against pattern list
  1808. //
  1809. if (EnumFirstInfLine (&e, MainInf, TEXT("RunOnceExclusions.ValueData"))) {
  1810. do {
  1811. if (IsPatternMatch (e.FieldZeroData, exeBuffer)) {
  1812. AbortInfLineEnum (&e);
  1813. ignore = TRUE;
  1814. break;
  1815. }
  1816. } while (EnumNextInfLine (&e));
  1817. }
  1818. if (ignore) {
  1819. continue;
  1820. }
  1821. //
  1822. // Found a RunOnce entry that should be executed before upgrading
  1823. //
  1824. foundValues = TRUE;
  1825. break;
  1826. }
  1827. }
  1828. }
  1829. if (!foundValues) {
  1830. __leave;
  1831. }
  1832. //
  1833. // Otherwise, provide the warning, and write Winnt32Warning to the Setup
  1834. // key and RunOnce key.
  1835. //
  1836. if (ISNT() && BuildNumber <= 1381) {
  1837. //
  1838. // Get the number of values for the worker fn, so it
  1839. // can protect itself against a runaway enumeration.
  1840. //
  1841. Error = RegQueryInfoKey (
  1842. hKey,
  1843. NULL, // class
  1844. NULL, // class size
  1845. NULL, // reserved
  1846. NULL, // subkey count
  1847. NULL, // max subkeys
  1848. NULL, // max class
  1849. &valueNumber, // value count
  1850. NULL, // max value name len
  1851. NULL, // max value data len
  1852. NULL, // security desc
  1853. NULL // last write time
  1854. );
  1855. if (Error != ERROR_SUCCESS) {
  1856. valueNumber = 100; // some random count, doesn't really matter because failure case is impracticle
  1857. }
  1858. FixRunOnceForNT4 (valueNumber);
  1859. }
  1860. result = TRUE;
  1861. }
  1862. __finally {
  1863. if (hKey) {
  1864. RegCloseKey (hKey);
  1865. }
  1866. }
  1867. return result;
  1868. }
  1869. #ifdef UNICODE
  1870. BOOL
  1871. pCheckForPendingFileRename (
  1872. VOID
  1873. )
  1874. {
  1875. LONG Error;
  1876. HKEY smKey;
  1877. DWORD dataSize;
  1878. BOOL result = FALSE;
  1879. DWORD type;
  1880. Error = RegOpenKeyEx (
  1881. HKEY_LOCAL_MACHINE,
  1882. TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager"),
  1883. 0,
  1884. KEY_ALL_ACCESS,
  1885. &smKey
  1886. );
  1887. if (Error == ERROR_SUCCESS) {
  1888. dataSize = 0;
  1889. Error = RegQueryValueEx (
  1890. smKey,
  1891. TEXT("PendingFileRenameOperations"),
  1892. NULL,
  1893. &type,
  1894. NULL,
  1895. &dataSize
  1896. );
  1897. if (Error == ERROR_SUCCESS && type == REG_MULTI_SZ && dataSize > 0) {
  1898. result = TRUE;
  1899. }
  1900. RegCloseKey (smKey);
  1901. }
  1902. return result;
  1903. }
  1904. VOID
  1905. pCleanFileRenames (
  1906. VOID
  1907. )
  1908. {
  1909. LONG Error;
  1910. HKEY smKey;
  1911. Error = RegOpenKeyEx (
  1912. HKEY_LOCAL_MACHINE,
  1913. TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager"),
  1914. 0,
  1915. KEY_ALL_ACCESS,
  1916. &smKey
  1917. );
  1918. if (Error == ERROR_SUCCESS) {
  1919. RegDeleteValue (smKey, TEXT("PendingFileRenameOperations"));
  1920. RegCloseKey (smKey);
  1921. }
  1922. }
  1923. #else
  1924. //
  1925. // not implemented on ANSI platforms
  1926. //
  1927. #define pCheckForPendingFileRename() (FALSE)
  1928. #define pCleanFileRenames()
  1929. #endif
  1930. BOOL
  1931. ProcessCompatibilityData(
  1932. HWND hDlg
  1933. )
  1934. {
  1935. DWORD Count;
  1936. PCOMPATIBILITY_DATA CompData;
  1937. TCHAR textBuffer[512];
  1938. BOOL runOnce;
  1939. BOOL fileRenames;
  1940. if( !CompatibilityData.Flink ) {
  1941. InitializeListHead( &CompatibilityData );
  1942. }
  1943. //
  1944. // On clean install we have to process [ServicesToStopInstallation].
  1945. // This section will contain at least the check for unsupported architectures that has to be
  1946. // executed onb clean install.
  1947. //
  1948. GlobalCompFlags = COMPFLAG_STOPINSTALL;
  1949. //
  1950. // please don't reset this variable; it may be > 0 intentionally!
  1951. //
  1952. // CompatibilityCount = 0;
  1953. //
  1954. // check for "RunOnce" Stuff
  1955. //
  1956. if( (Upgrade) && !(CheckUpgradeOnly) ) {
  1957. //
  1958. // on NT upgrades check PendingFileRenameOperations value as well
  1959. // [RAID# 713484]
  1960. //
  1961. runOnce = pCheckForPendingRunOnce();
  1962. fileRenames = pCheckForPendingFileRename();
  1963. if (runOnce || fileRenames) {
  1964. if (pRebootAfterWarning ()) {
  1965. //
  1966. // they did reboot, but bogus software left traces behind;
  1967. // clean it before continuing
  1968. //
  1969. if (fileRenames) {
  1970. pCleanFileRenames();
  1971. }
  1972. } else {
  1973. CompData = (PCOMPATIBILITY_DATA) MALLOC( sizeof(COMPATIBILITY_DATA) );
  1974. if (CompData) {
  1975. ZeroMemory(CompData,sizeof(COMPATIBILITY_DATA));
  1976. if(!LoadString(hInst, IDS_COMPAT_PENDING_REBOOT, textBuffer, ARRAYSIZE(textBuffer))) {
  1977. CompData->Description = 0;
  1978. } else {
  1979. CompData->Description = DupString(textBuffer);
  1980. }
  1981. CompData->Flags |= GlobalCompFlags;
  1982. CompData->HtmlName = DupString( TEXT("compdata\\runonce.htm") );
  1983. CompData->TextName = DupString( TEXT("compdata\\runonce.txt") );
  1984. InsertTailList( &CompatibilityData, &CompData->ListEntry );
  1985. CompatibilityCount++;
  1986. IncompatibilityStopsInstallation = TRUE;
  1987. pSetWarningFlag ();
  1988. }
  1989. }
  1990. }
  1991. }
  1992. if (ISNT()) {
  1993. CompatibilityCount += ProcessCompatibilitySection( NtcompatInf, TEXT("ServicesToStopInstallation") );
  1994. if (CompatibilityCount) {
  1995. IncompatibilityStopsInstallation = TRUE;
  1996. }
  1997. GlobalCompFlags = 0;
  1998. CompatibilityCount += ProcessCompatibilitySection( NtcompatInf, TEXT("ServicesToDisable") );
  1999. //
  2000. // Now cleanup any turds we left in the registry on the services we checked.
  2001. //
  2002. RemoveCompatibilityServiceEntries( NtcompatInf, TEXT("ServicesToStopInstallation") );
  2003. RemoveCompatibilityServiceEntries( NtcompatInf, TEXT("ServicesToDisable") );
  2004. }
  2005. if( CompatibilityCount ) {
  2006. return TRUE;
  2007. } else {
  2008. return FALSE;
  2009. }
  2010. }
  2011. BOOL
  2012. WriteTextmodeReplaceData(
  2013. IN HANDLE hTargetFile
  2014. )
  2015. {
  2016. CHAR Buffer[MAX_PATH*2];
  2017. PLIST_ENTRY Next;
  2018. PCOMPATIBILITY_DATA CompData;
  2019. BOOL Result = FALSE;
  2020. DWORD Bytes;
  2021. //
  2022. // For textmode "overwriting" files, write them out to the
  2023. // WINNT_OVERWRITE_EXISTING (IncompatibleFilesToOverWrite) section
  2024. // of this compatibility data file.
  2025. //
  2026. // Textmode just needs to know the name of the file.
  2027. //
  2028. SetFilePointer(hTargetFile, 0, 0, FILE_END);
  2029. #pragma prefast(suppress:53, the result of _snprintf is tested)
  2030. if(_snprintf(Buffer, ARRAYSIZE(Buffer), "\r\n[%s]\r\n", WINNT_OVERWRITE_EXISTING_A) < 0){
  2031. Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
  2032. MYASSERT(FALSE);
  2033. }
  2034. WriteFile(hTargetFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL);
  2035. //
  2036. // Loop down the list of items
  2037. //
  2038. if ( ( Next = CompatibilityData.Flink ) != NULL )
  2039. {
  2040. while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData)
  2041. {
  2042. CompData = CONTAINING_RECORD(Next, COMPATIBILITY_DATA, ListEntry);
  2043. Next = CompData->ListEntry.Flink;
  2044. if (!ProcessLine(CompData->Flags))
  2045. continue;
  2046. //
  2047. // The set string is:
  2048. //
  2049. // "shortfilename" = "fullpathname","version.string"
  2050. //
  2051. // ExpandEnvironmentStrings to ensure that the full path for any
  2052. // 't' line is expanded properly
  2053. //
  2054. if ((CompData->Type == TEXT('t')) && CompData->FileName)
  2055. {
  2056. static TCHAR tchLocalExpandedPath[MAX_PATH*2];
  2057. PTSTR ptszFileNameBit = NULL;
  2058. DWORD dwResult = 0;
  2059. dwResult = ExpandEnvironmentStrings(
  2060. CompData->FileName,
  2061. tchLocalExpandedPath,
  2062. MAX_PATH );
  2063. //
  2064. // Did we run out of characters expanding the path? Wierd...
  2065. //
  2066. if ( dwResult > MAX_PATH*2 )
  2067. goto Exit;
  2068. //
  2069. // Find the actual file name by looking backwards from the end of
  2070. // the string.
  2071. //
  2072. ptszFileNameBit = _tcsrchr( tchLocalExpandedPath, TEXT('\\') );
  2073. if(ptszFileNameBit == NULL){
  2074. ptszFileNameBit = _tcsrchr( tchLocalExpandedPath, TEXT('/') );
  2075. }
  2076. //
  2077. // Form up this buffer containing the details Texmode will want.
  2078. // If there's no filenamebit, use the full path name. Textmode
  2079. // will likely fail to find the file, but Nothing Bad will happen.
  2080. // If the version is missing (strange....) then use a blank string
  2081. // to avoid upsetting textmode.
  2082. //
  2083. #pragma prefast(suppress:53, the result of _snprintf is tested)
  2084. if(_snprintf(
  2085. Buffer,
  2086. ARRAYSIZE(Buffer),
  2087. #ifdef UNICODE
  2088. "\"%ls\" = \"%ls\",\"%ls\"\r\n",
  2089. #else
  2090. "\"%s\" = \"%s\",\"%s\"\r\n",
  2091. #endif
  2092. ptszFileNameBit ? ptszFileNameBit + 1 : tchLocalExpandedPath,
  2093. CompData->FileVer ? CompData->FileVer : TEXT(""),
  2094. tchLocalExpandedPath) < 0){
  2095. Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
  2096. MYASSERT(FALSE);
  2097. }
  2098. //
  2099. // Spit the buffer (in ansi chars, no less) into the file.
  2100. //
  2101. if (!WriteFile(hTargetFile, Buffer, strlen(Buffer), &Bytes, NULL ))
  2102. goto Exit;
  2103. }
  2104. }
  2105. }
  2106. Result = TRUE;
  2107. Exit:
  2108. return Result;
  2109. }
  2110. #ifdef UNICODE
  2111. BOOL
  2112. pIsOEMService (
  2113. IN PCTSTR ServiceKeyName,
  2114. OUT PTSTR OemInfPath, OPTIONAL
  2115. IN INT BufferSize OPTIONAL
  2116. );
  2117. //This function is defined in unsupdrv.c
  2118. #endif
  2119. BOOL
  2120. WriteCompatibilityData(
  2121. IN LPCTSTR FileName
  2122. )
  2123. {
  2124. TCHAR Text[MAX_PATH*2];
  2125. PLIST_ENTRY Next;
  2126. PCOMPATIBILITY_DATA CompData;
  2127. HANDLE hFile;
  2128. CHAR Buffer[MAX_PATH*2];
  2129. DWORD Bytes;
  2130. PSTRINGLIST listServices = NULL, p;
  2131. PCTSTR serviceName;
  2132. BOOL b = FALSE;
  2133. if (CompatibilityCount == 0) {
  2134. return FALSE;
  2135. }
  2136. hFile = CreateFile(
  2137. FileName,
  2138. GENERIC_WRITE,
  2139. FILE_SHARE_READ,
  2140. NULL,
  2141. OPEN_EXISTING,
  2142. FILE_ATTRIBUTE_NORMAL,
  2143. NULL
  2144. );
  2145. if(hFile == INVALID_HANDLE_VALUE) {
  2146. return FALSE;
  2147. }
  2148. __try {
  2149. SetFilePointer(hFile, 0, 0, FILE_END);
  2150. #pragma prefast(suppress:53, the result of _snprintf is tested)
  2151. if(_snprintf(Buffer, ARRAYSIZE(Buffer), "\r\n[%s]\r\n", WINNT_COMPATIBILITY_A) < 0){
  2152. Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
  2153. MYASSERT(FALSE);
  2154. }
  2155. WriteFile(hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL);
  2156. Next = CompatibilityData.Flink;
  2157. if (Next) {
  2158. while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
  2159. CompData = CONTAINING_RECORD( Next, COMPATIBILITY_DATA, ListEntry );
  2160. Next = CompData->ListEntry.Flink;
  2161. if( !( ProcessLine( CompData->Flags) ))
  2162. continue;
  2163. if (CompData->RegKeyName) {
  2164. if (CompData->RegValDataSize == sizeof(DWORD)) {
  2165. if(_sntprintf(Text,
  2166. ARRAYSIZE(Text),
  2167. TEXT("HKLM,\"%s\",\"%s\",0x%08x,%d\r\n"),
  2168. CompData->RegKeyName, CompData->RegValName,
  2169. FLG_ADDREG_TYPE_DWORD,
  2170. *(LPDWORD)CompData->RegValData) < 0){
  2171. Text[ARRAYSIZE(Text) - 1] = '\0';
  2172. MYASSERT(FALSE);
  2173. }
  2174. if (*(LPDWORD)CompData->RegValData == SERVICE_DISABLED) {
  2175. //
  2176. // also record this as a service to be disabled
  2177. // for additional service-specific processing during textmode setup
  2178. //
  2179. serviceName = _tcsrchr (CompData->RegKeyName, TEXT('\\'));
  2180. if (!serviceName) {
  2181. SetLastError (ERROR_INVALID_DATA);
  2182. __leave;
  2183. }
  2184. if (!InsertList (
  2185. (PGENERIC_LIST*)&listServices,
  2186. (PGENERIC_LIST)CreateStringCell (serviceName + 1)
  2187. )) {
  2188. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  2189. __leave;
  2190. }
  2191. }
  2192. } else {
  2193. if(_sntprintf(Text,
  2194. ARRAYSIZE(Text),
  2195. TEXT("HKLM,\"%s\",\"%s\",0x%08x,\"%s\"\r\n"),
  2196. CompData->RegKeyName,
  2197. CompData->RegValName,
  2198. FLG_ADDREG_TYPE_SZ,
  2199. (LPTSTR)CompData->RegValData) < 0){
  2200. Text[ARRAYSIZE(Text) - 1] = '\0';
  2201. MYASSERT(FALSE);
  2202. }
  2203. }
  2204. #ifdef UNICODE
  2205. WideCharToMultiByte(
  2206. CP_ACP,
  2207. 0,
  2208. Text,
  2209. -1,
  2210. Buffer,
  2211. sizeof(Buffer),
  2212. NULL,
  2213. NULL
  2214. );
  2215. if (!WriteFile( hFile, Buffer, strlen(Buffer), &Bytes, NULL )) {
  2216. __leave;
  2217. }
  2218. #else
  2219. if (!WriteFile( hFile, Text, strlen(Text), &Bytes, NULL )) {
  2220. __leave;
  2221. }
  2222. #endif
  2223. }
  2224. }
  2225. }
  2226. if (listServices) {
  2227. #pragma prefast(suppress:53, the result of _snprintf is tested)
  2228. if(_snprintf(Buffer, ARRAYSIZE(Buffer), "\r\n[%s]\r\n", WINNT_SERVICESTODISABLE_A) < 0){
  2229. Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
  2230. MYASSERT(FALSE);
  2231. }
  2232. if (!WriteFile (hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL)) {
  2233. __leave;
  2234. }
  2235. for (p = listServices; p; p = p->Next) {
  2236. #pragma prefast(suppress:53, the result of _snprintf is tested)
  2237. if(_snprintf(Buffer,
  2238. ARRAYSIZE(Buffer),
  2239. #ifdef UNICODE
  2240. "\"%ls\"\r\n",
  2241. #else
  2242. "\"%s\"\r\n",
  2243. #endif
  2244. p->String) < 0){
  2245. Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
  2246. MYASSERT(FALSE);
  2247. }
  2248. if (!WriteFile (hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL)) {
  2249. __leave;
  2250. }
  2251. }
  2252. }
  2253. #ifdef UNICODE
  2254. //////////////////////////////////////////////////
  2255. Next = CompatibilityData.Flink;
  2256. if (Next) {
  2257. while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
  2258. CompData = CONTAINING_RECORD( Next, COMPATIBILITY_DATA, ListEntry );
  2259. Next = CompData->ListEntry.Flink;
  2260. if( !( ProcessLine( CompData->Flags) ))
  2261. continue;
  2262. if (CompData->ServiceName
  2263. && (CompData->Flags & COMPFLAG_DELETE_INF))
  2264. {
  2265. TCHAR oemInfFileName[MAX_PATH];
  2266. if (pIsOEMService(CompData->ServiceName, oemInfFileName, ARRAYSIZE(oemInfFileName)))
  2267. {
  2268. //
  2269. // Write the following in the answer file
  2270. //
  2271. // note that 17 is the code for %windir%\INF
  2272. //
  2273. /*
  2274. [DelInf.serv]
  2275. Delfiles=DelInfFiles.serv
  2276. [DelInfFiles.serv]
  2277. "oem0.inf"
  2278. [DestinationDirs]
  2279. DelInfFiles.serv= 17
  2280. */
  2281. if(_snprintf(Buffer, ARRAYSIZE(Buffer),
  2282. "\r\n[DelInf.%ls]\r\n"
  2283. "Delfiles=DelInfFiles.%ls\r\n"
  2284. "\r\n[DelInfFiles.%ls]\r\n",
  2285. CompData->ServiceName,
  2286. CompData->ServiceName,
  2287. CompData->ServiceName) < 0)
  2288. {
  2289. Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
  2290. MYASSERT(FALSE);
  2291. continue;
  2292. }
  2293. if (!WriteFile (hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL)) {
  2294. __leave;
  2295. }
  2296. if(_snprintf(Buffer, ARRAYSIZE(Buffer),
  2297. "\"%ls\"\r\n"
  2298. "\r\n[DestinationDirs]\r\n"
  2299. "DelInfFiles.%ls= 17\r\n",
  2300. oemInfFileName,
  2301. CompData->ServiceName) < 0)
  2302. {
  2303. Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
  2304. MYASSERT(FALSE);
  2305. continue;
  2306. }
  2307. if (!WriteFile (hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL)) {
  2308. __leave;
  2309. }
  2310. }
  2311. }
  2312. }
  2313. }
  2314. //////////////////////////////////////////////////
  2315. #endif
  2316. if ( !WriteTextmodeReplaceData(hFile) )
  2317. __leave;
  2318. b = TRUE;
  2319. }
  2320. __finally {
  2321. DWORD rc = GetLastError ();
  2322. CloseHandle( hFile );
  2323. if (listServices) {
  2324. DeleteStringList (listServices);
  2325. }
  2326. SetLastError (rc);
  2327. }
  2328. return b;
  2329. }
  2330. BOOL
  2331. pIsValidService (
  2332. IN PCTSTR ServiceName
  2333. )
  2334. {
  2335. TCHAR KeyName[MAX_PATH];
  2336. HKEY key;
  2337. DWORD rc;
  2338. BOOL b = FALSE;
  2339. BuildPath (KeyName, TEXT("SYSTEM\\CurrentControlSet\\Services"), ServiceName);
  2340. //
  2341. // get an open key to the services database
  2342. //
  2343. rc = RegOpenKeyEx(
  2344. HKEY_LOCAL_MACHINE,
  2345. KeyName,
  2346. 0,
  2347. KEY_READ,
  2348. &key
  2349. );
  2350. if (rc == ERROR_SUCCESS) {
  2351. b = TRUE;
  2352. RegCloseKey (key);
  2353. }
  2354. return b;
  2355. }
  2356. BOOL
  2357. WriteTextmodeClobberData (
  2358. IN LPCTSTR FileName
  2359. )
  2360. {
  2361. HANDLE hFile;
  2362. CHAR Buffer[50];
  2363. DWORD LineCount, Bytes;
  2364. TCHAR keyGuid[200];
  2365. PCTSTR guidClass;
  2366. PSTRINGLIST listServices = NULL;
  2367. PSTRINGLIST listLines = NULL;
  2368. PSTRINGLIST e;
  2369. PCTSTR service;
  2370. PTSTR upperFilters = NULL;
  2371. PTSTR upperFiltersNew = NULL;
  2372. PTSTR lowerFilters = NULL;
  2373. PTSTR lowerFiltersNew = NULL;
  2374. PTSTR line;
  2375. HKEY key;
  2376. INT i, j;
  2377. PTSTR p, q;
  2378. PSTR ansi = NULL;
  2379. DWORD rc, size, type;
  2380. BOOL modified, found;
  2381. BOOL b = FALSE;
  2382. #define S_SECTION_CHECKCLASSFILTERS TEXT("CheckClassFilters")
  2383. MYASSERT (NtcompatInf);
  2384. LineCount = InfGetSectionLineCount (NtcompatInf, S_SECTION_CHECKCLASSFILTERS);
  2385. if (LineCount == 0 || LineCount == 0xffffffff) {
  2386. return TRUE;
  2387. }
  2388. __try {
  2389. //
  2390. // first check if any data needs to be written
  2391. //
  2392. for (i = 0; i < (INT)LineCount; i++) {
  2393. guidClass = InfGetFieldByIndex (NtcompatInf, S_SECTION_CHECKCLASSFILTERS, i, 0);
  2394. if (guidClass == NULL) {
  2395. MYASSERT (FALSE);
  2396. continue;
  2397. }
  2398. BuildPath (keyGuid, TEXT("SYSTEM\\CurrentControlSet\\Control\\Class"), guidClass);
  2399. rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE, keyGuid, 0, KEY_READ, &key);
  2400. if (rc != ERROR_SUCCESS) {
  2401. continue;
  2402. }
  2403. upperFilters = NULL;
  2404. rc = RegQueryValueEx (key, TEXT("UpperFilters"), NULL, &type, NULL, &size);
  2405. if (rc == ERROR_SUCCESS && type == REG_MULTI_SZ) {
  2406. MYASSERT (size >= 2);
  2407. upperFilters = MALLOC (size);
  2408. upperFiltersNew = MALLOC (size * 2);
  2409. if (!upperFilters || !upperFiltersNew) {
  2410. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  2411. __leave;
  2412. }
  2413. rc = RegQueryValueEx (key, TEXT("UpperFilters"), NULL, NULL, (LPBYTE)upperFilters, &size);
  2414. if (rc != ERROR_SUCCESS) {
  2415. FREE (upperFilters);
  2416. upperFilters = NULL;
  2417. FREE (upperFiltersNew);
  2418. upperFiltersNew = NULL;
  2419. }
  2420. }
  2421. lowerFilters = NULL;
  2422. rc = RegQueryValueEx (key, TEXT("LowerFilters"), NULL, &type, NULL, &size);
  2423. if (rc == ERROR_SUCCESS && type == REG_MULTI_SZ) {
  2424. MYASSERT (size >= 2);
  2425. lowerFilters = MALLOC (size);
  2426. lowerFiltersNew = MALLOC (size * 2);
  2427. if (!lowerFilters || !lowerFiltersNew) {
  2428. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  2429. __leave;
  2430. }
  2431. rc = RegQueryValueEx (key, TEXT("LowerFilters"), NULL, NULL, (LPBYTE)lowerFilters, &size);
  2432. if (rc != ERROR_SUCCESS) {
  2433. FREE (lowerFilters);
  2434. lowerFilters = NULL;
  2435. FREE (lowerFiltersNew);
  2436. lowerFiltersNew = NULL;
  2437. }
  2438. }
  2439. RegCloseKey (key);
  2440. if (!(upperFilters || lowerFilters)) {
  2441. continue;
  2442. }
  2443. j = 1;
  2444. do {
  2445. service = InfGetFieldByIndex (NtcompatInf, S_SECTION_CHECKCLASSFILTERS, i, j++);
  2446. if (service && *service) {
  2447. if (!InsertList (
  2448. (PGENERIC_LIST*)&listServices,
  2449. (PGENERIC_LIST)CreateStringCell (service)
  2450. )) {
  2451. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  2452. __leave;
  2453. }
  2454. }
  2455. } while (service);
  2456. if (upperFilters) {
  2457. modified = FALSE;
  2458. *upperFiltersNew = 0;
  2459. for (p = upperFilters, q = upperFiltersNew; *p; p = _tcschr (p, 0) + 1) {
  2460. if (listServices) {
  2461. found = FindStringCell (listServices, p, FALSE);
  2462. } else {
  2463. found = !pIsValidService (p);
  2464. }
  2465. if (found) {
  2466. DebugLog (
  2467. Winnt32LogInformation,
  2468. TEXT("NTCOMPAT: Removing \"%1\" from %2 of %3"),
  2469. 0,
  2470. p,
  2471. TEXT("UpperFilters"),
  2472. guidClass
  2473. );
  2474. modified = TRUE;
  2475. } else {
  2476. q = q + wsprintf (q, TEXT(",\"%s\""), p);
  2477. }
  2478. }
  2479. if (modified) {
  2480. //
  2481. // tell textmode setup to overwrite this value
  2482. //
  2483. line = MALLOC (
  2484. sizeof (TCHAR) *
  2485. (1 +
  2486. sizeof(TEXT("HKLM,\"%s\",\"%s\",0x%08x%s\r\n")) - 1 +
  2487. lstrlen (keyGuid) +
  2488. sizeof (TEXT("UpperFilters")) - 1 +
  2489. 2 + 8 +
  2490. lstrlen (upperFiltersNew)));
  2491. if (!line) {
  2492. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  2493. __leave;
  2494. }
  2495. wsprintf (
  2496. line,
  2497. TEXT("HKLM,\"%s\",\"%s\",0x%08x%s\r\n"),
  2498. keyGuid,
  2499. TEXT("UpperFilters"),
  2500. FLG_ADDREG_TYPE_MULTI_SZ,
  2501. upperFiltersNew
  2502. );
  2503. if (!InsertList (
  2504. (PGENERIC_LIST*)&listLines,
  2505. (PGENERIC_LIST)CreateStringCell (line)
  2506. )) {
  2507. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  2508. __leave;
  2509. }
  2510. FREE (line);
  2511. line = NULL;
  2512. }
  2513. }
  2514. if (lowerFilters) {
  2515. modified = FALSE;
  2516. *lowerFiltersNew = 0;
  2517. for (p = lowerFilters, q = lowerFiltersNew; *p; p = _tcschr (p, 0) + 1) {
  2518. if (listServices) {
  2519. found = FindStringCell (listServices, p, FALSE);
  2520. } else {
  2521. found = !pIsValidService (p);
  2522. }
  2523. if (found) {
  2524. DebugLog (
  2525. Winnt32LogInformation,
  2526. TEXT("NTCOMPAT: Removing \"%1\" from %2 of %3"),
  2527. 0,
  2528. p,
  2529. TEXT("LowerFilters"),
  2530. guidClass
  2531. );
  2532. modified = TRUE;
  2533. } else {
  2534. q = q + wsprintf (q, TEXT(",\"%s\""), p);
  2535. }
  2536. }
  2537. if (modified) {
  2538. //
  2539. // tell textmode setup to overwrite this value
  2540. //
  2541. line = MALLOC (
  2542. sizeof (TCHAR) *
  2543. (1 +
  2544. sizeof(TEXT("HKLM,\"%s\",\"%s\",0x%08x%s\r\n")) - 1 +
  2545. lstrlen (keyGuid) +
  2546. sizeof (TEXT("LowerFilters")) - 1 +
  2547. 2 + 8 +
  2548. lstrlen (lowerFiltersNew)));
  2549. if (!line) {
  2550. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  2551. __leave;
  2552. }
  2553. wsprintf (
  2554. line,
  2555. TEXT("HKLM,\"%s\",\"%s\",0x%08x%s\r\n"),
  2556. keyGuid,
  2557. TEXT("LowerFilters"),
  2558. FLG_ADDREG_TYPE_MULTI_SZ,
  2559. lowerFiltersNew
  2560. );
  2561. if (!InsertList (
  2562. (PGENERIC_LIST*)&listLines,
  2563. (PGENERIC_LIST)CreateStringCell (line)
  2564. )) {
  2565. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  2566. __leave;
  2567. }
  2568. FREE (line);
  2569. line = NULL;
  2570. }
  2571. }
  2572. if (listServices) {
  2573. DeleteStringList (listServices);
  2574. listServices = NULL;
  2575. }
  2576. if (upperFilters) {
  2577. FREE (upperFilters);
  2578. upperFilters = NULL;
  2579. }
  2580. if (upperFiltersNew) {
  2581. FREE (upperFiltersNew);
  2582. upperFiltersNew = NULL;
  2583. }
  2584. if (lowerFilters) {
  2585. FREE (lowerFilters);
  2586. lowerFilters = NULL;
  2587. }
  2588. if (lowerFiltersNew) {
  2589. FREE (lowerFiltersNew);
  2590. lowerFiltersNew = NULL;
  2591. }
  2592. }
  2593. b = TRUE;
  2594. }
  2595. __finally {
  2596. rc = GetLastError ();
  2597. if (listServices) {
  2598. DeleteStringList (listServices);
  2599. }
  2600. if (upperFilters) {
  2601. FREE (upperFilters);
  2602. }
  2603. if (upperFiltersNew) {
  2604. FREE (upperFiltersNew);
  2605. }
  2606. if (lowerFilters) {
  2607. FREE (lowerFilters);
  2608. }
  2609. if (lowerFiltersNew) {
  2610. FREE (lowerFiltersNew);
  2611. }
  2612. if (!b) {
  2613. if (listLines) {
  2614. DeleteStringList (listLines);
  2615. listLines = NULL;
  2616. }
  2617. }
  2618. SetLastError (rc);
  2619. }
  2620. if (listLines) {
  2621. b = FALSE;
  2622. __try {
  2623. hFile = CreateFile(
  2624. FileName,
  2625. GENERIC_WRITE,
  2626. FILE_SHARE_READ,
  2627. NULL,
  2628. OPEN_EXISTING,
  2629. FILE_ATTRIBUTE_NORMAL,
  2630. NULL
  2631. );
  2632. if (hFile == INVALID_HANDLE_VALUE) {
  2633. __leave;
  2634. }
  2635. SetFilePointer (hFile, 0, 0, FILE_END);
  2636. #pragma prefast(suppress:53, the result of _snprintf is tested)
  2637. if(_snprintf(Buffer, ARRAYSIZE(Buffer), "\r\n[%s]\r\n", WINNT_COMPATIBILITY_A)){
  2638. Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
  2639. MYASSERT(FALSE);
  2640. }
  2641. if (!WriteFile (hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL)) {
  2642. __leave;
  2643. }
  2644. for (e = listLines; e; e = e->Next) {
  2645. #ifdef UNICODE
  2646. ansi = MALLOC ((lstrlen (e->String) + 1) * 2);
  2647. if (!ansi) {
  2648. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  2649. __leave;
  2650. }
  2651. if (!WideCharToMultiByte (
  2652. CP_ACP,
  2653. 0,
  2654. e->String,
  2655. -1,
  2656. ansi,
  2657. (lstrlen (e->String) + 1) * 2,
  2658. NULL,
  2659. NULL
  2660. )) {
  2661. __leave;
  2662. }
  2663. if (!WriteFile (hFile, (LPBYTE)ansi, strlen(ansi), &Bytes, NULL)) {
  2664. __leave;
  2665. }
  2666. FREE (ansi);
  2667. ansi = NULL;
  2668. #else
  2669. if (!WriteFile (hFile, (LPBYTE)e->String, strlen(e->String), &Bytes, NULL)) {
  2670. __leave;
  2671. }
  2672. #endif
  2673. }
  2674. b = TRUE;
  2675. }
  2676. __finally {
  2677. DWORD rc = GetLastError ();
  2678. if (hFile != INVALID_HANDLE_VALUE) {
  2679. CloseHandle (hFile);
  2680. }
  2681. if (ansi) {
  2682. FREE (ansi);
  2683. }
  2684. DeleteStringList (listLines);
  2685. SetLastError (rc);
  2686. }
  2687. }
  2688. return b;
  2689. }
  2690. BOOL
  2691. SaveCompatibilityData(
  2692. IN LPCTSTR FileName,
  2693. IN BOOL IncludeHiddenItems
  2694. )
  2695. /*++
  2696. Routine Description:
  2697. We call this function when the user has asked us to save the
  2698. contents of the Compatibility page to a file.
  2699. Arguments:
  2700. FileName - supplies filename of file to be used for our output.
  2701. IncludeHiddenItems - if set, hidden items are also saved
  2702. Return Value:
  2703. Boolean value indicating whether we succeeded.
  2704. --*/
  2705. {
  2706. #define WRITE_TEXT( s ) if(!WriteFile(hFile, s, lstrlenA(s), &Written, NULL)){MYASSERT(FALSE);}
  2707. HANDLE hFile;
  2708. CHAR AnsiMessage[5000];
  2709. DWORD Written;
  2710. PLIST_ENTRY Next;
  2711. PCOMPATIBILITY_DATA CompData;
  2712. DWORD i;
  2713. TCHAR FullPath[MAX_PATH+8], *t;
  2714. PVOID textDescription;
  2715. BOOL bUnicode;
  2716. BOOL bEmpty = TRUE;
  2717. //
  2718. // Open the file. NOTE THAT WE DON'T APPEND.
  2719. //
  2720. hFile = CreateFile( FileName,
  2721. GENERIC_WRITE,
  2722. FILE_SHARE_READ,
  2723. NULL,
  2724. CREATE_ALWAYS,
  2725. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  2726. NULL );
  2727. if(hFile == INVALID_HANDLE_VALUE) {
  2728. return FALSE;
  2729. }
  2730. //
  2731. // Header...
  2732. //
  2733. WRITE_TEXT( "\r\n********************************************************************\r\n\r\n" );
  2734. if(!LoadStringA(hInst, IDS_COMPAT_REPORTHEADER, AnsiMessage, ARRAYSIZE(AnsiMessage))){
  2735. WRITE_TEXT( "Report Header" );
  2736. }
  2737. else{
  2738. WRITE_TEXT( AnsiMessage );
  2739. }
  2740. WRITE_TEXT( "\r\n\r\n********************************************************************\r\n\r\n" );
  2741. //
  2742. // Body...
  2743. //
  2744. Next = CompatibilityData.Flink;
  2745. if (Next) {
  2746. while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
  2747. CompData = CONTAINING_RECORD( Next, COMPATIBILITY_DATA, ListEntry );
  2748. Next = CompData->ListEntry.Flink;
  2749. if( CompData->Flags & COMPFLAG_HIDE )
  2750. continue;
  2751. if( !ProcessLine(CompData->Flags))
  2752. continue;
  2753. //
  2754. // Convert the description to ANSI and write it.
  2755. //
  2756. #ifdef UNICODE
  2757. WideCharToMultiByte( CP_ACP,
  2758. 0,
  2759. CompData->Description,
  2760. -1,
  2761. AnsiMessage,
  2762. sizeof(AnsiMessage) - 2 * sizeof(AnsiMessage[0])/*\r\n*/,
  2763. NULL,
  2764. NULL );
  2765. #else
  2766. lstrcpyn(AnsiMessage, CompData->Description, ARRAYSIZE(AnsiMessage) - 2/*\r\n*/);
  2767. #endif
  2768. strcat( AnsiMessage, "\r\n" );
  2769. WriteFile( hFile, AnsiMessage, lstrlenA(AnsiMessage), &Written, NULL );
  2770. //
  2771. // Underline the description.
  2772. //
  2773. Written = strlen( AnsiMessage );
  2774. if(Written >= (ARRAYSIZE(AnsiMessage) - 2/*\r\n*/)){
  2775. Written = ARRAYSIZE(AnsiMessage) - 3/*\r\n\0*/;
  2776. }
  2777. AnsiMessage[0] = 0;
  2778. for( i = 0; i < (Written - 2); i++ ) {
  2779. strcat( AnsiMessage, "=" );
  2780. }
  2781. strcat( AnsiMessage, "\r\n\r\n" );
  2782. WriteFile( hFile, AnsiMessage, lstrlenA(AnsiMessage), &Written, NULL );
  2783. //
  2784. // Append the text file that this entry points to.
  2785. //
  2786. if (pGetText (CompData->TextName, &textDescription, &bUnicode)) {
  2787. if (bUnicode) {
  2788. #ifdef UNICODE
  2789. WideCharToMultiByte( CP_ACP,
  2790. 0,
  2791. textDescription,
  2792. -1,
  2793. AnsiMessage,
  2794. sizeof(AnsiMessage),
  2795. NULL,
  2796. NULL );
  2797. #else
  2798. lstrcpyn(AnsiMessage, textDescription, ARRAYSIZE(AnsiMessage));
  2799. #endif
  2800. WriteFile (hFile, AnsiMessage, lstrlenA (AnsiMessage), &Written, NULL );
  2801. } else {
  2802. WriteFile (hFile, textDescription, lstrlenA (textDescription), &Written, NULL );
  2803. }
  2804. FREE (textDescription);
  2805. }
  2806. //
  2807. // Buffer space...
  2808. //
  2809. WRITE_TEXT( "\r\n\r\n\r\n" );
  2810. bEmpty = FALSE;
  2811. }
  2812. }
  2813. if (IncludeHiddenItems) {
  2814. //
  2815. // Hidden Items Header...
  2816. //
  2817. //
  2818. // Body...
  2819. //
  2820. Next = CompatibilityData.Flink;
  2821. if (Next) {
  2822. BOOL bFirst = TRUE;
  2823. while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
  2824. CompData = CONTAINING_RECORD( Next, COMPATIBILITY_DATA, ListEntry );
  2825. Next = CompData->ListEntry.Flink;
  2826. if (!(CompData->Flags & COMPFLAG_HIDE ))
  2827. continue;
  2828. if( !ProcessLine(CompData->Flags))
  2829. continue;
  2830. if (bFirst) {
  2831. WRITE_TEXT( "\r\n--------------------------------------------------------------------\r\n\r\n" );
  2832. bFirst = FALSE;
  2833. }
  2834. //
  2835. // Convert the description to ANSI and write it.
  2836. //
  2837. #ifdef UNICODE
  2838. WideCharToMultiByte( CP_ACP,
  2839. 0,
  2840. CompData->Description,
  2841. -1,
  2842. AnsiMessage,
  2843. sizeof(AnsiMessage) - 2 * sizeof(AnsiMessage[0])/*\r\n*/,
  2844. NULL,
  2845. NULL );
  2846. #else
  2847. lstrcpyn(AnsiMessage, CompData->Description, ARRAYSIZE(AnsiMessage) - 2/*\r\n*/);
  2848. #endif
  2849. strcat( AnsiMessage, "\r\n" );
  2850. WriteFile( hFile, AnsiMessage, lstrlenA(AnsiMessage), &Written, NULL );
  2851. //
  2852. // Underline the description.
  2853. //
  2854. Written = strlen( AnsiMessage );
  2855. if(Written >= (ARRAYSIZE(AnsiMessage) - 2/*\r\n*/)){
  2856. Written = ARRAYSIZE(AnsiMessage) - 3/*\r\n\0*/;
  2857. }
  2858. AnsiMessage[0] = 0;
  2859. for( i = 0; i < (Written - 2); i++ ) {
  2860. strcat( AnsiMessage, "=" );
  2861. }
  2862. strcat( AnsiMessage, "\r\n\r\n" );
  2863. WriteFile( hFile, AnsiMessage, lstrlenA(AnsiMessage), &Written, NULL );
  2864. //
  2865. // Append the text file that this entry points to.
  2866. //
  2867. if( (CompData->TextName) && *(CompData->TextName) ) {
  2868. if (FindPathToWinnt32File (CompData->TextName, FullPath, MAX_PATH)) {
  2869. ConcatenateFile( hFile, FullPath );
  2870. } else {
  2871. DebugLog (Winnt32LogError,
  2872. TEXT("Compatibility data file \"%1\" not found"),
  2873. 0,
  2874. CompData->TextName
  2875. );
  2876. }
  2877. }
  2878. //
  2879. // Buffer space...
  2880. //
  2881. WRITE_TEXT( "\r\n\r\n\r\n" );
  2882. bEmpty = FALSE;
  2883. }
  2884. }
  2885. }
  2886. if (bEmpty) {
  2887. if (LoadStringA (hInst, IDS_COMPAT_NOPROBLEMS, AnsiMessage, ARRAYSIZE(AnsiMessage) - 2/*\r\n*/)) {
  2888. strcat (AnsiMessage, "\r\n");
  2889. WriteFile (hFile, AnsiMessage, lstrlenA(AnsiMessage), &Written, NULL);
  2890. }
  2891. else{
  2892. MYASSERT(FALSE);
  2893. }
  2894. }
  2895. CloseHandle( hFile );
  2896. return TRUE;
  2897. }
  2898. VOID
  2899. WriteGUIModeInfOperations(
  2900. IN LPCTSTR FileName
  2901. )
  2902. {
  2903. PLIST_ENTRY Next_Link;
  2904. PCOMPATIBILITY_DATA CompData;
  2905. BOOLEAN FirstTime = TRUE;
  2906. TCHAR Text[MAX_PATH*2];
  2907. TCHAR Temp[MAX_PATH];
  2908. CHAR Buffer[MAX_PATH*2];
  2909. DWORD Bytes;
  2910. HANDLE hFile;
  2911. PCTSTR p;
  2912. hFile = CreateFile(
  2913. FileName,
  2914. GENERIC_WRITE,
  2915. FILE_SHARE_READ,
  2916. NULL,
  2917. OPEN_EXISTING,
  2918. FILE_ATTRIBUTE_NORMAL,
  2919. NULL
  2920. );
  2921. if(hFile == INVALID_HANDLE_VALUE) {
  2922. return;
  2923. }
  2924. SetFilePointer( hFile, 0, 0, FILE_END );
  2925. Next_Link = CompatibilityData.Flink;
  2926. if( Next_Link ){
  2927. while ((ULONG_PTR)Next_Link != (ULONG_PTR)&CompatibilityData) {
  2928. CompData = CONTAINING_RECORD( Next_Link, COMPATIBILITY_DATA, ListEntry );
  2929. Next_Link = CompData->ListEntry.Flink;
  2930. if( FirstTime ){
  2931. #pragma prefast(suppress:53, the result of _snprintf is tested)
  2932. if(_snprintf(Buffer,
  2933. ARRAYSIZE(Buffer),
  2934. "[%s]\r\n",
  2935. WINNT_COMPATIBILITYINFSECTION_A) < 0){
  2936. Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
  2937. MYASSERT(FALSE);
  2938. }
  2939. WriteFile( hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL );
  2940. FirstTime = FALSE;
  2941. }
  2942. if(CompData->InfName && CompData->InfSection && *CompData->InfName && *CompData->InfSection){
  2943. //Add the information for GUI setup.
  2944. #if defined(_AMD64_) || defined(_X86_)
  2945. lstrcpyn(Temp, LocalBootDirectory, ARRAYSIZE(Temp));
  2946. #else
  2947. lstrcpyn(Temp, LocalSourceWithPlatform, ARRAYSIZE(Temp));
  2948. #endif
  2949. p = _tcsrchr (CompData->InfName, TEXT('\\'));
  2950. if (p) {
  2951. p++;
  2952. } else {
  2953. p = CompData->InfName;
  2954. }
  2955. if(!ConcatenatePaths(Temp, p, MAX_PATH)){
  2956. MYASSERT(FALSE);
  2957. }
  2958. if(_sntprintf(Text,
  2959. ARRAYSIZE(Text),
  2960. TEXT("%s,%s\r\n"),
  2961. Temp,
  2962. CompData->InfSection) < 0){
  2963. Text[ARRAYSIZE(Text) - 1] = '\0';
  2964. MYASSERT(FALSE);
  2965. }
  2966. #ifdef UNICODE
  2967. WideCharToMultiByte(
  2968. CP_ACP,
  2969. 0,
  2970. Text,
  2971. -1,
  2972. Buffer,
  2973. sizeof(Buffer),
  2974. NULL,
  2975. NULL
  2976. );
  2977. WriteFile( hFile, Buffer, strlen(Buffer), &Bytes, NULL );
  2978. #else
  2979. WriteFile( hFile, Text, strlen(Text), &Bytes, NULL );
  2980. #endif
  2981. }
  2982. #ifdef UNICODE
  2983. if (CompData->ServiceName
  2984. && (CompData->Flags & COMPFLAG_DELETE_INF))
  2985. {
  2986. TCHAR oemInfFileName[MAX_PATH];
  2987. if (pIsOEMService(CompData->ServiceName, oemInfFileName, ARRAYSIZE(oemInfFileName)))
  2988. {
  2989. if(_snprintf(Buffer, ARRAYSIZE(Buffer),
  2990. "%ls, DelInf.%ls\r\n",
  2991. WINNT_GUI_FILE_W,
  2992. CompData->ServiceName) < 0)
  2993. {
  2994. Buffer[ARRAYSIZE(Buffer) - 1] = '\0';
  2995. MYASSERT(FALSE);
  2996. continue;
  2997. }
  2998. if (!WriteFile (hFile, (LPBYTE)Buffer, strlen(Buffer), &Bytes, NULL)) {
  2999. MYASSERT(FALSE);
  3000. continue;
  3001. }
  3002. }
  3003. }
  3004. #endif
  3005. }
  3006. }
  3007. CloseHandle( hFile );
  3008. return;
  3009. }
  3010. BOOL
  3011. IsIE4Installed(
  3012. VOID
  3013. );
  3014. BOOL
  3015. IsIE3Installed(
  3016. VOID
  3017. );
  3018. #if 0
  3019. BOOL
  3020. ServerWizPage(
  3021. IN HWND hdlg,
  3022. IN UINT msg,
  3023. IN WPARAM wParam,
  3024. IN LPARAM lParam
  3025. )
  3026. {
  3027. /*++
  3028. Routine Description:
  3029. This routine notifies the user about the existance of the
  3030. ever-so-official-sounding "Directory of Applications for Windows 2000".
  3031. Note that we'll only run this page on server installs/upgrades.
  3032. Arguments:
  3033. --*/
  3034. TCHAR FullPath[1024];
  3035. LPWSTR Url;
  3036. DWORD i;
  3037. BOOL b;
  3038. switch(msg) {
  3039. case WM_INITDIALOG:
  3040. //
  3041. // Nothing to do here.
  3042. //
  3043. b = FALSE;
  3044. break;
  3045. case WMX_ACTIVATEPAGE:
  3046. if (Winnt32Restarted ()) {
  3047. return FALSE;
  3048. }
  3049. //
  3050. // We're going to skip this page if we're installing
  3051. // a PROFESSIONAL product.
  3052. //
  3053. if( !Server ) {
  3054. return FALSE;
  3055. }
  3056. //
  3057. // Don't do this if we're on OSR2 because it
  3058. // will AV sometimes when we fire IE3 w/o an internet
  3059. // connection.
  3060. //
  3061. if( !ISNT() ) {
  3062. return FALSE;
  3063. }
  3064. //
  3065. // If we don't have IE, skip this page.
  3066. //
  3067. b = (IsIE4Installed() || IsIE3Installed());
  3068. SetForegroundWindow(hdlg);
  3069. if( !b ) {
  3070. return FALSE;
  3071. }
  3072. b = TRUE;
  3073. //
  3074. // If we're unattended, skip this page.
  3075. //
  3076. if( UnattendedOperation ) {
  3077. return FALSE;
  3078. }
  3079. if(wParam) {
  3080. }
  3081. b = TRUE;
  3082. // Stop the bill board and show the wizard again.
  3083. SendMessage(GetParent (hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  3084. break;
  3085. case WM_COMMAND:
  3086. if ((LOWORD(wParam) == IDC_DIRECTORY) && (HIWORD(wParam) == BN_CLICKED)) {
  3087. //
  3088. // The user wants to go look at the directory.
  3089. // Fire IE.
  3090. //
  3091. //
  3092. // Depending on which flavor we're upgrading to, we need
  3093. // to go to a different page.
  3094. //
  3095. b = TRUE; // silence PREfix. Not relevant, but presumably,
  3096. // if the directory is being opened, it must exist.
  3097. // So we return TRUE.
  3098. if( Server ) {
  3099. if(!LoadString(hInst, IDS_SRV_APP_DIRECTORY, FullPath, ARRAYSIZE(FullPath))){
  3100. MYASSERT(FALSE);
  3101. break;
  3102. }
  3103. } else {
  3104. if(!LoadString(hInst, IDS_PRO_APP_DIRECTORY, FullPath, ARRAYSIZE(FullPath))){
  3105. MYASSERT(FALSE);
  3106. break;
  3107. }
  3108. }
  3109. i = _tcslen( FullPath );
  3110. Url = (LPWSTR)MALLOC((i + 1/*\0*/) * sizeof(WCHAR));
  3111. if(Url) {
  3112. #ifdef UNICODE
  3113. wcscpy( Url, FullPath );
  3114. #else
  3115. MultiByteToWideChar( CP_ACP, 0, FullPath, -1, Url, i );
  3116. #endif
  3117. if (!LaunchIE4Instance(Url)) {
  3118. if (!LaunchIE3Instance(Url)) {
  3119. //
  3120. // Sniff... the user doesn't have IE
  3121. // on his machine. Quietly move on.
  3122. //
  3123. }
  3124. }
  3125. FREE(Url);
  3126. }
  3127. }
  3128. else
  3129. b = FALSE;
  3130. break;
  3131. case WMX_I_AM_VISIBLE:
  3132. b = TRUE;
  3133. break;
  3134. default:
  3135. b = FALSE;
  3136. break;
  3137. }
  3138. return b;
  3139. }
  3140. #endif
  3141. BOOL
  3142. AnyBlockingCompatibilityItems (
  3143. VOID
  3144. )
  3145. {
  3146. PLIST_ENTRY Next = CompatibilityData.Flink;
  3147. if (Next) {
  3148. while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
  3149. PCOMPATIBILITY_DATA CompData = CONTAINING_RECORD( Next, COMPATIBILITY_DATA, ListEntry );
  3150. Next = CompData->ListEntry.Flink;
  3151. if ((!(CompData->Flags & COMPFLAG_HIDE)) && ProcessLine( CompData->Flags)) {
  3152. if( CompData->Flags & COMPFLAG_STOPINSTALL ) {
  3153. return TRUE;
  3154. }
  3155. }
  3156. }
  3157. }
  3158. return FALSE;
  3159. }
  3160. DWORD
  3161. pGetQFEsInstalled (
  3162. OUT PTSTR* SpQfeList,
  3163. OUT PDWORD StringCount,
  3164. OUT PDWORD TotalStringsLen
  3165. )
  3166. /*++
  3167. Routine Description:
  3168. Gets the list of currently installed ServicePacks/QFEs.
  3169. Arguments:
  3170. SpQfeList - Receives the multi-sz list
  3171. Return Value:
  3172. TRUE if detection was successful, FALSE otherwise
  3173. --*/
  3174. {
  3175. DWORD rc;
  3176. HKEY key, subKey;
  3177. DWORD subkeys, index;
  3178. DWORD maxSubKeyLen;
  3179. DWORD type, installed, size;
  3180. PTSTR list = NULL, crt = NULL;
  3181. DWORD count, len, totalLen;
  3182. *SpQfeList = NULL;
  3183. if (StringCount) {
  3184. *StringCount = 0;
  3185. }
  3186. if (TotalStringsLen) {
  3187. *TotalStringsLen = 0;
  3188. }
  3189. rc = RegOpenKeyEx (
  3190. HKEY_LOCAL_MACHINE,
  3191. TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\HotFix"),
  3192. 0,
  3193. KEY_READ,
  3194. &key
  3195. );
  3196. if (rc != ERROR_SUCCESS) {
  3197. return rc == ERROR_FILE_NOT_FOUND ? ERROR_SUCCESS : rc;
  3198. }
  3199. __try {
  3200. rc = RegQueryInfoKey (
  3201. key,
  3202. NULL,
  3203. NULL,
  3204. NULL,
  3205. &subkeys,
  3206. &maxSubKeyLen,
  3207. NULL,
  3208. NULL,
  3209. NULL,
  3210. NULL,
  3211. NULL,
  3212. NULL
  3213. );
  3214. if (rc != ERROR_SUCCESS) {
  3215. __leave;
  3216. }
  3217. if (subkeys > 0) {
  3218. maxSubKeyLen++;
  3219. list = MALLOC ((subkeys * maxSubKeyLen + 1) * sizeof (TCHAR));
  3220. if (!list) {
  3221. rc = ERROR_NOT_ENOUGH_MEMORY;
  3222. __leave;
  3223. }
  3224. crt = list;
  3225. count = totalLen = 0;
  3226. for (index = 0; index < subkeys; index++) {
  3227. rc = RegEnumKey (key, index, crt, maxSubKeyLen);
  3228. if (rc != ERROR_SUCCESS) {
  3229. break;
  3230. }
  3231. if (_tcsicmp (crt, TEXT("Q147222")) == 0) {
  3232. continue;
  3233. }
  3234. rc = RegOpenKeyEx (
  3235. key,
  3236. crt,
  3237. 0,
  3238. KEY_READ,
  3239. &subKey
  3240. );
  3241. if (rc != ERROR_SUCCESS) {
  3242. __leave;
  3243. }
  3244. size = sizeof (installed);
  3245. rc = RegQueryValueEx (
  3246. subKey,
  3247. TEXT("Installed"),
  3248. NULL,
  3249. &type,
  3250. (LPBYTE)&installed,
  3251. &size
  3252. );
  3253. RegCloseKey (subKey);
  3254. if (rc != ERROR_SUCCESS) {
  3255. __leave;
  3256. }
  3257. if (type != REG_DWORD || !installed) {
  3258. continue;
  3259. }
  3260. len = _tcslen (crt);
  3261. count++;
  3262. totalLen += len;
  3263. crt += len + 1;
  3264. *crt = 0;
  3265. }
  3266. if (rc == ERROR_NO_MORE_ITEMS) {
  3267. rc = ERROR_SUCCESS;
  3268. }
  3269. if (rc == ERROR_SUCCESS) {
  3270. if (totalLen == 0) {
  3271. FREE (list);
  3272. list = NULL;
  3273. }
  3274. }
  3275. }
  3276. }
  3277. __finally {
  3278. if (rc == ERROR_SUCCESS) {
  3279. *SpQfeList = list;
  3280. if (StringCount) {
  3281. *StringCount = count;
  3282. }
  3283. if (TotalStringsLen) {
  3284. *TotalStringsLen = totalLen;
  3285. }
  3286. } else {
  3287. if (list) {
  3288. FREE (list);
  3289. }
  3290. }
  3291. RegCloseKey (key);
  3292. }
  3293. return rc;
  3294. }
  3295. BOOL
  3296. pDumpQfeListToFile (
  3297. IN PCTSTR SPVersion, OPTIONAL
  3298. IN PCTSTR List, OPTIONAL
  3299. IN DWORD Count, OPTIONAL
  3300. IN DWORD TotalLen OPTIONAL
  3301. )
  3302. {
  3303. TCHAR qfeTemplatePath[MAX_PATH];
  3304. TCHAR qfeListPath[MAX_PATH];
  3305. PSTR ansiFile = NULL;
  3306. DWORD size;
  3307. DWORD spSize, qfeListSize;
  3308. PSTR qfeList = NULL;
  3309. PSTR dest, end;
  3310. PCTSTR src, p;
  3311. DWORD len;
  3312. DWORD qfeID;
  3313. DWORD fileSize;
  3314. HANDLE fileHandle;
  3315. HANDLE mappingHandle;
  3316. PVOID baseAddress;
  3317. INT bytes;
  3318. HANDLE handle = INVALID_HANDLE_VALUE;
  3319. DWORD written;
  3320. BOOL b = FALSE;
  3321. if (!FindPathToWinnt32File (S_QFE_TEMPLATE_FILE, qfeTemplatePath, ARRAYSIZE(qfeTemplatePath))) {
  3322. return b;
  3323. }
  3324. if (MapFileForRead (qfeTemplatePath, &fileSize, &fileHandle, &mappingHandle, &baseAddress) != ERROR_SUCCESS) {
  3325. return b;
  3326. }
  3327. __try {
  3328. spSize = SPVersion ? sizeof (S_SP_TEMPLATE) + lstrlen (SPVersion) : 0;
  3329. qfeListSize = Count ? Count * (sizeof (S_QFE_LINK_TEMPLATE) + 10) + TotalLen + 1 : 0;
  3330. size = fileSize + spSize + qfeListSize;
  3331. ansiFile = (PSTR) MALLOC (size);
  3332. if (!ansiFile) {
  3333. __leave;
  3334. }
  3335. qfeList = (PSTR) MALLOC (qfeListSize);
  3336. if (!qfeList) {
  3337. __leave;
  3338. }
  3339. if (List) {
  3340. for (src = List, dest = qfeList; *src; src = _tcschr (src, 0) + 1) {
  3341. for (p = src; !_istdigit ((TCHAR)_tcsnextc (p)); p = _tcsinc (p)) {
  3342. //
  3343. // nothing
  3344. //
  3345. }
  3346. qfeID = _ttol (p);
  3347. #pragma prefast(suppress:53, the result of _snprintf is tested)
  3348. bytes = _snprintf (dest, qfeListSize - (dest - qfeList), S_QFE_LINK_TEMPLATE, qfeID, src);
  3349. if (bytes < 0) {
  3350. __leave;
  3351. }
  3352. dest += bytes;
  3353. }
  3354. }
  3355. dest = ansiFile;
  3356. end = ansiFile + size;
  3357. if (SPVersion) {
  3358. #pragma prefast(suppress:53, the result of _snprintf is tested)
  3359. bytes = _snprintf (dest, end - dest, S_SP_TEMPLATE, SPVersion);
  3360. if (bytes < 0) {
  3361. MYASSERT (FALSE);
  3362. __leave;
  3363. }
  3364. } else {
  3365. bytes = 0;
  3366. }
  3367. dest += bytes;
  3368. if (List) {
  3369. #pragma prefast(suppress:53, the result of _snprintf is tested)
  3370. bytes = _snprintf (dest, end - dest, baseAddress, qfeList);
  3371. if (bytes < 0) {
  3372. MYASSERT (FALSE);
  3373. __leave;
  3374. }
  3375. } else {
  3376. bytes = 0;
  3377. }
  3378. dest += bytes;
  3379. if (!MyGetWindowsDirectory (qfeListPath, ARRAYSIZE(qfeListPath))) {
  3380. __leave;
  3381. }
  3382. ConcatenatePaths (qfeListPath, S_QFE_TARGET_FILENAME, ARRAYSIZE(qfeListPath));
  3383. handle = CreateFile (
  3384. qfeListPath,
  3385. GENERIC_WRITE,
  3386. 0,
  3387. NULL,
  3388. CREATE_ALWAYS,
  3389. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  3390. NULL
  3391. );
  3392. if (handle == INVALID_HANDLE_VALUE) {
  3393. __leave;
  3394. }
  3395. if (!WriteFile (
  3396. handle,
  3397. ansiFile,
  3398. (DWORD)(dest - ansiFile),
  3399. &written,
  3400. NULL) ||
  3401. (INT)written != dest - ansiFile
  3402. ) {
  3403. __leave;
  3404. }
  3405. b = TRUE;
  3406. }
  3407. __finally {
  3408. if (handle != INVALID_HANDLE_VALUE) {
  3409. CloseHandle (handle);
  3410. }
  3411. if (ansiFile) {
  3412. FREE (ansiFile);
  3413. }
  3414. if (qfeList) {
  3415. FREE (qfeList);
  3416. }
  3417. UnmapFile (mappingHandle, baseAddress);
  3418. CloseHandle (fileHandle);
  3419. }
  3420. return b;
  3421. }
  3422. BOOL
  3423. pReplaceEnvVars (
  3424. IN PCTSTR CompdataTemplate,
  3425. OUT PTSTR TargetPath,
  3426. IN INT CchTargetPath
  3427. )
  3428. {
  3429. TCHAR templatePath[MAX_PATH];
  3430. PSTR targetBuf = NULL;
  3431. PCTSTR filename;
  3432. DWORD reqChars;
  3433. DWORD fileSize;
  3434. HANDLE fileHandle;
  3435. HANDLE mappingHandle;
  3436. PVOID baseAddress;
  3437. INT bytes;
  3438. HANDLE handle = INVALID_HANDLE_VALUE;
  3439. DWORD written;
  3440. BOOL b = FALSE;
  3441. if (!MyGetWindowsDirectory (TargetPath, CchTargetPath)) {
  3442. return b;
  3443. }
  3444. if (!FindPathToWinnt32File (CompdataTemplate, templatePath, ARRAYSIZE(templatePath))) {
  3445. return b;
  3446. }
  3447. if (MapFileForRead (templatePath, &fileSize, &fileHandle, &mappingHandle, &baseAddress) != ERROR_SUCCESS) {
  3448. return b;
  3449. }
  3450. __try {
  3451. reqChars = ExpandEnvironmentStringsA ((PCSTR)baseAddress, NULL, 0);
  3452. if (!reqChars) {
  3453. __leave;
  3454. }
  3455. filename = _tcsrchr (CompdataTemplate, TEXT('\\'));
  3456. if (!filename) {
  3457. filename = CompdataTemplate;
  3458. }
  3459. ConcatenatePaths (TargetPath, filename, CchTargetPath);
  3460. handle = CreateFile (
  3461. TargetPath,
  3462. GENERIC_WRITE,
  3463. 0,
  3464. NULL,
  3465. CREATE_ALWAYS,
  3466. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  3467. NULL
  3468. );
  3469. if (handle == INVALID_HANDLE_VALUE) {
  3470. __leave;
  3471. }
  3472. targetBuf = MALLOC (reqChars * sizeof (CHAR));
  3473. if (!targetBuf) {
  3474. __leave;
  3475. }
  3476. reqChars = ExpandEnvironmentStringsA ((PCSTR)baseAddress, targetBuf, reqChars);
  3477. if (!reqChars) {
  3478. __leave;
  3479. }
  3480. if (!WriteFile (
  3481. handle,
  3482. targetBuf,
  3483. reqChars * sizeof (CHAR),
  3484. &written,
  3485. NULL) ||
  3486. (INT)written != reqChars * sizeof (CHAR)
  3487. ) {
  3488. __leave;
  3489. }
  3490. b = TRUE;
  3491. }
  3492. __finally {
  3493. if (handle != INVALID_HANDLE_VALUE) {
  3494. CloseHandle (handle);
  3495. }
  3496. if (targetBuf) {
  3497. FREE (targetBuf);
  3498. }
  3499. UnmapFile (mappingHandle, baseAddress);
  3500. CloseHandle (fileHandle);
  3501. }
  3502. return b;
  3503. }
  3504. BOOL
  3505. QFECheck (
  3506. PCOMPAIBILITYCALLBACK CompatibilityCallback,
  3507. LPVOID Context
  3508. )
  3509. /*++
  3510. Routine Description:
  3511. Checks if any ServicePacks/QFEs are currently installed.
  3512. Arguments:
  3513. CompatibilityCallback - pointer to call back function
  3514. Context - context pointer
  3515. Return Value:
  3516. Returns always TRUE.
  3517. --*/
  3518. {
  3519. COMPATIBILITY_ENTRY CompEntry;
  3520. PTSTR list;
  3521. TCHAR text[512];
  3522. TCHAR htmTarget[MAX_PATH];
  3523. DWORD count = 0, totalLen;
  3524. //
  3525. // only do this check on identical builds
  3526. //
  3527. if (OsVersion.dwBuildNumber != VER_PRODUCTBUILD) {
  3528. return FALSE;
  3529. }
  3530. if (pGetQFEsInstalled (&list, &count, &totalLen) != ERROR_SUCCESS) {
  3531. return FALSE;
  3532. }
  3533. if (OsVersion.szCSDVersion[0] || list) {
  3534. MYASSERT (!list || *list && count && totalLen);
  3535. if (pDumpQfeListToFile (
  3536. OsVersion.szCSDVersion[0] ? OsVersion.szCSDVersion : NULL,
  3537. list,
  3538. count,
  3539. totalLen
  3540. )) {
  3541. if (!pReplaceEnvVars (TEXT("compdata\\svcpack.htm"), htmTarget, ARRAYSIZE(htmTarget))) {
  3542. //
  3543. // failed, just use the template
  3544. //
  3545. lstrcpyn (htmTarget, TEXT("compdata\\svcpack.htm"), ARRAYSIZE(htmTarget));
  3546. }
  3547. if (LoadString (hInst, IDS_DESCRIPTION_SERVICEPACKS, text, ARRAYSIZE(text))) {
  3548. ZeroMemory (&CompEntry, sizeof (CompEntry));
  3549. CompEntry.Description = text;
  3550. CompEntry.HtmlName = htmTarget;
  3551. CompEntry.TextName = TEXT("compdata\\svcpack.txt");
  3552. if (!CompatibilityCallback (&CompEntry, Context)){
  3553. MYASSERT (FALSE);
  3554. }
  3555. } else {
  3556. MYASSERT (FALSE);
  3557. }
  3558. }
  3559. FREE (list);
  3560. }
  3561. return TRUE;
  3562. }