1

我正在尝试实现一个按钮命令,该命令在用户第一次单击该按钮时启动一个新的 WPF 应用程序,然后(当用户再次单击该按钮时)将其发送到前台(如果它已经在运行)。整个事情正在运行.Net v4.0

当启动的进程是一个普通的 WPF 应用程序时,我尝试做的工作正常,但如果启动的 WPF 应用程序有启动画面,它就不会很好。问题是SetForegroundWindow失败了,因为在这种特定情况下我无法检索正确的窗口句柄。你能建议一个修复或解决方法吗?假设您可以修改启动器和已启动 WPF 的源。

启动器视图模型中的相关代码

   private void ClaimRptLogic()
    {
        if (ClaimRptHandle != IntPtr.Zero)
        {
            ShowWindow(ClaimRptHandle, SW_RESTORE);
            LaunchState = SetForegroundWindow(ClaimRptHandle)? "" : "can't set to foreground";
            return;
        }

        Process rpt = new Process();
        rpt.StartInfo = new ProcessStartInfo()
        {
            WorkingDirectory = ConfigurationManager.AppSettings["ClaimRptPath"],
            FileName = ConfigurationManager.AppSettings["ClaimRptexe"]
        };
        rpt.Start();
        BackgroundWorker bg = new BackgroundWorker();
        bg.DoWork += new DoWorkEventHandler((o, e) => {
            rpt.WaitForExit();
        });
        bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler((o, e) => {
            ClaimRptHandle = IntPtr.Zero;
            LaunchState = "ClaimRpt closed";
        });
        bg.RunWorkerAsync();
        Thread.Sleep(3000);
        ClaimRptHandle = rpt.MainWindowHandle;
    }
4

2 回答 2

0

只是另一种选择,如果您无法修改已启动的 WPF 应用程序,但您知道其主窗口的标题标题,当然,除了进程 ID。

在这种情况下,后台搜索将是

LaunchedHandle = rpt.MainWindowHandle;
mainWin = rpt.MainWindowHandle;
BackgroundWorker bgTitle = new BackgroundWorker();
bgTitle.DoWork += new DoWorkEventHandler((o, e) => {
while (!rpt.HasExited)
    {

        LaunchedHandle = MainWindowHandle(rpt);
        Thread.Sleep(500);
    }
    Debug.WriteLine("Process exited!");
});
bgTitle.RunWorkerAsync();

使用基于进程 ID 的过滤器

private IntPtr MainWindowHandle(Process rpt)
{
    EnumWindowsProc ewp = new EnumWindowsProc(EvalWindow);
    EnumWindows(ewp, new IntPtr(rpt.Id));
    return mainWin;
}

和一个测试标题标题的回调(在这个例子中是Launched

private bool EvalWindow(IntPtr hWnd, IntPtr lParam)
{
    int procId;
    GetWindowThreadProcessId(hWnd, out procId);
    if (new IntPtr(procId) != lParam)
    {
        return true;
    }
    StringBuilder b = new StringBuilder(50);
    GetWindowText(hWnd, b, 50);
    string test = b.ToString();
    if (test.Equals("Launched"))
    {
        mainWin = hWnd;
    }
    return true;
}
于 2017-03-18T23:11:04.977 回答
0

假设您可以修改启动器和已启动 WPF 的源。

基于这个假设,我可以在Loaded启动 WPF 应用程序的情况下确定正确的句柄,并使用命名管道将其发送回启动器。

private void Window_Loaded(object sender, RoutedEventArgs e)
{   
    var callback = new WindowInteropHelper(this).Handle;
    BackgroundWorker bg = new BackgroundWorker();
    bg.DoWork += (s, a) =>
    {
        WritePipe("at loaded evt: " + callback);
    };
    bg.RunWorkerAsync();
}

private void WritePipe(string line)
{
    using (NamedPipeServerStream server = 
        new NamedPipeServerStream(Environment.UserName, PipeDirection.InOut))
    {
        server.WaitForConnection();
        using (StreamWriter sw = new StreamWriter(server))
        {
            sw.WriteLine(line);
        }
    }
}

并从启动器的另一个后台工作人员中的同一命名管道中读取正确的窗口句柄

bg.RunWorkerAsync();
Thread.Sleep(3000);
if (rpt.HasExited)
{
    return;
}
LaunchedHandle = rpt.MainWindowHandle;
BackgroundWorker bgPipe = new BackgroundWorker();
bgPipe.DoWork += new DoWorkEventHandler((o, e) => {
    while (!rpt.HasExited)
    {
        string testHandle = ReadPipe();
        if (testHandle.StartsWith("at loaded evt: "))
        {
            Debug.WriteLine(testHandle);
            Debug.WriteLine("CallBack from Launched Process!");
            var handle = testHandle.Replace("at loaded evt: ","");
            LaunchedHandle = new IntPtr(int.Parse(handle));
            return;
        }
        LaunchedHandle = rpt.MainWindowHandle;
        Thread.Sleep(500);
    }
    Debug.WriteLine("Process exited!");
});
bgPipe.RunWorkerAsync();
CanLaunchCmd = true;

private string ReadPipe()
{
    string line = "";
    using (NamedPipeClientStream client =
        new NamedPipeClientStream(".", Environment.UserName, PipeDirection.InOut))
    {
        client.Connect();
        using (StreamReader sr = new StreamReader(client))
        {
            line = sr.ReadLine();
        }
        return line;
    }
}

当然,我对不同的想法持开放态度。

于 2017-03-18T18:27:05.837 回答