2016-06-27 7 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) - [Вторая ссылка] (http://stackoverflow.com/questions/2238609/get-handles-to-all-windows-of-a-process) –

+0

Я пробовал EnumThreadWindows без успеха. –

ответ

1

Always On Top имеет смысл только для окон верхнего уровня или, возможно, для детей MDI.

Вы можете поднять дочернее окно, манипулируя заказом Z, но он не совсем точно определяет, как вернуть его.

+0

Я также попытался использовать EnumThreadWindows без каких-либо успехов, поэтому я предполагаю, что то, что я пытаюсь сделать, плохо поддерживается и, вероятно, не имеет смысла. –

 Смежные вопросы

  • Нет связанных вопросов^_^