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.

1127 lines
30 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: dciman.c *
  3. * *
  4. * Client side stubs for DCIMAN functions. *
  5. * *
  6. * Created: 07-Sep-1994 *
  7. * Author: Andre Vachon [andreva] *
  8. * *
  9. * Copyright (c) 1994-1998 Microsoft Corporation *
  10. \**************************************************************************/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <stddef.h>
  15. #include <windows.h>
  16. #include <winspool.h>
  17. #include <wingdip.h>
  18. #include <ddrawp.h>
  19. #include <winddi.h>
  20. #include "dciddi.h"
  21. #include "dciman.h"
  22. #include <ddrawi.h>
  23. #include <ddrawgdi.h>
  24. #if DBG
  25. #define RIP(x) {DbgPrint(x); DbgBreakPoint();}
  26. #define ASSERTGDI(x,y) if(!(x)) RIP(y)
  27. #define WARNING(x) {DbgPrint(x);}
  28. #else
  29. #define ASSERTGDI(x,y)
  30. #define WARNING(x)
  31. #endif
  32. typedef struct _WINWATCH *PWINWATCH;
  33. typedef struct _WINWATCH {
  34. PWINWATCH pWinWatchNext;
  35. HWND hwnd;
  36. BOOL changed;
  37. ULONG lprgndataSize;
  38. LPRGNDATA lprgndata;
  39. } WINWATCH, *PWINWATCH;
  40. //
  41. // The following structure incorporates the DirectDraw structures required
  42. // to identify a surface. It is allocated before the start of the
  43. // DCISURFACEINFO structure.
  44. //
  45. typedef struct _DCIMAN_SURF
  46. {
  47. BOOL SurfaceLost; // True if the surface can no
  48. // longer be accessed because
  49. // a mode change occured
  50. DDRAWI_DIRECTDRAW_GBL DirectDrawGlobal; // Identifies device
  51. DDRAWI_DDRAWSURFACE_GBL SurfaceGlobal; // Identifies surface
  52. DDRAWI_DDRAWSURFACE_LCL SurfaceLocal; // Identifies surface
  53. DDHAL_DDCALLBACKS DDCallbacks; // Contains address of CreateSurface
  54. // call for BeginAccess
  55. DDHAL_DDSURFACECALLBACKS DDSurfaceCallbacks;// Contains addresses of Lock, Unlock,
  56. // and DestroySurface calls for
  57. // BeginAccess and EndAccess
  58. } DCIMAN_SURF, *PDCIMAN_SURF;
  59. //
  60. // We maintain a linked list of all winwatch's so that we can notify their
  61. // owners whenever we notice that the clippping has changed. The list may
  62. // be accessed only while holding the gcsWinWatchLock critical section.
  63. //
  64. CRITICAL_SECTION gcsWinWatchLock;
  65. PWINWATCH gpWinWatchList = NULL;
  66. /******************************Private*Routine*****************************\
  67. * dciCreateSurface
  68. *
  69. * History: 1-Aug-1998 Jerry Van Aken [jvanaken] wrote it.
  70. \**************************************************************************/
  71. static BOOL bCreateSurface(PDCIMAN_SURF pPrivate)
  72. {
  73. DDSURFACEDESC ddsd;
  74. DDHAL_CREATESURFACEDATA csd;
  75. LPDDRAWI_DDRAWSURFACE_LCL pSurfaceLocal = &pPrivate->SurfaceLocal;
  76. //
  77. // Fill in DDSURFACEDESC struct for CreateSurface call.
  78. //
  79. ZeroMemory(&ddsd, sizeof(ddsd));
  80. ddsd.dwSize = sizeof(ddsd);
  81. ddsd.dwFlags = DDSD_CAPS;
  82. ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE;
  83. //
  84. // Fill in DDHAL_CREATESURFACEDATA struct for CreateSurface call.
  85. //
  86. csd.lpDD = pPrivate->SurfaceGlobal.lpDD;
  87. csd.lpDDSurfaceDesc = &ddsd;
  88. csd.lplpSList = &pSurfaceLocal;
  89. csd.dwSCnt = 1;
  90. csd.ddRVal = DDERR_GENERIC;
  91. csd.CreateSurface = pPrivate->DDCallbacks.CreateSurface;
  92. if ((pPrivate->DDCallbacks.dwFlags & DDHAL_CB32_CREATESURFACE) &&
  93. (csd.CreateSurface != NULL) &&
  94. ((*csd.CreateSurface)(&csd) == DDHAL_DRIVER_HANDLED) &&
  95. (csd.ddRVal == DD_OK))
  96. {
  97. return TRUE;
  98. }
  99. return FALSE;
  100. }
  101. /******************************Private*Routine*****************************\
  102. * dciCreateSurface
  103. *
  104. * History: 1-Aug-1998 Jerry Van Aken [jvanaken] wrote it.
  105. \**************************************************************************/
  106. static BOOL bDestroySurface(PDCIMAN_SURF pPrivate)
  107. {
  108. DDHAL_DESTROYSURFACEDATA dsd;
  109. dsd.lpDD = pPrivate->SurfaceGlobal.lpDD;
  110. dsd.lpDDSurface = &pPrivate->SurfaceLocal;
  111. dsd.ddRVal = DDERR_GENERIC;
  112. dsd.DestroySurface = pPrivate->DDSurfaceCallbacks.DestroySurface;
  113. if ((pPrivate->DDSurfaceCallbacks.dwFlags & DDHAL_SURFCB32_DESTROYSURFACE) &&
  114. (dsd.DestroySurface != NULL) &&
  115. ((*dsd.DestroySurface)(&dsd) == DDHAL_DRIVER_HANDLED) &&
  116. (dsd.ddRVal == DD_OK))
  117. {
  118. return TRUE;
  119. }
  120. return FALSE;
  121. }
  122. /******************************Public*Routine******************************\
  123. * DciOpenProvider
  124. *
  125. * History: 1-Aug-1998 Jerry Van Aken [jvanaken] added multimon support.
  126. \**************************************************************************/
  127. HDC
  128. WINAPI
  129. DCIOpenProvider(
  130. void
  131. )
  132. {
  133. HANDLE h;
  134. DWORD iDevice;
  135. BOOL (WINAPI *pfnEnum)(LPVOID, DWORD, DISPLAY_DEVICEW *, DWORD);
  136. int cMonitors = GetSystemMetrics(SM_CMONITORS);
  137. if (cMonitors <= 1)
  138. {
  139. //
  140. // This is a single-monitor system.
  141. //
  142. return CreateDCW(L"Display", NULL, NULL, NULL);
  143. }
  144. //
  145. // This is a multimon system. Get the DC for the primary monitor.
  146. //
  147. h = GetModuleHandle("user32.dll");
  148. (FARPROC)pfnEnum = GetProcAddress(h, "EnumDisplayDevicesW");
  149. if (pfnEnum == NULL)
  150. {
  151. return NULL;
  152. }
  153. for (iDevice = 0; iDevice < (DWORD)cMonitors; ++iDevice)
  154. {
  155. DISPLAY_DEVICEW dd;
  156. ZeroMemory(&dd, sizeof(dd));
  157. dd.cb = sizeof(dd);
  158. if (!(*pfnEnum)(NULL, iDevice, &dd, 0))
  159. {
  160. return NULL;
  161. }
  162. if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
  163. {
  164. //
  165. // Return the DC for the primary monitor.
  166. //
  167. return CreateDCW(NULL, dd.DeviceName, NULL, NULL);
  168. }
  169. }
  170. return NULL;
  171. }
  172. /******************************Public*Routine******************************\
  173. * DciCloseProvider
  174. *
  175. * History:
  176. \**************************************************************************/
  177. void
  178. WINAPI
  179. DCICloseProvider(
  180. HDC hdc
  181. )
  182. {
  183. DeleteDC(hdc);
  184. }
  185. /******************************Public*Routine******************************\
  186. * DciEnum
  187. *
  188. * History:
  189. \**************************************************************************/
  190. int
  191. WINAPI
  192. DCIEnum(
  193. HDC hdc,
  194. LPRECT lprDst,
  195. LPRECT lprSrc,
  196. LPVOID lpFnCallback,
  197. LPVOID lpContext
  198. )
  199. {
  200. return DCI_FAIL_UNSUPPORTED;
  201. }
  202. /******************************Public*Routine******************************\
  203. * DciCreatePrimarySurface
  204. *
  205. * History:
  206. \**************************************************************************/
  207. int
  208. WINAPI
  209. DCICreatePrimary(
  210. HDC hdc,
  211. LPDCISURFACEINFO *lplpSurface
  212. )
  213. {
  214. int iRet;
  215. LPDCISURFACEINFO lpSurface;
  216. PDCIMAN_SURF pPrivate;
  217. DDHALINFO HalInfo;
  218. DDHAL_DDCALLBACKS DDCallbacks;
  219. DDHAL_DDPALETTECALLBACKS DDPaletteCallbacks;
  220. BOOL NewMode;
  221. *lplpSurface = NULL;
  222. iRet = DCI_FAIL_GENERIC;
  223. pPrivate = (PDCIMAN_SURF) LocalAlloc(LMEM_ZEROINIT, sizeof(DCIMAN_SURF)
  224. + sizeof(DCISURFACEINFO));
  225. if (pPrivate != NULL)
  226. {
  227. //
  228. // We store private DCIMAN information in the DCIMAN_SURF structure
  229. // that immediately preceeds the DCISURFACEINFO structure we'll give
  230. // out.
  231. //
  232. lpSurface = (LPDCISURFACEINFO) (pPrivate + 1);
  233. if (DdCreateDirectDrawObject(&pPrivate->DirectDrawGlobal, hdc))
  234. {
  235. if (DdReenableDirectDrawObject(&pPrivate->DirectDrawGlobal, &NewMode) &&
  236. DdQueryDirectDrawObject(&pPrivate->DirectDrawGlobal,
  237. &HalInfo,
  238. &pPrivate->DDCallbacks,
  239. &pPrivate->DDSurfaceCallbacks,
  240. &DDPaletteCallbacks,
  241. NULL, NULL, NULL, NULL,
  242. NULL,
  243. NULL))
  244. {
  245. //
  246. // Build the required DirectDraw links for the 'global' and
  247. // 'local' surfaces.
  248. //
  249. pPrivate->SurfaceLost = FALSE;
  250. pPrivate->DirectDrawGlobal.vmiData = HalInfo.vmiData;
  251. pPrivate->SurfaceLocal.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  252. pPrivate->SurfaceLocal.lpGbl = &pPrivate->SurfaceGlobal;
  253. pPrivate->SurfaceLocal.hDDSurface = 0;
  254. pPrivate->SurfaceGlobal.lpDD = &pPrivate->DirectDrawGlobal;
  255. pPrivate->SurfaceGlobal.wHeight = (WORD) HalInfo.vmiData.dwDisplayHeight;
  256. pPrivate->SurfaceGlobal.wWidth = (WORD) HalInfo.vmiData.dwDisplayWidth;
  257. pPrivate->SurfaceGlobal.lPitch = HalInfo.vmiData.lDisplayPitch;
  258. if (bCreateSurface(pPrivate))
  259. {
  260. //
  261. // Associate an hwnd of '-1' with this surface to let the
  262. // kernel know that the application may be drawing to any
  263. // window, so Visrgn notifications should happen when any
  264. // window changes.
  265. //
  266. if (DdResetVisrgn(&pPrivate->SurfaceLocal, (HWND) -1))
  267. {
  268. lpSurface->dwSize = sizeof(DCISURFACEINFO);
  269. if (HalInfo.vmiData.ddpfDisplay.dwRGBBitCount <= 8)
  270. {
  271. lpSurface->dwCompression = BI_RGB;
  272. }
  273. else
  274. {
  275. lpSurface->dwCompression = BI_BITFIELDS;
  276. }
  277. lpSurface->dwDCICaps = DCI_PRIMARY | DCI_VISIBLE;
  278. lpSurface->dwMask[0] = HalInfo.vmiData.ddpfDisplay.dwRBitMask;
  279. lpSurface->dwMask[1] = HalInfo.vmiData.ddpfDisplay.dwGBitMask;
  280. lpSurface->dwMask[2] = HalInfo.vmiData.ddpfDisplay.dwBBitMask;
  281. lpSurface->dwWidth = HalInfo.vmiData.dwDisplayWidth;
  282. lpSurface->dwHeight = HalInfo.vmiData.dwDisplayHeight;
  283. lpSurface->lStride = HalInfo.vmiData.lDisplayPitch;
  284. lpSurface->dwBitCount = HalInfo.vmiData.ddpfDisplay.dwRGBBitCount;
  285. lpSurface->dwOffSurface = 0;
  286. lpSurface->wSelSurface = 0;
  287. lpSurface->wReserved = 0;
  288. lpSurface->dwReserved1 = 0;
  289. lpSurface->dwReserved2 = 0;
  290. lpSurface->dwReserved3 = 0;
  291. lpSurface->BeginAccess = NULL;
  292. lpSurface->EndAccess = NULL;
  293. lpSurface->DestroySurface = NULL;
  294. *lplpSurface = lpSurface;
  295. return(DCI_OK);
  296. }
  297. //
  298. // The call to DdResetVisrgn failed.
  299. //
  300. bDestroySurface(pPrivate);
  301. }
  302. }
  303. else
  304. {
  305. //
  306. // DirectDraw is not supported on this device.
  307. //
  308. iRet = DCI_FAIL_UNSUPPORTED;
  309. }
  310. DdDeleteDirectDrawObject(&pPrivate->DirectDrawGlobal);
  311. }
  312. else
  313. {
  314. //
  315. // DirectDraw is not supported on this device.
  316. //
  317. iRet = DCI_FAIL_UNSUPPORTED;
  318. }
  319. LocalFree(pPrivate);
  320. }
  321. else
  322. {
  323. //
  324. // Can't allocate memory for PDCIMAN_SURF struct.
  325. //
  326. iRet = DCI_ERR_OUTOFMEMORY;
  327. }
  328. *lplpSurface = NULL;
  329. return iRet;
  330. }
  331. /******************************Public*Routine******************************\
  332. * GdiDciCreateOffscreenSurface
  333. *
  334. * Stub to call CreateOffscreenSurface
  335. *
  336. * History:
  337. \**************************************************************************/
  338. int
  339. WINAPI
  340. DCICreateOffscreen(
  341. HDC hdc,
  342. DWORD dwCompression,
  343. DWORD dwRedMask,
  344. DWORD dwGreenMask,
  345. DWORD dwBlueMask,
  346. DWORD dwWidth,
  347. DWORD dwHeight,
  348. DWORD dwDCICaps,
  349. DWORD dwBitCount,
  350. LPDCIOFFSCREEN *lplpSurface
  351. )
  352. {
  353. return DCI_FAIL_UNSUPPORTED;
  354. }
  355. /******************************Public*Routine******************************\
  356. * DciCreateOverlay
  357. *
  358. * History:
  359. \**************************************************************************/
  360. int
  361. WINAPI
  362. DCICreateOverlay(
  363. HDC hdc,
  364. LPVOID lpOffscreenSurf,
  365. LPDCIOVERLAY FAR *lplpSurface
  366. )
  367. {
  368. return DCI_FAIL_UNSUPPORTED;
  369. }
  370. /******************************Public*Routine******************************\
  371. * WinWatchOpen
  372. *
  373. * History:
  374. \**************************************************************************/
  375. HWINWATCH
  376. WINAPI
  377. WinWatchOpen(
  378. HWND hwnd
  379. )
  380. {
  381. HDC hdc;
  382. PWINWATCH pwatch;
  383. EnterCriticalSection(&gcsWinWatchLock);
  384. pwatch = (PWINWATCH) LocalAlloc(LPTR, sizeof(WINWATCH));
  385. if (pwatch)
  386. {
  387. pwatch->hwnd = hwnd;
  388. pwatch->changed = FALSE;
  389. pwatch->lprgndataSize = 0;
  390. pwatch->lprgndata = NULL;
  391. //
  392. // Add this to the head of the list.
  393. //
  394. pwatch->pWinWatchNext = gpWinWatchList;
  395. gpWinWatchList = pwatch;
  396. }
  397. LeaveCriticalSection(&gcsWinWatchLock);
  398. return (HWINWATCH) (pwatch);
  399. }
  400. /******************************Public*Routine******************************\
  401. * WinWatchClose
  402. *
  403. * History:
  404. \**************************************************************************/
  405. void
  406. WINAPI
  407. WinWatchClose(
  408. HWINWATCH hWW
  409. )
  410. {
  411. PWINWATCH pwatch = (PWINWATCH) hWW;
  412. PWINWATCH ptmp;
  413. EnterCriticalSection(&gcsWinWatchLock);
  414. if (gpWinWatchList == pwatch)
  415. {
  416. //
  417. // The specified winwatch is at the head of the list.
  418. //
  419. gpWinWatchList = pwatch->pWinWatchNext;
  420. LocalFree(pwatch->lprgndata);
  421. LocalFree(pwatch);
  422. }
  423. else
  424. {
  425. for (ptmp = gpWinWatchList;
  426. ptmp != NULL;
  427. ptmp = ptmp->pWinWatchNext)
  428. {
  429. if (ptmp->pWinWatchNext == pwatch)
  430. {
  431. //
  432. // We've found the specified winwatch in the list.
  433. //
  434. ptmp->pWinWatchNext = pwatch->pWinWatchNext;
  435. LocalFree(pwatch->lprgndata);
  436. LocalFree(pwatch);
  437. break;
  438. }
  439. }
  440. }
  441. LeaveCriticalSection(&gcsWinWatchLock);
  442. }
  443. /******************************Public*Routine******************************\
  444. * WinWatchGetClipList
  445. *
  446. * History:
  447. \**************************************************************************/
  448. UINT
  449. WINAPI
  450. WinWatchGetClipList(
  451. HWINWATCH hWW,
  452. LPRECT prc, // May be NULL
  453. UINT size,
  454. LPRGNDATA prd
  455. )
  456. {
  457. PWINWATCH pwatch = (PWINWATCH) hWW;
  458. DWORD dwSize;
  459. DWORD dwNewSize;
  460. UINT dwRet;
  461. //
  462. // The first time after the VisRgn has changed, we download and
  463. // cache a copy of the clipping region. We do this because the VisRgn
  464. // can change under our implementation even between doing a BeginAccess/
  465. // EndAccess, and we should at least maintain a consistent copy of what
  466. // we think is the current VisRgn.
  467. //
  468. // Mostly, we do this so that the following scenario doesn't happen:
  469. //
  470. // 1. The app calls WinWatchGetClipList to ascertain the clip size;
  471. // 2. The VisRgn gets more complex;
  472. // 3. The app then calls WinWatchGetClipList with a buffer size
  473. // allocated from the return code of step 1., and the call fails
  474. // because now the buffer isn't long enough. The problem is that
  475. // most applications probably wouldn't expect this second call to
  476. // fail, and so would keep on using what is now a completely invalid
  477. // region buffer.
  478. //
  479. if (pwatch->changed)
  480. {
  481. pwatch->changed = FALSE;
  482. //
  483. // Assume failure.
  484. //
  485. pwatch->lprgndataSize = 0;
  486. dwSize = GetWindowRegionData(pwatch->hwnd,
  487. 0,
  488. NULL);
  489. if (dwSize != 0)
  490. {
  491. Try_Again:
  492. if (pwatch->lprgndata != NULL)
  493. {
  494. LocalFree(pwatch->lprgndata);
  495. }
  496. pwatch->lprgndata = LocalAlloc(0, dwSize);
  497. if (pwatch->lprgndata != NULL)
  498. {
  499. dwNewSize = GetWindowRegionData(pwatch->hwnd,
  500. dwSize,
  501. pwatch->lprgndata);
  502. if (dwNewSize == dwSize)
  503. {
  504. //
  505. // Success! (Note that the docs are wrong and NT does
  506. // not return '1' for success -- it returns the size
  507. // of the buffer.)
  508. //
  509. pwatch->lprgndataSize = dwSize;
  510. }
  511. else if (dwSize != 0)
  512. {
  513. //
  514. // Since dwSize is not zero, which would indicate failure
  515. // or success, then we know that the clipping region grew
  516. // in size between the time we queried the size and the
  517. // time we tried to download it. This is a pretty rare
  518. // event, and the chances of it happening again are slight
  519. // (it's more likely that it will shrink the second time,
  520. // anyway), so we just try it again.
  521. //
  522. dwSize = dwNewSize;
  523. goto Try_Again;
  524. }
  525. }
  526. }
  527. }
  528. //
  529. // Now use the cached copy to handle any queries.
  530. //
  531. dwRet = 0;
  532. if (size < pwatch->lprgndataSize)
  533. {
  534. dwRet = pwatch->lprgndataSize;
  535. }
  536. else
  537. {
  538. if (pwatch->lprgndataSize != 0)
  539. {
  540. RtlCopyMemory(prd, pwatch->lprgndata, pwatch->lprgndataSize);
  541. dwRet = 1;
  542. }
  543. }
  544. return dwRet;
  545. }
  546. /******************************Public*Routine******************************\
  547. * WinWatchDidStatusChange
  548. *
  549. * History:
  550. \**************************************************************************/
  551. BOOL
  552. WINAPI
  553. WinWatchDidStatusChange(
  554. HWINWATCH hWW
  555. )
  556. {
  557. PWINWATCH pwatch = (PWINWATCH) hWW;
  558. return pwatch->changed;
  559. }
  560. /******************************Public*Routine******************************\
  561. * GetWindowRegionData
  562. *
  563. * History:
  564. \**************************************************************************/
  565. DWORD
  566. WINAPI
  567. GetWindowRegionData(
  568. HWND hwnd,
  569. DWORD size,
  570. LPRGNDATA prd
  571. )
  572. {
  573. HDC hdc;
  574. DWORD dwRet = 0;
  575. hdc = GetDC(hwnd);
  576. if (hdc)
  577. {
  578. dwRet = GetDCRegionData(hdc, size, prd);
  579. ReleaseDC(hwnd, hdc);
  580. }
  581. return dwRet;
  582. }
  583. /******************************Public*Routine******************************\
  584. * GetDCRegionData
  585. *
  586. * History:
  587. \**************************************************************************/
  588. DWORD
  589. WINAPI GetDCRegionData(
  590. HDC hdc,
  591. DWORD size,
  592. LPRGNDATA prd
  593. )
  594. {
  595. HRGN hrgn;
  596. DWORD num;
  597. LPRGNDATA lpdata;
  598. hrgn = CreateRectRgn(0, 0, 0, 0);
  599. if (hrgn == NULL) {
  600. WARNING("GetDCRegionData - CreateRectRgn failed.\n");
  601. return 0;
  602. }
  603. GetRandomRgn(hdc, hrgn, 4);
  604. num = GetRegionData(hrgn, size, prd);
  605. DeleteObject(hrgn);
  606. return num;
  607. }
  608. /******************************Public*Routine******************************\
  609. * WinWatchNotify
  610. *
  611. * History:
  612. \**************************************************************************/
  613. BOOL
  614. WINAPI
  615. WinWatchNotify(
  616. HWINWATCH hWW,
  617. WINWATCHNOTIFYPROC NotifyCallback,
  618. LPARAM NotifyParam
  619. )
  620. {
  621. return FALSE;
  622. }
  623. /******************************Private*Routine*****************************\
  624. * bDisplayModeChanged
  625. *
  626. * History: 9-Feb-1999 John Stephens [johnstep] wrote it.
  627. \**************************************************************************/
  628. static BOOL bDisplayModeChanged(PDCIMAN_SURF pPrivate)
  629. {
  630. LPDCISURFACEINFO lpSurface;
  631. DDHALINFO HalInfo;
  632. lpSurface = (LPDCISURFACEINFO) (pPrivate + 1);
  633. if (DdQueryDirectDrawObject(&pPrivate->DirectDrawGlobal,
  634. &HalInfo,
  635. NULL,
  636. NULL,
  637. NULL,
  638. NULL, NULL, NULL, NULL,
  639. NULL,
  640. NULL))
  641. {
  642. return
  643. (lpSurface->dwWidth != HalInfo.vmiData.dwDisplayWidth) ||
  644. (lpSurface->dwHeight != HalInfo.vmiData.dwDisplayHeight) ||
  645. (lpSurface->lStride != HalInfo.vmiData.lDisplayPitch) ||
  646. (lpSurface->dwBitCount != HalInfo.vmiData.ddpfDisplay.dwRGBBitCount);
  647. }
  648. //
  649. // If we cannot even query the DirectDraw object, then we cannot make any
  650. // assumptions about the current display mode, so it may have changed.
  651. //
  652. return TRUE;
  653. }
  654. /******************************Public*Routine******************************\
  655. * DciBeginAccess
  656. *
  657. * History:
  658. \**************************************************************************/
  659. DCIRVAL
  660. WINAPI
  661. DCIBeginAccess(
  662. LPDCISURFACEINFO lpSurface,
  663. int x,
  664. int y,
  665. int dx,
  666. int dy
  667. )
  668. {
  669. DCIRVAL iRet;
  670. PDCIMAN_SURF pPrivate;
  671. DDHAL_LOCKDATA LockData;
  672. BOOL NewMode;
  673. PWINWATCH pwatch;
  674. iRet = DCI_FAIL_GENERIC;
  675. pPrivate = ((PDCIMAN_SURF) lpSurface) - 1;
  676. __try
  677. {
  678. //
  679. // Fail if the mode changed.
  680. //
  681. if (pPrivate->SurfaceLost)
  682. {
  683. return DCI_FAIL_INVALIDSURFACE;
  684. }
  685. LockData.lpDD = &pPrivate->DirectDrawGlobal;
  686. LockData.lpDDSurface = &pPrivate->SurfaceLocal;
  687. LockData.bHasRect = TRUE;
  688. LockData.rArea.left = x;
  689. LockData.rArea.top = y;
  690. LockData.rArea.right = x + dx;
  691. LockData.rArea.bottom = y + dy;
  692. LockData.dwFlags = DDLOCK_SURFACEMEMORYPTR;
  693. //
  694. // The DCI specification says we could return DCI_STATUS_WASSTILLDRAWING
  695. // if the accelerator was still busy, but the previous release of DCI on
  696. // Windows NT 3.51 did not support that feature, so we will endeavor to
  697. // remain backwards compatible and do the wait explicitly on behalf of
  698. // the application.
  699. //
  700. Try_Again:
  701. do {
  702. //
  703. // Hold the DCI critical section while calling the kernel to do the
  704. // lock because the kernel surface lock API does not have waiting
  705. // semantics; it will fail if another thread is currently in the
  706. // kernel locking the same surface. This is the expected behaviour
  707. // for DirectDraw, but some clients of DCI -- OpenGL in particular --
  708. // do not expect this. So we will protect them against themselves
  709. // by acquiring the WinWatch lock before calling the kernel.
  710. //
  711. // This lock is also needed for traversing the WinWatchList.
  712. //
  713. EnterCriticalSection(&gcsWinWatchLock);
  714. do {
  715. pPrivate->DDSurfaceCallbacks.Lock(&LockData);
  716. } while (LockData.ddRVal == DDERR_WASSTILLDRAWING);
  717. if (LockData.ddRVal == DDERR_VISRGNCHANGED)
  718. {
  719. if (!DdResetVisrgn(&pPrivate->SurfaceLocal, (HWND) -1))
  720. {
  721. WARNING("DCIBeginAccess - ResetVisRgn failed\n");
  722. }
  723. //
  724. // The VisRgn has changed, and we can't be sure what window it
  725. // was for. So we'll mark all WinWatches as having dirty VisRgns.
  726. // This effect of this is that some of the WinWatches will have to
  727. // re-download their clipping information when they don't really
  728. // have to because their specific window has not changed.
  729. //
  730. // Note that the WinWatchLock must be held here.
  731. //
  732. for (pwatch = gpWinWatchList;
  733. pwatch != NULL;
  734. pwatch = pwatch->pWinWatchNext)
  735. {
  736. pwatch->changed = TRUE;
  737. }
  738. }
  739. LeaveCriticalSection(&gcsWinWatchLock);
  740. } while (LockData.ddRVal == DDERR_VISRGNCHANGED);
  741. //
  742. // 'Surface Lost' means that some sort of mode change occured, and
  743. // we have to re-enable DirectDraw.
  744. //
  745. if (LockData.ddRVal == DDERR_SURFACELOST)
  746. {
  747. if (!DdReenableDirectDrawObject(&pPrivate->DirectDrawGlobal,
  748. &NewMode))
  749. {
  750. //
  751. // We're still in full-screen mode:
  752. //
  753. iRet = DCI_ERR_SURFACEISOBSCURED;
  754. }
  755. else
  756. {
  757. if (!bDisplayModeChanged(pPrivate))
  758. {
  759. //
  760. // We switched back to the same mode. Now that we've re-enabled
  761. // DirectDraw, we can try again:
  762. //
  763. bDestroySurface(pPrivate);
  764. if (bCreateSurface(pPrivate) &&
  765. DdResetVisrgn(&pPrivate->SurfaceLocal, (HWND) -1))
  766. {
  767. goto Try_Again;
  768. }
  769. else
  770. {
  771. WARNING("DCIBeginAccess - couldn't recreate surface.\n");
  772. }
  773. }
  774. //
  775. // We can't reenable the surface, perhaps because a resolution
  776. // switch or colour depth change occured. Mark this surface as
  777. // unusable -- the application will have to reinitialize:
  778. //
  779. pPrivate->SurfaceLost = TRUE;
  780. iRet = DCI_FAIL_INVALIDSURFACE;
  781. //
  782. // Unmap the frame buffer now:
  783. //
  784. if (!bDestroySurface(pPrivate) ||
  785. !DdDeleteDirectDrawObject(&pPrivate->DirectDrawGlobal))
  786. {
  787. WARNING("DCIBeginAccess - failed to delete surface.\n");
  788. }
  789. }
  790. }
  791. if (LockData.ddRVal == DD_OK)
  792. {
  793. //
  794. // Return the pointer to the frame buffer in the DCI structure.
  795. // We always return DCI_STATUS_POINTERCHANGED because it's possible
  796. // that the Lock() call mapped the frame buffer to a different
  797. // virtual address than it was previously.
  798. //
  799. lpSurface->wSelSurface = 0;
  800. //
  801. // DirectDraw has a goofy convention where it returns a pointer to
  802. // the upper-left corner of the specified rectangle. We have to
  803. // undo that for DCI:
  804. //
  805. lpSurface->dwOffSurface = (ULONG_PTR) LockData.lpSurfData
  806. - (y * lpSurface->lStride)
  807. - (x * (lpSurface->dwBitCount >> 3));
  808. iRet = DCI_STATUS_POINTERCHANGED;
  809. }
  810. }
  811. __except(EXCEPTION_EXECUTE_HANDLER)
  812. {
  813. WARNING("DCIBeginAccess - exception caused by invalid surface pointer.\n");
  814. return DCI_FAIL_GENERIC;
  815. }
  816. return iRet;
  817. }
  818. /******************************Public*Routine******************************\
  819. * DciEndAccess
  820. *
  821. * History:
  822. \**************************************************************************/
  823. void
  824. WINAPI
  825. DCIEndAccess(
  826. LPDCISURFACEINFO pdci
  827. )
  828. {
  829. DDHAL_UNLOCKDATA UnlockData;
  830. PDCIMAN_SURF pPrivate = ((PDCIMAN_SURF) pdci) - 1;
  831. __try
  832. {
  833. if (!(pPrivate->SurfaceLost))
  834. {
  835. UnlockData.lpDD = &pPrivate->DirectDrawGlobal;
  836. UnlockData.lpDDSurface = &pPrivate->SurfaceLocal;
  837. //
  838. // For the same reasons as stated in DCIBeginAccess, protect against
  839. // two threads trying to unlock the same surface at the same time
  840. // in kernel -- kernel would simply fail the call instead of waiting,
  841. // and DCI apps won't expect that.
  842. //
  843. EnterCriticalSection(&gcsWinWatchLock);
  844. pPrivate->DDSurfaceCallbacks.Unlock(&UnlockData);
  845. LeaveCriticalSection(&gcsWinWatchLock);
  846. if (UnlockData.ddRVal != DD_OK)
  847. {
  848. WARNING("DCIEndAccess - failed Unlock\n");
  849. }
  850. }
  851. //
  852. // The application shouldn't try to access the frame buffer after
  853. // after having called EndAccess.
  854. //
  855. pdci->wSelSurface = 0;
  856. pdci->dwOffSurface = 0;
  857. }
  858. __except(EXCEPTION_EXECUTE_HANDLER)
  859. {
  860. WARNING("DCIEndAccess - exception caused by invalid surface pointer.\n");
  861. }
  862. }
  863. /******************************Public*Routine******************************\
  864. * DciDestroy
  865. *
  866. * History:
  867. \**************************************************************************/
  868. void
  869. WINAPI
  870. DCIDestroy(
  871. LPDCISURFACEINFO pdci
  872. )
  873. {
  874. PDCIMAN_SURF pPrivate;
  875. if (pdci != NULL)
  876. {
  877. pPrivate = ((PDCIMAN_SURF) pdci) - 1;
  878. if (!(pPrivate->SurfaceLost))
  879. {
  880. DDHAL_DESTROYSURFACEDATA dsd;
  881. dsd.lpDD = pPrivate->SurfaceGlobal.lpDD;
  882. dsd.lpDDSurface = &pPrivate->SurfaceLocal;
  883. dsd.ddRVal = DDERR_GENERIC;
  884. dsd.DestroySurface = pPrivate->DDSurfaceCallbacks.DestroySurface;
  885. if (!(pPrivate->DDSurfaceCallbacks.dwFlags & DDHAL_SURFCB32_DESTROYSURFACE) ||
  886. (dsd.DestroySurface == NULL) ||
  887. ((*dsd.DestroySurface)(&dsd) != DDHAL_DRIVER_HANDLED) ||
  888. !DdDeleteDirectDrawObject(&pPrivate->DirectDrawGlobal))
  889. {
  890. WARNING("DCIDestroy - failed to delete surface.\n");
  891. }
  892. }
  893. LocalFree(pPrivate);
  894. }
  895. }
  896. DCIRVAL
  897. WINAPI
  898. DCIDraw(
  899. LPDCIOFFSCREEN pdci
  900. )
  901. {
  902. return DCI_FAIL_UNSUPPORTED;
  903. }
  904. DCIRVAL
  905. WINAPI
  906. DCISetClipList(
  907. LPDCIOFFSCREEN pdci,
  908. LPRGNDATA prd
  909. )
  910. {
  911. return DCI_FAIL_UNSUPPORTED;
  912. }
  913. DCIRVAL
  914. WINAPI
  915. DCISetDestination(
  916. LPDCIOFFSCREEN pdci,
  917. LPRECT dst,
  918. LPRECT src
  919. )
  920. {
  921. return DCI_FAIL_UNSUPPORTED;
  922. }
  923. DCIRVAL
  924. WINAPI
  925. DCISetSrcDestClip(
  926. LPDCIOFFSCREEN pdci,
  927. LPRECT srcrc,
  928. LPRECT destrc,
  929. LPRGNDATA prd
  930. )
  931. {
  932. return DCI_FAIL_UNSUPPORTED;
  933. }