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 gpldevWin32k
->pGdiDriverInfo
->DriverName
.Buffer
= NULL
; // FIXME
58 gpldevWin32k
->pGdiDriverInfo
->ImageAddress
= &__ImageBase
;
59 gpldevWin32k
->pGdiDriverInfo
->SectionPointer
= NULL
;
60 gpldevWin32k
->pGdiDriverInfo
->EntryPoint
= (PVOID
)DriverEntry
;
61 gpldevWin32k
->pGdiDriverInfo
->ExportSectionPointer
= NULL
;
62 gpldevWin32k
->pGdiDriverInfo
->ImageLength
= 0; // FIXME;
69 LDEVOBJ_AllocLDEV(LDEVTYPE ldevtype
)
73 /* Allocate the structure from paged pool */
74 pldev
= ExAllocatePoolWithTag(PagedPool
, sizeof(LDEVOBJ
), GDITAG_LDEV
);
77 DPRINT1("Failed to allocate LDEVOBJ.\n");
81 /* Zero out the structure */
82 RtlZeroMemory(pldev
, sizeof(LDEVOBJ
));
84 /* Set the ldevtype */
85 pldev
->ldevtype
= ldevtype
;
92 LDEVOBJ_vFreeLDEV(PLDEVOBJ pldev
)
94 /* Make sure we don't have a driver loaded */
95 ASSERT(pldev
&& pldev
->pGdiDriverInfo
== NULL
);
98 ExFreePoolWithTag(pldev
, TAG_LDEV
);
103 LDEVOBJ_pdmiGetModes(
107 ULONG cbSize
, cbFull
;
108 PDEVMODEINFO pdminfo
;
110 DPRINT1("LDEVOBJ_pdmiGetModes(%p, %p)\n", pldev
, hDriver
);
112 /* Call the driver to get the required size */
113 cbSize
= pldev
->pfn
.GetModes(hDriver
, 0, NULL
);
116 DPRINT1("DrvGetModes returned 0\n");
120 /* Add space for the header */
121 cbFull
= cbSize
+ FIELD_OFFSET(DEVMODEINFO
, adevmode
);
123 /* Allocate a buffer for the DEVMODE array */
124 pdminfo
= ExAllocatePoolWithTag(PagedPool
, cbFull
, GDITAG_DEVMODE
);
127 DPRINT1("Could not allocate devmodeinfo\n");
131 pdminfo
->pldev
= pldev
;
132 pdminfo
->cbdevmode
= cbSize
;
134 /* Call the driver again to fill the buffer */
135 cbSize
= pldev
->pfn
.GetModes(hDriver
, cbSize
, pdminfo
->adevmode
);
138 /* Could not get modes */
139 DPRINT1("returned size %ld(%ld)\n", cbSize
, pdminfo
->cbdevmode
);
152 PUNICODE_STRING pstrPathName
)
154 PSYSTEM_GDI_DRIVER_INFORMATION pDriverInfo
;
158 /* Make sure no image is loaded yet */
159 ASSERT(pldev
&& pldev
->pGdiDriverInfo
== NULL
);
161 /* Allocate a SYSTEM_GDI_DRIVER_INFORMATION structure */
162 cbSize
= sizeof(SYSTEM_GDI_DRIVER_INFORMATION
) + pstrPathName
->Length
;
163 pDriverInfo
= ExAllocatePoolWithTag(PagedPool
, cbSize
, GDITAG_LDEV
);
166 DPRINT1("Failed to allocate SYSTEM_GDI_DRIVER_INFORMATION\n");
170 /* Initialize the UNICODE_STRING */
171 pDriverInfo
->DriverName
.Buffer
= (PWSTR
)(pDriverInfo
+ 1);
172 pDriverInfo
->DriverName
.Length
= pstrPathName
->Length
;
173 pDriverInfo
->DriverName
.MaximumLength
= pstrPathName
->Length
;
175 /* Copy the driver name */
176 // RtlCopyUnicodeString(pDriverInfo->DriverName, pstrPathName);
177 RtlCopyMemory(pDriverInfo
->DriverName
.Buffer
,
178 pstrPathName
->Buffer
,
179 pstrPathName
->Length
);
181 /* Try to load the driver */
182 Status
= ZwSetSystemInformation(SystemLoadGdiDriverInformation
,
184 sizeof(SYSTEM_GDI_DRIVER_INFORMATION
));
186 if (!NT_SUCCESS(Status
))
188 DPRINT1("Failed to load a GDI driver: '%S'\n", pstrPathName
->Buffer
);
190 /* Free the allocated memory */
191 ExFreePoolWithTag(pDriverInfo
, TAG_LDEV
);
195 /* Set the driver info */
196 pldev
->pGdiDriverInfo
= pDriverInfo
;
198 /* Return success. */
204 LDEVOBJ_vUnloadImage(
209 /* Make sure we have a driver info */
210 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
212 /* Check if we have loaded a driver */
213 if (pldev
->pfn
.DisableDriver
)
215 /* Call the unload function */
216 pldev
->pfn
.DisableDriver();
219 /* Unload the driver */
220 Status
= ZwSetSystemInformation(SystemUnloadGdiDriverInformation
,
221 &pldev
->pGdiDriverInfo
->ImageAddress
,
223 if (!NT_SUCCESS(Status
))
225 DPRINT1("Failed to unload the driver, this is bad.\n");
228 /* Free the driver info structure */
229 ExFreePoolWithTag(pldev
->pGdiDriverInfo
, GDITAG_LDEV
);
230 pldev
->pGdiDriverInfo
= NULL
;
238 PFN_DrvEnableDriver pfnEnableDriver
;
242 /* Make sure we have a driver info */
243 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
245 /* Call the drivers DrvEnableDriver function */
246 RtlZeroMemory(&ded
, sizeof(ded
));
247 pfnEnableDriver
= pldev
->pGdiDriverInfo
->EntryPoint
;
248 if (!pfnEnableDriver(GDI_ENGINE_VERSION
, sizeof(ded
), &ded
))
250 DPRINT1("DrvEnableDriver failed\n");
252 /* Unload the image. */
253 LDEVOBJ_vUnloadImage(pldev
);
257 /* Copy the returned driver version */
258 pldev
->ulDriverVersion
= ded
.iDriverVersion
;
260 /* Fill the driver function array */
261 for (i
= 0; i
< ded
.c
; i
++)
263 pldev
->apfn
[ded
.pdrvfn
[i
].iFunc
] = ded
.pdrvfn
[i
].pfn
;
266 /* Return success. */
273 LDEVOBJ_pvFindImageProcAddress(
275 IN LPSTR pszProcName
)
278 PIMAGE_EXPORT_DIRECTORY pExportDir
;
279 PVOID pvProcAdress
= NULL
;
281 PULONG pNames
, pAddresses
;
284 /* Make sure we have a driver info */
285 ASSERT(pldev
&& pldev
->pGdiDriverInfo
!= NULL
);
287 /* Get the pointer to the export directory */
288 pvImageBase
= pldev
->pGdiDriverInfo
->ImageAddress
;
289 pExportDir
= RtlImageDirectoryEntryToData(pvImageBase
,
291 IMAGE_DIRECTORY_ENTRY_EXPORT
,
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 LPWSTR pwszDriverName
,
326 UNICODE_STRING strDriverName
;
328 DPRINT("EngLoadImageEx(%ls, %ld)\n", pwszDriverName
, ldevtype
);
330 /* Initialize the driver name */
331 RtlInitUnicodeString(&strDriverName
, pwszDriverName
);
334 EngAcquireSemaphore(ghsemLDEVList
);
336 /* Search the List of LDEVS for the driver name */
337 for (pldev
= gpldevHead
; pldev
!= NULL
; pldev
= pldev
->pldevNext
)
339 /* Check if the ldev is associated with a file */
340 if (pldev
->pGdiDriverInfo
)
342 /* Check for match */
343 if (RtlEqualUnicodeString(&pldev
->pGdiDriverInfo
->DriverName
, &strDriverName
, 1))
345 /* Image found in LDEV list */
351 /* Did we find one? */
354 /* No, allocate a new LDEVOBJ */
355 pldev
= LDEVOBJ_AllocLDEV(ldevtype
);
358 DPRINT1("Could not allocate LDEV\n");
363 if (!LDEVOBJ_bLoadImage(pldev
, &strDriverName
))
365 LDEVOBJ_vFreeLDEV(pldev
);
367 DPRINT1("LDEVOBJ_bLoadImage failed\n");
371 /* Shall we load a driver? */
372 if (ldevtype
!= LDEV_IMAGE
)
374 /* Load the driver */
375 if (!LDEVOBJ_bLoadDriver(pldev
))
377 DPRINT1("LDEVOBJ_bLoadDriver failed\n");
378 LDEVOBJ_vFreeLDEV(pldev
);
384 /* Insert the LDEV into the global list */
385 pldev
->pldevPrev
= NULL
;
386 pldev
->pldevNext
= gpldevHead
;
390 /* Increase ref count */
395 EngReleaseSemaphore(ghsemLDEVList
);
397 DPRINT("EngLoadImageEx returning %p\n", pldev
);
405 LPWSTR pwszDriverName
,
408 WCHAR acwBuffer
[MAX_PATH
];
411 ASSERT(pwszDriverName
);
412 DPRINT("EngLoadDriver(%ls, %ld)\n", pwszDriverName
, ldevtype
);
414 /* Create a full file name */ // FIXME: do better than that
415 swprintf(acwBuffer
, L
"\\SystemRoot\\System32\\%ls.dll", pwszDriverName
);
417 pldev
= EngLoadImageEx(acwBuffer
, ldevtype
);
422 /** Exported functions ********************************************************/
427 LPWSTR pwszDriverName
)
429 return (HANDLE
)EngLoadImageEx(pwszDriverName
, LDEV_IMAGE
);
438 PLDEVOBJ pldev
= (PLDEVOBJ
)hModule
;
440 /* Make sure the LDEV is in the list */
441 ASSERT(pldev
->pldevPrev
|| pldev
->pldevNext
);
444 EngAcquireSemaphore(ghsemLDEVList
);
446 /* Decrement reference count */
449 /* No more references left? */
450 if (pldev
->cRefs
== 0)
452 /* Remove ldev from the list */
453 if (pldev
->pldevPrev
)
454 pldev
->pldevPrev
->pldevNext
= pldev
->pldevNext
;
455 if (pldev
->pldevNext
)
456 pldev
->pldevNext
->pldevPrev
= pldev
->pldevPrev
;
458 /* Unload the image */
459 LDEVOBJ_vUnloadImage(pldev
);
463 EngReleaseSemaphore(ghsemLDEVList
);
469 EngFindImageProcAddress(
473 PLDEVOBJ pldev
= (PLDEVOBJ
)hModule
;
475 ASSERT(gpldevWin32k
!= NULL
);
477 /* Check if win32k is requested */
480 pldev
= gpldevWin32k
;
483 /* Check if the drivers entry point is requested */
484 if (_strnicmp(lpProcName
, "DrvEnableDriver", 15) == 0)
486 return pldev
->pGdiDriverInfo
->EntryPoint
;
489 /* Try to find the address */
490 return LDEVOBJ_pvFindImageProcAddress(pldev
, lpProcName
);