【问题标题】:How do I get a System.Windows.Form instance from its Win32 handle?如何从其 Win32 句柄中获取 System.Windows.Form 实例?
【发布时间】:2010-10-09 13:39:22
【问题描述】:

以下代码实现了一个简单的单例,可确保我的应用程序只有一个实例可以运行。但是,如果启动另一个实例,我需要能够获取该实例的命令行参数,将它们传递给初始实例,然后终止第二个实例。

当我试图获取应用程序的第一个实例时,问题就出现了。一旦我找到了该实例的主窗体的句柄,我将它传递给Control.FromHandle() 方法,期望得到一个MainForm。相反,返回值始终为null。 (Control.FromChildHandle() 给出相同的结果。)

因此,我的问题很简单:我做错了什么?这在 .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;
  }
}

【问题讨论】:

    标签: c# winforms winapi interop ipc


    【解决方案1】:

    试试下面的

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

    编辑

    重新阅读您的问题并意识到您正在查看另一个进程中的句柄。无法将另一个进程中的句柄转换为当前进程中的 Form 实例。我的解决方案只适用于同一进程中的句柄。

    获取表单实例的唯一方法是使用远程处理。但这需要两个过程的合作,而这似乎不是您想要的。

    【讨论】:

      【解决方案2】:

      Control.FromHandle 不起作用,因为您要查找的控件在另一个进程中(因此在另一个应用程序域中)。

      您已经拥有 WindowHandle,但它的使用仅限于 Win32 API。 WinForms 中的任何内容都不起作用。

      您可以发送 (WM_) 消息,但很难传递数据。

      选项

      1. 使用低级别的东西 临时文件。

      2. 使用远程处理 (WCF)

      【讨论】:

        【解决方案3】:

        您确实在尝试实现单例应用程序。网上有几个例子(不好意思,我自己没有真正尝试过),例如

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

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

        【讨论】:

          【解决方案4】:

          你不能直接调用另一个进程中的代码,你需要使用某种形式的进程间通信

          如果您只在同一台计算机上由同一用户启动的进程之间进行通信,您可以使用窗口消息(使用 WinAPI PostMessage 并覆盖 WndProc),否则我认为远程处理是 .net 中最容易使用的

          【讨论】:

            【解决方案5】:

            .NET 框架很好地支持单实例应用程序。查看this thread 以获取完全符合您需要的示例。

            【讨论】:

            • 谢谢你 - 我完全忘记了 WindowsFormsApplicationBase 类。 System.Windows.Forms 命名空间中不包含这样一个有用的类,这对我来说似乎很奇怪,但是哦。
            【解决方案6】:

            我使用 nobugz 指向的线程中描述的 Microsoft.VisualBasic.dll 库。是的,您可以在 C# 中使用它。您只需覆盖 OnStartupNextInstance 并以最适合您的方式将命令行传递到您的程序中。

            这比手动处理线程要容易得多。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-09-02
              • 2014-05-22
              • 2011-02-26
              相关资源
              最近更新 更多