【问题标题】:System.Diagnostics.Process.Start() strange behaviourSystem.Diagnostics.Process.Start() 奇怪的行为
【发布时间】:2012-06-06 19:57:38
【问题描述】:

我有一个使用 Process.Start(string Filename) 打开文件的应用程序。此方法重载将导致系统根据文件扩展名调用适当的应用程序。就我而言,它通常是 WORD、PPT、PDF、JPG 等……某种类型的可查看文档。最终,我需要启动进程,然后在应用程序中我需要对 MainWindowHandle 值做一些事情。

我发现至少三种不同的情况会导致 Process.Start(string filename) 以不同的方式返回...

对于下面的第一种和第二种情况,假设我要打开两个 .pdf 文件(但 如果我打开两个 .ppt 或两个 .doc 文件,似乎会发生同样的事情 嗯)...

案例 1: 如果 AcroRd32 没有运行,我会执行类似的操作..

Process p = Process.Start("yada.pdf");
p.WaitForInputIdle();
p.Refresh();

事情按预期工作。 p.MainWindowHandle 值已正确填充。 这种情况没问题。

案例 2: 现在假设在调用 Process.Start() AcroRd32 时已经 在以前打开的 pdf 文件上运行。现在事情变得很奇怪。参考 下面的代码(为清楚起见删除了一些错误检查逻辑),在调用之后 对于 Process.Start(),p.MainWindowHandle 的值为零(即使 窗口已创建),并且 p.MainWindowTitle 为空。然后我睡1秒 并且句柄仍然为零,但现在填充了主窗口标题(甚至 虽然我没有在睡眠后调用 p.Referesh() 。每个跟踪语句 在运行时打印在 cmets 中具有“

Process p = Process.Start("SomeFileName.pdf");
p.WaitForInputIdle();
p.Refresh();
if (p.MainWindowHandle == 0)
    DebugTrace("MainWindowHandle is zero, why??");   //<<<<
if (p.MainWindowTitle.Length == 0)
    DebugTrace("MainWindowTitle is null");           //<<<<
Thread.Sleep(1000);
if (p.MainWindowHandle == 0)
    DebugTrace("MainWindowHandle is still zero.");   //<<<<
if (p.MainWindowTitle.Length == 0)
    DebugTrace("MainWindowTitle is null");
else
    DebugTrace("MainWindowTitle: " + p.MainWindowTitle);  //<<<<

我确信这与 AcroRd32 已经 正在运行,但我无法控制它,我确实需要获得价值 p.MainWindowHandle。任何想法如何处理这个?

案例 3: 然后进入第三种情况:在某些情况下, Process.Start() 将返回 null 即使它成功打开文件。我发现情况就是这样 .jpg 文件,但我确信这仅取决于应用程序 分配给 .jpg 扩展名。 Process.Start("file.jpg") 返回 null 如果应用程序是“Windows 照片查看器”但如果我将其更改为 “绘制”它不返回 null。那是怎么回事?我怎样才能得到 那么处理呢?

好的,一切都完成了,抱歉细节,但希望我能解释一下情况 我正在努力解决!

【问题讨论】:

  • 出于好奇,您需要对 MainWindowHandle 做什么?也许有更好的方法!
  • 我需要跟踪窗口的位置/大小,我目前正在使用 GetWindowRect(),它将窗口句柄作为输入。由于 Process.Start() 的限制,我还必须根据知道文件名和有时知道进程名来“猜测”活动窗口是什么。理想情况下,我不想猜测! :-)

标签: c# process.start


【解决方案1】:

您不能依赖 Process.Start 返回的 MainWindowHandle。正如您所提到的,当文件被已经运行的应用程序打开时,它不会返回它。从 Windows Vista 开始,MS 添加了 ReStart Manager,这是一个新的 api,可以在给定文件上提供锁定进程。 https://msdn.microsoft.com/en-us/magazine/cc163450.aspx

我解决这个问题的方法是尝试 Process.Start 的 MainWindowHandle 和锁定句柄 ReStart 管理器返回。有一个来自 MSDN 杂志的示例代码。 https://github.com/andrewchaa/PopOpen/blob/master/Pop.Cs/InUseDetection.cs

【讨论】:

    【解决方案2】:

    我怀疑 windows 使用 acroRd32 启动一个新进程,然后将给定的文件路径传递给正在运行的实例,然后关闭。

    这通常是为了避免程序的多个实例这样做......

    【讨论】:

    • 明白了,我确信 powerpoint、word 等也会发生同样的事情......问题是我需要使用此代码获取在这些情况下似乎不可用的窗口句柄。
    • 使用 GetProcesses 检查 AcroRd32 是否存在并从那里检索主句柄 msdn.microsoft.com/en-us/library/…
    • 不能这样做,因为我真的不知道会启动什么进程。我在上面的示例中使用了 acroRd32,但它可以是 word 文档、powerpoint、jpeg,以及与文件扩展名挂钩的任何应用程序。上面不清楚的一件事是传递给 Process.Start() 的字符串是任意的。
    • 我假设你从Process.Start()返回的进程被填满了?不能搜索系统上是否还存在同一个进程?
    • 这就是我目前所做的(为了简洁起见,上面没有提到,因为我希望有一种更优雅的方式来做到这一点)。如果 Process.Start() 返回 MainWindowHandle 成员为零的进程,我使用 ProcessName 成员(在这种情况下似乎始终可用)以及文件名来解析 EnumWindows() 的结果以进行有根据的猜测在实际的窗口是什么。请注意,这仍然不能解决 Process.Start() 返回 null 的情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    • 2015-07-20
    • 2010-10-03
    • 2021-07-12
    • 2013-10-04
    相关资源
    最近更新 更多