tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルWindows 10 におけるデスクトップのハンドル取得
記事No11585
投稿日: 2016/01/14(Thu) 09:33
投稿者花ちゃん
今まで、下記のようにしてマウス直下のカラー値を取得していたのですが、Windows 10 に移行してから
取得できなくなりました。

テスト環境 : Windows 10 / VB2015 / Framework 4.6.1 / 対象の CPU:x86

  Dim hDC As IntPtr = GetDC(IntPtr.Zero)
  '指定箇所のカラーを取得
  Dim col As Color = ColorTranslator.FromWin32(GetPixel(hDC, Cursor.Position.X, Cursor.Position.Y))

最初、GetPixel に問題があるのかなと思っていましたが、色々調べていて、GetDC(IntPtr.Zero) では
Windows 10 のデスクトップのハンドルが取得できないようなのですが、その対処法が解りません。
(VB6.0 の場合でも同様です。)
ご存知の方教えて頂けないでしょうか

[ツリー表示へ]
タイトルRe: Windows 10 におけるデスクトップのハンドル取得
記事No11586
投稿日: 2016/01/14(Thu) 09:43
投稿者Hongliang
Win10が手元にないので提案だけですが…。
IntPtr.Zeroの代わりに、GetDesktopWindow関数で手に入れたウィンドハンドルを使えばどうでしょうか?

[ツリー表示へ]
タイトルRe^2: Windows 10 におけるデスクトップのハンドル取得
記事No11587
投稿日: 2016/01/14(Thu) 10:11
投稿者花ちゃん
> Win10が手元にないので提案だけですが…。
> IntPtr.Zeroの代わりに、GetDesktopWindow関数で手に入れたウィンドハンドルを使えばどうでしょうか?

レスありがとうございます。GetDesktopWindow も試したのですが同様に取得できませんでした。
Windows 10 から仮想デスクトップが採用されたのが関係しているようなのですが?

[ツリー表示へ]
タイトルRe^3: Windows 10 におけるデスクトップのハンドル取得
記事No11588
投稿日: 2016/01/14(Thu) 13:02
投稿者YuO
> > IntPtr.Zeroの代わりに、GetDesktopWindow関数で手に入れたウィンドハンドルを使えばどうでしょうか?
> レスありがとうございます。GetDesktopWindow も試したのですが同様に取得できませんでした。

GetDesktopWindowだとGetDCのかわりにはならないですよね。
# GetDC(nullptr)はデスクトップではなくスクリーンDC取得なので。
ただ,GetDesktopWindowで得たDCからでも取得できないなら,別の問題な気もします。

とりあえず,VC++でコードを書いてみました。
リモートデスクトップ接続でWindows 10マシンに繋いで試したところ,色を取得できるようです。
タイマーハンドラにデバッグ出力コードを追加して,デスクトップ切り替えを行いましたが,
切り替えられたデスクトップでもちゃんと色を取得できていました。

ただ,リモートデスクトップ環境でない場合にちゃんと取得できるかは確かめられていませんが……。
https://github.com/YuneKichi/BbsSample/tree/master/hanatyan.sakura.ne.jp/vbnetbbs/11585/GetCursorPosColor
# HTTPSでもh抜かせばよいのかな?

[ツリー表示へ]
タイトルRe^4: Windows 10 におけるデスクトップのハンドル取得
記事No11589
投稿日: 2016/01/14(Thu) 14:33
投稿者花ちゃん
取得できましたか。

Windows 8.1 や Windows 7 で動作確認をしているコードです。

Imports System.Runtime.InteropServices

Public Class Form1

    Private Sub Timer1_Elapsed(sender As Object, e As Timers.ElapsedEventArgs) Handles Timer1.Elapsed
        TextBox1.Text = Cursor.Position.ToString
        Dim hDC As IntPtr = GetDC(IntPtr.Zero)
        Dim col As Color = ColorTranslator.FromWin32(GetPixel(hDC, Cursor.Position.X, Cursor.Position.Y))
        Label1.BackColor = col
        TextBox2.Text = col.ToString
        ReleaseDC(IntPtr.Zero, hDC)
    End Sub

    <DllImport("gdi32.dll", CharSet:=CharSet.Auto)>
    Private Shared Function GetPixel(
        ByVal hdc As IntPtr,
        ByVal x As Integer,
        ByVal y As Integer) As Integer
    End Function

    <DllImport("user32.dll", CharSet:=CharSet.Auto)>
    Private Shared Function GetDC(
        ByVal hwnd As IntPtr
        ) As IntPtr
    End Function

    <DllImport("user32.dll", CharSet:=CharSet.Auto)>
    Private Shared Function ReleaseDC(
        ByVal hWnd As IntPtr,
        ByVal hDC As IntPtr
        ) As Boolean
    End Function

End Class

一応 Windows 10 上でも  Dim hDC As IntPtr = GetDC(IntPtr.Zero) でエラー値ではなくハンドルが
取得はできているのですが?。

[ツリー表示へ]
タイトルRe^5: Windows 10 におけるデスクトップのハンドル取得
記事No11590
投稿日: 2016/01/15(Fri) 13:05
投稿者shu
Timers.Timerは別スレッドで実行されるので
その辺が関係してないですか?

Forms.Timerなら大丈夫とか?

[ツリー表示へ]
タイトルRe^6: Windows 10 におけるデスクトップのハンドル取得
記事No11591
投稿日: 2016/01/15(Fri) 15:42
投稿者YuO
> Timers.Timerは別スレッドで実行されるので
> その辺が関係してないですか?
> Forms.Timerなら大丈夫とか?

たぶん,それですね。
Timer1.SynchronizingObjectを指定しないと,
を追加しておくと,デバッグ出力にSystem.InvalidOperationExceptionが大量発生しています。
で,例外で止めてみると,クロススレッドアクセスの例外であることが書かれています。

・System.Windows.Forms.Timerを使う
・Timer1.SynchronizingObjectを設定する
・System.Windows.Forms.Control.Invokeのコールバックを使う
あたりが解決策でしょうか。
# これ,Windows 10以前から起きていそうですが……。

[ツリー表示へ]
タイトルRe^7: Windows 10 におけるデスクトップのハンドル取得
記事No11592
投稿日: 2016/01/15(Fri) 15:52
投稿者花ちゃん
> > Timers.Timerは別スレッドで実行されるので
> > その辺が関係してないですか?
> > Forms.Timerなら大丈夫とか?
>
> たぶん,それですね。

関係ないみたいですね?
VB6.0 のコードでも同様に取得できないし、念のため Forms.Timer や Form1_MouseMove 内で
試しても同様に取得できませんでした。

[ツリー表示へ]
タイトルRe^8: Windows 10 におけるデスクトップのハンドル取得
記事No11593
投稿日: 2016/01/15(Fri) 16:20
投稿者YuO
> > > Timers.Timerは別スレッドで実行されるので
> > > その辺が関係してないですか?
> > > Forms.Timerなら大丈夫とか?
> >
> > たぶん,それですね。
>
> 関係ないみたいですね?
> VB6.0 のコードでも同様に取得できないし、念のため Forms.Timer や Form1_MouseMove 内で
> 試しても同様に取得できませんでした。

なんでしょうねぇ……。
リモートでない環境下でも,No.11588でのコードでは取得できたのですが,花ちゃんさんの環境ではどうでしょうか。
これで取得できないならドライバ等,もっと低レベル層の問題になりそうな気がします。

[ツリー表示へ]
タイトルRe: Windows 10 におけるデスクトップのハンドル取得
記事No11594
投稿日: 2016/01/15(Fri) 19:11
投稿者魔界の仮面弁士
> Windows 10 に移行してから取得できなくなりました。

「取得できない」とのことですが、
具体的には、どうなってしまうのでしょうか?

(1)例外が発生している
(2)どの座標を指定しても、常に同じ色情報(間違った値)が返却されてしまう
(3)結果に再現性が見当たらず、同じ座標を指定しても毎回異なる値が返却されてしまう
(4)座標から返される値は一定しているのだが、それが本来の色とは異なっている
(5)その他

また、Marshal.GetLastWin32Error() は何を返してきますか?


> (VB6.0 の場合でも同様です。)

お使いの環境の DPI 設定は、Win10 およびそれ以前の OS ともに
100% (96dpi)に設定されていますか?

Windows 10 で、このあたりの動作が変わったという話は
聞いたことが無いので、外しているかも知れませんが、
仮に Win10 環境だけが高 DPI 環境だったというだけであれば、
exe のプロパティで DPI スケールを無効化すれば
解決できるかもしれません。


蛇足情報:
http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=9850
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ff684173%28v=vs.85%29.aspx


> ご存知の方教えて頂けないでしょうか

特に情報は無いですが、以下思い付きで。

・管理者モードか否かで、結果は変化しますか?
・対象の座標に、レイヤードウィンドウがありませんか?
・問題の発生する座標に、オーバーレイ表示なアプリがありませんか?

[ツリー表示へ]
タイトルRe^2: Windows 10 におけるデスクトップのハンドル取得
記事No11595
投稿日: 2016/01/15(Fri) 22:22
投稿者花ちゃん
皆さん色々アドバイスありがとうございます。

私の環境によるようだとの事で色々知らべなおしたところ。
4K のノートパソコンから外部ディスプレイと液晶テレビに接続して使っていたのですが
GetDC(IntPtr.Zero) でとれていたのが、液晶テレビの画面のようです。
もちろん設定上は、ノートパソコンの画面がデスクトップとして表示はしているので、テレビ画面の方
まではチェックしていませんでした。

どうもドライバーあたりに問題がありそうなので、これから、Windows 8.1 に戻します。
他にも色々問題をかかえているので。

どうもお騒がせしました。そしてありがとうございました。

[ツリー表示へ]
タイトルRe^3: Windows 10 におけるデスクトップのハンドル取得
記事No11596
投稿日: 2016/01/16(Sat) 00:39
投稿者魔界の仮面弁士
> GetDC(IntPtr.Zero) でとれていたのが、液晶テレビの画面のようです。

テレビ側がプライマリになっていませんか?
https://msdn.microsoft.com/ja-jp/library/cc428664.aspx

[ツリー表示へ]
タイトルRe^4: Windows 10 におけるデスクトップのハンドル取得
記事No11597
投稿日: 2016/01/16(Sat) 01:23
投稿者花ちゃん
> テレビ側がプライマリになっていませんか?
見た目はなっていませんね、それに変更するたびに再起動されたりとか Windows 8.1 の時のように
動作しません。

因みに、 Windows 8.1 に戻したら、ここの色見本のページをどの画面に表示してもマウス直下のカラー値が
取得できます。(ハンドルの取得の変更をしなくても、起動したままマウスの位置を変えるだけで)

[ツリー表示へ]
タイトルRe^5: Windows 10 におけるデスクトップのハンドル取得
記事No11598
投稿日: 2016/01/16(Sat) 02:49
投稿者魔界の仮面弁士
> 因みに、 Windows 8.1 に戻したら、ここの色見本のページをどの画面に表示してもマウス直下のカラー値が
> 取得できます。(ハンドルの取得の変更をしなくても、起動したままマウスの位置を変えるだけで)

自分の Win 10 端末は、dpi 設定を 175% にしているのですが(初期設定は 200%)、
この場合、 No.11589 のコードはそのままだと期待動作しないため、
 Dim rate = 1.75   '← dpi 設定に合わせる
 Dim p1 = Cursor.Position
 Dim p2 As New Point(p1.X * rate, p1.Y * rate)
 col = ColorTranslator.FromWin32(GetPixel(hDC, p2.X, p2.Y))
に変更することで、正しい色を取得できるようになっています。
※ Build 10586.63 な環境です。

また、dpiAware を True にするか、先述のスケール無効化を施した場合は、
元のコードのままでも取得することができています。

逆に、DPI 設定を高く設定してみた場合には、Windows 7 においても同様の問題が生じ、
元のコードでは期待する結果が得られていませんでした。
(8.1 ではないので、Per-Monitor DPI は利用できない状態です)


しかし、そちらの言う「取得できない」状態というのは、
上記とは別の問題なのですね?

[ツリー表示へ]
タイトルRe^6: Windows 10 におけるデスクトップのハンドル取得
記事No11599
投稿日: 2016/01/16(Sat) 08:28
投稿者花ちゃん
> しかし、そちらの言う「取得できない」状態というのは、
> 上記とは別の問題なのですね?

DPI の違いによる位置ずれとは違い、電源も入れていないモニターのハンドルを取得している状態です。
従って、マウスを動かすと、殆ど黒色で場所によって白の2色しか表示しないのです。

モニターを識別すると、ノートパソコンが1 テレビが2 外部ディスプレイが3 になっていて
テレビにはケーブルは接続していますが、画面は写していないので原因がつかめなかったと言う次第です。
それで、GetDC(IntPtr.Zero) この辺に問題があるものと判断して投稿したのですが。

もう少し待ってから Windows 10 に Update します。

※ Windows 10 に Update して数日後、PC のメーカーからのディスプレイ関係とモニター関係の
  Update がありトラブルが解決されました。
  この間システムのリフレッシュをしたりとかデバイス関係のドライバーをチェックしたりとか
  数日を無駄にしました。 

[ツリー表示へ]