📄 pmdisplay.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//
// This module implements the APIs the power manager uses to send power
// requests to display devices. It's defined in the MDD, but OEMs can
// override it or remove it from their image by not referencing
// gDisplayInterface in their code -- that will keep it from being pulled
// in by the linker.
//
#include <pmimpl.h>
#include <wingdi.h>
typedef HDC (WINAPI *PFN_CreateDCW)(LPCWSTR, LPCWSTR , LPCWSTR , CONST DEVMODEW *);
typedef BOOL (WINAPI *PFN_DeleteDC)(HDC);
typedef int (WINAPI *PFN_ExtEscape)(HDC, int, int, LPCSTR, int, LPSTR);
// global function pointers
static PFN_CreateDCW gpfnCreateDCW = NULL;
static PFN_DeleteDC gpfnDeleteDC = NULL;
static PFN_ExtEscape gpfnExtEscape = NULL;
static HANDLE ghevGwesAPISetReady = NULL;
static BOOL gfGwesReady = FALSE;
// This routine arranges for initialization of the API used to communicate
// with devices of this class. It may be called more than once. If
// successful it returns TRUE. Otherwise it returns FALSE.
static BOOL
InitDisplayDeviceInterface(VOID)
{
BOOL fOk = FALSE;
SETFNAME(_T("InitDisplayDeviceInterface"));
if(gpfnCreateDCW == NULL) {
HMODULE hmCore = (HMODULE) LoadLibrary(_T("coredll.dll"));
PMLOGMSG(ZONE_WARN && hmCore == NULL, (_T("%s: LoadLibrary() failed %d\r\n"),
pszFname, GetLastError()));
if(hmCore != NULL) {
// get procedure addresses
gpfnCreateDCW = (PFN_CreateDCW) GetProcAddress(hmCore, _T("CreateDCW"));
gpfnDeleteDC = (PFN_DeleteDC) GetProcAddress(hmCore, _T("DeleteDC"));
gpfnExtEscape = (PFN_ExtEscape) GetProcAddress(hmCore, _T("ExtEscape"));
if(gpfnCreateDCW == NULL || gpfnExtEscape == NULL || gpfnDeleteDC == NULL) {
PMLOGMSG(ZONE_WARN,
(_T("%s: can't get APIs: pfnCreateDCW 0x%08x, pfnDeleteDC 0x%08x, pfnExtEscape 0x%08x\r\n"),
pszFname, gpfnCreateDCW, gpfnDeleteDC, gpfnExtEscape));
gpfnCreateDCW = NULL;
gpfnDeleteDC = NULL;
gpfnExtEscape = NULL;
FreeLibrary(hmCore);
}
}
}
// do we have the endpoints we need?
if(gpfnCreateDCW != NULL && gpfnExtEscape != NULL && gpfnDeleteDC != NULL) {
// yes, get a handle to the GWES API set event
if(ghevGwesAPISetReady == NULL) {
ghevGwesAPISetReady = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("SYSTEM/GweApiSetReady"));
DEBUGCHK(ghevGwesAPISetReady != NULL); // shouldn't happen since we have GWES APIs
if(ghevGwesAPISetReady == NULL) {
PMLOGMSG(ZONE_WARN, (_T("%s: can't open GWES API set ready event handle\r\n"),
pszFname));
}
}
}
// did we get all the resources we'll need to eventually access
// devices of this type?
if(ghevGwesAPISetReady != NULL) {
// yes, return a good status
fOk = TRUE;
}
PMLOGMSG(ZONE_INIT || (ZONE_WARN && !fOk), (_T("%s: returning %d\r\n"), pszFname, fOk));
return fOk;
}
// This routine opens a handle to a given device, or to the parent device
// that is its proxy. The return value is the device's handle, or
// INVALID_HANDLE_VALUE if there's an error.
static HANDLE
OpenDisplayDevice(PDEVICE_STATE pds)
{
SETFNAME(_T("OpenDisplayDevice"));
HANDLE hRet = NULL;
// Get a handle to the client device. The client's name will generally be "DISPLAY" for
// the default display, but it could be anything that CreateDC supports.
PREFAST_DEBUGCHK(gpfnCreateDCW != NULL);
PREFAST_DEBUGCHK(gpfnDeleteDC != NULL);
PREFAST_DEBUGCHK(gpfnExtEscape != NULL);
// Make sure GWES is ready for us to access this device
if(!gfGwesReady) {
// We need to wait for GWES to finish -- since this is happening
// at boot time, we shouldn't have to wait for long.
DEBUGCHK(ghevGwesAPISetReady != NULL);
PMLOGMSG(ZONE_INIT, (_T("%s: waiting for GWES to initialize\r\n"),
pszFname));
DWORD dwStatus = WaitForSingleObject(ghevGwesAPISetReady, INFINITE);
if(dwStatus != WAIT_OBJECT_0) {
PMLOGMSG(ZONE_WARN,
(_T("%s: WaitForSingleObject() returned %d (error %d) on GWES ready event\r\n"),
pszFname, GetLastError()));
} else {
PMLOGMSG(ZONE_INIT, (_T("%s: GWES API sets are ready\r\n"), pszFname));
// we don't need to access the event, but keep the handle value non-NULL
// in case more than one display registers itself
CloseHandle(ghevGwesAPISetReady);
gfGwesReady = TRUE;
}
}
if(gfGwesReady) {
hRet = gpfnCreateDCW(pds->pszName, NULL, NULL, NULL);
if(hRet == NULL) {
PMLOGMSG(ZONE_WARN || ZONE_IOCTL, (_T("%s: CreateDC('%s') failed %d (0x%08x)\r\n"), pszFname,
pds->pszName, GetLastError(), GetLastError()));
hRet = INVALID_HANDLE_VALUE;
} else {
// determine whether the display driver really supports the PM IOCTLs
DWORD dwIoctl[] = { IOCTL_POWER_CAPABILITIES, IOCTL_POWER_SET, IOCTL_POWER_GET };
int i;
for(i = 0; i < dim(dwIoctl); i++) {
if(gpfnExtEscape((HDC) hRet, QUERYESCSUPPORT, sizeof(dwIoctl[i]), (LPCSTR) &dwIoctl[i], 0, NULL) <= 0) {
break;
}
}
if(i < dim(dwIoctl)) {
PMLOGMSG(ZONE_WARN, (_T("%s: '%s' doesn't support all power manager control codes\r\n"),
pszFname, pds->pszName));
gpfnDeleteDC((HDC) hRet);
hRet = INVALID_HANDLE_VALUE;
}
}
}
PMLOGMSG(ZONE_DEVICE || ZONE_IOCTL, (_T("%s: handle to '%s' is 0x%08x\r\n"), \
pszFname, pds->pszName, hRet));
return hRet;
}
// This routine closes a handle opened with OpenDisplayDevice(). It returns TRUE
// if successful, FALSE if there's a problem.
static BOOL
CloseDisplayDevice(HANDLE hDevice)
{
SETFNAME(_T("CloseDisplayDevice"));
DEBUGCHK(gpfnCreateDCW != NULL);
DEBUGCHK(gpfnDeleteDC != NULL);
DEBUGCHK(gpfnExtEscape != NULL);
DEBUGCHK(hDevice != NULL && hDevice != INVALID_HANDLE_VALUE);
DEBUGCHK(gfGwesReady);
PMLOGMSG(ZONE_DEVICE || ZONE_IOCTL, (_T("%s: closing 0x%08x\r\n"), pszFname, hDevice));
BOOL fOk = gpfnDeleteDC((HDC) hDevice);
PMLOGMSG(!fOk && (ZONE_WARN || ZONE_IOCTL), (_T("%s: DeleteDC(0x%08x) failed %d (0x%08x)\r\n"), pszFname,
hDevice, GetLastError(), GetLastError()));
return fOk;
}
// This routine issues a request to a device. It returns TRUE if successful,
// FALSE if there's a problem.
static BOOL
RequestDisplayDevice(HANDLE hDevice, DWORD dwRequest, LPVOID pInBuf, DWORD dwInSize,
LPVOID pOutBuf, DWORD dwOutSize, LPDWORD pdwBytesRet)
{
BOOL fOk = FALSE;
int iStatus;
SETFNAME(_T("RequestDisplayDevice"));
DEBUGCHK(gpfnCreateDCW != NULL);
PREFAST_DEBUGCHK(gpfnDeleteDC != NULL);
PREFAST_DEBUGCHK(gpfnExtEscape != NULL);
DEBUGCHK(hDevice != NULL && hDevice != INVALID_HANDLE_VALUE);
DEBUGCHK(gfGwesReady);
__try {
PMLOGMSG(ZONE_IOCTL, (_T("%s: calling ExtEscape(0x%08x) w/ request %d ('%s')\r\n"),
pszFname, hDevice, dwRequest,
dwRequest == IOCTL_POWER_CAPABILITIES ? _T("IOCTL_POWER_CAPABILITIES")
: dwRequest == IOCTL_POWER_GET ? _T("IOCTL_POWER_GET")
: dwRequest == IOCTL_POWER_SET ? _T("IOCTL_POWER_SET")
: dwRequest == IOCTL_POWER_QUERY ? _T("IOCTL_POWER_QUERY")
: dwRequest == IOCTL_REGISTER_POWER_RELATIONSHIP ? _T("IOCTL_REGISTER_POWER_RELATIONSHIP")
: _T("<UNKNOWN>")));
iStatus = gpfnExtEscape((HDC) hDevice, dwRequest, dwInSize, (LPCSTR) pInBuf,
dwOutSize, (LPSTR) pOutBuf);
if(iStatus > 0) {
fOk = TRUE;
if(pdwBytesRet != NULL) {
// need to fill this in with something
*pdwBytesRet = dwOutSize;
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER) {
PMLOGMSG(ZONE_WARN || ZONE_IOCTL, (_T("%s: exception in DeviceIoControl(%d)\r\n"), pszFname,
dwRequest));
fOk = FALSE;
}
PMLOGMSG(!fOk && (ZONE_WARN || ZONE_IOCTL),
(_T("%s: DeviceIoControl(%d) to 0x%08x failed %d (0x%08x)\r\n"), pszFname,
dwRequest, hDevice, GetLastError(), GetLastError()));
return fOk;
}
// create a data structure to encapsulate this interface
EXTERN_C DEVICE_INTERFACE gDisplayInterface = {
InitDisplayDeviceInterface,
OpenDisplayDevice,
CloseDisplayDevice,
RequestDisplayDevice
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -