C#最小化窗口没有通过调用System.Diagnostics.Process.GetProcesses()返回

sap*_*ket 8 c# windows user32

我正在尝试找到一个最小化的窗口并显示它.

该程序可以从三星下载,标题为"SideSync".要完全复制我的问题,您需要安装此问题并使用三星手机插入计算机.

以下是完全配置和运行的屏幕截图:

在此输入图像描述

观察到有两个窗口,A和B.我使用一个名为Microsoft Inspect的工具来确定两个程序窗口是正常的窗口.他们没有孩子的父母关系.但是,当我启动SideSync时,只显示窗口A. 然后我必须单击"电话屏幕",然后出现窗口B(除了窗口A).这可能是解决这个问题的线索吗?我们会看到.

以下是Microsoft Inspect中出现的两个窗口:

在此输入图像描述

两个窗口都有窗口标题.使用下面的代码我可以检索Process窗口(这是我的目标).

服务器代码:

public static Process GetProcessByWindowTitle(string windowTitleContains)
{
    foreach (var windowProcess in GetWindowProcesses())
        if (windowProcess.MainWindowTitle.Contains(windowTitleContains))
            return windowProcess;

    return null;
}
Run Code Online (Sandbox Code Playgroud)

然而,一些奇怪的行为正在发生.GetProcessByWindowTitle()将返回一个但不是两个进程.我假设因为有两个窗口必须有两个进程.

Process则返回依赖于这是我和我的鼠标点击最后一个窗口.

例如,如果我上次点击了窗口A; 然后GetProcessByWindowTitle("SideSync")将返回Process,但随后GetProcessByWindowTitle("SAMSUNG")将返回void.

...反之亦然,如果我上次点击窗口B,GetProcessByWindowTitle("SideSync")将返回一个void,但随后GetProcessByWindowTitle("SAMSUNG")将返回Process.

客户代码:

[Ignore("Requires starting SideSync and clicking one of the windows. Only the last clicked will return a Process.")]
[Test]
public void NonMinimizedWindowProcessIsDetected()
{

    Process p1 = Windows.GetProcessByWindowTitle("SAMSUNG");

    if(p1==null) { Console.WriteLine("SAMSUNG process is null.");}
    else { Console.WriteLine("SAMSUNG process detected.");}

    Process p2 = Windows.GetProcessByWindowTitle("SideSync");

    if (p2 == null) { Console.WriteLine("SideSync process is null."); }
    else { Console.WriteLine("SideSync process detected."); }
}
Run Code Online (Sandbox Code Playgroud)

我的目标是展示Window B.我的问题是,这只有在我最后点击它时才有可能,这会产生不必要的依赖.我希望能够独立于任何点击顺序显示窗口B.

Mar*_*far 11

我花了一些时间试图重现你的问题.根据我的分析(花了一些时间,因为我没有让SideSync正确运行;-))只存在一个名为SideSync.exe的进程,它承载多个窗口.

我猜你的方法中的"缺陷"是你试图通过获取进程MainWindowTitle.但是,如果您使用以下代码段,您将看到MainWindowTitle更改取决于该进程中当前活动的窗口.

while (true)
{
    var processes = Process.GetProcesses();

    foreach (var process in processes)
    {
        if (process.ProcessName != "SideSync")
            continue;

        Console.WriteLine($"{process.ProcessName}, {process.MainWindowTitle}, {process.MainWindowHandle.ToString()}");
    }

    Thread.Sleep(1000);
}
Run Code Online (Sandbox Code Playgroud)

在我的情况下,MainWindowTitle不同标题之间的变化,如:

SideSync, SideSync, 1313728
SideSync, SideSync, 1313728
SideSync, SideSync, 1313728
SideSync, SideSync, 1313728
SideSync, SideSync, 1313728
SideSync, Notifier, 1903168
SideSync, Notifier, 1903168
SideSync, Notifier, 1903168
SideSync, Notifier, 1903168
SideSync, Notifier, 1903168
SideSync, Notifier, 1903168
SideSync, Notifier, 1903168
SideSync, Notifier, 1903168
SideSync, Notifier, 1903168
SideSync, Samsung Galaxy S7, 3082852
SideSync, Samsung Galaxy S7, 3082852
SideSync, Samsung Galaxy S7, 3082852
SideSync, Samsung Galaxy S7, 3082852
SideSync, ToolTip, 3148196
SideSync, Samsung Galaxy S7, 3082852
SideSync, Samsung Galaxy S7, 3082852
SideSync, Samsung Galaxy S7, 3082852
SideSync, Samsung Galaxy S7, 3082852
SideSync, ToolTip, 3148196
SideSync, ToolTip, 3148196
SideSync, Samsung Galaxy S7, 3082852
SideSync, Samsung Galaxy S7, 3082852
SideSync, SideSync, 1313728
SideSync, SideSync, 1313728
SideSync, SideSync, 1313728
SideSync, SideSync, 1313728
SideSync, SideSync, 1313728
SideSync, SideSync, 1313728
SideSync, SideSync, 1313728
SideSync, SideSync, 1313728
Run Code Online (Sandbox Code Playgroud)

正如您所看到的那样,输出还包括NotifierToolTip等标题,这些标题出现在Notification Window时,或者您将鼠标移到SideSync应用程序中的Icon上.从输出中可以进一步看出,MainWindowHandle活动窗口当然也会改变.

因此,在我看来,您只需要使用其他方式获取SideSync进程Process.GetProcessesByName("SideSync").

我希望这有帮助 ;-)

更新:

根据OP的评论,他需要一种方法来打开最后一次打开的SideSync进程的一个特定窗口.为了实现这一点,第一步是找到属于SideSync进程的窗口的相应窗口句柄.

我在cREcker的答案代码上有以下代码,cREcker根据资源获取所有打开窗口的列表.

以下类的GetOpenWindowsByProcessId方法允许获取属于指定进程ID的所有窗口的句柄.

public static class OpenWindowGetter
{
    public static IDictionary<string, IntPtr> GetOpenWindowsByProcessId(int processId)
    {
        IntPtr shellWindow = GetShellWindow();
        Dictionary<string, IntPtr> windows = new Dictionary<string, IntPtr>();

        EnumWindows(delegate (IntPtr hWnd, int lParam)
        {
            uint ownerProcessId;
            GetWindowThreadProcessId(hWnd, out ownerProcessId);

            if (ownerProcessId != processId)
                return true;

            if (hWnd == shellWindow)
                return true;

            if (!IsWindowVisible(hWnd))
                return true;

            int length = GetWindowTextLength(hWnd);

            if (length == 0)
                return true;

            StringBuilder builder = new StringBuilder(length);
            GetWindowText(hWnd, builder, length + 1);
            windows[builder.ToString()] = hWnd;

            return true;

        }, 0);

        return windows;
    }

    private delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);

    [DllImport("USER32.DLL")]
    private static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam);

    [DllImport("USER32.DLL")]
    private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

    [DllImport("USER32.DLL")]
    private static extern int GetWindowTextLength(IntPtr hWnd);

    [DllImport("USER32.DLL")]
    private static extern bool IsWindowVisible(IntPtr hWnd);

    [DllImport("USER32.DLL")]
    private static extern IntPtr GetShellWindow();

    [DllImport("user32.dll", SetLastError = true)]
    private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
}
Run Code Online (Sandbox Code Playgroud)

另外我们需要一种"显示"窗口的方法.

private const int SW_SHOWNORMAL = 1;
private const int SW_SHOWMINIMIZED = 2;
private const int SW_SHOWMAXIMIZED = 3;

[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
Run Code Online (Sandbox Code Playgroud)

有了这些知识,我们现在可以编写如下代码(可以肯定地以千种方式进行优化):

private static void ShowPhoneScreenWindow()
{
    const string PROCESSNAME = "sidesync";
    const string WINDOWTITLE = "samsung";

    var process = Process.GetProcessesByName(PROCESSNAME).FirstOrDefault();

    if (process == null)
        throw new InvalidOperationException($"No process with name {PROCESSNAME} running.");

    var windowHandles = OpenWindowGetter.GetOpenWindowsByProcessId(process.Id);
    IntPtr windowHandle = IntPtr.Zero;

    foreach (var key in windowHandles.Keys)
        if (key.ToLower().StartsWith(WINDOWTITLE))
        {
            windowHandle = windowHandles[key];
            break;
        }

    if (windowHandle == IntPtr.Zero)
        throw new InvalidOperationException($"No window with title {WINDOWTITLE} hosted.");

    ShowWindowAsync(windowHandle, SW_SHOWNORMAL);
}
Run Code Online (Sandbox Code Playgroud)