C#を使用してプログラムでWindows10の表示スケーリングを変更する方法を見つけようとしています。
また、ユーザーの画面に解像度/スケーリングを自動的に変更させるアプリケーションを作成しようとしているのではありません。それは私がテストのためにしばしばしなければならないこととして、トレイからスケールを切り替えることができるようにするための単なるツールです。したがって、このアクションのために意図的に設計されています。
そのため、ユーザーが表示されている公式ダイアログを介して手動でこれを行ったときに、どのレジストリエントリ(HKEY_CURRENT_USER\Control Panel\Desktop)が設定されているかを追跡できました。未満:
ただし、明らかにレジストリを直接操作するということは、有効にするにはマシンを再起動する必要があることを意味します。
Pinvokeを使用して画面の解像度を変更できることを認識しています: ディスプレイの解像度の設定
特定の画面でこの「%」を変更する方法もあるのでしょうか。つまり、上の画面に150%と表示されているので、プログラムで100〜500%の全範囲で変更できるようにしたいと思います。
これは、システム設定アプリ(没入型コントロールパネル)で行ったRnDからの私の学習です。 (この学習から作成した単純なC++ APIについては、他の回答を参照してください https://stackoverflow.com/a/58066736/981766 )
WinDbgを使用して、このアプリからの呼び出しを実行しました。特定の機能が実行されるとすぐに--_user32!_imp_NtUserDisplayConfigSetDeviceInfo
_新しいDPI設定が私のマシンで有効になることがわかりました。
この関数にブレークポイントを設定することはできませんでしたが、DisplayConfigSetDeviceInfo()
_(bp user32!DisplayConfigSetDeviceInfo)
_にブレークポイントを設定することはできました。
DisplayConfigSetDeviceInfo( msdn link )はパブリック関数ですが、設定アプリが文書化されていないパラメーターを送信しているようです。デバッグセッション中に見つけたパラメータは次のとおりです。
_((user32!DISPLAYCONFIG_DEVICE_INFO_HEADER *)0x55df8fba30) : 0x55df8fba30 [Type: DISPLAYCONFIG_DEVICE_INFO_HEADER *]
[+0x000] type : -4 [Type: DISPLAYCONFIG_DEVICE_INFO_TYPE]
[+0x004] size : 0x18 [Type: unsigned int]
[+0x008] adapterId [Type: _LUID]
[+0x010] id : 0x0 [Type: unsigned int]
0:003> dx -r1 (*((user32!_LUID *)0x55df8fba38))
(*((user32!_LUID *)0x55df8fba38)) [Type: _LUID]
[+0x000] LowPart : 0xcbae [Type: unsigned long]
[+0x004] HighPart : 0 [Type: long]
_
基本的に、DisplayConfigSetDeviceInfo()
に渡される_DISPLAYCONFIG_DEVICE_INFO_HEADER
_構造体のメンバーの値は次のとおりです。
_type : -4
size : 0x18
adapterId : LowPart : 0xcbae HighPart :0
_
Wingdi.hで定義されている列挙型は次のとおりです。
_typedef enum
{
DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4,
DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6,
DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7,
DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8,
DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9,
DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10,
DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xFFFFFFFF
} DISPLAYCONFIG_DEVICE_INFO_TYPE;
_
設定アプリがタイプに-4を送信しようとしている間、列挙型に負の値がないことがわかります。
これを完全にリバースエンジニアリングできれば、モニターのDPIを設定するためのAPIが機能します。
Microsoftが独自のアプリ用に他の人が使用できない特別なAPIを持っていることは、信じられないほど不公平に思えます。
私の理論を検証するために、パラメーターとしてDisplayConfigSetDeviceInfo()
に送信される_DISPLAYCONFIG_DEVICE_INFO_HEADER
_構造体のバイトを(WinDbgを使用して)コピーしました。システム設定アプリからDPIスケーリングを変更した場合(150%DPIスケーリングを設定してみました)。
次に、これらのバイト(24バイト-0x18バイト)をDisplayConfigSetDeviceInfo()
に送信する簡単なCプログラムを作成しました。
次に、DPIスケーリングを100%に戻し、コードを実行しました。案の定、DPIスケーリングはコードの実行時に変更されました!!!
_BYTE buf[] = { 0xFC,0xFF,0xFF,0xFF,0x18,0x00,0x00,0x00,0xAE,0xCB,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00 };
DISPLAYCONFIG_DEVICE_INFO_HEADER* packet = (DISPLAYCONFIG_DEVICE_INFO_HEADER*)buf;
DisplayConfigSetDeviceInfo(packet);
_
LUIDと同じコードが機能しない場合があり、システム上の表示を指すidパラメーターが異なることに注意してください(LUIDは通常GPUに使用され、idはソースID、ターゲットID、またはその他のIDである可能性があります) 、このパラメーターはDISPLAYCONFIG_DEVICE_INFO_HEADER :: typeに依存します。
ここで、これらの24バイトの意味を理解する必要があります。
175%dpiのスケーリングを設定しようとしたときに取得したバイトは次のとおりです。
_BYTE buf[] = { 0xFC,0xFF,0xFF,0xFF,0x18,0x00,0x00,0x00,0xAE,0xCB,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00 };
_
2バイトのバッファを比較すると、次の結論を導き出すことができます。
残っているのは、ディスプレイの推奨DPIスケーリング値を取得する方法を理解することだけです。これにより、次の形式のAPIを記述できるようになります-SetDPIScaling(monitor_LUID, DPIScale_percent)
。
@Dodgeの回答に記載されているレジストリエントリを確認すると、これらの整数がDWORDとして格納されていることがわかります。私のコンピュータはリトルエンディアンであるため、最後の4バイト(バイト21〜24)が使用されていることを意味します。したがって、負の数を送信するには、DWORDの2の補数を使用し、バイトをリトルエンディアンとして書き込む必要があります。
また、WindowsがDPIスケーリング値を格納するためのモニターIDを生成する方法についても調査しています。どのモニターでも、ユーザーが選択したDPIスケーリング値は次の場所に保存されます。
_HKEY_CURRENT_USER\Control Panel\Desktop\PerMonitorSettings\
*MonitorID*
_
私のマシンに接続されているDellディスプレイの場合、モニターIDは_DELA0BC9DRXV68A0LWL_21_07E0_33^7457214C9330EFC0300669BF736A5297
_でした。モニターIDの構造がわかりました。私は4つの異なるモニターで私の理論を検証しました。
デルのディスプレイ(_HKEY_CURRENT_USER\Control Panel\Desktop\PerMonitorSettings\ DELA0BC9DRXV68A0LWL_21_07E0_33^7457214C9330EFC0300669BF736A5297
_に保存されているdpiスケーリング)の場合、次のようになります(画像を追加して申し訳ありませんが、情報を簡潔に表現する方法がわかりませんでした)。
基本的に、モニターIDを作成するためにEDIDから必要なデータは次のとおりです。
@@@
_000
_0x0A
_)で終了します。00-00-00-FF-00-39-44-52-58-56-36-38-41-30-4C-57-4C-0A
_でした。シリアル番号は12バイトで、改行(_0x0A
_)で終了することに注意してください。 _39-44-52-58-56-36-38-41-30-4C-57-4C
_をASCIIに変換すると、_9DRXV68A0LWL
_が得られます。0
_が使用されます。00
_0000
_EDIDの最初の128バイトのみが必要であることに注意してください。
モニターIDの作成に必要なデータの一部が存在しない場合、OSはフォールバックを使用します。 Windows 10マシンで観察したように、モニターIDの作成に必要な各データのフォールバックは上記のリストに示されています。デルのディスプレイのEDIDを手動で編集しました( link1link2 、 link -注意してください-リンク3で提案されている方法は、システムに損傷を与える可能性があります。続行してください。確かな場合のみ; Link1が最も推奨されます)上記の6つの項目すべてを削除するには、OSが作成したモニターID(MD5サフィックスなし)は_@@@0000810309452_00_0000_85
_でしたが、バイト12のシリアル番号も削除しました。構築されたIDは_@@@00000_00_0000_A4
_でした。
DPIスケーリングはソースのプロパティであり、ターゲットのプロパティではないため、DisplayConfigGetDeviceInfo()
およびDisplayConfigSetDeviceInfo()
で使用されるidパラメーターはソースIDであり、ターゲットIDではありません。
上記で提案されたレジストリ方法は、ほとんどの場合正常に機能するはずですが、2つの欠点があります。 1つは、システム設定アプリと同等ではないということです(設定が行われる時間に関して)。次に、まれに(これ以上再現できない)、OSによって生成されたモニターID文字列がわずかに異なることがわかりました。上の写真に示されているコンポーネントが多く含まれています。
システム設定アプリとまったく同じ方法でDPIスケーリングを取得/設定するために使用できるAPIを正常に作成しました。これは私が解決策を見つけるために取ったアプローチに関するものなので、新しい回答を投稿します。
まったく同じものを検索しているときに、私はあなたの質問を見つけ、可能な解決策を見つけました。
この%値のモニターごとの切り替えは、レジストリのComputer\HKEY_CURRENT_USER\Control Panel\Desktop\PerMonitorSettings\*monitorId*\DpiValue
にあることがわかりました。値の意味は画面(サイズとdpi)によって異なるようです。詳細については、 このredditの投稿 を参照してください。
私の24 "1080p画面の場合、0
は100%を意味し、1
は125%を意味します。 このTechnetの記事 は値を少し説明しているようです。
残念ながら、レジストリ値を変更するだけでは不十分です。ただし、レジストリへの書き込み後に解像度を変更することで、dpiを更新できます。
次のコードは、dpiを設定してから、解像度を低くしたり高くしたりして、dpiの更新をトリガーします。
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace SetDpiScale
{
public partial class Form1 : Form
{
public enum DMDO
{
DEFAULT = 0,
D90 = 1,
D180 = 2,
D270 = 3
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct DEVMODE
{
public const int DM_PELSWIDTH = 0x80000;
public const int DM_PELSHEIGHT = 0x100000;
private const int CCHDEVICENAME = 32;
private const int CCHFORMNAME = 32;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
public int dmPositionX;
public int dmPositionY;
public DMDO dmDisplayOrientation;
public int dmDisplayFixedOutput;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
public string dmFormName;
public short dmLogPixels;
public int dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
public int dmICMMethod;
public int dmICMIntent;
public int dmMediaType;
public int dmDitherType;
public int dmReserved1;
public int dmReserved2;
public int dmPanningWidth;
public int dmPanningHeight;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int ChangeDisplaySettings([In] ref DEVMODE lpDevMode, int dwFlags);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ChangeDPI(0); // 100%
}
private void button2_Click(object sender, EventArgs e)
{
ChangeDPI(1); // 125%
}
void ChangeDPI(int dpi)
{
RegistryKey key = Registry.CurrentUser.OpenSubKey("Control Panel", true);
key = key.OpenSubKey("Desktop", true);
key = key.OpenSubKey("PerMonitorSettings", true);
key = key.OpenSubKey("*monitor id where to change the dpi*", true); // my second monitor here
key.SetValue("DpiValue", dpi);
SetResolution(1920, 1080); // this sets the resolution on primary screen
SetResolution(2560, 1440); // returning back to my primary screens default resolution
}
private static void SetResolution(int w, int h)
{
long RetVal = 0;
DEVMODE dm = new DEVMODE();
dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
dm.dmPelsWidth = w;
dm.dmPelsHeight = h;
dm.dmFields = DEVMODE.DM_PELSWIDTH | DEVMODE.DM_PELSHEIGHT;
RetVal = ChangeDisplaySettings(ref dm, 0);
}
}
}
SahilSinghsの答えに加えて。 MonitorIDは、次の場所にsubkeys
として配置できます。HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\ScaleFactors
これが@SahilSinghに基づく私のコードです:
C++ APIをラップするDLLプロジェクト:
stdafx.h:
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
// reference additional headers your program requires here
#ifdef __cplusplus
extern "C" {
#endif
extern __declspec(dllexport) void PrintDpiInfo();
extern __declspec(dllexport) void SetDPIScaling(INT32 adapterIDHigh, UINT32 adapterIDlow, UINT32 sourceID, UINT32 dpiPercentToSet);
extern __declspec(dllexport) void RestoreDPIScaling();
#ifdef __cplusplus
}
#endif
DpiHelper.cpp:
// DpiHelper.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "DpiHelper.h"
#include <memory>
#include <cassert>
#include <string>
#include <map>
bool DpiHelper::GetPathsAndModes(std::vector<DISPLAYCONFIG_PATH_INFO>& pathsV, std::vector<DISPLAYCONFIG_MODE_INFO>& modesV, int flags)
{
UINT32 numPaths = 0, numModes = 0;
auto status = GetDisplayConfigBufferSizes(flags, &numPaths, &numModes);
if (ERROR_SUCCESS != status)
{
return false;
}
std::unique_ptr<DISPLAYCONFIG_PATH_INFO[]> paths(new DISPLAYCONFIG_PATH_INFO[numPaths]);
std::unique_ptr<DISPLAYCONFIG_MODE_INFO[]> modes(new DISPLAYCONFIG_MODE_INFO[numModes]);
status = QueryDisplayConfig(flags, &numPaths, paths.get(), &numModes, modes.get(), nullptr);
if (ERROR_SUCCESS != status)
{
return false;
}
for (unsigned int i = 0; i < numPaths; i++)
{
pathsV.Push_back(paths[i]);
}
for (unsigned int i = 0; i < numModes; i++)
{
modesV.Push_back(modes[i]);
}
return true;
}
DpiHelper::DpiHelper()
{
}
DpiHelper::~DpiHelper()
{
}
DpiHelper::DPIScalingInfo DpiHelper::GetDPIScalingInfo(LUID adapterID, UINT32 sourceID)
{
DPIScalingInfo dpiInfo = {};
DpiHelper::DISPLAYCONFIG_SOURCE_DPI_SCALE_GET requestPacket = {};
requestPacket.header.type = (DISPLAYCONFIG_DEVICE_INFO_TYPE)DpiHelper::DISPLAYCONFIG_DEVICE_INFO_TYPE_CUSTOM::DISPLAYCONFIG_DEVICE_INFO_GET_DPI_SCALE;
requestPacket.header.size = sizeof(requestPacket);
assert(0x20 == sizeof(requestPacket));//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 (DpiHelper::CountOf(DpiVals) >= (size_t)(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;
}
else
{
//Error! Probably DpiVals array is outdated
return dpiInfo;
}
}
else
{
//DisplayConfigGetDeviceInfo() failed
return dpiInfo;
}
return dpiInfo;
}
std::wstring GetTargetName(LUID adapterLUID, UINT32 sourceId)
{
std::vector<DISPLAYCONFIG_PATH_INFO> pathsV;
std::vector<DISPLAYCONFIG_MODE_INFO> modesV;
int flags = QDC_ONLY_ACTIVE_PATHS;
if (false == DpiHelper::GetPathsAndModes(pathsV, modesV, flags))
{
wprintf(L"DpiHelper::GetPathsAndModes() failed\r\n");
}
for (const auto& path : pathsV)
{
if (adapterLUID.LowPart == path.targetInfo.adapterId.LowPart
&& adapterLUID.HighPart == path.targetInfo.adapterId.HighPart
&& sourceId == path.sourceInfo.id)
{
DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName;
deviceName.header.size = sizeof(deviceName);
deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
deviceName.header.adapterId = adapterLUID;
deviceName.header.id = path.targetInfo.id;
if (ERROR_SUCCESS != DisplayConfigGetDeviceInfo(&deviceName.header))
{
wprintf(L"DisplayConfigGetDeviceInfo() failed\r\n");
}
else
{
std::wstring nameString = deviceName.monitorFriendlyDeviceName;
if (DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL == deviceName.outputTechnology)
{
nameString += L"(internal display)";
}
return nameString;
}
}
}
return L"N/A";
}
void printOne(LUID adapterLUID, UINT32 sourceID) {
wprintf(L"GPU=%ld.%u,Desktop_Index_In_GPU=%d,Monitor=%ls\r\n"
,adapterLUID.HighPart
, adapterLUID.LowPart
, sourceID
, GetTargetName(adapterLUID, sourceID).data());
}
bool DpiHelper::SetDPIScaling(LUID adapterID, UINT32 sourceID, UINT32 dpiPercentToSet)
{
wprintf(L"setting dpi scale to %d: ", dpiPercentToSet);
printOne(adapterID, sourceID);
DPIScalingInfo dPIScalingInfo = GetDPIScalingInfo(adapterID, sourceID);
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;
DpiHelper::DISPLAYCONFIG_SOURCE_DPI_SCALE_SET setPacket = {};
setPacket.header.adapterId = adapterID;
setPacket.header.id = sourceID;
setPacket.header.size = sizeof(setPacket);
assert(0x18 == sizeof(setPacket));//if this fails => OS has changed somthing, and our reverse enginnering knowledge about the API is outdated
setPacket.header.type = (DISPLAYCONFIG_DEVICE_INFO_TYPE)DpiHelper::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;
}
#define MAX_ID 10
LUID GpuId[MAX_ID];
UINT32 DesktopIndexInGpu[MAX_ID];
UINT32 oldDPI[MAX_ID];
void PrintDpiInfo() {
std::vector<DISPLAYCONFIG_PATH_INFO> pathsV;
std::vector<DISPLAYCONFIG_MODE_INFO> modesV;
int flags = QDC_ONLY_ACTIVE_PATHS;
if (false == DpiHelper::GetPathsAndModes(pathsV, modesV, flags))
{
wprintf(L"DpiHelper::GetPathsAndModes() failed");
}
int i = 0;
for (const auto& path : pathsV)
{
//get display name
auto adapterLUID = path.targetInfo.adapterId;
auto sourceID = path.sourceInfo.id;
std::wstring monitor_name = GetTargetName(adapterLUID, sourceID);
printOne(adapterLUID, sourceID);
DpiHelper::DPIScalingInfo dpiInfo = DpiHelper::GetDPIScalingInfo(adapterLUID, sourceID);
GpuId[i] = adapterLUID;
DesktopIndexInGpu[i] = sourceID;
oldDPI[i] = dpiInfo.current;
wprintf(L"Available DPI:\r\n");
int curdpi = 0;
for (const auto& dpi : DpiVals)
{
if ((dpi >= dpiInfo.mininum) && (dpi <= dpiInfo.maximum))
wprintf(L" %d\r\n",dpi);
}
wprintf(L" current DPI: %d\r\n",dpiInfo.current);
i++;
if (i >= MAX_ID) {
wprintf(L"To many desktops\r\n");
break;
}
}
}
void SetDPIScaling(INT32 adapterIDHigh, UINT32 adapterIDlow, UINT32 sourceID, UINT32 dpiPercentToSet) {
LUID adapterId;
adapterId.HighPart = adapterIDHigh;
adapterId.LowPart = adapterIDlow;
DpiHelper::SetDPIScaling(adapterId, sourceID, dpiPercentToSet);
}
void RestoreDPIScaling()
{
wprintf(L"Now restore DPI settings...\r\n");
for (int i = 0;i < MAX_ID;i++) {
if (GpuId[i].LowPart == 0 && GpuId[i].HighPart==0) break;
DpiHelper::SetDPIScaling(GpuId[i], DesktopIndexInGpu[i], oldDPI[i]);
}
}
DpiHelper.hは、参照されている回答と同じです。 VisualStudioでC++ Dllプロジェクトを作成し、上記のコードを追加/配置して、次のC#アプリケーションでdllを使用します。
C#コンソールアプリケーションコマンドラインパラメータに従ってDPIを設定し、任意のキーを押すとそれらを復元します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace DispSetEx
{
class Program
{
[DllImport("DpiHelper.dll")]
static public extern void PrintDpiInfo();
[DllImport("DpiHelper.dll")]
static public extern int SetDPIScaling(Int32 adapterIDHigh, UInt32 adapterIDlow, UInt32 sourceID, UInt32 dpiPercentToSet);
[DllImport("DpiHelper.dll")]
static public extern void RestoreDPIScaling();
static void Main(string[] args)
{
if ((args.Length % 3) != 0)
{
Console.WriteLine("wrong parameters");
return;
}
//print the DPI info, you need to set the command line parameters
//according to this
PrintDpiInfo();
//commandline parameters should be of groups of three
//each groups's tree paramters control a desktop's setting
//in each group:
//GPUIdhigh.GPUIdlow DesktopIndexInGPU DPIScalingValue
//for example:
// 0.1234 0 100 //set the DPI scaling to 100 for desktop 0 on GPU 0.1234
// 0.4567 0 125 //set the DPI scaling to 125 for desktop 0 on GPU 0.5678
// 0.4567 1 150 //set the DPI scaling to 150 for desktop 1 on GPU 0.5678
//in most cases GPUIdhigh is 0.
//you can use the monitor name to identify which is which easily
//you need to set the command line parameters according to the result of PrintDpiInfo
//e.g. you should only set the DPI scaling to a value that is supported by
//that desktop.
for (int i = 0; i < args.Length / 3; i++)
{
string[] sa = args[i * 3].Split(new char[] { '.' });
Int32 adapterHigh = Int32.Parse(sa[0]);
UInt32 adapterLow = UInt32.Parse(sa[1]);
UInt32 source = UInt32.Parse(args[i * 3 + 1]);
UInt32 dpiscale = UInt32.Parse(args[i * 3 + 2]);
SetDPIScaling(adapterHigh, adapterLow, source,dpiscale);
}
Console.WriteLine("Press any key to resotre the settings...");
Console.ReadKey();
RestoreDPIScaling();
}
}
}