2011-10-26 37 views
7

Tôi đang làm việc trên một ứng dụng sử dụng Mutex để đảm bảo rằng đó là trường hợp duy nhất của ứng dụng đang chạy trên hệ thống.Làm thế nào tôi có thể gọi một phương thức trong một cá thể tiến trình khác của ứng dụng WinForms của tôi?

Khi một phiên bản khác của ứng dụng cố gắng bắt đầu, tôi muốn một phương thức chạy trong phiên bản gốc.

Tôi có thể gọi một phương thức cụ thể trong ứng dụng của mình từ một phiên bản ứng dụng khác không?

Tôi đã tìm thấy một số ví dụ bằng cách sử dụng API RegisterWindowMessage/PostMessage Win32 bằng cách gửi thư đến HWND_BROADCAST, nhưng tôi không thể khiến chúng hoạt động và tôi đã đọc ở nơi khác sử dụng HWND_BROADCAST có thể nguy hiểm.

Có cách nào tốt hơn để thực hiện việc này không liên quan đến ứng dụng cần chạy ở chế độ đặc quyền không?

+2

Nếu bạn muốn có một cách tiếp cận hacky, (và tôi KHÔNG có nghĩa là hacky), khi một trường hợp thứ hai của ứng dụng được khởi động, tạo ra một số tập tin dummy ở một số vị trí tạm thời, và để ứng dụng sử dụng FileSystemWatcher để theo dõi vị trí tạm thời đó cho tệp mới được tạo. Khi phát hiện một tập tin mới đã được tạo, hãy làm những gì bạn cần làm :) – BFree

Trả lời

3

Tôi đã nghiên cứu về điều này trước đây - bạn có thể sử dụng tệp ánh xạ bộ nhớ, được minh họa trong bài viết này http://www.codeproject.com/KB/cs/singleinstanceapplication.aspx hoặc bạn có thể làm những gì tôi đã làm (cách dễ dàng) và tận dụng các tính năng vb.net (cụ thể, một trong đó cho phép bạn tạo các ứng dụng cá thể đơn lẻ và gọi một phương thức trong cá thể hiện đang chạy mà chuyển trên dòng lệnh args [để bạn có thể sử dụng nó để gọi phương thức trong ứng dụng của mình]). Tôi biết bằng cách sử dụng các lớp VB trong C# âm thanh một chút nghèo nhưng đó là cách trừu tượng và dễ dàng nhất. Liên kết đến các bài viết có liên quan - http://www.codeproject.com/KB/cs/CSSIApp.aspx, phần cuối cùng của http://msdn.microsoft.com/en-us/magazine/cc163741.aspx

+0

Kỹ thuật này hoạt động ... và hoạt động tốt. Tôi đã sử dụng nó để gọi vào một thể hiện đang chạy từ trình đơn 'Gần đây' của ứng dụng của tôi khi được ghim vào thanh ứng dụng Win7. – AlfredBr

+0

vâng, đó là một cách khá đơn giản nhưng hiệu quả, nhưng sử dụng các lớp vb là "= /" cho một số người (bao gồm cả bản thân mình) – Zhanger

+3

Tôi sẽ sử dụng NamedPipes vì ​​chúng không yêu cầu bất kỳ PInvoking và chạy tự nhiên trong C# mà không có bất kỳ tài liệu tham khảo thêm. Hiệu trưởng cũng giống như bài viết mã hóa đầu tiên được tham chiếu ở trên, ngoại trừ việc bạn thực sự có thể hợp lý hóa mã với NamedPipes. Bài viết đó là 6 tuổi ... – BenSwayne

6

Đây là một trợ giúp nhỏ mà tôi đã viết.

Để sử dụng nó:

var pipeListener = new NamedPipeListener<String>(); // instantiate an instance 
pipeListener.MessageReceived += (sender, e) => MessageBox.Show(e.Message); // when a message is received, show a messagebox with the message 
pipeListener.Error += (sender, e) => MessageBox.Show("Error ({0}): {1}", e.ErrorType, e.Exception.Message); // oh noes! 
pipeListener.Start(); // when you're ready, start listening 

Từ quá trình khác:

NamedPipeListener<String>.SendMessage("Howdy howdy howdy"); 

Lưu ý rằng nó sử dụng tên đầy đủ của PipeListener như tên mặc định của ống. Nếu bạn cần phải kín đáo hơn, hãy sử dụng quá tải của hàm khởi tạo có tên đường ống.

Dưới đây là các lớp:

using System; 
using System.IO.Pipes; 
using System.Runtime.Serialization.Formatters.Binary; 

namespace FunWithNamedPipes 
{ 
    /// <summary>Contains event data for <see cref="NamedPipeMessageReceiveHandler{TMessage}" /> events.</summary> 
    /// <typeparam name="TMessage"></typeparam> 
    public class NamedPipeListenerMessageReceivedEventArgs<TMessage> : EventArgs 
    { 
     /// <summary>Initializes an instance of <see cref="NamedPipeListenerMessageReceivedEventArgs{TMessage}" /> with the specified <paramref name="message" />.</summary> 
     /// <param name="message">The message passed by the event.</param> 
     public NamedPipeListenerMessageReceivedEventArgs(TMessage message) 
     { 
      this.Message = message; 
     } 

     /// <summary>Gets the message passed by the event.</summary> 
     public TMessage Message { get; private set; } 
    } 

    /// <summary>Contains event data for <see cref="NamedPipeListenerErrorEventHandler" /> events.</summary> 
    public class NamedPipeListenerErrorEventArgs : EventArgs 
    { 
     /// <summary>Initializes an instance of <see cref="NamedPipeListenerErrorEventArgs" /> with the specified <paramref name="errorType" /> and <paramref name="exception" />.</summary> 
     /// <param name="errorType">A <see cref="NamedPipeListenerErrorType" /> describing the part of the listener process where the error was caught.</param> 
     /// <param name="ex">The <see cref="Exception" /> that was thrown.</param> 
     public NamedPipeListenerErrorEventArgs(NamedPipeListenerErrorType errorType, Exception ex) 
     { 
      this.ErrorType = errorType; 
      this.Exception = ex; 
     } 

     /// <summary>Gets a <see cref="NamedPipeListenerErrorType" /> describing the part of the listener process where the error was caught.</summary> 
     public NamedPipeListenerErrorType ErrorType { get; private set; } 

     /// <summary>Gets the <see cref="Exception" /> that was caught.</summary> 
     public Exception Exception { get; private set; } 
    } 

    /// <summary>Represents a method that will handle an event where a message is received via named pipes.</summary> 
    /// <typeparam name="TMessage">The type of message that will be received.</typeparam> 
    /// <param name="sender">The source of the event.</param> 
    /// <param name="e">The event data passed by the event, which includes the message that was received.</param> 
    public delegate void NamedPipeMessageReceivedHandler<TMessage>(Object sender, NamedPipeListenerMessageReceivedEventArgs<TMessage> e); 

    /// <summary>Represents a method that will handle an event that is fired when an exception is caught.</summary> 
    /// <param name="sender">The source of the event.</param> 
    /// <param name="e">The event data passed by the event, included the error type and exception that was caught.</param> 
    public delegate void NamedPipeMessageErrorHandler(Object sender, NamedPipeListenerErrorEventArgs e); 

    /// <summary>Includes different types of errors that describe where in the listening process an exception was caught.</summary> 
    public enum NamedPipeListenerErrorType : byte 
    { 
     /// <summary>Indicates that an exception was caught while calling <see cref="NamedPipeServerStream.BeginWaitForConnection" />.</summary> 
     BeginWaitForConnection = 1, 

     /// <summary>Indicates that an exception was caught while calling <see cref="NamedPipeServerStream.EndWaitForConnection" />.</summary> 
     EndWaitForConnection = 2, 

     /// <summary>Indicates that an exception was caught while deserializing a message received from the named pipe.</summary> 
     DeserializeMessage = 3, 

     /// <summary>Indicates that an exception was caught while closing or disposing a used named pipe.</summary> 
     CloseAndDisposePipe = 4, 

     /// <summary>Indicates that an exception was caught while invoking the <see cref="NamedPipeListener{TMessage}.MessageReceived"/> event.</summary> 
     NotifyMessageReceived = 5 
    } 

    /// <summary>A helper class for sending and receiving messages using named pipes.</summary> 
    /// <typeparam name="TMessage">The type of message that will be sent or received.</typeparam> 
    public class NamedPipeListener<TMessage> : IDisposable 
    { 
     /// <summary>Occurs when a message is received.</summary> 
     public event NamedPipeMessageReceivedHandler<TMessage> MessageReceived; 

     /// <summary>Occurs when an exception is caught.</summary> 
     public event NamedPipeMessageErrorHandler Error; 

     static readonly String DEFAULT_PIPENAME = typeof(NamedPipeListener<TMessage>).FullName; 
     static readonly BinaryFormatter formatter = new BinaryFormatter(); 

     NamedPipeServerStream pipeServer; 

