2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Support for logical devices
5 * FILE: subsystems/win32/win32k/eng/ldevobj.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
17 #define RVA_TO_ADDR(Base,Rva) ((PVOID)(((ULONG_PTR)(Base)) + (Rva)))
20 /** Globals *******************************************************************/
22 HSEMAPHORE ghsemLDEVList
;
23 LDEVOBJ
*gpldevHead
= NULL
;
24 LDEVOBJ
*gpldevWin32k
= NULL
;
27 /** Private functions *********************************************************/
36 /* Initialize the loader lock */
37 ghsemLDEVList
= EngCreateSemaphore();
40 return STATUS_INSUFFICIENT_RESOURCES
;
43 /* Allocate a LDEVOBJ for win32k */
44 gpldevWin32k
= ExAllocatePoolWithTag(PagedPool
,
46 sizeof(SYSTEM_GDI_DRIVER_INFORMATION
),
50 return STATUS_NO_MEMORY
;
53 /* Initialize the LDEVOBJ for win32k */
54 gpldevWin32k
->pldevNext
= NULL
;
55 gpldevWin32k
->pldevPrev
= NULL
;
56 gpldevWin32k
->ldevtype
= LDEV_DEVICE_DISPLAY
;
57 gpldevWin32k
->cRefs
= 1;
58 gpldevWin32k
->ulDriverVersion
= GDI_ENGINE_VERSION
;
59 gpldevWin32k
->pGdiDriverInfo
= (PVOID
)(gpldevWin32k
+ 1);
60 RtlInitUnicodeString(&gpldevWin32k
->pGdiDriverInfo
->DriverName
,
61 L
"\\SystemRoot\\System32\\win32k.sys");
62 gpldevWin32k
->pGdiDriverInfo
->ImageAddress
= &__ImageBase
;
63 gpldevWin32k
->pGdiDriverInfo
->SectionPointer
= NULL
;
64 gpldevWin32k
->pGdiDriverInfo
->EntryPoint
= (PVOID
)DriverEntry
;
65 gpldevWin32k
->pGdiDriverInfo
->ExportSectionPointer
=
66 RtlImageDirectoryEntryToData(&__ImageBase
,
68 IMAGE_DIRECTORY_ENTRY_EXPORT
,
70 gpldevWin32k
->pGdiDriverInfo
->ImageLength
= 0; // FIXME;
72 return STATUS_SUCCESS
;
77 LDEVOBJ_AllocLDEV(LDEVTYPE ldevtype
)
81 /* Allocate the structure from paged pool */
82 pldev
= ExAllocatePoolWithTag(PagedPool
, sizeof(LDEVOBJ
), GDITAG_LDEV
);
85 DPRINT1("Failed to allocate LDEVOBJ.\n");
89 /* Zero out the structure */
90 RtlZeroMemory(pldev
, sizeof(LDEVOBJ
));
92 /* Set the ldevtype */
93 pldev
->ldevtype
= ldevtype
;
100 LDEVOBJ_vFreeLDEV(PLDEVOBJ pldev
)
102 /* Make sure we don't have a driver loaded */
103 ASSERT(pldev
&& pldev
->pGdiDriverInfo
== NULL
);
105 /* Free the memory */
106 ExFreePoolWithTag(pldev
, TAG_LDEV
);
111 LDEVOBJ_pdmiGetModes(
115 ULONG cbSize
, cbFull
;
116 PDEVMODEINFO pdminfo
;
118 DPRINT("LDEVOBJ_pdmiGetModes(%p, %p)\n", pldev
, hDriver
);
120 /* Call the driver to get the required size */
121 cbSize
= pldev
->pfn
.GetModes(hDriver
, 0, NULL
);
124 DPRINT1("DrvGetModes returned 0\n");
128 /* Add space for the header */
129 cbFull
= cbSize
+ FIELD_OFFSET(DEVMODEINFO
, adevmode
);
131 /* Allocate a buffer for the DEVMODE array */
132 pdminfo
= ExAllocatePoolWithTag(PagedPool
, cbFull
, GDITAG_DEVMODE
);
135 DPRINT1("Could not allocate devmodeinfo\n");
139 pdminfo
->pldev
= pldev
;
140 pdminfo
->cbdevmode
= cbSize
;
142 /* Call the driver again to fill the buffer */
143 cbSize
= pldev
->pfn
.GetModes(hDriver
, cbSize
, pdminfo
->adevmode
);
146 /* Could not get modes */
147 DPRINT1("returned size %ld(%ld)\n", cbSize
, pdminfo
->cbdevmode
);
160 PUNICODE_STRING pstrPathName
)
162 PSYSTEM_GDI_DRIVER_INFORMATION pDriverInfo
;
166 /* Make sure no image is loaded yet */
167 ASSERT(pldev
&& pldev
->pGdiDriverInfo
== NULL
);
169 /* Allocate a SYSTEM_GDI_DRIVER_INFORMATION structure */
170 cbSize
= sizeof(SYSTEM_GDI_DRIVER_INFORMATION
) + pstrPathName
->Length
;
171 pDriverInfo
= ExAllocatePoolWithTag(PagedPool
, cbSize
, GDITAG_LDEV
);
174 DPRINT1("Failed to allocate SYSTEM_GDI_DRIVER_INFORMATION\n");
178 /* Initialize the UNICODE_STRING and copy the driver name */
179 RtlInitEmptyUnicodeString(&pDriverInfo
->DriverName
,
180 (PWSTR
)(pDriverInfo
+ 1),
181 pstrPathName
->Length
);
182 RtlCopyUnicodeString(&pDriverInfo
->DriverName
, pstrPathName
);
184 /* Try to load the driver */
185 Status
= ZwSetSystemInformation(SystemLoadGdiDriverInformation
,
187 sizeof(SYSTEM_GDI_DRIVER_INFORMATION
));
189 if (!NT_SUCCESS(Status
))
191 DPRINT1("Failed to load a GDI driver: '%S', Status = 0x%lx\n",
192 pstrPathName
->Buffer
, Status
);
194 /* Free the allocated memory */
195 ExFreePoolWithTag(pDriverInfo
, TAG_LDEV
);
199 /* Set the driver info */
200 pldev
->pGdiDriverInfo
= pDriverInfo
;
202 /* Return success. */
208 LDEVOBJ_vUnloadImage(
213 /* Make sure we have a driver info */
214 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
216 /* Check if we have loaded a driver */
217 if (pldev
->pfn
.DisableDriver
)
219 /* Call the unload function */
220 pldev
->pfn
.DisableDriver();
223 /* Unload the driver */
224 Status
= ZwSetSystemInformation(SystemUnloadGdiDriverInformation
,
225 &pldev
->pGdiDriverInfo
->ImageAddress
,
227 if (!NT_SUCCESS(Status
))
229 DPRINT1("Failed to unload the driver, this is bad.\n");
232 /* Free the driver info structure */
233 ExFreePoolWithTag(pldev
->pGdiDriverInfo
, GDITAG_LDEV
);
234 pldev
->pGdiDriverInfo
= NULL
;
242 PFN_DrvEnableDriver pfnEnableDriver
;
246 /* Make sure we have a driver info */
247 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
249 /* Call the drivers DrvEnableDriver function */
250 RtlZeroMemory(&ded
, sizeof(ded
));
251 pfnEnableDriver
= pldev
->pGdiDriverInfo
->EntryPoint
;
252 if (!pfnEnableDriver(GDI_ENGINE_VERSION
, sizeof(ded
), &ded
))
254 DPRINT1("DrvEnableDriver failed\n");
256 /* Unload the image. */
257 LDEVOBJ_vUnloadImage(pldev
);
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. */
277 LDEVOBJ_pvFindImageProcAddress(
279 IN LPSTR pszProcName
)
282 PIMAGE_EXPORT_DIRECTORY pExportDir
;
283 PVOID pvProcAdress
= NULL
;
285 PULONG pNames
, pAddresses
;
288 /* Make sure we have a driver info */
289 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
291 /* Get the pointer to the export directory */
292 pvImageBase
= pldev
->pGdiDriverInfo
->ImageAddress
;
293 pExportDir
= pldev
->pGdiDriverInfo
->ExportSectionPointer
;
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 LPWSTR pwszDriverName
,
326 WCHAR acwBuffer
[MAX_PATH
];
328 UNICODE_STRING strDriverName
;
332 DPRINT("EngLoadImageEx(%ls, %ld)\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 (_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.
363 ms win32k EngLoadImageEx loading .sys file without append .dll
365 if ( (_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 (pldev
= gpldevHead
; pldev
!= NULL
; pldev
= pldev
->pldevNext
)
378 /* Check if the ldev is associated with a file */
379 if (pldev
->pGdiDriverInfo
)
381 /* Check for match (case insensative) */
382 if (RtlEqualUnicodeString(&pldev
->pGdiDriverInfo
->DriverName
, &strDriverName
, 1))
384 /* Image found in LDEV list */
390 /* Did we find one? */
393 /* No, allocate a new LDEVOBJ */
394 pldev
= LDEVOBJ_AllocLDEV(ldevtype
);
397 DPRINT1("Could not allocate LDEV\n");
402 if (!LDEVOBJ_bLoadImage(pldev
, &strDriverName
))
404 LDEVOBJ_vFreeLDEV(pldev
);
406 DPRINT1("LDEVOBJ_bLoadImage failed\n");
410 /* Shall we load a driver? */
411 if (ldevtype
!= LDEV_IMAGE
)
413 /* Load the driver */
414 if (!LDEVOBJ_bLoadDriver(pldev
))
416 DPRINT1("LDEVOBJ_bLoadDriver failed\n");
417 LDEVOBJ_vFreeLDEV(pldev
);
423 /* Insert the LDEV into the global list */
424 pldev
->pldevPrev
= NULL
;
425 pldev
->pldevNext
= gpldevHead
;
429 /* Increase ref count */
434 EngReleaseSemaphore(ghsemLDEVList
);
436 DPRINT("EngLoadImageEx returning %p\n", pldev
);
442 /** Exported functions ********************************************************/
447 LPWSTR pwszDriverName
)
449 return (HANDLE
)EngLoadImageEx(pwszDriverName
, LDEV_IMAGE
);
458 PLDEVOBJ pldev
= (PLDEVOBJ
)hModule
;
460 /* Make sure the LDEV is in the list */
461 ASSERT(pldev
->pldevPrev
|| pldev
->pldevNext
);
464 EngAcquireSemaphore(ghsemLDEVList
);
466 /* Decrement reference count */
469 /* No more references left? */
470 if (pldev
->cRefs
== 0)
472 /* Remove ldev from the list */
473 if (pldev
->pldevPrev
)
474 pldev
->pldevPrev
->pldevNext
= pldev
->pldevNext
;
475 if (pldev
->pldevNext
)
476 pldev
->pldevNext
->pldevPrev
= pldev
->pldevPrev
;
478 /* Unload the image */
479 LDEVOBJ_vUnloadImage(pldev
);
483 EngReleaseSemaphore(ghsemLDEVList
);
489 EngFindImageProcAddress(
493 PLDEVOBJ pldev
= (PLDEVOBJ
)hModule
;
495 ASSERT(gpldevWin32k
!= NULL
);
497 /* Check if win32k is requested */
500 pldev
= gpldevWin32k
;
503 /* Check if the drivers entry point is requested */
504 if (_strnicmp(lpProcName
, "DrvEnableDriver", 15) == 0)
506 return pldev
->pGdiDriverInfo
->EntryPoint
;
509 /* Try to find the address */
510 return LDEVOBJ_pvFindImageProcAddress(pldev
, lpProcName
);