Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Как корректно получить сообщение от SendMessage / 12 сообщений из 12, страница 1 из 1
27.06.2019, 11:33
    #39831022
Как корректно получить сообщение от SendMessage
Не програмистъ. Сильно прошу не бить (если только чуть).
Кратко:
Не могу разобраться как получить сообщение от SendMessage;
Код почти полная копипаста:

Отправитель:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
procedure TForm1.Button1Click(Sender: TObject);
var
  CDS: TCopyDataStruct;
  str:string;
begin
  str := 'message1';

  CDS.dwData := 1;

  CDS.cbData := Length(str) + 1;

  GetMem(CDS.lpData, CDS.cbData);

  StrPCopy(CDS.lpData, AnsiString(str));

  SendMessage(FindWindow(nil, 'Receiver'),
                  WM_COPYDATA, Handle, Integer(@CDS));

  FreeMem(CDS.lpData, CDS.cbData);

 end;



Получатель:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
procedure TForm1.WMCopyData(var MessageData: TWMCopyData);
var
  s:string;
begin
  if MessageData.CopyDataStruct.dwData = 1 then
  begin
    s := PAnsiChar((MessageData.CopyDataStruct.lpData));
    Label1.Caption:=s;
 //   ShowMessage(S);
    MessageData.Result := 123;
  end
  else
    MessageData.Result := -321;
end;



И получатель никак не реагирует, ничего не меняет, вообще не входит в данную процедуру.
Код: pascal
1.
FindWindow(nil, 'Receiver')


Работает корректно и находит нужное окно.
Например команды
Код: pascal
1.
2.
3.
    SendMessage(receiverHandle, WM_LBUTTONDOWN, 300,300);
    SendMessage(receiverHandle, WM_LBUTTONup, 300,300);
    SetWindowPos(receiverHandle, HWND_BOTTOM, 1, 1, 20, 20, swp_nosize);


Вполне себе успешно перемещают нужное окно получателя или кликают по нему.

Если чуть подробнее, может подскажите более корректное решение:
Есть программа (оболочка), которая запускает множество расчетных одинаковых подпрограмм (~100), но так сразу 100 положит любой компьютер, запускать надо по "N" штук, потому надо отслеживать сколько программ работает в текущий момент и запускать новые по мере закрытия старых, потому завершившие работы программы посылают сообщение с идентификатором (который получили при запуске) о окончании работы и закрываются.
С передачей сообщений никогда ранее дела не имел, потому - темный лес.
Можно, конечно, отслеживать количество запущенных программ, но это неудобно в случае если запустить расчетную программу вручную (что тоже бывает).
...
Рейтинг: 0 / 0
27.06.2019, 11:35
    #39831026
Мимопроходящий
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как корректно получить сообщение от SendMessage
почему не потоки а процессы?
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
27.06.2019, 11:43
    #39831031
goldmi45
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как корректно получить сообщение от SendMessage
Андрей Игоревич,

Код: pascal
1.
procedure WMCopyData(var MessageData: TWMCopyData); message WM_COPYDATA; //это есть?
...
Рейтинг: 0 / 0
27.06.2019, 12:35
    #39831079
Как корректно получить сообщение от SendMessage
Мимопроходящийпочему не потоки а процессы?

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

goldmi45Андрей Игоревич,

Код: pascal
1.
procedure WMCopyData(var MessageData: TWMCopyData); message WM_COPYDATA; //это есть?


Ааа...ааа... 3 часа сидел и тупил, вот как я мог прозевать, ведь вроде проверял, всё смотрел....
Всё, работает спасибо. Вот блин тупняк...
...
Рейтинг: 0 / 0
27.06.2019, 14:34
    #39831173
Василий 2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как корректно получить сообщение от SendMessage
SendMessage излишнее тут (и негибкое), если надо сообщать просто об окончании. Запускай процессы через CreateProcess, проверяй код завершения
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
var si: TStartupInfo;
    pi: TProcessInformation;
    ExitCode: DWORD;
begin
  Result := True;
  // запускаем проверку архива
  si := Default(TStartupInfo);
  if not CreateProcess(nil, PChar(string(AppPath)),
                       nil, nil, False, CREATE_NO_WINDOW, nil, nil, si, pi) then
    raise Err('Не удалось запустить');
  // и ждем, пока процесс отработает
  try
    repeat
      if WaitForSingleObject(pi.hProcess, 5*MSecsPerSec) = WAIT_TIMEOUT then
        begin TerminateProcess(pi.hProcess, 0); raise Err('Превышен срок ожидания'); end;
      if not GetExitCodeProcess(pi.hProcess, ExitCode) then Break;
    until ExitCode <> STILL_ACTIVE;
  finally
    CloseHandle(pi.hProcess); CloseHandle(pi.hThread);
  end;
  // проверяем код завершения проги. 0 - ОК, иначе - ошибка
  Result := (ExitCode = 0);



Выдрано из рабочей функции, но могут быть артефакты вырезания лишнего
...
Рейтинг: 0 / 0
27.06.2019, 23:18
    #39831424
Как корректно получить сообщение от SendMessage
Василий 2SendMessage излишнее тут (и негибкое), если надо сообщать просто об окончании. Запускай процессы через CreateProcess, проверяй код завершения
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
var si: TStartupInfo;
    pi: TProcessInformation;
    ExitCode: DWORD;
begin
  Result := True;
  // запускаем проверку архива
  si := Default(TStartupInfo);
  if not CreateProcess(nil, PChar(string(AppPath)),
                       nil, nil, False, CREATE_NO_WINDOW, nil, nil, si, pi) then
    raise Err('Не удалось запустить');
  // и ждем, пока процесс отработает
  try
    repeat
      if WaitForSingleObject(pi.hProcess, 5*MSecsPerSec) = WAIT_TIMEOUT then
        begin TerminateProcess(pi.hProcess, 0); raise Err('Превышен срок ожидания'); end;
      if not GetExitCodeProcess(pi.hProcess, ExitCode) then Break;
    until ExitCode <> STILL_ACTIVE;
  finally
    CloseHandle(pi.hProcess); CloseHandle(pi.hThread);
  end;
  // проверяем код завершения проги. 0 - ОК, иначе - ошибка
  Result := (ExitCode = 0);



Выдрано из рабочей функции, но могут быть артефакты вырезания лишнего
Однако не очень простая функция :). Но интересная.
Раз уж первый вопрос решился столь банально, не подскажете, как можно принудительно закрыть программы запущенные исключительно данной родительской программой (ну допустим запущенно две программы одновременно или вручную запущенна расчетная программа) у CreateProcess параметров какое-то безумное количество,способна ли она на такое?
Смысл - сделать кнопку в родительской программе "Остановить расчет": процесс запуска новых модулей остановить легко, но вот сами модули закрыть сложнее (не закрыв лишнего), стоит понимать, что средний расчет в одном расчетном модуле идет 4-6 часов (а весть расчет может идти около недели). Впихивать в расчетные модули что-то для прерывания крайне не хочется, к этому модулю достаточно суровые требования по коду и разрабатывается он не мной, обработкой параметров при запуске и сообщением при окончании хотелось бы ограничится.
...
Рейтинг: 0 / 0
28.06.2019, 10:19
    #39831488
Василий 2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как корректно получить сообщение от SendMessage
Конечно, посмотри внимательнее, у меня есть закрытие процесса по таймеру
...
Рейтинг: 0 / 0
28.06.2019, 10:26
    #39831496
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как корректно получить сообщение от SendMessage
Андрей ИгоревичРаз уж первый вопрос решился столь банально, не подскажете, как можно принудительно закрыть программы запущенные исключительно данной родительской программой (ну допустим запущенно две программы одновременно или вручную запущенна расчетная программа) у CreateProcess параметров какое-то безумное количество,способна ли она на такое?
Смысл - сделать кнопку в родительской программе "Остановить расчет": процесс запуска новых модулей остановить легко, но вот сами модули закрыть сложнее (не закрыв лишнего), стоит понимать, что средний расчет в одном расчетном модуле идет 4-6 часов (а весть расчет может идти около недели). Впихивать в расчетные модули что-то для прерывания крайне не хочется, к этому модулю достаточно суровые требования по коду и разрабатывается он не мной, обработкой параметров при запуске и сообщением при окончании хотелось бы ограничится.
TerminateProcess() должен помочь. Хэндл процесса у вас уже есть из кода выше, разве что с правами могут возникнуть трудности, но, по-идее, не должны.
...
Рейтинг: 0 / 0
28.06.2019, 10:28
    #39831499
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как корректно получить сообщение от SendMessage
Василий 2Конечно, посмотри внимательнее, у меня есть закрытие процесса по таймеру
Код: pascal
1.
2.
if WaitForSingleObject(pi.hProcess, 5*MSecsPerSec) = WAIT_TIMEOUT then
        begin TerminateProcess(pi.hProcess, 0); raise Err('Превышен срок ожидания'); end;


Это вот жесть, с точки зрения читаемости кода, ИМХО.
...
Рейтинг: 0 / 0
28.06.2019, 14:41
    #39831679
Как корректно получить сообщение от SendMessage
Василий 2Конечно, посмотри внимательнее, у меня есть закрытие процесса по таймеру
Ага, спасибо. Всё отлично работает, открывает, закрывает, на удивление...

Из любопытства, понимаю что не про Делфи, но вдруг знаете чисто теоретически может ли Handle у программ повторятся? Ну например запомнил я все Handle всех запущенных программ, пользователь позакрывал часть руками, потом понаоткрывал новых всяких разных, а затем нажал "остановить расчет" - который убивает все процессы с запомненными Handle и дополнительно убил и ни в чем не повинные процессы? Надо ли такое отслеживать или шанс подобного пренебрежительно мал?

alekcvp TerminateProcess() должен помочь. Хэндл процесса у вас уже есть из кода выше, разве что с правами могут возникнуть трудности, но, по-идее, не должны.
Отлично работает, спасибо. Про права, если у пользователя нет прав админа будет ли работать?
...
Рейтинг: 0 / 0
28.06.2019, 14:47
    #39831682
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как корректно получить сообщение от SendMessage
Андрей ИгоревичИз любопытства, понимаю что не про Делфи, но вдруг знаете чисто теоретически может ли Handle у программ повторятся? Ну например запомнил я все Handle всех запущенных программ, пользователь позакрывал часть руками, потом понаоткрывал новых всяких разных, а затем нажал "остановить расчет" - который убивает все процессы с запомненными Handle и дополнительно убил и ни в чем не повинные процессы? Надо ли такое отслеживать или шанс подобного пренебрежительно мал?
Может, но:
When a process terminates, its kernel object is not destroyed until all processes that have open handles to the process have released those handles.Т.е. пока все, у кого открыт этот процесс, не сделают CloseHandle() или не завершат работу - он будет валидным.
...
Рейтинг: 0 / 0
28.06.2019, 14:51
    #39831683
Мимопроходящий
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как корректно получить сообщение от SendMessage
28.06.2019 14:41, Андрей Игоревич пишет:
> чисто теоретически может ли Handle у программ повторятся?

в рамках текущей сессии - НЕТ
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Как корректно получить сообщение от SendMessage / 12 сообщений из 12, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]