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.

725 lines
19 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: dispdib32.c
  3. *
  4. * Fakes the display of full screen videos.
  5. *
  6. *
  7. * Created: 23-03-94
  8. * Author: Stephen Estrop [StephenE]
  9. *
  10. * Copyright (c) 1994 Microsoft Corporation
  11. \**************************************************************************/
  12. #include <windows.h>
  13. #include "dispdib.h"
  14. #include "drawdib.h"
  15. /* -------------------------------------------------------------------------
  16. ** Private constants
  17. ** -------------------------------------------------------------------------
  18. */
  19. #define CX_MAX_MOVIE_DEFAULT 640
  20. #define CY_MAX_MOVIE_DEFAULT 480
  21. /* -------------------------------------------------------------------------
  22. ** Private functions prototypes
  23. ** -------------------------------------------------------------------------
  24. */
  25. LRESULT CALLBACK
  26. FullScreenWndProc(
  27. HWND hwnd,
  28. UINT message,
  29. WPARAM wParam,
  30. LPARAM lParam
  31. );
  32. LRESULT CALLBACK
  33. KeyboardHookProc(
  34. int nCode,
  35. WPARAM wParam,
  36. LPARAM lParam
  37. );
  38. UINT
  39. DisplayDibEnter(
  40. LPBITMAPINFOHEADER lpbi,
  41. UINT wFlags
  42. );
  43. void
  44. DisplayDibLeave(
  45. UINT wFlags
  46. );
  47. int
  48. DisplayCalcMovieMultiplier(
  49. int cxOriginal,
  50. int cyOriginal,
  51. DWORD dwCompression
  52. );
  53. /* -------------------------------------------------------------------------
  54. ** Debugging stuff
  55. ** -------------------------------------------------------------------------
  56. */
  57. #if DBG
  58. void
  59. dprintf(
  60. LPSTR lpszFormat,
  61. ...
  62. );
  63. int DebugLevel = 1;
  64. #define dpf( _x_ ) dprintf _x_
  65. #define dpf1( _x_ ) if (DebugLevel >= 1) {dprintf _x_ ;} else
  66. #define dpf2( _x_ ) if (DebugLevel >= 2) {dprintf _x_ ;} else
  67. #define dpf3( _x_ ) if (DebugLevel >= 3) {dprintf _x_ ;} else
  68. #define dpf4( _x_ ) if (DebugLevel >= 4) {dprintf _x_ ;} else
  69. #define dpf5( _x_ ) if (DebugLevel >= 5) {dprintf _x_ ;} else
  70. #else
  71. #define dpf( _x_ )
  72. #define dpf1( _x_ )
  73. #define dpf2( _x_ )
  74. #define dpf3( _x_ )
  75. #define dpf4( _x_ )
  76. #define dpf5( _x_ )
  77. #endif
  78. /* -------------------------------------------------------------------------
  79. ** Private Globals
  80. ** These are only valid in the process that started playing the movie.
  81. ** -------------------------------------------------------------------------
  82. */
  83. HWND hwndFullScreen;
  84. HDC hdcFullScreen;
  85. HDRAWDIB hdd;
  86. BOOL fClassRegistered;
  87. int dxScreen;
  88. int dyScreen;
  89. int iMovieSizeMultiplier;
  90. /* -------------------------------------------------------------------------
  91. ** Global data shared between all processes that attach to this library.
  92. ** This is required to make the keyboard hook work correctly.
  93. ** -------------------------------------------------------------------------
  94. */
  95. #pragma data_seg( ".sdata" )
  96. BOOL fStop;
  97. HHOOK hHookK;
  98. #pragma data_seg()
  99. /******************************Public*Routine******************************\
  100. * DisplayDib
  101. *
  102. * Just call DisplayDibEx
  103. *
  104. * History:
  105. * 23-03-94 - StephenE - Created
  106. *
  107. \**************************************************************************/
  108. UINT FAR PASCAL
  109. DisplayDib(
  110. LPBITMAPINFOHEADER lpbi,
  111. LPSTR lpBits,
  112. UINT wFlags
  113. )
  114. {
  115. dpf(( "Down level api, use DisplayDibEx" ));
  116. return DisplayDibEx( lpbi, 0, 0, lpBits, wFlags );
  117. }
  118. /******************************Public*Routine******************************\
  119. * @doc EXTERNAL DISPDIB
  120. *
  121. * @api UINT | DisplayDibEx | This function displays a 256-color bitmap on a
  122. * standard VGA display. It reduces the display resolution to 320-by-200
  123. * or 320-by-240 and uses the full screen to display the bitmap, clipping
  124. * and centering it as necessary. The function normally does not return to
  125. * the application until the user presses a key or clicks a mouse button.
  126. *
  127. * To call <f DisplayDibEx>, an application must be the active
  128. * application. All inactive applications and GDI screen updates
  129. * are suspended while <f DisplayDib> temporarily reconfigures
  130. * the display.
  131. *
  132. * @parm LPBITMAPINFO | lpbi | Specifies a pointer to a <t BITMAPINFO>
  133. * header describing the bitmap to be displayed.
  134. *
  135. * @parm int | x | x position to place DIB iff DISPLAYDIB_NOCENTER flags is set
  136. * the lower left is (0,0)
  137. *
  138. * @parm int | y | y position to place DIB iff DISPLAYDIB_NOCENTER flags is set
  139. * the lower left is (0,0)
  140. *
  141. * @parm LPSTR | lpBits | Specifies a pointer to the bitmap bits. If this
  142. * parameter is NULL, the bits are assumed to follow the
  143. * <t BITMAPINFO> structure pointed to by <p lpbi>.
  144. *
  145. * @parm UINT | wFlags | Specifies options for displaying the bitmap. Use
  146. * the following flags:
  147. *
  148. * @flag DISPLAYDIB_MODE_DEFAULT | Use the default mode (320 by 240)
  149. * to display the bitmap.
  150. * @flag DISPLAYDIB_MODE_320x200x8 | Use 320-by-200 mode to display
  151. * the bitmap.
  152. * @flag DISPLAYDIB_MODE_320x240x8 | Use 320-by-240 mode to display
  153. * the bitmap. This is the default.
  154. * @flag DISPLAYDIB_NOWAIT | Return immediately after displaying the
  155. * bitmap; don't wait for a key press or mouse click before returning.
  156. * @flag DISPLAYDIB_NOPALETTE | Ignore the palette associated
  157. * with the bitmap. You can use this flag when displaying a series
  158. * of bitmaps that use a common palette.
  159. * @flag DISPLAYDIB_NOCENTER | Don't center the image. The function
  160. * displays the bitmap in the lower-left corner of the display.
  161. * @flag DISPLAYDIB_NOIMAGE | Don't draw image
  162. * @flag DISPLAYDIB_ZOOM2 | Stretch image by 2
  163. * @flag DISPLAYDIB_DONTLOCKTASK | dont lock out other tasks
  164. * @flag DISPLAYDIB_TEST | dont do any thing just test for support
  165. * @flag DISPLAYDIB_BEGIN | Switch to the low-resolution
  166. * display mode and set the palette. The bitmap is not displayed.
  167. *
  168. * If you are displaying a series of images that use the same palette,
  169. * you can call <f DisplayDib> with this flag to prepare the display for
  170. * the bitmaps, then make a series of <f DisplayDib> calls with the
  171. * DISPLAYDIB_NOPALETTE flag. This technique
  172. * eliminates the screen flicker that occurs when the display is
  173. * switched between the low-resolution and standard VGA modes.
  174. * To return the display to standard VGA mode, subsequently
  175. * call <f DisplayDib> with the DISPLAYDIB_END flag.
  176. *
  177. * @flag DISPLAYDIB_END | Switch back to standard VGA mode
  178. * and return without displaying a bitmap. Signifies the end of multiple
  179. * calls to <f DisplayDib>. With this flag, you can specify
  180. * NULL for the <p lpbi> and <p lpBits> parameters.
  181. *
  182. * @rdesc Returns zero if successful, otherwise returns an error code.
  183. * Error codes are as follows:
  184. *
  185. * @flag DISPLAYDIB_NOTSUPPORTED | <f DisplayDib> is not supported
  186. * in the current mode.
  187. * @flag DISPLAYDIB_INVALIDDIB | The bitmap specified by
  188. * <p lpbi> is not a valid bitmap.
  189. * @flag DISPLAYDIB_INVALIDFORMAT | The bitmap specified by
  190. * <p lpbi> specifes a type of bitmap that is not supported.
  191. * @flag DISPLAYDIB_INVALIDTASK | The caller is an inactive application.
  192. * <f DisplayDib> can only be called by an active application.
  193. *
  194. * @comm The <f DisplayDib> function displays bitmaps described with
  195. * the Windows 3.0 <t BITMAPINFO> data structure in either BI_RGB
  196. * or BI_RLE8 format; it does not support bitmaps described with
  197. * the OS/2 <t BITMAPCOREHEADER> data structure.
  198. *
  199. * When <f DisplayDib> switches to a low-resolution display, it
  200. * disables the current display driver. As a result, you cannot use GDI
  201. * functions to update the display while <f DisplayDib> is displaying a
  202. * bitmap.
  203. *
  204. *
  205. * History:
  206. * 23-03-94 - StephenE - Created
  207. *
  208. \**************************************************************************/
  209. UINT FAR PASCAL
  210. DisplayDibEx(
  211. LPBITMAPINFOHEADER lpbi,
  212. int x,
  213. int y,
  214. LPSTR lpBits,
  215. UINT wFlags
  216. )
  217. {
  218. DWORD wNumColors;
  219. LONG yExt;
  220. LONG xExt;
  221. int xScreen,yScreen;
  222. /*
  223. ** If not already done so:
  224. ** Register our class and Create our window "fullscreen"
  225. */
  226. if (wFlags & DISPLAYDIB_BEGIN) {
  227. dpf4(( "DISPLAYDIB_BEGIN..." ));
  228. return DisplayDibEnter( lpbi, wFlags );
  229. }
  230. /*
  231. ** Just testing return OK
  232. */
  233. else if (wFlags & DISPLAYDIB_TEST) {
  234. dpf1(( "lpbi->biCompression = 0x%X = %c%c%c%c",
  235. lpbi->biCompression,
  236. *((LPSTR)&lpbi->biCompression + 0),
  237. *((LPSTR)&lpbi->biCompression + 1),
  238. *((LPSTR)&lpbi->biCompression + 2),
  239. *((LPSTR)&lpbi->biCompression + 3) ));
  240. dpf4(( "DISPLAYDIB_TEST... returning OK" ));
  241. return DISPLAYDIB_NOERROR;
  242. }
  243. /*
  244. ** Palette change message
  245. */
  246. else if ( (wFlags & (DISPLAYDIB_NOWAIT | DISPLAYDIB_NOIMAGE)) ==
  247. (DISPLAYDIB_NOWAIT | DISPLAYDIB_NOIMAGE) ) {
  248. PALETTEENTRY ape[256];
  249. LPRGBQUAD lprgb;
  250. int i;
  251. lprgb = (LPRGBQUAD) ((LPBYTE) lpbi + lpbi->biSize);
  252. for (i = 0; i < (int) lpbi->biClrUsed; i++) {
  253. ape[i].peRed = lprgb[i].rgbRed;
  254. ape[i].peGreen = lprgb[i].rgbGreen;
  255. ape[i].peBlue = lprgb[i].rgbBlue;
  256. ape[i].peFlags = 0;
  257. }
  258. DrawDibChangePalette(hdd, 0, (int)lpbi->biClrUsed, (LPPALETTEENTRY)ape);
  259. return DISPLAYDIB_NOERROR;
  260. }
  261. /*
  262. ** Time to kill the window and the class
  263. */
  264. else if (wFlags & DISPLAYDIB_END) {
  265. dpf4(( "DISPLAYDIB_END..." ));
  266. DisplayDibLeave( wFlags );
  267. return DISPLAYDIB_NOERROR;
  268. }
  269. /*
  270. ** Do the drawing here !!
  271. */
  272. else if ( !fStop ) {
  273. /*
  274. ** If we were'nt asked to draw anything just return.
  275. */
  276. if ( wFlags & DISPLAYDIB_NOIMAGE ) {
  277. return DISPLAYDIB_NOERROR;
  278. }
  279. xExt = lpbi->biWidth;
  280. yExt = lpbi->biHeight;
  281. if ( wFlags & DISPLAYDIB_ZOOM2 ) {
  282. xExt <<= 1;
  283. yExt <<= 1;
  284. }
  285. else if ( iMovieSizeMultiplier ) {
  286. xExt <<= iMovieSizeMultiplier;
  287. yExt <<= iMovieSizeMultiplier;
  288. }
  289. wNumColors = lpbi->biClrUsed;
  290. if (wNumColors == 0 && lpbi->biBitCount <= 8) {
  291. wNumColors = 1 << (UINT)lpbi->biBitCount;
  292. }
  293. /*
  294. ** setup pointers
  295. */
  296. if (lpBits == NULL) {
  297. lpBits = (LPBYTE)lpbi + lpbi->biSize + wNumColors * sizeof(RGBQUAD);
  298. }
  299. /*
  300. ** center the image
  301. */
  302. if (!(wFlags & DISPLAYDIB_NOCENTER)) {
  303. xScreen = ((int)dxScreen - xExt) / 2;
  304. yScreen = ((int)dyScreen - yExt) / 2;
  305. }
  306. else {
  307. xScreen = 0;
  308. yScreen = 0;
  309. }
  310. dpf5(( "Drawing to the screen..." ));
  311. DrawDibDraw( hdd, hdcFullScreen,
  312. xScreen, yScreen, xExt, yExt,
  313. lpbi, lpBits,
  314. 0, 0, lpbi->biWidth, lpbi->biHeight,
  315. DDF_SAME_HDC | DDF_SAME_DRAW );
  316. return DISPLAYDIB_NOERROR;
  317. }
  318. /*
  319. ** The user pressed a key... time to stop
  320. */
  321. else {
  322. dpf4(( "The keyboard hook is telling us to stop..." ));
  323. DisplayDibLeave( wFlags );
  324. return DISPLAYDIB_NOTSUPPORTED;
  325. }
  326. }
  327. /*****************************Private*Routine******************************\
  328. * DisplayDibEnter
  329. *
  330. *
  331. *
  332. * History:
  333. * 23-03-94 - StephenE - Created
  334. *
  335. \**************************************************************************/
  336. UINT
  337. DisplayDibEnter(
  338. LPBITMAPINFOHEADER lpbi,
  339. UINT wFlags
  340. )
  341. {
  342. WNDCLASS wc;
  343. HINSTANCE hInst = GetModuleHandle( NULL );
  344. /*
  345. ** If our class isn't already registered with windows register it
  346. */
  347. fClassRegistered = GetClassInfo( hInst, TEXT("SJE_FULLSCREEN"), &wc );
  348. if ( fClassRegistered == FALSE ) {
  349. ZeroMemory( &wc, sizeof(wc) );
  350. wc.style = CS_OWNDC;
  351. wc.lpfnWndProc = FullScreenWndProc;
  352. wc.hInstance = hInst;
  353. wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
  354. wc.lpszClassName = TEXT("SJE_FULLSCREEN");
  355. fClassRegistered = RegisterClass( &wc );
  356. dpf4(( "Class registered... %s", fClassRegistered ? "OK" : "FAILED" ));
  357. }
  358. if ( fClassRegistered ) {
  359. /*
  360. ** Do we already have a window ??
  361. */
  362. if ( hwndFullScreen == NULL ) {
  363. hwndFullScreen = CreateWindowEx(WS_EX_TOPMOST,
  364. TEXT("SJE_FULLSCREEN"),
  365. NULL,
  366. WS_POPUP,
  367. 0, 0, 0, 0,
  368. NULL, NULL,
  369. hInst, NULL );
  370. dpf4(( "Window created... %s", hwndFullScreen ? "OK" : "FAILED" ));
  371. }
  372. if ( hwndFullScreen ) {
  373. LONG yExt;
  374. LONG xExt;
  375. MSG msg;
  376. /*
  377. ** purge the queue of keyboard messages before installing
  378. ** the hook.
  379. */
  380. while ( PeekMessage( &msg, NULL, WM_KEYFIRST, WM_KEYLAST,
  381. PM_REMOVE | PM_NOYIELD ) );
  382. hHookK = SetWindowsHookEx( WH_KEYBOARD, KeyboardHookProc,
  383. GetModuleHandle(TEXT("DISPDB32.DLL")),
  384. 0 );
  385. dpf4(( "Hook created... %s", hHookK ? "OK" : "FAILED" ));
  386. dxScreen = GetSystemMetrics( SM_CXSCREEN );
  387. dyScreen = GetSystemMetrics( SM_CYSCREEN );
  388. hdcFullScreen = GetDC( hwndFullScreen );
  389. hdd = DrawDibOpen();
  390. xExt = lpbi->biWidth;
  391. yExt = lpbi->biHeight;
  392. iMovieSizeMultiplier =
  393. DisplayCalcMovieMultiplier( xExt, yExt, lpbi->biCompression );
  394. if ( wFlags & DISPLAYDIB_ZOOM2 ) {
  395. xExt <<= 1;
  396. yExt <<= 1;
  397. }
  398. else if ( iMovieSizeMultiplier ) {
  399. xExt <<= iMovieSizeMultiplier;
  400. yExt <<= iMovieSizeMultiplier;
  401. }
  402. dpf1(( "Drawing at %d by %d... Flags = 0x%X", xExt, yExt, wFlags ));
  403. DrawDibBegin( hdd, hdcFullScreen, xExt, yExt,
  404. lpbi, lpbi->biWidth, lpbi->biHeight, 0 );
  405. MoveWindow( hwndFullScreen, 0, 0, dxScreen, dyScreen, FALSE );
  406. ShowWindow( hwndFullScreen, SW_SHOW );
  407. UpdateWindow( hwndFullScreen );
  408. ShowCursor( FALSE );
  409. SetFocus( hwndFullScreen );
  410. }
  411. }
  412. fStop = FALSE;
  413. return hwndFullScreen != NULL ? DISPLAYDIB_NOERROR : DISPLAYDIB_NOTSUPPORTED;
  414. }
  415. /*****************************Private*Routine******************************\
  416. * DisplayDibLeave
  417. *
  418. *
  419. *
  420. * History:
  421. * 23-03-94 - StephenE - Created
  422. *
  423. \**************************************************************************/
  424. void
  425. DisplayDibLeave(
  426. UINT wFlags
  427. )
  428. {
  429. if (hwndFullScreen) {
  430. DestroyWindow( hwndFullScreen );
  431. hwndFullScreen = NULL;
  432. }
  433. }
  434. /*****************************Private*Routine******************************\
  435. * DisplayCalcMovieMultiplier
  436. *
  437. * Determines the largest movie that the display is capable of displaying.
  438. *
  439. * History:
  440. * dd-mm-94 - StephenE - Created
  441. *
  442. \**************************************************************************/
  443. int
  444. DisplayCalcMovieMultiplier(
  445. int cxOriginal,
  446. int cyOriginal,
  447. DWORD dwCompression
  448. )
  449. {
  450. SYSTEM_INFO SysInfo;
  451. int iMult;
  452. int iMultTemp;
  453. int cxOriginalSave, cyOriginalSave;
  454. /*
  455. ** For now, don't try to stretch 'cvid' compressed movies. This is
  456. ** because it looks bad!!
  457. */
  458. if ( *((LPSTR)&dwCompression + 0) == 'c'
  459. && *((LPSTR)&dwCompression + 1) == 'v'
  460. && *((LPSTR)&dwCompression + 2) == 'i'
  461. && *((LPSTR)&dwCompression + 3) == 'd' ) {
  462. return 0;
  463. }
  464. GetSystemInfo( &SysInfo );
  465. iMultTemp = iMult = 0;
  466. cxOriginalSave = cxOriginal;
  467. cyOriginalSave = cyOriginal;
  468. switch ( SysInfo.wProcessorArchitecture ) {
  469. case PROCESSOR_ARCHITECTURE_INTEL:
  470. if ( SysInfo.wProcessorLevel <= 3 ) {
  471. break;
  472. }
  473. /*
  474. ** maybe later we will do something different for i486's
  475. ** for now they just fall through to the RISC / Pentium default
  476. ** case below.
  477. */
  478. default:
  479. while ( (cxOriginal <= CX_MAX_MOVIE_DEFAULT)
  480. && (cyOriginal <= CY_MAX_MOVIE_DEFAULT) ) {
  481. iMult = iMultTemp;
  482. iMultTemp++;
  483. cxOriginal = cxOriginalSave << iMultTemp;
  484. cyOriginal = cyOriginalSave << iMultTemp;
  485. }
  486. break;
  487. }
  488. return iMult;
  489. }
  490. /******************************Public*Routine******************************\
  491. * FullScreenWndProc
  492. *
  493. *
  494. *
  495. * History:
  496. * 23-03-94 - StephenE - Created
  497. *
  498. \**************************************************************************/
  499. LRESULT CALLBACK
  500. FullScreenWndProc(
  501. HWND hwnd,
  502. UINT message,
  503. WPARAM wParam,
  504. LPARAM lParam
  505. )
  506. {
  507. switch ( message ) {
  508. case WM_PAINT:
  509. {
  510. PAINTSTRUCT ps;
  511. RECT rc;
  512. dpf4(( "Window needs painting" ));
  513. BeginPaint( hwnd, &ps );
  514. GetUpdateRect( hwnd, &rc, FALSE );
  515. FillRect( hdcFullScreen, &rc, GetStockObject( BLACK_BRUSH ) );
  516. EndPaint( hwnd, &ps );
  517. }
  518. break;
  519. case WM_PALETTECHANGED:
  520. if ( (HWND)wParam == hwnd ) {
  521. break;
  522. }
  523. /* fall thru */
  524. case WM_QUERYNEWPALETTE:
  525. if ( DrawDibRealize( hdd, hdcFullScreen, FALSE ) > 0 ) {
  526. InvalidateRect( hwnd, NULL, TRUE );
  527. }
  528. break;
  529. case WM_DESTROY:
  530. dpf4(( "Window destroyed releasing DC" ));
  531. ReleaseDC( hwnd, hdcFullScreen );
  532. DrawDibEnd( hdd );
  533. DrawDibClose( hdd );
  534. UnregisterClass( TEXT("SJE_FULLSCREEN"), GetModuleHandle( NULL ) );
  535. fClassRegistered = FALSE;
  536. fStop = FALSE;
  537. ShowCursor( TRUE );
  538. UnhookWindowsHookEx( hHookK );
  539. break;
  540. default:
  541. return DefWindowProc( hwnd, message, wParam, lParam );
  542. }
  543. return (LRESULT)FALSE;
  544. }
  545. /******************************Public*Routine******************************\
  546. * KeyboardHookProc
  547. *
  548. *
  549. *
  550. * History:
  551. * 23-03-94 - StephenE - Created
  552. *
  553. \**************************************************************************/
  554. LRESULT CALLBACK
  555. KeyboardHookProc(
  556. int nCode,
  557. WPARAM wParam,
  558. LPARAM lParam
  559. )
  560. {
  561. if ( nCode == HC_ACTION) {
  562. /*
  563. ** Only interested in keydowns
  564. */
  565. if ( !(lParam & 0x80000000) ) {
  566. dpf4(( "Stop requested from the keyboard hook" ));
  567. fStop = TRUE;
  568. }
  569. }
  570. return CallNextHookEx( hHookK, nCode, wParam, lParam );
  571. }
  572. #if DBG
  573. /*****************************Private*Routine******************************\
  574. * dprintf
  575. *
  576. * Standard debug out stuff
  577. *
  578. * History:
  579. * 23-03-94 - StephenE - Created
  580. *
  581. \**************************************************************************/
  582. void
  583. dprintf(
  584. LPSTR lpszFormat,
  585. ...
  586. )
  587. {
  588. char buf[512];
  589. UINT n;
  590. va_list va;
  591. n = wsprintfA(buf, "DISPDB32: (tid %x) ", GetCurrentThreadId());
  592. va_start(va, lpszFormat);
  593. n += wvsprintfA(buf+n, lpszFormat, va);
  594. va_end(va);
  595. buf[n++] = '\n';
  596. buf[n] = 0;
  597. OutputDebugStringA(buf);
  598. }
  599. #endif