簡體   English   中英

如何從其他進程而不是子控件中獲得子窗口?

[英]How do I get child windows from another process and not child controls?

我的任務是找到一種方法,使另一個應用程序顯示在其他窗口的頂部(始終在頂部)。 我可以使用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;
    }
}

Always On Top僅對於頂級窗口或MDI子級才有意義。

您可以通過操縱Z順序來引發子窗口,但如何將其放回尚無明確定義。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM