none
一个关于防止程序重复启动的问题 RRS feed

  • 问题

  • 目前已经能够检测到程序重复启动,但是我想当程序检测到被重复启动后之前已经启动的程序由hide状态变为show状态。

    我检测重复进程使用的方式是检测进程列表,一旦有检测到重复进程就向本地127.0.0.1发送一个UDP数据包,然后后启动的就app.current.shutdown()。

    App.cs:

    AsyncCallback callBack = new AsyncCallback(receiveFile_RequestSendFile);

     UdpClient uc2 = new UdpClient(7021);

     uc2.BeginReceive(callBack, "1"); //当端口7021接收到数据包的时候执行回调函数

    void receiveFile_RequestSendFile(IAsyncResult result)
           {
               if (SizeFlag == 0) //检测当前mainwindow状态是否为.hide()状态
               {
                   Action action = new Action(delegate()
                       {
                           Thread.Sleep(5000);
                           this.MainWindow.Show();
                           this.MainWindow.Activate();
                       });
                   action.BeginInvoke(null, null);
               }
           }

     

    错误提示:调用线程无法访问此对象,因为另一个线程拥有该对象。请问是什么原因导致的?有什么好的解决方法么?

    2011年3月18日 2:16

答案

  • WaitOne方法会阻塞线程,这应该是期待的一个特点:第一个进程并不知道第二个进程何时启动,所以它在WaitOne这里阻塞等待,类似于你原来方案里的监听过程,一旦阻塞通过了,那表明第二个进程被启动了,然后紧接着按排你的那个设置主窗口拥有焦点Action执行

     这个方法的缺点是只能传送非常有限的信息,就一个信号而已;如果有更多信息需要在进程间交换,还是版主提到的命名管道的方式最为有效和方便;UDP端口适用于跨机器的进程交换,对于一台机器上进程间通信来说,它的代价高了些

    共享文件的方式,我个人一直觉得这个方法用于进程通信有点尴尬,它需要使用磁盘外设,性能上会有个损失,不如用命名管道.共享文件我觉得更主要的目的是用于集群性质进程的持久化,比如工作流那的玩意的持久化.

    嗯,这个可以试试,不知道WaitOne会不会影响到程序正常运行..

    2011年3月23日 1:31
  • mutex 可以用,也可以到msdn里面查查mutex。
    关于mutex,我保留意见,在比较差的机器上运行,这个东东就不太管用了,因为他自己也需要创建时间,你可以到网上找找资料。

    查找进程,这个方法比较快,我也是用这个。

    第二个程序运行后,可以给第一个程序SendMessage,然后自己hidden

    第一个程序通过hook接收消息,进行相关操作。

    这篇文章可以帮到你,仔细看看,跟你的要求基本类似。

    http://www.cnblogs.com/xiaokang088/archive/2011/02/23/1962503.html

    2011年3月24日 3:25
  • 我已经找到解决方案了,就是使用进程查找配合FindWindow的方法,很好用,窗口hide之前我将句柄存储在配置文件中就可以了。谢谢xiaokang088、AceBear还有Bob版主的帮助!
    2011年3月29日 8:11

全部回复

  • "我检测重复进程使用的方式是检测进程列表"  为什么不使用互斥对象来检测单例进程呢? 使用Mutex互斥对象可以实现这个功能,而且非常简单,只要这个进程创建了一个Mutex对象,这个进程如果还要启动并且创建这个互斥对象就会被阻止,然后就可以收到消息,通知说这个进程实例已经存在。这个内容在《WPF编程》一书中有提到,下面是一个例子,你可以试试:

      public partial class App : Application
      {
        Mutex mutex;
        protected override void OnStartup(StartupEventArgs e)
        {
          base.OnStartup(e);
          bool isNew;
          mutex = new Mutex(true, "MyApplicationName", out isNew);
          if (!isNew) {
            MessageBox.Show("MyApplicationName is running!");
            Shutdown();
          }
        }
      }
    

     

    “错误提示:调用线程无法访问此对象,因为另一个线程拥有该对象” 这样子调用方法去show Window:

    void receiveFile_RequestSendFile(IAsyncResult result)
    {
      if (SizeFlag == 0) //检测当前mainwindow状态是否为.hide()状态
      {
        Action action = new Action(delegate()
          {
            Thread.Sleep(5000);
            this.MainWindow.Show();
            this.MainWindow.Activate();
          });
        this.MainWindow.Dispatcher.BeginInvoke(action, null); 
      }
    }
    

     

    使用 MainWindow的Dispatcher去调用委托,而不是在接收线程中调用 (接收线程异于UI线程)

     

    Sincerely,


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年3月21日 8:54
    版主
  • "这个进程如果还要启动并且创建这个互斥对象就会被阻止,然后就可以收到消息"

    前一个已经启动的进程如何收到进程被互斥的消息?

    2011年3月22日 2:45
  • mutex = new Mutex(true, "MyApplicationName", out isNew);

    isNew 会返回一个值 ,如果这个互斥对象已经存在,那么他返回 False.


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年3月22日 3:03
    版主
  • 试试EventWaitHandle吧,它是Mutex的兄弟

    和Mutex有些相似,但它有Set和Reset方法,可以设置它的信号状态,可以利用这个特点发信号给先前启动的进程,先前启动的进程可以用WaitOne方法检测信号状态

    2011年3月22日 3:25
  • 返回 False是对于后启动的进程返回的false,我如何让"之前"启动的进程知道"有同样进进程被启动了,该执行"receiveFile_RequestSendFile(IAsyncResult result)
    "了?
    2011年3月22日 3:48
  • 你可以保留原来的网络通知的功能,在后来的进程中发送消息到之前的进程.


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年3月22日 10:37
    版主
  • 又回到老问题上了。。

    即使我使用this.MainWindow.Dispatcher.BeginInvoke(action, null);
    也是提示"调用线程无法访问此对象,因为另一个线程拥有该对象”

    2011年3月22日 12:53
  • 嗯,这个可以试试,不知道WaitOne会不会影响到程序正常运行..

    2011年3月22日 12:55
  • 来个具体的例子吧 我来测试下  试试看有没有一个解决方案。

    不过夸进程通信来说,方法有很多,我个人比较喜欢用 Remote .Net,开一个名字管道,发个消息;还有就是利用共享文件,也可以。

    很久以前写的一个例子,是进程间通讯的:http://cid-51b2fdd068799d15.office.live.com/self.aspx/.Public/Samples%5E_2010/MultiProcessCommunication.zip


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年3月22日 14:53
    版主
  • WaitOne方法会阻塞线程,这应该是期待的一个特点:第一个进程并不知道第二个进程何时启动,所以它在WaitOne这里阻塞等待,类似于你原来方案里的监听过程,一旦阻塞通过了,那表明第二个进程被启动了,然后紧接着按排你的那个设置主窗口拥有焦点Action执行

     这个方法的缺点是只能传送非常有限的信息,就一个信号而已;如果有更多信息需要在进程间交换,还是版主提到的命名管道的方式最为有效和方便;UDP端口适用于跨机器的进程交换,对于一台机器上进程间通信来说,它的代价高了些

    共享文件的方式,我个人一直觉得这个方法用于进程通信有点尴尬,它需要使用磁盘外设,性能上会有个损失,不如用命名管道.共享文件我觉得更主要的目的是用于集群性质进程的持久化,比如工作流那的玩意的持久化.

    嗯,这个可以试试,不知道WaitOne会不会影响到程序正常运行..

    2011年3月23日 1:31
  • 我做了一个简单的例子,还是用的udp本地通信,当前一个收到后一个的udp包后开始mainwindow.hide();

     

    http://www.vippiano.com/WpfApplication21.rar

    2011年3月23日 8:17
  • 我尝试了共享文件的方式,也是提示"调用线程无法访问此对象,因为另一个线程拥有该对象”

     

    2011年3月23日 8:20
  • mutex 可以用,也可以到msdn里面查查mutex。
    关于mutex,我保留意见,在比较差的机器上运行,这个东东就不太管用了,因为他自己也需要创建时间,你可以到网上找找资料。

    查找进程,这个方法比较快,我也是用这个。

    第二个程序运行后,可以给第一个程序SendMessage,然后自己hidden

    第一个程序通过hook接收消息,进行相关操作。

    这篇文章可以帮到你,仔细看看,跟你的要求基本类似。

    http://www.cnblogs.com/xiaokang088/archive/2011/02/23/1962503.html

    2011年3月24日 3:25
  • 补充一点,关于查找进程的方法,如下所示,存在弊端:当多个用户同时登陆后,只有一个用户可以启动程序,因为进程是跨用户的哦。

    int processCount = Process.GetProcessesByName("windowWPF").Where(o => o.Id != Process.GetCurrentProcess().Id).Count();
    if (processCount > 1)
        Environment.Exit(0);
    2011年3月29日 5:35
  • 我已经找到解决方案了,就是使用进程查找配合FindWindow的方法,很好用,窗口hide之前我将句柄存储在配置文件中就可以了。谢谢xiaokang088、AceBear还有Bob版主的帮助!
    2011年3月29日 8:11
  • 感谢你分享你的解决方案。


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年3月29日 10:07
    版主