以下代码实现了一个简单的单例,它确保只能运行我的应用程序的一个实例。但是,如果启动了另一个实例,我需要能够获取该实例的命令行参数,将它们传递给初始实例,然后终止第二个实例。
当我试图获取应用程序的第一个实例时,会出现此问题。一旦我找到该实例的主窗体的句柄,我将其传递给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;
}
}
答案 0 :(得分:4)
.NET框架很好地支持单实例应用程序。请查看this thread以获取您所需要的示例。
答案 1 :(得分:3)
Control.FromHandle无法正常工作,因为您正在寻找的控件位于另一个进程中(因此位于另一个应用程序域中)。
您已经拥有WindowHandle但它的使用仅限于Win32 API。 WinForms什么都不会起作用。
您可以发送(WM_)消息,但很难获取数据。
选项
使用低级别的东西 临时文件。
使用远程处理(WCF)
答案 2 :(得分:2)
尝试以下
var form = (Form)(Control.FromHandle(myHandle));
修改强>
重新阅读你的问题并意识到你正在寻找另一个过程中的句柄。无法将另一个进程中的句柄转换为当前进程中的Form实例。我的解决方案仅适用于同一过程中的句柄。
获取Form实例的唯一方法是使用Remoting。但这需要两个过程的合作,这似乎不是你想要的。
答案 3 :(得分:2)
您确实在尝试实施单例应用程序。互联网上有一些例子(抱歉,我没有真正尝试过自己),例如。
答案 4 :(得分:0)
您不能直接在另一个进程中调用代码,您需要使用某种形式的进程间通信
如果您只是在同一台计算机上由同一用户启动的进程之间进行通信,则可以使用窗口消息(使用WinAPI PostMessage并覆盖WndProc),否则我认为远程处理在.net中最容易使用
答案 5 :(得分:0)
我使用nobugz指向的线程中描述的Microsoft.VisualBasic.dll库。是的,你可以在C#中使用它。您只需覆盖OnStartupNextInstance并以最适合您的方式将命令行传递到您的程序中。
这比手动处理线程容易得多。