Отправить сообщение в C # - PullRequest
       6

Отправить сообщение в C #

12 голосов
/ 23 февраля 2011

Я создаю приложение, которое использует основной проект, который подключен к нескольким различным DLL.Из одного окна DLL мне нужно открывать окно в другом, но библиотеки DLL не могут ссылаться друг на друга.

Мне было предложено использовать функцию sendmessage в первой DLL и иметь прослушиватель в основной программе, который направляет это сообщение в соответствующую DLL, чтобы открыть ее окно.

Однако я совершенно не знаком с функцией sendmessage, и у меня много трудностей, связанных с информацией, которую я нахожу в Интернете.

Если кто-то может показать мне правильный путь (если есть) использовать функцию sendmessage и, возможно, как слушатель захватит это сообщение, которое было бы удивительным.Вот часть кода, который я получил до сих пор, я не уверен, что я иду в правильном направлении.

    [DllImport("user32.dll")]
    public static extern int FindWindow(string lpClassName, String lpWindowName);
    [DllImport("user32.dll")]
    public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

    public void button1_Click(object sender, EventArgs e)
    {
        int WindowToFind = FindWindow(null, "Form1");
    }

Ответы [ 6 ]

10 голосов
/ 23 февраля 2011
public static extern int FindWindow(string lpClassName, String lpWindowName);

Чтобы найти окно, вам нужно имя класса окна. Вот несколько примеров:

C #:

const string lpClassName = "Winamp v1.x";
IntPtr hwnd = FindWindow(lpClassName, null);

Пример из программы, которую я сделал, написанной на VB:

hParent = FindWindow("TfrmMain", vbNullString)

Чтобы получить имя класса окна, вам понадобится что-то под названием Win Spy

Если у вас есть дескриптор окна, вы можете отправлять ему сообщения, используя функцию SendMessage (IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam).

hWnd, здесь, является результатом функции FindWindow. В приведенных выше примерах это будут hwnd и hParent. Он сообщает функции SendMessage, в какое окно отправлять сообщение.

Второй параметр, wMsg, является константой, обозначающей TYPE сообщения, которое вы отправляете. Сообщение может быть нажатием клавиши (например, отправить «ключ ввода» или «пробел» в окно), но это также может быть команда закрыть окно (WM_CLOSE), команда изменить окно (скрыть его, показать его, свернуть, изменить его заголовок и т. д.), запросить информацию в окне (получить заголовок, получить текст в текстовом поле и т. д.) и т. д. Вот некоторые распространенные примеры:

Public Const WM_CHAR = &H102
Public Const WM_SETTEXT = &HC
Public Const WM_KEYDOWN = &H100
Public Const WM_KEYUP = &H101
Public Const WM_LBUTTONDOWN = &H201
Public Const WM_LBUTTONUP = &H202
Public Const WM_CLOSE = &H10
Public Const WM_COMMAND = &H111
Public Const WM_CLEAR = &H303
Public Const WM_DESTROY = &H2
Public Const WM_GETTEXT = &HD
Public Const WM_GETTEXTLENGTH = &HE
Public Const WM_LBUTTONDBLCLK = &H203

Их можно найти с помощью средства просмотра API (или простого текстового редактора, такого как блокнот), открыв (каталог Microsoft Visual Studio) /Common/Tools/WINAPI/winapi32.txt.

Следующие два параметра являются определенными деталями, если они необходимы. Что касается нажатия определенных клавиш, они будут точно указывать, какая именно клавиша должна быть нажата.

C # пример, установка текста "windowHandle" с помощью WM_SETTEXT:

x = SendMessage(windowHandle, WM_SETTEXT, new IntPtr(0),
m_strURL);

Дополнительные примеры из программы, которую я сделал, написанной на VB, для установки иконки программы (ICONBIG - это константа, которую можно найти в winapi32.txt):

Call SendMessage(hParent, WM_SETICON, ICON_BIG, ByVal hIcon)

Другой пример из VB - нажатие клавиши пробела (VK_SPACE - это константа, которую можно найти в winapi32.txt):

Call SendMessage(button%, WM_KEYDOWN, VK_SPACE, 0)
Call SendMessage(button%, WM_KEYUP, VK_SPACE, 0)

VB отправка нажатия кнопки (левая кнопка вниз, а затем вверх):

Call SendMessage(button%, WM_LBUTTONDOWN, 0, 0&)
Call SendMessage(button%, WM_LBUTTONUP, 0, 0&)

Не знаю, как настроить прослушиватель в .DLL, но эти примеры должны помочь понять, как отправить сообщение.

6 голосов
/ 23 февраля 2011

Вам не нужно отправлять сообщения.

Добавьте событие в одну форму и обработчик события в другую.Затем вы можете использовать третий проект, который ссылается на два других, чтобы прикрепить обработчик события к событию.Две библиотеки DLL не должны ссылаться друг на друга, чтобы это работало.

3 голосов
/ 23 февраля 2011

Вы почти у цели.(обратите внимание на изменение в возвращаемом значении объявления FindWindow).В этом случае я бы порекомендовал использовать RegisterWindowMessage , чтобы вам не приходилось беспокоиться о плюсах и минусах WM_USER .

[DllImport("user32.dll")]    
public static extern IntPtr FindWindow(string lpClassName, String lpWindowName);    
[DllImport("user32.dll")]    
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);    
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);

public void button1_Click(object sender, EventArgs e)   
{        
     // this would likely go in a constructor because you only need to call it 
     // once per process to get the id - multiple calls in the same instance 
     // of a windows session return the same value for a given string
     uint id = RegisterWindowMessage("MyUniqueMessageIdentifier");
     IntPtr WindowToFind = FindWindow(null, "Form1");    
     Debug.Assert(WindowToFind != IntPtr.Zero);
     SendMessage(WindowToFind, id, IntPtr.Zero, IntPtr.Zero);
}

.Класс Form1:

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

    private uint _messageId = RegisterWindowMessage("MyUniqueMessageIdentifier");

    protected override void WndProc(ref Message m)
    {
       if (m.Msg == _messageId)
       {
           // do stuff

       }
       base.WndProc(ref m);
    }
}

Имейте в виду, что я не скомпилировал ничего из вышеперечисленного, поэтому может потребоваться некоторая настройка.Также имейте в виду, что другие ответы, предупреждающие вас вдали от SendMessage, являются точными.В настоящее время это не предпочтительный способ межмодульной связи, и, вообще говоря, переопределение WndProc и использование SendMessage/PostMessage подразумевает хорошее понимание того, как работает инфраструктура сообщений Win32 .

Но если выхочу / нужно идти по этому пути Я думаю, что вышеизложенное поможет вам двигаться в правильном направлении.

0 голосов
/ 23 февраля 2011

Опираясь на ответ Марка Байерса.

Третьим проектом может быть проект WCF, размещенный как служба Windows.Если все программы прослушивают этот сервис, одно приложение может вызвать сервис.Служба передает сообщение всем прослушивающим клиентам, и они могут при необходимости выполнить действие.

Хорошие видео WCF здесь - http://msdn.microsoft.com/en-us/netframework/dd728059

0 голосов
/ 23 февраля 2011

Некоторые другие опции:

Общее собрание

Создайте другую сборку, которая имеет некоторые общие интерфейсы, которые могут быть реализованы сборками.

Отражение

Это имеет всевозможные предупреждения и недостатки, но вы можете использовать отражение для создания экземпляров / связи с формами. Это и медленный, и динамический динамический режим (без статической проверки этого кода во время компиляции).

0 голосов
/ 23 февраля 2011

Не очень хорошая идея использовать отправленное сообщение.Я думаю, что вы должны попытаться обойти проблему, что библиотеки DLL не могут ссылаться друг на друга ...

...