Windowsデスクトップへの直接描画


GetDCでアプリケーション外のOS描画域をとってくるだけ。
OpenCvの認識領域とかを判別するのが面倒だったので。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Runtime.InteropServices;

namespace win32
{
  public class DrawWindow : IDisposable
  {
    //RedrawWindow() flags
    private enum RDW : int
    {
      INVALIDATE = 0x1,
      INTERNALPAINT = 0x2,
      ERASE = 0x4,
      VALIDATE = 0x8,
      NOINTERNALPAINT = 0x10,
      NOERASE = 0x20,
      NOCHILDREN = 0x40,
      ALLCHILDREN = 0x80,
      UPDATENOW = 0x100,
      ERASENOW = 0x200,
      FRAME = 0x400,
      NOFRAME = 0x800
    }

    [DllImport("user32.dll")]
    private static extern IntPtr GetDC(IntPtr hWnd);

    [DllImport("user32.dll")]
    private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

    [DllImport("user32.dll")]
    private static extern bool UpdateWindow(IntPtr hWnd);

    [DllImport("user32.dll")]
    private static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, RDW flags);

    [DllImport("gdi32.dll")]
    private static extern IntPtr CreateDC(string pszDriver, string pszDevice, string pszOutput, IntPtr pInitData);

    private IntPtr m_Hdc = IntPtr.Zero;

    public void RefreshDesktop()
    {
      RedrawWindow(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, RDW.ALLCHILDREN | RDW.UPDATENOW | RDW.ERASE | RDW.INVALIDATE | RDW.INTERNALPAINT);
      UpdateWindow(IntPtr.Zero);
    }

    public Graphics CreateDisplayGraphics()
    {
      string deviceName = System.Windows.Forms.Screen.PrimaryScreen.DeviceName;
      return this.CreateDisplayGraphics(deviceName);
    }

    public Graphics CreateDisplayGraphics(string deviceName)
    {
      IntPtr hDc = CreateDC(deviceName, null, null, IntPtr.Zero);
      return Graphics.FromHdc(hDc);
    }

    public void Release()
    {
      if (this.m_Hdc != IntPtr.Zero)
        ReleaseDC(IntPtr.Zero, this.m_Hdc);
    }

    public void Dispose()
    {
      this.Release();
    }//end method
  }//end class
}//end namespace

使い方はこんな感じ

var draw = new win32.DrawWindow();
using (var window = draw.CreateDisplayGraphics())
using (SolidBrush solid = new SolidBrush(Color.FromArgb(125, 255,0,0)))
using (Pen pen = new Pen(solid, 5f))
{
  try
  {
    var rects = cv.MatchTemplates(img, screenImg);
    foreach (var rect in rects)
    {
      window.DrawRectangle(pen, rect);
    }//end loop
  }
  catch (Exception ex)
  {
    Debug.Print(ex.Message);
    Debug.Print(ex.StackTrace);
  }
}//end  window graphics
draw.Release();

SynchronizationContext ctx = SynchronizationContext.Current;
ThreadPool.QueueUserWorkItem(_ =>
{
  //10秒待機
  Thread.Sleep(1000 * 10);
  ctx.Post(obj =>
  {
    draw.RefreshDesktop();
    draw.Dispose();
  }, null);
});//end thread
カテゴリー: 開発 タグ: パーマリンク