     /// <summary>Initializes a new instance of <see cref="NamedPipeListener{TMessage}" /> using the specified <paramref name="pipeName" />.</summary> 
     /// <param name="pipeName">The name of the named pipe that will be used to listen on.</param> 
     public NamedPipeListener(String pipeName) 
     { 
      this.PipeName = pipeName; 
     } 

     /// <summary>Initializes a new instance of <see cref="NamedPipeListener{TMessage}" /> using the default pipe name.</summary> 
     /// <remarks>The default pipe name is the full name of the type of the instance.</remarks> 
     public NamedPipeListener() 
      : this(DEFAULT_PIPENAME) { } 

     /// <summary>The name of the named pipe that will be used to listen on.</summary> 
     public String PipeName { get; private set; } 

     /// <summary>Starts listening on the named pipe specified for the instance.</summary> 
     internal void Start() 
     { 
      if (pipeServer == null) pipeServer = new NamedPipeServerStream(DEFAULT_PIPENAME, PipeDirection.In, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous); 

      try { pipeServer.BeginWaitForConnection(new AsyncCallback(PipeConnectionCallback), null); } 
      catch (Exception ex) { this.OnError(NamedPipeListenerErrorType.BeginWaitForConnection, ex); } 
     } 

     private void PipeConnectionCallback(IAsyncResult result) 
     { 
      try 
      { 
       pipeServer.EndWaitForConnection(result); 
      } 
      catch (Exception ex) 
      { 
       this.OnError(NamedPipeListenerErrorType.EndWaitForConnection, ex); 
       return; 
      } 

      TMessage message; 
      try 
      { 
       message = (TMessage)formatter.Deserialize(pipeServer); 
      } 
      catch (Exception ex) 
      { 
       this.OnError(NamedPipeListenerErrorType.DeserializeMessage, ex); 
       return; 
      } 

      try 
      { 
       this.OnMessageReceived(new NamedPipeListenerMessageReceivedEventArgs<TMessage>(message)); 
      } 
      catch (Exception ex) 
      { 
       this.OnError(NamedPipeListenerErrorType.NotifyMessageReceived, ex); 
       return; 
      } 

      if (this.End()) 
      { 
       this.Start(); 
      } 
     } 

     internal Boolean End() 
     { 
      try 
      { 
       pipeServer.Close(); 
       pipeServer.Dispose(); 
       pipeServer = null; 

       return true; 
      } 
      catch (Exception ex) 
      { 
       this.OnError(NamedPipeListenerErrorType.CloseAndDisposePipe, ex); 
       return false; 
      } 
     } 

     private void OnMessageReceived(TMessage message) 
     { 
      this.OnMessageReceived(new NamedPipeListenerMessageReceivedEventArgs<TMessage>(message)); 
     } 

     protected virtual void OnMessageReceived(NamedPipeListenerMessageReceivedEventArgs<TMessage> e) 
     { 
      if (this.MessageReceived != null) 
      { 
       this.MessageReceived(this, e); 
      } 
     } 

     private void OnError(NamedPipeListenerErrorType errorType, Exception ex) 
     { 
      this.OnError(new NamedPipeListenerErrorEventArgs(errorType, ex)); 
     } 

     protected virtual void OnError(NamedPipeListenerErrorEventArgs e) 
     { 
      if (this.Error != null) 
      { 
       this.Error(this, e); 
      } 
     } 

     void IDisposable.Dispose() 
     { 
      if(pipeServer != null) 
      { 
       try { pipeServer.Disconnect(); } 
       catch { } 

       try { pipeServer.Close(); } 
       catch { } 

       try { pipeServer.Dispose(); } 
       catch { } 
      } 
     } 

     /// <summary>Sends the specified <paramref name="message" /> to the default named pipe for the message.</summary>   
     /// <param name="message">The message to send.</param> 
     public static void SendMessage(TMessage message) 
     { 
      NamedPipeListener<TMessage>.SendMessage(DEFAULT_PIPENAME, message); 
     } 

     /// <summary>Sends the specified <paramref name="message" /> to the specified named pipe.</summary> 
     /// <param name="pipeName">The name of the named pipe the message will be sent to.</param> 
     /// <param name="message">The message to send.</param> 
     public static void SendMessage(String pipeName, TMessage message) 
     { 
      using (var pipeClient = new NamedPipeClientStream(".", DEFAULT_PIPENAME, PipeDirection.Out, PipeOptions.None)) 
      { 
       pipeClient.Connect(); 

       formatter.Serialize(pipeClient, message); 
       pipeClient.Flush(); 

       pipeClient.WaitForPipeDrain(); 
       pipeClient.Close(); 
      } 
     } 
    } 
} 
Các vấn đề liên quan