ディスプレイの拡大率の取得

解決


 2022-08-15 14:09:42  No: 150356  IP: [192.*.*.*]

こんばんはです。win10&D7で拡大率?の100%、125%、150%を取得するには
どのような手法になるでしょうか?

ここと同じ事をD7で行いたいと思っています。
https://okwave.jp/qa/q8972028.html

下記が参考になるかなと思ったのですが
https://www.petitmonte.com/bbs/answers?question_id=8212

レジストリは
HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics\AppliedDPI は144になっているのですが、
コントロールパネルで変更しても、ここの値に反映されないようです。

編集 削除
Mr.XRAY  2022-08-15 23:35:27  No: 150357  IP: [192.*.*.*]

> コントロールパネルで変更しても、ここの値に反映されないようです。
> AppliedDPI は ( 以下,略 )

DPI は,私が知る限りでは拡大率のことではありません.

[ dpi - Wikipedia ]
https://ja.wikipedia.org/wiki/Dpi

procedure TForm1.Button1Click(Sender: TObject);
var
  LValue : integer;
begin
  LValue := Trunc(144 / USER_DEFAULT_SCREEN_DPI * 100.0);
  ShowMessage(IntToStr(LValue));
end;

編集 削除
 2022-08-16 03:08:31  No: 150358  IP: [192.*.*.*]

お返事ありがとうございます。

>DPI は,私が知る限りでは拡大率のことではありません.

たぶん、回答いただいた物のUSER_DEFAULT_SCREEN_DPIは96を入れると150が返るので
環境の値を入れろと言うことだと思いますが、その場合だとUSER_DEFAULT_SCREEN_DPI を得るにはどうすれば的な方向性になると思いますが、
そこら辺を突き進めるとまた違っているという感じになるとおもうので、DPIが何を]意味するかとかは突き進めずにコントロールパネルの「拡大縮小とレイアウト」の部分で100%125%150%175%の切り替えを行うと、どれが選択されているかを得るのが目的という感じで、逆に、この値を切り替えても上記の%が反映されていないモニターサイズを得られれば、そこから逆算という手法もあるかもなど思っています。

編集 削除
Mr.XRAY  2022-08-16 04:30:53  No: 150359  IP: [192.*.*.*]

残念ながら,目的 ( 文章 ) が理解できません .以下は,もしかしたら参考になるかも知れない記事です.

[ WM_DPICHANGED メッセージ (WinUser.h) - Win32 apps Microsoft Docs ] - 注釈
https://docs.microsoft.com/ja-jp/windows/win32/hidpi/wm-dpichanged#remarks

編集 削除
 2022-08-16 05:38:04  No: 150360  IP: [192.*.*.*]

コントロールパネルのディスプレーで、てきすと、あぷり、その他の項目サイズの設定で
100%/125%/150%/175%のどれかが選べますよね。

DPIのpixelを指定したいという感じでは無く。その選ばれた物が上のどれを選択されているかを取得したいのです。
(sendkeyやhandle経由で調べるというのでは無く、レジストリだったり、何かのコマンドだかで得られれが
)

目的としては、TPOINTを得るときに100%と150%では座標の返り値が変わりますよね?
それを100%で利用しているモニターでも、150%で利用しているモニターでも、自動で%を認識し
切り替えさせるのが目的になります。



編集 削除
 2022-08-16 10:15:57  No: 150361  IP: [192.*.*.*]

以前調べた時に ShellScaling.pas がクサいと思ったのですが邪魔くさかったので
DwmGetWindowAttribute と GetWindowRect の比率でお茶を濁しました

編集 削除
mam  2022-08-16 12:29:13  No: 150362  IP: [192.*.*.*]

