检测笔记本盖子是否关闭/集成屏幕是否关闭

9
是否有Windows API可以检测笔记本电脑盖子是否关闭(= 集成笔记本屏幕关闭)?
已经有类似的问题:
获取当前笔记本电脑盖子状态 尽管自答案依赖于在盖子关闭时删除集成屏幕"设备",但并非所有笔记本电脑都会这样做。某些笔记本即使在盖子关闭时也会将屏幕"保留"给系统(实际上不显示任何内容)。这意味着当"多个显示器"设置为"扩展这些显示器"时,Windows桌面仍然延伸到关闭的屏幕上。
我还没有确定这种行为是否可以配置或者它是否是特定于驱动程序的:
从Windows桌面中删除关闭的笔记本电脑屏幕 但即使在这样的系统上,操作系统也知道盖子关闭了,因为它可以在盖子关闭时关闭/休眠机器。并且它会广播一个通知(WM_POWERBROADCAST):
检测笔记本电脑盖子关闭和打开 背景:我有一个应用程序,它在上次关闭时启动在相同的显示器上。如果它是在集成笔记本屏幕上关闭的,并且下一次应用程序启动时盖子关闭了(因为用户现在使用外部监视器),我的应用程序将在现在看不见的集成笔记本屏幕上启动。
因此,我想检测盖子是否关闭并将应用程序强制转到外部监视器。因此我要么寻找一种方法来检测盖子是否关闭,要么寻找一种方法来检测特定屏幕是否关闭(这将是更清洁的解决方案)。

你看到这个了吗:https://dev59.com/slLTa4cB1Zd3GeqPdcma? - theB
你有检查过WMI的Win32_DesktopMonitor吗?也许一些字段(可用性?)与你的上下文相关。 - Simon Mourier
@SimonMourier 感谢您的建议。尽管 select * from Win32_DesktopMonitor 查询甚至没有显示集成屏幕。 - Martin Prikryl
那么我想你需要调用ACPI的“_LID”方法(http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf),但这需要一个内核驱动程序。在Windows8+中可以使用用户模式驱动程序(https://msdn.microsoft.com/en-us/library/windows/hardware/ff536139.aspx)。 - Simon Mourier
@SimonMourier 嗯,不幸的是,这对我的目的来说有些过度了。 - Martin Prikryl
显示剩余2条评论
1个回答

2
听起来你并不关心盖子是否关闭,而只想知道你即将启动应用程序的屏幕区域是否可用。
如果操作系统“仍然使用关闭屏幕作为其扩展桌面”,那么这意味着(从操作系统的角度来看)该屏幕可用于应用程序。换句话说,你的应用程序不会是唯一受此问题影响的应用程序。虽然我必须说我从未亲眼观察过这种特定行为。
如果你需要在运行时移动应用程序,则可以注册RegisterPowerSettingNotification并对其进行操作。
但是,如果你正在启动并且需要知道屏幕是否打开或关闭,则有两个选项:

EnumDisplayDevices

这将为你提供有关屏幕是否连接到桌面并处于活动状态的信息。这是从User32.dll中的API获取的“系统信息”。
DISPLAY_DEVICE ddi;
ddi.cb = sizeof(ddi);
DWORD iDevNum = 0; // or iterate 0..15
EnumDisplayDevices(NULL, iDevNum, &ddi, /*EDD_GET_DEVICE_INTERFACE_NAME*/0);
if( (ddi.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0 &&
    (ddi.StateFlags & DISPLAY_DEVICE_ACTIVE) != 0 ){...}

DXGI (DX11)

这基本上提供了与上述相同的信息,但采用了更现代的方法(可能会减少虚阳性)。当然,这需要您链接 DXGI 以使其工作,并包括头文件,这将增加您的应用程序大小:

#include <atltypes.h>

IDXGIAdapter * pAdapter; 
std::vector <IDXGIAdapter*> vAdapters; 
IDXGIFactory* pFactory = NULL; 
// Create a DXGIFactory object.
if(FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory) ,(void**)&pFactory)))
{
    return;
}
for(UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i){
    DXGI_ADAPTER_DESC ad = {0};
    if(SUCCEEDED(pAdapter->GetDesc(&ad))){
        UINT j = 0;
        IDXGIOutput * pOutput;
        while(pAdapter->EnumOutputs(j, &pOutput) != DXGI_ERROR_NOT_FOUND)
        {
            DXGI_OUTPUT_DESC od = {0};
            if(SUCCEEDED(pOutput->GetDesc(&od))){
                // in here you can access od.DesktopCoordinates
                // od.AttachedToDesktop tells you if the screen is attached
            }
            pOutput->Release();
            ++j;
        }
    }
    pAdapter->Release();
} 

if(pFactory)
{
    pFactory->Release();
}

希望这能有所帮助。

Direct3D9

这种方法以稍微不同的方式提供显示信息 - 通过适配器列表和连接到这些适配器的监视器。请记得链接 d3d9 库以使其工作:

void d3d_adapterInfo(IDirect3D9 * _pD3D9, UINT _n)
{
    D3DADAPTER_IDENTIFIER9 id;
    const DWORD flags = 0;
    if(SUCCEEDED(_pD3D9->GetAdapterIdentifier(_n, flags, &id))){
        // id provides info on Driver, Description, Name
        HMONITOR hm = _pD3D9->GetAdapterMonitor(_n);
        // and based on that hm you get the same monitor info as
        // with the first method
    }
}

void d3d_enumDisplays()
{
    cout << endl << "--- Information by Direct3D9 ---" << endl;
    IDirect3D9 * pD3D9 = Direct3DCreate9(D3D_SDK_VERSION);
    const auto nAdapters = pD3D9->GetAdapterCount();
    cout << "A total of " << nAdapters << " adapters are listed by Direct3D9" << endl;
    for(UINT i = 0; i < nAdapters; ++i){
        d3d_adapterInfo(pD3D9, i);
    }
    pD3D9->Release();
}

以下所有代码片段均来自我的一些项目,您可以直接复制粘贴代码,它应该可以工作(除了一些缺少的函数或变量需要一些小修补,因为我在发布这里的代码时对其进行了修改以减小其大小)


感谢您的回复。您说得对,我实际上是在寻找屏幕可用性而不是盖子状态(我在问题的最后一段提到了这一点)。问题在于受影响的系统认为关闭的盖子屏幕是可用的。如果不是这样,它可能会从桌面本身中删除屏幕。因此,当盖子关闭时,您提供的所有三种方法都将集成屏幕表示为可用,不幸的是。 - Martin Prikryl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接