Отправить сообщение в C#
Я создаю приложение, которое использует основной проект, который подключен к нескольким различным 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 ответов
Вам не нужно отправлять сообщения.
Добавьте событие в одну форму и обработчик события в другую. Затем вы можете использовать третий проект, который ссылается на два других, чтобы прикрепить обработчик события к событию. Две библиотеки DLL не должны ссылаться друг на друга, чтобы это работало.
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, является константой, обозначающей ТИП сообщения, которое вы отправляете. Сообщение может быть нажатием клавиши (например, отправить "ключ ввода" или "пробел" в окно), но это также может быть команда закрытия окна (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, но эти примеры должны помочь понять, как отправить сообщение.
Вы почти там. (обратите внимание на изменение в возвращаемом значении объявления 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.
Но если вы хотите / должны идти по этому пути, я думаю, что вышеизложенное поможет вам двигаться в правильном направлении.
Некоторые другие варианты:
Общее собрание
Создайте другую сборку, которая имеет некоторые общие интерфейсы, которые могут быть реализованы сборками.
отражение
Это имеет все виды предупреждений и недостатков, но вы можете использовать отражение для создания экземпляров / общения с формами. Это и медленный, и динамический динамический режим (без статической проверки этого кода во время компиляции).
Опираясь на Марк Байерс ответ.
Третий проект может быть проектом WCF, размещенным как служба Windows. Если все программы прослушивают этот сервис, одно приложение может вызвать сервис. Служба передает сообщение всем прослушивающим клиентам, и они могут выполнить действие, если это необходимо.
Хорошие видео WCF здесь - http://msdn.microsoft.com/en-us/netframework/dd728059
Это не похоже на хорошую идею использовать отправку сообщения. Я думаю, что вы должны попытаться обойти проблему, что библиотеки DLL не могут ссылаться друг на друга...