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 *********************************************************/
33 /* Initialize the loader lock */
34 ghsemLDEVList
= EngCreateSemaphore();
40 /* Allocate a LDEVOBJ for win32k */
41 gpldevWin32k
= ExAllocatePoolWithTag(PagedPool
,
43 sizeof(SYSTEM_GDI_DRIVER_INFORMATION
),
50 /* Initialize the LDEVOBJ for win32k */
51 gpldevWin32k
->pldevNext
= NULL
;
52 gpldevWin32k
->pldevPrev
= NULL
;
53 gpldevWin32k
->ldevtype
= LDEV_DEVICE_DISPLAY
;
54 gpldevWin32k
->cRefs
= 1;
55 gpldevWin32k
->ulDriverVersion
= GDI_ENGINE_VERSION
;
56 gpldevWin32k
->pGdiDriverInfo
= (PVOID
)(gpldevWin32k
+ 1);
57 RtlInitUnicodeString(&gpldevWin32k
->pGdiDriverInfo
->DriverName
,
58 L
"\\SystemRoot\\System32\\win32k.sys");
59 gpldevWin32k
->pGdiDriverInfo
->ImageAddress
= &__ImageBase
;
60 gpldevWin32k
->pGdiDriverInfo
->SectionPointer
= NULL
;
61 gpldevWin32k
->pGdiDriverInfo
->EntryPoint
= (PVOID
)DriverEntry
;
62 gpldevWin32k
->pGdiDriverInfo
->ExportSectionPointer
= NULL
;
63 gpldevWin32k
->pGdiDriverInfo
->ImageLength
= 0; // FIXME;
70 LDEVOBJ_AllocLDEV(LDEVTYPE ldevtype
)
74 /* Allocate the structure from paged pool */
75 pldev
= ExAllocatePoolWithTag(PagedPool
, sizeof(LDEVOBJ
), GDITAG_LDEV
);
78 DPRINT1("Failed to allocate LDEVOBJ.\n");
82 /* Zero out the structure */
83 RtlZeroMemory(pldev
, sizeof(LDEVOBJ
));
85 /* Set the ldevtype */
86 pldev
->ldevtype
= ldevtype
;
93 LDEVOBJ_vFreeLDEV(PLDEVOBJ pldev
)
95 /* Make sure we don't have a driver loaded */
96 ASSERT(pldev
&& pldev
->pGdiDriverInfo
== NULL
);
99 ExFreePoolWithTag(pldev
, TAG_LDEV
);
104 LDEVOBJ_pdmiGetModes(
108 ULONG cbSize
, cbFull
;
109 PDEVMODEINFO pdminfo
;
111 DPRINT("LDEVOBJ_pdmiGetModes(%p, %p)\n", pldev
, hDriver
);
113 /* Call the driver to get the required size */
114 cbSize
= pldev
->pfn
.GetModes(hDriver
, 0, NULL
);
117 DPRINT1("DrvGetModes returned 0\n");
121 /* Add space for the header */
122 cbFull
= cbSize
+ FIELD_OFFSET(DEVMODEINFO
, adevmode
);
124 /* Allocate a buffer for the DEVMODE array */
125 pdminfo
= ExAllocatePoolWithTag(PagedPool
, cbFull
, GDITAG_DEVMODE
);
128 DPRINT1("Could not allocate devmodeinfo\n");
132 pdminfo
->pldev
= pldev
;
133 pdminfo
->cbdevmode
= cbSize
;
135 /* Call the driver again to fill the buffer */
136 cbSize
= pldev
->pfn
.GetModes(hDriver
, cbSize
, pdminfo
->adevmode
);
139 /* Could not get modes */
140 DPRINT1("returned size %ld(%ld)\n", cbSize
, pdminfo
->cbdevmode
);
153 PUNICODE_STRING pstrPathName
)
155 PSYSTEM_GDI_DRIVER_INFORMATION pDriverInfo
;
159 /* Make sure no image is loaded yet */
160 ASSERT(pldev
&& pldev
->pGdiDriverInfo
== NULL
);
162 /* Allocate a SYSTEM_GDI_DRIVER_INFORMATION structure */
163 cbSize
= sizeof(SYSTEM_GDI_DRIVER_INFORMATION
) + pstrPathName
->Length
;
164 pDriverInfo
= ExAllocatePoolWithTag(PagedPool
, cbSize
, GDITAG_LDEV
);
167 DPRINT1("Failed to allocate SYSTEM_GDI_DRIVER_INFORMATION\n");
171 /* Initialize the UNICODE_STRING and copy the driver name */
172 RtlInitEmptyUnicodeString(&pDriverInfo
->DriverName
,
173 (PWSTR
)(pDriverInfo
+ 1),
174 pstrPathName
->Length
);
175 RtlCopyUnicodeString(&pDriverInfo
->DriverName
, pstrPathName
);
177 /* Try to load the driver */
178 Status
= ZwSetSystemInformation(SystemLoadGdiDriverInformation
,
180 sizeof(SYSTEM_GDI_DRIVER_INFORMATION
));
182 if (!NT_SUCCESS(Status
))
184 DPRINT1("Failed to load a GDI driver: '%S', Status = 0x%lx\n",
185 pstrPathName
->Buffer
, Status
);
187 /* Free the allocated memory */
188 ExFreePoolWithTag(pDriverInfo
, TAG_LDEV
);
192 /* Set the driver info */
193 pldev
->pGdiDriverInfo
= pDriverInfo
;
195 /* Return success. */
201 LDEVOBJ_vUnloadImage(
206 /* Make sure we have a driver info */
207 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
209 /* Check if we have loaded a driver */
210 if (pldev
->pfn
.DisableDriver
)
212 /* Call the unload function */
213 pldev
->pfn
.DisableDriver();
216 /* Unload the driver */
217 Status
= ZwSetSystemInformation(SystemUnloadGdiDriverInformation
,
218 &pldev
->pGdiDriverInfo
->ImageAddress
,
220 if (!NT_SUCCESS(Status
))
222 DPRINT1("Failed to unload the driver, this is bad.\n");
225 /* Free the driver info structure */
226 ExFreePoolWithTag(pldev
->pGdiDriverInfo
, GDITAG_LDEV
);
227 pldev
->pGdiDriverInfo
= NULL
;
235 PFN_DrvEnableDriver pfnEnableDriver
;
239 /* Make sure we have a driver info */
240 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
242 /* Call the drivers DrvEnableDriver function */
243 RtlZeroMemory(&ded
, sizeof(ded
));
244 pfnEnableDriver
= pldev
->pGdiDriverInfo
->EntryPoint
;
245 if (!pfnEnableDriver(GDI_ENGINE_VERSION
, sizeof(ded
), &ded
))
247 DPRINT1("DrvEnableDriver failed\n");
249 /* Unload the image. */
250 LDEVOBJ_vUnloadImage(pldev
);
254 /* Copy the returned driver version */
255 pldev
->ulDriverVersion
= ded
.iDriverVersion
;
257 /* Fill the driver function array */
258 for (i
= 0; i
< ded
.c
; i
++)
260 pldev
->apfn
[ded
.pdrvfn
[i
].iFunc
] = ded
.pdrvfn
[i
].pfn
;
263 /* Return success. */
270 LDEVOBJ_pvFindImageProcAddress(
272 IN LPSTR pszProcName
)
275 PIMAGE_EXPORT_DIRECTORY pExportDir
;
276 PVOID pvProcAdress
= NULL
;
278 PULONG pNames
, pAddresses
;
281 /* Make sure we have a driver info */
282 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
284 /* Get the pointer to the export directory */
285 pvImageBase
= pldev
->pGdiDriverInfo
->ImageAddress
;
286 pExportDir
= RtlImageDirectoryEntryToData(pvImageBase
,
288 IMAGE_DIRECTORY_ENTRY_EXPORT
,
295 /* Get pointers to some tables */
296 pNames
= RVA_TO_ADDR(pvImageBase
, pExportDir
->AddressOfNames
);
297 pOrdinals
= RVA_TO_ADDR(pvImageBase
, pExportDir
->AddressOfNameOrdinals
);
298 pAddresses
= RVA_TO_ADDR(pvImageBase
, pExportDir
->AddressOfFunctions
);
300 /* Loop the export table */
301 for (i
= 0; i
< pExportDir
->NumberOfNames
; i
++)
303 /* Compare the name */
304 if (_stricmp(pszProcName
, RVA_TO_ADDR(pvImageBase
, pNames
[i
])) == 0)
306 /* Found! Calculate the procedure address */
307 pvProcAdress
= RVA_TO_ADDR(pvImageBase
, pAddresses
[pOrdinals
[i
]]);
312 /* Return the address */
319 LPWSTR pwszDriverName
,
322 WCHAR acwBuffer
[MAX_PATH
];
324 UNICODE_STRING strDriverName
;
328 DPRINT("EngLoadImageEx(%ls, %ld)\n", pwszDriverName
, ldevtype
);
329 ASSERT(pwszDriverName
);
331 /* Initialize buffer for the the driver name */
332 RtlInitEmptyUnicodeString(&strDriverName
, acwBuffer
, sizeof(acwBuffer
));
334 /* Start path with systemroot */
335 RtlAppendUnicodeToString(&strDriverName
, L
"\\SystemRoot\\System32\\");
337 /* Get Length of given string */
338 cwcLength
= wcslen(pwszDriverName
);
340 /* Check if we have a system32 path given */
341 pwsz
= pwszDriverName
+ cwcLength
;
342 while (pwsz
> pwszDriverName
)
344 if (_wcsnicmp(pwsz
, L
"\\system32\\", 10) == 0)
346 /* Driver name starts after system32 */
353 /* Append the driver name */
354 RtlAppendUnicodeToString(&strDriverName
, pwsz
);
356 /* MSDN says "The driver must include this suffix in the pwszDriver string."
357 But in fact it's optional. */
358 if (_wcsnicmp(pwszDriverName
+ cwcLength
- 4, L
".dll", 4) != 0)
360 /* Append the .dll suffix */
361 RtlAppendUnicodeToString(&strDriverName
, L
".dll");
365 EngAcquireSemaphore(ghsemLDEVList
);
367 /* Search the List of LDEVS for the driver name */
368 for (pldev
= gpldevHead
; pldev
!= NULL
; pldev
= pldev
->pldevNext
)
370 /* Check if the ldev is associated with a file */
371 if (pldev
->pGdiDriverInfo
)
373 /* Check for match (case insensative) */
374 if (RtlEqualUnicodeString(&pldev
->pGdiDriverInfo
->DriverName
, &strDriverName
, 1))
376 /* Image found in LDEV list */
382 /* Did we find one? */
385 /* No, allocate a new LDEVOBJ */
386 pldev
= LDEVOBJ_AllocLDEV(ldevtype
);
389 DPRINT1("Could not allocate LDEV\n");
394 if (!LDEVOBJ_bLoadImage(pldev
, &strDriverName
))
396 LDEVOBJ_vFreeLDEV(pldev
);
398 DPRINT1("LDEVOBJ_bLoadImage failed\n");
402 /* Shall we load a driver? */
403 if (ldevtype
!= LDEV_IMAGE
)
405 /* Load the driver */
406 if (!LDEVOBJ_bLoadDriver(pldev
))
408 DPRINT1("LDEVOBJ_bLoadDriver failed\n");
409 LDEVOBJ_vFreeLDEV(pldev
);
415 /* Insert the LDEV into the global list */
416 pldev
->pldevPrev
= NULL
;
417 pldev
->pldevNext
= gpldevHead
;
421 /* Increase ref count */
426 EngReleaseSemaphore(ghsemLDEVList
);
428 DPRINT("EngLoadImageEx returning %p\n", pldev
);
434 /** Exported functions ********************************************************/
439 LPWSTR pwszDriverName
)
441 return (HANDLE
)EngLoadImageEx(pwszDriverName
, LDEV_IMAGE
);
450 PLDEVOBJ pldev
= (PLDEVOBJ
)hModule
;
452 /* Make sure the LDEV is in the list */
453 ASSERT(pldev
->pldevPrev
|| pldev
->pldevNext
);
456 EngAcquireSemaphore(ghsemLDEVList
);
458 /* Decrement reference count */
461 /* No more references left? */
462 if (pldev
->cRefs
== 0)
464 /* Remove ldev from the list */
465 if (pldev
->pldevPrev
)
466 pldev
->pldevPrev
->pldevNext
= pldev
->pldevNext
;
467 if (pldev
->pldevNext
)
468 pldev
->pldevNext
->pldevPrev
= pldev
->pldevPrev
;
470 /* Unload the image */
471 LDEVOBJ_vUnloadImage(pldev
);
475 EngReleaseSemaphore(ghsemLDEVList
);
481 EngFindImageProcAddress(
485 PLDEVOBJ pldev
= (PLDEVOBJ
)hModule
;
487 ASSERT(gpldevWin32k
!= NULL
);
489 /* Check if win32k is requested */
492 pldev
= gpldevWin32k
;
495 /* Check if the drivers entry point is requested */
496 if (_strnicmp(lpProcName
, "DrvEnableDriver", 15) == 0)
498 return pldev
->pGdiDriverInfo
->EntryPoint
;
501 /* Try to find the address */
502 return LDEVOBJ_pvFindImageProcAddress(pldev
, lpProcName
);