2015-08-14 52 views
1

UPD:添加了MCVE。使用SendMessage將消息循環發送到不同的procces()

這是一項教育任務。我必須使用SendMessage()功能:

[DllImport("user32.dll")] 
public static extern IntPtr SendMessage(IntPtr hWnd, 
    uint wMsg, UIntPtr wParam, IntPtr lParam); 

我有信息,以與GUI communicationg兩個不同的應用。在得到諸如「開始」1 app之類的消息之後,必須每5秒開始發送消息「請求值」至2 app。並且2 app發送到1 app消息「發送值」與一些數據。

1 app是的WinForms方案:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

namespace Oven_Monitor 
{ 
    public partial class Form1 : Form 
    { 
     [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
     public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern int GetCurrentProcessId(); 

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

     [DllImport("user32.dll")] 
     public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, UIntPtr wParam, IntPtr lParam); 

     private uint askMessageID  = RegisterWindowMessage("Ask value"); 
     private uint dataMessageID  = RegisterWindowMessage("Send value"); 
     private uint registerMessageID = RegisterWindowMessage("Register sensor"); 

     public Form1() { 
      InitializeComponent(); 
      this.Text = "Really rare title"; 
     } 

     public void checkSensors() { 
      while (true) { 
       SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0); 
       System.Threading.Thread.Sleep(500); 
      } 
     } 

     private IntPtr secondAppHWnd; 

     protected override void WndProc(ref Message m) { 
      if (m.Msg == registerMessageID) { 
       secondAppHWnd = m.LParam; 
       Thread tr = new Thread(checkSensors); 
       tr.Start(); 
      } else if (m.Msg == dataMessageID) { 
       //do some stuff 
      } 
      base.WndProc(ref m); 
     } 
    } 
} 

2 app是控制檯項目,但它需要System.Windows.Forms referens:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

namespace HeatSensor 
{ 
    class Program 
    { 
     [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
     public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 

     static void Main(string[] args) 
     { 
      IntPtr mainAppHandle = FindWindow(null, "Really rare title"); 
      while (mainAppHandle == IntPtr.Zero) 
      { 
       Console.ReadKey(); 
       mainAppHandle = FindWindow(null, "Really rare title"); 
      } 
      HiddenForm form = new HiddenForm(mainAppHandle); 

      while (true) //it's actually not infinit 
      { 
       //do some stuff 
      } 
     } 
    } 
} 

及隱藏表單類:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

namespace HeatSensor 
{ 
    public partial class HiddenForm : Form 
    { 
     [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
     public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 

     [DllImport("user32.dll")] 
     public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, UIntPtr wParam, IntPtr lParam); 

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

     static private IntPtr mainAppHandle; 

     public HiddenForm(IntPtr mainAppHWnd) 
     { 
      InitializeComponent(); 
      mainAppHandle = mainAppHWnd; 
      string title = System.DateTime.Now.ToLongDateString(); 
      title += System.DateTime.Now.ToLongTimeString(); 
      title += System.DateTime.Now.Ticks.ToString(); 
      this.Text = title; 
      this.CreateHandle(); 
      int currentWindowHandle = (int)FindWindow(null, title); 
      SendMessage(mainAppHandle, RegisterWindowMessage("Register sensor"), 
       (UIntPtr)0, currentWindowHandle); 
     } 

     private uint askMessageID = RegisterWindowMessage("Ask value"); 
     private uint dataMessageID = RegisterWindowMessage("Send value"); 
     private uint registerMessageID = RegisterWindowMessage("Register sensor"); 

     protected override void WndProc(ref Message m) 
     { 
      if (m.Msg == askMessageID) 
      { 
       SendMessage(mainAppHandle, dataMessageID, (UIntPtr)1, (IntPtr)1); 
      } 
      base.WndProc(ref m); 
     } 
    } 
} 

出於某種原因,這個程序行爲很奇怪。幾乎每次2 app都沒有收到「詢問價值」消息,有時checkSensors()發送1-3條消息並停止。

有什麼不對?

這兩個HWnd都是正確的。


更新:我試圖檢查錯誤的位置:

public void checkSensors() { 
    while (true) { 
     SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0); 
     int error = Marshal.GetLastWin32Error();     
     System.Threading.Thread.Sleep(500); 
    } 
} 

看看。當SendMessage被執行時,這個線程被阻塞了(什麼意思,SendMessage沒有被弄錯,當我關閉2 app之後,線程被解除了阻塞,並且我得到了164個錯誤(ERROR_MAX_THRDS_REACHED:系統中沒有更多的線程可以被創建)。 ?意味着

此外,補充說:

protected override void WndProc(ref Message m) 
      { 
       //here is all message checks 
       int erro2r = Marshal.GetLastWin32Error(); 
       if (erro2r != 0) { 
        int j; //stop to debug here 
       } 
       base.WndProc(ref m); 
      } 

它只是不斷地返回1400 ERROR_INVALID_WINDOW_HANDLE(我沒有在那一刻發送任何消息)

因此,它看起來完全以我不清楚


更新2:如果我從WndProc()調用它,一切正常:

SendMessage(secondAppHWnd, askMessageID, (UIntPtr)0, (IntPtr)0); 

,但我需要從不同的線程發送此消息每5秒。

+1

'HWND's可能是正確的,但你的P/Invoke簽名是全部錯誤的。你必須爲'hWnd'和'lParam'使用'IntPtr'。 'wParam'應該使用'UIntPtr'類型。同樣,返回值應該是'IntPtr'。如果你想保持CLS兼容,所有的上述內容使用'IntPtr'。 – IInspectable

+0

@IInspectable,謝謝!我解決了這個問題,但主要問題仍然存在。 – InfernumDeus

+1

請製作一個MCVE。不止一次地停止調用RegisterWindowMessage。添加錯誤檢查。也請考慮做一些調試。試圖在不進行調試的情況下進行編程並不有效。 –

回答

-1

所以,如果兩個程序都是WinForms項目,它終於可以工作。我可以從2 app運行控制檯窗口並隱藏主窗口。

+2

這不是一個像解決方法一樣的解決方案。你放棄了試圖瞭解消息泵,並轉而採用另一種設計,讓別人爲你運行消息泵。 –

+1

你說得對。但是,總比沒有好。 – InfernumDeus

相關問題