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

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

lt
Offline Offline

« : 06-09-2013 19:02 » 

Привет!

Возникла примитивная задача, про которую я сначала подумал, что щелкать семечки по-сравнению с ней - тяжелый труд :-) Мне нужно просто-напросто передать команду (число типа int) в другой процесс. Какие проблемы? PostMessage и все дела! Благо HWND его (в смысле, другого процесса) окна я знаю. Команда, конечно, собственная, из диапазона > WM_USER. Оказывается не все так просто! (Ёлки! Думается, что в Микрософте рулят сплошь бывшие советские комсомольцы: им, видите ли, не интересно, если не в гамаке на лыжах и с аквалангом...)

Ладно, начал углубляться в этот вопрос. Много чего просмотрел, с интересом прочитал топик Взаимодействие процессов - яснее не стало. Не, я понимаю, что через какой-нить Memory mapped file это сделать можно. Но хотелось бы попроще...

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

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

Как решить такую задачу максимально просто, несколькими строками текста программы (ну ладно, пол-странички)?

Спасибо!

P.S. Система Win XP, самое обычное PC-совместимое железо. 2008-я Студия, C/C++.
Записан

MPEG-4 - в массы!
zubr
Гость
« Ответ #1 : 06-09-2013 19:14 » 

1. FindWindowEx - находим все окна определенного класса, желательно с уникальным именем, соответствующие процессам, в которые надо передавать сообщения.
2. SendMessage в найденные окна.
Записан
jur
Помогающий

lt
Offline Offline

« Ответ #2 : 06-09-2013 19:30 » 

1. FindWindowEx - находим все окна определенного класса, желательно с уникальным именем, соответствующие процессам, в которые надо передавать сообщения.

Этого не нужно. Я же написал: HWND окна другого процесса я знаю.

2. SendMessage в найденные окна.

Не годится. SendMessage ждет получения сообщения другим окном. А я писал, что ждать нельзя: "Никакие таймауты не допустимы: не прочитал другой процесс команду пока пришла следующая - ну и черт с ней, со старой командой." Т.е. полностью устраивает команда PostMessage, но она не работает с сообщениями > WM_USER.

P.S. Точнее, работает, но "... в гамаке и с аквалангом..." :-)
« Последнее редактирование: 06-09-2013 19:33 от jur » Записан

MPEG-4 - в массы!
Вад
Модератор

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

« Ответ #3 : 07-09-2013 10:05 » 

Цитата
нужно сообщить другому процессу, что в данном процессе (типа, в головной программе, которая иногда порождает дочерние процессы) пользователь нажал кнопку, или сделал еще что-то с интерфейсом пользователя.
Может, каналы и использовать тогда: сокеты или пайпы попробовать?
Записан
zubr
Гость
« Ответ #4 : 07-09-2013 10:11 » 

Цитата
Не годится. SendMessage ждет получения сообщения другим окном. А я писал, что ждать нельзя: "Никакие таймауты не допустимы: не прочитал другой процесс команду пока пришла следующая - ну и черт с ней, со старой командой." Т.е. полностью устраивает команда PostMessage, но она не работает с сообщениями > WM_USER.
Ну CreateThread еще никто не отменял.
Записан
Dimka
Деятель
Команда клуба

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

« Ответ #5 : 07-09-2013 11:27 » 

Вад, в pipe'ах он не перезапишет ранее ушедшее. А при отсутствии подключения с той стороны буфер переполнится, и всё упадёт.

Либо в отдельном потоке крутить цикл опроса глобальной (межпоточной volatile переменной) и делать sendmessage. Либо сделать MemoryMappedFile - по сути глобальную межпроцессную область памяти тоже с volatile переменной.

Второй вариант с (MemoryMappedFile) предпочтительнее как с точки зрения быстродействия, так и с точки зрения простоты подключения клиентов-читателей, каковых может быть много. Но у него есть проблема с уведомлением клиентов об изменении данных. UNIX-сигналы в Windows работают скверно - по сути запускаются отдельные потоки внутри процесса для обработки сигнала, т.е. это не прерывание процесса, и возникает проблема синхронизации. SendMessage в этом плане ведёт себя хорошо, но у клиента нет возможности узнать, какие из сообщений пропускать. Кроме того, не вполне понятно, что будет при попытке сервера оборвать текущий SendMessage, когда на клиенте он стоит в очереди сообщений.
« Последнее редактирование: 07-09-2013 11:33 от Dimka » Записан

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

lt
Offline Offline

« Ответ #6 : 07-09-2013 18:49 » 

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

1. Данные будут помещаться в память, что позволит в будущем расширить размер передаваемой информации сверх простого числа. Иными словами Memory mapped file. Это позволит перезаписывать отправляемые данные, не заботясь о их получении другим процессом.

2. Для оповещения всех желающих о поступлении новых данных используется именованный ивент. Ожидает его кто-нибудь, или нет - до лампочки. "Мое дело сказать - я сказал. А вы сидите на мели, не сидите на мели - у нас в машине куча дел и без вас!" (С) :-)

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

Вот как-то так. Завтра попробую и отпишусь о результатах. Прельщает в таком решении то, что оно один-в-один похоже на простой RS-232 без хэндшейка :-)

Цитата
SendMessage ждет получения сообщения другим окном.
Ну CreateThread еще никто не отменял.

Увы, все равно не пройдет. Потому, что SendMessage в своем триде повиснет на передаче числа (если другого процесса нема) и не будет больше ни на что реагировать. Это не фатально, конечно, но как-то не очень... Не люблю, когда код на чем-то повисает, неприятно...

Записан

MPEG-4 - в массы!
zubr
Гость
« Ответ #7 : 07-09-2013 18:59 » 

Цитата
Увы, все равно не пройдет. Потому, что SendMessage в своем триде повиснет на передаче числа (если другого процесса нема) и не будет больше ни на что реагировать. Это не фатально, конечно, но как-то не очень... Не люблю, когда код на чем-то повисает, неприятно...
Глупости. Если нет процесса, нет окна, соответственно хендл неликвидный, SendMessage просто вернет ошибку. Да и проверять можно перед вызовом наличие окна.
Записан
Dimka
Деятель
Команда клуба

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

« Ответ #8 : 07-09-2013 20:17 » 

Цитата: jur
Для оповещения всех желающих о поступлении новых данных используется именованный ивент. Ожидает его кто-нибудь, или нет - до лампочки. "Мое дело сказать - я сказал. А вы сидите на мели, не сидите на мели - у нас в машине куча дел и без вас!"
Это подходит только для одиночного клиента. Причём нужен AutoEvent, иначе будет риск пропуска сообщения.

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

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

lt
Offline Offline

« Ответ #9 : 07-09-2013 20:32 » 

Если нет процесса, нет окна, соответственно хендл неликвидный, SendMessage просто вернет ошибку. Да и проверять можно перед вызовом наличие окна.

С одной стороны - да, можно. Но с другой стороны, неизвестно, сколько ждать, если то, другое окно есть. Оно может далеко не сразу получить это сообщение. Прямой вызов SendMessage в этом случае неприемлем из-за возможных задержек. Если же всю эту бодягу помещать в отдельный трид, со всеми необходимыми средствами синхронизации, то получится еще сложнее, чем с Memory mapped file.

Это подходит только для одиночного клиента. Причём нужен AutoEvent, иначе будет риск пропуска сообщения.

Да, клиент один. С этим вопросом проблем нет.

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

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

Записан

MPEG-4 - в массы!
zubr
Гость
« Ответ #10 : 07-09-2013 20:46 » 

Цитата
Если же всю эту бодягу помещать в отдельный трид, со всеми необходимыми средствами синхронизации, то получится еще сложнее, чем с Memory mapped file.
В том то и фишка, что с SendMessage никакой синхронизации не надо, в отличие от файлмаппинга. Как только надо послать сообщение создаешь новый поток с единственной командой SendMessage, хендл потока сразу закрываешь. Ну для очистки совести, на случай если процесс принимающий сообщения вдруг завис, можно прикрутить чистилку потоков, которая будет через определенный интервал проверять состояние потоков и тем которые висят больше допустимого времени делать терминайт.
Записан
jur
Помогающий

lt
Offline Offline

« Ответ #11 : 07-09-2013 21:43 » 

В том то и фишка, что с SendMessage никакой синхронизации не надо, в отличие от файлмаппинга. Как только надо послать сообщение создаешь новый поток с единственной командой SendMessage, хендл потока сразу закрываешь. Ну для очистки совести, на случай если процесс принимающий сообщения вдруг завис, можно прикрутить чистилку потоков, которая будет через определенный интервал проверять состояние потоков и тем которые висят больше допустимого времени делать терминайт.

Недопонял... Сложно как-то...

