2009-07-31 40 views
1

我有一個WinForms應用程序,如果已經有一個實例運行&用戶試圖旋轉另一個實例,我通過在調用Application.Run()之前檢查一個Mutex來停止它。這部分工作得很好。我想要做的是在殺死新進程之前,將應用程序新實例的消息(以及字符串形式的一段數據)傳遞給現有實例。如何從託管應用程序的一個實例向另一個實例發送消息?

我試過調用PostMessage,並且確實收到了正在運行的應用程序的消息,但是我在lparam中傳遞的字符串失敗了(是的,我已經檢查過以確保我傳遞的是一個好的字符串開始)。我怎樣才能最好地做到這一點?

static class Program 
{ 
    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    public static extern bool PostMessage(int hhwnd, uint msg, IntPtr wparam, IntPtr lParam); 

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
    static extern uint RegisterWindowMessage(string lpString); 

    private const int HWND_BROADCAST = 0xffff; 
    static uint _wmJLPC = unchecked((uint)-1); 

    /// <summary> 
    /// The main entry point for the application. 
    /// </summary> 
    [STAThread] 
    static void Main() 
    { 
     _wmJLPC = RegisterWindowMessage("JumpListProjectClicked"); 
     if (_wmJLPC == 0) 
     { 
      throw new Exception(string.Format("Error registering window message: \"{0}\"", Marshal.GetLastWin32Error().ToString())); 
     } 

     bool onlyInstance = false; 
     Mutex mutex = new Mutex(true, "b73fd756-ac15-49c4-8a9a-45e1c2488599_ProjectTracker", out onlyInstance); 

     if (!onlyInstance) { 
      ProcessArguments(); 
      return; 
     } 

     Application.EnableVisualStyles(); 
     Application.SetCompatibleTextRenderingDefault(false); 
     Application.Run(new MainForm()); 

     GC.KeepAlive(mutex); 
    } 

    internal static void ProcessArguments() 
    { 
     if (Environment.GetCommandLineArgs().Length > 1) 
     { 
      IntPtr param = Marshal.StringToHGlobalAuto(Environment.GetCommandLineArgs()[1]); 
      PostMessage(HWND_BROADCAST, _wmJLPC, IntPtr.Zero, param); 
     } 
    } 
} 

其他地方,在我的表...

protected override void WndProc(ref Message m) 
{ 
    try 
    { 
     if (m.Msg == _wmJLPC) 
     { 
      // always returns an empty string 
      string param = Marshal.PtrToStringAnsi(m.LParam); 

      // UI code omitted 
     } 
    } 
    catch (Exception ex) 
    { 
     HandleException(ex); 
    } 

    base.WndProc(ref m); 
} 

回答

3

格雷格,

通過StringToHGlobalAuto創建的非託管指針只在創建它的進程空間中有效。它引用的內存不能從其他進程訪問。

要將數據從一個應用程序傳遞到另一個應用程序,請使用SendMessage()和WM_COPYDATA消息。

斯科特

0

再次檢查你的代碼。您正在使用StringToHGlobalAuto創建字符串(可能以Unicode結尾)。然後,你調用PtrToStringAnsi,它不使用Unicode。

如果你不能得到這個解決方案的工作,有幾個選項。您可以通過查找IPC(InterProcess Communication。)來了解它們。

我使用過的一種方法,既快速又簡單,是使用所需內容創建一個衆所周知的文件。您將該文件的使用與已命名事件一起使用,並通過設置另一個命名事件來告訴「所有者」應用程序該文件已更改。 「所有者」偶爾檢查事件,或者啓動一個工作線程來監視它。

同樣,IPC有許多口味,如果這些想法不起作用,繼續尋找。

0

現在有很多簡單和現代的方法來進行跨進程通信。特別是檢查WCF。

雖然我會承認有一點點的學習曲線。一旦你發現它真的很容易。您甚至可以通過編程完成所有操作,因此您不必擔心任何配置混淆。

0

這是一個簡單的方法。我還沒有運行的代碼,但你的想法

class Program 
{ 
    static Thread listenThread; 
    static void Main(string[] args) 
    { 
     try 
     { 
      using (Mutex mutex = new Mutex(true, "my mutex")) 
      { 
       listenThread = new Thread(Listen); 
       listenThread.IsBackground = true; 
       listenThread.Start(); 
      } 
     } 
     catch (ApplicationException) 
     { 
      using (Mutex mutex = Mutex.OpenExisting("my mutex")) 
      { 
       mutex.WaitOne(); 
       try 
       { 
        using (NamedPipeClientStream client = new NamedPipeClientStream("some pipe")) 
        { 
         using (StreamWriter writer = new StreamWriter(client)) 
         { 
          writer.WriteLine("SomeMessage"); 
         } 
        } 
       } 
       finally 
       { 
        mutex.ReleaseMutex(); 
       } 
      } 
     } 
    } 
    static void Listen() 
    { 
     using (NamedPipeServerStream server = new NamedPipeServerStream("some pipe")) 
     { 
      using (StreamReader reader = new StreamReader(server)) 
      { 
       for (; ;) 
       { 
        server.WaitForConnection(); 
        string message = reader.ReadLine(); 
        //Dispatch the message, probably onto the thread your form 
        // was contructed on with Form.BeginInvoke 

       } 
      } 
     } 
    } 
相關問題