Отправка/получение строки через PostMessage

Хотя в Интернете уже есть несколько ресурсов, посвященных этой сложной теме, я до сих пор не нашел подходящего ответа.

Я хочу иметь полную связь между моим процессом VB.net и моим процессом C++. Я хотел бы иметь возможность отправлять строку в и из процесса C++, но пока мне нужно добиться:

Отправка строки процессу C++ и ее обработка.

Это создает несколько моментов, в которых я не уверен, но я постараюсь сделать это как можно проще...

Используя следующее объявление функции в VB;

Declare Function PostMessage Lib "user32" Alias "PostMessageA" ( _
    ByVal hWnd As IntPtr, _
    ByVal Msg As UInteger, _
    ByVal wParam As IntPtr, _
    ByVal lParam As String _
) As Boolean

И отправив сообщение так;

PostMessage(hWnd, SM_PING, Nothing, "schlampe")

Со следующим объявлением метода для захвата сообщения в C++;

LRESULT CALLBACK newWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

И для проверки того, могу ли я получить доступ к строке, используя;

char buffer[50];
sprintf(buffer, "Received: %s", (char *)lParam);
MsgBox(buffer);


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

Моя проблема в том, что сообщение получено получено и "обработано"... но окно сообщения, созданное процессом C++, не содержит моего тестового сообщения (оно гласит: "Получено:").

Итак, как я могу отправить строку через PostMessage/SendMessage из VB в C++?




Решение:

См. принятый ответ для решения... но, кроме того, вот как я получаю строку (С++):

LRESULT CALLBACK newWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch(uMsg) {
        case WM_COPYDATA:
            MsgBox("Received a WM_COPYDATA message");
            COPYDATASTRUCT * pcds = (COPYDATASTRUCT *)lParam;
            LPCTSTR lpszString = (LPCTSTR)(pcds->lpData);
            MsgBox(lpszString);
            return 1L;
    }
    return CallWindowProc(instance->OriginalProcessor(), hwnd, uMsg, wParam, lParam);
}


И, наконец, я использовал пример IPC здесь, чтобы отправить сообщение. В этом примере сообщение отправляется с использованием C#, но мне нужна была только эта концепция (не говоря уже о том, что преобразовать такой код в VB несложно). Обратите внимание, что в моей реализации VB мне не нужно было заканчивать строку нулевым символом.


person Spooky    schedule 16.05.2012    source источник
comment
Является ли требование использования оконных сообщений конкретным? Или передача данных между процессами является конечной целью? Для последнего есть лучшие способы добиться этого.   -  person ulidtko    schedule 16.05.2012
comment
Вы, вероятно, должны сделать некоторую базовую проверку COPYDATASTRUCT перед его использованием. Какое-то вредоносное приложение может отправлять вам поддельные WM_COPYDATA сообщения.   -  person jamesdlin    schedule 17.05.2012


Ответы (1)


При использовании сообщений Windows следует использовать WM_COPYDATA для передачи строковых данных между процессами. Если вы используете настраиваемые идентификаторы сообщений, строковые данные не будут сортироваться между двумя разными адресными пространствами процесса.

И именно поэтому ваш текущий код терпит неудачу. Принимающему процессу передается lParam указатель на память в адресном пространстве вызывающего процесса. И, конечно, это бессмысленно в другом процессе.

Хотя существуют и другие способы маршалинга данных между процессами с сообщениями Windows, WM_COPYDATA, безусловно, самый простой. Если ваши требования становятся намного более сложными, вам может потребоваться рассмотреть более комплексный подход IPC, чем сообщения Windows.

person David Heffernan    schedule 16.05.2012
comment
Я бы обязательно упомянул общие способы выполнения IPC: каналы, разделяемая память + мьютексы, сокеты и т.д. - person ulidtko; 16.05.2012
comment
@ulidtko Я исследовал другие методы и пришел к выводу, что сообщения Windows доставят мне меньше хлопот, но спасибо за беспокойство. - person Spooky; 16.05.2012
comment
Нужно ли использовать OnCopyData для получения данных? Важно отметить, что моя C++ DLL внедряется в другой процесс, и я не уверен, смогу ли я получить COPYDATASTRUCT - person Spooky; 16.05.2012
comment
Кроме того, я бы предпочел не делать невидимое окно из моей C++ DLL (для получения OnCopyData)... но если нет другого способа, я уступлю. - person Spooky; 16.05.2012
comment
Вам нужно невидимое окно. - person David Heffernan; 16.05.2012
comment
@DavidHeffernan Посмотрите мой измененный первый пост, чтобы увидеть, как я добился этого без невидимого окна. Можете ли вы назвать недостаток использования этого метода? - person Spooky; 16.05.2012
comment
Вы повторно используете существующий дескриптор окна? Это тоже хорошо. - person David Heffernan; 16.05.2012
comment
Я обошел WndProc окна, используя SetWindowLong со смещением GWL_WNDPROC, чтобы создать подкласс окна (?) (см.: в этом примере) - person Spooky; 16.05.2012
comment
@Spooky: Вы можете использовать окно только для сообщений, если вам от этого станет лучше. - person jamesdlin; 17.05.2012