Расскажу, что у меня в мозгу сложилось с помощью уважаемого коллеги Dimka. Я применяю ивент, мьютекс и файлмаппинг для организации передающего канала (а-ля простейший RS-232), который ничуть не влияет на работу основной программы, нисколько ее не тормозит и просто посылает данные тем, кто готов их получить. Никто не захочет - и прекрасно, программа работает без проблем. Плюс тот, что в главной программе я вставлю единственную строку текста, что-то вроде SendData(command, my_data, my_data_size);

В случае же SendMessage мне все равно придется городить трид, а кроме того в головной программе делать "чистилку потоков".

Сравниваю плюсы и минусы. Получается: ивент с мьютексом и файлом - против трида с чистильщиком и SendMessage. Первый вариант, IMHO, проще :-) Кроме того, он сулит возможность в будущем передавать еще и блок данных, а не просто число. Это - хорошо. (Типа, команда "юзер подвинул ползунок N 3" и тут же массив из 8 байт с новыми значениями положений всех ползунков. Пока не нужно, но удобно, если понадобится. Так сказать, задел на будущее.)

P.S. Сейчас мне даже мьютекса не нужно, т.к. передается просто число. Мьютекс - это на будущее, чтобы передавать небольшие блоки данных.

« Последнее редактирование: 07-09-2013 21:51 от jur » Записан

MPEG-4 - в массы!
zubr
Гость
« Ответ #12 : 08-09-2013 07:55 » 

На самом деле с SendMessage все просто, тут и пол-страницы кода не нужно:
Код:
typedef struct Thread_Data
{
HWND hwnd;
        DWORD number;
}THREAD_DATA, *PTHREAD_DATA;

DWORD WINAPI SendThreadProc(LPVOID lpParameter)
{
       PTHREAD_DATA phtd = (PTHREAD_DATA)lpParameter;
       if(!IsWindow(phtd->hwnd))
       {
              VirtualFree(phtd, 0, MEM_RELEASE);
             return 0;
       }
       SendMessage(phtd->hwnd, WM_USER + 1, phtd->number, 0);
       VirtualFree(phtd, 0, MEM_RELEASE);
       return 1;
}

DWORD WINAPI DispathThreadProc(LPVOID lpParameter)
{
        if(!lpParameter)
        return 0;
        HANDLE hThread = CreateThread(NULL, 0, SendThreadProc, lpParameter, 0, NULL);
        if(!hThread)
        return 0;
        if(WaitForSingleObect(hThread, 1000/*ждем секунду*/) != WAIT_OBJECT_0)
        TerminateThread(hThread, 0);
        CloseHandle(hThread);
        return 1;
}

int main()
{
      //отправка сообщения
      PTHREAD_DATA pthrd = (PTHREAD_DATA)VirtualAlloc(NULL, sizeof(THREAD_DATA), MEM_COMMIT, PAGE_READWRITE);      
      pthrd->hwnd = 123;
      pthrd->number = 123;
      HANDLE hThread = CreateThread(NULL, 0, DispathThreadProc, pthrd, 0, NULL);
      CloseHandle(hThread);
}
Что касается передачи блока данных, то тогда, имхо проще вообще через файл все решить. На стороне сервера запись данных в определенный файл, на стороне клиента ставим нотификатор на этот файл и по WaitForSingleObject читаем файл. Тогда не надо двусторонней синхронизации и сопутствующим заморочкам с правами пользователя. Конечно, если скорость обмена данными не критична.
« Последнее редактирование: 08-09-2013 08:05 от zubr » Записан
Dimka
Деятель
Команда клуба

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

« Ответ #13 : 08-09-2013 11:18 » 

zubr, лишние потоки лучше, конечно, не создавать - использовать пул. Однако там, где надо обрывать зависшие потоки, пул не подходит.

Код: (C++)
#include <Windows.h>

class Post
{

private:

        struct Parameter
        {
                Post *Instance;
                int Value;

                Parameter(Post *instance, int value) :
                        Instance(instance),
                        Value(value)
                {}
        };

        static const int Timeout = 1000;

        const HWND targetWindowHandle;
        const UINT message;

        static DWORD WINAPI post(LPVOID parameter)
        {
                Parameter *argument = static_cast<Parameter *>(parameter);
                Post *instance = argument->Instance;
                int value = argument->Value;
                delete argument;
                instance->Send(value);
                return 0;
        }

