Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Обработка сообщений.


Автор: iddqd 7.3.2006, 13:40
Программа к которой я подключаю совй плагин не умеет обрабатывать сообщения. Я хочу написать плагин, который бы делал это. Итоговая цель сделать примерно так, как в Winamp я нахожу окно и отправляю ему какое-либо сообщение и мне возвращает нужные мне данные, например длину текущего трека.
Как мне реализовать такое самостоятельно если это вобще возможно сделать через плагин?
Хотелось бы пример самой простой функции.

Автор: Romikgy 7.3.2006, 13:44
Цитата(iddqd @ 7.3.2006, 12:40 Найти цитируемый пост)
Как мне реализовать такое самостоятельно если это вобще возможно сделать через плагин?

Я бы создал окно , которое ловилобы мессаги,
имхо можно, даже где то видел без окна такое smile

Автор: iddqd 7.3.2006, 14:13
Цитата(Romikgy @ 7.3.2006, 13:44 Найти цитируемый пост)
Я бы создал окно , которое ловилобы мессаги,
имхо можно, даже где то видел без окна такое


Я бы тоже так сделали если бы мне объяснили как их ловить и отвечать на них. Собсна в этом и была суть вопроса.

Автор: Romikgy 7.3.2006, 14:34
http://forum.vingrad.ru/index.php?showtopic=86452&hl=

Автор: iddqd 7.3.2006, 14:45
Цитата(Romikgy @ 7.3.2006, 14:34 Найти цитируемый пост)
http://forum.vingrad.ru/index.php?showtopic=86452&hl=

Спасибо, но мне всё это сложно понять и разобрать, не силён я в С++ и WinAPI, вот если бы кто-нибудь написал простейший пример... :\

Автор: Romikgy 7.3.2006, 14:53
Упс ошибочка вышла насчет языка , щаз еще чет поищем smile
Цитата(iddqd @ 7.3.2006, 13:45 Найти цитируемый пост)
не силён я


Цитата(iddqd @ 7.3.2006, 13:45 Найти цитируемый пост)
WinAPI

А здеся учить это надо будет если хошь то что задумал написать.

PS щаз пороюсь еще
Добавлено @ 14:58
http://web.ict.nsc.ru/~cancel/delphi/realapp.html
Добавлено @ 14:59
http://web.ict.nsc.ru/~cancel/delphi/msg.html
Добавлено @ 15:00
http://www.firststeps.ru/mfc/winapi/win/apiwind1.html
Добавлено @ 15:05
http://www.drkb.ru/

Автор: Romikgy 7.3.2006, 15:09
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=169

Автор: iddqd 7.3.2006, 16:39
Спасибо за ссылки.
Использую следующую функцию из рекомендованных ссылок.

Код

function WindowProc(wnd:HWND; Msg : Integer; wParam: WPARAM; lParam: LPARAM):LRESULT; stdcall;
var nCode, ctrlID : word;
begin
case msg of
  WM_COMMAND : begin
    nCode:=HIWORD(wParam);
    ctrlID:=LOWORD(wParam);
    case ctrlID of
      IDCANCEL : begin
        DestroyWindow(wnd);
        result := 0;
      end;
      else result := 1;
    end;
  end;


  WM_DESTROY : begin
    postquitmessage(0);
    Result:=0;
  end;

 999: ShowMessage('Поймали'); //ловлю своё сообщение

  else Result:=DefWindowProc(wnd,msg,wParam,lParam);
end;


Но код не рабочий. smile

Автор: Romikgy 7.3.2006, 16:45
А что шлешь? (код где?)
Имхо надо юзать не
Цитата(iddqd @ 7.3.2006, 15:39 Найти цитируемый пост)
WM_COMMAND

а WM_USER+N (любое целое число)
Добавлено @ 16:48
Цитата(iddqd @ 7.3.2006, 15:39 Найти цитируемый пост)
999: ShowMessage('Поймали'); //ловлю своё сообщение

не увидел этого smile
но лучше не 999, а WM_USER+999
ShowMessage , ненадо юзать , если хошь , то
Код

int MessageBox(

    HWND hWnd,    // handle of owner window
    LPCTSTR lpText,    // address of text in message box
    LPCTSTR lpCaption,    // address of title of message box  
    UINT uType    // style of message box
   );

Добавлено @ 16:50
Код

Range    Meaning
0 through WM_USER - 1    Messages reserved for use by Windows.
WM_USER through 0x7FFF    Integer messages for use by private window classes.
0x8000 through 0xBFFF    Messages reserved for future use by Windows.
0xC000 through 0xFFFF    String messages for use by applications.
Greater than 0xFFFF    Reserved by Windows for future use.

Автор: Romero 9.3.2006, 10:30
Romikgy, подскажи, как лучше организовать следующее:
Есть служба MyService.exe, есть обычная прога MyProg.exe (которая запускается непосредственно самой службой).
Нужно с определенной периодичностью отсылать некоторое сообщение от MyService окну программы (хэндл известен из функции ее запуска, CreateProcess, например), ждать некоторое время и если не получен ответ (соответственно, в самой проге нужно реализовать прием и отправку сообщений), убивать процесс MyProg и запускать заново.
Очень важный момент: вся эта махинация нужна не только для контроля присутствия в памяти MyProg.exe (если вдруг случайно вылетит), но и для выявления зависания (если прога запущена, но зависла, то она не должна отвечать на сообщения службы).

Поступили предложения организовать это через pipe или через системные сообщения. Как лучше, проще и надежнее в данной ситуации? Если не сложно, smile

Автор: Romikgy 9.3.2006, 10:59
Romero, имхо сначало надо читать правила smile
один топик один вопрос!

А по существу, я бы делал через мессаги, только если возможен неответ , то вместо SendMessage я бы юзал PostMessage, а подтверждение делал бы из
Цитата(Romero @ 9.3.2006, 09:30 Найти цитируемый пост)
MyProg

сообщения юзал бы за
Цитата(Romikgy @ 7.3.2006, 15:45 Найти цитируемый пост)
WM_USER

и последнее , эти все мессаги юзают хендл окна, а
Цитата(Romero @ 9.3.2006, 09:30 Найти цитируемый пост)
(хэндл известен из функции ее запуска, CreateProcess, например)

это дает хендл процесса , это разные вещи!!!
Если надо отсылать процессу тогда юзай PostThreadMessage

Автор: Romero 9.3.2006, 17:06
Спасибо. Как отправлять сообщение я понял. Больше интересует, как их принимать лучше всего (если использовать PostThreadMessage)?

Делать бесконечный цикл, который лезет в очередь сообщений? Или есть какое-то событие при поступлении сообщения?

Автор: Romikgy 9.3.2006, 17:49
Цитата(Romero @ 9.3.2006, 16:06 Найти цитируемый пост)
Делать бесконечный цикл, который лезет в очередь сообщений

Имхо так , только надо в него еще внедрить обработку сообщений системы, чтоб приложение не висло

Автор: Romikgy 9.3.2006, 18:05
http://forum.vingrad.ru/index.php?showtopic=61383&hl=postthreadmessage

Автор: Демо 9.3.2006, 22:02
iddqd,

Мне кажется, что для твоей задачи будет проще создать отдельный поток, в котором обрабатывать сообщения, посылаемые PostThreadMessage.
организуется такой поток очень просто.
Если необходимо, приведу пример.

Автор: Демо 9.3.2006, 22:17
Да вот простейший пример:

Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  FMsg: TMsg;
  ThrId: THandle;

implementation

{$R *.dfm}

procedure ThrProc(p: Pointer);
begin
    PeekMessage(FMsg,0,0,0,PM_NOREMOVE);
    while GetMessage(FMsg,0,0,0) do
    begin
      case FMsg.message of
        WM_USER+1:
          begin
            MessageBox(0,'WM_USER+1','Message',MB_OK);
          end;
        WM_QUIT:
          begin
            Exit;
          end;
      end;
    end;

end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  PostThreadMessage(ThrId,WM_USER+1,0,0);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  BeginThread(nil,0,@ThrProc,nil,0,ThrId);
end;

end.


Автор: Romero 12.3.2006, 09:25
Огромное спасибо! Работает. Только я разбил пример на 2 проги: одна отправляет, другая принимает.

Цитата(Romikgy @ 9.3.2006, 17:49 Найти цитируемый пост)
надо в него еще внедрить обработку сообщений системы, чтоб приложение не висло

Нужно ли делать обработку других сообщений, кроме WM_USER+1, WM_QUIT?

Как мне организовать передачу ThrId от запущенной второй проги, если она зпускается из первой? При создании потока отправлять родителю сообщение тем же способом? Тогда как узнать хэндл родителя?

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

Автор: Romikgy 13.3.2006, 10:08
Цитата(Romero @ 12.3.2006, 08:25 Найти цитируемый пост)
Нужно ли делать обработку других сообщений, кроме WM_USER+1, WM_QUIT?

Нужно обрабатывать , только которые те нужны, ну чтоб можно было с прогой работать (типа выключить прогу)

Цитата(Romero @ 12.3.2006, 08:25 Найти цитируемый пост)
передачу ThrId

что это?
Цитата(Romero @ 12.3.2006, 08:25 Найти цитируемый пост)
При создании потока отправлять родителю сообщение тем же способом? Тогда как узнать хэндл родителя?

ни ля ля не понял smile
Цитата(Romero @ 12.3.2006, 08:25 Найти цитируемый пост)
Моя программа, которая должна реагировать на отправленные ей сообщения, состоит из 2 форм. На второй форме выполняется некая процедура, которая может вызвать зависание всей проги (собственно, это я и хочу отлавливать). Так вот, если сделать отдельный поток, то при зависании он ведь наверняка сможет среагировать на сообщение, а мне это не нужно.
Может, все-таки стоит мне сделать на одной из форм бесконечный цикл с проверкой? Тогда и с хэндлом будет проще - буду брать хэндл запускаемого приложения.

ты мож сказать конкретно че нужно то ?

Автор: Romero 15.3.2006, 07:15
Цитата(Romikgy @ 13.3.2006, 10:08 Найти цитируемый пост)
что это?

Как сообщить родителю ThrId из BeginThread, я имел ввиду.

Объянсяю конкретно:
Первая прогу зависает или "вылетает".
Вторая прога ("родитель" первой, т.е. первая запускается из второй) должна периодически отправлять ей сообщения и принимать ответы. В случае отсутствия ответа выполнять некие действия. Но нужно учесть, что при зависании первой проги ответ прийти не должен (вот я и интересуюсь... если в варианте с созданием отдельного потока при зависании мессага дойдет без проблем, тогда плохо).

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

Автор: Демо 15.3.2006, 07:50
Цитата(Romero @ 15.3.2006, 07:15 Найти цитируемый пост)
Но нужно учесть, что при зависании первой проги ответ прийти не должен


Да не ответ придти не должен, а определить нужно, что программа повисла. Не так ли?

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

Так как первая программа дочерняя по отношению ко второй и запусается из нее, то какие проблемы определить идентификатор потока?

Известен дочерний процесс. Через него и получи ид доп. потока.

Автор: Romero 15.3.2006, 08:36
Цитата(Демо @ 15.3.2006, 07:50 Найти цитируемый пост)
Дополнительный поток получает сообщение, проверяет доступность основного потока и отвечает в запросившую программу код состояния программы.

Да.

Цитата(Демо @ 15.3.2006, 07:50 Найти цитируемый пост)
Так как первая программа дочерняя по отношению ко второй и запусается из нее, то какие проблемы определить идентификатор потока?

Пример, плиззз.

Автор: Демо 15.3.2006, 13:35
Цитата(Romero @ 15.3.2006, 08:36 Найти цитируемый пост)
Пример, плиззз.


Пожалуйста -


Приложение1:

Код

unit ufMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

const
  UM_GetTHrId=WM_USER+1;

type
  TAppThread=class(TThread)
  private
    FReady: Boolean;
  protected
    procedure Execute; override;
  public
    constructor Create;
    property Ready: Boolean read FReady;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    procedure AppMessage(var Msg: TMsg; var Handled: Boolean);
  end;

var
  Form1: TForm1;
  Thr: TAppThread;

implementation

{$R *.dfm}

{ TForm1 }
procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
  if Msg.message = UM_GetTHrId then
  begin
    if Assigned(Thr) then
    begin
      while not thr.Ready do Sleep(10);
      ShowMessage('Process Query ThreadId');
      PostThreadMessage(Msg.WParam,UM_GETTHrId,Thr.ThreadID,0);
    end;
    Handled := True;
  end;
end;

{ TAppThread }

constructor TAppThread.Create;
begin
  inherited Create(True);
  FReady := False;
  FreeOnTerminate := True;
  Resume;
end;

procedure TAppThread.Execute;
var
  M: TMsg;
begin
  PeekMessage(M,0,0,0,PM_NOREMOVE);
  FReady := True;
  while GetMessage(M,0,0,0) do
  begin
    if M.wParam=0 then MessageBox(0,'Message from Prog2!','Warning',MB_OK);
    if M.wParam=1 then TerminateProcess(GetCurrentProcess,0);
    if M.message=WM_CLOSE then Exit;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.OnMessage := AppMessage;
  Thr := TAppThread.Create;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
//Имитация завсиания

  Sleep(100000);
end;

end.


Приложение2:

Код

unit ufMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

const
  UM_GetThrId=WM_USER+1;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    procedure AppMessage(var Msg: TMsg; var Handled: Boolean);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  H: THandle;
  ThrId: THandle;

implementation

{$R *.dfm}

function ExecCmd(const aCommand: String): THandle;
var
  pi:PROCESS_INFORMATION;
  si:STARTUPINFO;
  cmdLine,Path: String;
begin
  Result := 0;
  ZeroMemory(@si,sizeof(si));
  si.cb:=SizeOf(si);
  si.dwFlags := STARTF_FORCEONFEEDBACK+STARTF_USESHOWWINDOW;
  si.wShowWindow := SW_SHOWNORMAL;
  Path := ExtractFilePath(aCommand);
  cmdLine := aCommand;

  if CreateProcess( nil,             // No module name (use command line).
                        PChar(cmdLine),  // Command line.
                        nil,             // Process handle not inheritable.
                        nil,             // Thread handle not inheritable.
                        False,           // Set handle inheritance to FALSE.
                        0,               // No creation flags.
                        nil,             // Use parent's environment block.
                        PChar(Path),     // Use parent's starting directory.
                        si,              // Pointer to STARTUPINFO structure.
                        pi )             // Pointer to PROCESS_INFORMATION structure.

    then
    begin
      Result := pi.dwThreadId;
      WaitForInputIdle(pi.hProcess,5000);
      CloseHandle(pi.hThread);
      CloseHandle(pi.hProcess);
    end;
end;


procedure TForm1.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
  if Msg.message = UM_GetThrId then
  begin
    ShowMessage('Handle ThreadId From App1: '+IntToStr(Msg.wParam));
    ThrId := Msg.wParam;
    PostThreadMessage(Msg.wParam,UM_GetTHrId,0,0);
    Handled := True;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  H := ExecCmd('..\prog1\prog1.exe');
  PostThreadMessage(H,UM_GetTHrId,GetCurrentThreadId,0);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.OnMessage := AppMessage;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
//Убиваем первое приложение
  PostThreadMessage(ThrId,UM_GetTHrId,1,0);
end;

end.

Автор: Romero 19.3.2006, 11:41
Спасибо!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)