unit Unit1;
interface
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
    //DPIが変更された時
    procedure DPIChanged(var msg:TMessage);message WM_DPICHANGED;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation
{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var h:THandle;
    dc:HDC;
    dpi,rate:Integer;
begin
  h:=GetDesktopWindow();
  dc:=getdc(h);
  dpi:=GetDeviceCaps(dc,LOGPIXELSX);
  ReleaseDC(h,dc);
  Memo1.Lines.Add(inttostr(dpi)+'dpi');
  //96dpiで100%、120dpiで125%、144dpiで150%、192dpiで200%
  //よって96で割れば拡大率が出るらしい
  rate:=dpi*100 div 96;
  Memo1.Lines.Add(IntToStr(rate)+'%');
end;

procedure TForm1.DPIChanged(var msg: TMessage);
var dpi,rate:Integer;
begin
  dpi:=msg.WParam shr 16;
  Memo1.Lines.Add(inttostr(dpi)+'dpi');
  //96dpiで100%、120dpiで125%、144dpiで150%、192dpiで200%
  //よって96で割れば拡大率が出るらしい
  rate:=dpi*100 div 96;
  Memo1.Lines.Add(IntToStr(rate)+'%');
end;

end.


ではダメでしょうか。外していたらすいません。

編集 削除
 2022-08-16 15:45:22  No: 150363  IP: [192.*.*.*]

て、さん。mamさんありがとうございます。

>て、さん
私も ShellScaling.pas のにおいをかぎつけたの調べていたのですが ShellScaling.pasはD7にはないようでした。
DwmGetWindowAttribute と GetWindowRect の代替案をいただいたので、どちらとも初見なので今から調べてみたいと思います。

>mamさん
やりたいことの意図が伝わっているようでよかったです。

WM_DPICHANGED; はD7では来ないようでしたが、deko様のページを見たところリアルタイムで切り替えを得るものとのことなので
https://ht-deko.com/ft1601.html

リアルタイムでは無くてもいいのでButton1にしたら出来るかなとおもい試してみました。

ところ。ここが同じ値しか返らないのようなので調べてみたところ

これが理由なんだと思うのですが、環境が違うので代用無理でした。

https://gist.github.com/retorillo/4e0c4a3cf4c7096e05ac

編集 削除
 2022-08-16 19:12:42  No: 150364  IP: [192.*.*.*]

マニフェストファイルを埋め込む方法は簡単だと思います。
delphi10.4などが吐き出すリソース内のマニフェストの真似をしてみるのが1番簡単だと思います。適用の仕方は検索すればすぐ出てきます。

-----書き足す内容、ご指定のサイトより

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
    xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"
    manifestVersion="1.0">
  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>

-----参考(マニフェストの埋め込み方法ではないですが)

https://docs.microsoft.com/ja-jp/windows-hardware/manufacture/desktop/dpi-related-apis-and-registry-settings?view=windows-11

編集 削除
 2022-08-17 07:42:02  No: 150365  IP: [192.*.*.*]

>あ。さん

ありがとうございます。

調べてみましたが、DWMAPIをusesし    WindowsXP.resの</assembly>の上に追加すればいいと、みたページに書いてあったので上記を差し込んでみましたが、どう反映するのかが不明でしたので</assembly>の下に差し込んだり、全部入れ替えてみましたが反映確認できませんでした。

初物過ぎて私には簡単じゃやいっぽいです。

>て 。さん

す。スバラシイ!!
て。さんの方法で無事取得できました。わかりやすい方法でたすかりました。

皆さんありがとうございました。無事解決させていただきました♪


編集 削除
 2022-08-18 04:25:30  No: 150366  IP: [192.*.*.*]

Windows 8.1 以降限定、Shcore.dll の GetScaleFactorForMonitor を使う。

  type
    TGetScaleFactorForMonitor = function (hMon: HMONITOR; out Scale: Integer): HRESULT; stdcall;
var
  hProc81: TGetScaleFactorForMonitor;

@hProc81 := GetProcAddress(hLib, PChar('GetScaleFactorForMonitor'));

hProc81(Screen.Monitors[0].Handle, hogehoge)

125%であれば hogehoge = 125 が返る。

という仕様と思って作った自作関数があったけど、使ってないので、使えるものかわからない。

自分で使っているのは、EnumDisplaySettingsExAでTDevModeを取得し、
その幅と、Screen.Monitors[xxx].Width との差を使っていた。

編集 削除
Mr.XRAY  2022-08-19 07:41:14  No: 150368  IP: [192.*.*.*]

テストしてみました.

[ ディスプレイの DPI を取得 ]
http://mrxray.on.coocan.jp/Delphi/Others/GetDisplayDPI.htm

> DwmGetWindowAttribute と GetWindowRect の比率でお茶を濁しました

もサンプルを作成したかったのですが,残念ながら・・・

編集 削除
 2022-08-19 22:13:55  No: 150370  IP: [192.*.*.*]

追記ありがとうございます。
のちほど一段落しましたら試さしていただこうと思います。
ありがとうございました。

編集 削除
Mr.XRAY  2022-08-22 09:57:50  No: 150381  IP: [192.*.*.*]

> のちほど一段落しましたら試さしていただこうと思います。 

すでに解決しているのて,必要ないと思いますよ.

リンクの記事は,もし,検索でこのスレッドにきた方のためです.
ついでに,このスレッドで話題がでた関数類も,と思ったのです.

[ 04_コミュニティの場は give & take ( ギブ・アンド・テイク ) ]
http://mrxray.on.coocan.jp/Delphi/Others/013.htm#04

編集 削除