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.

2172 lines
60 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. compat.cpp
  5. Abstract:
  6. compatibility code -- adapted from winnt32u.dll's compatibility code.
  7. Author:
  8. Andrew Ritz (AndrewR) 7-Jul-2000
  9. Revision History:
  10. Andrew Ritz (andrewr) 7-Jul-2000 : Created It
  11. --*/
  12. #include "pch.h"
  13. #pragma hdrstop
  14. #include <TCHAR.H>
  15. #include <commctrl.h>
  16. #include <setupapi.h>
  17. #include <spapip.h>
  18. #include <stdlib.h>
  19. #include "callback.h"
  20. #include "utils.h"
  21. #include "compat.h"
  22. #include "logging.h"
  23. DEFINE_MODULE( "RIPREP" )
  24. #define HideWindow(_hwnd) SetWindowLong((_hwnd),GWL_STYLE,GetWindowLong((_hwnd),GWL_STYLE)&~WS_VISIBLE)
  25. #define UnHideWindow(_hwnd) SetWindowLong((_hwnd),GWL_STYLE,GetWindowLong((_hwnd),GWL_STYLE)|WS_VISIBLE)
  26. #define MALLOC(_sz_) TraceAlloc(LMEM_FIXED,_sz_)
  27. #define FREE(_ptr_) TraceFree((PVOID)_ptr_)
  28. #define AppTitleStringId (IDS_APPNAME)
  29. #define WM_MYSTOPSVC WM_APP+3
  30. #define WM_DOSTOPSVC WM_APP+4
  31. #define WM_STOPSVCCOMPLETE WM_APP+5
  32. CRITICAL_SECTION CompatibilityCS;
  33. HINF g_hCompatibilityInf = INVALID_HANDLE_VALUE;
  34. LIST_ENTRY CompatibilityData;
  35. DWORD CompatibilityCount;
  36. DWORD ServicesToStopCount;
  37. DWORD IncompatibilityStopsInstallation = FALSE;
  38. DWORD GlobalCompFlags;
  39. BOOL UserCancelled;
  40. BOOL AnyNt5CompatDlls = FALSE;
  41. WNDPROC OldEditProc;
  42. BOOL
  43. FileExists(
  44. IN LPCTSTR FileName
  45. )
  46. {
  47. WIN32_FIND_DATA fd;
  48. HANDLE hFile;
  49. hFile = FindFirstFile( FileName, &fd);
  50. if (hFile != INVALID_HANDLE_VALUE) {
  51. FindClose( hFile );
  52. return(TRUE);
  53. }
  54. return(FALSE);
  55. }
  56. LPTSTR
  57. DupString(
  58. IN LPCTSTR String
  59. )
  60. /*++
  61. Routine Description:
  62. Make a duplicate of a nul-terminated string.
  63. Arguments:
  64. String - supplies pointer to nul-terminated string to copy.
  65. Return Value:
  66. Copy of string or NULL if OOM. Caller can free with FREE().
  67. --*/
  68. {
  69. LPTSTR p;
  70. if(p = (LPTSTR)MALLOC((lstrlen(String)+1)*sizeof(TCHAR))) {
  71. lstrcpy(p,String);
  72. }
  73. return(p);
  74. }
  75. DWORD
  76. MapFileForRead(
  77. IN LPCTSTR FileName,
  78. OUT PDWORD FileSize,
  79. OUT PHANDLE FileHandle,
  80. OUT PHANDLE MappingHandle,
  81. OUT PVOID *BaseAddress
  82. )
  83. /*++
  84. Routine Description:
  85. Open and map an entire file for read access. The file must
  86. not be 0-length or the routine fails.
  87. Arguments:
  88. FileName - supplies pathname to file to be mapped.
  89. FileSize - receives the size in bytes of the file.
  90. FileHandle - receives the win32 file handle for the open file.
  91. The file will be opened for generic read access.
  92. MappingHandle - receives the win32 handle for the file mapping
  93. object. This object will be for read access. This value is
  94. undefined if the file being opened is 0 length.
  95. BaseAddress - receives the address where the file is mapped. This
  96. value is undefined if the file being opened is 0 length.
  97. Return Value:
  98. NO_ERROR if the file was opened and mapped successfully.
  99. The caller must unmap the file with UnmapFile when
  100. access to the file is no longer desired.
  101. Win32 error code if the file was not successfully mapped.
  102. --*/
  103. {
  104. DWORD rc;
  105. //
  106. // Open the file -- fail if it does not exist.
  107. //
  108. *FileHandle = CreateFile(
  109. FileName,
  110. GENERIC_READ,
  111. FILE_SHARE_READ,
  112. NULL,
  113. OPEN_EXISTING,
  114. 0,
  115. NULL
  116. );
  117. if(*FileHandle == INVALID_HANDLE_VALUE) {
  118. rc = GetLastError();
  119. } else {
  120. //
  121. // Get the size of the file.
  122. //
  123. *FileSize = GetFileSize(*FileHandle,NULL);
  124. if(*FileSize == (DWORD)(-1)) {
  125. rc = GetLastError();
  126. } else {
  127. //
  128. // Create file mapping for the whole file.
  129. //
  130. *MappingHandle = CreateFileMapping(
  131. *FileHandle,
  132. NULL,
  133. PAGE_READONLY,
  134. 0,
  135. *FileSize,
  136. NULL
  137. );
  138. if(*MappingHandle) {
  139. //
  140. // Map the whole file.
  141. //
  142. *BaseAddress = MapViewOfFile(
  143. *MappingHandle,
  144. FILE_MAP_READ,
  145. 0,
  146. 0,
  147. *FileSize
  148. );
  149. if(*BaseAddress) {
  150. return(NO_ERROR);
  151. }
  152. rc = GetLastError();
  153. CloseHandle(*MappingHandle);
  154. } else {
  155. rc = GetLastError();
  156. }
  157. }
  158. CloseHandle(*FileHandle);
  159. }
  160. return(rc);
  161. }
  162. DWORD
  163. UnmapFile(
  164. IN HANDLE MappingHandle,
  165. IN PVOID BaseAddress
  166. )
  167. /*++
  168. Routine Description:
  169. Unmap and close a file.
  170. Arguments:
  171. MappingHandle - supplies the win32 handle for the open file mapping
  172. object.
  173. BaseAddress - supplies the address where the file is mapped.
  174. Return Value:
  175. NO_ERROR if the file was unmapped successfully.
  176. Win32 error code if the file was not successfully unmapped.
  177. --*/
  178. {
  179. DWORD rc;
  180. rc = UnmapViewOfFile(BaseAddress) ? NO_ERROR : GetLastError();
  181. if(!CloseHandle(MappingHandle)) {
  182. if(rc == NO_ERROR) {
  183. rc = GetLastError();
  184. }
  185. }
  186. return(rc);
  187. }
  188. LRESULT
  189. CALLBACK
  190. TextEditSubProc(
  191. IN HWND hwnd,
  192. IN UINT msg,
  193. IN WPARAM wParam,
  194. IN LPARAM lParam
  195. )
  196. {
  197. //
  198. // For setsel messages, make start and end the same.
  199. //
  200. if ((msg == EM_SETSEL) && ((LPARAM)wParam != lParam)) {
  201. lParam = wParam;
  202. }
  203. return CallWindowProc( OldEditProc, hwnd, msg, wParam, lParam );
  204. }
  205. BOOL
  206. SetTextInDialog(
  207. HWND hwnd,
  208. LPTSTR FileName
  209. )
  210. {
  211. DWORD FileSize;
  212. HANDLE FileHandle;
  213. HANDLE MappingHandle;
  214. PVOID BaseAddress;
  215. LPSTR Text;
  216. OldEditProc = (WNDPROC) GetWindowLongPtr( hwnd, GWLP_WNDPROC );
  217. SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG_PTR)TextEditSubProc );
  218. if (MapFileForRead( FileName, &FileSize, &FileHandle, &MappingHandle, &BaseAddress )) {
  219. return FALSE;
  220. }
  221. Text = (LPSTR) MALLOC( FileSize + 16 );
  222. if( Text ) {
  223. CopyMemory( Text, BaseAddress, FileSize );
  224. Text[FileSize] = '\0';
  225. SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)Text );
  226. FREE( Text );
  227. }
  228. UnmapFile( MappingHandle, BaseAddress );
  229. CloseHandle( FileHandle );
  230. return TRUE;
  231. }
  232. INT_PTR
  233. CALLBACK
  234. CompatibilityTextDlgProc(
  235. HWND hwndDlg,
  236. UINT uMsg,
  237. WPARAM wParam,
  238. LPARAM lParam
  239. )
  240. {
  241. switch(uMsg) {
  242. case WM_INITDIALOG:
  243. SetTextInDialog( GetDlgItem( hwndDlg, IDC_TEXT ), (LPTSTR) lParam );
  244. break;
  245. case WM_COMMAND:
  246. if (wParam == IDOK) {
  247. EndDialog( hwndDlg, IDOK );
  248. }
  249. break;
  250. case WM_CTLCOLOREDIT:
  251. SetBkColor( (HDC)wParam, GetSysColor(COLOR_BTNFACE));
  252. return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
  253. break;
  254. }
  255. return 0;
  256. }
  257. BOOL
  258. LaunchIE4Instance(
  259. LPWSTR szResourceURL
  260. );
  261. BOOL
  262. LaunchIE3Instance(
  263. LPWSTR szResourceURL
  264. );
  265. INT_PTR
  266. CompatibilityDlgProc(
  267. IN HWND hdlg,
  268. IN UINT msg,
  269. IN WPARAM wParam,
  270. IN LPARAM lParam
  271. )
  272. {
  273. TCHAR FullPath[MAX_PATH+8], *t;
  274. LPWSTR Url;
  275. BOOL UseText = FALSE;
  276. BOOL b = FALSE;
  277. DWORD i;
  278. PRIPREP_COMPATIBILITY_DATA CompData;
  279. DWORD Index;
  280. static int CurrentSelectionIndex=0;
  281. static DWORD Count = 0;
  282. LV_ITEM lvi = {0};
  283. HWND TmpHwnd;
  284. static BOOL WarningsPresent = FALSE;
  285. static BOOL ErrorsPresent = FALSE;
  286. static BOOL CheckUpgradeNoItems = TRUE;
  287. DWORD dw;
  288. switch(msg) {
  289. case WM_INITDIALOG:
  290. if (CompatibilityCount) {
  291. HWND hList = GetDlgItem( hdlg, IDC_ROOT_LIST );
  292. PLIST_ENTRY Next;
  293. HIMAGELIST himl;
  294. HICON hIcon;
  295. LV_COLUMN lvc = {0};
  296. RECT rc;
  297. GetClientRect( hList, &rc );
  298. lvc.mask = LVCF_WIDTH;
  299. lvc.cx = rc.right - rc.left - 16;
  300. ListView_InsertColumn( hList, 0, &lvc );
  301. Next = CompatibilityData.Flink;
  302. if (Next) {
  303. himl = ImageList_Create( GetSystemMetrics(SM_CXSMICON),
  304. GetSystemMetrics(SM_CXSMICON),
  305. ILC_COLOR,
  306. 2,
  307. 0 );
  308. ListView_SetImageList( hList, himl, LVSIL_SMALL );
  309. hIcon = LoadIcon( NULL, IDI_HAND );
  310. ImageList_AddIcon( himl, hIcon );
  311. hIcon = LoadIcon( NULL, IDI_EXCLAMATION );
  312. ImageList_AddIcon( himl, hIcon );
  313. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  314. lvi.state = 0;
  315. lvi.stateMask = 0;
  316. while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
  317. CompData = CONTAINING_RECORD( Next, RIPREP_COMPATIBILITY_DATA, ListEntry );
  318. Next = CompData->ListEntry.Flink;
  319. if (OsVersion.dwMajorVersion < 5) {
  320. if ( CompData->Flags & COMPFLAG_ALLOWNT5COMPAT ) {
  321. AnyNt5CompatDlls = TRUE;
  322. } else {
  323. goto NextIteration;
  324. }
  325. }
  326. if (((CompData->Flags & COMPFLAG_HIDE) == 0) &&
  327. ((CompData->Flags & COMPFLAG_CHANGESTATE) == 0)) {
  328. //
  329. // Add the icon.
  330. //
  331. if( himl ) {
  332. if( CompData->Flags & COMPFLAG_STOPINSTALL ) {
  333. lvi.iImage = 0;
  334. ErrorsPresent = TRUE;
  335. } else {
  336. lvi.iImage = 1;
  337. WarningsPresent = TRUE;
  338. }
  339. }
  340. //
  341. // And the text...
  342. //
  343. lvi.pszText = (LPTSTR)CompData->Description;
  344. lvi.lParam = (LPARAM)CompData;
  345. Index = ListView_InsertItem( hList, &lvi );
  346. Count += 1;
  347. }
  348. NextIteration:
  349. NOTHING;
  350. }
  351. }
  352. // If we have an item then make it the default selection
  353. if( ErrorsPresent || WarningsPresent ){
  354. SetFocus( hList );
  355. ListView_SetItemState( hList,
  356. 0,
  357. LVIS_SELECTED | LVIS_FOCUSED,
  358. LVIS_SELECTED | LVIS_FOCUSED);
  359. CurrentSelectionIndex = 0;
  360. lvi.mask = LVIF_PARAM;
  361. lvi.iItem = 0;
  362. lvi.iSubItem = 0;
  363. ListView_GetItem( GetDlgItem( hdlg, IDC_ROOT_LIST ), &lvi );
  364. CompData = (PRIPREP_COMPATIBILITY_DATA)lvi.lParam;
  365. }
  366. }
  367. break;
  368. case WM_NOTIFY:
  369. {
  370. LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
  371. LPNMHDR lpnmhdr = (LPNMHDR) lParam;
  372. switch (lpnmhdr->code) {
  373. case PSN_SETACTIVE:
  374. PropSheet_SetWizButtons(
  375. GetParent( hdlg ),
  376. PSWIZB_BACK |
  377. (ErrorsPresent ? 0 : PSWIZB_NEXT) );
  378. ClearMessageQueue( );
  379. if (Count) {
  380. //
  381. // only need this page if there are incompatibities
  382. //
  383. TCHAR Text[512];
  384. //
  385. // Customize the look of the page, depending on
  386. // what we have to display. 3 cases are possible:
  387. // 1. Warnings only (services we'll stop).
  388. // 2. Errors only (items that will prevent installation).
  389. // 3. combination of 1. and 2.
  390. //
  391. if( (WarningsPresent == TRUE) && (ErrorsPresent == TRUE) ) {
  392. dw = LoadString(g_hinstance,IDS_COMPAT_ERR_WRN,Text,ARRAYSIZE(Text));
  393. Assert( dw );
  394. } else if( WarningsPresent == TRUE ) {
  395. dw = LoadString(g_hinstance,IDS_COMPAT_WRN,Text,ARRAYSIZE(Text));
  396. Assert( dw );
  397. } else if( ErrorsPresent == TRUE ) {
  398. dw = LoadString(g_hinstance,IDS_COMPAT_ERR,Text,ARRAYSIZE(Text));
  399. Assert( dw );
  400. } else {
  401. Assert(FALSE);
  402. }
  403. SetDlgItemText(hdlg,IDC_INTRO_TEXT,Text);
  404. return(TRUE);
  405. } else {
  406. DebugMsg( "Skipping compatibility page, no incompatibilities...\n" );
  407. SetWindowLongPtr( hdlg, DWLP_MSGRESULT, -1 ); // don't show
  408. }
  409. return(TRUE);
  410. break;
  411. case PSN_QUERYCANCEL:
  412. return VerifyCancel( hdlg );
  413. break;
  414. }
  415. if( (pnmv->hdr.code == LVN_ITEMCHANGED) ) {
  416. Index = ListView_GetNextItem( GetDlgItem( hdlg, IDC_ROOT_LIST ),
  417. (int)-1,
  418. (UINT) (LVNI_ALL | LVNI_SELECTED | LVNI_FOCUSED) );
  419. if( (Index != LB_ERR) && (pnmv->iItem != CurrentSelectionIndex)) {
  420. // Always set the Details button
  421. TmpHwnd = GetDlgItem( hdlg, IDC_DETAILS );
  422. EnableWindow( TmpHwnd, TRUE );
  423. InvalidateRect( GetParent(hdlg), NULL, FALSE );
  424. }else if((Index != LB_ERR) && (pnmv->uNewState == (LVIS_SELECTED|LVIS_FOCUSED))){
  425. //Transition from nothing selected to previous selection
  426. TmpHwnd = GetDlgItem( hdlg, IDC_DETAILS );
  427. EnableWindow( TmpHwnd, TRUE );
  428. }else if( Index == LB_ERR){
  429. // Disable the "Details" button as nothing is selected
  430. TmpHwnd = GetDlgItem( hdlg, IDC_DETAILS );
  431. EnableWindow( TmpHwnd, FALSE );
  432. }
  433. }
  434. }
  435. break;
  436. case WM_COMMAND:
  437. if ((LOWORD(wParam) == IDC_DETAILS) && (HIWORD(wParam) == BN_CLICKED)) {
  438. TCHAR MessageText[300];
  439. TCHAR FormatText[300];
  440. Index = ListView_GetNextItem( GetDlgItem( hdlg, IDC_ROOT_LIST ),
  441. (int)-1,
  442. (UINT) (LVNI_ALL | LVNI_SELECTED) );
  443. if (Index == LB_ERR) {
  444. return FALSE;
  445. }
  446. //
  447. // Select the item, and get the compatibility data for the item
  448. //
  449. lvi.mask = LVIF_PARAM;
  450. lvi.iItem = Index;
  451. lvi.iSubItem = 0;
  452. ListView_GetItem( GetDlgItem( hdlg, IDC_ROOT_LIST ), &lvi );
  453. CompData = (PRIPREP_COMPATIBILITY_DATA)lvi.lParam;
  454. if (CompData->MsgResourceId) {
  455. dw = LoadString(g_hinstance,CompData->MsgResourceId,MessageText,ARRAYSIZE(MessageText));
  456. Assert( dw );
  457. } else {
  458. LoadString(
  459. g_hinstance,
  460. ((CompData->Flags & COMPFLAG_STOPINSTALL)
  461. ? IDS_INCOMPAT_STOP_FORMAT
  462. : IDS_INCOMPAT_WARN_FORMAT ),
  463. FormatText,ARRAYSIZE(FormatText));
  464. wsprintf(MessageText, FormatText, CompData->Description );
  465. }
  466. dw = LoadString(g_hinstance,IDS_INCOMPAT_MSG_TITLE,FormatText,ARRAYSIZE(FormatText));
  467. Assert( dw );
  468. MessageBox(
  469. hdlg,
  470. MessageText,
  471. FormatText,
  472. ((CompData->Flags & COMPFLAG_STOPINSTALL)
  473. ? MB_OK | MB_ICONERROR
  474. : MB_OK | MB_ICONWARNING ));
  475. #if 0
  476. //
  477. // We check to see if the pointer as well as its contents are valid. If the contents are Null then we try
  478. // the txt file before we decide to not do anything.
  479. //
  480. if( (CompData->HtmlName) && *(CompData->HtmlName) ) {
  481. lstrcpy( FullPath, TEXT("file://") );
  482. _tfullpath( FullPath+7, CompData->HtmlName, MAX_PATH );
  483. if( !FileExists( FullPath+7 ) ){
  484. GetModuleFileName( NULL, (LPTSTR)(FullPath+7), MAX_PATH);
  485. t = _tcsrchr( FullPath, TEXT('\\'));
  486. t[1] = 0;
  487. _tcscat( FullPath, CompData->HtmlName );
  488. }
  489. i = lstrlen( FullPath );
  490. Url = (LPWSTR)SysAllocStringLen( NULL, i );
  491. if( Url ) {
  492. #ifdef UNICODE
  493. wcscpy( Url, FullPath );
  494. #else
  495. MultiByteToWideChar( CP_ACP, 0, FullPath, -1, Url, i );
  496. #endif
  497. if (!LaunchIE4Instance(Url)) {
  498. if (!LaunchIE3Instance(Url)) {
  499. UseText = TRUE;
  500. }
  501. }
  502. SysFreeString( Url );
  503. }
  504. } else {
  505. UseText = TRUE;
  506. }
  507. if (UseText && (CompData->TextName) && *(CompData->TextName) ) {
  508. _tfullpath( FullPath, CompData->TextName, MAX_PATH );
  509. if( !FileExists( FullPath ) ){
  510. GetModuleFileName( NULL, FullPath, MAX_PATH);
  511. t = _tcsrchr( FullPath, TEXT('\\'));
  512. t[1] = 0;
  513. _tcscat( FullPath, CompData->TextName );
  514. }
  515. DialogBoxParam(
  516. g_hinstance,
  517. MAKEINTRESOURCE(IDD_COMPATIBILITY_TEXT),
  518. NULL,
  519. CompatibilityTextDlgProc,
  520. (LPARAM)FullPath
  521. );
  522. } else if( UseText ){
  523. TCHAR Heading[512];
  524. //
  525. // When there is no txt name present, as last resort we put up this message
  526. //
  527. if(!LoadString(g_hinstance,AppTitleStringId,Heading,ARRAYSIZE(Heading))) {
  528. Heading[0] = 0;
  529. }
  530. MessageBox( hdlg,
  531. TEXT( "No further details are available for this incompatibility. " ),
  532. Heading,
  533. MB_OK | MB_ICONWARNING );
  534. }
  535. SetFocus( GetDlgItem( hdlg, IDC_ROOT_LIST ) );
  536. ListView_SetItemState( GetDlgItem( hdlg, IDC_ROOT_LIST ),Index, LVIS_SELECTED, LVIS_SELECTED);
  537. #endif
  538. }
  539. break;
  540. default:
  541. break;
  542. }
  543. return(b);
  544. }
  545. INT_PTR
  546. StopServiceWrnDlgProc(
  547. IN HWND hdlg,
  548. IN UINT msg,
  549. IN WPARAM wParam,
  550. IN LPARAM lParam
  551. )
  552. {
  553. TCHAR FullPath[MAX_PATH+8], *t;
  554. LPWSTR Url;
  555. BOOL UseText = FALSE;
  556. BOOL b = FALSE;
  557. DWORD i;
  558. PRIPREP_COMPATIBILITY_DATA CompData;
  559. DWORD Index;
  560. static int CurrentSelectionIndex=0;
  561. static DWORD Count = 0;
  562. LV_ITEM lvi = {0};
  563. HWND TmpHwnd;
  564. static BOOL TriedStoppingServices = FALSE;
  565. PLIST_ENTRY Next;
  566. HIMAGELIST himl;
  567. HICON hIcon;
  568. LV_COLUMN lvc = {0};
  569. RECT rc;
  570. WCHAR szText[ 80 ];
  571. HWND hList = GetDlgItem( hdlg, IDC_ROOT_LIST );
  572. DWORD dw;
  573. switch(msg) {
  574. case WM_INITDIALOG:
  575. if (ServicesToStopCount) {
  576. //
  577. // add a column
  578. //
  579. lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  580. lvc.fmt = LVCFMT_LEFT;
  581. lvc.pszText = szText;
  582. lvc.iSubItem = 0;
  583. lvc.cx = 100;
  584. LoadString(
  585. g_hinstance,
  586. IDS_SERVICE_NAME_COLUMN,
  587. szText,
  588. sizeof(szText)/sizeof(WCHAR));
  589. i = ListView_InsertColumn( hList, 0, &lvc );
  590. Assert( i != -1 );
  591. //
  592. // add a 2nd column
  593. //
  594. GetClientRect( hList, &rc );
  595. lvc.iSubItem++;
  596. lvc.cx = ( rc.right - rc.left ) - lvc.cx;
  597. dw = LoadString(
  598. g_hinstance,
  599. IDS_SERVICE_DESCRIPTION_COLUMN,
  600. szText,
  601. ARRAYSIZE(szText));
  602. Assert( dw );
  603. i = ListView_InsertColumn ( hList, lvc.iSubItem, &lvc );
  604. Assert( i != -1 );
  605. }
  606. break;
  607. case WM_NOTIFY:
  608. {
  609. LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
  610. LPNMHDR lpnmhdr = (LPNMHDR) lParam;
  611. switch (lpnmhdr->code) {
  612. case PSN_SETACTIVE:
  613. PropSheet_SetWizButtons(
  614. GetParent( hdlg ),
  615. PSWIZB_BACK | PSWIZB_NEXT );
  616. ClearMessageQueue( );
  617. Next = CompatibilityData.Flink;
  618. if (Next && (Count == 0)) {
  619. himl = ImageList_Create( GetSystemMetrics(SM_CXSMICON),
  620. GetSystemMetrics(SM_CXSMICON),
  621. ILC_COLOR,
  622. 2,
  623. 0 );
  624. ListView_SetImageList( hList, himl, LVSIL_SMALL );
  625. hIcon = LoadIcon( NULL, IDI_HAND );
  626. ImageList_AddIcon( himl, hIcon );
  627. hIcon = LoadIcon( NULL, IDI_EXCLAMATION );
  628. ImageList_AddIcon( himl, hIcon );
  629. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  630. lvi.state = 0;
  631. lvi.stateMask = 0;
  632. while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
  633. CompData = CONTAINING_RECORD( Next, RIPREP_COMPATIBILITY_DATA, ListEntry );
  634. Next = CompData->ListEntry.Flink;
  635. if (OsVersion.dwMajorVersion < 5) {
  636. if ( CompData->Flags & COMPFLAG_ALLOWNT5COMPAT ) {
  637. AnyNt5CompatDlls = TRUE;
  638. } else {
  639. goto NextIteration;
  640. }
  641. }
  642. if (CompData->Flags & COMPFLAG_CHANGESTATE) {
  643. //
  644. // Add the icon.
  645. //
  646. if( himl ) {
  647. lvi.iImage = 0;
  648. }
  649. //
  650. // And the text...
  651. //
  652. lvi.pszText = (LPTSTR)CompData->ServiceName;
  653. lvi.lParam = (LPARAM)CompData;
  654. Index = ListView_InsertItem( hList, &lvi );
  655. //
  656. // and the description
  657. //
  658. ListView_SetItemText(
  659. hList,
  660. Index,
  661. 1,
  662. (LPWSTR)CompData->Description );
  663. Count += 1;
  664. }
  665. NextIteration:
  666. NOTHING;
  667. }
  668. }
  669. // If we have an item then make it the default selection
  670. if( Count && !TriedStoppingServices ){
  671. TCHAR Text[512];
  672. SetFocus( hList );
  673. ListView_SetItemState( hList,
  674. 0,
  675. LVIS_SELECTED | LVIS_FOCUSED,
  676. LVIS_SELECTED | LVIS_FOCUSED);
  677. CurrentSelectionIndex = 0;
  678. lvi.mask = LVIF_PARAM;
  679. lvi.iItem = 0;
  680. lvi.iSubItem = 0;
  681. ListView_GetItem( GetDlgItem( hdlg, IDC_ROOT_LIST ), &lvi );
  682. //
  683. // only need this page if there are incompatibities
  684. //
  685. dw = LoadString(g_hinstance,IDS_STOPSVC_WRN,Text,ARRAYSIZE(Text));
  686. Assert( dw );
  687. SetDlgItemText(hdlg,IDC_INTRO_TEXT,Text);
  688. } else {
  689. DebugMsg( "Skipping StopService page, no services to stop...\n" );
  690. SetWindowLongPtr( hdlg, DWLP_MSGRESULT, -1 ); // don't show
  691. }
  692. return(TRUE);
  693. break;
  694. case PSN_QUERYCANCEL:
  695. return VerifyCancel( hdlg );
  696. break;
  697. case PSN_WIZNEXT:
  698. if (!TriedStoppingServices) {
  699. TriedStoppingServices = TRUE;
  700. }
  701. }
  702. }
  703. break;
  704. default:
  705. break;
  706. }
  707. return(b);
  708. }
  709. BOOL
  710. MyStopService(
  711. IN LPCTSTR ServiceName
  712. )
  713. {
  714. SC_HANDLE hSC;
  715. SC_HANDLE hService;
  716. SERVICE_STATUS ServiceStatus;
  717. BOOL Status = FALSE;
  718. hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  719. if (hSC != NULL) {
  720. hService = OpenService( hSC, ServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS);
  721. if (hService != NULL) {
  722. if (QueryServiceStatus(
  723. hService,
  724. &ServiceStatus) &&
  725. ServiceStatus.dwCurrentState == SERVICE_STOPPED) {
  726. Status = TRUE;
  727. } else {
  728. ULONG StartTime = GetTickCount();
  729. while( ((GetTickCount() - StartTime) <= (30 * 1000)) && // Did we run over 30 seconds?
  730. (!UserCancelled) ) { // Did the user cancel via the UI?
  731. if (ControlService( hService,
  732. SERVICE_CONTROL_STOP,
  733. &ServiceStatus ) &&
  734. (ServiceStatus.dwCurrentState == SERVICE_STOPPED)) {
  735. Status = TRUE;
  736. break;
  737. }
  738. if (QueryServiceStatus( hService,
  739. &ServiceStatus) &&
  740. (ServiceStatus.dwCurrentState == SERVICE_STOPPED)) {
  741. Status = TRUE;
  742. break;
  743. }
  744. //
  745. // Make sure we didn't wrap over 32-bits in our counter.
  746. //
  747. if( GetTickCount() < StartTime ) {
  748. // he wrapped. Reset StartTime.
  749. StartTime = GetTickCount();
  750. }
  751. //
  752. // It hasn't stopped yet. Sleep and try again.
  753. //
  754. Sleep(1000);
  755. }
  756. }
  757. CloseServiceHandle( hService );
  758. }
  759. CloseServiceHandle( hSC );
  760. }
  761. return(Status);
  762. }
  763. DWORD
  764. StopServiceThreadProc(
  765. LPVOID lParam
  766. )
  767. {
  768. PLIST_ENTRY Next;
  769. BOOL RetVal = FALSE;
  770. PRIPREP_COMPATIBILITY_DATA CompData;
  771. DWORD StoppedServicesCount = 0;
  772. HWND hDlg = (HWND)lParam;
  773. CWaitCursor Cursor;
  774. EnterCriticalSection(&CompatibilityCS);
  775. Next = CompatibilityData.Flink;
  776. if (Next) {
  777. while (((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) && !UserCancelled) {
  778. CompData = CONTAINING_RECORD( Next, RIPREP_COMPATIBILITY_DATA, ListEntry );
  779. Next = CompData->ListEntry.Flink;
  780. if (CompData->Flags & COMPFLAG_CHANGESTATE) {
  781. DebugMsg( "Stopping %s...\n", CompData->ServiceName );
  782. SetDlgItemText( hDlg, IDC_STOP_SERVICE, CompData->Description );
  783. if (MyStopService(CompData->ServiceName)) {
  784. StoppedServicesCount += 1;
  785. } else {
  786. LogMsg( L"Failed to stop service: %s\r\n", CompData->ServiceName );
  787. }
  788. }
  789. }
  790. }
  791. LeaveCriticalSection(&CompatibilityCS);
  792. if (!RetVal) {
  793. PostMessage(
  794. hDlg,
  795. WM_STOPSVCCOMPLETE,
  796. (StoppedServicesCount == ServicesToStopCount),
  797. 0);
  798. }
  799. return(0);
  800. }
  801. INT_PTR
  802. DoStopServiceDlgProc(
  803. IN HWND hdlg,
  804. IN UINT msg,
  805. IN WPARAM wParam,
  806. IN LPARAM lParam
  807. )
  808. {
  809. static DWORD StoppedServicesCount = 0;
  810. static BOOL TriedStoppingServices = FALSE;
  811. static BOOL AlreadyPostedMessage = FALSE;
  812. BOOL b = FALSE;
  813. switch(msg) {
  814. case WM_NOTIFY:
  815. {
  816. LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
  817. LPNMHDR lpnmhdr = (LPNMHDR) lParam;
  818. switch (lpnmhdr->code) {
  819. case PSN_SETACTIVE:
  820. PropSheet_SetWizButtons(
  821. GetParent( hdlg ), 0 );
  822. ClearMessageQueue( );
  823. if (TriedStoppingServices || ServicesToStopCount == 0) {
  824. DebugMsg( "Skipping DoStopService page, already tried to stop services...\n" );
  825. SetWindowLongPtr( hdlg, DWLP_MSGRESULT, -1 ); // don't show
  826. }
  827. if (!AlreadyPostedMessage && ServicesToStopCount) {
  828. PostMessage( hdlg, WM_MYSTOPSVC, 0, 0 );
  829. AlreadyPostedMessage = TRUE;
  830. }
  831. return(TRUE);
  832. break;
  833. case PSN_QUERYCANCEL:
  834. b = VerifyCancel( hdlg );
  835. if (!b) {
  836. UserCancelled = TRUE;
  837. }
  838. return(b);
  839. break;
  840. }
  841. }
  842. break;
  843. case WM_MYSTOPSVC:
  844. {
  845. HANDLE hThread;
  846. DWORD dontcare;
  847. DebugMsg( "received WM_MYSTOPSVC...\n" );
  848. hThread = CreateThread( NULL, 0, StopServiceThreadProc, hdlg, 0, &dontcare);
  849. if (hThread) {
  850. CloseHandle(hThread);
  851. } else {
  852. PostMessage( hdlg, WM_STOPSVCCOMPLETE, 0, 0);
  853. }
  854. }
  855. break;
  856. case WM_STOPSVCCOMPLETE:
  857. DebugMsg( "received WM_STOPSVCCOMPLETE...\n" );
  858. TriedStoppingServices = TRUE;
  859. if (wParam == (WPARAM)FALSE) {
  860. MessageBoxFromStrings( hdlg, IDS_STOPSVC_FAIL_TITLE, IDS_STOPSVC_FAIL_TEXT, MB_OK );
  861. }
  862. PropSheet_SetWizButtons(
  863. GetParent( hdlg ), PSWIZB_BACK | PSWIZB_NEXT );
  864. PropSheet_PressButton( GetParent( hdlg ), PSBTN_NEXT );
  865. break;
  866. default:
  867. break;
  868. }
  869. return(b);
  870. }
  871. BOOLEAN
  872. CheckForFileVersion(
  873. LPCTSTR FileName,
  874. LPCTSTR FileVer
  875. )
  876. /*
  877. Arguments -
  878. FileName - Full path to the file to check
  879. Filever - Version value to check against of the for x.x.x.x
  880. Function will check the actual file against the version specified. The depth of the check
  881. is as deep as specified in "x.x.x.x" i..e if FileVer = 3.5.1 and actual version on the file
  882. is 3.5.1.4 we only compare upto 3.5.1.
  883. Return values -
  884. TRUE - If the version of the file is <= FileVer which means that the file is an incompatible one
  885. else we return FALSE
  886. */
  887. {
  888. TCHAR Buffer[MAX_PATH];
  889. DWORD dwLength, dwTemp;
  890. TCHAR Datum[2];
  891. UINT DataLength;
  892. LPVOID lpData;
  893. VS_FIXEDFILEINFO *VsInfo;
  894. LPTSTR s,e;
  895. DWORD Vers[5],File_Vers[5];//MajVer, MinVer;
  896. int i=0, Depth=0;
  897. if (!ExpandEnvironmentStrings( FileName, Buffer, ARRAYSIZE(Buffer) )) {
  898. return FALSE;
  899. }
  900. if(!FileExists(Buffer))
  901. return FALSE;
  902. if( !FileVer || !(*FileVer) ){ // Since no version info is provided this boils down to a
  903. return TRUE; // presence check which was already done above
  904. }
  905. //
  906. // NT3.51 VerQueryValue writes into the buffer, can't use
  907. // a string constant.
  908. //
  909. lstrcpy( Datum, TEXT("\\") );
  910. if(dwLength = GetFileVersionInfoSize( Buffer, &dwTemp )) {
  911. if(lpData = LocalAlloc( LPTR, dwLength )) {
  912. if(GetFileVersionInfo( Buffer, 0, dwLength, lpData )) {
  913. if (VerQueryValue(
  914. lpData,
  915. Datum,
  916. (LPVOID *)&VsInfo,
  917. &DataLength )) {
  918. File_Vers[0] = (HIWORD(VsInfo->dwFileVersionMS));
  919. File_Vers[1] = (LOWORD(VsInfo->dwFileVersionMS));
  920. File_Vers[2] = (HIWORD(VsInfo->dwFileVersionLS));
  921. File_Vers[3] = (LOWORD(VsInfo->dwFileVersionLS));
  922. lstrcpy( Buffer, FileVer );
  923. //Parse and get the depth of versioning we look for
  924. s = e = Buffer;
  925. while( e ){
  926. if ( ((*e < TEXT('0')) || (*e > TEXT('9'))) && ((*e != TEXT('.')) && (*e != TEXT('\0'))) )
  927. return FALSE;
  928. if(*e == TEXT('\0')){
  929. *e = 0;
  930. Vers[i] = (DWORD)_ttoi(s);
  931. break;
  932. }
  933. if( *e == TEXT('.') ){
  934. *e = 0;
  935. Vers[i++] = (DWORD)_ttoi(s);
  936. s = e+1;
  937. }
  938. e++;
  939. }// while
  940. Depth = i+1;
  941. if (Depth > 4)
  942. Depth = 4;
  943. for( i=0; i < Depth; i++ ){
  944. if( File_Vers[i] > Vers[i] ){
  945. LocalFree( lpData );
  946. return FALSE;
  947. }
  948. else if( File_Vers[i] == Vers[i] )
  949. continue;
  950. else
  951. break;
  952. }
  953. }
  954. }
  955. LocalFree( lpData );
  956. }
  957. }
  958. return TRUE;
  959. }
  960. DWORD
  961. ProcessRegistryLine(
  962. PINFCONTEXT InfContext
  963. )
  964. {
  965. LONG Error;
  966. HKEY hKey;
  967. DWORD Size, Reg_Type;
  968. LPBYTE Buffer;
  969. PRIPREP_COMPATIBILITY_DATA CompData;
  970. TCHAR RegKey[100];
  971. TCHAR RegValue[100];
  972. TCHAR RegValueExpect[100];
  973. TCHAR Path[MAX_PATH];
  974. TCHAR Value[20];
  975. INT Flags = 0;
  976. RegKey[0] = NULL;
  977. RegValue[0] = NULL;
  978. RegValueExpect[0] = NULL;
  979. SetupGetStringField( InfContext, 2, RegKey, ARRAYSIZE( RegKey ), NULL);
  980. SetupGetStringField( InfContext, 3, RegValue, ARRAYSIZE( RegValue ), NULL);
  981. SetupGetStringField( InfContext, 4, RegValueExpect, ARRAYSIZE( RegValueExpect ), NULL);
  982. //
  983. // open the reg key
  984. //
  985. Error = RegOpenKeyEx(
  986. HKEY_LOCAL_MACHINE,
  987. RegKey,
  988. 0,
  989. KEY_READ,
  990. &hKey
  991. );
  992. if( Error != ERROR_SUCCESS ) {
  993. //
  994. // bogus reg key
  995. //
  996. return 0;
  997. }
  998. if( *RegValue ){
  999. //
  1000. // find out how much data there is
  1001. //
  1002. Error = RegQueryValueEx(
  1003. hKey,
  1004. RegValue,
  1005. NULL,
  1006. &Reg_Type,
  1007. NULL,
  1008. &Size
  1009. );
  1010. if( Error != ERROR_SUCCESS ) {
  1011. RegCloseKey( hKey );
  1012. return 0;
  1013. }
  1014. //
  1015. // allocate the buffer
  1016. //
  1017. Buffer = (LPBYTE) MALLOC( Size );
  1018. if (Buffer == NULL) {
  1019. RegCloseKey( hKey );
  1020. return 0;
  1021. }
  1022. //
  1023. // read the data
  1024. //
  1025. Error = RegQueryValueEx(
  1026. hKey,
  1027. RegValue,
  1028. NULL,
  1029. NULL,
  1030. Buffer,
  1031. &Size
  1032. );
  1033. if( Error != ERROR_SUCCESS ) {
  1034. RegCloseKey( hKey );
  1035. FREE( Buffer );
  1036. return 0;
  1037. }
  1038. RegCloseKey( hKey );
  1039. if( Reg_Type == REG_DWORD ){
  1040. _itot( (DWORD)*Buffer, Value, 10 );
  1041. FREE( Buffer );
  1042. Buffer = (LPBYTE) DupString(Value);
  1043. if (!Buffer) {
  1044. return(0);
  1045. }
  1046. }
  1047. if ( *RegValueExpect && lstrcmp( RegValueExpect, (LPTSTR)Buffer ) != 0) {
  1048. FREE( Buffer );
  1049. return 0;
  1050. }
  1051. FREE( Buffer );
  1052. }
  1053. CompData = (PRIPREP_COMPATIBILITY_DATA) MALLOC( sizeof(RIPREP_COMPATIBILITY_DATA) );
  1054. if (CompData == NULL) {
  1055. return 0;
  1056. }
  1057. ZeroMemory(CompData,sizeof(RIPREP_COMPATIBILITY_DATA));
  1058. CompData->RegKey = DupString(RegKey);
  1059. CompData->RegValue = DupString(RegValue);
  1060. CompData->RegValueExpect = DupString(RegValueExpect);
  1061. SetupGetStringField( InfContext, 5, Path, ARRAYSIZE( Path ), NULL);
  1062. CompData->HtmlName = DupString(Path);
  1063. SetupGetStringField( InfContext, 6, Path, ARRAYSIZE( Path ), NULL);
  1064. CompData->TextName = DupString(Path);
  1065. SetupGetStringField( InfContext, 7, Path, ARRAYSIZE( Path ), NULL);
  1066. CompData->Description = DupString(Path);
  1067. SetupGetIntField( InfContext,10,&Flags);
  1068. CompData->Flags |= (GlobalCompFlags | Flags);
  1069. EnterCriticalSection(&CompatibilityCS);
  1070. InsertTailList( &CompatibilityData, &CompData->ListEntry );
  1071. LeaveCriticalSection(&CompatibilityCS);
  1072. return 1;
  1073. }
  1074. BOOL
  1075. MyGetServiceDescription(
  1076. IN LPCTSTR ServiceName,
  1077. IN OUT LPTSTR Buffer,
  1078. IN DWORD BufferSizeInChars
  1079. )
  1080. {
  1081. SC_HANDLE hSC;
  1082. SC_HANDLE hService;
  1083. LPQUERY_SERVICE_CONFIG pServiceConfig;
  1084. DWORD SizeNeeded;
  1085. BOOL Status = FALSE;
  1086. hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  1087. if (hSC != NULL) {
  1088. hService = OpenService( hSC, ServiceName, SERVICE_QUERY_CONFIG);
  1089. if (hService != NULL) {
  1090. if (!QueryServiceConfig(
  1091. hService,
  1092. NULL,
  1093. 0,
  1094. &SizeNeeded) &&
  1095. GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  1096. (pServiceConfig = (LPQUERY_SERVICE_CONFIG)MALLOC(SizeNeeded)) &&
  1097. QueryServiceConfig(
  1098. hService,
  1099. pServiceConfig,
  1100. SizeNeeded,
  1101. &SizeNeeded) &&
  1102. wcslen(pServiceConfig->lpDisplayName)+1 <= BufferSizeInChars) {
  1103. wcscpy(Buffer,pServiceConfig->lpDisplayName);
  1104. FREE(pServiceConfig);
  1105. Status = TRUE;
  1106. }
  1107. CloseServiceHandle( hService );
  1108. }
  1109. CloseServiceHandle( hSC );
  1110. }
  1111. return(Status);
  1112. }
  1113. BOOL
  1114. IsServiceStopped(
  1115. IN LPCTSTR ServiceName
  1116. )
  1117. {
  1118. SC_HANDLE hSC;
  1119. SC_HANDLE hService;
  1120. BOOL Status = FALSE;
  1121. SERVICE_STATUS ServiceStatus;
  1122. hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  1123. if (hSC != NULL) {
  1124. hService = OpenService( hSC, ServiceName, SERVICE_QUERY_STATUS);
  1125. if (hService != NULL) {
  1126. if (QueryServiceStatus(
  1127. hService,
  1128. &ServiceStatus) &&
  1129. ServiceStatus.dwCurrentState == SERVICE_STOPPED ) {
  1130. Status = TRUE;
  1131. }
  1132. CloseServiceHandle( hService );
  1133. } else if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) {
  1134. Status = TRUE;
  1135. }
  1136. CloseServiceHandle( hSC );
  1137. }
  1138. return(Status);
  1139. }
  1140. DWORD
  1141. ProcessServiceLine(
  1142. PINFCONTEXT InfContext,
  1143. BOOL SetCheckedFlag
  1144. )
  1145. {
  1146. TCHAR Buffer[100],Buffer2[64],Buffer3[MAX_PATH];
  1147. LONG Error;
  1148. HKEY hKey;
  1149. INT Flags = 0;
  1150. PRIPREP_COMPATIBILITY_DATA CompData;
  1151. LPDWORD RegData;
  1152. DWORD Value;
  1153. DWORD ValueSize;
  1154. TCHAR FileVersion[20];
  1155. LPTSTR KeyName = Buffer2;
  1156. LPTSTR FileName = Buffer3;
  1157. DWORD dw;
  1158. SetupGetStringField( InfContext, 2, Buffer, ARRAYSIZE( Buffer ), NULL);
  1159. lstrcpy( KeyName, TEXT("SYSTEM\\CurrentControlSet\\Services\\") );
  1160. lstrcat( KeyName, Buffer );
  1161. //
  1162. // get an open key to the services database
  1163. //
  1164. Error = RegOpenKeyEx(
  1165. HKEY_LOCAL_MACHINE,
  1166. KeyName,
  1167. 0,
  1168. KEY_READ | KEY_WRITE,
  1169. &hKey
  1170. );
  1171. if( Error != ERROR_SUCCESS ) {
  1172. return 0;
  1173. }
  1174. //
  1175. // We'll ceate a key here so that others will know that we've
  1176. // already checked this service. We'll remove it later. We
  1177. // don't care about error codes here because this is only used
  1178. // as a safety net for checks that may come after us.
  1179. //
  1180. if( SetCheckedFlag ) {
  1181. Value = 1;
  1182. RegSetValueEx( hKey,
  1183. TEXT("SetupChecked"),
  1184. 0,
  1185. REG_DWORD,
  1186. (CONST BYTE *)&Value,
  1187. sizeof(DWORD) );
  1188. } else {
  1189. //
  1190. // The user has asked us to simply remove these 'checked' flags
  1191. // from the services that we've examined.
  1192. //
  1193. RegDeleteValue( hKey,
  1194. TEXT("SetupChecked") );
  1195. RegCloseKey( hKey );
  1196. return 0;
  1197. }
  1198. //
  1199. // Check the start value of our target service. If it's disabled,
  1200. // then we don't have an incompatibility.
  1201. //
  1202. ValueSize = sizeof(Value);
  1203. Error = RegQueryValueEx(
  1204. hKey,
  1205. TEXT("Start"),
  1206. NULL,
  1207. NULL,
  1208. (LPBYTE)&Value,
  1209. &ValueSize
  1210. );
  1211. if( (Error == ERROR_SUCCESS) && (Value == SERVICE_DISABLED) ){
  1212. RegCloseKey( hKey );
  1213. return 0;
  1214. }
  1215. RegCloseKey( hKey );
  1216. //
  1217. // Check the version of a file for the service. If only some
  1218. // versions are bad, then we may or may not have an incompatibility.
  1219. //
  1220. FileName[0] = NULL;
  1221. FileVersion[0] = NULL;
  1222. SetupGetStringField( InfContext, 6, FileName, ARRAYSIZE( Buffer3 ), NULL);
  1223. SetupGetStringField( InfContext, 7, FileVersion, ARRAYSIZE( FileVersion ), NULL);
  1224. SetupGetIntField( InfContext, 8 , &Flags);
  1225. Flags |= GlobalCompFlags;
  1226. if( *FileName && *FileVersion ){
  1227. if( !CheckForFileVersion( FileName, FileVersion ) )
  1228. return 0;
  1229. }
  1230. //
  1231. // if we're only incompatible if the service is actually running at the
  1232. // moment, then check that. Note that we check for the service being
  1233. // stopped instead of running, as we don't want to the service to be in
  1234. // some pending state when we continue on.
  1235. //
  1236. if (Flags & COMPFLAG_SERVICERUNNING) {
  1237. if (IsServiceStopped(Buffer)) {
  1238. return 0;
  1239. }
  1240. }
  1241. RegData = (LPDWORD)MALLOC( sizeof(DWORD) );
  1242. if (RegData == NULL) {
  1243. return 0;
  1244. }
  1245. CompData = (PRIPREP_COMPATIBILITY_DATA) MALLOC( sizeof(RIPREP_COMPATIBILITY_DATA) );
  1246. if (CompData == NULL) {
  1247. FREE(RegData);
  1248. return 0;
  1249. }
  1250. ZeroMemory(CompData,sizeof(RIPREP_COMPATIBILITY_DATA));
  1251. CompData->ServiceName = DupString(Buffer);
  1252. SetupGetStringField( InfContext, 3, Buffer, ARRAYSIZE( Buffer ), NULL);
  1253. CompData->HtmlName = DupString(Buffer);
  1254. SetupGetStringField( InfContext, 4, Buffer, ARRAYSIZE( Buffer ), NULL);
  1255. CompData->TextName = DupString(Buffer);
  1256. Buffer[0] = UNICODE_NULL;
  1257. SetupGetStringField( InfContext, 5, Buffer, ARRAYSIZE( Buffer ), NULL);
  1258. if (Buffer[0] == UNICODE_NULL) {
  1259. if (!MyGetServiceDescription(CompData->ServiceName,Buffer,ARRAYSIZE(Buffer))) {
  1260. LPVOID Args[2];
  1261. dw = LoadString(g_hinstance,IDS_SERVICE_DESC_UNKNOWN,Buffer2,ARRAYSIZE(Buffer2));
  1262. Assert( dw );
  1263. dw = LoadString(g_hinstance,IDS_SERVICE_DESC_FORMAT,Buffer3,ARRAYSIZE(Buffer3));
  1264. Assert( dw );
  1265. Args[0] = (LPVOID)CompData->ServiceName;
  1266. Args[1] = (LPVOID)Buffer2;
  1267. FormatMessage(
  1268. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1269. Buffer3,
  1270. 0,
  1271. 0,
  1272. Buffer,
  1273. ARRAYSIZE(Buffer), // size of buffer
  1274. (va_list*) &Args ); // arguments
  1275. }
  1276. }
  1277. CompData->Description = DupString(Buffer);
  1278. CompData->RegKeyName = DupString( KeyName );
  1279. CompData->RegValName = DupString( TEXT("Start") );
  1280. RegData[0] = 4;
  1281. CompData->RegValData = RegData;
  1282. CompData->RegValDataSize = sizeof(DWORD);
  1283. CompData->Flags |= Flags ;
  1284. EnterCriticalSection(&CompatibilityCS);
  1285. InsertTailList( &CompatibilityData, &CompData->ListEntry );
  1286. LeaveCriticalSection(&CompatibilityCS);
  1287. return 1;
  1288. }
  1289. DWORD
  1290. ProcessFileLine(
  1291. PINFCONTEXT InfContext
  1292. )
  1293. {
  1294. PRIPREP_COMPATIBILITY_DATA CompData;
  1295. TCHAR FileName[MAX_PATH];
  1296. TCHAR FileVer[100];
  1297. INT Flags;
  1298. FileVer[0] = NULL;
  1299. FileName[0] = NULL;
  1300. SetupGetStringField( InfContext, 2, FileName, ARRAYSIZE( FileName ), NULL);
  1301. SetupGetStringField( InfContext, 3, FileVer, ARRAYSIZE( FileVer ), NULL);
  1302. if( *FileName ){
  1303. if( !CheckForFileVersion( FileName, FileVer ) )
  1304. return 0;
  1305. } else{
  1306. return 0;
  1307. }
  1308. CompData = (PRIPREP_COMPATIBILITY_DATA) MALLOC( sizeof(RIPREP_COMPATIBILITY_DATA) );
  1309. if (CompData == NULL) {
  1310. return 0;
  1311. }
  1312. ZeroMemory(CompData,sizeof(RIPREP_COMPATIBILITY_DATA));
  1313. CompData->FileName = DupString( FileName );
  1314. CompData->FileVer = DupString( FileVer );
  1315. SetupGetStringField( InfContext, 4, FileName, ARRAYSIZE( FileName ), NULL);
  1316. CompData->HtmlName = DupString( FileName );
  1317. SetupGetStringField( InfContext, 5, FileName, ARRAYSIZE( FileName ), NULL);
  1318. CompData->TextName = DupString( FileName );
  1319. SetupGetStringField( InfContext, 6, FileName, ARRAYSIZE( FileName ), NULL);
  1320. CompData->Description = DupString( FileName );
  1321. Flags = 0;
  1322. SetupGetIntField( InfContext, 7 , &Flags);
  1323. CompData->Flags |= (GlobalCompFlags | Flags);
  1324. EnterCriticalSection(&CompatibilityCS);
  1325. InsertTailList( &CompatibilityData, &CompData->ListEntry );
  1326. LeaveCriticalSection(&CompatibilityCS);
  1327. return 1;
  1328. }
  1329. BOOL
  1330. CompatibilityCallback(
  1331. PRIPREP_COMPATIBILITY_ENTRY CompEntry,
  1332. PRIPREP_COMPATIBILITY_CONTEXT CompContext
  1333. )
  1334. {
  1335. PRIPREP_COMPATIBILITY_DATA CompData;
  1336. //
  1337. // parameter validation
  1338. //
  1339. if (CompEntry->Description == NULL || CompEntry->Description[0] == 0) {
  1340. SetLastError( COMP_ERR_DESC_MISSING );
  1341. return FALSE;
  1342. }
  1343. if (CompEntry->TextName == NULL || CompEntry->TextName[0] ==0) {
  1344. SetLastError( COMP_ERR_TEXTNAME_MISSING );
  1345. return FALSE;
  1346. }
  1347. if (CompEntry->RegKeyName) {
  1348. if (CompEntry->RegValName == NULL) {
  1349. SetLastError( COMP_ERR_REGVALNAME_MISSING );
  1350. return FALSE;
  1351. }
  1352. if (CompEntry->RegValData == NULL) {
  1353. SetLastError( COMP_ERR_REGVALDATA_MISSING );
  1354. return FALSE;
  1355. }
  1356. }
  1357. #ifdef UNICODE
  1358. if (IsTextUnicode( CompEntry->Description, wcslen(CompEntry->Description)*sizeof(WCHAR), NULL ) == 0) {
  1359. SetLastError( COMP_ERR_DESC_NOT_UNICODE );
  1360. return FALSE;
  1361. }
  1362. if (IsTextUnicode( CompEntry->TextName, wcslen(CompEntry->TextName)*sizeof(WCHAR), NULL ) == 0) {
  1363. SetLastError( COMP_ERR_TEXTNAME_NOT_UNICODE );
  1364. return FALSE;
  1365. }
  1366. if (CompEntry->HtmlName) {
  1367. if (IsTextUnicode( CompEntry->HtmlName, wcslen(CompEntry->HtmlName)*sizeof(WCHAR), NULL ) == 0) {
  1368. SetLastError( COMP_ERR_HTMLNAME_NOT_UNICODE );
  1369. return FALSE;
  1370. }
  1371. }
  1372. if (CompEntry->RegKeyName) {
  1373. if (IsTextUnicode( CompEntry->RegKeyName, wcslen(CompEntry->RegKeyName)*sizeof(WCHAR), NULL ) == 0) {
  1374. SetLastError( COMP_ERR_REGKEYNAME_NOT_UNICODE );
  1375. return FALSE;
  1376. }
  1377. if (IsTextUnicode( CompEntry->RegValName, wcslen(CompEntry->RegValName)*sizeof(WCHAR), NULL ) == 0) {
  1378. SetLastError( COMP_ERR_REGVALNAME_NOT_UNICODE );
  1379. return FALSE;
  1380. }
  1381. }
  1382. #endif
  1383. //
  1384. // allocate the compatibility structure
  1385. //
  1386. CompData = (PRIPREP_COMPATIBILITY_DATA) MALLOC( sizeof(RIPREP_COMPATIBILITY_DATA) );
  1387. if (CompData == NULL) {
  1388. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1389. return FALSE;
  1390. }
  1391. ZeroMemory(CompData, sizeof(RIPREP_COMPATIBILITY_DATA));
  1392. //
  1393. // save the sata
  1394. //
  1395. CompData->Description = DupString( CompEntry->Description );
  1396. CompData->HtmlName = CompEntry->HtmlName ? DupString( CompEntry->HtmlName ) : NULL;
  1397. CompData->TextName = DupString( CompEntry->TextName );
  1398. CompData->Flags = CompEntry->Flags;
  1399. CompData->Flags |= CompContext->Flags;
  1400. CompData->Flags |= GlobalCompFlags;
  1401. CompData->hModDll = CompContext->hModDll;
  1402. CompData->MsgResourceId = CompEntry->MsgResourceId;
  1403. if (CompEntry->RegKeyName) {
  1404. CompData->RegKeyName = DupString( CompEntry->RegKeyName );
  1405. CompData->RegValName = DupString( CompEntry->RegValName );
  1406. CompData->RegValDataSize = CompEntry->RegValDataSize;
  1407. CompData->RegValData = MALLOC(CompEntry->RegValDataSize);
  1408. if (CompData->RegValData) {
  1409. CopyMemory( CompData->RegValData, CompEntry->RegValData, CompEntry->RegValDataSize );
  1410. }
  1411. }
  1412. EnterCriticalSection(&CompatibilityCS);
  1413. InsertTailList( &CompatibilityData, &CompData->ListEntry );
  1414. LeaveCriticalSection(&CompatibilityCS);
  1415. CompContext->Count += 1;
  1416. return TRUE;
  1417. }
  1418. DWORD
  1419. ProcessDLLLine(
  1420. PINFCONTEXT InfContext
  1421. )
  1422. {
  1423. TCHAR Buffer[MAX_PATH];
  1424. HMODULE hMod;
  1425. CHAR CompCheckEntryPoint[MAX_PATH];
  1426. PCOMPATIBILITYCHECK CompCheck;
  1427. TCHAR DllName[100];
  1428. TCHAR CompCheckEntryPointW[100];
  1429. LPTSTR ProcessOnCleanInstall;
  1430. INT AllowCompatibilityErrorOnNT5;
  1431. RIPREP_COMPATIBILITY_CONTEXT CompContext;
  1432. BOOL Rslt;
  1433. DWORD Status;
  1434. SetupGetStringField( InfContext, 2, DllName, ARRAYSIZE( DllName ), NULL);
  1435. SetupGetStringField( InfContext, 3, CompCheckEntryPointW, ARRAYSIZE( CompCheckEntryPointW ), NULL);
  1436. SetupGetIntField( InfContext, 6, &AllowCompatibilityErrorOnNT5);
  1437. if (!ExpandEnvironmentStrings( DllName, Buffer, ARRAYSIZE(Buffer) )) {
  1438. return 0;
  1439. }
  1440. hMod = LoadLibrary( Buffer );
  1441. if (hMod == NULL) {
  1442. return 0;
  1443. }
  1444. #ifdef UNICODE
  1445. WideCharToMultiByte(
  1446. CP_ACP,
  1447. 0,
  1448. CompCheckEntryPointW,
  1449. -1,
  1450. CompCheckEntryPoint,
  1451. sizeof(CompCheckEntryPoint),
  1452. NULL,
  1453. NULL
  1454. );
  1455. #else
  1456. lstrcpy( CompCheckEntryPoint, CompCheckEntryPointW );
  1457. #endif
  1458. CompCheck = (PCOMPATIBILITYCHECK) GetProcAddress( hMod, CompCheckEntryPoint );
  1459. if (CompCheck == NULL) {
  1460. FreeLibrary( hMod );
  1461. return 0;
  1462. }
  1463. CompContext.SizeOfStruct = sizeof(CompContext);
  1464. CompContext.Count = 0;
  1465. CompContext.hModDll = hMod;
  1466. CompContext.Flags = (AllowCompatibilityErrorOnNT5) ? COMPFLAG_ALLOWNT5COMPAT : 0;
  1467. if ((OsVersion.dwMajorVersion < 5 )
  1468. && ((CompContext.Flags & COMPFLAG_ALLOWNT5COMPAT)==0)) {
  1469. Rslt = FALSE;
  1470. } else {
  1471. __try {
  1472. Rslt = CompCheck( (PCOMPATIBILITYCALLBACK)CompatibilityCallback, (LPVOID)&CompContext );
  1473. } __except(EXCEPTION_EXECUTE_HANDLER) {
  1474. Status = GetExceptionCode();
  1475. Rslt = FALSE;
  1476. }
  1477. }
  1478. if (!Rslt) {
  1479. FreeLibrary( hMod );
  1480. return 0;
  1481. }
  1482. if (CompContext.Count == 0) {
  1483. FreeLibrary( hMod );
  1484. }
  1485. return CompContext.Count;
  1486. }
  1487. DWORD
  1488. ProcessCompatibilitySection(
  1489. HINF hInf,
  1490. LPTSTR SectionName
  1491. )
  1492. {
  1493. DWORD LineCount;
  1494. DWORD Count;
  1495. DWORD i;
  1496. TCHAR Type[20];
  1497. DWORD Good;
  1498. INFCONTEXT InfContext;
  1499. //
  1500. // get the section count, zero means bail out
  1501. //
  1502. LineCount = SetupGetLineCount( hInf, SectionName );
  1503. if (LineCount == 0 || LineCount == 0xffffffff) {
  1504. return 0;
  1505. }
  1506. for (i=0,Count=0; i<LineCount; i++) {
  1507. if (SetupGetLineByIndex( hInf , SectionName, i, &InfContext ) &&
  1508. SetupGetStringField( &InfContext, 1, Type, ARRAYSIZE( Type ), NULL)) {
  1509. switch (_totlower(Type[0])) {
  1510. case TEXT('r'):
  1511. //
  1512. // registry value
  1513. //
  1514. Count += ProcessRegistryLine( &InfContext );
  1515. break;
  1516. case TEXT('s'):
  1517. //
  1518. // service or driver
  1519. //
  1520. Count += ProcessServiceLine( &InfContext, TRUE );
  1521. break;
  1522. case TEXT('f'):
  1523. //
  1524. // presence of a file
  1525. //
  1526. Count += ProcessFileLine( &InfContext );
  1527. break;
  1528. case TEXT('d'):
  1529. //
  1530. // run an external dll
  1531. //
  1532. Count += ProcessDLLLine( &InfContext );
  1533. break;
  1534. default:
  1535. break;
  1536. }
  1537. }
  1538. }
  1539. return Count;
  1540. }
  1541. VOID
  1542. RemoveCompatibilityServiceEntries(
  1543. HINF hInf,
  1544. LPTSTR SectionName
  1545. )
  1546. {
  1547. DWORD LineCount;
  1548. DWORD Count;
  1549. DWORD i;
  1550. TCHAR Type[20];
  1551. DWORD Good;
  1552. INFCONTEXT InfContext;
  1553. //
  1554. // get the section count, zero means bail out
  1555. //
  1556. LineCount = SetupGetLineCount( hInf , SectionName );
  1557. if (LineCount == 0 || LineCount == 0xffffffff) {
  1558. return;
  1559. }
  1560. for (i=0,Count=0; i<LineCount; i++) {
  1561. if (SetupGetLineByIndex( hInf , SectionName, i, &InfContext ) &&
  1562. SetupGetStringField( &InfContext, 1, Type, ARRAYSIZE( Type ), NULL)) {
  1563. switch (_totlower(Type[0])) {
  1564. case TEXT('s'):
  1565. //
  1566. // service or driver
  1567. //
  1568. Count += ProcessServiceLine( &InfContext, FALSE );
  1569. break;
  1570. default:
  1571. break;
  1572. }
  1573. }
  1574. }
  1575. }
  1576. BOOL
  1577. ProcessCompatibilityData(
  1578. VOID
  1579. )
  1580. {
  1581. HINF hInf;
  1582. TCHAR Path[MAX_PATH], *p;
  1583. if( !CompatibilityData.Flink ) {
  1584. InitializeListHead( &CompatibilityData );
  1585. InitializeCriticalSection( &CompatibilityCS );
  1586. } else {
  1587. Assert(FALSE);
  1588. return (CompatibilityCount != 0);
  1589. }
  1590. GetModuleFileName( NULL, Path, ARRAYSIZE( Path ));
  1591. if (p = _tcsrchr(Path, TEXT('\\'))) {
  1592. *p = NULL;
  1593. lstrcat(Path, TEXT("\\riprep.inf"));
  1594. hInf = SetupOpenInfFile(
  1595. Path,
  1596. NULL,
  1597. INF_STYLE_WIN4,
  1598. NULL );
  1599. if (hInf == INVALID_HANDLE_VALUE) {
  1600. return(TRUE);
  1601. }
  1602. }
  1603. g_hCompatibilityInf = hInf;
  1604. GlobalCompFlags = COMPFLAG_STOPINSTALL;
  1605. CompatibilityCount = 0;
  1606. CompatibilityCount += ProcessCompatibilitySection(hInf, TEXT("ServicesToStopInstallation") );
  1607. if (CompatibilityCount) {
  1608. IncompatibilityStopsInstallation = TRUE;
  1609. }
  1610. GlobalCompFlags = 0;
  1611. CompatibilityCount += ProcessCompatibilitySection(hInf, TEXT("ServicesToWarn") );
  1612. GlobalCompFlags = COMPFLAG_SERVICERUNNING | COMPFLAG_CHANGESTATE;
  1613. ServicesToStopCount = ProcessCompatibilitySection(hInf, TEXT("ServicesToStop") );
  1614. //
  1615. // Now cleanup any turds we left in the registry on the services we checked.
  1616. //
  1617. RemoveCompatibilityServiceEntries(hInf, TEXT("ServicesToStopInstallation") );
  1618. RemoveCompatibilityServiceEntries(hInf, TEXT("ServicesToWarn") );
  1619. RemoveCompatibilityServiceEntries(hInf, TEXT("ServicesToStop") );
  1620. if( CompatibilityCount ) {
  1621. return TRUE;
  1622. } else {
  1623. return FALSE;
  1624. }
  1625. }
  1626. BOOL CleanupCompatibilityData(
  1627. VOID
  1628. )
  1629. {
  1630. PLIST_ENTRY Next = CompatibilityData.Flink;
  1631. PRIPREP_COMPATIBILITY_DATA CompData;
  1632. if (CompatibilityData.Flink) {
  1633. EnterCriticalSection(&CompatibilityCS);
  1634. while ((ULONG_PTR)Next != (ULONG_PTR)&CompatibilityData) {
  1635. CompData = CONTAINING_RECORD( Next, RIPREP_COMPATIBILITY_DATA, ListEntry );
  1636. RemoveEntryList( &CompData->ListEntry );
  1637. Next = CompData->ListEntry.Flink;
  1638. if (CompData->ServiceName) {
  1639. FREE(CompData->ServiceName);
  1640. }
  1641. if (CompData->RegKey) {
  1642. FREE(CompData->RegKey);
  1643. }
  1644. if (CompData->RegValue) {
  1645. FREE(CompData->RegValue);
  1646. }
  1647. if (CompData->RegValueExpect) {
  1648. FREE(CompData->RegValueExpect);
  1649. }
  1650. if (CompData->FileName) {
  1651. FREE(CompData->FileName);
  1652. }
  1653. if (CompData->FileVer) {
  1654. FREE(CompData->FileVer);
  1655. }
  1656. if (CompData->Description) {
  1657. FREE(CompData->Description);
  1658. }
  1659. if (CompData->HtmlName) {
  1660. FREE(CompData->HtmlName);
  1661. }
  1662. if (CompData->TextName) {
  1663. FREE(CompData->TextName);
  1664. }
  1665. if (CompData->RegKeyName) {
  1666. FREE(CompData->RegKeyName);
  1667. }
  1668. if (CompData->RegValName) {
  1669. FREE(CompData->RegValName);
  1670. }
  1671. if (CompData->RegValData) {
  1672. FREE(CompData->RegValData);
  1673. }
  1674. FREE(CompData);
  1675. }
  1676. LeaveCriticalSection(&CompatibilityCS);
  1677. }
  1678. return(TRUE);
  1679. }