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)
12 DBG_DEFAULT_CHANNEL(EngLDev
);
15 #define RVA_TO_ADDR(Base,Rva) ((PVOID)(((ULONG_PTR)(Base)) + (Rva)))
18 /** Globals *******************************************************************/
20 static HSEMAPHORE ghsemLDEVList
;
21 static LIST_ENTRY gleLdevListHead
;
22 static LDEVOBJ
*gpldevWin32k
= NULL
;
25 /** Private functions *********************************************************/
34 /* Initialize the LDEV list head */
35 InitializeListHead(&gleLdevListHead
);
37 /* Initialize the loader lock */
38 ghsemLDEVList
= EngCreateSemaphore();
41 ERR("Failed to create ghsemLDEVList\n");
42 return STATUS_INSUFFICIENT_RESOURCES
;
45 /* Allocate a LDEVOBJ for win32k */
46 gpldevWin32k
= ExAllocatePoolWithTag(PagedPool
,
48 sizeof(SYSTEM_GDI_DRIVER_INFORMATION
),
52 return STATUS_NO_MEMORY
;
55 /* Initialize the LDEVOBJ for win32k */
56 gpldevWin32k
->leLink
.Flink
= NULL
;
57 gpldevWin32k
->leLink
.Blink
= NULL
;
58 gpldevWin32k
->ldevtype
= LDEV_DEVICE_DISPLAY
;
59 gpldevWin32k
->cRefs
= 1;
60 gpldevWin32k
->ulDriverVersion
= GDI_ENGINE_VERSION
;
61 gpldevWin32k
->pGdiDriverInfo
= (PVOID
)(gpldevWin32k
+ 1);
62 RtlInitUnicodeString(&gpldevWin32k
->pGdiDriverInfo
->DriverName
,
63 L
"\\SystemRoot\\System32\\win32k.sys");
64 gpldevWin32k
->pGdiDriverInfo
->ImageAddress
= &__ImageBase
;
65 gpldevWin32k
->pGdiDriverInfo
->SectionPointer
= NULL
;
66 gpldevWin32k
->pGdiDriverInfo
->EntryPoint
= (PVOID
)DriverEntry
;
67 gpldevWin32k
->pGdiDriverInfo
->ExportSectionPointer
=
68 RtlImageDirectoryEntryToData(&__ImageBase
,
70 IMAGE_DIRECTORY_ENTRY_EXPORT
,
72 gpldevWin32k
->pGdiDriverInfo
->ImageLength
= 0; // FIXME
74 return STATUS_SUCCESS
;
80 _In_ LDEVTYPE ldevtype
)
84 /* Allocate the structure from paged pool */
85 pldev
= ExAllocatePoolWithTag(PagedPool
, sizeof(LDEVOBJ
), GDITAG_LDEV
);
88 ERR("Failed to allocate LDEVOBJ.\n");
92 /* Zero out the structure */
93 RtlZeroMemory(pldev
, sizeof(LDEVOBJ
));
95 /* Set the ldevtype */
96 pldev
->ldevtype
= ldevtype
;
104 _In_ _Post_ptr_invalid_ PLDEVOBJ pldev
)
106 /* Make sure we don't have a driver loaded */
107 ASSERT(pldev
&& pldev
->pGdiDriverInfo
== NULL
);
108 ASSERT(pldev
->cRefs
== 0);
110 /* Free the memory */
111 ExFreePoolWithTag(pldev
, GDITAG_LDEV
);
116 LDEVOBJ_pdmiGetModes(
120 ULONG cbSize
, cbFull
;
121 PDEVMODEINFO pdminfo
;
123 TRACE("LDEVOBJ_pdmiGetModes(%p, %p)\n", pldev
, hDriver
);
125 /* Call the driver to get the required size */
126 cbSize
= pldev
->pfn
.GetModes(hDriver
, 0, NULL
);
129 ERR("DrvGetModes returned 0\n");
133 /* Add space for the header */
134 cbFull
= cbSize
+ FIELD_OFFSET(DEVMODEINFO
, adevmode
);
136 /* Allocate a buffer for the DEVMODE array */
137 pdminfo
= ExAllocatePoolWithTag(PagedPool
, cbFull
, GDITAG_DEVMODE
);
140 ERR("Could not allocate devmodeinfo\n");
144 pdminfo
->pldev
= pldev
;
145 pdminfo
->cbdevmode
= cbSize
;
147 /* Call the driver again to fill the buffer */
148 cbSize
= pldev
->pfn
.GetModes(hDriver
, cbSize
, pdminfo
->adevmode
);
151 /* Could not get modes */
152 ERR("returned size %lu(%lu)\n", cbSize
, pdminfo
->cbdevmode
);
153 ExFreePoolWithTag(pdminfo
, GDITAG_DEVMODE
);
163 _Inout_ PLDEVOBJ pldev
,
164 _In_ PUNICODE_STRING pustrPathName
)
166 PSYSTEM_GDI_DRIVER_INFORMATION pDriverInfo
;
170 /* Make sure no image is loaded yet */
171 ASSERT(pldev
&& pldev
->pGdiDriverInfo
== NULL
);
173 /* Allocate a SYSTEM_GDI_DRIVER_INFORMATION structure */
174 cbSize
= sizeof(SYSTEM_GDI_DRIVER_INFORMATION
) + pustrPathName
->Length
;
175 pDriverInfo
= ExAllocatePoolWithTag(PagedPool
, cbSize
, GDITAG_LDEV
);
178 ERR("Failed to allocate SYSTEM_GDI_DRIVER_INFORMATION\n");
182 /* Initialize the UNICODE_STRING and copy the driver name */
183 RtlInitEmptyUnicodeString(&pDriverInfo
->DriverName
,
184 (PWSTR
)(pDriverInfo
+ 1),
185 pustrPathName
->Length
);
186 RtlCopyUnicodeString(&pDriverInfo
->DriverName
, pustrPathName
);
188 /* Try to load the driver */
189 Status
= ZwSetSystemInformation(SystemLoadGdiDriverInformation
,
191 sizeof(SYSTEM_GDI_DRIVER_INFORMATION
));
192 if (!NT_SUCCESS(Status
))
194 ERR("Failed to load a GDI driver: '%wZ', Status = 0x%lx\n",
195 pustrPathName
, Status
);
197 /* Free the allocated memory */
198 ExFreePoolWithTag(pDriverInfo
, GDITAG_LDEV
);
202 /* Set the driver info */
203 pldev
->pGdiDriverInfo
= pDriverInfo
;
205 /* Return success. */
211 LDEVOBJ_vUnloadImage(
212 _Inout_ PLDEVOBJ pldev
)
216 /* Make sure we have a driver info */
217 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
219 /* Check if we have loaded a driver */
220 if (pldev
->pfn
.DisableDriver
)
222 /* Call the unload function */
223 pldev
->pfn
.DisableDriver();
226 /* Unload the driver */
227 Status
= ZwSetSystemInformation(SystemUnloadGdiDriverInformation
,
228 &pldev
->pGdiDriverInfo
->SectionPointer
,
230 if (!NT_SUCCESS(Status
))
232 ERR("Failed to unload the driver, this is bad.\n");
235 /* Free the driver info structure */
236 ExFreePoolWithTag(pldev
->pGdiDriverInfo
, GDITAG_LDEV
);
237 pldev
->pGdiDriverInfo
= NULL
;
242 LDEVOBJ_bEnableDriver(
243 _Inout_ PLDEVOBJ pldev
)
245 PFN_DrvEnableDriver pfnEnableDriver
;
249 /* Make sure we have a driver info */
250 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
252 /* Call the drivers DrvEnableDriver function */
253 RtlZeroMemory(&ded
, sizeof(ded
));
254 pfnEnableDriver
= pldev
->pGdiDriverInfo
->EntryPoint
;
255 if (!pfnEnableDriver(GDI_ENGINE_VERSION
, sizeof(ded
), &ded
))
257 ERR("DrvEnableDriver failed\n");
261 /* Copy the returned driver version */
262 pldev
->ulDriverVersion
= ded
.iDriverVersion
;
264 /* Fill the driver function array */
265 for (i
= 0; i
< ded
.c
; i
++)
267 pldev
->apfn
[ded
.pdrvfn
[i
].iFunc
] = ded
.pdrvfn
[i
].pfn
;
270 /* Return success. */
276 LDEVOBJ_pvFindImageProcAddress(
278 _In_z_ LPSTR pszProcName
)
281 PIMAGE_EXPORT_DIRECTORY pExportDir
;
282 PVOID pvProcAdress
= NULL
;
284 PULONG pNames
, pAddresses
;
287 /* Make sure we have a driver info */
288 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
290 /* Get the pointer to the export directory */
291 pvImageBase
= pldev
->pGdiDriverInfo
->ImageAddress
;
292 pExportDir
= pldev
->pGdiDriverInfo
->ExportSectionPointer
;
295 ERR("LDEVOBJ_pvFindImageProcAddress: no export section found\n");
299 /* Get pointers to some tables */
300 pNames
= RVA_TO_ADDR(pvImageBase
, pExportDir
->AddressOfNames
);
301 pOrdinals
= RVA_TO_ADDR(pvImageBase
, pExportDir
->AddressOfNameOrdinals
);
302 pAddresses
= RVA_TO_ADDR(pvImageBase
, pExportDir
->AddressOfFunctions
);
304 /* Loop the export table */
305 for (i
= 0; i
< pExportDir
->NumberOfNames
; i
++)
307 /* Compare the name */
308 if (_stricmp(pszProcName
, RVA_TO_ADDR(pvImageBase
, pNames
[i
])) == 0)
310 /* Found! Calculate the procedure address */
311 pvProcAdress
= RVA_TO_ADDR(pvImageBase
, pAddresses
[pOrdinals
[i
]]);
316 /* Return the address */
323 _In_z_ LPWSTR pwszDriverName
,
326 WCHAR acwBuffer
[MAX_PATH
];
329 UNICODE_STRING strDriverName
;
333 TRACE("EngLoadImageEx(%ls, %lu)\n", pwszDriverName
, ldevtype
);
334 ASSERT(pwszDriverName
);
336 /* Initialize buffer for the the driver name */
337 RtlInitEmptyUnicodeString(&strDriverName
, acwBuffer
, sizeof(acwBuffer
));
339 /* Start path with systemroot */
340 RtlAppendUnicodeToString(&strDriverName
, L
"\\SystemRoot\\System32\\");
342 /* Get Length of given string */
343 cwcLength
= wcslen(pwszDriverName
);
345 /* Check if we have a system32 path given */
346 pwsz
= pwszDriverName
+ cwcLength
;
347 while (pwsz
> pwszDriverName
)
349 if ((*pwsz
== L
'\\') && (_wcsnicmp(pwsz
, L
"\\system32\\", 10) == 0))
351 /* Driver name starts after system32 */
358 /* Append the driver name */
359 RtlAppendUnicodeToString(&strDriverName
, pwsz
);
361 /* MSDN says "The driver must include this suffix in the pwszDriver string."
362 But in fact it's optional. The function can also load .sys files without
363 appending the .dll extension. */
364 if ((cwcLength
< 4) ||
365 ((_wcsnicmp(pwszDriverName
+ cwcLength
- 4, L
".dll", 4) != 0) &&
366 (_wcsnicmp(pwszDriverName
+ cwcLength
- 4, L
".sys", 4) != 0)) )
368 /* Append the .dll suffix */
369 RtlAppendUnicodeToString(&strDriverName
, L
".dll");
373 EngAcquireSemaphore(ghsemLDEVList
);
375 /* Search the List of LDEVS for the driver name */
376 for (pleLink
= gleLdevListHead
.Flink
;
377 pleLink
!= &gleLdevListHead
;
378 pleLink
= pleLink
->Flink
)
380 pldev
= CONTAINING_RECORD(pleLink
, LDEVOBJ
, leLink
);
382 /* Check if the ldev is associated with a file */
383 if (pldev
->pGdiDriverInfo
)
385 /* Check for match (case insensative) */
386 if (RtlEqualUnicodeString(&pldev
->pGdiDriverInfo
->DriverName
, &strDriverName
, TRUE
))
388 /* Image found in LDEV list */
394 /* Did we find one? */
395 if (pleLink
== &gleLdevListHead
)
397 /* No, allocate a new LDEVOBJ */
398 pldev
= LDEVOBJ_AllocLDEV(ldevtype
);
401 ERR("Could not allocate LDEV\n");
406 if (!LDEVOBJ_bLoadImage(pldev
, &strDriverName
))
408 LDEVOBJ_vFreeLDEV(pldev
);
410 ERR("LDEVOBJ_bLoadImage failed\n");
414 /* Shall we load a driver? */
415 if (ldevtype
!= LDEV_IMAGE
)
417 /* Load the driver */
418 if (!LDEVOBJ_bEnableDriver(pldev
))
420 ERR("LDEVOBJ_bEnableDriver failed\n");
422 /* Unload the image. */
423 LDEVOBJ_vUnloadImage(pldev
);
424 LDEVOBJ_vFreeLDEV(pldev
);
430 /* Insert the LDEV into the global list */
431 InsertHeadList(&gleLdevListHead
, &pldev
->leLink
);
434 /* Increase ref count */
439 EngReleaseSemaphore(ghsemLDEVList
);
441 TRACE("EngLoadImageEx returning %p\n", pldev
);
446 /** Exported functions ********************************************************/
451 _In_ LPWSTR pwszDriverName
)
453 return (HANDLE
)EngLoadImageEx(pwszDriverName
, LDEV_IMAGE
);
462 PLDEVOBJ pldev
= (PLDEVOBJ
)hModule
;
464 /* Make sure the LDEV is in the list */
465 ASSERT((pldev
->leLink
.Flink
!= NULL
) && (pldev
->leLink
.Blink
!= NULL
));
468 EngAcquireSemaphore(ghsemLDEVList
);
470 /* Decrement reference count */
473 /* No more references left? */
474 if (pldev
->cRefs
== 0)
476 /* Remove ldev from the list */
477 RemoveEntryList(&pldev
->leLink
);
479 /* Unload the image and free the LDEV */
480 LDEVOBJ_vUnloadImage(pldev
);
481 LDEVOBJ_vFreeLDEV(pldev
);
485 EngReleaseSemaphore(ghsemLDEVList
);
491 EngFindImageProcAddress(
493 _In_ LPSTR lpProcName
)
495 PLDEVOBJ pldev
= (PLDEVOBJ
)hModule
;
497 ASSERT(gpldevWin32k
!= NULL
);
499 /* Check if win32k is requested */
502 pldev
= gpldevWin32k
;
505 /* Check if the drivers entry point is requested */
506 if (_strnicmp(lpProcName
, "DrvEnableDriver", 15) == 0)
508 return pldev
->pGdiDriverInfo
->EntryPoint
;
511 /* Try to find the address */
512 return LDEVOBJ_pvFindImageProcAddress(pldev
, lpProcName
);