如何操作我的程序的另一个实例(进程)?

还不够格啊 2008-12-21 01:41:48
我自己的程序:

static void Main(string[] args)
{
Process oCurrentProcess = Process.GetCurrentProcess();
Process[] oCurrentProcesses = Process.GetProcessesByName(oCurrentProcess.ProcessName);
if (oCurrentProcesses.Length > 1)
{
//oCurrentProcesses [0].MainWindowHandle
//这里如何操作上面的窗口句柄??
return;
}

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

Application.Run(new MainForm());
}

我的目的是:在已经有一个实例运行的情况下,如果再运行同一个程序,再次运行的程序会找到那个已经运行的进程并取得其主窗口句柄,然后调用已经存在的主窗口的一个方法进行一些操作,比如传递个数据,之后再次运行的那个进程退出,而已经存在的进程接收到传入的数据之后做相应的处理,并把自己的主窗口激活。

我想到的方法有两个:

1.在Main里给找到的已经存在的主窗口发送自定义消息,主窗口接收并处理。
2.把找到的主窗口句柄转换为类MainForm的实例,然后直接调用MainForm的一个方法。

觉得1可能能实现,但2如何做转换呢?或者还有其他方法?

希望尽量用.net方法,实在不行再用Windows API。
...全文
601 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
口圭Y口塞 2010-07-18
  • 打赏
  • 举报
回复
3楼说的 有点看不懂啊……差不多理解一点 但是那些方法都没用过 只能照搬过来
kinglshadow 2009-11-18
  • 打赏
  • 举报
回复
不懂,学习下
CsToD 2009-06-02
  • 打赏
  • 举报
回复
方法2也可以实现,但是
“希望尽量用.net方法,实在不行再用Windows API。 ”
这是办不到的,不仅要使用API,而且要大量使用API。

如果你想要研究,可以参考我写的文章《托管注入深入研究》(网上随便一搜就能找到)
如果你只是想实现这个功能,而不关系怎样实现的,可以下载我随文的一个附件SuperSpy,我提供了一个接口,你可以自己编写插件。
pennymay 2009-06-02
  • 打赏
  • 举报
回复
mark
whitechololate 2009-01-21
  • 打赏
  • 举报
回复
UP
尐孑 2009-01-21
  • 打赏
  • 举报
回复
gz
535cheng110 2009-01-21
  • 打赏
  • 举报
回复
mark
gomoku 2008-12-21
  • 打赏
  • 举报
回复
2.把找到的主窗口句柄转换为类MainForm的实例,然后直接调用MainForm的一个方法。
不能这样做。
由于进程的隔离,如果窗口句柄不属于在本进程中创建的托管窗口,你并不能将找到的主窗口句柄转换为MainForm的实例。


当一个托管Control(Winform也是Control)收到第一个窗口消息的时候,
这个托管实例以及它对应的窗口句柄被缓存到Control的一个静态数组中(HandleBucket[] hashBuckets)。
随后,当你调用Control.FromHandle(IntPtr)的时候,实际上是到hashBuckets中匹配窗口句柄,并返回缓存的托管实例。


1.在Main里给找到的已经存在的主窗口发送自定义消息,主窗口接收并处理。
这个可以。
要小心的是,如果已经运行的窗口被隐藏(比如放到系统托盘上),那么它Process.MainWindowHandle返回的句柄可能为空。
拿不到它的句柄,你就不能向它发窗口消息。


觉得1可能能实现,但2如何做转换呢?或者还有其他方法?
可以用命名事件来通知,而对于数量不多的参数,可以通过注册表来传递,详见例子。

其他进程间通讯还可以用Remoting(包括WCF),Socket,窗口消息,共享内存,命名管道,数据库中转等等。



// Program.cs
using System;
using System.Windows.Forms;
using System.Threading;
using Microsoft.Win32;
using System.Diagnostics;

namespace WindowsApplication1
{
static class Program
{
[STAThread]
static void Main()
{
// 尝试创建一个命名事件
bool createNew;
ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, "MyStartEvent", out createNew);

// 如果该命名事件已经存在(存在有前一个运行实例),则
if (!createNew)
{
// 先写一些数据到注册表中,以便传递给前一个运行实例
Registry.SetValue(@"HKEY_CURRENT_USER\Software\MyMy", "", DateTime.Now.ToLongTimeString());

// 发事件通知
ProgramStarted.Set();

// 等一小会以便前一个运行实例接到通知后恢复显示(也可以采用等待事件通知的方式)
Thread.Sleep(200);

// 将焦点转移到前一个实例
foreach (Process p in Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName))
{
if (p.MainWindowHandle != IntPtr.Zero)
{
SetForegroundWindow(p.MainWindowHandle);
}
}

// 就此退出第二个进程
return;
}

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
public static EventWaitHandle ProgramStarted;

[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
}
}




using System;
using System.Windows.Forms;
using System.Threading;
using Microsoft.Win32;

namespace WindowsApplication1
{
public partial class Form1 : Form
{
NotifyIcon notifyIcon1 = new NotifyIcon();

public Form1()
{
//InitializeComponent();
this.Controls.Add(new TextBox());

this.notifyIcon1.Text = "Double click me to show window";
this.notifyIcon1.Icon = System.Drawing.SystemIcons.Question;
this.notifyIcon1.DoubleClick += OnNotifyIconDoubleClicked;

this.SizeChanged += OnSizeChanged;
ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
}

// 当最小化时,放到系统托盘。
void OnSizeChanged(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Minimized)
{
this.notifyIcon1.Visible = true;
this.Visible = false;
}
}

// 当双击托盘图标时,恢复窗口显示
void OnNotifyIconDoubleClicked(object sender, EventArgs e)
{
this.Visible = true;
this.notifyIcon1.Visible = false;
this.WindowState = FormWindowState.Normal;
}

// 当收到第二个进程的通知时,从注册表中获得传入的参数,并恢复窗口显示
void OnProgramStarted(object state, bool timeout)
{
if (this.InvokeRequired)
{
this.Invoke(new WaitOrTimerCallback(OnProgramStarted), state, timeout);
}
else
{
object param = Registry.GetValue(@"HKEY_CURRENT_USER\Software\MyMy", "", string.Empty);
this.Text = param as string;
OnNotifyIconDoubleClicked(this, EventArgs.Empty);
}
}
}
}
EveryCase 2008-12-21
  • 打赏
  • 举报
回复
ICanUseThisID 2008-12-21
  • 打赏
  • 举报
回复
方法1能够实现,而且也不是很复杂,为什么不采用呢,呵呵

110,560

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