        static DWORD WINAPI work(LPVOID parameter)
        {
                HANDLE thread = CreateThread(NULL, 0, Post::post, parameter, 0, NULL);
                DWORD wait = WaitForSingleObject(thread, Post::Timeout);
                if(wait != WAIT_OBJECT_0)
                {
                        TerminateThread(thread, 1);
                }
                CloseHandle(thread);
                return 0;
        }

public:

        Post(const HWND targetWinowHandle, const UINT message) :
                targetWindowHandle(targetWindowHandle),
                message(message)
        {}

        void Send(int value)
        {
                SendMessage(this->targetWindowHandle, WM_USER + this->message, value, NULL);
        }

        void AsyncSend(int value)
        {
                QueueUserWorkItem(Post::work, new Parameter(this, value), WT_EXECUTEDEFAULT);
        }

};

// ...

Post post(FindWindow(NULL, "Диспетчер задач Windows"), 1);
post.AsyncSend(3);

Но и у тебя и тут нет сброса предыдущего значения, если новое пришло до того, как предыдущее было обработано.
« Последнее редактирование: 08-09-2013 13:20 от Dimka » Записан

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

lt
Offline Offline

« Ответ #14 : 08-09-2013 13:11 » 


Дааа... Разных вариантов немало. Придется еще более тщательно все обдумать и провести эксперименты. Тут деньком/другим не обойдешься. Вот прямо завтра и начну. Хотя понедельник и "день тяжелый"... :-)

P.S. О результатах отпишусь, как и обещал. Может кому-нибудь они окажутся полезными.

Записан

MPEG-4 - в массы!
Вад
Модератор

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

« Ответ #15 : 08-09-2013 13:49 » 

Вад, в pipe'ах он не перезапишет ранее ушедшее. А при отсутствии подключения с той стороны буфер переполнится, и всё упадёт.
Пишущий ведь может вытирать историю? А остальные читатели - вытягивать без очистки. По-моему, можно сделать тот же самый MMF, только без лишней возни с инфраструктурой доступа к нему.
Записан
Dimka
Деятель
Команда клуба

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

« Ответ #16 : 08-09-2013 14:31 » 

Цитата: Вад
Пишущий ведь может вытирать историю?
Каким образом? Pipe - это ж поток (побайтовый или поблоковый). Если из процесса ушло в буфер ядра ОС, так ушло - с концами. Работа как с последовательным файлом: CreateNamedPipe, CreateFile, ReadFile, WriteFile, FlushFileBuffers. Дополнительно: ConnectNamedPipe - узнать о подключении клиента, DisconnectNamedPipe - принудительно отключить клиента, WaitNamedPipe - ждать прихода данных без чтения, PeekNamedPipe - читать без выталкивания. А вот писать без вталкивания - нет такого.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
zubr
Гость
« Ответ #17 : 08-09-2013 16:35 » 

Цитата
Но и у тебя и тут нет сброса предыдущего значения, если новое пришло до того, как предыдущее было обработано.
Dimka, так вроде по условию это не требуется.
Записан
Dimka
Деятель
Команда клуба

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

« Ответ #18 : 08-09-2013 18:25 » 

Цитата: zubr
Dimka, так вроде по условию это не требуется.
Цитата: jur
Дело осложняется тем, что того, другого процесса может не быть. Никакой очереди мне не нужно, посланная команда должна замещаться новой, если другой процесс не прочитал предыдущую (это когда другой процесс вообще не запущен). Никакие таймауты не допустимы: не прочитал другой процесс команду пока пришла следующая - ну и черт с ней, со старой командой
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
zubr
Гость
« Ответ #19 : 08-09-2013 18:41 » 

Dimka, я понимаю это условие как - принимающий процесс получает команды в последовательности отправляющего процесса, начиная с момента получения первой (для принимающего процесса) команды, причем допускается, если скорость приема и обработки команд ниже чем у передающего процесса, пропускать команды.
Другой вопрос, что теоретически в моем и твоем коде может быть нарушена последовательность команд, то есть поток, который был создан раньше для предыдущей команды, может выполниться после потока последующей команды.
Записан
Dimka
Деятель
Команда клуба

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

« Ответ #20 : 08-09-2013 20:39 » 

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

Но это всё "академические упражнения", поскольку способ не расширяется на произвольную структуру - WM_USER-сообщения не сериализуются автоматически, и надо ещё marshalling городить. Продолжаю считать MemoryMappedFile более предпочтительным вариантом - с именованным мьютексом для синхронизации доступа. А вот именованный autoevent не расширяется на много клиентов - увы. Выдача каждому клиенту по собственному autoevent требует создания небольшого протокола подключений и отключений клиентов.
Записан

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

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

