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

Я создаю приложение, которое использует основной проект, который связан с несколькими различными 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