2015-08-14 8 views
1

UPD: добавлен MCVE.Циклическая отправка сообщений в разные версии с помощью SendMessage()

Это образовательная задача. Я должен использовать SendMessage() функции:

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

я должен сделать два разных приложения с графическим интерфейсом communicationg сообщениями. После получения сообщения типа «старт» 1 app должны начать посылать сообщение «Задавать значение» до 2 app каждые 5 секунд. И 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 Референс:

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 не получают отложенное сообщение «Ask value», иногда 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' может быть правильным, но ваша подпись P/Invoke - все неправильно. Вы должны использовать 'IntPtr' для' hWnd' и 'lParam'. 'wParam' должен использовать тип' UIntPtr'. Аналогично, возвращаемое значение должно быть 'IntPtr'. Если вы хотите остаться CLS-совместимым, используйте 'IntPtr' для всего перечисленного. – IInspectable

+0

@ Невозможно, спасибо! Я исправил это, но главная проблема все еще здесь. – InfernumDeus

+1

Пожалуйста, сделайте MCVE. Остановите вызов RegisterWindowMessage более одного раза. Добавить проверку ошибок. Также, пожалуйста, подумайте над выполнением некоторой отладки. Попытка программы без отладки не является продуктивной. –

ответ

-1

Итак, он, наконец, работает, если обе программы являются проектами WinForms. Я могу просто запустить консольное окно от 2 app и скрыть главное окно.

+2

Это не столько решение, сколько обходной путь. Вы отказались от попыток понять сообщения насосов и просто переключились на другой дизайн, где кто-то еще запускает насос сообщений для вас. –

+1

Вы правы. Но все же, лучше ничего. – InfernumDeus