You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
421 lines
12 KiB
421 lines
12 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1996 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: moninfo.c
|
|
* Content: Code to query monitor specifications
|
|
*@@BEGIN_MSINTERNAL
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 24-mar-96 kylej initial implementation (code from Toddla)
|
|
*@@END_MSINTERNAL
|
|
*
|
|
***************************************************************************/
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <minivdd.h>
|
|
#include "edid.h"
|
|
|
|
#pragma optimize("gle", off)
|
|
#define Not_VxD
|
|
#include <vmm.h>
|
|
#include <configmg.h>
|
|
#pragma optimize("", on)
|
|
|
|
#include "ddraw16.h"
|
|
|
|
/***************************************************************************
|
|
* just incase these are not defined, define them localy.
|
|
***************************************************************************/
|
|
|
|
#ifndef VDD_OPEN
|
|
#define VDD_OPEN (13 + MINIVDD_SVC_BASE_OFFSET)
|
|
#endif
|
|
|
|
#ifndef VDD_OPEN_TEST
|
|
#define VDD_OPEN_TEST 0x00000001
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
***************************************************************************/
|
|
static int myatoi(LPSTR sz)
|
|
{
|
|
int i=0;
|
|
int sign=+1;
|
|
|
|
if (*sz=='-')
|
|
{
|
|
sign=-1;
|
|
sz++;
|
|
}
|
|
|
|
while (*sz && *sz >= '0' && *sz <= '9')
|
|
i = i*10 + (*sz++-'0');
|
|
|
|
return i*sign;
|
|
}
|
|
|
|
/***************************************************************************
|
|
VDDCall - make a service call into the VDD
|
|
***************************************************************************/
|
|
|
|
#pragma optimize("gle", off)
|
|
DWORD VDDCall(DWORD dev, DWORD function, DWORD flags, LPVOID buffer, DWORD buffer_size)
|
|
{
|
|
static DWORD VDDEntryPoint=0;
|
|
DWORD result=0xFFFFFFFF;
|
|
|
|
if (VDDEntryPoint == 0)
|
|
{
|
|
_asm
|
|
{
|
|
xor di,di ;set these to zero before calling
|
|
mov es,di ;
|
|
mov ax,1684h ;INT 2FH: Get VxD API Entry Point
|
|
mov bx,0ah ;this is device code for VDD
|
|
int 2fh ;call the multiplex interrupt
|
|
mov word ptr VDDEntryPoint[0],di ;
|
|
mov word ptr VDDEntryPoint[2],es ;save the returned data
|
|
}
|
|
|
|
if (VDDEntryPoint == 0)
|
|
return result;
|
|
}
|
|
|
|
_asm
|
|
{
|
|
_emit 66h _asm push si ; push esi
|
|
_emit 66h _asm push di ; push edi
|
|
_emit 66h _asm mov ax,word ptr function ;eax = function
|
|
_emit 66h _asm mov bx,word ptr dev ;ebx = device
|
|
_emit 66h _asm mov cx,word ptr buffer_size ;ecx = buffer_size
|
|
_emit 66h _asm mov dx,word ptr flags ;edx = flags
|
|
_emit 66h _asm xor di,di ; HIWORD(edi)=0
|
|
les di,buffer
|
|
mov si,di ;si
|
|
call dword ptr VDDEntryPoint ;call the VDD's PM API
|
|
cmp ax,word ptr function
|
|
je fail
|
|
_emit 66h _asm mov word ptr result,ax
|
|
fail: _emit 66h _asm pop di ; pop edi
|
|
_emit 66h _asm pop si ; pop esi
|
|
}
|
|
|
|
return result;
|
|
}
|
|
#pragma optimize("", on)
|
|
|
|
/***************************************************************************
|
|
* GetDisplayInfo - call the VDD to get the DISPLAYINFO for a device
|
|
*
|
|
* input
|
|
* szDevice - device name, use NULL or "DISPLAY" for primary device.
|
|
*
|
|
* output
|
|
* DISPLAYINFO filled in
|
|
*
|
|
***************************************************************************/
|
|
DWORD NEAR GetDisplayInfo(LPSTR szDevice, DISPLAYINFO FAR *pdi)
|
|
{
|
|
DWORD dev;
|
|
|
|
if (szDevice && lstrcmpi(szDevice, "DISPLAY") != 0)
|
|
dev = VDDCall(0, VDD_OPEN, VDD_OPEN_TEST, (LPVOID)szDevice, 0);
|
|
else
|
|
dev = 1;
|
|
|
|
if (dev == 0 || dev == 0xFFFFFFFF)
|
|
return 0;
|
|
|
|
pdi->diHdrSize = sizeof(DISPLAYINFO);
|
|
pdi->diDevNodeHandle = 0;
|
|
pdi->diMonitorDevNodeHandle = 0;
|
|
|
|
VDDCall(dev, VDD_GET_DISPLAY_CONFIG, 0, (LPVOID)pdi, sizeof(DISPLAYINFO));
|
|
|
|
if (pdi->diDevNodeHandle == 0)
|
|
return 0;
|
|
else
|
|
return dev;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* GetMonitorMaxSize - returns the max xresolution the monitor supports
|
|
*
|
|
* input
|
|
* szDevice - device name, use NULL or "DISPLAY" for primary device.
|
|
*
|
|
* output
|
|
* max xresolution of the monitor, or zero if the monitor
|
|
* is unknown.
|
|
*
|
|
***************************************************************************/
|
|
int DDAPI DD16_GetMonitorMaxSize(LPSTR szDevice)
|
|
{
|
|
DISPLAYINFO di;
|
|
char ach[40];
|
|
DWORD cb;
|
|
|
|
GetDisplayInfo(szDevice, &di);
|
|
|
|
if (di.diMonitorDevNodeHandle == 0)
|
|
return 0;
|
|
|
|
//
|
|
// we have the devnode handle for the monitor, read the max
|
|
// size from the registry, first try the HW key then the SW
|
|
// key, this way PnP monitors will be supported.
|
|
//
|
|
ach[0] = 0;
|
|
cb = sizeof(ach);
|
|
CM_Read_Registry_Value(di.diMonitorDevNodeHandle, NULL, "MaxResolution",
|
|
REG_SZ, ach, &cb, CM_REGISTRY_HARDWARE);
|
|
|
|
if (ach[0] == 0)
|
|
{
|
|
cb = sizeof(ach);
|
|
CM_Read_Registry_Value(di.diMonitorDevNodeHandle, NULL, "MaxResolution",
|
|
REG_SZ, ach, &cb, CM_REGISTRY_SOFTWARE);
|
|
}
|
|
|
|
//
|
|
// ach now contains the maxres, ie "1024,768" convert the xres to a
|
|
// integer and return it.
|
|
//
|
|
return myatoi(ach);
|
|
}
|
|
|
|
/***************************************************************************
|
|
* GetMonitorRefreshRateRanges
|
|
*
|
|
* returns the min/max refresh rate ranges for a given mode
|
|
*
|
|
* input
|
|
* szDevice - device name, use NULL (or "DISPLAY") for the primary device.
|
|
* xres - xres of the mode to query refresh ranges for
|
|
* yres - yres of the mode to query refresh ranges for
|
|
* pmin - place to put min refresh
|
|
* pmax - place to put max refresh
|
|
*
|
|
* output
|
|
* true if success
|
|
* is unknown.
|
|
*
|
|
***************************************************************************/
|
|
BOOL DDAPI DD16_GetMonitorRefreshRateRanges(LPSTR szDevice, int xres, int yres, int FAR *pmin, int FAR *pmax)
|
|
{
|
|
DISPLAYINFO di;
|
|
char ach[40];
|
|
DWORD cb;
|
|
HKEY hkey;
|
|
char SaveRes[40];
|
|
char SaveRate[40];
|
|
DWORD dev;
|
|
|
|
//
|
|
// set these to zero in case we fail
|
|
//
|
|
*pmin = 0;
|
|
*pmax = 0;
|
|
|
|
//
|
|
// get the devnode handle for the display
|
|
//
|
|
dev = GetDisplayInfo(szDevice, &di);
|
|
|
|
if (di.diDevNodeHandle == 0)
|
|
return 0;
|
|
|
|
//
|
|
// open the settings key for the device, if no custom key exists
|
|
// use HKCC/Display/Settings
|
|
//
|
|
hkey = NULL;
|
|
VDDCall(dev, VDD_OPEN_KEY, 0, &hkey, sizeof(hkey));
|
|
|
|
if (hkey == NULL)
|
|
RegOpenKey(HKEY_CURRENT_CONFIG, "Display\\Settings", &hkey);
|
|
|
|
if (hkey == NULL)
|
|
return 0;
|
|
|
|
//
|
|
// save the current values of RefreshRate, and Resolution
|
|
//
|
|
SaveRate[0] = 0;
|
|
SaveRes[0] = 0;
|
|
cb = sizeof(SaveRes);
|
|
RegQueryValueEx(hkey, "Resolution", NULL, NULL, SaveRes, &cb);
|
|
|
|
cb = sizeof(SaveRate);
|
|
CM_Read_Registry_Value(di.diDevNodeHandle, "DEFAULT", "RefreshRate",
|
|
REG_SZ, SaveRate, &cb, CM_REGISTRY_SOFTWARE);
|
|
|
|
//
|
|
// set our new values, the VDD uses the resoluton in the
|
|
// registry when computing the refresh rate ranges so we need
|
|
// to update the registry to contain the mode we want to test.
|
|
// we also need to write RefreshRate=-1 to enable automatic
|
|
// refresh rate calcultion.
|
|
//
|
|
cb = wsprintf(ach, "%d,%d", xres, yres);
|
|
RegSetValueEx(hkey, "Resolution", NULL, REG_SZ, ach, cb);
|
|
|
|
CM_Write_Registry_Value(di.diDevNodeHandle, "DEFAULT", "RefreshRate",
|
|
REG_SZ, "-1", 2, CM_REGISTRY_SOFTWARE);
|
|
|
|
//
|
|
// now call the VDD to get the refresh rate info.
|
|
//
|
|
di.diHdrSize = sizeof(DISPLAYINFO);
|
|
di.diRefreshRateMin = 0;
|
|
di.diRefreshRateMax = 0;
|
|
VDDCall(dev, VDD_GET_DISPLAY_CONFIG, 0, (LPVOID)&di, sizeof(DISPLAYINFO));
|
|
|
|
*pmin = di.diRefreshRateMin;
|
|
*pmax = di.diRefreshRateMax;
|
|
|
|
//
|
|
// restore the saved values back to the registry
|
|
//
|
|
CM_Write_Registry_Value(di.diDevNodeHandle, "DEFAULT", "RefreshRate",
|
|
REG_SZ, SaveRate, lstrlen(SaveRate), CM_REGISTRY_SOFTWARE);
|
|
RegSetValueEx(hkey, "Resolution", NULL, REG_SZ, SaveRes, lstrlen(SaveRes));
|
|
|
|
RegCloseKey(hkey);
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* GetDeviceConfig
|
|
*
|
|
* get the device resource config
|
|
*
|
|
* input
|
|
* szDevice - device name, use NULL (or "DISPLAY") for the primary device.
|
|
* lpConfig - points to a CMCONFIG struct (or NULL)
|
|
* cbConfig - size of lpConfig buffer
|
|
*
|
|
* output
|
|
* return the devnode handle, or 0 if failure
|
|
*
|
|
***************************************************************************/
|
|
DWORD DDAPI DD16_GetDeviceConfig(LPSTR szDevice, LPVOID lpConfig, DWORD cbConfig)
|
|
{
|
|
DISPLAYINFO di;
|
|
|
|
//
|
|
// get the devnode handle for the display
|
|
//
|
|
GetDisplayInfo(szDevice, &di);
|
|
|
|
if (di.diDevNodeHandle == 0)
|
|
return 0;
|
|
|
|
//
|
|
// call CONFIGMG to get the config
|
|
//
|
|
if (lpConfig)
|
|
{
|
|
if (cbConfig < sizeof(CMCONFIG))
|
|
return 0;
|
|
|
|
CM_Get_Alloc_Log_Conf((CMCONFIG FAR *)lpConfig, di.diDevNodeHandle, 0);
|
|
}
|
|
|
|
//
|
|
// return the DEVNODE handle
|
|
//
|
|
return di.diDevNodeHandle;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* GetMonitorEDIDData
|
|
*
|
|
* input
|
|
* szDevice - device name, use NULL or "DISPLAY" for primary device.
|
|
*
|
|
* output
|
|
* lpEdidData - EDID data.
|
|
*
|
|
***************************************************************************/
|
|
int DDAPI DD16_GetMonitorEDIDData(LPSTR szDevice, LPVOID lpEdidData)
|
|
{
|
|
DISPLAYINFO di;
|
|
DWORD cb;
|
|
|
|
GetDisplayInfo(szDevice, &di);
|
|
|
|
if (di.diMonitorDevNodeHandle == 0)
|
|
return 0;
|
|
|
|
cb = sizeof( VESA_EDID );
|
|
if (CM_Read_Registry_Value(di.diMonitorDevNodeHandle, NULL, "EDID", REG_BINARY, lpEdidData, &cb, CM_REGISTRY_HARDWARE) == CR_SUCCESS)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* GetRateFromRegistry
|
|
*
|
|
* input
|
|
* szDevice - device name, use NULL or "DISPLAY" for primary device.
|
|
*
|
|
***************************************************************************/
|
|
DWORD DDAPI DD16_GetRateFromRegistry(LPSTR szDevice)
|
|
{
|
|
DISPLAYINFO di;
|
|
DWORD cb;
|
|
BYTE szTemp[20];
|
|
|
|
//
|
|
// get the devnode handle for the display
|
|
//
|
|
GetDisplayInfo(szDevice, &di);
|
|
|
|
if (di.diDevNodeHandle == 0)
|
|
return 0;
|
|
|
|
cb = sizeof( szTemp );
|
|
if (CM_Read_Registry_Value(di.diDevNodeHandle, "DEFAULT", "RefreshRate", REG_SZ, szTemp, &cb, CM_REGISTRY_SOFTWARE) == CR_SUCCESS)
|
|
{
|
|
return atoi( szTemp );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* SetRateInRegistry
|
|
*
|
|
* input
|
|
* szDevice - device name, use NULL or "DISPLAY" for primary device.
|
|
* dwRate - Rate to set in the registry
|
|
*
|
|
***************************************************************************/
|
|
int DDAPI DD16_SetRateInRegistry(LPSTR szDevice, DWORD dwRate)
|
|
{
|
|
DISPLAYINFO di;
|
|
DWORD cb;
|
|
BYTE szTemp[20];
|
|
|
|
//
|
|
// get the devnode handle for the display
|
|
//
|
|
GetDisplayInfo(szDevice, &di);
|
|
|
|
if (di.diDevNodeHandle == 0)
|
|
return 0;
|
|
|
|
wsprintf( szTemp, "%d", (int)dwRate );
|
|
cb = lstrlen( szTemp ) ;
|
|
CM_Write_Registry_Value(di.diDevNodeHandle, "DEFAULT", "RefreshRate", REG_SZ, szTemp, cb, CM_REGISTRY_SOFTWARE);
|
|
|
|
return 0;
|
|
}
|
|
|