简体   繁体   English

如何从其 Win32 句柄中获取 System.Windows.Form 实例?

[英]How do I get a System.Windows.Form instance from its Win32 handle?

The following code implements a simple singleton that ensures only 1 instance of my application can be run.下面的代码实现了一个简单的 singleton,它确保我的应用程序只有一个实例可以运行。 However, if another instance is started, I need to be able to grab that instance's command-line arguments, pass them to the initial instance, then terminate the second instance.但是,如果启动另一个实例,我需要能够获取该实例的命令行 arguments,将它们传递给初始实例,然后终止第二个实例。

The issue comes in when I'm attempting to get hold of the first instance of the application.当我试图获取应用程序的第一个实例时,问题就出现了。 Once I've found the handle of that instance's main form, I pass it to the Control.FromHandle() method, expecting to get back a MainForm .一旦我找到了该实例的主窗体的句柄,我将它传递给Control.FromHandle()方法,期望得到一个MainForm Instead, the return value is always null .相反,返回值始终是null ( Control.FromChildHandle() gives the same result.) Control.FromChildHandle()给出相同的结果。)

Therefore, my question is simply: what am I doing wrong?因此,我的问题很简单:我做错了什么? And is this even possible in .NET?这在 .NET 中是否可能?

public class MainForm : Form
{
[DllImport("user32")]
extern static int ShowWindowAsync(IntPtr hWnd, int nCmdShow);

[DllImport("user32")]
extern static bool SetForegroundWindow(IntPtr hWnd);

private Mutex singletonMutex;

private void MainForm_Load(object sender, EventArgs e)
{
  bool wasCreated;
  singletonMutex = new Mutex(false, Application.ProductName + "Mutex", out wasCreated);

  // returns false for every instance except the first
  if (!wasCreated)
  {
    Process thisProcess = Process.GetCurrentProcess();
    Process[] peerProcesses = Process.GetProcessesByName(thisProcess.ProcessName.Replace(".vshost", string.Empty));

    foreach (Process currentProcess in peerProcesses)
    {
      if (currentProcess.Handle != thisProcess.Handle)
      {
        ShowWindowAsync(currentProcess.MainWindowHandle, 1); // SW_NORMAL
        SetForegroundWindow(currentProcess.MainWindowHandle);

        // always returns null !!!
        MainForm runningForm = (MainForm) Control.FromHandle(currentProcess.MainWindowHandle);

        if (runningForm != null)
        {
          runningForm.Arguments = this.Arguments;
          runningForm.ProcessArguments();
        }

        break;
      }
    }

    Application.Exit();

    return;
  }
}

Single-instance apps are well supported by the .NET framework. .NET 框架很好地支持单实例应用程序。 Check this thread for an example that does exactly what you need.检查此线程以获取完全符合您需要的示例。

Control.FromHandle isn't going to work because the control you're looking for is in another process (and therefore in another appdomain). Control.FromHandle 不起作用,因为您要查找的控件在另一个进程中(因此在另一个应用程序域中)。

You already have the WindowHandle but it's use is limited to the Win32 API.您已经拥有 WindowHandle,但它的使用仅限于 Win32 API。 Nothing from WinForms is going to work. WinForms 中的任何内容都不起作用。

You can send (WM_) messages but it's hard to get data across.您可以发送 (WM_) 消息,但很难获取数据。

Options选项

  1. use something low-level with a temp-file.在临时文件中使用低级别的东西。

  2. use remoting (WCF)使用远程处理 (WCF)

Try the following尝试以下

var form = (Form)(Control.FromHandle(myHandle));

EDIT编辑

Re-read your question and realized you are looking at a handle in another process.重新阅读您的问题并意识到您正在查看另一个进程中的句柄。 There is no way to convert a handle in another process to a Form instance in the current process.无法将另一个进程中的句柄转换为当前进程中的 Form 实例。 My solution will only work for handles in the same process.我的解决方案仅适用于同一进程中的句柄。

The only way to get ahold of the Form instance is to use Remoting.获得 Form 实例的唯一方法是使用 Remoting。 But that will require cooperation on the part of both processes which does not appear to be what you are looking for.但这需要两个过程的合作,而这似乎不是您想要的。

You are really trying to implement a singleton application.您确实在尝试实现 singleton 应用程序。 There are a few examples in the Internet (sorry, haven't really tried myself), eg网上有几个例子(对不起,我自己没有真正尝试过),例如

http://www.codeproject.com/KB/cs/SingletonApplication.aspx http://www.codeproject.com/KB/cs/SingletonApplication.aspx

http://www.nathanm.com/csharp-wpf-singleton-application/ http://www.nathanm.com/csharp-wpf-singleton-application/

You can't call code in another process directly, you need to use some form of inter-process communication你不能直接调用另一个进程中的代码,你需要使用某种形式的进程间通信

If you are communication only between processes started by the same user on the same computer you can use window messages (using WinAPI PostMessage and overriding WndProc), otherwise I think remoting is the easiest to use in .net如果您仅在同一台计算机上由同一用户启动的进程之间进行通信,您可以使用 window 消息(使用 WinAPI PostMessage 并覆盖 WndProc),否则我认为远程处理是最容易在 Z2D50972FECCD37612895455 中使用的

I use the Microsoft.VisualBasic.dll library described in the thread that nobugz pointed to.我使用 nobugz 指向的线程中描述的 Microsoft.VisualBasic.dll 库。 Yes, you can use it in C#.是的,您可以在 C# 中使用它。 You just override the OnStartupNextInstance and pass the command line into your program in whatever way works best for you.您只需覆盖 OnStartupNextInstance 并以最适合您的方式将命令行传递到您的程序中。

This is a whole lot easier than messing around with the threads manually.这比手动处理线程要容易得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM