ReactOS  0.4.15-dev-5126-g3bb451b
ldevobj.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS Win32k subsystem
4  * PURPOSE: Support for logical devices
5  * FILE: win32ss/gdi/eng/ldevobj.c
6  * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
7  */
8 
9 #include <win32k.h>
10 #define NDEBUG
11 #include <debug.h>
12 DBG_DEFAULT_CHANNEL(EngLDev);
13 
14 #ifndef RVA_TO_ADDR
15 #define RVA_TO_ADDR(Base,Rva) ((PVOID)(((ULONG_PTR)(Base)) + (Rva)))
16 #endif
17 
23 
24 
27 CODE_SEG("INIT")
29 NTAPI
31 {
32  ULONG cbSize;
33 
34  /* Initialize the LDEV list head */
36 
37  /* Initialize the loader lock */
39  if (!ghsemLDEVList)
40  {
41  ERR("Failed to create ghsemLDEVList\n");
43  }
44 
45  /* Allocate a LDEVOBJ for win32k */
47  sizeof(LDEVOBJ) +
49  GDITAG_LDEV);
50  if (!gpldevWin32k)
51  {
52  return STATUS_NO_MEMORY;
53  }
54 
55  /* Initialize the LDEVOBJ for win32k */
59  gpldevWin32k->cRefs = 1;
63  L"\\SystemRoot\\System32\\win32k.sys");
69  TRUE,
71  &cbSize);
73 
74  return STATUS_SUCCESS;
75 }
76 
77 static
80  _In_ LDEVTYPE ldevtype)
81 {
82  PLDEVOBJ pldev;
83 
84  /* Allocate the structure from paged pool */
86  if (!pldev)
87  {
88  ERR("Failed to allocate LDEVOBJ.\n");
89  return NULL;
90  }
91 
92  /* Zero out the structure */
93  RtlZeroMemory(pldev, sizeof(LDEVOBJ));
94 
95  /* Set the ldevtype */
96  pldev->ldevtype = ldevtype;
97 
98  return pldev;
99 }
100 
101 static
102 VOID
105 {
106  /* Make sure we don't have a driver loaded */
107  ASSERT(pldev && pldev->pGdiDriverInfo == NULL);
108  ASSERT(pldev->cRefs == 0);
109 
110  /* Free the memory */
112 }
113 
114 static
115 BOOL
117  _Inout_ PLDEVOBJ pldev,
118  _In_ PUNICODE_STRING pustrPathName)
119 {
120  PSYSTEM_GDI_DRIVER_INFORMATION pDriverInfo;
122  ULONG cbSize;
123 
124  /* Make sure no image is loaded yet */
125  ASSERT(pldev && pldev->pGdiDriverInfo == NULL);
126 
127  /* Allocate a SYSTEM_GDI_DRIVER_INFORMATION structure */
128  cbSize = sizeof(SYSTEM_GDI_DRIVER_INFORMATION) + pustrPathName->Length;
129  pDriverInfo = ExAllocatePoolWithTag(PagedPool, cbSize, GDITAG_LDEV);
130  if (!pDriverInfo)
131  {
132  ERR("Failed to allocate SYSTEM_GDI_DRIVER_INFORMATION\n");
133  return FALSE;
134  }
135 
136  /* Initialize the UNICODE_STRING and copy the driver name */
137  RtlInitEmptyUnicodeString(&pDriverInfo->DriverName,
138  (PWSTR)(pDriverInfo + 1),
139  pustrPathName->Length);
140  RtlCopyUnicodeString(&pDriverInfo->DriverName, pustrPathName);
141 
142  /* Try to load the driver */
144  pDriverInfo,
146  if (!NT_SUCCESS(Status))
147  {
148  ERR("Failed to load a GDI driver: '%wZ', Status = 0x%lx\n",
149  pustrPathName, Status);
150 
151  /* Free the allocated memory */
152  ExFreePoolWithTag(pDriverInfo, GDITAG_LDEV);
153  return FALSE;
154  }
155 
156  /* Set the driver info */
157  pldev->pGdiDriverInfo = pDriverInfo;
158 
159  /* Return success. */
160  return TRUE;
161 }
162 
163 static
164 BOOL
166  _Inout_ PLDEVOBJ pldev,
167  _In_ PFN_DrvEnableDriver pfnEnableDriver)
168 {
169  DRVENABLEDATA ded;
170  ULONG i;
171 
172  TRACE("LDEVOBJ_bEnableDriver('%wZ')\n", &pldev->pGdiDriverInfo->DriverName);
173 
174  ASSERT(pldev);
175  ASSERT(pldev->cRefs == 0);
176 
177  if (pldev->ldevtype == LDEV_IMAGE)
178  return TRUE;
179 
180  /* Call the drivers DrvEnableDriver function */
181  RtlZeroMemory(&ded, sizeof(ded));
182  if (!pfnEnableDriver(GDI_ENGINE_VERSION, sizeof(ded), &ded))
183  {
184  ERR("DrvEnableDriver failed\n");
185  return FALSE;
186  }
187 
188  /* Copy the returned driver version */
189  pldev->ulDriverVersion = ded.iDriverVersion;
190 
191  /* Fill the driver function array */
192  for (i = 0; i < ded.c; i++)
193  {
194  pldev->apfn[ded.pdrvfn[i].iFunc] = ded.pdrvfn[i].pfn;
195  }
196 
197  /* Return success. */
198  return TRUE;
199 }
200 
201 static
202 VOID
204  _Inout_ PLDEVOBJ pldev)
205 {
206  ASSERT(pldev);
207  ASSERT(pldev->cRefs == 0);
208 
209  TRACE("LDEVOBJ_vDisableDriver('%wZ')\n", &pldev->pGdiDriverInfo->DriverName);
210 
211  if (pldev->ldevtype == LDEV_IMAGE)
212  return;
213 
214  if (pldev->pfn.DisableDriver)
215  {
216  /* Call the unload function */
217  pldev->pfn.DisableDriver();
218  }
219 }
220 
221 static
222 PVOID
224  _In_ PLDEVOBJ pldev,
225  _In_z_ LPSTR pszProcName)
226 {
227  PVOID pvImageBase;
228  PIMAGE_EXPORT_DIRECTORY pExportDir;
229  PVOID pvProcAdress = NULL;
230  PUSHORT pOrdinals;
231  PULONG pNames, pAddresses;
232  ULONG i;
233 
234  /* Make sure we have a driver info */
235  ASSERT(pldev && pldev->pGdiDriverInfo != NULL);
236 
237  /* Get the pointer to the export directory */
238  pvImageBase = pldev->pGdiDriverInfo->ImageAddress;
239  pExportDir = pldev->pGdiDriverInfo->ExportSectionPointer;
240  if (!pExportDir)
241  {
242  ERR("LDEVOBJ_pvFindImageProcAddress: no export section found\n");
243  return NULL;
244  }
245 
246  /* Get pointers to some tables */
247  pNames = RVA_TO_ADDR(pvImageBase, pExportDir->AddressOfNames);
248  pOrdinals = RVA_TO_ADDR(pvImageBase, pExportDir->AddressOfNameOrdinals);
249  pAddresses = RVA_TO_ADDR(pvImageBase, pExportDir->AddressOfFunctions);
250 
251  /* Loop the export table */
252  for (i = 0; i < pExportDir->NumberOfNames; i++)
253  {
254  /* Compare the name */
255  if (_stricmp(pszProcName, RVA_TO_ADDR(pvImageBase, pNames[i])) == 0)
256  {
257  /* Found! Calculate the procedure address */
258  pvProcAdress = RVA_TO_ADDR(pvImageBase, pAddresses[pOrdinals[i]]);
259  break;
260  }
261  }
262 
263  /* Return the address */
264  return pvProcAdress;
265 }
266 
267 static
268 BOOL
270  _Inout_ PLDEVOBJ pldev)
271 {
273 
274  /* Make sure we have a driver info */
275  ASSERT(pldev && pldev->pGdiDriverInfo != NULL);
276  ASSERT(pldev->cRefs == 0);
277 
278  TRACE("LDEVOBJ_bUnloadImage('%wZ')\n", &pldev->pGdiDriverInfo->DriverName);
279 
280  /* Unload the driver */
281 #if 0
283  &pldev->pGdiDriverInfo->SectionPointer,
284  sizeof(HANDLE));
285 #else
286  /* Unfortunately, ntoskrnl allows unloading a driver, but fails loading
287  * it again with STATUS_IMAGE_ALREADY_LOADED. Prevent this problem by
288  * never unloading any driver.
289  */
292 #endif
293  if (!NT_SUCCESS(Status))
294  return FALSE;
295 
296  ExFreePoolWithTag(pldev->pGdiDriverInfo, GDITAG_LDEV);
297  pldev->pGdiDriverInfo = NULL;
298 
299  return TRUE;
300 }
301 
302 PLDEVOBJ
304  _In_ PFN_DrvEnableDriver pfnEnableDriver,
305  _In_ ULONG ldevtype)
306 {
307  PLDEVOBJ pldev;
308 
309  TRACE("LDEVOBJ_pLoadInternal(%lu)\n", ldevtype);
310 
311  /* Lock loader */
313 
314  /* Allocate a new LDEVOBJ */
315  pldev = LDEVOBJ_AllocLDEV(ldevtype);
316  if (!pldev)
317  {
318  ERR("Could not allocate LDEV\n");
319  goto leave;
320  }
321 
322  /* Load the driver */
323  if (!LDEVOBJ_bEnableDriver(pldev, pfnEnableDriver))
324  {
325  ERR("LDEVOBJ_bEnableDriver failed\n");
326  LDEVOBJ_vFreeLDEV(pldev);
327  pldev = NULL;
328  goto leave;
329  }
330 
331  /* Insert the LDEV into the global list */
333 
334  /* Increase ref count */
335  pldev->cRefs++;
336 
337 leave:
338  /* Unlock loader */
340 
341  TRACE("LDEVOBJ_pLoadInternal returning %p\n", pldev);
342  return pldev;
343 }
344 
345 PLDEVOBJ
346 NTAPI
348  _In_z_ LPWSTR pwszDriverName,
349  _In_ ULONG ldevtype)
350 {
351  WCHAR acwBuffer[MAX_PATH];
352  PLIST_ENTRY pleLink;
353  PLDEVOBJ pldev;
354  UNICODE_STRING strDriverName;
355  SIZE_T cwcLength;
356  LPWSTR pwsz;
357 
358  TRACE("LDEVOBJ_pLoadDriver(%ls, %lu)\n", pwszDriverName, ldevtype);
359  ASSERT(pwszDriverName);
360 
361  /* Initialize buffer for the the driver name */
362  RtlInitEmptyUnicodeString(&strDriverName, acwBuffer, sizeof(acwBuffer));
363 
364  /* Start path with systemroot */
365  RtlAppendUnicodeToString(&strDriverName, L"\\SystemRoot\\System32\\");
366 
367  /* Get Length of given string */
368  cwcLength = wcslen(pwszDriverName);
369 
370  /* Check if we have a system32 path given */
371  pwsz = pwszDriverName + cwcLength;
372  while (pwsz > pwszDriverName)
373  {
374  if ((*pwsz == L'\\') && (_wcsnicmp(pwsz, L"\\system32\\", 10) == 0))
375  {
376  /* Driver name starts after system32 */
377  pwsz += 10;
378  break;
379  }
380  pwsz--;
381  }
382 
383  /* Append the driver name */
384  RtlAppendUnicodeToString(&strDriverName, pwsz);
385 
386  /* MSDN says "The driver must include this suffix in the pwszDriver string."
387  But in fact it's optional. The function can also load .sys files without
388  appending the .dll extension. */
389  if ((cwcLength < 4) ||
390  ((_wcsnicmp(pwszDriverName + cwcLength - 4, L".dll", 4) != 0) &&
391  (_wcsnicmp(pwszDriverName + cwcLength - 4, L".sys", 4) != 0)) )
392  {
393  /* Append the .dll suffix */
394  RtlAppendUnicodeToString(&strDriverName, L".dll");
395  }
396 
397  /* Lock loader */
399 
400  /* Search the List of LDEVS for the driver name */
401  for (pleLink = gleLdevListHead.Flink;
402  pleLink != &gleLdevListHead;
403  pleLink = pleLink->Flink)
404  {
405  pldev = CONTAINING_RECORD(pleLink, LDEVOBJ, leLink);
406 
407  /* Check if the ldev is associated with a file */
408  if (pldev->pGdiDriverInfo)
409  {
410  /* Check for match (case insensative) */
411  if (RtlEqualUnicodeString(&pldev->pGdiDriverInfo->DriverName, &strDriverName, TRUE))
412  {
413  /* Image found in LDEV list */
414  break;
415  }
416  }
417  }
418 
419  /* Did we find one? */
420  if (pleLink == &gleLdevListHead)
421  {
422  /* No, allocate a new LDEVOBJ */
423  pldev = LDEVOBJ_AllocLDEV(ldevtype);
424  if (!pldev)
425  {
426  ERR("Could not allocate LDEV\n");
427  goto leave;
428  }
429 
430  /* Load the image */
431  if (!LDEVOBJ_bLoadImage(pldev, &strDriverName))
432  {
433  LDEVOBJ_vFreeLDEV(pldev);
434  pldev = NULL;
435  ERR("LDEVOBJ_bLoadImage failed\n");
436  goto leave;
437  }
438 
439  /* Load the driver */
440  if (!LDEVOBJ_bEnableDriver(pldev, pldev->pGdiDriverInfo->EntryPoint))
441  {
442  ERR("LDEVOBJ_bEnableDriver failed\n");
443 
444  /* Unload the image. */
445  LDEVOBJ_bUnloadImage(pldev);
446  LDEVOBJ_vFreeLDEV(pldev);
447  pldev = NULL;
448  goto leave;
449  }
450 
451  /* Insert the LDEV into the global list */
453  }
454 
455  /* Increase ref count */
456  pldev->cRefs++;
457 
458 leave:
459  /* Unlock loader */
461 
462  TRACE("LDEVOBJ_pLoadDriver returning %p\n", pldev);
463  return pldev;
464 }
465 
466 static
467 VOID
469  _Inout_ PLDEVOBJ pldev)
470 {
471  /* Lock loader */
473 
474  /* Decrement reference count */
475  ASSERT(pldev->cRefs > 0);
476  pldev->cRefs--;
477 
478  /* More references left? */
479  if (pldev->cRefs > 0)
480  {
482  return;
483  }
484 
485  LDEVOBJ_vDisableDriver(pldev);
486 
487  if (LDEVOBJ_bUnloadImage(pldev))
488  {
489  /* Remove ldev from the list */
490  RemoveEntryList(&pldev->leLink);
491 
492  /* Free the driver info structure */
493  LDEVOBJ_vFreeLDEV(pldev);
494  }
495  else
496  {
497  WARN("Failed to unload driver '%wZ', trying to re-enable it.\n", &pldev->pGdiDriverInfo->DriverName);
498  LDEVOBJ_bEnableDriver(pldev, pldev->pGdiDriverInfo->EntryPoint);
499 
500  /* Increment again reference count */
501  pldev->cRefs++;
502  }
503 
504  /* Unlock loader */
506 }
507 
508 ULONG
510  _In_ LPWSTR pwszDriverName,
512  _Out_ PDEVMODEW *ppdm)
513 {
514  PLDEVOBJ pldev = NULL;
515  ULONG cbSize = 0;
516  PDEVMODEW pdm = NULL;
517 
518  TRACE("LDEVOBJ_ulGetDriverModes('%ls', %p)\n", pwszDriverName, hDriver);
519 
520  pldev = LDEVOBJ_pLoadDriver(pwszDriverName, LDEV_DEVICE_DISPLAY);
521  if (!pldev)
522  goto cleanup;
523 
524  /* Mirror drivers may omit this function */
525  if (!pldev->pfn.GetModes)
526  goto cleanup;
527 
528  /* Call the driver to get the required size */
529  cbSize = pldev->pfn.GetModes(hDriver, 0, NULL);
530  if (!cbSize)
531  {
532  ERR("DrvGetModes returned 0\n");
533  goto cleanup;
534  }
535 
536  /* Allocate a buffer for the DEVMODE array */
538  if (!pdm)
539  {
540  ERR("Could not allocate devmodeinfo\n");
541  goto cleanup;
542  }
543 
544  /* Call the driver again to fill the buffer */
545  cbSize = pldev->pfn.GetModes(hDriver, cbSize, pdm);
546  if (!cbSize)
547  {
548  /* Could not get modes */
549  ERR("DrvrGetModes returned 0 on second call\n");
551  pdm = NULL;
552  }
553 
554 cleanup:
555  if (pldev)
556  LDEVOBJ_vDereference(pldev);
557 
558  *ppdm = pdm;
559  return cbSize;
560 }
561 
562 BOOL
564  _Inout_ PGRAPHICS_DEVICE pGraphicsDevice)
565 {
566  PWSTR pwsz;
567  PDEVMODEINFO pdminfo;
568  PDEVMODEW pdm, pdmEnd;
569  ULONG i, cModes = 0;
570  ULONG cbSize, cbFull;
571 
572  if (pGraphicsDevice->pdevmodeInfo)
573  return TRUE;
574  ASSERT(pGraphicsDevice->pDevModeList == NULL);
575 
576  pwsz = pGraphicsDevice->pDiplayDrivers;
577 
578  /* Loop through the driver names
579  * This is a REG_MULTI_SZ string */
580  for (; *pwsz; pwsz += wcslen(pwsz) + 1)
581  {
582  /* Get the mode list from the driver */
583  TRACE("Trying driver: %ls\n", pwsz);
584  cbSize = LDEVOBJ_ulGetDriverModes(pwsz, pGraphicsDevice->DeviceObject, &pdm);
585  if (!cbSize)
586  {
587  WARN("Driver %ls returned no valid mode\n", pwsz);
588  continue;
589  }
590 
591  /* Add space for the header */
592  cbFull = cbSize + FIELD_OFFSET(DEVMODEINFO, adevmode);
593 
594  /* Allocate a buffer for the DEVMODE array */
595  pdminfo = ExAllocatePoolWithTag(PagedPool, cbFull, GDITAG_DEVMODE);
596  if (!pdminfo)
597  {
598  ERR("Could not allocate devmodeinfo\n");
600  continue;
601  }
602 
603  pdminfo->cbdevmode = cbSize;
604  RtlCopyMemory(pdminfo->adevmode, pdm, cbSize);
606 
607  /* Attach the mode info to the device */
608  pdminfo->pdmiNext = pGraphicsDevice->pdevmodeInfo;
609  pGraphicsDevice->pdevmodeInfo = pdminfo;
610 
611  /* Loop all DEVMODEs */
612  pdmEnd = (DEVMODEW*)((PCHAR)pdminfo->adevmode + pdminfo->cbdevmode);
613  for (pdm = pdminfo->adevmode;
614  (pdm + 1 <= pdmEnd) && (pdm->dmSize != 0);
615  pdm = (DEVMODEW*)((PCHAR)pdm + pdm->dmSize + pdm->dmDriverExtra))
616  {
617  /* Count this DEVMODE */
618  cModes++;
619 
620  /* Some drivers like the VBox driver don't fill the dmDeviceName
621  with the name of the display driver. So fix that here. */
622  RtlStringCbCopyW(pdm->dmDeviceName, sizeof(pdm->dmDeviceName), pwsz);
623  }
624  }
625 
626  if (!pGraphicsDevice->pdevmodeInfo || cModes == 0)
627  {
628  ERR("No devmodes\n");
629  return FALSE;
630  }
631 
632  /* Allocate an index buffer */
633  pGraphicsDevice->cDevModes = cModes;
634  pGraphicsDevice->pDevModeList = ExAllocatePoolWithTag(PagedPool,
635  cModes * sizeof(DEVMODEENTRY),
637  if (!pGraphicsDevice->pDevModeList)
638  {
639  ERR("No devmode list\n");
640  return FALSE;
641  }
642 
643  /* Loop through all DEVMODEINFOs */
644  for (pdminfo = pGraphicsDevice->pdevmodeInfo, i = 0;
645  pdminfo;
646  pdminfo = pdminfo->pdmiNext)
647  {
648  /* Calculate End of the DEVMODEs */
649  pdmEnd = (DEVMODEW*)((PCHAR)pdminfo->adevmode + pdminfo->cbdevmode);
650 
651  /* Loop through the DEVMODEs */
652  for (pdm = pdminfo->adevmode;
653  (pdm + 1 <= pdmEnd) && (pdm->dmSize != 0);
654  pdm = (PDEVMODEW)((PCHAR)pdm + pdm->dmSize + pdm->dmDriverExtra))
655  {
656  TRACE(" %S has mode %lux%lux%lu(%lu Hz)\n",
657  pdm->dmDeviceName,
658  pdm->dmPelsWidth,
659  pdm->dmPelsHeight,
660  pdm->dmBitsPerPel,
661  pdm->dmDisplayFrequency);
662 
663  /* Initialize the entry */
664  pGraphicsDevice->pDevModeList[i].dwFlags = 0;
665  pGraphicsDevice->pDevModeList[i].pdm = pdm;
666  i++;
667  }
668  }
669  return TRUE;
670 }
671 
672 /* Search the closest display mode according to some settings.
673  * Note that we don't care about the DM_* flags in dmFields, but check if value != 0 instead */
674 static
675 BOOL
677  _Inout_ PGRAPHICS_DEVICE pGraphicsDevice,
678  _In_ PDEVMODEW RequestedMode,
679  _Out_ PDEVMODEW *pSelectedMode)
680 {
681  DEVMODEW dmDiff;
682  PDEVMODEW pdmCurrent, pdmBest = NULL;
683  ULONG i;
684 
685  /* Use a DEVMODE to keep the differences between best mode found and expected mode.
686  * Initialize fields to max value so we can find better modes. */
687  dmDiff.dmPelsWidth = 0xffffffff;
688  dmDiff.dmPelsHeight = 0xffffffff;
689  dmDiff.dmBitsPerPel = 0xffffffff;
690  dmDiff.dmDisplayFrequency = 0xffffffff;
691 
692  /* Search the closest mode */
693 #define DM_DIFF(field) (RequestedMode->field > pdmCurrent->field ? (RequestedMode->field - pdmCurrent->field) : (pdmCurrent->field - RequestedMode->field))
694  for (i = 0; i < pGraphicsDevice->cDevModes; i++)
695  {
696  pdmCurrent = pGraphicsDevice->pDevModeList[i].pdm;
697 
698  /* Skip current mode if it is worse than best mode found */
699  if (RequestedMode->dmPelsWidth != 0 && DM_DIFF(dmPelsWidth) > dmDiff.dmPelsWidth)
700  continue;
701  if (RequestedMode->dmPelsHeight != 0 && DM_DIFF(dmPelsHeight) > dmDiff.dmPelsHeight)
702  continue;
703  if (RequestedMode->dmBitsPerPel != 0 && DM_DIFF(dmBitsPerPel) > dmDiff.dmBitsPerPel)
704  continue;
705  if (RequestedMode->dmDisplayFrequency != 0 && DM_DIFF(dmDisplayFrequency) > dmDiff.dmDisplayFrequency)
706  continue;
707 
708  /* Better (or equivalent) mode found. Update differences */
709  dmDiff.dmPelsWidth = DM_DIFF(dmPelsWidth);
710  dmDiff.dmPelsHeight = DM_DIFF(dmPelsHeight);
711  dmDiff.dmBitsPerPel = DM_DIFF(dmBitsPerPel);
712  dmDiff.dmDisplayFrequency = DM_DIFF(dmDisplayFrequency);
713  pdmBest = pdmCurrent;
714  }
715 #undef DM_DIFF
716 
717  if (pdmBest)
718  {
719  TRACE("Closest display mode to '%dx%dx%d %d Hz' is '%dx%dx%d %d Hz'\n",
720  RequestedMode->dmPelsWidth,
721  RequestedMode->dmPelsHeight,
722  RequestedMode->dmBitsPerPel,
723  RequestedMode->dmDisplayFrequency,
724  pdmBest->dmPelsWidth,
725  pdmBest->dmPelsHeight,
726  pdmBest->dmBitsPerPel,
727  pdmBest->dmDisplayFrequency);
728  }
729 
730  *pSelectedMode = pdmBest;
731  return pdmBest != NULL;
732 }
733 
734 BOOL
736  _Inout_ PGRAPHICS_DEVICE pGraphicsDevice,
737  _In_ PDEVMODEW RequestedMode,
738  _Out_ PDEVMODEW *pSelectedMode,
739  _In_ BOOL bSearchClosestMode)
740 {
741  DEVMODEW dmSearch;
742  PDEVMODEW pdmCurrent, pdm, pdmSelected = NULL;
743  ULONG i;
744  ULONG ulVirtualWidth = 0, ulVirtualHeight = 0;
745  BOOL bResult = TRUE;
747 
748  if (!LDEVOBJ_bBuildDevmodeList(pGraphicsDevice))
749  return FALSE;
750 
751  /* At first, load information from registry */
752  RtlZeroMemory(&dmSearch, sizeof(dmSearch));
753  Status = EngpGetDisplayDriverParameters(pGraphicsDevice, &dmSearch);
754  if (!NT_SUCCESS(Status))
755  {
756  ERR("EngpGetDisplayDriverParameters() failed with status 0x%08x\n", Status);
757  return FALSE;
758  }
759 
760  /* Override values with the new ones provided */
761 
762  _SEH2_TRY
763  {
764  bSearchClosestMode |= RequestedMode->dmFields == 0;
765 
766  /* Copy standard fields (if provided) */
767  if (RequestedMode->dmFields & DM_BITSPERPEL && RequestedMode->dmBitsPerPel != 0)
768  dmSearch.dmBitsPerPel = RequestedMode->dmBitsPerPel;
769  if (RequestedMode->dmFields & DM_PELSWIDTH && RequestedMode->dmPelsWidth != 0)
770  dmSearch.dmPelsWidth = RequestedMode->dmPelsWidth;
771  if (RequestedMode->dmFields & DM_PELSHEIGHT && RequestedMode->dmPelsHeight != 0)
772  dmSearch.dmPelsHeight = RequestedMode->dmPelsHeight;
773  if (RequestedMode->dmFields & DM_DISPLAYFREQUENCY && RequestedMode->dmDisplayFrequency != 0)
774  dmSearch.dmDisplayFrequency = RequestedMode->dmDisplayFrequency;
775 
776  if ((RequestedMode->dmFields & (DM_PANNINGWIDTH | DM_PANNINGHEIGHT)) == (DM_PANNINGWIDTH | DM_PANNINGHEIGHT) &&
777  RequestedMode->dmPanningWidth != 0 && RequestedMode->dmPanningHeight != 0 &&
778  RequestedMode->dmPanningWidth < dmSearch.dmPelsWidth &&
779  RequestedMode->dmPanningHeight < dmSearch.dmPelsHeight)
780  {
781  /* Get new panning values */
782  ulVirtualWidth = RequestedMode->dmPelsWidth;
783  ulVirtualHeight = RequestedMode->dmPelsHeight;
784  dmSearch.dmPelsWidth = RequestedMode->dmPanningWidth;
785  dmSearch.dmPelsHeight = RequestedMode->dmPanningHeight;
786  }
787  else if (dmSearch.dmPanningWidth != 0 && dmSearch.dmPanningHeight != 0 &&
788  dmSearch.dmPanningWidth < dmSearch.dmPelsWidth &&
789  dmSearch.dmPanningHeight < dmSearch.dmPelsHeight)
790  {
791  /* Keep existing panning values */
792  ulVirtualWidth = dmSearch.dmPelsWidth;
793  ulVirtualHeight = dmSearch.dmPelsHeight;
794  dmSearch.dmPelsWidth = dmSearch.dmPanningWidth;
795  dmSearch.dmPelsHeight = dmSearch.dmPanningHeight;
796  }
797  }
799  {
800  bResult = FALSE;
801  }
802  _SEH2_END;
803 
804  if (!bResult)
805  return FALSE;
806 
807  if (LDEVOBJ_bGetClosestMode(pGraphicsDevice, &dmSearch, &pdmSelected))
808  {
809  if (bSearchClosestMode)
810  {
811  /* Ok, found a closest mode. Update search */
812  dmSearch.dmBitsPerPel = pdmSelected->dmBitsPerPel;
813  dmSearch.dmPelsWidth = pdmSelected->dmPelsWidth;
814  dmSearch.dmPelsHeight = pdmSelected->dmPelsHeight;
815  dmSearch.dmDisplayFrequency = pdmSelected->dmDisplayFrequency;
816  }
817  else
818  {
819  /* Only update not provided fields */
820  _SEH2_TRY
821  {
822  if (!(RequestedMode->dmFields & DM_BITSPERPEL) || RequestedMode->dmBitsPerPel == 0)
823  dmSearch.dmBitsPerPel = pdmSelected->dmBitsPerPel;
824  if (!(RequestedMode->dmFields & DM_PELSWIDTH) || RequestedMode->dmPelsWidth == 0)
825  dmSearch.dmPelsWidth = pdmSelected->dmPelsWidth;
826  if (!(RequestedMode->dmFields & DM_PELSHEIGHT) || RequestedMode->dmPelsHeight == 0)
827  dmSearch.dmPelsHeight = pdmSelected->dmPelsHeight;
828  if (!(RequestedMode->dmFields & DM_DISPLAYFREQUENCY) || RequestedMode->dmDisplayFrequency == 0)
829  dmSearch.dmDisplayFrequency = pdmSelected->dmDisplayFrequency;
830  }
832  {
833  bResult = FALSE;
834  }
835  _SEH2_END;
836 
837  if (!bResult)
838  return FALSE;
839  }
840  }
841 
842  /* Now, search the exact mode to return to caller */
843  for (i = 0; i < pGraphicsDevice->cDevModes; i++)
844  {
845  pdmCurrent = pGraphicsDevice->pDevModeList[i].pdm;
846 
847  /* For now, we only need those */
848  if (pdmCurrent->dmBitsPerPel != dmSearch.dmBitsPerPel)
849  continue;
850  if (pdmCurrent->dmPelsWidth != dmSearch.dmPelsWidth)
851  continue;
852  if (pdmCurrent->dmPelsHeight != dmSearch.dmPelsHeight)
853  continue;
854  if (pdmCurrent->dmDisplayFrequency != dmSearch.dmDisplayFrequency)
855  continue;
856 
857  pdmSelected = pdmCurrent;
858  break;
859  }
860 
861  if (!pdmSelected)
862  {
863  ERR("Requested mode not found (%dx%dx%d %d Hz)\n",
864  dmSearch.dmPelsWidth,
865  dmSearch.dmPelsHeight,
866  dmSearch.dmBitsPerPel,
867  dmSearch.dmDisplayFrequency);
868  return FALSE;
869  }
870 
871  /* Allocate memory for output */
872  pdm = ExAllocatePoolZero(PagedPool, pdmSelected->dmSize + pdmSelected->dmDriverExtra, GDITAG_DEVMODE);
873  if (!pdm)
874  return FALSE;
875 
876  /* Copy selected mode */
877  RtlCopyMemory(pdm, pdmSelected, pdmSelected->dmSize);
878  RtlCopyMemory((PVOID)((ULONG_PTR)pdm + pdm->dmSize),
879  (PVOID)((ULONG_PTR)pdmSelected + pdmSelected->dmSize),
880  pdmSelected->dmDriverExtra);
881 
882  /* Add back panning */
883  if (ulVirtualWidth != 0 && ulVirtualHeight != 0 &&
884  pdm->dmPelsWidth < ulVirtualWidth &&
885  pdm->dmPelsHeight < ulVirtualHeight)
886  {
888  pdm->dmPanningWidth = pdm->dmPelsWidth;
889  pdm->dmPanningHeight = pdm->dmPelsHeight;
890  pdm->dmPelsWidth = ulVirtualWidth;
891  pdm->dmPelsHeight = ulVirtualHeight;
892  }
893 
894  *pSelectedMode = pdm;
895  return TRUE;
896 }
897 
900 HANDLE
901 APIENTRY
903  _In_ LPWSTR pwszDriverName)
904 {
905  return (HANDLE)LDEVOBJ_pLoadDriver(pwszDriverName, LDEV_IMAGE);
906 }
907 
908 
909 VOID
910 APIENTRY
913 {
914  PLDEVOBJ pldev = (PLDEVOBJ)hModule;
915 
916  /* Make sure the LDEV is in the list */
917  ASSERT((pldev->leLink.Flink != NULL) && (pldev->leLink.Blink != NULL));
918 
919  LDEVOBJ_vDereference(pldev);
920 }
921 
922 
923 PVOID
924 APIENTRY
927  _In_ LPSTR lpProcName)
928 {
929  PLDEVOBJ pldev = (PLDEVOBJ)hModule;
930 
932 
933  /* Check if win32k is requested */
934  if (!pldev)
935  {
936  pldev = gpldevWin32k;
937  }
938 
939  /* Check if the drivers entry point is requested */
940  if (_strnicmp(lpProcName, "DrvEnableDriver", 15) == 0)
941  {
942  return pldev->pGdiDriverInfo->EntryPoint;
943  }
944 
945  /* Try to find the address */
946  return LDEVOBJ_pvFindImageProcAddress(pldev, lpProcName);
947 }
948 
949 /* EOF */
_SEH2_TRY
Definition: create.c:4226
signed char * PCHAR
Definition: retypes.h:7
NTSTRSAFEAPI RtlStringCbCopyW(_Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_ NTSTRSAFE_PCWSTR pszSrc)
Definition: ntstrsafe.h:174
#define GDITAG_LDEV
Definition: tags.h:136
VOID WINAPI EngReleaseSemaphore(IN HSEMAPHORE hsem)
Definition: eng.c:235
static VOID LDEVOBJ_vDereference(_Inout_ PLDEVOBJ pldev)
Definition: ldevobj.c:468
ULONG iFunc
Definition: winddi.h:530
DBG_DEFAULT_CHANNEL(EngLDev)
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define GDITAG_DEVMODE
Definition: tags.h:73
struct _devicemodeW * PDEVMODEW
NTSTATUS EngpGetDisplayDriverParameters(_In_ PGRAPHICS_DEVICE pGraphicsDevice, _Out_ PDEVMODEW pdm)
Definition: device.c:168
#define _Inout_
Definition: ms_sal.h:378
static VOID LDEVOBJ_vFreeLDEV(_In_ _Post_ptr_invalid_ PLDEVOBJ pldev)
Definition: ldevobj.c:103
DWORD dmFields
Definition: wingdi.h:1622
#define _Out_
Definition: ms_sal.h:345
BOOL LDEVOBJ_bProbeAndCaptureDevmode(_Inout_ PGRAPHICS_DEVICE pGraphicsDevice, _In_ PDEVMODEW RequestedMode, _Out_ PDEVMODEW *pSelectedMode, _In_ BOOL bSearchClosestMode)
Definition: ldevobj.c:735
#define TRUE
Definition: types.h:120
uint16_t * PWSTR
Definition: typedefs.h:56
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
FORCEINLINE VOID InsertHeadList(_Inout_ PLIST_ENTRY ListHead, _Inout_ __drv_aliasesMem PLIST_ENTRY Entry)
Definition: rtlfuncs.h:201
#define WARN(fmt,...)
Definition: debug.h:112
static BOOL LDEVOBJ_bGetClosestMode(_Inout_ PGRAPHICS_DEVICE pGraphicsDevice, _In_ PDEVMODEW RequestedMode, _Out_ PDEVMODEW *pSelectedMode)
Definition: ldevobj.c:676
#define DM_PANNINGWIDTH
Definition: wingdi.h:1277
LONG NTSTATUS
Definition: precomp.h:26
_Check_return_ _CRTIMP int __cdecl _wcsnicmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
WORD dmDriverExtra
Definition: wingdi.h:1621
_In_ LPWSTR _In_ ULONG _In_ ULONG _In_ ULONG _Out_ DEVINFO _In_ HDEV _In_ LPWSTR _In_ HANDLE hDriver
Definition: winddi.h:3553
ULONG LDEVOBJ_ulGetDriverModes(_In_ LPWSTR pwszDriverName, _In_ HANDLE hDriver, _Out_ PDEVMODEW *ppdm)
Definition: ldevobj.c:509
_SEH2_END
Definition: create.c:4400
DWORD dmBitsPerPel
Definition: wingdi.h:1647
char * LPSTR
Definition: xmlstorage.h:182
static VOID LDEVOBJ_vDisableDriver(_Inout_ PLDEVOBJ pldev)
Definition: ldevobj.c:203
static PVOID LDEVOBJ_pvFindImageProcAddress(_In_ PLDEVOBJ pldev, _In_z_ LPSTR pszProcName)
Definition: ldevobj.c:223
#define _stricmp
Definition: cat.c:22
NTSYSAPI VOID NTAPI RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString)
DWORD AddressOfNameOrdinals
Definition: compat.h:167
#define DM_PELSWIDTH
Definition: wingdi.h:1269
uint32_t ULONG_PTR
Definition: typedefs.h:65
PFN pfn
Definition: winddi.h:531
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
return STATUS_NOT_IMPLEMENTED
#define L(x)
Definition: ntvdm.h:50
NTSTATUS NTAPI InitLDEVImpl(VOID)
Definition: ldevobj.c:30
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
static HSEMAPHORE ghsemLDEVList
Definition: ldevobj.c:20
#define FALSE
Definition: types.h:117
PFN_DrvGetModes GetModes
Definition: ntgdityp.h:610
unsigned int BOOL
Definition: ntddk_ex.h:94
static const unsigned GDI_ENGINE_VERSION
Definition: ldevobj.h:4
ULONG cbdevmode
Definition: pdevobj.h:46
ENGAPI VOID APIENTRY EngAcquireSemaphore(_Inout_ HSEMAPHORE hsem)
FN_DrvEnableDriver * PFN_DrvEnableDriver
Definition: winddi.h:3542
#define _In_
Definition: ms_sal.h:308
#define _In_z_
Definition: ms_sal.h:313
void * PVOID
Definition: retypes.h:9
static LDEVOBJ * gpldevWin32k
Definition: ldevobj.c:22
static LIST_ENTRY gleLdevListHead
Definition: ldevobj.c:21
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
DEVMODEW adevmode[1]
Definition: pdevobj.h:47
VOID APIENTRY EngUnloadImage(_In_ HANDLE hModule)
Definition: ldevobj.c:911
DRIVER_FUNCTIONS pfn
Definition: ldevobj.h:27
SYSTEM_GDI_DRIVER_INFORMATION * pGdiDriverInfo
Definition: ldevobj.h:19
Status
Definition: gdiplustypes.h:24
#define _Post_ptr_invalid_
Definition: ms_sal.h:698
NTSTATUS RtlAppendUnicodeToString(IN PUNICODE_STRING Str1, IN PWSTR Str2)
Definition: string_lib.cpp:62
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
#define TRACE(s)
Definition: solgame.cpp:4
#define ASSERT(a)
Definition: mode.c:44
DWORD_PTR HSEMAPHORE
Definition: axcore.idl:60
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
struct _DEVMODEINFO * pdmiNext
Definition: pdevobj.h:44
static PLDEVOBJ LDEVOBJ_AllocLDEV(_In_ LDEVTYPE ldevtype)
Definition: ldevobj.c:79
WORD dmSize
Definition: wingdi.h:1620
#define MAX_PATH
Definition: compat.h:34
#define _strnicmp(_String1, _String2, _MaxCount)
Definition: compat.h:23
DRVFN * pdrvfn
Definition: winddi.h:544
WCHAR dmDeviceName[CCHDEVICENAME]
Definition: wingdi.h:1617
DWORD dmPelsWidth
Definition: wingdi.h:1648
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
HANDLE APIENTRY EngLoadImage(_In_ LPWSTR pwszDriverName)
Definition: ldevobj.c:902
#define RtlImageDirectoryEntryToData
Definition: compat.h:668
LDEVTYPE
Definition: ldevobj.h:6
NTSYSAPI NTSTATUS NTAPI ZwSetSystemInformation(_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, _In_reads_bytes_(SystemInformationLength) PVOID SystemInformation, _In_ ULONG SystemInformationLength)
#define DM_DISPLAYFREQUENCY
Definition: wingdi.h:1272
Definition: typedefs.h:119
#define IMAGE_DIRECTORY_ENTRY_EXPORT
Definition: compat.h:151
static BOOL LDEVOBJ_bEnableDriver(_Inout_ PLDEVOBJ pldev, _In_ PFN_DrvEnableDriver pfnEnableDriver)
Definition: ldevobj.c:165
#define GDITAG_GDEVICE
Definition: tags.h:99
#define ERR(fmt,...)
Definition: debug.h:110
#define SystemLoadGdiDriverInformation
Definition: DriverTester.h:34
ULONG_PTR SIZE_T
Definition: typedefs.h:80
DWORD dmDisplayFrequency
Definition: wingdi.h:1654
PVOID APIENTRY EngFindImageProcAddress(_In_ HANDLE hModule, _In_ LPSTR lpProcName)
Definition: ldevobj.c:925
DRIVER_INITIALIZE DriverEntry
Definition: condrv.c:21
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define DM_PELSHEIGHT
Definition: wingdi.h:1270
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
static BOOL LDEVOBJ_bUnloadImage(_Inout_ PLDEVOBJ pldev)
Definition: ldevobj.c:269
ULONG iDriverVersion
Definition: winddi.h:542
unsigned int * PULONG
Definition: retypes.h:1
#define NULL
Definition: types.h:112
PLDEVOBJ LDEVOBJ_pLoadInternal(_In_ PFN_DrvEnableDriver pfnEnableDriver, _In_ ULONG ldevtype)
Definition: ldevobj.c:303
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define leave
Definition: btrfs_drv.h:138
DWORD dmPelsHeight
Definition: wingdi.h:1649
static BOOL LDEVOBJ_bLoadImage(_Inout_ PLDEVOBJ pldev, _In_ PUNICODE_STRING pustrPathName)
Definition: ldevobj.c:116
#define DM_DIFF(field)
ULONG ulDriverVersion
Definition: ldevobj.h:22
struct _SYSTEM_GDI_DRIVER_INFORMATION SYSTEM_GDI_DRIVER_INFORMATION
struct _LDEVOBJ * PLDEVOBJ
#define RVA_TO_ADDR(Base, Rva)
Definition: ldevobj.c:15
HSEMAPHORE WINAPI EngCreateSemaphore(VOID)
Definition: eng.c:75
unsigned int ULONG
Definition: retypes.h:1
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define UNIMPLEMENTED
Definition: debug.h:115
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
LDEVTYPE ldevtype
Definition: ldevobj.h:20
char * cleanup(char *str)
Definition: wpickclick.c:99
BOOL LDEVOBJ_bBuildDevmodeList(_Inout_ PGRAPHICS_DEVICE pGraphicsDevice)
Definition: ldevobj.c:563
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define DM_BITSPERPEL
Definition: wingdi.h:1268
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:40
LIST_ENTRY leLink
Definition: ldevobj.h:18
#define STATUS_SUCCESS
Definition: shellext.h:65
#define __ImageBase
Definition: crt_handler.c:22
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define DM_PANNINGHEIGHT
Definition: wingdi.h:1278
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
static CODE_SEG("PAGE")
Definition: isapnp.c:1482
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
PIMAGE_EXPORT_DIRECTORY ExportSectionPointer
Definition: DriverTester.h:49
unsigned short * PUSHORT
Definition: retypes.h:2
PLDEVOBJ NTAPI LDEVOBJ_pLoadDriver(_In_z_ LPWSTR pwszDriverName, _In_ ULONG ldevtype)
Definition: ldevobj.c:347
#define APIENTRY
Definition: api.h:79
HMODULE hModule
Definition: animate.c:44
ULONG cRefs
Definition: ldevobj.h:21