diff --git a/win32ss/gdi/eng/mdevobj.c b/win32ss/gdi/eng/mdevobj.c index 25b85b6e94c..98d835e6c5a 100644 --- a/win32ss/gdi/eng/mdevobj.c +++ b/win32ss/gdi/eng/mdevobj.c @@ -9,5 +9,200 @@ #include #define NDEBUG #include +DBG_DEFAULT_CHANNEL(EngMDev); PMDEVOBJ gpmdev = NULL; /* FIXME: should be stored in gpDispInfo->pmdev */ + +VOID +MDEVOBJ_vEnable( + _Inout_ PMDEVOBJ pmdev) +{ + ULONG i; + + for (i = 0; i < pmdev->cDev; i++) + { + PDEVOBJ_vEnableDisplay(pmdev->dev[i].ppdev); + } +} + +BOOL +MDEVOBJ_bDisable( + _Inout_ PMDEVOBJ pmdev) +{ + BOOL bSuccess = TRUE; + ULONG i, j; + + for (i = 0; i < pmdev->cDev; i++) + { + if (!PDEVOBJ_bDisableDisplay(pmdev->dev[i].ppdev)) + { + bSuccess = FALSE; + break; + } + } + + if (!bSuccess) + { + /* Failed to disable all PDEVs. Reenable those we have disabled */ + for (j = 0; j < i; j++) + { + PDEVOBJ_vEnableDisplay(pmdev->dev[i].ppdev); + } + } + + return bSuccess; +} + +PMDEVOBJ +MDEVOBJ_Create( + _In_opt_ PUNICODE_STRING pustrDeviceName, + _In_opt_ PDEVMODEW pdm) +{ + PMDEVOBJ pmdev = NULL; + PPDEVOBJ ppdev; + PGRAPHICS_DEVICE pGraphicsDevice; + DEVMODEW dmDefault; + PDEVMODEW localPdm; + ULONG iDevNum = 0; + + TRACE("MDEVOBJ_Create('%wZ' '%dx%dx%d (%d Hz)')\n", + pustrDeviceName, + pdm ? pdm->dmPelsWidth : 0, + pdm ? pdm->dmPelsHeight : 0, + pdm ? pdm->dmBitsPerPel : 0, + pdm ? pdm->dmDisplayFrequency : 0); + + pmdev = ExAllocatePoolZero(PagedPool, sizeof(MDEVOBJ), GDITAG_MDEV); + if (!pmdev) + { + ERR("Failed to allocate memory for MDEV\n"); + return NULL; + } + + pmdev->cDev = 0; + + while (TRUE) + { + /* Get the right graphics devices: either the specified one, or all of them (one after one) */ + if (pustrDeviceName) + pGraphicsDevice = (iDevNum == 0) ? EngpFindGraphicsDevice(pustrDeviceName, 0) : NULL; + else + pGraphicsDevice = EngpFindGraphicsDevice(NULL, iDevNum); + iDevNum++; + + if (!pGraphicsDevice) + { + TRACE("Done enumeration of graphic devices (DeviceName '%wZ' iDevNum %d)\n", pustrDeviceName, iDevNum); + break; + } + + if (!pdm) + { + /* No settings requested. Read default settings from registry to dmDefault */ + HKEY hKey; + WCHAR DeviceKey[128]; + ULONG cbSize; + NTSTATUS Status; + DWORD dwValue; + + RtlZeroMemory(&dmDefault, sizeof(dmDefault)); + dmDefault.dmSize = sizeof(dmDefault); + + Status = RegOpenKey(L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO", &hKey); + if (!NT_SUCCESS(Status)) + { + /* Ignore this device and continue */ + ERR("Failed to open VIDEO key: status 0x%08x\n", Status); + continue; + } + cbSize = sizeof(DeviceKey); + Status = RegQueryValue(hKey, + pGraphicsDevice->szNtDeviceName, + REG_SZ, + DeviceKey, + &cbSize); + ZwClose(hKey); + if (!NT_SUCCESS(Status)) + { + /* Ignore this device and continue */ + ERR("Failed to open get device key for '%S': status 0x%08x\n", pGraphicsDevice->szNtDeviceName, Status); + continue; + } + Status = RegOpenKey(DeviceKey, &hKey); + if (!NT_SUCCESS(Status)) + { + /* Ignore this device and continue */ + ERR("Failed to open open device key '%S' for '%S': status 0x%08x\n", DeviceKey, pGraphicsDevice->szNtDeviceName, Status); + continue; + } +#define READ(field, str, flag) \ + if (RegReadDWORD(hKey, L##str, &dwValue)) \ + { \ + dmDefault.field = dwValue; \ + dmDefault.dmFields |= flag; \ + } + READ(dmBitsPerPel, "DefaultSettings.BitsPerPel", DM_BITSPERPEL); + READ(dmPelsWidth, "DefaultSettings.XResolution", DM_PELSWIDTH); + READ(dmPelsHeight, "DefaultSettings.YResolution", DM_PELSHEIGHT); + READ(dmDisplayFlags, "DefaultSettings.Flags", DM_DISPLAYFLAGS); + READ(dmDisplayFrequency, "DefaultSettings.VRefresh", DM_DISPLAYFREQUENCY); + READ(dmPanningWidth, "DefaultSettings.XPanning", DM_PANNINGWIDTH); + READ(dmPanningHeight, "DefaultSettings.YPanning", DM_PANNINGHEIGHT); + READ(dmDisplayOrientation, "DefaultSettings.Orientation", DM_DISPLAYORIENTATION); + READ(dmDisplayFixedOutput, "DefaultSettings.FixedOutput", DM_DISPLAYFIXEDOUTPUT); + READ(dmPosition.x, "Attach.RelativeX", DM_POSITION); + READ(dmPosition.y, "Attach.RelativeY", DM_POSITION); + ZwClose(hKey); + } + + /* Get or create a PDEV for these settings */ + if (LDEVOBJ_bProbeAndCaptureDevmode(pGraphicsDevice, pdm ? pdm : &dmDefault, &localPdm, !pdm)) + { + ppdev = PDEVOBJ_Create(pGraphicsDevice, localPdm, LDEV_DEVICE_DISPLAY); + } + else + { + ppdev = NULL; + } + + if (ppdev) + { + /* Great. We have a found a matching PDEV. Store it in MDEV */ + TRACE("Adding '%S' to MDEV %p\n", pGraphicsDevice->szWinDeviceName, pmdev); + PDEVOBJ_vReference(ppdev); + pmdev->dev[pmdev->cDev].ppdev = ppdev; + pmdev->cDev++; + } + else + { + WARN("Failed to add '%S' to MDEV %p\n", pGraphicsDevice->szWinDeviceName, pmdev); + } + } + + if (pmdev->cDev == 0) + { + TRACE("Failed to add any device to MDEV. Returning NULL\n"); + MDEVOBJ_vDestroy(pmdev); + return NULL; + } + + TRACE("Returning new MDEV %p with %d devices\n", pmdev, pmdev->cDev); + return pmdev; +} + +VOID +MDEVOBJ_vDestroy( + _Inout_ PMDEVOBJ pmdev) +{ + ULONG i; + + for (i = 0; i < pmdev->cDev; i++) + { + PDEVOBJ_vRelease(pmdev->dev[i].ppdev); + } + + if (pmdev->cDev > 1) + PDEVOBJ_vRelease(pmdev->ppdevGlobal); + + ExFreePoolWithTag(pmdev, GDITAG_MDEV); +} diff --git a/win32ss/gdi/eng/mdevobj.h b/win32ss/gdi/eng/mdevobj.h index 1d687d436a4..6dfb7aea4cf 100644 --- a/win32ss/gdi/eng/mdevobj.h +++ b/win32ss/gdi/eng/mdevobj.h @@ -7,11 +7,40 @@ typedef struct _PDEVOBJ *PPDEVOBJ; typedef struct _MDEVOBJ { + ULONG cDev; PPDEVOBJ ppdevGlobal; + struct + { + PPDEVOBJ ppdev; + } dev[10]; /* FIXME: max number of displays. Needs dynamic allocation */ } MDEVOBJ, *PMDEVOBJ; /* Globals ********************************************************************/ extern PMDEVOBJ gpmdev; /* FIXME: should be stored in gpDispInfo->pmdev */ +/* Function prototypes ********************************************************/ + +VOID +MDEVOBJ_vEnable( + _Inout_ PMDEVOBJ pmdev); + +BOOL +MDEVOBJ_bDisable( + _Inout_ PMDEVOBJ pmdev); + +/* Create a new MDEV: + * - pustrDeviceName: name of the device to put in MDEV. If NULL, will put all graphics devices in MDEV + * - pdm: settings associated to pustrDeviceName. Unused if pustrDeviceName is NULL. + * Return value: the new MDEV (or NULL in case of error) + */ +PMDEVOBJ +MDEVOBJ_Create( + _In_opt_ PUNICODE_STRING pustrDeviceName, + _In_opt_ PDEVMODEW pdm); + +VOID +MDEVOBJ_vDestroy( + _Inout_ PMDEVOBJ pmdev); + #endif /* !__WIN32K_MDEVOBJ_H */