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

3514 lines
104 KiB

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