2016-06-27 14 views
0

他のウィンドウの上に別のアプリケーションを表示させる方法を見つけることが任されています(Always On Top)。 RetrieveProcesses()関数を使用してウィンドウタイトルを持つプロセスを取得できます。ユーザーが変更するプロセスを選択すると、アプリケーションはMakeProcessOnTopまたはMakeProcessNormalのいずれかを呼び出します。どちらの関数もメインアプリケーションのウィンドウを変更します。子供の修正を追加する前に、これは正しく機能しました。他のプロセスから子ウィンドウを取得するにはどうすればよいのですか?

私は子ウィンドウ(outlookの電子メールのような)では動作しないことを発見しましたので、私は子ウィンドウを処理する方法を見つけるために出発しました。以下のコードが書かれているように、それは子供の窓を乱してしまいます。子ウィンドウのハンドルポインタを取得しますが、子コントロールは取得しません。

public static class ProcessManagement 
{ 
    [DllImport("user32.dll", SetLastError = true)] 
    static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags); 

    [DllImport("user32.dll", SetLastError = true)] 
    static extern IntPtr SetFocus(IntPtr hWnd); 

    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow); 

    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    public static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); 

    static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); 
    static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2); 
    static readonly IntPtr HWND_TOP = new IntPtr(0); 
    static readonly IntPtr HWND_BOTTOM = new IntPtr(1); 

    public static IEnumerable<Process> RetrieveProcesses() 
    { 
     List<Process> returnList = new List<Process>(); 

     Process[] processArray = Process.GetProcesses(); 

     foreach (Process p in processArray) 
     { 
      if (!String.IsNullOrEmpty(p.MainWindowTitle)) 
      { 
       returnList.Add(p); 
      } 
     } 

     return returnList; 
    } 

    public static IntPtr GetProcessWindowHandle(int processId) 
    { 
     Process p = Process.GetProcessById(processId: processId); 
     return p.MainWindowHandle; 
    } 

    public static List<IntPtr> GetProcessChildWindowHandles(IntPtr parent) 
    { 
     List<IntPtr> result = new List<IntPtr>(); 
     GCHandle listHandle = GCHandle.Alloc(result); 
     try 
     { 
      EnumWindowsProc childProc = new EnumWindowsProc(EnumWindow); 
      EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle)); 
     } 
     finally 
     { 
      if (listHandle.IsAllocated) 
       listHandle.Free(); 
     } 
     return result; 
    } 

    private static bool EnumWindow(IntPtr handle, IntPtr pointer) 
    { 
     GCHandle gch = GCHandle.FromIntPtr(pointer); 
     List<IntPtr> list = gch.Target as List<IntPtr>; 
     if (list == null) 
     { 
      throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>"); 
     } 
     list.Add(handle); 
     // You can modify this to check to see if you want to cancel the operation, then return a null here 
     return true; 
    } 

    public static bool MakeProcessOnTop(IntPtr targetWindowHandle, bool targetChildren = true) 
    { 
     bool bReturn = true; 

     if (!ShowWindow(targetWindowHandle, ShowWindowCommands.Minimize)) 
     { 
      bReturn = false; 
     } 

     if (!ShowWindow(targetWindowHandle, ShowWindowCommands.Restore)) 
     { 
      bReturn = false; 
     } 

     if (!ShowWindow(targetWindowHandle, ShowWindowCommands.ShowNoActivate)) 
     { 
      bReturn = false; 
     } 

     if (!SetWindowPos(targetWindowHandle, HWND_TOPMOST, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE)) 
     { 
      bReturn = false; 
     } 

     if (targetChildren) 
     { 
      List<IntPtr> childProcesses = GetProcessChildWindowHandles(targetWindowHandle); 

      foreach(IntPtr iPtr in childProcesses) 
      { 
       MakeProcessOnTop(iPtr, false); 
      } 
     } 

     return bReturn; 
    } 
    public static bool MakeProcessNormal(IntPtr targetWindowHandle, bool targetChildren = true) 
    { 
     bool bReturn = true; 

     if (!ShowWindow(targetWindowHandle, ShowWindowCommands.Minimize)) 
     { 
      bReturn = false; 
     } 

     if (!ShowWindow(targetWindowHandle, ShowWindowCommands.Restore)) 
     { 
      bReturn = false; 
     } 

     if (!ShowWindow(targetWindowHandle, ShowWindowCommands.ShowNoActivate)) 
     { 
      bReturn = false; 
     } 

     if (!SetWindowPos(targetWindowHandle, HWND_NOTOPMOST, 0, 0, 0, 0, SetWindowPosFlags.SWP_NOACTIVATE | SetWindowPosFlags.SWP_NOMOVE | SetWindowPosFlags.SWP_NOSIZE)) 
     { 
      bReturn = false; 
     } 

     if (targetChildren) 
     { 
      List<IntPtr> childProcesses = GetProcessChildWindowHandles(targetWindowHandle); 

      foreach (IntPtr iPtr in childProcesses) 
      { 
       MakeProcessNormal(iPtr, false); 
      } 
     } 

     return bReturn; 
    } 
} 
+1

これらの投稿を見ましたか?[最初のリンク](http://stackoverflow.com/questions/2531828/how-to-enumerate-all-windows-belonging-to-a-particular-process-using-net ) - [2番目のリンク](http://stackoverflow.com/questions/2238609/get-handles-to-all-windows-of-a-process) –

+0

私は成功なしでEnumThreadWindowsを試しました。 –

答えて

1

Always On Topは、トップレベルのウィンドウまたはおそらくMDIの子にのみ意味があります。

Zオーダーを操作して子ウィンドウを表示することはできますが、戻す方法は明確に定義されていません。

+0

私もEnumThreadWindowsを使用しようとしましたが、成功していないので、私がしようとしていることはうまくサポートされていないと思われ、おそらく意味をなさないでしょう。 –

関連する問題