DOBON.NETプログラミング道掲示板

HOME HELP 新規作成 新着記事 ツリー表示 スレッド表示 トピック表示 発言ランク ファイル一覧 検索 過去ログ

[ 最新記事及び返信フォームをトピックトップへ ]

■33539 / inTopicNo.1)  マルチディスプレイ環境で任意のモニターに描画したい
  
□投稿者/ 旬な人 一般人(1回)-(2016/12/23(Fri) 14:26:37)
  • アイコン環境/言語:[OS : Windows 7 / 言語 : Visual Basic .NET] 
    分類:[.NET] 

    初めまして。
    普段は質問しないのですが、あまりにも.netでの関連資料が見つからないのでご教示いただきたく質問させていただきます。

    【解決したい問題】

    .netで、マルチディスプレイの環境で任意のモニターに描画したい(最前面)。

    分からないポイント
    1. マルチディスプレイ全体のデバイスコンテキストの取得方法
    2. 各モニターの左上座標とサイズの取得方法

    上記が分かればプライマリモニタへの描画(もしくはキャプチャ)を参考にすれば実現できると考えております。

    【解決するために何をしたか】

    ググったところいいサイトに巡り合えましたが、ただでさえ私の勉強不足でハンドルやコンテキストの理解もままならないのに、そのサイトでは私の苦手なC++のコードで表現されており.netへの落とし方がイメージできず、質問することにしました。

    そのサイト↓
    http://yamatyuu.net/computer/program/sdk/base/enumdisplay/index.html

    【追加事項】

    私の力量ですが、
    ・APIのラップ方法は何となくわかっている。
    ・でも、EnumDisplayMonitorsのコールバックって何ですか?
    ・結局EnumDisplayMonitorsは何をしてくれるの?
    って感じです。(つまり何もわかってないですね...)
マルチポストを報告
違反を報告
引用返信 削除キー/
■33540 / inTopicNo.2)  Re[1]: マルチディスプレイ環境で任意のモニターに描画したい
□投稿者/ Hongliang 大御所(527回)-(2016/12/23(Fri) 16:24:34)
  • アイコン仮想ディスプレイ上における各ディスプレイの位置とサイズは、System.Windows.Forms.ScreenクラスのAllScreensで取得できる各ScreenオブジェクトのBoundsプロパティを参照することで取得できます。
    問題は描画の方で、多分Graphicsクラスを使うのは不可能です。
    GetDC関数にNULLを渡せば仮想ディスプレイのHDCが取れるので、それに対して各種GDI関数を使って描画することになるかと。
    // ディスプレイ毎のDPI変えてる場合どうなるかとかは知らない。
違反を報告
引用返信 削除キー/
■33541 / inTopicNo.3)  Re[1]: マルチディスプレイ環境で任意のモニターに描画したい
□投稿者/ 魔界の仮面弁士 大御所(1058回)-(2016/12/23(Fri) 16:48:45)
  • アイコンNo33539に返信(旬な人さんの記事)
    > 1. マルチディスプレイ全体のデバイスコンテキストの取得方法
    デスクトップのデバイスコンテキストではなく、
    スクリーンのデバイスコンテキストであれば、
    GetDC(IntPtr.Zero) で取得できます。

    なお、GDI+ の制約により、このデバイスコンテキストから
    Graphics オブジェクトへの変換はできないようです。


    > 2. 各モニターの左上座標とサイズの取得方法
    こんな感じで。

    Dim fullRect As Rectangle = Screen.PrimaryScreen.Bounds
    Dim rects As New Dictionary(Of String, Rectangle)()
    For Each scr As Screen In Screen.AllScreens
      rects.Add(scr.DeviceName, scr.Bounds)
      fullRect = Rectangle.FromLTRB( _
        Math.Min(fullRect.Left, scr.Bounds.Left), _
        Math.Min(fullRect.Top, scr.Bounds.Top), _
        Math.Max(fullRect.Right, scr.Bounds.Right), _
        Math.Max(fullRect.Bottom, scr.Bounds.Bottom) _
      )
    Next


    > 【解決したい問題】
    > .netで、マルチディスプレイの環境で任意のモニターに描画したい(最前面)。

    スクリーンDC への描画を希望されているのであれば、
    過去ログの YAS さんのスレッドが参考になるかと思います。
    http://dobon.net/vb/bbs/log3-25/14985.html
    http://dobon.net/vb/bbs/log3-25/14968.html

    リンク先の URL の内容については、archive.org で
    過去のキャッシュを辿ってみてください。


    > ・結局EnumDisplayMonitorsは何をしてくれるの?
    役割としては、VB.NET でいうところの

     For Each scr As Screen In Screen.AllScreens
      'コールバックの第三引数 lprcMonitor に相当
      Debug.WriteLine(scr.Bounds.ToString())
     Next

    のような感じですね。


    > ・でも、EnumDisplayMonitorsのコールバックって何ですか?
    細かい事を端折って言えば、AddressOf で指定するデリゲートのことです。
    参考にされていたサイトでいえば「myinfoenumproc関数」の項にあたります。

    モニタが列挙されるたびに指定したコールバック関数が呼ばれますが、
    VB でいえばイベントのようなものであると連想しておけばよいかと。

    コールバックされるメソッド定義は下記のように定義します。

    Function MonitorEnumProc( _
    hMonitor As HandleRef, _
    hdcMonitor As HandleRef, _
    lprcMonitor As RECT,
    dwData As 何某 _
    ) As Boolean


    第1第2引数については、HandleRef のかわりに IntPtr でも OK です。

    第3引数については、
    RECT を構造体として宣言した場合は ByRef lprcMonitor As RECT
    RECT をクラスとして宣言した場合は ByVal lprcMonitor As RECT
    にしておいてください。

    第4引数は、EnumDisplayMonitors で指定したものと同じ定義にします。
    dwData はユーザー定義の情報であり、何を渡すのかは開発者が任意に
    決めて構いません。特に使う予定が無ければ ByVal IntPtr にでも
    しておき、IntPtr.Zero でも渡しておけば良いでしょう。

    ちなみに最初にご覧になっていたサイトでは、モニタ情報を保存するための
    自作 MONITORS 構造体への参照を dwData として渡しておき、コールバックのたびに
    その内容を書き換えていたようです。
違反を報告
引用返信 削除キー/
■33543 / inTopicNo.4)  Re[2]: マルチディスプレイ環境で任意のモニターに描画したい
□投稿者/ 旬な人 一般人(2回)-(2016/12/25(Sun) 07:44:15)
  • アイコンHongliangさん、魔界の仮面弁士さん、ありがとうございます。


    >1. マルチディスプレイ全体のデバイスコンテキストの取得方法

    GetDC(IntPtr.Zero)で解決。


    >2. 各モニターの左上座標とサイズの取得方法

    各ScreenのBoundsからプロパティを取得することで解決。
    (イニシャルでコンテキストメニューにScreenオブジェクトごと突っ込んで描画画面を選択できるようにしました。正確にはToString()をオーバーライドしたScreenをメンバに持つ自作クラスを突っ込んで、モニター名がコンテキストメニューに表示されるように改良。)


    >.netで、マルチディスプレイの環境で任意のモニターに描画したい(最前面)。

    これが本題でしたが、お二人のおっしゃる通りGraphicsでは問題があるようで、セカンダリモニターに描画できませんでした。GDI+で描画してみようと思います。
    適当にラッパーを作って動作が確認でき次第解決済みにさせていただきます。

    教えていただいた「http://dobon.net/vb/bbs/log3-25/14985.html」の「http://homepage1.nifty.com/yasunari/VB/VB2005/DrawToScreen.htm」は、本当によく纏まっていて参考になるので、YASさんに同じ内容でまたアップしていただきたいですね。


    コールバックについて

    少しだけ勉強してみましたが、C言語などポインタが扱える言語だと関数ポインタが使用できて、それがほぼデリゲートと同じ役割が果たせるのですね...!
    .netではScreenオブジェクトから位置や大きさを取得できるので、私が参考にしていたサイトの方法は使用せずとも良さそうです。