« Ответ #21 : 10-09-2013 19:39 » 

Dimka, я не про запись. Я про чтение: может ли писатель тоже читать из собственного пайпа (с выталкиванием)?
Записан
Dimka
Деятель
Команда клуба

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

« Ответ #22 : 10-09-2013 20:35 » 

Вад, наверно может. Только пока он будет подключен, не сможет подключиться читатель. Это ж не broadcast на много читателей, это point2point - именно из-за самого характера последовательного потока (а не файла с random access).
Записан

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

ru
Offline Offline

« Ответ #23 : 11-09-2013 13:15 » 

Привет..

А если использовать SetWindowLong  GWL_USERDATA?
Записан

while (8==8)
sss
Специалист

ru
Offline Offline

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

Я тут почитал ссылку на топик - увидел своё сообщение 10 летней давности! Ввел IPC в впоисковике и нашел ссылку на MSDN и там пишут про WM_COPYDATA.. Что не работает такое сообщение ?
Записан

while (8==8)
zubr
Гость
« Ответ #25 : 12-09-2013 13:12 » 

sss, не понял, каким боком для данной задачи SetWindowLong  GWL_USERDATA? Ну ладно передали мы в окно данные, а как уведомить это окно, что данные пришли? Все равно надо SendMessage посылать, или процесс окна должен опрашивать постоянно в цикле GetWindowLong  GWL_USERDATA, что есть криво. Что касается WM_COPYDATA - то да работать будет, позволит передавать блоки данных, а не просто число, но насколько я сталкивался с WM_COPYDATA - работает это сообщение медленно.
Записан
Dimka
Деятель
Команда клуба

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

« Ответ #26 : 12-09-2013 13:17 » 

sss, работает - я в прошлом году использовал. Только там надо протокол изобретать: либо гарантировать, что данные клиент и сервер используют copydata только одним образом, либо внутри копируемой структуры заводить какой-то индентификатор типа, чтобы клиент мог различать сообщения, получаемые по разным поводам, да ещё и таким образом оформить структуру, чтобы не сломать уже работающий код. Если клиент полностью свой, и оба процесса в одной сессии под одним пользователем - не вопрос.

С какой скоростью работает - не знаю. У меня оно только между разными instance одного процесса 1 раз срабатывало, когда новый instance обнаруживал предыдущий, пересылал ему свои параметры командной строки и на этом выключался. Тут real time не было.
Записан

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

ru
Offline Offline

« Ответ #27 : 12-09-2013 13:56 » 

sss, не понял, каким боком для данной задачи SetWindowLong  GWL_USERDATA? Ну ладно передали мы в окно данные, а как уведомить это окно, что данные пришли? Все равно надо SendMessage посылать, или процесс окна должен опрашивать постоянно в цикле GetWindowLong  GWL_USERDATA, что есть криво. Что касается WM_COPYDATA - то да работать будет, позволит передавать блоки данных, а не просто число, но насколько я сталкивался с WM_COPYDATA - работает это сообщение медленно.

Обнулять например и проверять с необходимой  скоростью.. И почему криво - используя таймер перепроверять раз в 100 мс. При этом оставаться в одном и том же основном потоке.
Тут из контекста топикстартера - надо сделать как-нибудь не сложно и быстро.

...
Тут real time не было.


В смысле там ?  Улыбаюсь


Добавлю урл по теме

http://msdn.microsoft.com/en-us/library/windows/desktop/aa365574%28v=vs.85%29.aspx
« Последнее редактирование: 12-09-2013 14:10 от sss » Записан

while (8==8)
sss
Специалист

ru
Offline Offline

« Ответ #28 : 12-09-2013 14:13 » 

Ну и если есть проекты обоих приложений - можно использовать WriteProcessMemory/ReadProcessMemory по известным виртуальным адресам
Записан

while (8==8)
Джон
просто
Администратор

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

« Ответ #29 : 12-09-2013 15:24 » 

ИМХО в дебри забрались. Может всё-таки выяснить чем прекрасно работающий с 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."
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 Кб - загружено 821 раз.)
« Последнее редактирование: 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 Кб - загружено 1448 раз.)
* receiver.gif (4.43 Кб - загружено 1481 раз.)
« Последнее редактирование: 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