Отправить сообщение в С#
Я создаю приложение, которое использует основной проект, который связан с несколькими различными 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");
}
Ответы
Ответ 1
Вам не нужно отправлять сообщения.
Добавьте событие в одну форму и обработчик событий в другую. Затем вы можете использовать третий проект, который ссылается на два других, чтобы присоединить обработчик события к событию. Для этого две библиотеки DLL не должны ссылаться друг на друга.
Ответ 2
public static extern int FindWindow(string lpClassName, String lpWindowName);
Чтобы найти окно, вам нужно имя класса окна. Вот несколько примеров:
С#:
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 Directory)/Common/Tools/WINAPI/winapi32.txt.
Следующие два параметра - это определенные детали, если они необходимы. Что касается нажатия определенных клавиш, они будут точно определять, какой конкретный ключ нужно нажать.
Пример С#, установив текст "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, но эти примеры должны помочь понять, как отправить сообщение.
Ответ 3
Ты почти там. (изменение примечания в возвращаемом значении объявления 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 работает.
Но если вам нужно/нужно идти по этому маршруту, я думаю, что вышеизложенное приведет вас в правильном направлении.
Ответ 4
Не рекомендуется использовать сообщение отправки. Я думаю, вы должны попытаться решить проблему, что DLL не могут ссылаться друг на друга...
Ответ 5
Некоторые другие опции:
Общая сборка
Создайте еще одну сборку, которая имеет некоторые общие интерфейсы, которые могут быть реализованы сборками.
Отражение
У этого есть всевозможные предупреждения и недостатки, но вы можете использовать отражение для создания экземпляра/общения с формами. Это медленная и динамическая динамика (статическая проверка этого кода во время компиляции).
Ответ 6
Отвечая на вопрос Марка Байерса.
Третий проект может быть проектом WCF, размещенным в качестве службы Windows. Если все программы прослушали эту услугу, одно приложение может вызвать службу. Служба передает сообщение всем слушающим клиентам, и они могут выполнять действие, если оно подходит.
Хорошие видео WCF здесь - http://msdn.microsoft.com/en-us/netframework/dd728059