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 *********************************************************/
34 /* Initialize the loader lock */
35 ghsemLDEVList
= EngCreateSemaphore();
38 return STATUS_INSUFFICIENT_RESOURCES
;
41 /* Allocate a LDEVOBJ for win32k */
42 gpldevWin32k
= ExAllocatePoolWithTag(PagedPool
,
44 sizeof(SYSTEM_GDI_DRIVER_INFORMATION
),
48 return STATUS_NO_MEMORY
;
51 /* Initialize the LDEVOBJ for win32k */
52 gpldevWin32k
->pldevNext
= NULL
;
53 gpldevWin32k
->pldevPrev
= NULL
;
54 gpldevWin32k
->ldevtype
= LDEV_DEVICE_DISPLAY
;
55 gpldevWin32k
->cRefs
= 1;
56 gpldevWin32k
->ulDriverVersion
= GDI_ENGINE_VERSION
;
57 gpldevWin32k
->pGdiDriverInfo
= (PVOID
)(gpldevWin32k
+ 1);
58 RtlInitUnicodeString(&gpldevWin32k
->pGdiDriverInfo
->DriverName
,
59 L
"\\SystemRoot\\System32\\win32k.sys");
60 gpldevWin32k
->pGdiDriverInfo
->ImageAddress
= &__ImageBase
;
61 gpldevWin32k
->pGdiDriverInfo
->SectionPointer
= NULL
;
62 gpldevWin32k
->pGdiDriverInfo
->EntryPoint
= (PVOID
)DriverEntry
;
63 gpldevWin32k
->pGdiDriverInfo
->ExportSectionPointer
= NULL
;
64 gpldevWin32k
->pGdiDriverInfo
->ImageLength
= 0; // FIXME;
66 return STATUS_SUCCESS
;
71 LDEVOBJ_AllocLDEV(LDEVTYPE ldevtype
)
75 /* Allocate the structure from paged pool */
76 pldev
= ExAllocatePoolWithTag(PagedPool
, sizeof(LDEVOBJ
), GDITAG_LDEV
);
79 DPRINT1("Failed to allocate LDEVOBJ.\n");
83 /* Zero out the structure */
84 RtlZeroMemory(pldev
, sizeof(LDEVOBJ
));
86 /* Set the ldevtype */
87 pldev
->ldevtype
= ldevtype
;
94 LDEVOBJ_vFreeLDEV(PLDEVOBJ pldev
)
96 /* Make sure we don't have a driver loaded */
97 ASSERT(pldev
&& pldev
->pGdiDriverInfo
== NULL
);
100 ExFreePoolWithTag(pldev
, TAG_LDEV
);
105 LDEVOBJ_pdmiGetModes(
109 ULONG cbSize
, cbFull
;
110 PDEVMODEINFO pdminfo
;
112 DPRINT("LDEVOBJ_pdmiGetModes(%p, %p)\n", pldev
, hDriver
);
114 /* Call the driver to get the required size */
115 cbSize
= pldev
->pfn
.GetModes(hDriver
, 0, NULL
);
118 DPRINT1("DrvGetModes returned 0\n");
122 /* Add space for the header */
123 cbFull
= cbSize
+ FIELD_OFFSET(DEVMODEINFO
, adevmode
);
125 /* Allocate a buffer for the DEVMODE array */
126 pdminfo
= ExAllocatePoolWithTag(PagedPool
, cbFull
, GDITAG_DEVMODE
);
129 DPRINT1("Could not allocate devmodeinfo\n");
133 pdminfo
->pldev
= pldev
;
134 pdminfo
->cbdevmode
= cbSize
;
136 /* Call the driver again to fill the buffer */
137 cbSize
= pldev
->pfn
.GetModes(hDriver
, cbSize
, pdminfo
->adevmode
);
140 /* Could not get modes */
141 DPRINT1("returned size %ld(%ld)\n", cbSize
, pdminfo
->cbdevmode
);
154 PUNICODE_STRING pstrPathName
)
156 PSYSTEM_GDI_DRIVER_INFORMATION pDriverInfo
;
160 /* Make sure no image is loaded yet */
161 ASSERT(pldev
&& pldev
->pGdiDriverInfo
== NULL
);
163 /* Allocate a SYSTEM_GDI_DRIVER_INFORMATION structure */
164 cbSize
= sizeof(SYSTEM_GDI_DRIVER_INFORMATION
) + pstrPathName
->Length
;
165 pDriverInfo
= ExAllocatePoolWithTag(PagedPool
, cbSize
, GDITAG_LDEV
);
168 DPRINT1("Failed to allocate SYSTEM_GDI_DRIVER_INFORMATION\n");
172 /* Initialize the UNICODE_STRING and copy the driver name */
173 RtlInitEmptyUnicodeString(&pDriverInfo
->DriverName
,
174 (PWSTR
)(pDriverInfo
+ 1),
175 pstrPathName
->Length
);
176 RtlCopyUnicodeString(&pDriverInfo
->DriverName
, pstrPathName
);
178 /* Try to load the driver */
179 Status
= ZwSetSystemInformation(SystemLoadGdiDriverInformation
,
181 sizeof(SYSTEM_GDI_DRIVER_INFORMATION
));
183 if (!NT_SUCCESS(Status
))
185 DPRINT1("Failed to load a GDI driver: '%S', Status = 0x%lx\n",
186 pstrPathName
->Buffer
, Status
);
188 /* Free the allocated memory */
189 ExFreePoolWithTag(pDriverInfo
, TAG_LDEV
);
193 /* Set the driver info */
194 pldev
->pGdiDriverInfo
= pDriverInfo
;
196 /* Return success. */
202 LDEVOBJ_vUnloadImage(
207 /* Make sure we have a driver info */
208 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
210 /* Check if we have loaded a driver */
211 if (pldev
->pfn
.DisableDriver
)
213 /* Call the unload function */
214 pldev
->pfn
.DisableDriver();
217 /* Unload the driver */
218 Status
= ZwSetSystemInformation(SystemUnloadGdiDriverInformation
,
219 &pldev
->pGdiDriverInfo
->ImageAddress
,
221 if (!NT_SUCCESS(Status
))
223 DPRINT1("Failed to unload the driver, this is bad.\n");
226 /* Free the driver info structure */
227 ExFreePoolWithTag(pldev
->pGdiDriverInfo
, GDITAG_LDEV
);
228 pldev
->pGdiDriverInfo
= NULL
;
236 PFN_DrvEnableDriver pfnEnableDriver
;
240 /* Make sure we have a driver info */
241 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
243 /* Call the drivers DrvEnableDriver function */
244 RtlZeroMemory(&ded
, sizeof(ded
));
245 pfnEnableDriver
= pldev
->pGdiDriverInfo
->EntryPoint
;
246 if (!pfnEnableDriver(GDI_ENGINE_VERSION
, sizeof(ded
), &ded
))
248 DPRINT1("DrvEnableDriver failed\n");
250 /* Unload the image. */
251 LDEVOBJ_vUnloadImage(pldev
);
255 /* Copy the returned driver version */
256 pldev
->ulDriverVersion
= ded
.iDriverVersion
;
258 /* Fill the driver function array */
259 for (i
= 0; i
< ded
.c
; i
++)
261 pldev
->apfn
[ded
.pdrvfn
[i
].iFunc
] = ded
.pdrvfn
[i
].pfn
;
264 /* Return success. */
271 LDEVOBJ_pvFindImageProcAddress(
273 IN LPSTR pszProcName
)
276 PIMAGE_EXPORT_DIRECTORY pExportDir
;
277 PVOID pvProcAdress
= NULL
;
279 PULONG pNames
, pAddresses
;
282 /* Make sure we have a driver info */
283 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
285 /* Get the pointer to the export directory */
286 pvImageBase
= pldev
->pGdiDriverInfo
->ImageAddress
;
287 pExportDir
= RtlImageDirectoryEntryToData(pvImageBase
,
289 IMAGE_DIRECTORY_ENTRY_EXPORT
,
296 /* Get pointers to some tables */
297 pNames
= RVA_TO_ADDR(pvImageBase
, pExportDir
->AddressOfNames
);
298 pOrdinals
= RVA_TO_ADDR(pvImageBase
, pExportDir
->AddressOfNameOrdinals
);
299 pAddresses
= RVA_TO_ADDR(pvImageBase
, pExportDir
->AddressOfFunctions
);
301 /* Loop the export table */
302 for (i
= 0; i
< pExportDir
->NumberOfNames
; i
++)
304 /* Compare the name */
305 if (_stricmp(pszProcName
, RVA_TO_ADDR(pvImageBase
, pNames
[i
])) == 0)
307 /* Found! Calculate the procedure address */
308 pvProcAdress
= RVA_TO_ADDR(pvImageBase
, pAddresses
[pOrdinals
[i
]]);
313 /* Return the address */
320 LPWSTR pwszDriverName
,
323 WCHAR acwBuffer
[MAX_PATH
];
325 UNICODE_STRING strDriverName
;
329 DPRINT("EngLoadImageEx(%ls, %ld)\n", pwszDriverName
, ldevtype
);
330 ASSERT(pwszDriverName
);
332 /* Initialize buffer for the the driver name */
333 RtlInitEmptyUnicodeString(&strDriverName
, acwBuffer
, sizeof(acwBuffer
));
335 /* Start path with systemroot */
336 RtlAppendUnicodeToString(&strDriverName
, L
"\\SystemRoot\\System32\\");
338 /* Get Length of given string */
339 cwcLength
= wcslen(pwszDriverName
);
341 /* Check if we have a system32 path given */
342 pwsz
= pwszDriverName
+ cwcLength
;
343 while (pwsz
> pwszDriverName
)
345 if (_wcsnicmp(pwsz
, L
"\\system32\\", 10) == 0)
347 /* Driver name starts after system32 */
354 /* Append the driver name */
355 RtlAppendUnicodeToString(&strDriverName
, pwsz
);
357 /* MSDN says "The driver must include this suffix in the pwszDriver string."
358 But in fact it's optional. */
359 if (_wcsnicmp(pwszDriverName
+ cwcLength
- 4, L
".dll", 4) != 0)
361 /* Append the .dll suffix */
362 RtlAppendUnicodeToString(&strDriverName
, L
".dll");
366 EngAcquireSemaphore(ghsemLDEVList
);
368 /* Search the List of LDEVS for the driver name */
369 for (pldev
= gpldevHead
; pldev
!= NULL
; pldev
= pldev
->pldevNext
)
371 /* Check if the ldev is associated with a file */
372 if (pldev
->pGdiDriverInfo
)
374 /* Check for match (case insensative) */
375 if (RtlEqualUnicodeString(&pldev
->pGdiDriverInfo
->DriverName
, &strDriverName
, 1))
377 /* Image found in LDEV list */
383 /* Did we find one? */
386 /* No, allocate a new LDEVOBJ */
387 pldev
= LDEVOBJ_AllocLDEV(ldevtype
);
390 DPRINT1("Could not allocate LDEV\n");
395 if (!LDEVOBJ_bLoadImage(pldev
, &strDriverName
))
397 LDEVOBJ_vFreeLDEV(pldev
);
399 DPRINT1("LDEVOBJ_bLoadImage failed\n");
403 /* Shall we load a driver? */
404 if (ldevtype
!= LDEV_IMAGE
)
406 /* Load the driver */
407 if (!LDEVOBJ_bLoadDriver(pldev
))
409 DPRINT1("LDEVOBJ_bLoadDriver failed\n");
410 LDEVOBJ_vFreeLDEV(pldev
);
416 /* Insert the LDEV into the global list */
417 pldev
->pldevPrev
= NULL
;
418 pldev
->pldevNext
= gpldevHead
;
422 /* Increase ref count */
427 EngReleaseSemaphore(ghsemLDEVList
);
429 DPRINT("EngLoadImageEx returning %p\n", pldev
);
435 /** Exported functions ********************************************************/
440 LPWSTR pwszDriverName
)
442 return (HANDLE
)EngLoadImageEx(pwszDriverName
, LDEV_IMAGE
);
451 PLDEVOBJ pldev
= (PLDEVOBJ
)hModule
;
453 /* Make sure the LDEV is in the list */
454 ASSERT(pldev
->pldevPrev
|| pldev
->pldevNext
);
457 EngAcquireSemaphore(ghsemLDEVList
);
459 /* Decrement reference count */
462 /* No more references left? */
463 if (pldev
->cRefs
== 0)
465 /* Remove ldev from the list */
466 if (pldev
->pldevPrev
)
467 pldev
->pldevPrev
->pldevNext
= pldev
->pldevNext
;
468 if (pldev
->pldevNext
)
469 pldev
->pldevNext
->pldevPrev
= pldev
->pldevPrev
;
471 /* Unload the image */
472 LDEVOBJ_vUnloadImage(pldev
);
476 EngReleaseSemaphore(ghsemLDEVList
);
482 EngFindImageProcAddress(
486 PLDEVOBJ pldev
= (PLDEVOBJ
)hModule
;
488 ASSERT(gpldevWin32k
!= NULL
);
490 /* Check if win32k is requested */
493 pldev
= gpldevWin32k
;
496 /* Check if the drivers entry point is requested */
497 if (_strnicmp(lpProcName
, "DrvEnableDriver", 15) == 0)
499 return pldev
->pGdiDriverInfo
->EntryPoint
;
502 /* Try to find the address */
503 return LDEVOBJ_pvFindImageProcAddress(pldev
, lpProcName
);