Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: 1 [2]  Все   Вниз
  Печать  
Автор Тема: Как передать команду (число) в другой процесс?  (Прочитано 42835 раз)
0 Пользователей и 3 Гостей смотрят эту тему.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #30 : 12-09-2013 16:41 » 

Джон, видимо, правами доступа. Каковые в последних версиях Windows стали какими-то вовсе неприлично сложно организованными.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
jur
Помогающий

lt
Offline Offline

« Ответ #31 : 12-09-2013 19:24 » 

Провел ряд успешных и не очень экспериментов. Пришел к выводу, что всякие Send/PostMessage, а тем более пайпы, майлслоты - это все или сложно, или запутанно, или не отвечает условиям задачи. Остановился на решении, предложенном уважаемым коллегой Dimka, т.е. Memory mapped file.

Напомню, речь идет о связи двух процессов типа тока-точка для передачи команды (двоичного числа). Это условие позволило максимально упростить задачу. Алгоритм сводится к следующему.

1.   Головная программа (сервер) создает два межпроцессных объекта: ивент и файл в памяти (Memory mapped file).
2.   Далее все просто, как дверь. Головная программа в случае необходимости передать команду (число) проверяет, не установлен-ли ивент.
3а. Если ивент установлен, то считается, что на том конце никого нет и команда отбрасывается (ее некому передавать).
3б. Если ивент сброшен, то команда (или любые нужные данные, например некая структура) записывается в файл и ивент устанавливается.

На стороне клиента алгоритм еще проще.

4. Открываются оба межпроцессных объекта. Ивент сбрасывается, чтобы не реагировать на старые данные, которые могут быть в файле.
5. Ожидаем сигнала ивента.
6. Когда сигнал поступает, забираем пришедшие данные и сбрасываем ивент, тем самым сигнализируя головной программе, что можно посылать новые данные.

Выглядит все это так. Запускаем сервер и клиент:


Затем нажимаем кнопку "Start" и наслаждаемся результатом:


Если клиента закрыть, то начинают считаться пропущенные пакеты. При повторном старте клиента пакеты начинают передаваться ему как ни в чем не бывало :-)

И все! Простое и элегантное решение! Как говорится: "Мы в восхищении!" (С) Кот Бегемот :-)

P.S. Прилагаю два проекта, иллюстрирующих применение этого механизма: клиент и сервер. Общие параметры описаны в файле "Transfer_defines.h". В нем определяются имена объектов и размер передаваемого блока данных. Функционал передачи/приема соответственно в файлах "Transfer_server.cpp" / "Transfer_client.cpp".

P.P.S. Я работаю на Win XP. Но проверял эти две программки на Win 7 64 бита (причем, в режиме обычного пользователя, не Администратора). Все работает нормально.


* Transfer_probe.zip (274.11 Кб - загружено 888 раз.)
« Последнее редактирование: 12-09-2013 19:33 от jur » Записан

MPEG-4 - в массы!
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #32 : 12-09-2013 20:34 » 

Джон, видимо, правами доступа. Каковые в последних версиях Windows стали какими-то вовсе неприлично сложно организованными.

Нуууу дык... На 7 64-bit с включённым UAC работает, на 7 32-bit без UAC тоже...


Код: (C++)
#define MY_MSG WM_USER+777
BOOL CReceiverDlg::PreTranslateMessage(MSG* pMsg)
{
        if(pMsg->message == MY_MSG)
        {
                m_stTrace.Format(_T("Value received: %d"), pMsg->wParam);
                UpdateData(FALSE);
        }
        return CDialogEx::PreTranslateMessage(pMsg);
}

void CSenderDlg::OnBnClickedOk()
{
        UpdateData(TRUE);
        CWnd *pWnd = CWnd::FindWindow(NULL, _T("Receiver"));
        if(pWnd) pWnd->PostMessageW(MY_MSG, m_nValue, 0);
}


Для пробы (на sendspace потому что компильнул MFC статически, студия 2012 и получилось ~3 МБ):
http://www.sendspace.com/file/ajitbs

* sender.gif (3.35 Кб - загружено 1532 раз.)
* receiver.gif (4.43 Кб - загружено 1577 раз.)
« Последнее редактирование: 12-09-2013 20:45 от Джон » Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
jur
Помогающий

lt
Offline Offline

« Ответ #33 : 12-09-2013 21:24 » 

На 7 64-bit с включённым UAC работает, на 7 32-bit без UAC тоже...

У меня PostMessage с юзеровскими кодами - ни в какую. Я с этого начал :-) Пока ковырялся да разбирался - сделал костыли в виде кода 0x03FF. С этим кодом PostMessage работает, команда доходит по назначению, но, понятно, это решение кривое. Да и чего-нибудь побольше, чем число (ну или два числа) не передашь. С Memory mapped file - совсем другое дело! Да и размер кода получился пустяшный :-)

Записан

MPEG-4 - в массы!
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #34 : 12-09-2013 21:43 » 

Нуууу дык. Изначально в задачке стояло передать одно число:

Мне нужно просто-напросто передать команду (число типа int) в другой процесс.
...
максимально просто, несколькими строками текста программы

Хотя если честно, меня заинтересовало именно почему вдруг не работает с PostMessage, тем более как ты говоришь на ХРюше (ладно бы на 8 или 8.1), ведь собственно вся винда построена в тч и на этих сообщениях. Те получается фундамент дал трещину?

зы Покажи изначальный код с PostMessage, как пробовал?
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
jur
Помогающий

lt
Offline Offline

« Ответ #35 : 13-09-2013 06:36 » 

Нуууу дык. Изначально в задачке стояло передать одно число:

Да. На первом этапе мне бы этого и хватило. Но ведь не работало, зараза...


зы Покажи изначальный код с PostMessage, как пробовал?

Да там проще валенка. Я вообще люблю простой код. Терпеть не могу темплейты, всякие навороченные иерархии классов и т.п. наукообразную лабуду, в которой сам же потом с большим трудом можешь разобраться :-) Темплейты и тем более классы я применяю очень широко, но они у меня простые, понятные и самодокументируемые (в сложных местах - конечно комментарии).

Поэтому и здесь я хотел сделать как можно проще, т.к. задача в общем-то элементарная. Начал с такого кода (макрос DEBUG_LOG - это вроде printf'а в файл лога, module - имя текущего программного модуля, т.е. функции, Hwnd - окно главной программы, catchBt - код нажатой клавиши).

Код:

В специальном заголовочном файле определены:

#define WM_SCUSB_ENCODER_CHANGE         (WM_USER+1)
#define WM_SCUSB_VARU_CHANGE            (WM_USER+2)
#define WM_SCUSB_KEY_PRESS              (WM_USER+3)
#define WM_SCUSB_TRACKBALL_MOVED        (WM_USER+4)
#define WM_SCUSB_ENCODER_KEY_PRESSED    (WM_USER+5)

В триде считывания клавиатуры (наших спец-клавиш) есть такой код:

   DEBUG_LOG("%s(): Event - normal SLE key pressed\r\n", module);
   ::PostMessage(Hwnd, WM_SCUSB_KEY_PRESS, NULL, catchBt);
   {
      HWND for_window = GetForegroundWindow();  // Посылаем наш код текущей внешней программе
      DEBUG_LOG("%s(): SLE901 hwnd = 0x%08X, foreground window  = 0x%08X\r\n", module, Hwnd, for_window);
      if(for_window != NULL && for_window != Hwnd) {
         ::PostMessage(for_window, WM_SCUSB_KEY_PRESS, NULL, catchBt);
      }
   }


Внешняя программа ни хрена не получает. Временно заменил WM_SCUSB_KEY_PRESS на 0x03FF - все работает нормально, но это кривой путь. Теперь смогу сделать по-человечески :-)

А насчет передачи чего-то бОльшего, чем просто команды - так это эволюция :-) Например, вместе с командой WM_SCUSB_ENCODER_CHANGE я смогу сразу передать массив из 8 int'ов, говорящий внешней программе, который (-ые) именно енкодер changed. Это - удобно.

P.S. Пока применен такой код:

Код:

   {
      LPCTSTR state_ini = UtilsR1_Paths_GetStateIniFullPath();
      CString ext_window_name = UtilsR1_IniEx_GetString2("General", "ExtWindowName", "", TRUE, state_ini);
      if(ext_window_name.GetLength()) {
         HWND ext_window = ::FindWindow(NULL, ext_window_name);
         DEBUG_LOG("%s(): External window is 0x%08X, pressed key %d (%s)\r\n",
            module, ext_window, catchBt, GetKeyName(catchBt));
         if(ext_window)
            ::PostMessage(ext_window, 0x03FF, NULL, catchBt);
      }
   }
  

« Последнее редактирование: 13-09-2013 06:47 от jur » Записан

MPEG-4 - в массы!
zubr
Гость
« Ответ #36 : 13-09-2013 07:05 » 

Хмм... Меня изначально терзали смутные сомнения, но я их не решился озвучить. GetForegroundWindow - очень ненадежная конструкция в определении нужного окна. Почему нельзя окну присвоить какой то уникальный класс и определять его хендл через FindWindow, тогда стопудово будешь попадать в нужное окно, а так ты отправляешь сообщения на деревню дедушке.
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #37 : 13-09-2013 07:41 » 

GetForegroundWindow - очень ненадежная конструкция в определении нужного окна. Почему нельзя окну присвоить какой то уникальный класс и определять его хендл через FindWindow, тогда стопудово будешь попадать в нужное окно, а так ты отправляешь сообщения на деревню дедушке.

100% согласен

Но в данном случае смущает
Внешняя программа ни хрена не получает. Временно заменил WM_SCUSB_KEY_PRESS на 0x03FF - все работает нормально

Я бы проверил Spy-ем что вобще окну приходит.
« Последнее редактирование: 13-09-2013 07:43 от Джон » Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
jur
Помогающий

lt
Offline Offline

« Ответ #38 : 13-09-2013 12:15 » 

GetForegroundWindow - очень ненадежная конструкция в определении нужного окна.

100% согласен

И я 100% согласен :-) Поэтому и сделал, как в постскриптуме написано, т.е. через FindWindow.

Но в данном случае смущает
Внешняя программа ни хрена не получает. Временно заменил WM_SCUSB_KEY_PRESS на 0x03FF - все работает нормально
Я бы проверил Spy-ем что вобще окну приходит.

Я так, конечно, делал, проверял. В случае посылки WM_SCUSB_KEY_PRESS не приходит ничего, а в случае 0x03FF нормально приходит моя команда (код нажатой клавиши).

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

Большое спасибо за помощь, друзья!

Записан

MPEG-4 - в массы!
Страниц: 1 [2]  Все   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines