Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2175 lines
67 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: ddefwp.c
  6. * Content: DirectDraw processing of Window messages
  7. * Takes care of palette changes, mode setting
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 26-mar-95 craige initial implementation
  12. * 01-apr-95 craige happy fun joy updated header file
  13. * 06-may-95 craige use driver-level csects only
  14. * 02-jun-95 craige flesh it out
  15. * 06-jun-95 craige added SetAppHWnd
  16. * 07-jun-95 craige more fleshing...
  17. * 12-jun-95 craige new process list stuff
  18. * 16-jun-95 craige new surface structure
  19. * 25-jun-95 craige one ddraw mutex
  20. * 30-jun-95 kylej use GetProcessPrimary instead of lpPrimarySurface
  21. * invalidate all primary surfaces upon focus lost
  22. * or regained.
  23. * 30-jun-95 craige minimze window for CAD, ALT-TAB, ALT-ESC or CTRL-ESC
  24. * 04-jul-95 craige YEEHAW: new driver struct
  25. * 06-jul-95 craige prevent reentry
  26. * 08-jul-95 craige allow dsound to share
  27. * 08-jul-95 kylej remove call to ResetSysPalette
  28. * 11-jul-95 craige DSoundHelp & internalSetAppHWnd needs to take a pid
  29. * 13-jul-95 craige first step in mode set fix; made it work.
  30. * 15-jul-95 craige unhook at WM_DESTROY; don't escape on ALT; do a
  31. * SetActiveWindow( NULL ) to stop tray from showing
  32. * our button as depressed
  33. * 17-jul-95 craige don't process hot key messages & activation messages
  34. * for non-excl mode apps; SetActiveWindow is bogus,
  35. * get bottom window in Z order and make it foreground
  36. * 18-jul-95 craige use flags instead of refcnt to track WININFO
  37. * 29-jul-95 toddla make ALT+TAB and CTRL+ESC work.
  38. * 31-jul-95 toddla make ALT+TAB and CTRL+ESC work better.
  39. * 09-aug-95 craige bug 424 - allow switching to/from apps without primary
  40. * surfaces to work
  41. * 09-aug-95 craige bug 404 - don't pass WM_ACTIVATEAPP messages to dsound
  42. * if app iconic
  43. * 10-aug-95 toddla check WININFO_DSOUNDHOOKED before calling DSound
  44. * 10-aug-95 toddla handle unhooking after/during WM_DESTROY right.
  45. * 13-aug-95 toddla added WININFO_ACTIVELIE
  46. * 23-aug-95 craige bug 388,610
  47. * 25-aug-95 craige bug 709
  48. * 27-aug-95 craige bug 735: call SetPaletteAlways
  49. * 04-sep-95 craige bug 894: force mode set when activating
  50. * 09-sep-95 toddla dont send nested WM_ACTIVATEAPP messages
  51. * 26-sep-95 craige bug 1364: use new csect to avoid dsound deadlock
  52. * 09-jan-96 kylej new interface structures
  53. * 13-apr-96 colinmc Bug 17736: No notification to driver of flip to GDI
  54. * 20-apr-96 kylej Bug 16747: Make exclusive window visible if it is not.
  55. * 23-apr-96 kylej Bug 14680: Make sure exclusive window is not maximized.
  56. * 16-may-96 kylej Bug 23013: pass the correct flags to StartExclusiveMode
  57. * 17-may-96 colinmc Bug 23029: Alt-tabbing straight back to a full screen
  58. * does not send the app an WM_ACTIVATEAPP
  59. * 12-oct-96 colinmc Improvements to Win16 locking code to reduce virtual
  60. * memory usage
  61. * 16-oct-96 colinmc Added PrintScreen support to allow screen grabbing
  62. * 05-feb-96 ketand Bug 1749: Alt-Tab from fullscreen app would cause cycling when
  63. * the only other window running is the Start::Run window.
  64. * 03-mar-97 jeffno Structure name change to avoid conflict w/ ActiveAccessibility
  65. * 24-mar-97 colinmc Bug 6913: Enable ModeX PRINTSCREEN
  66. *
  67. ***************************************************************************/
  68. #include "ddrawpr.h"
  69. #define TOPMOST_ID 0x4242
  70. #define TOPMOST_TIMEOUT 1500
  71. #define USESHOWWINDOW
  72. #ifdef WIN95
  73. extern CRITICAL_SECTION csWindowList;
  74. #define ENTERWINDOWLISTCSECT EnterCriticalSection( &csWindowList );
  75. #define LEAVEWINDOWLISTCSECT LeaveCriticalSection( &csWindowList );
  76. #elif defined(WINNT)
  77. extern HANDLE hWindowListMutex;
  78. #define ENTERWINDOWLISTCSECT WaitForSingleObject(hWindowListMutex,INFINITE);
  79. #define LEAVEWINDOWLISTCSECT ReleaseMutex(hWindowListMutex);
  80. #else
  81. #error "Win95 or winnt- make up your mind!"
  82. #endif
  83. #ifndef ENUM_CURRENT_SETTINGS
  84. #define ENUM_CURRENT_SETTINGS ((DWORD)-1)
  85. #endif
  86. /*
  87. * DD_GetDeviceRect
  88. *
  89. * get the rect in screen space for this device.
  90. * on a single monitor system this is (0,0) - (SM_CXSCREEN,SM_CYSCREEN)
  91. */
  92. BOOL DD_GetDeviceRect(LPDDRAWI_DIRECTDRAW_GBL pdrv, RECT *prc)
  93. {
  94. //
  95. // this is a non-DISPLAY device for compatibility with DDRAW 3.x
  96. // we should use the size of the primary display.
  97. //
  98. if (!(pdrv->dwFlags & DDRAWI_DISPLAYDRV))
  99. {
  100. DPF( 4, "DD_GetDeviceRect: not a display driver, using screen rect.");
  101. SetRect(prc,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
  102. return TRUE;
  103. }
  104. if (_stricmp(pdrv->cDriverName, "DISPLAY") == 0)
  105. {
  106. SetRect(prc,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
  107. }
  108. else
  109. {
  110. #ifdef WIN95
  111. DEVMODE dm;
  112. ZeroMemory(&dm, sizeof(dm));
  113. dm.dmSize = sizeof(dm);
  114. EnumDisplaySettings(pdrv->cDriverName, ENUM_CURRENT_SETTINGS, &dm);
  115. //
  116. // the position of the device is in the dmPosition field
  117. //
  118. CopyMemory(prc, &dm.dmOrientation, sizeof(RECT));
  119. if (IsRectEmpty(prc))
  120. {
  121. //
  122. // this device is not attached to the desktop
  123. // what should we do?
  124. //
  125. // make the window the size of the primary?
  126. //
  127. // put the window out in space?
  128. //
  129. // dont move the window?
  130. //
  131. DPF( 4, "DD_GetDeviceRect: device is not attached to desktop.");
  132. // put window on primary
  133. SetRect(prc,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
  134. // put window off in space.
  135. //SetRect(prc,10000,10000,10000+dm.dmPelsWidth,10000+dm.dmPelsHeight);
  136. // dont move window
  137. // return FALSE
  138. }
  139. #else
  140. if( GetNTDeviceRect( pdrv->cDriverName, prc ) != DD_OK )
  141. {
  142. DPF( 4, "DD_GetDeviceRect: device is not attached to desktop.");
  143. SetRect(prc,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
  144. }
  145. #endif
  146. }
  147. DPF( 5, "DD_GetDeviceRect: %s [%d %d %d %d]",pdrv->cDriverName, prc->left, prc->top, prc->right, prc->bottom);
  148. return TRUE;
  149. }
  150. #ifdef GDIDDPAL
  151. /*
  152. * getPalette
  153. *
  154. * Get a pointer to a palette object.
  155. * Takes a lock on the driver object and the palette object.
  156. */
  157. LPDDRAWI_DDRAWPALETTE_LCL getPalette( LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl )
  158. {
  159. LPDDRAWI_DDRAWPALETTE_LCL ppal_lcl;
  160. LPDDRAWI_DDRAWSURFACE_LCL psurf_lcl;
  161. if( pdrv_lcl->lpGbl->dwFlags & DDRAWI_HASGDIPALETTE )
  162. {
  163. psurf_lcl = pdrv_lcl->lpPrimary;
  164. if( psurf_lcl != NULL )
  165. {
  166. ppal_lcl = psurf_lcl->lpDDPalette;
  167. return ppal_lcl;
  168. }
  169. }
  170. return NULL;
  171. } /* getPalette */
  172. #endif
  173. static LONG bHelperStarting=0;
  174. static BOOL bStartHelper=0;
  175. static BYTE sys_key=0;
  176. static DWORD sys_state=0;
  177. /*
  178. * IsTaskWindow
  179. */
  180. BOOL IsTaskWindow(HWND hwnd)
  181. {
  182. DWORD dwStyleEx = GetWindowLong(hwnd, GWL_EXSTYLE);
  183. // Following windows do not qualify to be shown in task list:
  184. // Switch Window, Hidden windows (unless they are the active
  185. // window), Disabled windows, Kanji Conv windows.
  186. // Ignore windows that are actually child windows.
  187. return(((dwStyleEx & WS_EX_APPWINDOW) ||
  188. !(dwStyleEx & WS_EX_TOOLWINDOW)) &&
  189. IsWindowVisible(hwnd) &&
  190. IsWindowEnabled(hwnd) &&
  191. GetParent(hwnd) == NULL);
  192. }
  193. /*
  194. * CountTaskWindows
  195. */
  196. int CountTaskWindows()
  197. {
  198. HWND hwnd;
  199. int n;
  200. for (n=0,
  201. hwnd = GetWindow(GetDesktopWindow(), GW_CHILD);
  202. hwnd!= NULL;
  203. hwnd = GetWindow(hwnd, GW_HWNDNEXT))
  204. {
  205. if (IsTaskWindow(hwnd))
  206. n++;
  207. }
  208. return n;
  209. }
  210. /*
  211. * ClipTheCursor
  212. *
  213. * A DINPUT app keeps track of movement based on the delta from the last
  214. * movement. On a multi-mon system, the delta can be larger than the
  215. * app's window, but a fullscreen non-multimon aware app might count on
  216. * windows clipping the mouse to the primary so it could totally break
  217. * (e.g. Dungeon Keeper). This hack will clip/unclip the cursor movement
  218. * to the monitor if the app is not multi-mon aware.
  219. */
  220. void ClipTheCursor( LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl, LPRECT lpRect )
  221. {
  222. /*
  223. * Only unclip if it was previously clipped
  224. */
  225. if( lpRect == NULL )
  226. {
  227. if( pdrv_lcl->dwLocalFlags & DDRAWILCL_CURSORCLIPPED )
  228. {
  229. pdrv_lcl->dwLocalFlags &= ~DDRAWILCL_CURSORCLIPPED;
  230. ClipCursor( NULL );
  231. }
  232. }
  233. /*
  234. * Only clip them if they are not multi-mon aware and they own
  235. * exclusive mode
  236. */
  237. else if( !( pdrv_lcl->dwLocalFlags & DDRAWILCL_EXPLICITMONITOR ) &&
  238. ( pdrv_lcl->dwLocalFlags & DDRAWILCL_HASEXCLUSIVEMODE ) &&
  239. ( pdrv_lcl->dwLocalFlags & DDRAWILCL_ACTIVEYES ) )
  240. {
  241. /*
  242. * Hack to allow user to use debugger
  243. */
  244. #ifdef DEBUG
  245. if( !( pdrv_lcl->dwLocalFlags & DDRAWILCL_DISABLEINACTIVATE ) )
  246. {
  247. #endif
  248. pdrv_lcl->dwLocalFlags |= DDRAWILCL_CURSORCLIPPED;
  249. ClipCursor( lpRect );
  250. #ifdef DEBUG
  251. }
  252. #endif
  253. }
  254. }
  255. //
  256. // make the passed window fullscreen and topmost and set a timer
  257. // to make the window topmost again, what a hack.
  258. //
  259. void MakeFullscreen(LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl, HWND hwnd)
  260. {
  261. RECT rc;
  262. if (DD_GetDeviceRect(pdrv_lcl->lpGbl, &rc))
  263. {
  264. SetWindowPos(hwnd, NULL, rc.left, rc.top,
  265. rc.right - rc.left,rc.bottom - rc.top,
  266. SWP_NOZORDER | SWP_NOACTIVATE);
  267. ClipTheCursor( pdrv_lcl, &rc );
  268. }
  269. if (GetForegroundWindow() == (HWND)pdrv_lcl->hFocusWnd)
  270. {
  271. // If the exclusive mode window is not visible, make it so.
  272. if(!IsWindowVisible( hwnd ) )
  273. {
  274. ShowWindow(hwnd, SW_SHOW);
  275. }
  276. SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
  277. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  278. // If the exclusive mode window is maximized, restore it.
  279. if( IsZoomed( hwnd ) )
  280. {
  281. ShowWindow(hwnd, SW_RESTORE);
  282. }
  283. }
  284. if( giTopmostCnt < MAX_TIMER_HWNDS )
  285. {
  286. ghwndTopmostList[giTopmostCnt++] = hwnd;
  287. }
  288. SetTimer( (HWND)pdrv_lcl->hFocusWnd, TOPMOST_ID, TOPMOST_TIMEOUT, NULL);
  289. }
  290. //
  291. // Same as MakeFullscreen only it does it for every DirectDraw object that
  292. // thinks it has hooked the window
  293. //
  294. void MakeAllFullscreen(LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl, HWND hwnd)
  295. {
  296. LPDDRAWI_DIRECTDRAW_LCL this_lcl;
  297. /*
  298. * We need to maintain old behavior in the non-multimon case
  299. */
  300. giTopmostCnt = 0;
  301. MakeFullscreen( pdrv_lcl, (HWND) pdrv_lcl->hWnd );
  302. /*
  303. * Don't do this on multimon when de-activating.
  304. * Hack to minimize singlemon code impact - this function gets called
  305. * by the WM_DISPLAYCHANGE message, which gets called on a
  306. * RestoreDisplayMode when leaving exclusive mode on a deactivate.
  307. * Consider not calling MakeAllFullScreen when DDRAWILCL_ACTIVENO is set
  308. */
  309. if (!IsMultiMonitor() ||
  310. !(pdrv_lcl->dwLocalFlags & DDRAWILCL_ACTIVENO))
  311. {
  312. /*
  313. * Don't enter normal critical section because this is called
  314. * during WM_DISPLAYCHANGE which could cause problems.
  315. */
  316. ENTER_DRIVERLISTCSECT();
  317. this_lcl = lpDriverLocalList;
  318. while( this_lcl != NULL )
  319. {
  320. if( ( this_lcl != pdrv_lcl ) &&
  321. ( this_lcl->dwLocalFlags & DDRAWILCL_HASEXCLUSIVEMODE ) &&
  322. ( this_lcl->hFocusWnd == (ULONG_PTR) hwnd ) &&
  323. ( this_lcl->dwLocalFlags & DDRAWILCL_HOOKEDHWND ) &&
  324. ( this_lcl->hWnd != pdrv_lcl->hWnd ) )
  325. {
  326. MakeFullscreen( this_lcl, (HWND)this_lcl->hWnd );
  327. }
  328. this_lcl = this_lcl->lpLink;
  329. }
  330. LEAVE_DRIVERLISTCSECT();
  331. }
  332. }
  333. void InternalSetForegroundWindow(HWND hWnd)
  334. {
  335. DWORD dwTimeout;
  336. SystemParametersInfo( SPI_GETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID) &dwTimeout, 0 );
  337. SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0, NULL, 0 );
  338. #ifdef WINNT
  339. //
  340. // This works around a focus bug. If an app does createwindow,destroywindow,createwindow,
  341. // then it may not get focus on the second create because some other window stole it in
  342. // the meantime.
  343. //
  344. mouse_event(MOUSEEVENTF_WHEEL,0,0,0,0);
  345. #endif
  346. SetForegroundWindow(hWnd);
  347. SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID) ULongToPtr(dwTimeout), 0 );
  348. }
  349. /*
  350. * handleActivateApp
  351. */
  352. void handleActivateApp(
  353. LPDDRAWI_DIRECTDRAW_LCL this_lcl,
  354. LPDDWINDOWINFO pwinfo,
  355. BOOL is_active,
  356. BOOL bFirst )
  357. {
  358. LPDDRAWI_DDRAWPALETTE_INT ppal_int;
  359. LPDDRAWI_DDRAWPALETTE_LCL ppal_lcl;
  360. LPDDRAWI_DIRECTDRAW_GBL this;
  361. LPDDRAWI_DDRAWSURFACE_INT psurf_int;
  362. LPDDRAWI_DDRAWSURFACE_LCL psurf_lcl;
  363. LPDDRAWI_DDRAWSURFACE_GBL psurf;
  364. DWORD pid;
  365. HRESULT ddrval;
  366. BOOL has_excl;
  367. BOOL excl_exists;
  368. BOOL bMinimize = TRUE;
  369. this = this_lcl->lpGbl;
  370. pid = GetCurrentProcessId();
  371. psurf_int = this_lcl->lpPrimary;
  372. if( psurf_int != NULL )
  373. {
  374. psurf_lcl = psurf_int->lpLcl;
  375. psurf = psurf_lcl->lpGbl;
  376. ppal_int = psurf_lcl->lpDDPalette;
  377. if( NULL != ppal_int )
  378. {
  379. ppal_lcl = ppal_int->lpLcl;
  380. }
  381. else
  382. {
  383. ppal_lcl = NULL;
  384. }
  385. }
  386. else
  387. {
  388. psurf_lcl = NULL;
  389. ppal_lcl = NULL;
  390. }
  391. /*
  392. * An app could take exclusive mode just as another app is being activated by alt-tab.
  393. * Should we do anything about this remote chance?
  394. */
  395. CheckExclusiveMode(this_lcl, &excl_exists, &has_excl, TRUE, NULL, FALSE);
  396. /*
  397. * stuff to do before the mode set if deactivating
  398. */
  399. if( !is_active )
  400. {
  401. /*
  402. * flip back to GDI if deactivating
  403. */
  404. if( (psurf_lcl != NULL) && has_excl )
  405. {
  406. FlipToGDISurface( this_lcl, psurf_int); //, this->fpPrimaryOrig );
  407. }
  408. if( has_excl )
  409. {
  410. /*
  411. * Exclusive mode app losing or gaining focus.
  412. * If gaining focus, invalidate all non-exclusive mode primary
  413. * surfaces. If losing focus, invalidate the exclusive-mode
  414. * primary surface so that non-exclusive apps can restore
  415. * their primaries.
  416. *
  417. * NOTE: This call MUST come after FlipToGDISurface, or
  418. * else FlipToGDISurface will fail. craige 7/4/95
  419. *
  420. * NOTE: if we are coming in or out of exclusive mode,
  421. * we need to invalidate all surfaces so that resources are
  422. * available. craige 7/9/94
  423. *
  424. */
  425. InvalidateAllSurfaces( this, (HANDLE) this_lcl->hDDVxd, TRUE );
  426. }
  427. }
  428. /*
  429. * stuff to do before mode set if activating
  430. */
  431. else
  432. {
  433. /*
  434. * restore exclusive mode. Here we don't release the ref we took on the exclusive mode mutex,
  435. * since we want to keep the exclusive mode mutex.
  436. */
  437. if( this_lcl->dwLocalFlags & DDRAWILCL_ISFULLSCREEN )
  438. {
  439. this->dwFlags |= DDRAWI_FULLSCREEN;
  440. }
  441. StartExclusiveMode( this_lcl, pwinfo->DDInfo.dwDDFlags, pid );
  442. has_excl = TRUE;
  443. }
  444. /*
  445. * NOTE: We used to invalidate here but that was strange as it would
  446. * mean doing the invalidate twice as StartExclusiveMode() always
  447. * invalidates. So now we only explicitly invalidate if an exlcusive
  448. * mode app is being deactivated. StartExclusiveMode() handles the
  449. * other case.
  450. */
  451. /*
  452. * restore hwnd if we are about to be activated
  453. */
  454. if ( (pwinfo->DDInfo.dwDDFlags & DDSCL_FULLSCREEN) &&
  455. !(pwinfo->DDInfo.dwDDFlags & DDSCL_NOWINDOWCHANGES) &&
  456. IsWindowVisible(pwinfo->hWnd))
  457. {
  458. if (is_active)
  459. {
  460. pwinfo->dwFlags |= WININFO_SELFSIZE;
  461. #ifdef USESHOWWINDOW
  462. ShowWindow(pwinfo->hWnd, SW_SHOWNOACTIVATE);
  463. #else
  464. {
  465. RECT rc;
  466. if (DD_GetDeviceRect(this, &rc))
  467. {
  468. SetWindowPos(pwinfo->hWnd, NULL,rc.left, rc.top,
  469. rc.right - rc.left,rc.bottom - rc.top,
  470. SWP_NOZORDER | SWP_NOACTIVATE);
  471. }
  472. }
  473. #endif
  474. pwinfo->dwFlags &= ~WININFO_SELFSIZE;
  475. }
  476. }
  477. /*
  478. * restore the mode
  479. */
  480. if( !is_active )
  481. {
  482. if( (!excl_exists) || has_excl )
  483. {
  484. DPF( 4, "INACTIVE: %08lx: Restoring original mode (%ld)", GetCurrentProcessId(), this->dwModeIndexOrig );
  485. if( RestoreDisplayMode( this_lcl, TRUE ) == DDERR_UNSUPPORTED )
  486. {
  487. #ifdef WINNT
  488. /*
  489. * If RestoreDisplayMode failed, we are probably on a different desktop. In this case,
  490. * we should not minimize the window or else things won't work right when we switch
  491. * back to the original desktop.
  492. */
  493. HDESK hDesktop;
  494. static BYTE szName1[256];
  495. static BYTE szName2[256];
  496. DWORD dwTemp;
  497. // Get the name of the current desktop
  498. hDesktop = OpenInputDesktop( 0, FALSE, DESKTOP_READOBJECTS );
  499. GetUserObjectInformation( hDesktop, UOI_NAME, szName1, sizeof( szName1 ), &dwTemp );
  500. CloseDesktop( hDesktop );
  501. // Get the name of the apps' desktop
  502. hDesktop = GetThreadDesktop( GetCurrentThreadId() );
  503. GetUserObjectInformation( hDesktop, UOI_NAME, szName2, sizeof( szName2 ), &dwTemp );
  504. if( lstrcmp( szName1, szName2 ) )
  505. {
  506. bMinimize = FALSE;
  507. }
  508. #endif
  509. }
  510. }
  511. }
  512. else
  513. {
  514. DPF( 4, "ACTIVE: %08lx: Setting app's preferred mode (%ld)", GetCurrentProcessId(), this_lcl->dwPreferredMode );
  515. SetDisplayMode( this_lcl, this_lcl->dwPreferredMode, TRUE, TRUE );
  516. }
  517. /*
  518. * stuff to do after the mode set if activating
  519. */
  520. if( is_active )
  521. {
  522. /*
  523. * restore the palette
  524. */
  525. if( ppal_lcl != NULL )
  526. {
  527. ddrval = SetPaletteAlways( psurf_int, (LPDIRECTDRAWPALETTE) ppal_int );
  528. DPF( 5, "SetPalette, ddrval = %08lx (%ld)", ddrval, LOWORD( ddrval ) );
  529. }
  530. }
  531. /*
  532. * stuff to do after the mode set if deactivating
  533. */
  534. else
  535. {
  536. if( has_excl )
  537. {
  538. /*
  539. * ...and this will finally release the exclusive mode mutex
  540. */
  541. DoneExclusiveMode( this_lcl );
  542. }
  543. }
  544. /*
  545. * minimize window if deactivating
  546. */
  547. if ( (pwinfo->DDInfo.dwDDFlags & DDSCL_FULLSCREEN) &&
  548. !(pwinfo->DDInfo.dwDDFlags & DDSCL_NOWINDOWCHANGES) &&
  549. IsWindowVisible(pwinfo->hWnd))
  550. {
  551. pwinfo->dwFlags |= WININFO_SELFSIZE;
  552. if( is_active )
  553. {
  554. MakeFullscreen(this_lcl, (HWND)this_lcl->hWnd);
  555. }
  556. else if( bMinimize )
  557. {
  558. // get the last active popup
  559. this_lcl->hWndPopup = (ULONG_PTR) GetLastActivePopup(pwinfo->hWnd);
  560. if ((HWND) this_lcl->hWndPopup == pwinfo->hWnd)
  561. {
  562. this_lcl->hWndPopup = 0;
  563. }
  564. #ifdef USESHOWWINDOW
  565. ShowWindow(pwinfo->hWnd, SW_SHOWMINNOACTIVE);
  566. #else
  567. SetWindowPos(pwinfo->hWnd, NULL, 0, 0, 0, 0,
  568. SWP_NOZORDER | SWP_NOACTIVATE);
  569. #endif
  570. }
  571. pwinfo->dwFlags &= ~WININFO_SELFSIZE;
  572. }
  573. /*
  574. * We only want to do the following stuff once
  575. */
  576. if( !bFirst )
  577. {
  578. return;
  579. }
  580. #ifdef WIN95
  581. /*
  582. * if we got deactivated because of a syskey
  583. * then send that key to user now.
  584. * This is unnecessary for NT.
  585. *
  586. * NOTE because we disabled all the task-switching
  587. * hot keys the system did not see the hot key that
  588. * caused us to deactivate.
  589. *
  590. * if there is only one window to activate, activate the
  591. * desktop (shell window)
  592. */
  593. if( has_excl && sys_key && !is_active )
  594. {
  595. if (CountTaskWindows() <= 1)
  596. {
  597. DPF( 4, "activating the desktop" );
  598. /*
  599. * Calling SetforegroundWindow will cause WM_ACTIVATEAPP messages
  600. * to be sent, but if we get here, we are already processing a
  601. * WM_ACTIVATEAPP message and are holding the critical section.
  602. * If we don't LEAVE_DDRAW now, this will cause us to call the
  603. * apps WindProc w/ the critical section held, which results in
  604. * a deadlock situation for at least one app (Ashes to Ashes).
  605. * Leaving and re-entering does mean that we can't rely on the
  606. * DDraw state to be the same, but we are done using the
  607. * structures for now anyway.
  608. * smac 3/20/97
  609. */
  610. LEAVE_DDRAW();
  611. InternalSetForegroundWindow(GetWindow(pwinfo->hWnd, GW_HWNDLAST));
  612. ENTER_DDRAW();
  613. // we just activated the desktop, so we *dont* want
  614. // to force a ALT+ESC or ALT+TAB, we do want to force
  615. // a CTRL+ESC.
  616. if (sys_key != VK_ESCAPE || (sys_state & 0x20000000))
  617. sys_key = 0;
  618. }
  619. if (sys_key)
  620. {
  621. BYTE state_key;
  622. BOOL state_key_down;
  623. DPF( 4, "sending sys key to USER key=%04x state=%08x",sys_key,sys_state);
  624. if (sys_state & 0x20000000)
  625. state_key = VK_MENU;
  626. else
  627. state_key = VK_CONTROL;
  628. state_key_down = GetAsyncKeyState(state_key) < 0;
  629. if (!state_key_down)
  630. keybd_event(state_key, 0, 0, 0);
  631. keybd_event(sys_key, 0, 0, 0);
  632. keybd_event(sys_key, 0, KEYEVENTF_KEYUP, 0);
  633. if (!state_key_down)
  634. keybd_event(state_key, 0, KEYEVENTF_KEYUP, 0);
  635. }
  636. }
  637. #endif
  638. sys_key = 0;
  639. } /* handleActivateApp */
  640. static DWORD dwTime2=0;
  641. /*
  642. * tryHotKey
  643. */
  644. static void tryHotKey( WORD flags )
  645. {
  646. static int iState=0;
  647. static DWORD dwTime=0;
  648. #define TOGGLE1 0xe02a
  649. #define TOGGLE2 0xe036
  650. if( !bHelperStarting )
  651. {
  652. if( iState == 0 )
  653. {
  654. if( flags == TOGGLE1 )
  655. {
  656. dwTime = GetTickCount();
  657. iState++;
  658. }
  659. }
  660. else
  661. {
  662. if( iState == 5 )
  663. {
  664. iState = 0;
  665. if( flags == TOGGLE2 )
  666. {
  667. if( (GetTickCount() - dwTime) < 2500 )
  668. {
  669. if( InterlockedExchange( &bHelperStarting, TRUE ) )
  670. {
  671. return;
  672. }
  673. dwTime2 = GetTickCount();
  674. DPF( 5, "********** GET READY FOR A SURPRISE **********" );
  675. return;
  676. }
  677. }
  678. }
  679. else
  680. {
  681. if( !(iState & 1) )
  682. {
  683. iState = (flags == TOGGLE1) ? iState+1 : 0;
  684. }
  685. else
  686. {
  687. iState = (flags == TOGGLE2) ? iState+1 : 0;
  688. }
  689. }
  690. }
  691. }
  692. else
  693. {
  694. if( !bStartHelper )
  695. {
  696. bHelperStarting = FALSE;
  697. dwTime2 = 0;
  698. }
  699. }
  700. return;
  701. } /* tryHotKey */
  702. static LPDDWINDOWINFO GetDDrawWindowInfo( HWND hwnd )
  703. {
  704. LPDDWINDOWINFO lpwi=lpWindowInfo;
  705. while( NULL != lpwi )
  706. {
  707. if( lpwi->hWnd == hwnd )
  708. {
  709. return lpwi;
  710. }
  711. lpwi = lpwi->lpLink;
  712. }
  713. return NULL;
  714. }
  715. static void delete_wininfo( LPDDWINDOWINFO curr )
  716. {
  717. LPDDWINDOWINFO prev;
  718. if( NULL == curr )
  719. return;
  720. // curr is at the head of the list, delete it and return
  721. if( curr == lpWindowInfo )
  722. {
  723. lpWindowInfo = curr->lpLink;
  724. MemFree( curr );
  725. return;
  726. }
  727. if( NULL == lpWindowInfo )
  728. return;
  729. // find curr in the list, delete it and return
  730. for(prev=lpWindowInfo; NULL != prev->lpLink; prev = prev->lpLink)
  731. {
  732. if( curr == prev->lpLink )
  733. {
  734. break;
  735. }
  736. }
  737. if( NULL == prev->lpLink )
  738. {
  739. // couldn't find it
  740. return;
  741. }
  742. prev->lpLink = curr->lpLink;
  743. MemFree( curr );
  744. }
  745. /*
  746. * Copy the contents of the given surface to the clipboard
  747. */
  748. static HRESULT copySurfaceToClipboard( HWND hwnd,
  749. LPDDRAWI_DDRAWSURFACE_INT lpSurface,
  750. LPDDRAWI_DDRAWPALETTE_INT lpOverridePalette )
  751. {
  752. HRESULT hres;
  753. LPDDRAWI_DDRAWSURFACE_LCL lpSurfLcl;
  754. LPDDRAWI_DDRAWSURFACE_GBL lpSurfGbl;
  755. LPDDPIXELFORMAT lpddpf;
  756. DDSURFACEDESC ddsd;
  757. DWORD dwBitDepth;
  758. DWORD dwRBitMask;
  759. DWORD dwGBitMask;
  760. DWORD dwBBitMask;
  761. DWORD dwSize;
  762. DWORD dwDIBPitch;
  763. HANDLE hDIB;
  764. BITMAPINFO* lpDIB;
  765. HDC hdc;
  766. LPDDRAWI_DDRAWPALETTE_INT lpPalette;
  767. DWORD dwCompression;
  768. DWORD dwColorTableSize;
  769. RGBQUAD rgbColorTable[256];
  770. LPPALETTEENTRY lppeColorTable;
  771. PALETTEENTRY peColorTable[256];
  772. LPBYTE lpBits;
  773. int i;
  774. DWORD y;
  775. LPBYTE lpDstScan;
  776. LPBYTE lpSrcScan;
  777. DDASSERT( NULL != lpSurface );
  778. lpSurfLcl = lpSurface->lpLcl;
  779. DDASSERT( NULL != lpSurfLcl );
  780. lpSurfGbl = lpSurfLcl->lpGbl;
  781. DDASSERT( NULL != lpSurfGbl );
  782. if( lpSurfLcl->dwFlags & DDRAWISURF_HASPIXELFORMAT )
  783. lpddpf = &lpSurfGbl->ddpfSurface;
  784. else
  785. lpddpf = &lpSurfLcl->lpSurfMore->lpDD_lcl->lpGbl->vmiData.ddpfDisplay;
  786. dwBitDepth = lpddpf->dwRGBBitCount;
  787. dwRBitMask = lpddpf->dwRBitMask;
  788. dwGBitMask = lpddpf->dwGBitMask;
  789. dwBBitMask = lpddpf->dwBBitMask;
  790. switch (dwBitDepth)
  791. {
  792. case 8UL:
  793. if(! ( lpddpf->dwFlags & DDPF_PALETTEINDEXED8 ) )
  794. {
  795. DPF( 0, "Non-palettized 8-bit surfaces are not supported" );
  796. return DDERR_INVALIDPIXELFORMAT;
  797. }
  798. dwColorTableSize = 256UL;
  799. if( NULL != lpOverridePalette )
  800. lpPalette = lpOverridePalette;
  801. else
  802. lpPalette = lpSurfLcl->lpDDPalette;
  803. if( NULL == lpPalette )
  804. {
  805. hdc = (HDC) lpSurfLcl->lpSurfMore->lpDD_lcl->hDC;
  806. if( NULL == hdc )
  807. {
  808. DPF( 2, "No palette attached. Non-display driver. Using gray scale." );
  809. for( i = 0; i < 256; i++ )
  810. {
  811. peColorTable[i].peRed = (BYTE)i;
  812. peColorTable[i].peGreen = (BYTE)i;
  813. peColorTable[i].peBlue = (BYTE)i;
  814. peColorTable[i].peFlags = 0;
  815. }
  816. }
  817. else
  818. {
  819. DPF( 2, "No palette attached. Using system palette entries" );
  820. GetSystemPaletteEntries( hdc, 0, 256, peColorTable );
  821. }
  822. lppeColorTable = peColorTable;
  823. }
  824. else
  825. {
  826. DDASSERT( NULL != lpPalette->lpLcl );
  827. DDASSERT( NULL != lpPalette->lpLcl->lpGbl );
  828. if( !( lpPalette->lpLcl->lpGbl->dwFlags & DDRAWIPAL_256 ) )
  829. {
  830. DPF( 0, "Palette is not an 8-bit palette" );
  831. return DDERR_INVALIDPIXELFORMAT;
  832. }
  833. lppeColorTable = lpPalette->lpLcl->lpGbl->lpColorTable;
  834. DDASSERT( NULL != lppeColorTable );
  835. }
  836. for (i = 0; i < 256; i++)
  837. {
  838. rgbColorTable[i].rgbBlue = lppeColorTable->peBlue;
  839. rgbColorTable[i].rgbGreen = lppeColorTable->peGreen;
  840. rgbColorTable[i].rgbRed = lppeColorTable->peRed;
  841. rgbColorTable[i].rgbReserved = 0;
  842. lppeColorTable++;
  843. }
  844. dwCompression = BI_RGB;
  845. break;
  846. case 16UL:
  847. if( ( 0x7C00UL == dwRBitMask ) &&
  848. ( 0x03E0UL == dwGBitMask ) &&
  849. ( 0x001FUL == dwBBitMask ) )
  850. {
  851. dwColorTableSize = 0UL;
  852. dwCompression = BI_RGB;
  853. }
  854. else if( ( 0xF800UL == dwRBitMask ) &&
  855. ( 0x07E0UL == dwGBitMask ) &&
  856. ( 0x001FUL == dwBBitMask ) )
  857. {
  858. dwColorTableSize = 3UL;
  859. rgbColorTable[0] = *( (RGBQUAD*) &dwRBitMask );
  860. rgbColorTable[1] = *( (RGBQUAD*) &dwGBitMask );
  861. rgbColorTable[2] = *( (RGBQUAD*) &dwBBitMask );
  862. dwCompression = BI_BITFIELDS;
  863. }
  864. else
  865. {
  866. DPF( 0, "Unsupported 16-bit pixel format" );
  867. return DDERR_INVALIDPIXELFORMAT;
  868. }
  869. break;
  870. case 24UL:
  871. if( ( 0x000000FFUL == dwBBitMask ) &&
  872. ( 0x0000FF00UL == dwGBitMask ) &&
  873. ( 0x00FF0000UL == dwRBitMask ) )
  874. {
  875. dwColorTableSize = 0UL;
  876. dwCompression = BI_RGB;
  877. }
  878. else
  879. {
  880. DPF( 0, "Unsupported 24-bit pixel format" );
  881. return DDERR_INVALIDPIXELFORMAT;
  882. }
  883. break;
  884. case 32UL:
  885. if( ( 0x000000FFUL == dwRBitMask ) &&
  886. ( 0x0000FF00UL == dwGBitMask ) &&
  887. ( 0x00FF0000UL == dwBBitMask ) )
  888. {
  889. dwColorTableSize = 0UL;
  890. dwCompression = BI_RGB;
  891. }
  892. else if( ( 0x00FF0000UL == dwRBitMask ) &&
  893. ( 0x0000FF00UL == dwGBitMask ) &&
  894. ( 0x000000FFUL == dwBBitMask ) )
  895. {
  896. dwColorTableSize = 3UL;
  897. rgbColorTable[0] = *( (RGBQUAD*) &dwRBitMask );
  898. rgbColorTable[1] = *( (RGBQUAD*) &dwGBitMask );
  899. rgbColorTable[2] = *( (RGBQUAD*) &dwBBitMask );
  900. dwCompression = BI_BITFIELDS;
  901. }
  902. else
  903. {
  904. DPF( 0, "Unsupported 32-bit pixel format" );
  905. return DDERR_INVALIDPIXELFORMAT;
  906. }
  907. break;
  908. default:
  909. DPF( 0, "Unsupported pixel depth" );
  910. return DDERR_INVALIDPIXELFORMAT;
  911. };
  912. dwDIBPitch = ( ( ( ( lpSurfGbl->wWidth * dwBitDepth ) + 31 ) >> 3 ) & ~0x03UL );
  913. dwSize = sizeof( BITMAPINFOHEADER ) +
  914. ( dwColorTableSize * sizeof( RGBQUAD ) ) +
  915. ( lpSurfGbl->wHeight * dwDIBPitch );
  916. hDIB = GlobalAlloc( GHND | GMEM_DDESHARE, dwSize );
  917. if( 0UL == hDIB )
  918. {
  919. DPF( 0, "Unsufficient memory for DIB" );
  920. return DDERR_OUTOFMEMORY;
  921. }
  922. lpDIB = (BITMAPINFO*) GlobalLock( hDIB );
  923. if( NULL == lpDIB )
  924. {
  925. DPF( 0, "Unsufficient memory for DIB" );
  926. GlobalFree( hDIB );
  927. return DDERR_OUTOFMEMORY;
  928. }
  929. lpBits = ( (LPBYTE) lpDIB ) + sizeof( BITMAPINFOHEADER ) + ( dwColorTableSize * sizeof( RGBQUAD ) );
  930. lpDIB->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
  931. lpDIB->bmiHeader.biWidth = (LONG) lpSurfGbl->wWidth;
  932. lpDIB->bmiHeader.biHeight = (LONG) lpSurfGbl->wHeight;
  933. lpDIB->bmiHeader.biPlanes = 1;
  934. lpDIB->bmiHeader.biBitCount = (WORD) dwBitDepth;
  935. lpDIB->bmiHeader.biCompression = dwCompression;
  936. lpDIB->bmiHeader.biXPelsPerMeter = 1L;
  937. lpDIB->bmiHeader.biYPelsPerMeter = 1L;
  938. if( 8UL == dwBitDepth )
  939. {
  940. lpDIB->bmiHeader.biClrUsed = 256UL;
  941. lpDIB->bmiHeader.biClrImportant = 256UL;
  942. }
  943. else
  944. {
  945. lpDIB->bmiHeader.biClrUsed = 0UL;
  946. lpDIB->bmiHeader.biClrImportant = 0UL;
  947. }
  948. if( 0UL != dwColorTableSize )
  949. CopyMemory( &lpDIB->bmiColors[0], rgbColorTable, dwColorTableSize * sizeof( RGBQUAD ) );
  950. ZeroMemory( &ddsd, sizeof( ddsd ) );
  951. ddsd.dwSize = sizeof( ddsd );
  952. hres = DD_Surface_Lock( (LPDIRECTDRAWSURFACE) lpSurface,
  953. NULL,
  954. &ddsd,
  955. DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,
  956. 0UL );
  957. if( FAILED( hres ) )
  958. {
  959. DPF( 0, "Could not lock the surface" );
  960. GlobalUnlock( hDIB );
  961. GlobalFree( hDIB );
  962. return hres;
  963. }
  964. for( y = 0; y < ddsd.dwHeight; y++ )
  965. {
  966. lpDstScan = lpBits + ( y * dwDIBPitch );
  967. lpSrcScan = ( (LPBYTE) ddsd.lpSurface ) + ( ( ( ddsd.dwHeight - 1UL ) - y ) * ddsd.lPitch );
  968. CopyMemory( lpDstScan, lpSrcScan, dwDIBPitch );
  969. }
  970. hres = DD_Surface_Unlock( (LPDIRECTDRAWSURFACE) lpSurface, NULL );
  971. if( FAILED( hres ) )
  972. {
  973. DPF( 0, "Could not unlock the surface" );
  974. GlobalUnlock( hDIB );
  975. GlobalFree( hDIB );
  976. return hres;
  977. }
  978. GlobalUnlock( hDIB );
  979. if( OpenClipboard( hwnd ) )
  980. {
  981. EmptyClipboard();
  982. if( NULL == SetClipboardData( CF_DIB, hDIB ) )
  983. {
  984. DPF( 0, "Could not copy the bitmap to the clipboard" );
  985. return DDERR_GENERIC;
  986. }
  987. CloseClipboard();
  988. }
  989. else
  990. {
  991. DPF( 0, "Clipboard open by another application" );
  992. DDERR_GENERIC;
  993. }
  994. return DD_OK;
  995. } /* copySurfaceToClipboard */
  996. /*
  997. * HandleTimer
  998. *
  999. * This function exists because it requires some local variables and if
  1000. * we always push them on the stack each time the WindowProc is called, we
  1001. * see cases where the stack crashes. By putting them in a sperate function,
  1002. * they only get pushed when a timer message occurs.
  1003. */
  1004. void HandleTimer( LPDDWINDOWINFO curr )
  1005. {
  1006. HWND hwndTopmostList[MAX_TIMER_HWNDS];
  1007. BOOL bFound;
  1008. int iCnt;
  1009. int i;
  1010. int j;
  1011. DPF(4, "Bringing window to top");
  1012. /*
  1013. * Save the hwnds locally since the list can change
  1014. * out from under us.
  1015. */
  1016. iCnt = 0;
  1017. while( iCnt < giTopmostCnt )
  1018. {
  1019. hwndTopmostList[iCnt] = ghwndTopmostList[iCnt++];
  1020. }
  1021. giTopmostCnt = 0;
  1022. for( i = 0; i < iCnt; i++ )
  1023. {
  1024. /*
  1025. * There may be duplicates in the list, so make sure
  1026. * to call SetWindowPos only once per hwnd.
  1027. */
  1028. bFound = FALSE;
  1029. for( j = 0; (j < i) && !bFound; j++ )
  1030. {
  1031. if( hwndTopmostList[i] == hwndTopmostList[j] )
  1032. {
  1033. bFound = TRUE;
  1034. }
  1035. }
  1036. if( !bFound )
  1037. {
  1038. curr->dwFlags |= WININFO_SELFSIZE;
  1039. SetWindowPos( hwndTopmostList[i], HWND_TOPMOST,
  1040. 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  1041. curr->dwFlags &= ~WININFO_SELFSIZE;
  1042. }
  1043. }
  1044. }
  1045. /*
  1046. * This function exists for the same reason as HandleTimer
  1047. */
  1048. void CopyPrimaryToClipBoard(HWND hWnd, LPDDWINDOWINFO curr)
  1049. {
  1050. LPDDRAWI_DIRECTDRAW_GBL this;
  1051. LPDDRAWI_DIRECTDRAW_LCL this_lcl;
  1052. LPDDRAWI_DDRAWSURFACE_INT lpPrimary;
  1053. ENTER_DDRAW();
  1054. this_lcl = curr->DDInfo.lpDD_lcl;
  1055. DDASSERT( NULL != this_lcl );
  1056. this = this_lcl->lpGbl;
  1057. DDASSERT( NULL != this );
  1058. lpPrimary = this_lcl->lpPrimary;
  1059. if( NULL != lpPrimary)
  1060. {
  1061. if( this->dwFlags & DDRAWI_MODEX )
  1062. {
  1063. LPDIRECTDRAWSURFACE lpSurface;
  1064. LPDIRECTDRAWSURFACE lpBackBuffer;
  1065. LPDDRAWI_DDRAWSURFACE_INT lpBackBufferInt;
  1066. LPDDRAWI_DDRAWPALETTE_INT lpPalette;
  1067. DDSCAPS ddscaps;
  1068. HRESULT hres;
  1069. DPF( 4, "Copying ModeX backbuffer to the clipboard" );
  1070. lpSurface = (LPDIRECTDRAWSURFACE) this_lcl->lpPrimary;
  1071. ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  1072. hres = lpSurface->lpVtbl->GetAttachedSurface( lpSurface, &ddscaps, &lpBackBuffer );
  1073. if( !FAILED( hres ) )
  1074. {
  1075. DDASSERT( NULL != lpBackBuffer );
  1076. lpBackBufferInt = (LPDDRAWI_DDRAWSURFACE_INT) lpBackBuffer;
  1077. if( NULL == lpBackBufferInt->lpLcl->lpDDPalette )
  1078. {
  1079. DPF( 2, "Using ModeX primary palette for PRINTSCREEN" );
  1080. DDASSERT( NULL != lpPrimary->lpLcl );
  1081. lpPalette = lpPrimary->lpLcl->lpDDPalette;
  1082. }
  1083. else
  1084. {
  1085. DPF( 2, "Using ModeX backbuffer palette for PRINTSCREEN" );
  1086. DDASSERT( NULL != lpBackBufferInt->lpLcl );
  1087. lpPalette = lpBackBufferInt->lpLcl->lpDDPalette;
  1088. }
  1089. copySurfaceToClipboard( hWnd, lpBackBufferInt, lpPalette );
  1090. lpBackBuffer->lpVtbl->Release( lpBackBuffer );
  1091. }
  1092. else
  1093. {
  1094. DPF( 0, "Could not PRINTSCREEN - ModeX primary has no attached backbuffer" );
  1095. }
  1096. }
  1097. else
  1098. {
  1099. DPF( 4, "Copying linear primary surface to the clipboard" );
  1100. copySurfaceToClipboard( hWnd, lpPrimary, NULL );
  1101. }
  1102. }
  1103. else
  1104. {
  1105. DPF( 0, "Could not PRINTSCREEN - no primary" );
  1106. }
  1107. LEAVE_DDRAW();
  1108. }
  1109. /*
  1110. * WindowProc
  1111. */
  1112. LRESULT WINAPI WindowProc(
  1113. HWND hWnd,
  1114. UINT uMsg,
  1115. WPARAM wParam,
  1116. LPARAM lParam )
  1117. {
  1118. #ifdef GDIDDPAL
  1119. LPDDRAWI_DDRAWPALETTE_LCL ppal_lcl;
  1120. #endif
  1121. LPDDRAWI_DIRECTDRAW_LCL this_lcl;
  1122. LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
  1123. BOOL is_active;
  1124. LPDDWINDOWINFO curr;
  1125. WNDPROC proc;
  1126. BOOL get_away;
  1127. LRESULT rc;
  1128. BOOL is_hot;
  1129. BOOL is_excl;
  1130. /*
  1131. * find the hwnd
  1132. */
  1133. curr = GetDDrawWindowInfo(hWnd);
  1134. if( curr == NULL || curr->dwSmag != WININFO_MAGIC )
  1135. {
  1136. DPF( 0, "FATAL ERROR! Window Proc Called for hWnd %08lx, but not in list!", hWnd );
  1137. DEBUG_BREAK();
  1138. return DefWindowProc( hWnd, uMsg, wParam, lParam );
  1139. }
  1140. /*
  1141. * unhook at destroy (or if the WININFO_UNHOOK bit is set)
  1142. */
  1143. proc = curr->lpWndProc;
  1144. if( uMsg == WM_NCDESTROY )
  1145. {
  1146. DPF (4, "*** WM_NCDESTROY unhooking window ***" );
  1147. curr->dwFlags |= WININFO_UNHOOK;
  1148. }
  1149. if( curr->dwFlags & WININFO_UNHOOK )
  1150. {
  1151. DPF (4, "*** Unhooking window proc" );
  1152. if (curr->dwFlags & WININFO_ZOMBIE)
  1153. {
  1154. DPF (4, "*** Freeing ZOMBIE WININFO ***" );
  1155. delete_wininfo( curr );
  1156. }
  1157. KillTimer(hWnd,TOPMOST_ID);
  1158. SetWindowLongPtr( hWnd, GWLP_WNDPROC, (INT_PTR) proc );
  1159. rc = CallWindowProc( proc, hWnd, uMsg, wParam, lParam );
  1160. return rc;
  1161. }
  1162. /*
  1163. * Code to defer app activation of minimized app until it is restored.
  1164. */
  1165. switch( uMsg )
  1166. {
  1167. #ifdef WIN95
  1168. case WM_POWERBROADCAST:
  1169. if( (wParam == PBT_APMSUSPEND) || (wParam == PBT_APMSTANDBY) )
  1170. #else
  1171. //winnt doesn't know about standby vs suspend
  1172. case WM_POWER:
  1173. if( wParam == PWR_SUSPENDREQUEST)
  1174. #endif
  1175. {
  1176. DPF( 4, "WM_POWERBROADCAST: deactivating application" );
  1177. SendMessage( hWnd, WM_ACTIVATEAPP, 0, GetCurrentThreadId() );
  1178. }
  1179. break;
  1180. case WM_SIZE:
  1181. DPF( 4, "WM_SIZE hWnd=%X wp=%04X, lp=%08X", hWnd, wParam, lParam);
  1182. if( !(curr->dwFlags & WININFO_INACTIVATEAPP)
  1183. && ((wParam == SIZE_RESTORED) || (wParam == SIZE_MAXIMIZED))
  1184. && !(curr->dwFlags & WININFO_SELFSIZE)
  1185. && (GetForegroundWindow() == hWnd) )
  1186. {
  1187. #ifdef WINNT
  1188. //
  1189. // Wouldncha know it, but NT's messaging order is HUGELY different when alt-tabbing
  1190. // between two exclusive mode apps. The first WM_SIZE sent to the activating app is
  1191. // sent BEFORE the deactivating app loses FSE. This WM_SIZE is totally necessary to
  1192. // reactivate the activating app, but it has to wait until the app loses FSE.
  1193. // So, we simply wait on the exclusive mode mutex. This seems to work!
  1194. //
  1195. {
  1196. DWORD dwWaitResult;
  1197. dwWaitResult = WaitForSingleObject(hExclusiveModeMutex, INFINITE);
  1198. switch (dwWaitResult)
  1199. {
  1200. case WAIT_OBJECT_0:
  1201. case WAIT_ABANDONED:
  1202. ReleaseMutex( hExclusiveModeMutex );
  1203. break;
  1204. case WAIT_TIMEOUT:
  1205. default:
  1206. DDASSERT(!"Unexpected return value from WaitForSingleObject");
  1207. }
  1208. }
  1209. #endif
  1210. DPF( 4, "WM_SIZE: Window restored, sending WM_ACTIVATEAPP" );
  1211. PostMessage( hWnd, WM_ACTIVATEAPP, 1, GetCurrentThreadId() );
  1212. }
  1213. else
  1214. {
  1215. DPF( 4, "WM_SIZE: Window restored, NOT sending WM_ACTIVATEAPP" );
  1216. }
  1217. break;
  1218. case WM_ACTIVATEAPP:
  1219. if( IsIconic( hWnd ) && wParam )
  1220. {
  1221. DPF( 4, "WM_ACTIVATEAPP: Ignoring while minimized" );
  1222. return 0;
  1223. }
  1224. else
  1225. {
  1226. curr->dwFlags |= WININFO_INACTIVATEAPP;
  1227. }
  1228. break;
  1229. case WM_KEYUP:
  1230. if( ( VK_SNAPSHOT == wParam ) && ( dwRegFlags & DDRAW_REGFLAGS_ENABLEPRINTSCRN ) )
  1231. {
  1232. CopyPrimaryToClipBoard(hWnd, curr);
  1233. }
  1234. break;
  1235. }
  1236. /*
  1237. * direct sound need to be called?
  1238. */
  1239. if ( curr->dwFlags & WININFO_DSOUNDHOOKED )
  1240. {
  1241. if( curr->lpDSoundCallback != NULL )
  1242. {
  1243. curr->lpDSoundCallback( hWnd, uMsg, wParam, lParam );
  1244. }
  1245. }
  1246. /*
  1247. * is directdraw involved here?
  1248. */
  1249. if( !(curr->dwFlags & WININFO_DDRAWHOOKED) )
  1250. {
  1251. rc = CallWindowProc( proc, hWnd, uMsg, wParam, lParam );
  1252. // clear the WININFO_INACTIVATEAPP bit, but make sure to make sure
  1253. // we are still hooked!
  1254. if (uMsg == WM_ACTIVATEAPP && (GetDDrawWindowInfo(hWnd) != NULL))
  1255. {
  1256. curr->dwFlags &= ~WININFO_INACTIVATEAPP;
  1257. }
  1258. return rc;
  1259. }
  1260. #ifdef DEBUG
  1261. if ( (curr->DDInfo.dwDDFlags & DDSCL_FULLSCREEN) &&
  1262. !(curr->DDInfo.dwDDFlags & DDSCL_NOWINDOWCHANGES) &&
  1263. !IsIconic(hWnd) )
  1264. {
  1265. if (GetForegroundWindow() == hWnd)
  1266. {
  1267. HWND hwndT;
  1268. RECT rc,rcT;
  1269. GetWindowRect(hWnd, &rc);
  1270. for (hwndT = GetWindow(hWnd, GW_HWNDFIRST);
  1271. hwndT && hwndT != hWnd;
  1272. hwndT = GetWindow(hwndT, GW_HWNDNEXT))
  1273. {
  1274. if (IsWindowVisible(hwndT))
  1275. {
  1276. GetWindowRect(hwndT, &rcT);
  1277. if (IntersectRect(&rcT, &rcT, &rc))
  1278. {
  1279. DPF(4, "Window %08x is on top of us!!", hwndT);
  1280. }
  1281. }
  1282. }
  1283. }
  1284. }
  1285. #endif
  1286. /*
  1287. * NOTE: we don't take the DLL csect here. By not doing this, we can
  1288. * up the performance here. However, this means that the application
  1289. * could have a separate thread kill exclusive mode while window
  1290. * messages were being processed. This could cause our death.
  1291. * Is this OK?
  1292. */
  1293. this_lcl = curr->DDInfo.lpDD_lcl;
  1294. switch( uMsg )
  1295. {
  1296. /*
  1297. * WM_SYSKEYUP
  1298. *
  1299. * watch for system keys of app trying to switch away from us...
  1300. *
  1301. * we only need to do this on Win95 because we have disabled all
  1302. * the task-switching hot keys. on NT we will get switched
  1303. * away from normaly by the system.
  1304. */
  1305. //#ifdef WIN95
  1306. case WM_SYSKEYUP:
  1307. DPF( 4, "WM_SYSKEYUP: wParam=%08lx lParam=%08lx", wParam, lParam );
  1308. get_away = FALSE;
  1309. is_hot = FALSE;
  1310. if( wParam == VK_TAB )
  1311. {
  1312. if( lParam & 0x20000000l )
  1313. {
  1314. if( curr->dwFlags & WININFO_IGNORENEXTALTTAB )
  1315. {
  1316. DPF( 5, "AHHHHHHHHHHHH Ignoring AltTab" );
  1317. }
  1318. else
  1319. {
  1320. get_away = TRUE;
  1321. }
  1322. }
  1323. }
  1324. else if( wParam == VK_ESCAPE )
  1325. {
  1326. get_away = TRUE;
  1327. }
  1328. #ifdef WIN95
  1329. else if( wParam == VK_SHIFT )
  1330. {
  1331. if( HIBYTE( HIWORD( lParam ) ) == 0xe0 )
  1332. {
  1333. tryHotKey( HIWORD( lParam ) );
  1334. }
  1335. }
  1336. #endif
  1337. is_excl = ((this_lcl->dwLocalFlags & DDRAWILCL_HASEXCLUSIVEMODE) != 0);
  1338. #ifdef WIN95
  1339. if( get_away && dwTime2 != 0 )
  1340. {
  1341. if( GetTickCount() - dwTime2 < 2500 )
  1342. {
  1343. DPF( 4, "********** WANT TO SEE SOMETHING _REALLY_ SCARY? *************" );
  1344. bStartHelper = TRUE;
  1345. is_hot = TRUE;
  1346. }
  1347. else
  1348. {
  1349. bHelperStarting = FALSE;
  1350. dwTime2 = 0;
  1351. }
  1352. }
  1353. else
  1354. {
  1355. bHelperStarting = FALSE;
  1356. }
  1357. #endif
  1358. curr->dwFlags &= ~WININFO_IGNORENEXTALTTAB;
  1359. if( (get_away && is_excl) || is_hot )
  1360. {
  1361. DPF( 4, "Hot key pressed, switching away from app" );
  1362. if( is_hot && !is_excl )
  1363. {
  1364. PostMessage( hWnd, WM_USER+0x1234, 0xFFBADADD, 0xFFADDBAD );
  1365. }
  1366. else
  1367. {
  1368. sys_key = (BYTE)wParam;
  1369. sys_state = (DWORD)lParam;
  1370. PostMessage( hWnd, WM_ACTIVATEAPP, 0, GetCurrentThreadId() );
  1371. }
  1372. }
  1373. break;
  1374. //#endif
  1375. /*
  1376. * WM_SYSCOMMAND
  1377. *
  1378. * watch for screen savers, and don't allow them!
  1379. *
  1380. */
  1381. case WM_SYSCOMMAND:
  1382. is_excl = ((this_lcl->dwLocalFlags & DDRAWILCL_HASEXCLUSIVEMODE) != 0);
  1383. if( is_excl )
  1384. {
  1385. switch( wParam )
  1386. {
  1387. case SC_SCREENSAVE:
  1388. DPF( 3, "Ignoring screen saver!" );
  1389. return 1;
  1390. #ifndef WINNT
  1391. case SC_MONITORPOWER:
  1392. /*
  1393. * Allow screen savers to power down but not apps.
  1394. * This is because windows doesn't see joystick events
  1395. * so will power down a game even though they have been
  1396. * using the joystick.
  1397. */
  1398. if( this_lcl->dwAppHackFlags & DDRAW_APPCOMPAT_SCREENSAVER )
  1399. {
  1400. /*
  1401. * However, we don't want the screen saver to call the
  1402. * hardware because things can go wrong, so we will simply
  1403. * invalidate all of the surfaces and not allowed them
  1404. * to be restored until we are powered back up.
  1405. */
  1406. this_lcl->dwLocalFlags |= DDRAWILCL_POWEREDDOWN;
  1407. InvalidateAllSurfaces( this_lcl->lpGbl,
  1408. (HANDLE) this_lcl->hDDVxd, TRUE );
  1409. }
  1410. else
  1411. {
  1412. DPF( 3, "Ignoring monitor power command!" );
  1413. return 1;
  1414. }
  1415. break;
  1416. #endif
  1417. // allow window to be restored even if it has popup(s)
  1418. case SC_RESTORE:
  1419. if (this_lcl->hWndPopup)
  1420. {
  1421. ShowWindow(hWnd, SW_RESTORE);
  1422. }
  1423. break;
  1424. }
  1425. }
  1426. break;
  1427. case WM_TIMER:
  1428. if (wParam == TOPMOST_ID )
  1429. {
  1430. if ( GetForegroundWindow() == hWnd && !IsIconic(hWnd) )
  1431. {
  1432. HandleTimer(curr);
  1433. }
  1434. KillTimer(hWnd, wParam);
  1435. return 0;
  1436. }
  1437. break;
  1438. #ifdef USESHOWWINDOW
  1439. case WM_DISPLAYCHANGE:
  1440. DPF( 4, "WM_DISPLAYCHANGE: %dx%dx%d", LOWORD(lParam), HIWORD(lParam), wParam );
  1441. //
  1442. // WM_DISPLAYCHANGE is *sent* to the thread that called
  1443. // change display settings, we will most likely have the
  1444. // direct draw lock, make sure we set the WININFO_SELFSIZE
  1445. // bit while calling down the chain to prevent deadlock
  1446. //
  1447. if ( (DDSCL_DX8APP & curr->DDInfo.dwDDFlags) &&
  1448. !(DDRAWI_FULLSCREEN & this_lcl->lpGbl->dwFlags ))
  1449. {
  1450. // this is caused by DoneExclusiveMode() to restore original desktop
  1451. return 0L; // don't send to app, it's caused by MakeFullScreen
  1452. }
  1453. curr->dwFlags |= WININFO_SELFSIZE;
  1454. if ( (curr->DDInfo.dwDDFlags & DDSCL_FULLSCREEN) &&
  1455. !(curr->DDInfo.dwDDFlags & DDSCL_NOWINDOWCHANGES) )
  1456. {
  1457. MakeAllFullscreen(this_lcl, hWnd);
  1458. }
  1459. rc = CallWindowProc( proc, hWnd, uMsg, wParam, lParam );
  1460. // clear the WININFO_SELFSIZE bit, but make sure to make sure
  1461. // we are still hooked!
  1462. if (GetDDrawWindowInfo(hWnd) != NULL)
  1463. {
  1464. curr->dwFlags &= ~WININFO_SELFSIZE;
  1465. }
  1466. return rc;
  1467. #endif
  1468. /*
  1469. * WM_ACTIVATEAPP
  1470. *
  1471. * the application has been reactivated. In this case, we need to
  1472. * reset the mode
  1473. *
  1474. */
  1475. case WM_ACTIVATEAPP:
  1476. is_excl = ((this_lcl->dwLocalFlags & DDRAWILCL_HASEXCLUSIVEMODE) != 0);
  1477. if( is_excl )
  1478. {
  1479. is_active = (BOOL)wParam && GetForegroundWindow() == hWnd && !IsIconic(hWnd);
  1480. #ifdef DEBUG
  1481. /*
  1482. * Hack to allow debugging on multi-mon systems w/o minimizing
  1483. * the app all of the time.
  1484. */
  1485. if( this_lcl->dwLocalFlags & DDRAWILCL_DISABLEINACTIVATE )
  1486. {
  1487. wParam = is_active = TRUE;
  1488. }
  1489. #endif
  1490. if (!is_active && wParam != 0)
  1491. {
  1492. DPF( 3, "WM_ACTIVATEAPP: setting wParam to 0, not realy active");
  1493. wParam = 0;
  1494. }
  1495. if( is_active )
  1496. {
  1497. DPF( 5, "WM_ACTIVATEAPP: BEGIN Activating app pid=%08lx, tid=%08lx",
  1498. GetCurrentProcessId(), GetCurrentThreadId() );
  1499. }
  1500. else
  1501. {
  1502. DPF( 5, "WM_ACTIVATEAPP: BEGIN Deactivating app pid=%08lx, tid=%08lx",
  1503. GetCurrentProcessId(), GetCurrentThreadId() );
  1504. }
  1505. ENTER_DDRAW();
  1506. if( is_active && (this_lcl->dwLocalFlags & DDRAWILCL_ACTIVEYES) )
  1507. {
  1508. DPF( 4, "*** Already activated" );
  1509. }
  1510. else
  1511. if( !is_active && (this_lcl->dwLocalFlags & DDRAWILCL_ACTIVENO) )
  1512. {
  1513. DPF( 4, "*** Already deactivated" );
  1514. }
  1515. else
  1516. {
  1517. DPF( 4, "*** Active state changing" );
  1518. if( is_active )
  1519. {
  1520. if (GetAsyncKeyState( VK_MENU ) < 0)
  1521. DPF(4, "ALT key is DOWN");
  1522. if (GetKeyState( VK_MENU ) < 0)
  1523. DPF(4, "we think the ALT key is DOWN");
  1524. if( GetAsyncKeyState( VK_MENU ) < 0 )
  1525. {
  1526. curr->dwFlags |= WININFO_IGNORENEXTALTTAB;
  1527. DPF( 4, "AHHHHHHH Setting to ignore next alt tab" );
  1528. }
  1529. else
  1530. {
  1531. curr->dwFlags &= ~WININFO_IGNORENEXTALTTAB;
  1532. }
  1533. }
  1534. /*
  1535. * In the multi-mon scenario, it's possible that multiple
  1536. * devices are using this same window, so we need to do
  1537. * the following for each device.
  1538. */
  1539. this_lcl->dwLocalFlags &= ~(DDRAWILCL_ACTIVEYES|DDRAWILCL_ACTIVENO);
  1540. if( is_active )
  1541. {
  1542. this_lcl->dwLocalFlags |= DDRAWILCL_ACTIVEYES;
  1543. }
  1544. else
  1545. {
  1546. this_lcl->dwLocalFlags |= DDRAWILCL_ACTIVENO;
  1547. }
  1548. handleActivateApp( this_lcl, curr, is_active, TRUE );
  1549. pdrv_lcl = lpDriverLocalList;
  1550. while( pdrv_lcl != NULL )
  1551. {
  1552. if( ( this_lcl->lpGbl != pdrv_lcl->lpGbl ) &&
  1553. ( pdrv_lcl->hFocusWnd == (ULONG_PTR) hWnd ) &&
  1554. ( pdrv_lcl->dwLocalFlags & DDRAWILCL_HASEXCLUSIVEMODE ) &&
  1555. ( pdrv_lcl->lpGbl->dwFlags & DDRAWI_DISPLAYDRV ) &&
  1556. ( this_lcl->lpGbl->dwFlags & DDRAWI_DISPLAYDRV ) )
  1557. {
  1558. pdrv_lcl->dwLocalFlags &= ~(DDRAWILCL_ACTIVEYES|DDRAWILCL_ACTIVENO);
  1559. if( is_active )
  1560. {
  1561. pdrv_lcl->dwLocalFlags |= DDRAWILCL_ACTIVEYES;
  1562. }
  1563. else
  1564. {
  1565. pdrv_lcl->dwLocalFlags |= DDRAWILCL_ACTIVENO;
  1566. }
  1567. handleActivateApp( pdrv_lcl, curr, is_active, FALSE );
  1568. }
  1569. pdrv_lcl = pdrv_lcl->lpLink;
  1570. }
  1571. }
  1572. #ifdef DEBUG
  1573. if( is_active )
  1574. {
  1575. DPF( 4, "WM_ACTIVATEAPP: DONE Activating app pid=%08lx, tid=%08lx",
  1576. GetCurrentProcessId(), GetCurrentThreadId() );
  1577. }
  1578. else
  1579. {
  1580. DPF( 4, "WM_ACTIVATEAPP: DONE Deactivating app pid=%08lx, tid=%08lx",
  1581. GetCurrentProcessId(), GetCurrentThreadId() );
  1582. }
  1583. #endif
  1584. // set focus to last active popup
  1585. if (is_active && this_lcl->hWndPopup)
  1586. {
  1587. if (IsWindow((HWND) this_lcl->hWndPopup))
  1588. {
  1589. SetFocus((HWND) this_lcl->hWndPopup);
  1590. }
  1591. this_lcl->hWndPopup = 0;
  1592. }
  1593. LEAVE_DDRAW();
  1594. HIDESHOW_IME(); //Show/hide the IME OUTSIDE of the ddraw critsect.
  1595. if( !is_active && bStartHelper )
  1596. {
  1597. PostMessage( hWnd, WM_USER+0x1234, 0xFFBADADD, 0xFFADDBAD );
  1598. }
  1599. }
  1600. rc = CallWindowProc( proc, hWnd, uMsg, wParam, lParam );
  1601. // clear the WININFO_INACTIVATEAPP bit, but make sure to make sure
  1602. // we are still hooked!
  1603. if (GetDDrawWindowInfo(hWnd) != NULL)
  1604. {
  1605. curr->dwFlags &= ~WININFO_INACTIVATEAPP;
  1606. }
  1607. return rc;
  1608. break;
  1609. #ifdef WIN95
  1610. case WM_USER+0x1234:
  1611. if( wParam == 0xFFBADADD && lParam == 0xFFADDBAD )
  1612. {
  1613. if( bStartHelper )
  1614. {
  1615. //HelperCreateThread();
  1616. }
  1617. bHelperStarting = FALSE;
  1618. bStartHelper = FALSE;
  1619. dwTime2 = 0;
  1620. return 0;
  1621. }
  1622. break;
  1623. #endif
  1624. #ifdef GDIDDPAL
  1625. case WM_PALETTECHANGED:
  1626. if( (HWND) wParam == hWnd )
  1627. {
  1628. break;
  1629. }
  1630. // fall through
  1631. case WM_QUERYNEWPALETTE:
  1632. ENTER_DDRAW();
  1633. ppal_lcl = getPalette( this_lcl );
  1634. if( ppal_lcl != NULL )
  1635. {
  1636. }
  1637. LEAVE_DDRAW();
  1638. break;
  1639. case WM_PAINT:
  1640. ENTER_DDRAW();
  1641. ppal_lcl = getPalette( this_lcl );
  1642. if( ppal_lcl != NULL )
  1643. {
  1644. }
  1645. LEAVE_DDRAW();
  1646. break;
  1647. #endif
  1648. }
  1649. if ((curr->dwFlags & WININFO_SELFSIZE) &&
  1650. (curr->DDInfo.dwDDFlags & DDSCL_DX8APP))
  1651. {
  1652. return 0L; // don't send to app, it's caused by MakeFullScreen
  1653. }
  1654. rc = CallWindowProc( proc, hWnd, uMsg, wParam, lParam );
  1655. return rc;
  1656. } /* WindowProc */
  1657. #undef DPF_MODNAME
  1658. #define DPF_MODNAME "SetCooperativeLevel"
  1659. /*
  1660. * DeviceWindowProc
  1661. *
  1662. * This is the Window Proc when the app asks us to create the device window.
  1663. */
  1664. LRESULT WINAPI DeviceWindowProc(
  1665. HWND hWnd,
  1666. UINT uMsg,
  1667. WPARAM wParam,
  1668. LPARAM lParam )
  1669. {
  1670. HWND hParent;
  1671. LPCREATESTRUCT lpCreate;
  1672. switch( uMsg )
  1673. {
  1674. case WM_CREATE:
  1675. lpCreate = (LPCREATESTRUCT) lParam;
  1676. SetWindowLongPtr( hWnd, 0, (INT_PTR) lpCreate->lpCreateParams );
  1677. break;
  1678. case WM_SETFOCUS:
  1679. hParent = (HWND) GetWindowLongPtr( hWnd, 0 );
  1680. if( IsWindow( hParent ) )
  1681. {
  1682. SetFocus( hParent );
  1683. }
  1684. break;
  1685. case WM_SETCURSOR:
  1686. SetCursor(NULL);
  1687. break;
  1688. }
  1689. return DefWindowProc( hWnd, uMsg, wParam, lParam );
  1690. } /* WindowProc */
  1691. /*
  1692. * CleanupWindowList
  1693. *
  1694. * This function is called by the helper thread after termination and
  1695. * it's purpose is to remove any entries in the window list that could
  1696. * be left around due to subclassing, etc.
  1697. */
  1698. VOID CleanupWindowList( DWORD pid )
  1699. {
  1700. LPDDWINDOWINFO curr;
  1701. /*
  1702. * find the window list item associated with this process
  1703. */
  1704. curr = lpWindowInfo;
  1705. while( curr != NULL )
  1706. {
  1707. if( curr->dwPid == pid )
  1708. {
  1709. break;
  1710. }
  1711. curr = curr->lpLink;
  1712. }
  1713. if( curr != NULL )
  1714. {
  1715. delete_wininfo( curr );
  1716. }
  1717. } /* CleanupWindowList */
  1718. /*
  1719. * internalSetAppHWnd
  1720. *
  1721. * Set the WindowList struct up with the app's hwnd info
  1722. * Must be called with DLL & driver locks taken.
  1723. */
  1724. HRESULT internalSetAppHWnd(
  1725. LPDDRAWI_DIRECTDRAW_LCL this_lcl,
  1726. HWND hWnd,
  1727. DWORD dwFlags,
  1728. BOOL is_ddraw,
  1729. WNDPROC lpDSoundWndProc,
  1730. DWORD pid )
  1731. {
  1732. LPDDWINDOWINFO curr;
  1733. LPDDWINDOWINFO prev;
  1734. /*
  1735. * find the window list item associated with this process
  1736. */
  1737. curr = lpWindowInfo;
  1738. prev = NULL;
  1739. while( curr != NULL )
  1740. {
  1741. if( curr->dwPid == pid )
  1742. {
  1743. break;
  1744. }
  1745. prev = curr;
  1746. curr = curr->lpLink;
  1747. }
  1748. /*
  1749. * check if this is OK
  1750. */
  1751. if( curr == NULL )
  1752. {
  1753. if( hWnd == NULL )
  1754. {
  1755. DPF( 1, "HWnd must be specified" );
  1756. return DDERR_NOHWND;
  1757. }
  1758. }
  1759. else
  1760. {
  1761. if( hWnd != NULL )
  1762. {
  1763. if( curr->hWnd != hWnd )
  1764. {
  1765. DPF( 1, "Hwnd %08lx no good: Different Hwnd (%08lx) already set for process",
  1766. hWnd, curr->hWnd );
  1767. return DDERR_HWNDALREADYSET;
  1768. }
  1769. }
  1770. }
  1771. /*
  1772. * are we shutting an HWND down?
  1773. */
  1774. if( hWnd == NULL )
  1775. {
  1776. if( is_ddraw )
  1777. {
  1778. curr->dwFlags &= ~WININFO_DDRAWHOOKED;
  1779. }
  1780. else
  1781. {
  1782. curr->dwFlags &= ~WININFO_DSOUNDHOOKED;
  1783. }
  1784. if( (curr->dwFlags & (WININFO_DSOUNDHOOKED|WININFO_DDRAWHOOKED)) == 0 )
  1785. {
  1786. if( IsWindow(curr->hWnd) )
  1787. {
  1788. WNDPROC proc;
  1789. proc = (WNDPROC) GetWindowLongPtr( curr->hWnd, GWLP_WNDPROC );
  1790. if( proc != (WNDPROC) WindowProc &&
  1791. proc != (WNDPROC) curr->lpWndProc )
  1792. {
  1793. DPF( 3, "Window has been subclassed; cannot restore!" );
  1794. curr->dwFlags |= WININFO_ZOMBIE;
  1795. }
  1796. else if (GetWindowThreadProcessId(curr->hWnd, NULL) !=
  1797. GetCurrentThreadId())
  1798. {
  1799. DPF( 3, "intra-thread window unhook, letting window proc do it" );
  1800. curr->dwFlags |= WININFO_UNHOOK;
  1801. curr->dwFlags |= WININFO_ZOMBIE;
  1802. PostMessage(curr->hWnd, WM_NULL, 0, 0);
  1803. }
  1804. else
  1805. {
  1806. DPF( 4, "Unsubclassing window %08lx", curr->hWnd );
  1807. KillTimer(hWnd,TOPMOST_ID);
  1808. SetWindowLongPtr( curr->hWnd, GWLP_WNDPROC, (INT_PTR) curr->lpWndProc );
  1809. delete_wininfo( curr );
  1810. }
  1811. }
  1812. else
  1813. {
  1814. delete_wininfo( curr );
  1815. }
  1816. }
  1817. }
  1818. /*
  1819. * changing or adding an hwnd then...
  1820. */
  1821. else
  1822. {
  1823. /*
  1824. * brand new object...
  1825. */
  1826. if( curr == NULL )
  1827. {
  1828. if( GetDDrawWindowInfo(hWnd) != NULL)
  1829. {
  1830. DPF_ERR("Window already has WinInfo structure");
  1831. return DDERR_INVALIDPARAMS;
  1832. }
  1833. curr = MemAlloc( sizeof( DDWINDOWINFO ) );
  1834. if( curr == NULL )
  1835. {
  1836. return DDERR_OUTOFMEMORY;
  1837. }
  1838. curr->dwSmag = WININFO_MAGIC;
  1839. curr->dwPid = pid;
  1840. curr->lpLink = lpWindowInfo;
  1841. lpWindowInfo = curr;
  1842. curr->hWnd = hWnd;
  1843. curr->lpWndProc = (WNDPROC) GetWindowLongPtr( hWnd, GWLP_WNDPROC );
  1844. SetWindowLongPtr( hWnd, GWLP_WNDPROC, (INT_PTR) WindowProc );
  1845. }
  1846. /*
  1847. * set ddraw/dsound specific data
  1848. */
  1849. if( is_ddraw )
  1850. {
  1851. curr->DDInfo.lpDD_lcl = this_lcl;
  1852. curr->DDInfo.dwDDFlags = dwFlags;
  1853. curr->dwFlags |= WININFO_DDRAWHOOKED;
  1854. }
  1855. else
  1856. {
  1857. curr->lpDSoundCallback = lpDSoundWndProc;
  1858. curr->dwFlags |= WININFO_DSOUNDHOOKED;
  1859. }
  1860. DPF( 4, "Subclassing window %08lx", curr->hWnd );
  1861. }
  1862. return DD_OK;
  1863. } /* internalSetAppHWnd */
  1864. /*
  1865. * ChangeHookedLCL
  1866. *
  1867. * This function is called when an object wants to un-hook the window,
  1868. * but another object is still using it. If the driver being unhooked is
  1869. * the one that actaully did the hook, we need to setup the other LCL as
  1870. * the one to use.
  1871. */
  1872. HRESULT ChangeHookedLCL( LPDDRAWI_DIRECTDRAW_LCL this_lcl,
  1873. LPDDRAWI_DIRECTDRAW_LCL new_lcl, DWORD pid )
  1874. {
  1875. LPDDWINDOWINFO curr;
  1876. /*
  1877. * find the window list item associated with this process
  1878. */
  1879. curr = lpWindowInfo;
  1880. while( curr != NULL )
  1881. {
  1882. if( curr->dwPid == pid )
  1883. {
  1884. break;
  1885. }
  1886. curr = curr->lpLink;
  1887. }
  1888. if( curr == NULL )
  1889. {
  1890. return DD_OK;
  1891. }
  1892. /*
  1893. * Are we shutting down the object that has hooked the hwnd?
  1894. */
  1895. if( (curr->dwFlags & WININFO_DDRAWHOOKED) &&
  1896. ( curr->DDInfo.lpDD_lcl == this_lcl ) )
  1897. {
  1898. /*
  1899. * Yes - make it use the new LCL
  1900. */
  1901. curr->DDInfo.lpDD_lcl = new_lcl;
  1902. }
  1903. return DD_OK;
  1904. }
  1905. #undef DPF_MODNAME
  1906. /*
  1907. * SetAppHWnd
  1908. *
  1909. * Set the WindowList struct up with the app's hwnd info
  1910. */
  1911. HRESULT SetAppHWnd(
  1912. LPDDRAWI_DIRECTDRAW_LCL this_lcl,
  1913. HWND hWnd,
  1914. DWORD dwFlags )
  1915. {
  1916. LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl;
  1917. DWORD pid;
  1918. HRESULT ddrval;
  1919. /*
  1920. * set up the window
  1921. */
  1922. if( hWnd && (dwFlags & DDSCL_EXCLUSIVE) )
  1923. {
  1924. /*
  1925. * make the window fullscreen and topmost
  1926. */
  1927. if ( (dwFlags & DDSCL_FULLSCREEN) &&
  1928. !(dwFlags & DDSCL_NOWINDOWCHANGES))
  1929. {
  1930. MakeFullscreen(this_lcl, hWnd);
  1931. }
  1932. }
  1933. /*
  1934. * Don't hook the hWnd if it's already hooked and don't unhook it if
  1935. * it's still being used by another object.
  1936. */
  1937. pid = GETCURRPID();
  1938. pdrv_lcl = lpDriverLocalList;
  1939. while( pdrv_lcl != NULL )
  1940. {
  1941. if( ( pdrv_lcl->lpGbl != this_lcl->lpGbl ) &&
  1942. ( pdrv_lcl->dwLocalFlags & DDRAWILCL_HOOKEDHWND ) &&
  1943. ( pdrv_lcl->hFocusWnd == this_lcl->hFocusWnd ) )
  1944. {
  1945. if( hWnd != NULL )
  1946. {
  1947. // Already hooked - no need to do more
  1948. return DD_OK;
  1949. }
  1950. else
  1951. {
  1952. ENTERWINDOWLISTCSECT
  1953. ddrval = ChangeHookedLCL( this_lcl, pdrv_lcl, pid );
  1954. LEAVEWINDOWLISTCSECT
  1955. return ddrval;
  1956. }
  1957. }
  1958. pdrv_lcl = pdrv_lcl->lpLink;
  1959. }
  1960. ENTERWINDOWLISTCSECT
  1961. if( hWnd == NULL )
  1962. {
  1963. ddrval = internalSetAppHWnd( this_lcl, NULL, dwFlags, TRUE, NULL, pid );
  1964. }
  1965. else
  1966. {
  1967. ddrval = internalSetAppHWnd( this_lcl, (HWND)this_lcl->hFocusWnd, dwFlags, TRUE, NULL, pid );
  1968. }
  1969. LEAVEWINDOWLISTCSECT
  1970. return ddrval;
  1971. } /* SetAppHWnd */
  1972. /*
  1973. * DSoundHelp
  1974. */
  1975. HRESULT __stdcall DSoundHelp( HWND hWnd, WNDPROC lpWndProc, DWORD pid )
  1976. {
  1977. HRESULT ddrval;
  1978. DPF( 4, "DSoundHelp: hWnd = %08lx, lpWndProc = %08lx, pid = %08lx", hWnd, lpWndProc, pid );
  1979. ENTERWINDOWLISTCSECT
  1980. ddrval = internalSetAppHWnd( NULL, hWnd, 0, FALSE, lpWndProc, pid );
  1981. LEAVEWINDOWLISTCSECT
  1982. return ddrval;
  1983. } /* DSoundHelp */