2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Support for logical devices
5 * FILE: subsystems/win32/win32k/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
;
298 /* Get pointers to some tables */
299 pNames
= RVA_TO_ADDR(pvImageBase
, pExportDir
->AddressOfNames
);
300 pOrdinals
= RVA_TO_ADDR(pvImageBase
, pExportDir
->AddressOfNameOrdinals
);
301 pAddresses
= RVA_TO_ADDR(pvImageBase
, pExportDir
->AddressOfFunctions
);
303 /* Loop the export table */
304 for (i
= 0; i
< pExportDir
->NumberOfNames
; i
++)
306 /* Compare the name */
307 if (_stricmp(pszProcName
, RVA_TO_ADDR(pvImageBase
, pNames
[i
])) == 0)
309 /* Found! Calculate the procedure address */
310 pvProcAdress
= RVA_TO_ADDR(pvImageBase
, pAddresses
[pOrdinals
[i
]]);
315 /* Return the address */
322 _In_z_ LPWSTR pwszDriverName
,
325 WCHAR acwBuffer
[MAX_PATH
];
328 UNICODE_STRING strDriverName
;
332 TRACE("EngLoadImageEx(%ls, %lu)\n", pwszDriverName
, ldevtype
);
333 ASSERT(pwszDriverName
);
335 /* Initialize buffer for the the driver name */
336 RtlInitEmptyUnicodeString(&strDriverName
, acwBuffer
, sizeof(acwBuffer
));
338 /* Start path with systemroot */
339 RtlAppendUnicodeToString(&strDriverName
, L
"\\SystemRoot\\System32\\");
341 /* Get Length of given string */
342 cwcLength
= wcslen(pwszDriverName
);
344 /* Check if we have a system32 path given */
345 pwsz
= pwszDriverName
+ cwcLength
;
346 while (pwsz
> pwszDriverName
)
348 if ((*pwsz
== L
'\\') && (_wcsnicmp(pwsz
, L
"\\system32\\", 10) == 0))
350 /* Driver name starts after system32 */
357 /* Append the driver name */
358 RtlAppendUnicodeToString(&strDriverName
, pwsz
);
360 /* MSDN says "The driver must include this suffix in the pwszDriver string."
361 But in fact it's optional. The function can also load .sys files without
362 appending the .dll extension. */
363 if ((cwcLength
< 4) ||
364 ((_wcsnicmp(pwszDriverName
+ cwcLength
- 4, L
".dll", 4) != 0) &&
365 (_wcsnicmp(pwszDriverName
+ cwcLength
- 4, L
".sys", 4) != 0)) )
367 /* Append the .dll suffix */
368 RtlAppendUnicodeToString(&strDriverName
, L
".dll");
372 EngAcquireSemaphore(ghsemLDEVList
);
374 /* Search the List of LDEVS for the driver name */
375 for (pleLink
= gleLdevListHead
.Flink
;
376 pleLink
!= &gleLdevListHead
;
377 pleLink
= pleLink
->Flink
)
379 pldev
= CONTAINING_RECORD(pleLink
, LDEVOBJ
, leLink
);
381 /* Check if the ldev is associated with a file */
382 if (pldev
->pGdiDriverInfo
)
384 /* Check for match (case insensative) */
385 if (RtlEqualUnicodeString(&pldev
->pGdiDriverInfo
->DriverName
, &strDriverName
, TRUE
))
387 /* Image found in LDEV list */
393 /* Did we find one? */
394 if (pleLink
== &gleLdevListHead
)
396 /* No, allocate a new LDEVOBJ */
397 pldev
= LDEVOBJ_AllocLDEV(ldevtype
);
400 ERR("Could not allocate LDEV\n");
405 if (!LDEVOBJ_bLoadImage(pldev
, &strDriverName
))
407 LDEVOBJ_vFreeLDEV(pldev
);
409 ERR("LDEVOBJ_bLoadImage failed\n");
413 /* Shall we load a driver? */
414 if (ldevtype
!= LDEV_IMAGE
)
416 /* Load the driver */
417 if (!LDEVOBJ_bEnableDriver(pldev
))
419 ERR("LDEVOBJ_bEnableDriver failed\n");
421 /* Unload the image. */
422 LDEVOBJ_vUnloadImage(pldev
);
423 LDEVOBJ_vFreeLDEV(pldev
);
429 /* Insert the LDEV into the global list */
430 InsertHeadList(&gleLdevListHead
, &pldev
->leLink
);
433 /* Increase ref count */
438 EngReleaseSemaphore(ghsemLDEVList
);
440 TRACE("EngLoadImageEx returning %p\n", pldev
);
445 /** Exported functions ********************************************************/
450 _In_ LPWSTR pwszDriverName
)
452 return (HANDLE
)EngLoadImageEx(pwszDriverName
, LDEV_IMAGE
);
461 PLDEVOBJ pldev
= (PLDEVOBJ
)hModule
;
463 /* Make sure the LDEV is in the list */
464 ASSERT((pldev
->leLink
.Flink
!= NULL
) && (pldev
->leLink
.Blink
!= NULL
));
467 EngAcquireSemaphore(ghsemLDEVList
);
469 /* Decrement reference count */
472 /* No more references left? */
473 if (pldev
->cRefs
== 0)
475 /* Remove ldev from the list */
476 RemoveEntryList(&pldev
->leLink
);
478 /* Unload the image and free the LDEV */
479 LDEVOBJ_vUnloadImage(pldev
);
480 LDEVOBJ_vFreeLDEV(pldev
);
484 EngReleaseSemaphore(ghsemLDEVList
);
490 EngFindImageProcAddress(
492 _In_ LPSTR lpProcName
)
494 PLDEVOBJ pldev
= (PLDEVOBJ
)hModule
;
496 ASSERT(gpldevWin32k
!= NULL
);
498 /* Check if win32k is requested */
501 pldev
= gpldevWin32k
;
504 /* Check if the drivers entry point is requested */
505 if (_strnicmp(lpProcName
, "DrvEnableDriver", 15) == 0)
507 return pldev
->pGdiDriverInfo
->EntryPoint
;
510 /* Try to find the address */
511 return LDEVOBJ_pvFindImageProcAddress(pldev
, lpProcName
);