Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Обмен сообщениями между программами

490
28 октября 2007 года
frid-karatel
357 / / 15.09.2007
Как реализовать обмен сообщениями между программами?

Интересует такой вот формат:
Программа1 -> SendMessage(<param>) -> Программа2
switch (<param>)
{ case <something>: ....}

Как лучше всего это сделать? То есть я бы хотел посылать какие-нибудь переменные из Программы1 в Программу2, в свою очередь Программа2 обработала операции, связанные с посланной переменной и отправила Программе1.

Получается логикак как у клиент-серверного приложения... :)
3
28 октября 2007 года
Green
4.8K / / 20.01.2000
Используй pipe. Поищи по форуму, не раз обсуждалось.
490
29 октября 2007 года
frid-karatel
357 / / 15.09.2007
но у меня не консольное приложение... у меня две программы с формами... я к Программе2 подключаю DLL, в которой и надо реализовать фунции обмена сообщениями... чтобы получать некоторыезначения на Label, а также нажимать кнопки и заполнять некоторые контролы значениями.
240
29 октября 2007 года
aks
2.5K / / 14.07.2006
Цитата: frid-karatel
но у меня не консольное приложение...


И что с того?

490
29 октября 2007 года
frid-karatel
357 / / 15.09.2007
pipe мне не совсем подходит, точнее, вряд ли полходит...

у меня тут есть две интересные мысли:
1. использовать BEGIN_MESSAGE_MAP. Вот я набросал код:
Код:
struct TMyData
{
 char Text1[100];
 int Data1;
 int Data2;
};
TMyData *MyData;
<...>
BEGIN_MESSAGE_MAP
      MESSAGE_HANDLER(WM_COPYDATA, TMessage, OnMyMessage)
    END_MESSAGE_MAP(TForm)
<...>
void __fastcall TForm1::OnMyMessage(TMessage& Message)
{
  COPYDATASTRUCT *cpDS;
  cpDS = (COPYDATASTRUCT *)(void *)Message.LParam;
  MyData = (TMyData *)(cpDS->lpData);
  Edit1->Text = MyData->Text1;
  Edit2->Text = IntToStr((int)MyData->Data1);
  Edit3->Text = IntToStr((int)MyData->Data2);
};

И сразу проблема - у меня же не инициализируется в DLL класс формы Form1, а предложенный MESSAGE инициализируется в разделе public формы в заголовочном файле... что делать? Создать новую форму? или есть другой путь решения?

2. У каждого WinControl (и у TCustomForm) есть метод DefaultHandler(void *Message). Его можно подменить в производном классе (например, в форме Form1) приблизительно так:
Код:
void __fastcall TForm1::DefaultHandler(void* Message)
{
  TMessage *msg=(TMessage*)Message;
  switch(msg->Msg)
  {
    case WM_USER:  // твое сообщение  
    if (msg->WParam == ....)
    {  
      // какая-то обработка
      msg->Result = tue;
      return;
    }
  }
  TForm::::DefaultHandler(Message);  // вызов базового метода
}

И опять проблема... как это встроить в DLL? ведь я не могу просто так взять и объявить функцию void __fastcall TForm1 :: DefaultHandler(void* Message)... у меня в DLL нет формы... как быть?

Прошу помочь разобраться во всем этом...
3
29 октября 2007 года
Green
4.8K / / 20.01.2000
Цитата: frid-karatel
pipe мне не совсем подходит, точнее, вряд ли полходит...


А почему?

490
29 октября 2007 года
frid-karatel
357 / / 15.09.2007
1. сложно
2. вывод в файл
3. прочитал статью (http://www.codenet.ru/progr/bcb/pipes.php)
3.1 много кода писать приходится
3.2 используется (и практически везде) в работе с консолью
3.3. и т.д. в течение статью
4. некоторые другие нюансы
5. короче, pipe - это капец, и вряд ли мне лучше использовать его...

Я подумал - и решил, что в моем случае лучше - SendMessage() - проще, удобней и т.п.
3
29 октября 2007 года
Green
4.8K / / 20.01.2000
1. Просто. Да и аргумент не программиста.
2. Это вообще к чему? В какой файл?
3.1 Код примерно следующий:
CreatePipe
WriteFile
ReadFile
это сложно?
3.2 При чем тут консоль?
4. "некоторые др. нюансы" - это "надо разбираться, а влом" ?
5. pipe - это правильное решение, а SendMessage() базируется на оконных сообщениях, т.е. будут тормоза.

Впрочем, дело твое. Рациональное решение тебе подсказали, а воспользоваться им или делать через... дело твое.
490
30 октября 2007 года
frid-karatel
357 / / 15.09.2007
хм, убедил :) мне необходимо использовать обмен сообщениями между моей программой и программой, к которой я подключу свой DLL - значит с DLL, т.е. инициализировать в DLL все операции...

как это можно сделать - можешь подкинуть простой примерчик?
3
30 октября 2007 года
Green
4.8K / / 20.01.2000
Хороший пример есть в MSDN. Он состоит из двух частей:
1) сервер - http://msdn2.microsoft.com/en-us/library/aa365588.aspx
2) клиент - http://msdn2.microsoft.com/en-us/library/aa365592.aspx

Не пугайся объема кода, там просто все разжевано и куча проверок на всевозможные ошибки.
Сам же процесс сводится на стороне сервера
1) создание именованного pipe - CreateNamedPipe
2) ожидание подключения - ConnectNamedPipe
далее идет заточка на многопоточность, но можно без этого
3) читаем из pipe - ReadFile
4) пишем в pipe - WriteFile

на стороне клиента:
1) попытки подключиться к pipe - CreateFile, WaitNamedPipe
2) переключение pipe в "message-read mode" - SetNamedPipeHandleState
3) пишем в pipe - WriteFile
4) читаем из pipe пока возможно - ReadFile

я для себя это все обернул примерно в след. классы:
Код:
class PipeBase
{
public:
    void close();
    bool send(void* buff, size_t size);
    bool recv(void* buff, size_t& size);

protected:
    PipeBase();
    ~PipeBase();

    HANDLE hPipe;
};


class ServerPipe :public PipeBase
{
public:
    bool create(const char* name);
    bool connect();
};


class ClientPipe :public PipeBase
{
public:
    bool open(const char* name);
};

Код:
//============================================================================
//  PipeBase
//
PipeBase::PipeBase() :hPipe(INVALID_HANDLE_VALUE)
{}

PipeBase::~PipeBase()
{
    close();
}

void PipeBase::close()
{
    if(INVALID_HANDLE_VALUE != hPipe) {
        CloseHandle(hPipe);
        hPipe = INVALID_HANDLE_VALUE;
    }
}

bool PipeBase::send(void* buff, size_t size)
{
    DWORD bytes;
    return (WriteFile(hPipe, buff, (DWORD)size, &bytes, NULL) == TRUE);
}

bool PipeBase::recv(void* buff, size_t& size)
{
    return (ReadFile(hPipe, buff, (DWORD)size, (PDWORD)&size, NULL) == TRUE);
}


//============================================================================
//  ServerPipe
//
bool ServerPipe::create(const char* name)
{
    std::string pipeName("\\\\.\\pipe\\");
    pipeName += name;

    hPipe = CreateNamedPipe(pipeName.c_str(), PIPE_ACCESS_DUPLEX,
        PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
        PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE,
        NMPWAIT_USE_DEFAULT_WAIT, NULL);

    return (INVALID_HANDLE_VALUE != hPipe);
}

bool ServerPipe::connect()
{
    BOOL res = ConnectNamedPipe(hPipe, NULL);
    return (res == TRUE ? true : GetLastError() == ERROR_PIPE_CONNECTED);
}


//============================================================================
//  ClientPipe
//
bool ClientPipe::open(const char* name)
{
    std::string pipeName("\\\\.\\pipe\\");
    pipeName += name;

    while(true) {   // !!!
        hPipe = CreateFile(pipeName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
        if (INVALID_HANDLE_VALUE != hPipe) {
            break;
        }
        DWORD err = GetLastError();
        if (GetLastError() != ERROR_PIPE_BUSY) {
            return false;
        }      
        if (!WaitNamedPipe(name, 200)) {    // All pipe instances are busy, so wait for 200 ms.
            return false;
        }
    }

    DWORD dwMode = PIPE_READMODE_MESSAGE;
    BOOL res = SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL);
   
    return (res == TRUE);
}
246
30 октября 2007 года
GIZMO
1.8K / / 30.07.2004
Цитата: frid-karatel
И опять проблема... как это встроить в DLL? ведь я не могу просто так взять и объявить функцию void __fastcall TForm1 :: DefaultHandler(void* Message)... у меня в DLL нет формы... как быть?


Обычная тема для организации обмена сообщениями для "неоконного" компонента и т.п. - создание вспомогательного (невидимого) окна. В VCL-е для этого есть вспомогательная ф-и AllocateWnd/DeallocateWnd.

490
30 октября 2007 года
frid-karatel
357 / / 15.09.2007
Green, а использование pipe действительно лучше?
GIZMO, ты знаешь, что я тут делал и для чего мне нужна была DLL - посоветуй тоже - следует ли мне в моем случае использовать pipe или нет?
246
30 октября 2007 года
GIZMO
1.8K / / 30.07.2004
Цитата: frid-karatel

GIZMO, ты знаешь, что я тут делал и для чего мне нужна была DLL - посоветуй тоже - следует ли мне в моем случае использовать pipe или нет?


хз, пусть Green аргументирует ... он наверняка ветку, про доступ к VCL-объектам чужой программы читал
(кстати выше неправильно обозвал ф-ию - AllocateHWnd).
Я бы использовал сообщения + разделяемый мап-файл. SendMessage - обеспечит в этом случае и запрос и синхронизацию:
Из ЕХЕ через SendMessage шлем пользовательское сообщение сервисному окну в dll (например запрос какого-либо св-ва). Оконная процедура сервисного окна получив соотв. сообщение, пишет в мап-файл значение св-ва и возвращает управление в EXE. Как только отработала оконная процедура сервисного окна
идем дальше - читаем результат из мап-файла.
void GetEditText()
{
// просим, hWndInDll - создано в dll и записано в разделяемую память(мап-файл)
SendMessage(hWndInDll, WM_GETEDITTEXT_, 0, 0);
// читаем из мап-файла
}
можно просить вообще все (св-ва + значения) сразу это как тебе удобно.

490
31 октября 2007 года
frid-karatel
357 / / 15.09.2007
я тут подумал - может сделать так? :
создать на форме ПСР два Edit'а (или три :) ), в них через DLL добавлять значения, полученные из СтутусБара и Прогресса... Если значение изменилось, DLL делает SendMessage() мое программе, что, мол, обнови данные... Моя программа находит форму и получает значения из всех необходимых Edit'ов, в которые я занес данные... как такая реализаця - туповатая? :)
1
31 октября 2007 года
kot_
7.3K / / 20.01.2000
Цитата: frid-karatel
я тут подумал - может сделать так? :
создать на форме ПСР два Edit'а (или три :) ), в них через DLL добавлять значения, полученные из СтутусБара и Прогресса... Если значение изменилось, DLL делает SendMessage() мое программе, что, мол, обнови данные... Моя программа находит форму и получает значения из всех необходимых Edit'ов, в которые я занес данные... как такая реализаця - туповатая? :)


Есть несколько нормальных способов это сделать:
1. Использование пайпов - как было сказано выше решение практически наиболее оптимальное.
2. Использование сокетов - тоже ничем не худшее и маштабируемое решение.
3. Использование почтовых слотов - знаю о таком но сам реально не использовал, потому ничего конкретного сказать не могу.
4. Использование COM - громоздко и не очень надежно - но вполне нормально.
5. Использование мап-файлов (разделяемой памяти и все т.п.) - годится как подручное решение в некоторых случаях может быть оптимальным.
Все остальные реализации может и могут быть использованы - но оно надо? кстати забыл еще один способ - но думаю 5 приведенных достаточно.

240
31 октября 2007 года
aks
2.5K / / 14.07.2006
Цитата: kot_
Есть несколько нормальных способов это сделать:
2. Использование сокетов - тоже ничем не худшее и маштабируемое решение.


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

1
31 октября 2007 года
kot_
7.3K / / 20.01.2000
Цитата: aks
На самом деле пайпы предпочтительней, ибо реально могут быть реализованны снизу как угодно, в том числе и парой приведенных тут способов. Но при этом довольно универсальны. Сокеты по сути предоставляют почти тот же интерфейс что и пайпы только чуть более громоздкий. Но всеж их предназначение другое. Как то некрасиво это. )


Их (в смысле сокетов) предназначение как раз и заключается в передаче данных и установке связи между приложениями :)

490
31 октября 2007 года
frid-karatel
357 / / 15.09.2007
эх... pipe так pipe... :)
240
01 ноября 2007 года
aks
2.5K / / 14.07.2006
Цитата: kot_
Их (в смысле сокетов) предназначение как раз и заключается в передаче данных и установке связи между приложениями :)


Но универсальной пердачи по сети. А пайпы - для простой связи приложений. А так интерфейс аналогичный почти. Темболее, что сокеты сами могут служить основой для них )

490
01 ноября 2007 года
frid-karatel
357 / / 15.09.2007
сокеты какие ? я чего-то не могу понять - это что ли TClientSocket и TServerSocket? :) кстати, а через них можно же посылать... ;)
3
01 ноября 2007 года
Green
4.8K / / 20.01.2000
М-да... целую рабочую неделю мусолить механизм, реализация которого занимает полчаса, а если воспользоваться теми наметками классов, которые я привел, то минут за 10 можно управиться.
Это, наверное, самая важная часть твоей программы?
241
01 ноября 2007 года
Sanila_san
1.6K / / 07.06.2005
Цитата: Green
М-да... целую рабочую неделю мусолить механизм, реализация которого занимает полчаса, а если воспользоваться теми наметками классов, которые я привел, то минут за 10 можно управиться.

А это всё от обилия возможных решений и от нежелания эти решения принимать самостоятельно. А может, автор просто никуда не торопится.

490
01 ноября 2007 года
frid-karatel
357 / / 15.09.2007
Green, я уже твой код опробываю ;) остановился на pipe...
Sanila_san,
Цитата:
А может, автор просто никуда не торопится.


Тороплюсь ;) я делаю другие части программы...

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

490
01 ноября 2007 года
frid-karatel
357 / / 15.09.2007
есть еще такая вещь - разделяемая память... в каких случаях она вообще используется, и подойдет ли она к моему случаю?
490
01 ноября 2007 года
frid-karatel
357 / / 15.09.2007
1. bool send(void* buff, size_t size); - Type name expected
2. HANDLE hPipe; - Declaration missing ;
3. PipeBase::PipeBase():hPipe(INVALID_HANDLE_VALUE){} - 'hPipe' is not an unambiguosbase class of 'PipeBase'
4. if(INVALID_HANDLE_VALUE != hPipe) - Undefined symbol 'INVALID_HANDLE_VALUE'
5. if(INVALID_HANDLE_VALUE != hPipe) - Undefined symbol 'hPipe'
6. И т.д.

может я не так все объявил?

как должны выглядеть Unit1.cpp и Unit1.h? Я просто думал создать два файла - pipe.cpp и pipe.h, которые буду подключать к программе... как лучше всего это сделать?
3
02 ноября 2007 года
Green
4.8K / / 20.01.2000
Надо подключить windows.h
А на счет разделяемой памяти, так стандартно pipe и базируется на ней.
246
02 ноября 2007 года
GIZMO
1.8K / / 30.07.2004
Цитата: frid-karatel

проблема... как это встроить в DLL? ведь я не могу просто так взять и объявить функцию void __fastcall TForm1 :: DefaultHandler(void* Message)... у меня в DLL нет формы... как быть?


А зачем она нужна, форма?
Например, пределано наспех из одного класса и засунуто в dll ...

Код:
// in dll
class TEditHook
{
private:
    TEdit*          FEdit;
    HWND            FWnd;
    TKeyPressEvent  OnKeyPress;
    void __fastcall OnKeyPress2(TObject *Sender, char &Key);
public:
    void __fastcall Attach(TEdit* AEdit);
    void __fastcall Detach();
public:
    __fastcall TEditHook(String WndName);
    __fastcall ~TEditHook();
};
-------------------------------------------------------------
__fastcall TEditHook::TEditHook(String WndName)
{
    FEdit = NULL;
    OnKeyPress = NULL;
    FWnd = FindWindow(NULL, WndName.c_str());
}
//---------------------------------------------------------------------------
__fastcall TEditHook::~TEditHook()
{
    Detach();
}
//---------------------------------------------------------------------------
void __fastcall TEditHook::Attach(TEdit* AEdit)
{
    //TODO: Add your source code here
    if(FEdit) Detach();

    if(AEdit)
    {
        FEdit = AEdit;
        OnKeyPress = FEdit->OnKeyPress;
        FEdit->OnKeyPress = OnKeyPress2;
    }
}
//---------------------------------------------------------------------------
void __fastcall TEditHook::Detach()
{
    //TODO: Add your source code here
    if(FEdit)
    {
        FEdit->OnKeyPress = OnKeyPress;
        FEdit = NULL;
    }
}
//---------------------------------------------------------------------------

void __fastcall TEditHook::OnKeyPress2(TObject *Sender, char &Key)
{
  if(OnKeyPress)
    OnKeyPress(Sender, Key);

  if(FWnd)
  {
    String data("Кто-то нажал - "); data += Key;
    COPYDATASTRUCT CopyData = { 0, strlen(data.c_str()) + sizeof(char), data.c_str()};
    ::SendMessage( FWnd, WM_COPYDATA, NULL, reinterpret_cast<LPARAM>(&CopyData));
  }
}
//----------------------------------------------------------
...
#define TESTDLL_EXPORTS
#include "testdll.h"
#include "hook_events.h"

extern HHOOK    hHook;
HINSTANCE       hDLL;
char            Work[256];
String          s;
Windows::HINST  hModule=NULL;

TForm *fmMain=NULL;
TEditHook ehk("VCLViewer"); //<===========
...
TForm **pForm=(TForm**)::GetProcAddress(::GetModuleHandle(NULL), "_TargetForm");
            if(pForm == NULL)
            {
                ShowMessage("ERROR: export not found");
            }
            else
            {
                fmMain=*pForm;
                if(fmMain == NULL)
                {
                    ShowMessage("ERROR: form is not accessible");
                }

                TEdit* ed = (TEdit*)fmMain->FindComponent("Edit1");
                if(!ed)ShowMessage("Edit1 not found");
                else
                {ehk.Attach(ed); }
            }
...
// in injector
// hpp
class TfmMain : public TForm
{
...
protected:
    BEGIN_MESSAGE_MAP
        VCL_MESSAGE_HANDLER(WM_COPYDATA, TMessage, OnWMCopyData)
    END_MESSAGE_MAP(TForm)
};
// cpp
void __fastcall TfmMain::OnWMCopyData(TMessage& Message)
{
   
    DWORD CountData;
    PCOPYDATASTRUCT PassedCopyDataStruct;

    char* data;

    PassedCopyDataStruct = reinterpret_cast<COPYDATASTRUCT*>(Message.LParam);

    CountData = PassedCopyDataStruct->cbData;
    if (CountData > 0) {
        data = new char[CountData];
        if (PassedCopyDataStruct->lpData != NULL)
            memmove(data, PassedCopyDataStruct->lpData, CountData);
    }

    Win32Check( ReplyMessage(true) );

    if(data)
        Memo1->Lines->Add(data);

    delete [] data;
}

Запускаю тестовую прогу, запукаю инжектор, ставлю хук, набираю текст в Edit1 тестовой программы тоже добавляется в Memo1 инжектора.
246
02 ноября 2007 года
GIZMO
1.8K / / 30.07.2004
Цитата: frid-karatel
есть еще такая вещь - разделяемая память... в каких случаях она вообще используется, и подойдет ли она к моему случаю?


я же тебе на это уже раза три намекал:)

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог