找不到MainWindowHandle的过程 [英] Trouble finding MainWindowHandle of process

查看:127
本文介绍了找不到MainWindowHandle的过程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,

我有一个专用于启动进程并检查窗口何时打开的线程.我已经尝试过使用WaitForInputIdle,它在理论上应该可以工作,但是几乎就像被跳过了一样-无论如何它都是有用的.

因此,我尝试使用Process.MainWindowHandle方法检测何时有MainWindowHandle,但是在启动进程后,我收到一个错误:没有与此对象相关联的进程".但是仍然显示了已启动过程的窗口-向我保证正在运行一个过程,并且出现了一些问题.我已经给出了以下代码:

Hi All,

I have a thread that is solely dedicated to starting a process and checking when the window has opened. I have tried using the WaitForInputIdle which in theory should work but it is almost as if it is skipped - it is about as useful anyway.

So I have tried to detect when there is a MainWindowHandle using the Process.MainWindowHandle method, however after starting the process I am receiving an error: "No process associated with this object". But the window of the started process still appears - assuring me that there is a process running and something fishy is up. I''ve given the code below:

Process proc = new Process();
proc.StartInfo.FileName = link;
proc.StartInfo.UseShellExecute = true;

ThreadPool.QueueUserWorkItem(delegate
{
   proc.Start();
   proc.WaitForInputIdle();
   try
   {
      while(proc.MainWindowHandle == IntPtr.Zero)
      {
      }
   }
   catch(Exception e)
   {
      MessageBox.Show(e.Message);
   }
});



有什么帮助吗?在此先感谢!



Any help? Thanks in Advance!

推荐答案

如果您正在启动控制台应用程序,则此方法将无效.控制台应用程序永远不会具有MainWindowHandle.

如果那是您要尝试做的.您从未在帖子中真正指定此内容.

没有获取控制台应用程序的窗口句柄的函数调用或方法.可以这样做,但是您必须P/调用FindWindow函数以查找控制台窗口标题.
This won''t work if you''re launching a console application. Console applications will never have a MainWindowHandle.

If that''s what you''re trying to do. You never really specified this in your post.

There is no function call or method to get the window handle of a console app. It''s possible to do, but you have to P/Invoke the FindWindow function to look for the console windows title.


如果Start方法返回false,则没有可用的进程.我唯一观察到的情况是UseShellExecute为true并且StartInfo.FileName是快捷方式,即something.lnk.

我不知道这是否是您的情况,因为我看到您将一个名为"link"的变量分配给StartInfo.FileName.

解决方案是将快捷方式的目标分配给StartInfo.FileName.

艾伦.
If the Start method returns false then there is no process available. The only time I have observed this is when UseShellExecute was true and StartInfo.FileName was a shortcut, i.e. something.lnk.

I wonder if this is your situation as I see that you assign a variable called ''link'' to StartInfo.FileName.

The solution would be to assign the target of the shortcut to StartInfo.FileName.

Alan.


请参阅我的评论.首先,您需要确保该应用程序作为一个单独的进程启动,最终将显示Windowed应用程序的某些主窗口.不确定它可以是常规系统控制台.

鉴于以上我的评论,请尝试以下操作:
Please see my comments on what it can be. First of all, you need to be sure that the application started as a separate process will eventually show some main window of the Windowed application; not sure it can be the regular system console.

In view of my comments above, try this:
Process proc = new Process();
proc.StartInfo.FileName = link;
proc.StartInfo.UseShellExecute = false;
// proc.StartInfo.UseShellExecute = true; // not helpful, in most cases should be false, please see above
proc.Start(); // why not right here? it's not a blocking call, spawns a separate process

ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback( (state) => {
   proc.WaitForInputIdle(); // no need
   while (true) {
       try {
           IntPtr handle = proc.MainWindowHandle;
           // do something with the handle, see below
           return;
       } catch (System.InvalidOperationException) {
           // do something (log or whatever), but not re-throw
           // attention! this is a rare case when you can block distribution of exception; "don't repeat at home" :-)
           System.Threading.Thread.Sleep(0);
       } catch (System.System.NotSupportedException){
           // do something (log or whatever), but not re-throw
           // attention! this is a rare case when you can block distribution of exception; "don't repeat at home" :-)
           System.Threading.Thread.Sleep(0);
       }
   } //loop
}));



请查看,注意例外:
http://msdn.microsoft.com/en-us/library/system.diagnostics. process.aspx [^ ],
http://msdn.microsoft.com/en-us/library/8d7363e2.aspx [ ^ ],
http://msdn.microsoft.com/en-us/library/system. diagnostics.process.mainwindowhandle.aspx [ ^ ].

这应该解释为什么UseShellExecute = false:
http://msdn.microsoft.com/en-us/library/system. diagnostics.processstartinfo.useshellexecute.aspx [ ^ ].

这还不是全部.您应该组织不同线程之间正确的数据交换.您共享一个变量proc,并且可能需要共享至少一个对象,该对象是单独进程主窗口的句柄(如果找到).至于proc,您所做的不是互锁的,因此值得怀疑,但我认为应该在这种特定情况下可以工作.但是,如果您稍加修改此代码,则可能使其非常危险.为了远离罪恶,您应该将所有共享对象互锁.模式很简单:创建那些对象字段,添加这些字段支持的属性并使用lock语句.这是模式:



Please see, pay attention for exceptions:
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx[^],
http://msdn.microsoft.com/en-us/library/8d7363e2.aspx[^],
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.mainwindowhandle.aspx[^].

This should explain why UseShellExecute = false:
http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.useshellexecute.aspx[^].

This is not all. You should organize proper exchange of data between different threads. You share one variable, proc and probably need to share at least one more object, the handle to the separate process''s main window, if found. As to proc, what you have done is not interlocked, so it''s questionable, but I think is should work in this specific case. However, should you modify this code slightly, you can make it extremely dangerous. To stay away from the sin, you should interlock all shared object. The schema is simple: make those objects fields, add properties backed by these fields and use the lock statement. Here is the schema:

IntPtr handle;
object handleLock = new object();

IntPtr Handle {
    get { lock(handleLock) { return handle; } }
    set { lock(handleLock) { handle = value; } }
}



不同的对象可以与单独的锁定对象互锁,也可以与同一对象互锁:这取决于您从什么对象中锁定什么.您需要考虑适当的状态图来决定.除非您设计"死锁,否则共享锁的速度可能会更慢,但可以提供更多保护,而死锁只能通过lock语句来实现.

如果使用协作方法,则等待池线程完成的标准也一样.如果仅在阻塞调用中等待它,则没有额外线程的好处.您可以使用 lazy 方法:仅在即将使用句柄时等待线程完成(Thread.Join).请参阅:
http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx [ ^ ],
http://msdn.microsoft.com/en-us/library/95hbf2ta.aspx [ ^ ],
http://msdn.microsoft.com/en-us/library/6b1kkss0.aspx [ ^ ],
http://en.wikipedia.org/wiki/Lazy_evaluation [如何将ref参数传递给线程 [ ^ ],
启动后更改线程(生产者)的参数 [ ^ ](带锁的那个).

最后,我应该告诉您,使用单独流程的整个想法是非常可疑的:流程之间是很好隔离的.您通过主窗口句柄控制另一个进程的方法受到限制;它很难以任何可靠的方式进行维护.另外,这是Windows并非Windows而是在单进程DOS上运行时创建的Windows特定的IPC怪异方式.这些技巧不是可移植的,它们不能在其他任何通过命令行实现CLI的系统上运行,例如通过Mono.
( http://en.wikipedia.org/wiki/Common_Language_Infrastructure [ http://en.wikipedia.org/wiki/Mono_%28software%29 [ ^ ],
http://www.mono-project.com/Main_Page [
祝你好运,

—SA



Different objects can be interlocked with separate lock object or with the same: it depends what do you lock from what. You need to consider appropriate state diagram to decide. Shared lock can be slower but protect more, unless you "design" a deadlock, which is not likely with just the lock statements.

Same thing goes about the criterion for wait for completion of the pooled thread, if you use collaborative approach. If you simply wait for it in the blocking call, there are no benefits of an extra thread. You can use lazy approach: wait for the thread completion (Thread.Join) only when a handle is about to be used. Please see:
http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx[^],
http://msdn.microsoft.com/en-us/library/95hbf2ta.aspx[^],
http://msdn.microsoft.com/en-us/library/6b1kkss0.aspx[^],
http://en.wikipedia.org/wiki/Lazy_evaluation[^].

You can greatly improve and simplify inter-thread communications if you use my pattern of the thread wrapper. Please see my past answers with the code and explanations:
How to pass ref parameter to the thread[^],
change paramters of thread (producer) after it started[^] (this one with lock).

Finally, I should tell you that the whole idea of using a separate process is very questionable: processes are well isolated. You control of another process via main windows handle is limited; its hard to maintain in any reliable way. Also, this is a weird Windows-specific way of IPC created when Windows was not an operating system but worked over the single-process DOS. Such tricks are not portable, they won''t work on any other system where CLI is implemented, for example, via Mono.
(http://en.wikipedia.org/wiki/Common_Language_Infrastructure[^],
http://en.wikipedia.org/wiki/Mono_%28software%29[^],
http://www.mono-project.com/Main_Page[^].)

The best way of integration is no integration. If you want to use collaboration between different process, the other process should be designed for it. One example, albeit not most reasonable on, is automation interfaces. Ideally, it should be a library, so you could use it "in-proc". I do understand: sometimes you don''t need better choice. But it''s important to understand: then, it''s a bad choice.

Good luck,

—SA


这篇关于找不到MainWindowHandle的过程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