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.

686 lines
18 KiB

  1. #include "setupp.h"
  2. #pragma hdrstop
  3. ////////////////////////////////////////////
  4. //
  5. // Action item list control
  6. //
  7. ////////////////////////////////////////////
  8. //
  9. // Define locations in extra window storage
  10. //
  11. #define AIL_FONT (0)
  12. #define AIL_BOLDFONT (AIL_FONT + sizeof(PVOID))
  13. #define AIL_TEXT (AIL_BOLDFONT + sizeof(PVOID))
  14. #define AIL_BOLDITEM (AIL_TEXT + sizeof(PVOID))
  15. #define AIL_LINECOUNT (AIL_BOLDITEM + sizeof(LONG))
  16. #define AIL_FREEFONTS (AIL_LINECOUNT + sizeof(LONG))
  17. #define AIL_EXTRA ((3 * sizeof(PVOID)) + (3 * sizeof(LONG)))
  18. PCWSTR szActionItemListClassName = L"$$$ActionItemList";
  19. VOID
  20. ActionItemListPaint(
  21. IN HWND hwnd
  22. )
  23. {
  24. PAINTSTRUCT PaintStruct;
  25. PWSTR p,Text;
  26. UINT LineCount;
  27. HFONT OldFont,Font,BoldFont;
  28. UINT HighlightedItem;
  29. UINT i;
  30. int Length;
  31. int y;
  32. int yDelta;
  33. HBITMAP Bitmap,OldBitmap;
  34. BITMAP bitmap;
  35. HDC MemoryDC;
  36. SIZE Size;
  37. RECT rect;
  38. int Spacing;
  39. int oldmode;
  40. #define BORDER 3
  41. if(!BeginPaint(hwnd,&PaintStruct)) {
  42. return;
  43. }
  44. //
  45. // If no text, nothing to do.
  46. //
  47. if(Text = (PWSTR)GetWindowLongPtr(hwnd,AIL_TEXT)) {
  48. LineCount = (UINT)GetWindowLong(hwnd,AIL_LINECOUNT);
  49. }
  50. if(!Text || !LineCount) {
  51. return;
  52. }
  53. //
  54. // Get value indicating which item is to be bolded.
  55. //
  56. HighlightedItem = (UINT)GetWindowLong(hwnd,AIL_BOLDITEM);
  57. //
  58. // Get font handles.
  59. //
  60. Font = (HFONT)GetWindowLongPtr(hwnd,AIL_FONT);
  61. BoldFont = (HFONT)GetWindowLongPtr(hwnd,AIL_BOLDFONT);
  62. //
  63. // Select the non-boldface font to get the handle of
  64. // the currently selected font.
  65. //
  66. OldFont = SelectObject(PaintStruct.hdc,Font);
  67. oldmode = SetBkMode(PaintStruct.hdc,TRANSPARENT);
  68. //
  69. // Load the little triangle bitmap and create a compatible DC for it.
  70. //
  71. Bitmap = LoadBitmap(NULL,MAKEINTRESOURCE(OBM_MNARROW));
  72. if(MemoryDC = CreateCompatibleDC(PaintStruct.hdc)) {
  73. OldBitmap = SelectObject(MemoryDC,Bitmap);
  74. GetObject(Bitmap,sizeof(BITMAP),&bitmap);
  75. }
  76. Spacing = GetSystemMetrics(SM_CXICON) / 2;
  77. //
  78. // Treat the text as a series of lines and draw each one.
  79. //
  80. p = Text;
  81. y = 0;
  82. for(i=0; i<LineCount; i++) {
  83. SetBkColor(PaintStruct.hdc,GetSysColor(COLOR_3DFACE));
  84. //
  85. // Calculate the line's height based on the boldface font.
  86. // This is used to get to the y coord of the next line.
  87. //
  88. SelectObject(PaintStruct.hdc,BoldFont);
  89. GetClientRect(hwnd,&rect);
  90. rect.left = (2 * BORDER) + Spacing;
  91. rect.bottom = 0;
  92. DrawText(PaintStruct.hdc,p,lstrlen(p),&rect,DT_CALCRECT|DT_WORDBREAK);
  93. yDelta = rect.bottom + (2*BORDER);
  94. //
  95. // Change font to non-boldface for this line if necessary.
  96. //
  97. if(i != HighlightedItem) {
  98. SelectObject(PaintStruct.hdc,Font);
  99. }
  100. rect.top = y + BORDER;
  101. rect.left = (2 * BORDER) + Spacing;
  102. rect.bottom = rect.top + yDelta;
  103. //
  104. // Draw the line's text.
  105. //
  106. Length = lstrlen(p);
  107. DrawText(PaintStruct.hdc,p,Length,&rect,DT_WORDBREAK);
  108. //
  109. // Draw the little triangle thing if necessary.
  110. //
  111. if((i == HighlightedItem) && Bitmap && MemoryDC) {
  112. GetTextExtentPoint(PaintStruct.hdc,L"WWWWW",5,&Size);
  113. //
  114. // The arrow bitmap is monochrome. When blitted, 1-bits in the source
  115. // are converted to the text color in the destination DC and 0-bits
  116. // are converted to the background color. The effect we want to achieve
  117. // is to turn off in the destination bits that are 1 in the bitmap
  118. // and leave alone in the destination bits that are 0 in the bitmap.
  119. // Set the text color to all 0s and the background color to all 1s.
  120. // x AND 1 = x so background pixels stay undisturbed, and x AND 0 = 0
  121. // so foreground pixels get turned off.
  122. //
  123. SetBkColor(PaintStruct.hdc,RGB(255,255,255));
  124. BitBlt(
  125. PaintStruct.hdc,
  126. BORDER,
  127. y + ((Size.cy - bitmap.bmHeight) / 2) + BORDER,
  128. bitmap.bmWidth,
  129. bitmap.bmHeight,
  130. MemoryDC,
  131. 0,0,
  132. SRCAND
  133. );
  134. }
  135. //
  136. // Point to next line's text.
  137. //
  138. p += Length + 1;
  139. y += yDelta;
  140. }
  141. //
  142. // Clean up.
  143. //
  144. SetBkMode(PaintStruct.hdc,oldmode);
  145. if(OldFont) {
  146. SelectObject(PaintStruct.hdc,OldFont);
  147. }
  148. if(MemoryDC) {
  149. if(OldBitmap) {
  150. SelectObject(MemoryDC,OldBitmap);
  151. }
  152. if(Bitmap) {
  153. DeleteObject(Bitmap);
  154. }
  155. DeleteDC(MemoryDC);
  156. }
  157. EndPaint(hwnd,&PaintStruct);
  158. }
  159. LRESULT
  160. ActionItemListWndProc(
  161. IN HWND hwnd,
  162. IN UINT msg,
  163. IN WPARAM wParam,
  164. IN LPARAM lParam
  165. )
  166. {
  167. LRESULT rc;
  168. HFONT OldFont,Font,BoldFont;
  169. LOGFONT LogFont;
  170. PWSTR Text;
  171. PWSTR p;
  172. UINT LineCount;
  173. BOOL FreeFont,FreeBoldFont;
  174. switch(msg) {
  175. case WM_CREATE:
  176. //
  177. // Create fonts.
  178. //
  179. OldFont = (HFONT)SendMessage(GetParent(hwnd),WM_GETFONT,0,0);
  180. if(!OldFont) {
  181. //
  182. // Using system font.
  183. //
  184. OldFont = GetStockObject(DEFAULT_GUI_FONT);
  185. }
  186. FreeFont = TRUE;
  187. FreeBoldFont = TRUE;
  188. if(OldFont && GetObject(OldFont,sizeof(LOGFONT),&LogFont)) {
  189. LogFont.lfWeight = 400;
  190. Font = CreateFontIndirect(&LogFont);
  191. if(!Font) {
  192. Font = GetStockObject(DEFAULT_GUI_FONT);
  193. FreeFont = FALSE;
  194. }
  195. LogFont.lfWeight = 700;
  196. BoldFont = CreateFontIndirect(&LogFont);
  197. if(!BoldFont) {
  198. BoldFont = Font;
  199. FreeBoldFont = FALSE;
  200. }
  201. }
  202. SetWindowLongPtr(hwnd,AIL_FONT,(LONG_PTR)Font);
  203. SetWindowLongPtr(hwnd,AIL_BOLDFONT,(LONG_PTR)BoldFont);
  204. SetWindowLong(hwnd,AIL_BOLDITEM,0);
  205. SetWindowLongPtr(hwnd,AIL_TEXT,0);
  206. SetWindowLong(hwnd,AIL_LINECOUNT,0);
  207. SetWindowLong(hwnd,AIL_FREEFONTS,MAKELONG(FreeFont,FreeBoldFont));
  208. rc = 0;
  209. break;
  210. case WM_DESTROY:
  211. //
  212. // Get rid of fonts we created if necessary.
  213. //
  214. FreeFont = (BOOL)GetWindowLong(hwnd,AIL_FREEFONTS);
  215. FreeBoldFont = HIWORD(FreeFont);
  216. FreeFont = LOWORD(FreeFont);
  217. if(FreeFont && (Font = (HFONT)GetWindowLongPtr(hwnd,AIL_FONT))) {
  218. DeleteObject(Font);
  219. }
  220. if(FreeBoldFont && (BoldFont = (HFONT)GetWindowLongPtr(hwnd,AIL_BOLDFONT))) {
  221. DeleteObject(BoldFont);
  222. }
  223. if(Text = (PWSTR)GetWindowLongPtr(hwnd,AIL_TEXT)) {
  224. MyFree(Text);
  225. }
  226. rc = 0;
  227. break;
  228. case WM_SETTEXT:
  229. //
  230. // Free old text and remember new text.
  231. //
  232. if(Text = (PWSTR)GetWindowLongPtr(hwnd,AIL_TEXT)) {
  233. MyFree(Text);
  234. }
  235. LineCount = 0;
  236. if(Text = pSetupDuplicateString((PVOID)lParam)) {
  237. //
  238. // Count lines in the text. This is equal to the number of
  239. // newlines. We require that the last line have a newline
  240. // to be counted.
  241. //
  242. for(LineCount=0,p=Text; *p; p++) {
  243. if(*p == L'\r') {
  244. *p = L' ';
  245. } else {
  246. if(*p == L'\n') {
  247. *p = 0;
  248. LineCount++;
  249. }
  250. }
  251. }
  252. }
  253. //
  254. // Cheat a little: we expect wParam to be the 0-based index
  255. // of the boldfaced line. Callers will have to use SendMessage
  256. // instead of SetWindowText().
  257. //
  258. SetWindowLong(hwnd,AIL_BOLDITEM,(LONG)wParam);
  259. SetWindowLong(hwnd,AIL_LINECOUNT,LineCount);
  260. SetWindowLongPtr(hwnd,AIL_TEXT,(LONG_PTR)Text);
  261. rc = (Text != NULL);
  262. break;
  263. case WM_ERASEBKGND:
  264. //
  265. // Indicate that the background was erased successfully to prevent
  266. // any further processing. This allows us to lay text transparently
  267. // over any background bitmap on the dialog.
  268. //
  269. rc = TRUE;
  270. break;
  271. case WM_PAINT:
  272. ActionItemListPaint(hwnd);
  273. rc = 0;
  274. break;
  275. default:
  276. rc = DefWindowProc(hwnd,msg,wParam,lParam);
  277. break;
  278. }
  279. return(rc);
  280. }
  281. BOOL
  282. RegisterActionItemListControl(
  283. IN BOOL Init
  284. )
  285. {
  286. WNDCLASS wc;
  287. BOOL b;
  288. static BOOL Registered;
  289. if(Init) {
  290. if(Registered) {
  291. b = TRUE;
  292. } else {
  293. wc.style = CS_PARENTDC;
  294. wc.lpfnWndProc = ActionItemListWndProc;
  295. wc.cbClsExtra = 0;
  296. wc.cbWndExtra = AIL_EXTRA;
  297. wc.hInstance = MyModuleHandle;
  298. wc.hIcon = NULL;
  299. wc.hCursor = LoadCursor(NULL,IDC_ARROW);
  300. wc.hbrBackground = NULL; // want to get WM_ERASEBKGND messages
  301. wc.lpszMenuName = NULL;
  302. wc.lpszClassName = szActionItemListClassName;
  303. if(b = (RegisterClass(&wc) != 0)) {
  304. Registered = TRUE;
  305. }
  306. }
  307. } else {
  308. if(Registered) {
  309. if(b = UnregisterClass(szActionItemListClassName,MyModuleHandle)) {
  310. Registered = FALSE;
  311. }
  312. } else {
  313. b = TRUE;
  314. }
  315. }
  316. return(b);
  317. }
  318. typedef struct _SPREG_TO_TEXT {
  319. DWORD FailureCode;
  320. PCWSTR FailureText;
  321. } SPREG_TO_TEXT, *PSPREG_TO_TEXT;
  322. SPREG_TO_TEXT RegErrorToText[] = {
  323. { SPREG_SUCCESS, L"Success" },
  324. { SPREG_LOADLIBRARY, L"LoadLibrary" },
  325. { SPREG_GETPROCADDR, L"GetProcAddress" },
  326. { SPREG_REGSVR, L"DllRegisterServer" },
  327. { SPREG_DLLINSTALL, L"DllInstall" },
  328. { SPREG_TIMEOUT, L"Timed out" },
  329. { SPREG_UNKNOWN, L"Unknown" },
  330. { 0, NULL }
  331. };
  332. UINT
  333. RegistrationQueueCallback(
  334. IN PVOID Context,
  335. IN UINT Notification,
  336. IN UINT_PTR Param1,
  337. IN UINT_PTR Param2
  338. )
  339. /*++
  340. Routine Description:
  341. Callback routine that is called each time we self-register a file.
  342. Arguments:
  343. Context - context message passed from parent to caller.
  344. Notification - specifies an SPFILENOTIFY_*** code, which tells us how
  345. to interpret Param1 and Param2.
  346. Param1 - dependent on notification.
  347. Param2 - dependent on notification.
  348. Return Value:
  349. FILEOP_*** code dependent on Notification code.
  350. --*/
  351. {
  352. PSP_REGISTER_CONTROL_STATUS Status = (PSP_REGISTER_CONTROL_STATUS)Param1;
  353. PREGISTRATION_CONTEXT RegistrationContext = (PREGISTRATION_CONTEXT) Context;
  354. DWORD i, ErrorMessageId;
  355. PCWSTR p;
  356. if (Notification == SPFILENOTIFY_STARTREGISTRATION) {
  357. //
  358. // log that we're starting registration and update the progress
  359. // guage as well.
  360. //
  361. SetupDebugPrint1(
  362. L"SETUP: file to register is %s...",
  363. Status->FileName);
  364. if (RegistrationContext->hWndProgress) {
  365. SendMessage(
  366. RegistrationContext->hWndProgress,
  367. PBM_STEPIT,
  368. 0,
  369. 0 );
  370. }
  371. return FILEOP_DOIT;
  372. }
  373. if (Notification == SPFILENOTIFY_ENDREGISTRATION) {
  374. //
  375. // the file has been registered, so log failure if necessary
  376. // Note that we have a special code for timeouts
  377. //
  378. switch(Status->FailureCode) {
  379. case SPREG_SUCCESS:
  380. SetupDebugPrint1(
  381. L"SETUP: %s registered successfully",
  382. Status->FileName);
  383. break;
  384. case SPREG_TIMEOUT:
  385. SetuplogError(
  386. LogSevError,
  387. SETUPLOG_USE_MESSAGEID,
  388. MSG_OLE_REGISTRATION_HUNG,
  389. Status->FileName,
  390. NULL,NULL);
  391. SetupDebugPrint1(
  392. L"SETUP: %s timed out during registration",
  393. Status->FileName);
  394. break;
  395. default:
  396. //
  397. // log an error
  398. //
  399. for (i = 0;RegErrorToText[i].FailureText != NULL;i++) {
  400. if (RegErrorToText[i].FailureCode == Status->FailureCode) {
  401. p = RegErrorToText[i].FailureText;
  402. if ((Status->FailureCode == SPREG_LOADLIBRARY) &&
  403. (Status->Win32Error == ERROR_MOD_NOT_FOUND))
  404. ErrorMessageId = MSG_LOG_X_MOD_NOT_FOUND;
  405. else
  406. if ((Status->FailureCode == SPREG_GETPROCADDR) &&
  407. (Status->Win32Error == ERROR_PROC_NOT_FOUND))
  408. ErrorMessageId = MSG_LOG_X_PROC_NOT_FOUND;
  409. else
  410. ErrorMessageId = MSG_LOG_X_RETURNED_WINERR;
  411. break;
  412. }
  413. }
  414. if (!p) {
  415. p = L"Unknown";
  416. ErrorMessageId = MSG_LOG_X_RETURNED_WINERR;
  417. }
  418. SetuplogError(
  419. LogSevError,
  420. SETUPLOG_USE_MESSAGEID,
  421. MSG_LOG_OLE_CONTROL_NOT_REGISTERED,
  422. Status->FileName,
  423. NULL,
  424. SETUPLOG_USE_MESSAGEID,
  425. ErrorMessageId,
  426. p,
  427. Status->Win32Error,
  428. NULL,
  429. NULL
  430. );
  431. SetupDebugPrint1(
  432. L"SETUP: %s did not register successfully",
  433. Status->FileName);
  434. }
  435. //
  436. // Verify that the DLL didn't change our unhandled exception filter.
  437. //
  438. if( MyUnhandledExceptionFilter !=
  439. SetUnhandledExceptionFilter(MyUnhandledExceptionFilter)) {
  440. SetupDebugPrint1(
  441. L"SETUP: %ws broke the exception handler.",
  442. Status->FileName );
  443. #if 0
  444. //
  445. // We'll put this in after all the currently broken DLLs are fixed.
  446. //
  447. MessageBoxFromMessage(
  448. RegistrationContext->hwndParent,
  449. MSG_EXCEPTION_FILTER_CHANGED,
  450. NULL,
  451. IDS_WINNT_SETUP,
  452. MB_OK | MB_ICONWARNING,
  453. Status->FileName );
  454. #endif
  455. }
  456. return FILEOP_DOIT;
  457. }
  458. MYASSERT(FALSE);
  459. return(FILEOP_DOIT);
  460. }
  461. BOOL
  462. RegisterOleControls(
  463. IN HWND hwndParent,
  464. IN HINF hInf,
  465. IN HWND hProgress,
  466. IN ULONG StartAtPercent,
  467. IN ULONG StopAtPercent,
  468. IN PWSTR SectionName
  469. )
  470. /*++
  471. Routine Description:
  472. This routine runs down the entries in the specified INF section, and
  473. self-registers each file.
  474. Arguments:
  475. hwndParent - supplies the window handle used for the PRERELEASE message
  476. box that indicates an OLE registration has hung.
  477. InfHandle - supplies handle to inf containing the specified SectionName.
  478. hProgress - handle to progress gauge that gets ticked every time we
  479. process a file.
  480. StartAtPercent - Position where the progress window should start (0% to 100%).
  481. StopAtPercent - Maximum position where the progress window can be moved to (0% to 100%).
  482. SectionName - Supplies the name of the section contained in the INF
  483. specified by InfHandle that lists OLE control DLLs to be
  484. registered/installed.
  485. Return Value:
  486. Boolean value indicating outcome. If a file to be registered is
  487. not present, that is NOT reason for returning false.
  488. --*/
  489. {
  490. UINT GaugeRange;
  491. DWORD SectionCount,LineCount, i;
  492. INFCONTEXT InfContext;
  493. BOOL RetVal = TRUE;
  494. REGISTRATION_CONTEXT RegistrationContext;
  495. RegistrationContext.hWndParent = hwndParent;
  496. RegistrationContext.hWndProgress = hProgress;
  497. LineCount = 0;
  498. //
  499. // Initialize the progress indicator control.
  500. //
  501. if (hProgress) {
  502. //
  503. // find out how many files we have to register
  504. //
  505. if (SetupFindFirstLine(hInf,
  506. SectionName,
  507. TEXT("RegisterDlls"),
  508. &InfContext)) {
  509. do {
  510. SectionCount = SetupGetFieldCount(&InfContext);
  511. for (i = 1; i<=SectionCount; i++) {
  512. PCWSTR IndividualSectionName = pSetupGetField(&InfContext,i);
  513. if (IndividualSectionName) {
  514. LineCount += SetupGetLineCount(hInf, IndividualSectionName);
  515. }
  516. }
  517. } while(SetupFindNextMatchLine(
  518. &InfContext,
  519. TEXT("RegisterDlls"),
  520. &InfContext));
  521. }
  522. MYASSERT((StopAtPercent-StartAtPercent) != 0);
  523. GaugeRange = (LineCount*100/(StopAtPercent-StartAtPercent));
  524. SendMessage(hProgress, WMX_PROGRESSTICKS, LineCount, 0);
  525. SendMessage(hProgress,PBM_SETRANGE,0,MAKELPARAM(0,GaugeRange));
  526. SendMessage(hProgress,PBM_SETPOS,GaugeRange*StartAtPercent/100,0);
  527. SendMessage(hProgress,PBM_SETSTEP,1,0);
  528. }
  529. //
  530. // now allow Setup API to register the files, using our callback to log
  531. // errors if and when they occur.
  532. //
  533. if (!SetupInstallFromInfSection(
  534. hwndParent,
  535. hInf,
  536. SectionName,
  537. SPINST_REGSVR| SPINST_REGISTERCALLBACKAWARE,
  538. NULL,
  539. NULL,
  540. 0,
  541. RegistrationQueueCallback,
  542. (PVOID)&RegistrationContext,
  543. NULL,
  544. NULL
  545. )) {
  546. DWORD d;
  547. RetVal = FALSE;
  548. d = GetLastError();
  549. SetuplogError(
  550. LogSevError,
  551. SETUPLOG_USE_MESSAGEID,
  552. MSG_OLE_REGISTRATION_SECTION_FAILURE,
  553. SectionName,
  554. L"syssetup.inf",
  555. d,
  556. NULL,
  557. SETUPLOG_USE_MESSAGEID,
  558. MSG_LOG_X_RETURNED_WINERR,
  559. szSetupInstallFromInfSection,
  560. d,
  561. NULL,
  562. NULL
  563. );
  564. }
  565. return(RetVal);
  566. }