違反を報告
引用返信 削除キー/
■33544 / inTopicNo.5)  Re[3]: マルチディスプレイ環境で任意のモニターに描画したい
□投稿者/ 旬な人 一般人(3回)-(2016/12/25(Sun) 11:52:05)
  • アイコンGDI関数を使用することでとりあえず2画面に描画することはできました。
    しかし、何故かEllipseで描画した円の外側にEllipseに指定する四角の大きさで黒もしくは白で塗りつぶした背景が出来てしまいます。(言葉で表しにくいのでペイントで描いたイメージを添付します。)

    描画した方法は、
    1. GDIのGetDC(IntPtr.Zero)でhDCを取得。
    2. .netのScreenオブジェクトから画面のエリアを取得。
    3. GDIのCreatePen、CreateSolidBrushでペンとブラシを作成し、SelectObjectでhDCに設定する。
    4. GDIのEllipseで描画する。
    5. GDIのDeleteObjectでペンとブラシのリソースを開放。ReleaseDCでhDCを開放。

    GDIのSetBkModeでTRANSPARENTを指定してみてもダメでした。

    この新たな問題は表題とはおそらく関係ないと思いますので、解決済みとさせていただきます。ありがとうございました。
解決済み!
50×50
イメージ
1482634325.png
/1KB
違反を報告
引用返信 削除キー/
■33545 / inTopicNo.6)  Re[4]: マルチディスプレイ環境で任意のモニターに描画したい
□投稿者/ 魔界の仮面弁士 大御所(1059回)-(2016/12/27(Tue) 10:02:29)
  • アイコン2016/12/27(Tue) 19:06:10 編集(投稿者)

    No33544に返信(旬な人さんの記事)
    > 黒もしくは白で塗りつぶした背景が出来てしまいます。

    背景部は単色とは限らないようです。

    Dim hScreenDC As IntPtr = GetDC(IntPtr.Zero)
    FillRect(hScreenDC, Nothing, GetStockObject(NULL_BRUSH))
    UpdateWindow(IntPtr.Zero)
    ReleaseDC(IntPtr.Zero, hScreenDC)

    上記を実行すると、少し前のデスクトップが描画されました。
    描画していないエリアの情報は、この古い描画情報のようです。

    For Each scr As Screen In Screen.AllScreens
     Dim rMonitor As New RECT(scr.Bounds)
     FillRect(hScreenDC, rMonitor, GetStockObject(NULL_BRUSH))
     Dim rDraw As New RECT(rMonitor.Left + 50, rMonitor.Top + 50, rMonitor.Left + 200, rMonitor.Top + 200)
    Next
    UpdateWindow(IntPtr.Zero)

    こんな感じで、スクリーン単位に GetStockObject(NULL_BRUSH) を
    FillRect してから描画するようにすると、ゴミが残らなくなったようです。

    ※これが正しい手順なのかどうかは自信なし。


    > 黒もしくは白で塗りつぶした背景が出来てしまいます。

    画像からの転送なら、マスク画像を用意して描画してみてください。

    http://kitano.plala.jp/~kitano/winfaq/2/2-1.htm
    http://www14.big.or.jp/~ken1/tech/tech9.html
    http://masudahp.web.fc2.com/vb6/vb6first/pict032.html
    http://www.geocities.jp/ccfjd821/purogu/wpe-ji10.html
違反を報告
引用返信 削除キー/



トピック内ページ移動 / << 0 >>

このトピックに書きこむ

Mode/  Pass/

HOME HELP 新規作成 新着記事 ツリー表示 スレッド表示 トピック表示 発言ランク ファイル一覧 検索 過去ログ

- Child Tree -