在 Windows XP 中以编程方式旋转显示? (C++/Qt 和 WindowsAPI)

Posted

技术标签:

【中文标题】在 Windows XP 中以编程方式旋转显示? (C++/Qt 和 WindowsAPI)【英文标题】:Rotating displays programmatically in Windows XP? (C++/Qt and WindowsAPI) 【发布时间】:2012-03-26 08:56:39 【问题描述】:

因此,本质上,我们正在编写一个服务级应用程序,它可以更改各种用户级设置的属性。我现在正在处理显示部分。

我们已经让它适用于我们适用于 Windows 7 的软件版本,除了在 Windows XP 中旋转显示器(奇怪的是,它在 Windows 7 中确实适用)之外,几乎所有功能都可以正常工作。 Microsoft 提供的 Windows API 中的“ChangeDisplaySettingsEX”函数正在返回错误显示模式 (DISP_CHANGE_BADMODE) 的返回码,因此我尝试应用该标志以允许“不安全”显示模式(因为我是一个反叛者。是的,我将尝试不安全的显示模式,注意:我们正在处理一个糟糕的**s)。应用该标志会导致函数返回错误标志参数 (DISP_CHANGE_BADFLAGS)。

经过进一步调查,显然 Windows XP 本身无法旋转显示器。然而,我们可以找到一种方法来做到这一点,但它是通过英特尔 (IEGD) 提供的单独驱动程序。对我来说,这意味着两件事:第一是没有办法通过 Windows 以非编程方式做到这一点,也没有办法使用 Windows API 调用来做到这一点。第二个是,如果英特尔找到了一种方法来编写驱动程序来实现它,那么一定有某种方法来实现它。

我会在下面放一些代码,对不起,这有点 tl;dr。 tl;dr 版本可能只是帖子的标题,我想......

...

    else if( key == "Rotation" ) 
                QString rotationsStr = value.toString();
                QStringList rotations = rotationsStr.split(",", QString::SkipEmptyParts);

                for( int i = 0; i < currentLayout.size(); i++)
                    WinMon tempMon = currentLayout.at(i);

                    DWORD dwTemp = tempMon.dm.dmPelsHeight;
                    if(rotations.size() > 1) 
                        switch( rotations.at(i).toInt(&ok, 10) )
                        
                        case 0:     // Rotate 0 degrees

                            tempMon.dm.dmFields = DM_DISPLAYORIENTATION;
                            if(currentLayout.at(i).dm.dmDisplayOrientation == DMDO_90 ||
                               currentLayout.at(i).dm.dmDisplayOrientation == DMDO_270)
                                tempMon.dm.dmPelsHeight= tempMon.dm.dmPelsWidth;
                                tempMon.dm.dmPelsWidth = dwTemp;
                                tempMon.dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
                            
                            tempMon.dm.dmDisplayOrientation = DMDO_DEFAULT;
                            break;

                        case 1:     // Rotate 90 degrees

                            tempMon.dm.dmFields = DM_DISPLAYORIENTATION;
                            if(currentLayout.at(i).dm.dmDisplayOrientation == DMDO_DEFAULT ||
                               currentLayout.at(i).dm.dmDisplayOrientation == DMDO_180)
                                tempMon.dm.dmPelsHeight= tempMon.dm.dmPelsWidth;
                                tempMon.dm.dmPelsWidth = dwTemp;
                                tempMon.dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
                            
                            tempMon.dm.dmDisplayOrientation = DMDO_90;
                            break;

                        case 2:     // Rotate 180 degrees

                            tempMon.dm.dmFields = DM_DISPLAYORIENTATION;
                            if(currentLayout.at(i).dm.dmDisplayOrientation == DMDO_90 ||
                               currentLayout.at(i).dm.dmDisplayOrientation == DMDO_270)
                                tempMon.dm.dmPelsHeight= tempMon.dm.dmPelsWidth;
                                tempMon.dm.dmPelsWidth = dwTemp;
                                tempMon.dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
                            
                            tempMon.dm.dmDisplayOrientation = DMDO_180;
                            break;

                        case 3:     // Rotate 270 degrees

                            tempMon.dm.dmFields = DM_DISPLAYORIENTATION;
                            if(currentLayout.at(i).dm.dmDisplayOrientation == DMDO_DEFAULT ||
                               currentLayout.at(i).dm.dmDisplayOrientation == DMDO_180)
                                tempMon.dm.dmPelsHeight= tempMon.dm.dmPelsWidth;
                                tempMon.dm.dmPelsWidth = dwTemp;
                                tempMon.dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
                            
                            tempMon.dm.dmDisplayOrientation = DMDO_270;
                            break;

                        
                    

                    else
                    
                        switch( rotations.at(0).toInt(&ok, 10) ) 

                        case 0:     // Rotate 0 degrees

                            tempMon.dm.dmFields = DM_DISPLAYORIENTATION;
                            if(currentLayout.at(i).dm.dmDisplayOrientation == DMDO_90 ||
                               currentLayout.at(i).dm.dmDisplayOrientation == DMDO_270)
                                tempMon.dm.dmPelsHeight= tempMon.dm.dmPelsWidth;
                                tempMon.dm.dmPelsWidth = dwTemp;
                                tempMon.dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
                            
                            tempMon.dm.dmDisplayOrientation = DMDO_DEFAULT;
                            break;

                        case 1:     // Rotate 90 degrees

                            tempMon.dm.dmFields = DM_DISPLAYORIENTATION;
                            if(currentLayout.at(i).dm.dmDisplayOrientation == DMDO_DEFAULT ||
                               currentLayout.at(i).dm.dmDisplayOrientation == DMDO_180)
                                tempMon.dm.dmPelsHeight= tempMon.dm.dmPelsWidth;
                                tempMon.dm.dmPelsWidth = dwTemp;
                                tempMon.dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
                            
                            tempMon.dm.dmDisplayOrientation = DMDO_90;
                            break;

                        case 2:     // Rotate 180 degrees

                            tempMon.dm.dmFields = DM_DISPLAYORIENTATION;
                            if(currentLayout.at(i).dm.dmDisplayOrientation == DMDO_90 ||
                               currentLayout.at(i).dm.dmDisplayOrientation == DMDO_270)
                                tempMon.dm.dmPelsHeight= tempMon.dm.dmPelsWidth;
                                tempMon.dm.dmPelsWidth = dwTemp;
                                tempMon.dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
                            
                            tempMon.dm.dmDisplayOrientation = DMDO_180;
                            break;

                        case 3:     // Rotate 270 degrees

                            tempMon.dm.dmFields = DM_DISPLAYORIENTATION;
                            if(currentLayout.at(i).dm.dmDisplayOrientation == DMDO_DEFAULT ||
                               currentLayout.at(i).dm.dmDisplayOrientation == DMDO_180)
                                tempMon.dm.dmPelsHeight = tempMon.dm.dmPelsWidth;
                                tempMon.dm.dmPelsWidth = dwTemp;
                                tempMon.dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
                            
                            tempMon.dm.dmDisplayOrientation = DMDO_270;
                            break;
                        
                    

                    currentLayout.replace(i, tempMon);
                
            

我们应用以下设置:

     long returnCode;

    for( int i=0; i < currentLayout.size(); i++ )
        WinMon myMon = currentLayout.at(i);

        returnCode = ChangeDisplaySettingsEx(myMon.name.utf16(),(DEVMODE*)&(myMon.dm), NULL, CDS_UPDATEREGISTRY|CDS_NORESET, NULL);
        if( returnCode != DISP_CHANGE_SUCCESSFUL )
        
            qWarning() << "Failed to change display " << i;
            qWarning() << "Return Code:  " << returnCode;

            qWarning() << " ";
            qWarning() << "DISP_CHANGE_SUCCESSFUL  : " << DISP_CHANGE_SUCCESSFUL;
            qWarning() << "DISP_CHANGE_BADDUALVIEW : " << DISP_CHANGE_BADDUALVIEW;
            qWarning() << "DISP_CHANGE_BADFLAGS    : " << DISP_CHANGE_BADFLAGS;
            qWarning() << "DISP_CHANGE_BADMODE     : " << DISP_CHANGE_BADMODE;
            qWarning() << "DISP_CHANGE_BADPARAM    : " << DISP_CHANGE_BADPARAM;
            qWarning() << "DISP_CHANGE_FAILED      : " << DISP_CHANGE_FAILED;
            qWarning() << "DISP_CHANGE_NOTUPDATED  : " << DISP_CHANGE_NOTUPDATED;
            qWarning() << "DISP_CHANGE_RESTART     : " << DISP_CHANGE_RESTART;
            qWarning() << " ";
            qWarning() << "Again, your return value was: " << returnCode;
            return false;
        
    

    ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
    return true;

所以特别是底部的代码写得不是特别优雅,但那是因为我们在清理它之前试图掌握如何去做。

那么,有人知道如何在 Windows XP 上以这种方式旋转显示器吗?

【问题讨论】:

【参考方案1】:

XP 中的整个显示和监视器内容并不像 WDDM 中那样清晰。虽然您可以枚举“附加”到显示器的监视器,但不能通过调用 ChangeDisplaySettingsEx 来更改监视器的模式。要更改显示模式,请使用显示调用 CDSE,例如“\\.\Display1”或类似的东西。我在以前的生活中花了很多时间在 XP 上玩这些功能,但我认为你不能用它们做你想做的事情。

据我所知,屏幕旋转是XP下显示驱动程序的一个实现细节,在用户空间没有标准的方法来做到这一点。当您调用 EnumDisplaySettings 时,某些 Intel 驱动程序会列出纵向模式。通过将显示设置为其中一种模式,您最终会得到一个旋转的屏幕。

简而言之,没有针对所有显卡供应商执行此操作的标准方法。但是您也许可以通过他们的实用程序应用程序执行相同的操作来达到此效果。

在 Windows 7 下,旋转和镜像由操作系统提供。 This link 应该为您提供有关在 Win7 下如何工作的详细信息。恐怕没有与 XP 相同的东西。

【讨论】:

嘿,谢谢你的回复,这就是我害怕的。我知道你提到它内置在 Windows 7 的操作系统中,我可以确认这是真的。就像我说的,我们在我们的 Windows 7 软件版本中完全实现了这个功能。这是 MSDN API 令人沮丧的事情。他们列出了他们说可以实现这些效果的函数和结构,但他们不能。那好吧。我想如果没有办法在 Windows XP 中对所有显卡/处理器及其各自的驱动程序通用,那么我可能应该继续前进。再次感谢!

以上是关于在 Windows XP 中以编程方式旋转显示? (C++/Qt 和 WindowsAPI)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中以编程方式旋转一组按钮?

有没有办法在多 GPU 环境中以编程方式选择渲染 GPU? (视窗)

如何在 Roblox 第一人称视图中以编程方式调整旋转量?

在 Windows 上的 Java 中以编程方式创建 wifi 对等连接? [关闭]

如何在 Windows 10 及更高版本中以编程方式刷新任务栏?

iOS - 在 Swift 3 中以编程方式删除和激活新约束时布局损坏