C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

仮想ディスプレイの座標を取得する方法

[トピック内 30 記事 (1 - 20 表示)]  << 0 | 1 >>

■98686 / inTopicNo.1)  仮想ディスプレイの座標を取得する方法
  
□投稿者/ 餃子 (1回)-(2021/12/17(Fri) 19:17:51)

分類:[.NET 全般] 

VB.NET2015を使用しております。


マルチモニターで且つスケーリングがディスプレイ毎に異なる環境で
フォームのスクリーンショットを取得するために
フォームのある位置を取得したいと考えています。


仮想ディスプレイと呼ばれるものなので、

https://social.msdn.microsoft.com/Forums/vstudio/ja-JP/1bfd425f-b153-4079-bb51-8d525dc2937b/35079259681239812514124911247912487124511247312503125241245212?forum=vcgeneralja
http://www.vbaccelerator.com/home/vb/tips/Working_with_Multiple_Monitors/article.html


これらのページにあるように、
EnumDisplayMonitorsを使えば良いのではないかと思います。



        <DllImport("user32.dll")>
        Private Shared Function EnumDisplayMonitors(ByVal hdc As IntPtr, ByVal lprcClip As IntPtr, ByVal lpfnEnum As EnumMonitorsDelegate, ByVal dwData As IntPtr) As Boolean
        End Function

        <StructLayout(LayoutKind.Sequential)>
        Public Structure Rect
            Private Left As Integer, Top As Integer, Right As Integer, Bottom As Integer
        End Structure

        Delegate Function EnumMonitorsDelegate(hMonitor As IntPtr, hdcMonitor As IntPtr, ByRef lprcMonitor As Rect, dwData As IntPtr) As Boolean


        Sub main()

            EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, AddressOf EnumMonitorsDelegate, IntPtr.Zero)

        End Sub

こんな感じでコードを書いてみたのですが、


エラー	BC30577	'AddressOf' オペランドはメソッドの名前でなければなりません。かっこは不要です。	
というエラーが出てしまいます、


どのようにすれば、エラーが出なくなりますか?





引用返信 編集キー/
■98687 / inTopicNo.2)  Re[1]: 仮想ディスプレイの座標を取得する方法
□投稿者/ 魔界の仮面弁士 (3254回)-(2021/12/17(Fri) 19:36:25)
No98686 (餃子 さん) に返信
> Delegate Function EnumMonitorsDelegate(hMonitor As IntPtr, hdcMonitor As IntPtr, ByRef lprcMonitor As Rect, dwData As IntPtr) As Boolean

これは「デリゲート型」の宣言です。Dim x As EnumMonitorsDelegate などと書くための。


そしてその型宣言を
> <DllImport("user32.dll")>
> Private Shared Function EnumDisplayMonitors(ByVal hdc As IntPtr, ByVal lprcClip As IntPtr, ByVal lpfnEnum As EnumMonitorsDelegate, ByVal dwData As IntPtr) As Boolean
> End Function
の箇所で、『ByVal lpfnEnum As EnumMonitorsDelegate』として利用しているわけです。


> BC30577 'AddressOf' オペランドはメソッドの名前でなければなりません。
> どのようにすれば、エラーが出なくなりますか?
メソッドの名前は何でも良いですが、例えば
 Function 餃子(hMonitor As IntPtr, hdcMonitor As IntPtr, ByRef lprcMonitor As Rect, dwData As IntPtr) As Boolean
  '中身を実装
 End
というものを用意しておいて
 EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, AddressOf 餃子, IntPtr.Zero)
のように呼び出します。
AddressOf 演算子に、餃子という名前のメソッドを渡しているわけですね。

AddressOf に渡すメソッド(餃子)の引数・戻り値の定義は、
EnumMonitorsDelegate デリゲートの引数・戻り値の定義と一致させておいてください。

実装例。
https://dobon.net/cgi-bin/vbbbs/cbbs.cgi?mode=al2&namber=33691&no=0&KLOG=2
引用返信 編集キー/
■98688 / inTopicNo.3)  Re[1]: 仮想ディスプレイの座標を取得する方法
□投稿者/ Hongliang (1206回)-(2021/12/17(Fri) 19:36:40)
EnumDisplayMonitorsの第3引数は、EnumMonitorsDelegateと同じ返値・引数を持った関数を指定します。
その関数がディスプレイごとに1回ずつ呼び出されるので、関数の中で必要な処理を行います。

が、そもそもの話として、System.Windows.Forms名前空間のScreenクラスにAllScreensプロパティが用意されています。
(これは内部でEnumDisplayMonitorsを使用しています)
引用返信 編集キー/
■98689 / inTopicNo.4)  Re[2]: 仮想ディスプレイの座標を取得する方法
□投稿者/ 餃子 (2回)-(2021/12/17(Fri) 19:56:31)
お二方ありがとうございます。

まだ、EnumDisplayMonitorsは試していませんが、
AllScreensプロパティと同じ関数なのであれば、
使用する意味は無いと思います。

AllScreensプロパティは既に試しているのですが、
スケーリングファクターによらず、ディスプレイの物理的な解像度を返すため、
結局、フォームの位置を取得することができません、


スケーリングファクターを取得するには、
Dim LogicalScreenHeight As Integer = GetDeviceCaps(desktop, DeviceCap.VERTRES)
Dim PhysicalScreenHeight As Integer = GetDeviceCaps(desktop, DeviceCap.DESKTOPVERTRES)

Dim ScreenScalingFactor As Single = CSng(PhysicalScreenHeight / LogicalScreenHeight)

のようにして取得することができます。

もし、全てのモニターのスケーリングファクターが同じであれば、
このファクターを座標にかけるだけで、仮想ディスプレイ上での座標を取得することができます。

しかし、モニター毎にスケーリングが異なる場合には、
プライマリーモニターから順番にスケーリングファクターをかけ算して、
位置を特定する必要があるため、非常に面倒です。

何か良い方法はないでしょうか?

例えば、Alt+スクリーンショットキーを押すと
ウインドウのスクリーンショットを取得できるので、
モニター毎にスケーリングが異なったとしても
何かウインドウ位置を特定できる関数があるように思えるのですが
何か良い方法はございませんでしょうか?



引用返信 編集キー/
■98691 / inTopicNo.5)  Re[3]: 仮想ディスプレイの座標を取得する方法
□投稿者/ くま (60回)-(2021/12/17(Fri) 22:51:09)
> マルチモニターで且つスケーリングがディスプレイ毎に異なる環境で
> フォームのスクリーンショットを取得するために
> フォームのある位置を取得したいと考えています。
まず「フォームのスクリーンショット」という事で、自分以外のフォームの座標を取得する
という話になると思います。
その為「フォームのWindowハンドル」取得の方法ですが
a1. プロセスから対象フォームを検索する
a2. GetForegroundWindow APIにより 「フォアグランドフォームのWindowハンドル」を取得する
a3. 座標から「フォームのWindowハンドル」を取得する。
今回この辺りの話はなかったので、「フォームのWindowハンドル」は取得ができていると仮定します。

今回の問題点は2点あって
b1. GetWindowRectでは正確なウインドウサイズを取得できない
b2. DPIが96DPI以外の場合の問題

b1.に関しては
プログラマから見たWindows 10 #4 〜 最新情報とプログラミングTips
https://www.webtech.co.jp/blog/os/win10/8445/
に詳しい解説があるのですが
OSのバージョンによってウィンドウの表示の仕方が違います。
その為 GetWindowRect APIだと正確な座標とサイズが取得できません。
サイズ自体は DwmGetWindowAttribute APIに変更で良いのですが、
BitBlt APIではGetWindowRect APIの座標系を使用する為誤差を計算する必要があります。

b2.に関しては
Windows での高 DPI デスクトップアプリケーション開発
https://docs.microsoft.com/ja-jp/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows
辺りに解説がありました。
簡単にいうと
「OSがWin10以上なら96DPI以外で計算するAPIを用意したけど、それ以外には存在しないAPIだから使えない。
よって96DPI以外の場合、96DPI相当の座標に計算しなおしてください。」
という事です

で以下サンプルを作成しましたが、こちらで「マルチモニターでDPIが違う」環境を用意できませんでした。
よって実際、餃子さんの環境で試してみてください。
引用返信 編集キー/
■98692 / inTopicNo.6)  Re[4]: 仮想ディスプレイの座標を取得する方法
□投稿者/ くま (61回)-(2021/12/17(Fri) 22:57:01)
2021/12/17(Fri) 23:28:32 編集(投稿者)
Module1.vbのソース

