2016-06-26 16 views
1

メインウィンドウエリア外に描画する必要があるアプリケーションを作成しています。フォームの外の何かが再描画されると、それが呼び出されていないので、Paintイベントにコードを配置するためには不向きな場所であるしかしフォームエリア外に描画するときの再描画方法

[DllImport("User32.dll")] 
public static extern IntPtr GetDC(IntPtr hwnd); 
[DllImport("User32.dll")] 
public static extern void ReleaseDC(IntPtr hwnd, IntPtr dc); 

IntPtr desktopPtr = GetDC(IntPtr.Zero); 
Graphics g = Graphics.FromHdc(desktopPtr); 

g.DrawLine(Pens.White, 0, 0, Screen.FromControl(this).WorkingArea.Width, Screen.FromControl(this).WorkingArea.Height); 

g.Dispose(); 
ReleaseDC(IntPtr.Zero, desktopPtr); 

:私はすでに、実際に描画を行うためにコーディングする必要があります。だから私の質問は、どこにこのコードを置くことができるので、画面の一部が再描画されるたびに呼び出されるということですか?

+1

自分が所有していないため、実際にデスクトップウィンドウに直接ペイントしないでください。それをしたい場合は、 'WS_EX_NOACTIVATE'でウィンドウを作成し、そのウィンドウに描画する必要があります。 (あなたは 'SetWindowLongPtr'と' SetWindowPos'を呼び出して、winformsフォームのウィンドウスタイルを変更することができます) – theB

+0

このような意味になります:http://stackoverflow.com/a/6823357/3016335 – carefulnow1

+0

はい、それはチケットです。そうすることで、デスクトップが何をしているのか気にする必要はなく、無効化された四角形があなたの希望する領域であるかどうかを調べる必要はありません。私はこれが何らかのデスクトップウィジェットのためのものだと思いますか? – theB

答えて

2

コンテンツを画面に表示する場合は、常にそのコンテンツを保持するウィンドウを作成する必要があります。デスクトップ(自分が所有していないウィンドウ)でペイントするのは悪い考えです。

解決策は、拡張スタイルWS_EX_NOACTIVATEを使用してウィンドウを作成し、WM_PAINTメッセージに対する応答として描画することです。 WinFormsアプリケーションの場合、ランタイムはWM_PAINTを取得したときにForm.OnPaintを呼び出して、そのイベントを処理してそこでペイントすることができます。証明するために:

[DllImport("User32.dll")] 
private static extern IntPtr GetWindowLong(IntPtr hWnd, int index); 
[DllImport("User32.dll")] 
private static extern int SetWindowLong(IntPtr hWnd, int index, IntPtr value); 
[DllImport("User32.dll")] 
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); 

static readonly IntPtr HWND_BOTTOM = new IntPtr(1); 

private const int WS_EX_NOACTIVATE = 0x08000000; 
private const int GWL_EXSTYLE = -20; 

private const uint SWP_NOMOVE = 0x0002; 
private const uint SWP_NOSIZE = 0x0001; 
private const uint SWP_NOZORDER = 0x0004; 
private const uint SWP_FRAMECHANGED = 0x0020; 
private const uint StyleUpdateFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED; 

public Form1() 
{ 
    InitializeComponent(); 
    this.FormBorderStyle = FormBorderStyle.None; 
    this.Paint += Form1_Paint; 
    this.Shown += Form1_Shown; 
} 

private void Form1_Shown(object sender, EventArgs e) 
{ 
    IntPtr currentStyle = GetWindowLong(this.Handle, GWL_EXSTYLE); 
    int current = currentStyle.ToInt32(); 
    current |= WS_EX_NOACTIVATE; 
    SetWindowLong(this.Handle, GWL_EXSTYLE, new IntPtr(current)); 
    SetWindowPos(this.Handle, IntPtr.Zero, 0, 0, 0, 0, StyleUpdateFlags); 
} 

private void Form1_Paint(object sender, PaintEventArgs e) 
{ 
    e.Graphics.Clear(Color.Black); 
} 

を、あなたのウィンドウがトップにフロートしたい場合はtrueにフォームのTopMostプロパティを設定します。あなたはあなたの窓はZ-注文(TopMostの正反対)の底に固執したい場合は、フォームに次のロジックを追加します。

private struct WINDOWPOS 
{ 
    public IntPtr hwnd; 
    public IntPtr hwndInsertAfter; 
    public int x; 
    public int y; 
    public int cx; 
    public int cy; 
    public uint flags; 
} 
private const int WM_WINDOWPOSCHANGING = 0x0046; 
protected override void WndProc(ref Message m) 
{ 
    if (m.Msg == WM_WINDOWPOSCHANGING) 
    { 
     if (m.LParam != IntPtr.Zero) 
     { 
      WINDOWPOS posInfo = Marshal.PtrToStructure<WINDOWPOS>(m.LParam); 
      posInfo.hwndInsertAfter = HWND_BOTTOM; 
      Marshal.StructureToPtr(posInfo, m.LParam, true); 
      m.Result = IntPtr.Zero; 
      return; 
     } 
    } 
    base.WndProc(ref m); 
} 

これはWM_WINDOWPOSCHANGINGウィンドウメッセージを処理し、そしてから窓を防止ウィンドウマネージャーにZ軸を下に置くように指示することでZオーダーで上に移動します。

+0

これは44行目で 'EntryPointNotFound'例外を発生させます:http://i.imgur.com/JVf1CEB.png – carefulnow1

+0

32 bit ...コードを少し変更する必要があります。アップデートを参照してください。 – theB

+0

ああ、感謝しなかった。私はx64でビルドするためにプロパティを変更し、完全に動作します。ありがとう! – carefulnow1

関連する問題