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

发布于 2024-07-13 22:30:50 字数 1619 浏览 6 评论 0原文

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

当我尝试获取应用程序的第一个实例时,问题就出现了。 找到该实例的主窗体的句柄后,我将其传递给 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;
  }
}

The following code implements a simple singleton that ensures only 1 instance of my application can be run. 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.

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. Instead, the return value is always null. (Control.FromChildHandle() gives the same result.)

Therefore, my question is simply: what am I doing wrong? And is this even possible in .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;
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

酒绊 2024-07-20 22:30:50

.NET 框架很好地支持单实例应用程序。 检查此线程 的示例完全符合您的需要。

Single-instance apps are well supported by the .NET framework. Check this thread for an example that does exactly what you need.

七月上 2024-07-20 22:30:50

尝试以下

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

编辑

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

获取 Form 实例的唯一方法是使用 Remoting。 但这需要两个过程的合作,这似乎不是您所寻求的。

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. 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. But that will require cooperation on the part of both processes which does not appear to be what you are looking for.

吝吻 2024-07-20 22:30:50

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

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

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

选项

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

  2. 使用远程处理 (WCF)

Control.FromHandle isn't going to work because the control you're looking for is in another process (and therefore in another appdomain).

You already have the WindowHandle but it's use is limited to the Win32 API. Nothing from WinForms is going to work.

You can send (WM_) messages but it's hard to get data across.

Options

  1. use something low-level with a
    temp-file.

  2. use remoting (WCF)

女中豪杰 2024-07-20 22:30:50

您确实正在尝试实现一个单例应用程序。 互联网上有一些例子(抱歉,我自己还没有真正尝试过),例如

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

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

You are really trying to implement a singleton application. There are a few examples in the Internet (sorry, haven't really tried myself), e.g.

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

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

内心激荡 2024-07-20 22:30:50

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

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

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

伏妖词 2024-07-20 22:30:50

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

这比手动搞乱线程要容易得多。

I use the Microsoft.VisualBasic.dll library described in the thread that nobugz pointed to. Yes, you can use it in C#. You just override the OnStartupNextInstance and pass the command line into your program in whatever way works best for you.

This is a whole lot easier than messing around with the threads manually.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文