Imports System.Runtime.InteropServices
Module Module1

    <DllImport("user32.dll")>
    Private Function GetWindowRect(ByVal hwnd As IntPtr, ByRef lpRect As RECT) As Boolean
    End Function
    <StructLayout(LayoutKind.Sequential)>
    Private Structure RECT
        Public left As Integer
        Public top As Integer
        Public right As Integer
        Public bottom As Integer
    End Structure

    <DllImport("dwmapi.dll")>
    Private Function DwmGetWindowAttribute(ByVal hWnd As IntPtr, ByVal dwAttribute As DWMWINDOWATTRIBUTE, ByRef rect As RECT, ByVal cbAttribute As Integer) As Long
    End Function
    Private Enum DWMWINDOWATTRIBUTE
        DWMWA_NCRENDERING_ENABLED = 1
        DWMWA_NCRENDERING_POLICY
        DWMWA_TRANSITIONS_FORCEDISABLED
        DWMWA_ALLOW_NCPAINT
        DWMWA_CAPTION_BUTTON_BOUNDS
        DWMWA_NONCLIENT_RTL_LAYOUT
        DWMWA_FORCE_ICONIC_REPRESENTATION
        DWMWA_FLIP3D_POLICY
        DWMWA_EXTENDED_FRAME_BOUNDS 'ウィンドウのRect
        DWMWA_HAS_ICONIC_BITMAP
        DWMWA_DISALLOW_PEEK
        DWMWA_EXCLUDED_FROM_PEEK
        DWMWA_CLOAK
        DWMWA_CLOAKED
        DWMWA_FREEZE_REPRESENTATION
        DWMWA_LAST
    End Enum

    <DllImport("user32.dll")>
    Private Function GetDpiForWindow(ByVal hWnd As IntPtr) As Integer
    End Function
    <DllImport("kernel32.dll")>
    Private Function MulDiv(ByVal nNumber As Integer, ByVal nNumerator As Integer, ByVal nDenominator As Integer) As Integer
    End Function

    Public Structure WindowSize
        Public X As Integer
        Public Y As Integer
        Public Width As Integer
        Public Height As Integer
        Public OffsetX As Integer
        Public OffsetY As Integer
    End Structure

    Function GetWindowSize(ByVal hWnd As IntPtr) As WindowSize
        Dim lpRect As RECT
        Dim bounds As RECT

        '従来のフォームサイズの取得方法
        Call GetWindowRect(hWnd, lpRect)

        'プログラマから見たWindows 10 #4 〜 最新情報とプログラミングTips
        'https://www.webtech.co.jp/blog/os/win10/8445/
        '「ウィンドウのサイズと枠線についての仕様変更」より
        ' Windows10でのウインドウサイズの正確な求め方
        Call DwmGetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, bounds, Marshal.SizeOf(GetType(RECT)))

        '各座標を設定
        Dim ws As WindowSize
        ws.X = bounds.left
        ws.Y = bounds.top
        ws.Width = bounds.right - bounds.left
        ws.Height = bounds.bottom - bounds.top
        'C#での画面キャプチャの取得方法を徹底解説!
        'https://www.fenet.jp/dotnet/column/language/4633/
        'BitBlt API等で取得する際、x, y座標に指定する値
        ws.OffsetX = bounds.left - lpRect.left
        ws.OffsetY = bounds.top - lpRect.top

        'ここから後が必要かわからないが一応

        'Windows での高 DPI デスクトップアプリケーション開発
        'https://docs.microsoft.com/ja-jp/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows
        '現在表示されているウインドウのモニターのDPIを取得
        'SetWindowPos API等は96DPI固定で計算されているので、現在のDPIで96DPI相当の位置を再計算
        Dim iDpi As Long = GetDpiForWindow(hWnd)
        ws.X = MulDiv(ws.X, iDpi, 96)
        ws.Y = MulDiv(ws.Y, iDpi, 96)
        ws.Width = MulDiv(ws.Width, iDpi, 96)
        ws.Height = MulDiv(ws.Height, iDpi, 96)
        ws.OffsetX = MulDiv(ws.OffsetX, iDpi, 96)
        ws.OffsetY = MulDiv(ws.OffsetY, iDpi, 96)

        Return ws
    End Function


End Module

引用返信 編集キー/
■98693 / inTopicNo.7)  Re[5]: 仮想ディスプレイの座標を取得する方法
□投稿者/ ???? (2回)-(2021/12/17(Fri) 22:57:16)
2021/12/17(Fri) 22:58:09 編集(投稿者)

訂正
引用返信 編集キー/
■98694 / inTopicNo.8)  Re[6]: 仮想ディスプレイの座標を取得する方法
□投稿者/ くま (62回)-(2021/12/17(Fri) 22:58:28)
[Form1]フォームに[Button1]ボタンを配置
Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        '[メモ帳]を起動
        Dim p As System.Diagnostics.Process = System.Diagnostics.Process.Start("notepad.exe")
        '表示されるまで待機
        System.Threading.Thread.Sleep(1000)
        For Each p In System.Diagnostics.Process.GetProcesses()
            '[メモ帳]をプロセスから判断
            If p.ProcessName = "notepad" Then
        '座標を取得
                Dim ws As WindowSize = GetWindowSize(p.MainWindowHandle)
                Debug.Print("X={0},Y={1},Width={2},Height={3},OffsetX={4},OffsetY={5}", ws.X, ws.Y, ws.Width, ws.Height, ws.OffsetX, ws.OffsetY)
            End If
        Next
    End Sub
End Class

引用返信 編集キー/
■98696 / inTopicNo.9)  Re[7]: 仮想ディスプレイの座標を取得する方法
□投稿者/ くま (64回)-(2021/12/17(Fri) 23:42:05)
APIが96DPI相当の位置を返している[はず]なので
「現在のDPIで96DPI相当の位置を再計算」の部分は必要ない[はず]です。
その場合該当箇所をコメントアウトしてください。
引用返信 編集キー/
■98701 / inTopicNo.10)  Re[8]: 仮想ディスプレイの座標を取得する方法
□投稿者/ 餃子 (4回)-(2021/12/18(Sat) 10:22:36)


ありがとうございます。

マルチモニターではまだ試せていませんが、
シングルモニターだとDwmGetWindowAttributeで取得できることが分かりました。


ところで、フォームの中にあるPictureBoxだけのスクリーンショットをとりたい場合、
どのようにすれば良いですか?

DwmGetWindowAttributeを使って取得した、フォームの左端と右端の座標と
PictureBoxのフォーム内での相対位置から自分で計算するしかないですか?




引用返信 編集キー/
■98702 / inTopicNo.11)  Re[9]: 仮想ディスプレイの座標を取得する方法
□投稿者/ 魔界の仮面弁士 (3256回)-(2021/12/18(Sat) 10:42:30)
No98701 (餃子 さん) に返信
> DwmGetWindowAttributeを使って取得した、フォームの左端と右端の座標と
> PictureBoxのフォーム内での相対位置から自分で計算するしかないですか?

スクリーン座標とクライアント座標の変換方法なら、そのためのメソッドが
用意されていますが…そういうことではなく?
https://atmarkit.itmedia.co.jp/fdotnet/dotnettips/377screentoclient/screentoclient.html

あるいは自アプリの PictureBox ではなく、他アプリの PictureBox ウィンドウの話?
引用返信 編集キー/
■98703 / inTopicNo.12)  Re[10]: 仮想ディスプレイの座標を取得する方法
□投稿者/ 餃子 (6回)-(2021/12/18(Sat) 10:46:59)
ありがとうございます。

スクリーン座標とクライアント座標の変換方法というのはもちろん知っています。

しかし、スケーリングを100%以上に設定していると、Pictureboxのクライアント座標をスクリーン座標に変換後
その座標を使ってスクリーンショットをとると位置がずれてしまいます。
というのが今回の質問内容です。

もしかして、DwmGetWindowAttributeで取得したフォームのスクリーン座標をクライアント座標に変換するということを意図されていますでしょうか?

引用返信 編集キー/
■98706 / inTopicNo.13)  Re[11]: 仮想ディスプレイの座標を取得する方法
□投稿者/ 魔界の仮面弁士 (3257回)-(2021/12/18(Sat) 15:04:56)
2021/12/18(Sat) 15:07:22 編集(投稿者)

No98703 (餃子 さん) に返信
> その座標を使ってスクリーンショットをとると位置がずれてしまいます。
> というのが今回の質問内容です。

それで現状、何が問題になっているのですか?
『現象を再現可能な最低限のコード』が示されていないこともあり、未だに状況が見えていません。

取得した座標が想定された値と違っているという話なのか、それとも
座標は得られるが、論理サイズと物理ピクセル数の変換に問題が生じるという事なのか、
現状ご利用中の撮影法だと 100% 以外の dpi 設定でズレてしまうという事なのか、
マニフェスト設定によって違う動作になってしまったので補正したいという事なのか…。


そもそも DPI 設定を考慮した各画面の「論理サイズ」を知る必要は無いと思っています。
物理ピクセルで示される座標系さえ得られれば、撮影はできますので。

撮影した画像をファイルに保存する際に、dpi 設定を保持することはあるかもしれませんが、
複数モニターにまたがるように配置されたウィンドウなどもありえますし、とりたてて
No98689 のような各画面のスケーリングを考慮する必要性というものが思い当たりませんでした。


少なくとも EnumDisplaySettingsW API や EnumDisplaySettingsExW API は
DPI 仮想化には携わらず、常に物理ピクセルの観点で出力される仕様だったはずです。

実際に、 No98687 で紹介した先にある VB サンプル(EnumDisplayDevices + EnumDisplaySettings)で
改めて確認してみましたが、100%, 175% と異なるディスプレイの組み合わせや、
ダミープラグによるディスプレイレス画面も物理ピクセル数で得られることを確認できました。
http://www.vb-user.net/junk/replySamples/2017.10.16.16.09/EnumDisplayDevices.txt
https://docs.microsoft.com/ja-jp/windows-hardware/drivers/display/the-devmodew-structure

ついでに言えば、サンプル中で DM_DISPLAYFIXEDOUTPUT の処理が漏れていますね…。
元サンプルは後日直しておきます。

If (pDevMode.dmFields And DevModeFields.DisplayFixedOutput) <> 0 Then
 '0 [Default], 1[Stretch], 2[Center]
 ListBox3.Items.Add(vbTab & "dmDisplayFixedOutput=" & pDevMode.dmDisplayFixedOutput.ToString())
End If
引用返信 編集キー/
■98707 / inTopicNo.14)  Re[11]: 仮想ディスプレイの座標を取得する方法
□投稿者/ くま (69回)-(2021/12/18(Sat) 15:08:28)
なんか質問内容がズレていっているような...。
> しかし、スケーリングを100%以上に設定していると、Pictureboxのクライアント座標をスクリーン座標に変換後
> その座標を使ってスクリーンショットをとると位置がずれてしまいます。
> というのが今回の質問内容です。
それってこの掲示板で質問のあった「CopyFromScreenでブランク画像になってしまう」の話?
そっちは分からないので調査した話をすると、

まず
「別のフォームのPictureBoxコントロールのみの画像を取得したい」という事であっていますか?
それなら
前のDwmGetWindowAttribute APIで取得した値で「フォーム全体の画像」取得は成功したのなら
誤差はOffsetX,OffsetYで求められているので
クライアント座標→スクリーン座標→誤差調整でPictureBoxコントロールの位置は求まります
サイズはコントロールの表示状態がどうなっているかで調整しないといけませが
GetWindowRect APIで求まっているはずです。
(表示状態はSpy++またはGetWindowLong APIで確認)

手順は
1.「別のフォーム」を見つける。
見つかった場合「フォームWindowハンドル」が取得される。
2.「フォームWindowハンドル」から誤差を取得しておく
3.「フォームWindowハンドル」から子ウインドウ「PictureBoxコントロール」を検索する。
見つかった場合「PictureBoxコントロールWindowハンドル」が取得される。
4. GetWindowRect APIでクライアント座標を取得する
5. クライアント座標からスクリーン座標に変換
6. BitBlt APIで画像を取得する際誤差(Offset)が発生しているのでスクリーン座標+誤差(Offset)で画像を取得する。

ただ取得した画像のサイズですが、これは96DPIで換算した時のサイズになります。
これを修正したいのであれば先の資料で記載した方法でフォームの表示されているDPIを取得して
(GetDpiForWindow API)
Width = MulDiv(Width, 96, iDpi)
Height = MulDiv(Height, 96, iDpi)
で求まります。
BitBlt APIだと拡大ができないので StretchBlt APIで拡大・縮小取得になります。
ただサイズは合うのですが今度は画像がボヤけるとは思います。
これは相手側が高DPIに対応しているか、していないかで決まります。
引用返信 編集キー/
■98708 / inTopicNo.15)  Re[12]: 仮想ディスプレイの座標を取得する方法
□投稿者/ くま (71回)-(2021/12/18(Sat) 15:11:47)
No98706 (魔界の仮面弁士 さん) に返信
> 2021/12/18(Sat) 15:07:22 編集(投稿者)
申し訳ございません。回答が被ってしまいました。

引用返信 編集キー/
■98712 / inTopicNo.16)  Re[13]: 仮想ディスプレイの座標を取得する方法
□投稿者/ ???? (4回)-(2021/12/18(Sat) 18:02:51)
2021/12/18(Sat) 18:09:22 編集(投稿者)

訂正
引用返信 編集キー/
■98714 / inTopicNo.17)  Re[14]: 仮想ディスプレイの座標を取得する方法
□投稿者/ くま (74回)-(2021/12/18(Sat) 18:09:46)
> ところで、フォームの中にあるPictureBoxだけのスクリーンショットをとりたい場合、
> どのようにすれば良いですか?
> しかし、スケーリングを100%以上に設定していると、Pictureboxのクライアント座標をスクリーン座標に変換後
> その座標を使ってスクリーンショットをとると位置がずれてしまいます。
> というのが今回の質問内容です。

これに引っ張られて回答書いたけどよくよく考えたら

フォームやコントロールの外観をキャプチャする
https://dobon.net/vb/dotnet/graphics/invokepaint.html

コントロールのWindowハンドル取得できているならPrintWindowでコントロール取得できるよね?
クライアント座標をスクリーン座標に変換なんていらないでしょ?
引用返信 編集キー/
■98724 / inTopicNo.18)  Re[15]: 仮想ディスプレイの座標を取得する方法
□投稿者/ 餃子 (7回)-(2021/12/18(Sat) 19:55:00)
2021/12/18(Sat) 19:55:42 編集(投稿者)
お二方ありがとうございます。


本当にお聞きしたかったのは、
起動しているフォーム内(くまさんは.「別のフォーム」と仰っていますが、同じフォーム内です)にあるPictureBoxのスクリーンショットを取得することです。

最初から、これを質問するよりも
フォームだけを取得したいと質問した方が回答が得られやすいかと思い、
フォームの取得方法を先に質問しました、


魔界の仮面弁士さんの回答だと、
100%以外のDPIでも普通に取得できるそうなのですが、
こちらの環境だとうまくいきません、

以下のコードで何が間違っていますでしょうか?


    Public Sub PBoxScreenshot2()


        Dim PBox As PictureBox = PictureBox1


        Dim PBoxScreenLocation1 As Point = PBox.PointToScreen(PBox.ClientRectangle.Location)

        Dim BoundaryWidth As Integer = PBox.Width - PBox.ClientSize.Width
        Dim BoundaryWidth2 As Integer = BoundaryWidth \ 2


        PBoxScreenLocation1.X -= BoundaryWidth2
        PBoxScreenLocation1.Y -= BoundaryWidth2



        Using bmp As New Bitmap(PBox.Size.Width, PBox.Size.Height)

            Using g As Graphics = Graphics.FromImage(bmp)

                g.CopyFromScreen(PBoxScreenLocation1, New Point(0, 0), bmp.Size, CopyPixelOperation.SourceCopy)

            End Using

            Clipboard.SetImage(bmp)

        End Using


    End Sub


あとちなみに、スケーリングを変更しても、

Dim iDpi As Integer = GetDpiForWindow(hWnd)

で得られる値は96から変化しません、

検索して調べると、スケーリングを変えるとDPIが変化すると書かれてあるのですが
不思議です。

引用返信 編集キー/
■98728 / inTopicNo.19)  Re[16]: 仮想ディスプレイの座標を取得する方法
□投稿者/ くま (81回)-(2021/12/18(Sat) 21:03:16)
どんどん質問が変わっていくのは良くないですよ。
> 本当にお聞きしたかったのは、
> 起動しているフォーム内(くまさんは.「別のフォーム」と仰っていますが、同じフォーム内です)にあるPictureBoxのスクリーンショット
> を取得することです。
ちゃんと前提条件書いていますので違う場合そのように先に書いていただかないと...。

自分のフォーム上にあるPictureBoxコントロールの表示画像をクリップボードへコピーしたいのであれば

Clipboard.SetImage(PictureBox1.Image)

の1行だけですみます。
座標等関係ありません。

> Dim iDpi As Integer = GetDpiForWindow(hWnd)
> で得られる値は96から変化しません、
こちらの環境でスケーリングを100→125に変更しましたが
96DPI→120DPIと変更された値を取得しています。


引用返信 編集キー/
■98731 / inTopicNo.20)  Re[17]: 仮想ディスプレイの座標を取得する方法
 
□投稿者/ 餃子 (8回)-(2021/12/18(Sat) 21:47:42)
ありがとうございます。

Clipboard.SetImage(PictureBox1.Image)
だと、PictureBox1_Paint上に書いたラインなどが描画されません、

あと、Chart1に関してもクリップボードにコピーしたいのですが、
これにはImageがないのでコピーすることができません。

どのようにすればよろしいでしょうか??



引用返信 編集キー/

このトピックをツリーで一括表示

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -