Windows分辨率及缩放倍数
// WindowsSetting.cpp : This file contains the 'main' function. Program execution begins and ends there. // #include <iostream> #include <shobjidl_core.h> #include <vector> #include <string> class DpiApi { const std::vector<DEVICE_SCALE_FACTOR> DpiVals = { SCALE_100_PERCENT , SCALE_120_PERCENT, SCALE_125_PERCENT, SCALE_140_PERCENT, SCALE_150_PERCENT, SCALE_160_PERCENT, SCALE_175_PERCENT, SCALE_180_PERCENT, SCALE_200_PERCENT, SCALE_225_PERCENT, SCALE_250_PERCENT, SCALE_300_PERCENT, SCALE_350_PERCENT, SCALE_400_PERCENT, SCALE_450_PERCENT, SCALE_500_PERCENT, }; public: /* * @brief : Use QueryDisplayConfig() to get paths, and modes. * @param[out] pathsV : reference to a vector which will contain paths * @param[out] modesV : reference to a vector which will contain modes * @param[in] flags : determines the kind of paths to retrieve (only active paths by default) * return : false in case of failure, else true */ bool GetPathModeInfoList(std::vector<DISPLAYCONFIG_PATH_INFO>& vPathInfo, std::vector<DISPLAYCONFIG_MODE_INFO>& vModeInfo, int flags = QDC_ONLY_ACTIVE_PATHS) { UINT32 numPaths = 0, numModes = 0; LONG lStatus = GetDisplayConfigBufferSizes(flags, &numPaths, &numModes); if (lStatus != ERROR_SUCCESS) { return false; } vPathInfo.resize(numPaths, {}); vModeInfo.resize(numModes, {}); lStatus = ::QueryDisplayConfig(flags, &numPaths, vPathInfo.data(), &numModes, vModeInfo.data(), NULL); if (lStatus != ERROR_SUCCESS) { return false; } return true; } //out own enum, similar to DISPLAYCONFIG_DEVICE_INFO_TYPE enum in wingdi.h enum class DISPLAYCONFIG_DEVICE_INFO_TYPE_CUSTOM : int { DISPLAYCONFIG_DEVICE_INFO_GET_DPI_SCALE = -3, //returns min, max, suggested, and currently applied DPI scaling values. DISPLAYCONFIG_DEVICE_INFO_SET_DPI_SCALE = -4, //set current dpi scaling value for a display }; /* * struct DISPLAYCONFIG_SOURCE_DPI_SCALE_GET * @brief used to fetch min, max, suggested, and currently applied DPI scaling values. * All values are relative to the recommended DPI scaling value * Note that DPI scaling is a property of the source, and not of target. */ struct DISPLAYCONFIG_SOURCE_DPI_SCALE_GET { DISPLAYCONFIG_DEVICE_INFO_HEADER header; /* * @brief min value of DPI scaling is always 100, minScaleRel gives no. of steps down from recommended scaling * eg. if minScaleRel is -3 => 100 is 3 steps down from recommended scaling => recommended scaling is 175% */ std::int32_t minScaleRel; /* * @brief currently applied DPI scaling value wrt the recommended value. eg. if recommended value is 175%, * => if curScaleRel == 0 the current scaling is 175%, if curScaleRel == -1, then current scale is 150% */ std::int32_t curScaleRel; /* * @brief maximum supported DPI scaling wrt recommended value */ std::int32_t maxScaleRel; }; /* * struct DISPLAYCONFIG_SOURCE_DPI_SCALE_SET * @brief set DPI scaling value of a source * Note that DPI scaling is a property of the source, and not of target. */ struct DISPLAYCONFIG_SOURCE_DPI_SCALE_SET { DISPLAYCONFIG_DEVICE_INFO_HEADER header; /* * @brief The value we want to set. The value should be relative to the recommended DPI scaling value of source. * eg. if scaleRel == 1, and recommended value is 175% => we are trying to set 200% scaling for the source */ int32_t scaleRel; }; /* * struct DPIScalingInfo * @brief DPI info about a source * mininum : minumum DPI scaling in terms of percentage supported by source. Will always be 100%. * maximum : maximum DPI scaling in terms of percentage supported by source. eg. 100%, 150%, etc. * current : currently applied DPI scaling value * recommended : DPI scaling value reommended by OS. OS takes resolution, physical size, and expected viewing distance * into account while calculating this, however exact formula is not known, hence must be retrieved from OS * For a system in which user has not explicitly changed DPI, current should eqaul recommended. * bInitDone : If true, it means that the members of the struct contain values, as fetched from OS, and not the default * ones given while object creation. */ struct DPIScalingInfo { UINT32 mininum = 100; UINT32 maximum = 100; UINT32 current = 100; UINT32 recommended = 100; bool bInitDone = false; }; bool GetDPIScalingInfo(struct DPIScalingInfo& dpiInfo, LUID adapterID, UINT32 sourceID) { DISPLAYCONFIG_SOURCE_DPI_SCALE_GET requestPacket = {}; requestPacket.header.type = (DISPLAYCONFIG_DEVICE_INFO_TYPE)DISPLAYCONFIG_DEVICE_INFO_TYPE_CUSTOM::DISPLAYCONFIG_DEVICE_INFO_GET_DPI_SCALE; requestPacket.header.size = sizeof(requestPacket); if(0x20 != sizeof(requestPacket)) return false;//if this fails => OS has changed somthing, and our reverse enginnering knowledge about the API is outdated requestPacket.header.adapterId = adapterID; requestPacket.header.id = sourceID; auto res = ::DisplayConfigGetDeviceInfo(&requestPacket.header); if (ERROR_SUCCESS == res) {//success if (requestPacket.curScaleRel < requestPacket.minScaleRel) { requestPacket.curScaleRel = requestPacket.minScaleRel; } else if (requestPacket.curScaleRel > requestPacket.maxScaleRel) { requestPacket.curScaleRel = requestPacket.maxScaleRel; } std::int32_t minAbs = abs((int)requestPacket.minScaleRel); if ((int)DpiVals.size() >= (int)(minAbs + requestPacket.maxScaleRel + 1)) {//all ok dpiInfo.current = DpiVals[minAbs + requestPacket.curScaleRel]; dpiInfo.recommended = DpiVals[minAbs]; dpiInfo.maximum = DpiVals[minAbs + requestPacket.maxScaleRel]; dpiInfo.bInitDone = true; return true; } else { //Error! Probably DpiVals array is outdated return false; } } else { //DisplayConfigGetDeviceInfo() failed return false; } return false; } bool SetDPIScaling(LUID adapterID, UINT32 sourceID, UINT32 dpiPercentToSet) { DPIScalingInfo dPIScalingInfo = {}; bool bRet = GetDPIScalingInfo(dPIScalingInfo, adapterID, sourceID); if (bRet == false) { return false; } if (dpiPercentToSet == dPIScalingInfo.current) { return true; } if (dpiPercentToSet < dPIScalingInfo.mininum) { dpiPercentToSet = dPIScalingInfo.mininum; } else if (dpiPercentToSet > dPIScalingInfo.maximum) { dpiPercentToSet = dPIScalingInfo.maximum; } int idx1 = -1, idx2 = -1; int i = 0; for (const auto& val : DpiVals) { if (val == dpiPercentToSet) { idx1 = i; } if (val == dPIScalingInfo.recommended) { idx2 = i; } i++; } if ((idx1 == -1) || (idx2 == -1)) { //Error cannot find dpi value return false; } int dpiRelativeVal = idx1 - idx2; DISPLAYCONFIG_SOURCE_DPI_SCALE_SET setPacket = {}; setPacket.header.adapterId = adapterID; setPacket.header.id = sourceID; setPacket.header.size = sizeof(setPacket); if(0x18 != sizeof(setPacket)) return false;//if this fails => OS has changed somthing, and our reverse enginnering knowledge about the API is outdated setPacket.header.type = (DISPLAYCONFIG_DEVICE_INFO_TYPE)DISPLAYCONFIG_DEVICE_INFO_TYPE_CUSTOM::DISPLAYCONFIG_DEVICE_INFO_SET_DPI_SCALE; setPacket.scaleRel = (UINT32)dpiRelativeVal; auto res = ::DisplayConfigSetDeviceInfo(&setPacket.header); if (ERROR_SUCCESS == res) { return true; } else { return false; } return true; } //Get default DPI scaling percentage.The OS recommented value. DEVICE_SCALE_FACTOR GetDPIScalingInfoPrimary() { int dpi = 0; BOOL bRet = ::SystemParametersInfoW(SPI_GETLOGICALDPIOVERRIDE, 0, (LPVOID)&dpi, 1); if (bRet == TRUE) { return DpiVals[dpi * -1]; } return DEVICE_SCALE_FACTOR_INVALID; } bool SetDpiScalingPrimary(DEVICE_SCALE_FACTOR newDeviceScaleFactor) { bool bRet = FALSE; DEVICE_SCALE_FACTOR deviceScaleFactor = GetDPIScalingInfoPrimary(); if (deviceScaleFactor != DEVICE_SCALE_FACTOR_INVALID) { int index = 0, recIndex = 0, setIndex = 0; for (const auto& scale : DpiVals) { if (deviceScaleFactor == scale) { recIndex = index; } if (newDeviceScaleFactor == scale) { setIndex = index; } index++; } int relativeIndex = setIndex - recIndex; bRet = (::SystemParametersInfoW(SPI_SETLOGICALDPIOVERRIDE, relativeIndex, (LPVOID)0, 1) == TRUE); } return bRet; } bool ModifyWindows() { //检测当前分辨率 int Width = GetSystemMetrics(SM_CXSCREEN); int Height = GetSystemMetrics(SM_CYSCREEN); DEVMODE lpDevMode0; lpDevMode0.dmBitsPerPel = 32; lpDevMode0.dmPelsWidth = Width; lpDevMode0.dmPelsHeight = Height; lpDevMode0.dmSize = sizeof(lpDevMode0); lpDevMode0.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; //修改 DEVMODE lpDevMode; lpDevMode.dmBitsPerPel = 32; lpDevMode.dmPelsWidth = 1024; lpDevMode.dmPelsHeight = 768; lpDevMode.dmSize = sizeof(lpDevMode); lpDevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; LONG result = 0; result = ::ChangeDisplaySettingsW(&lpDevMode, 0); if (result == DISP_CHANGE_SUCCESSFUL) { ::ChangeDisplaySettingsW(&lpDevMode, CDS_UPDATEREGISTRY); //使用CDS_UPDATEREGISTRY表示次修改是持久的,并在注册表中写入了相关的数据 ::ChangeDisplaySettingsW(&lpDevMode0, CDS_UPDATEREGISTRY); } else { //MessageBox("修改失败,恢复原有设置!"); ::ChangeDisplaySettingsW(NULL, 0); } } INT GetCurrentScaleFactor() { // 获取窗口当前显示的监视器 // 使用桌面的句柄. HWND hWnd = GetDesktopWindow(); HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); // 获取监视器逻辑宽度与高度 MONITORINFOEXW miex = {}; miex.cbSize = sizeof(miex); ::GetMonitorInfoW(hMonitor, &miex); int cxLogical = (miex.rcMonitor.right - miex.rcMonitor.left); int cyLogical = (miex.rcMonitor.bottom - miex.rcMonitor.top); // 获取监视器物理宽度与高度 DEVMODE dm; dm.dmSize = sizeof(dm); dm.dmDriverExtra = 0; ::EnumDisplaySettingsW(miex.szDevice, ENUM_CURRENT_SETTINGS, &dm); int cxPhysical = dm.dmPelsWidth; int cyPhysical = dm.dmPelsHeight; // 缩放比例计算 实际上使用任何一个即可 double horzScale = ((double)cxPhysical / (double)cxLogical); double vertScale = ((double)cyPhysical / (double)cyLogical); return horzScale * 100; } std::string GetCurrentResolution() { int width = GetSystemMetrics(SM_CXSCREEN); int height = GetSystemMetrics(SM_CYSCREEN); return std::to_string(width) + "x" + std::to_string(height); } }; int main(int argc, char ** argv) { std::cout << "Hello World!\n"; std::cout << DpiApi().GetCurrentScaleFactor() << std::endl; std::cout << DpiApi().GetCurrentResolution() << std::endl; return 0; std::vector<DISPLAYCONFIG_PATH_INFO> vPathInfo; std::vector<DISPLAYCONFIG_MODE_INFO> vModeInfo; DpiApi().GetPathModeInfoList(vPathInfo, vModeInfo); DpiApi().SetDpiScalingPrimary(SCALE_100_PERCENT); return 0; } // Run program: Ctrl + F5 or Debug > Start Without Debugging menu // Debug program: F5 or Debug > Start Debugging menu // Tips for Getting Started: // 1. Use the Solution Explorer window to add/manage files // 2. Use the Team Explorer window to connect to source control // 3. Use the Output window to see build output and other messages // 4. Use the Error List window to view errors // 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project // 6. In the future, to open this project again, go to File > Open > Project and select the .sln file
收藏的用户(0)
X
正在加载信息~
2
最新回复 (0)