Конференция "WinAPI" » Отловить сообщение во втором потоке созданным CreateThread
 
  • Black_Tomcat (26.12.07 07:08) [0]
    Здравствуйте.
    Подскажите пожалуйста как отправить сообщение во второй поток и как его там поймать. А то, я что запутался окончательно вроде отправка осуществляется при помощи функции PostThreadMessage, а прием PeekMessage. Но вот только PostThreadMessage возвращает False, a GetLastError 1159. Что я не так делаю?
  • Сергей М. © (26.12.07 08:34) [1]
    Что говорит SysErrorMessage(GetLastError) ?
  • Black_Tomcat (26.12.07 09:19) [2]

    > Что говорит SysErrorMessage(GetLastError) ?


    'Сообщение может быть использовано только с операциями синхронизации'
    А что это значит?
  • Сергей М. © (26.12.07 09:27) [3]
    А какое конкретно сообщение ты посылаешь ?
  • Black_Tomcat (26.12.07 09:35) [4]
    var
    Data:tagCOPYDATASTRUCT;

    PostThreadMessage(ThreadID,WM_COPYDATA,0,lParam(@Data));

  • Сергей М. © (26.12.07 09:38) [5]
    Тогда отлуп ты получаешь вполне резонно - сообщение с кодом WM_COPYDATA есть специальный зарезервированный вид сообщения, которое можно отправлять только синхронно, т.е. с использованием SendMessage, а не Post[Thread]Message
  • Black_Tomcat (26.12.07 09:43) [6]
    Ясно спасибо.
    А как его отловить во втором потоке?
  • Сергей М. © (26.12.07 09:47) [7]
    Прежде чем его "ловить" нужно осознать, что ф-ция SendMessage подразумевает адресатом окно (или окна) , а не нить. Целевая нить у тебя создает хоть одно окно ?
  • Black_Tomcat (26.12.07 09:53) [8]
    Это я знаю :-)
    Окно у меня есть. И оно умеет обрабатывать это сообщение. Мне нужно его как-то перехватить перед тем как окно его обработает. Это возможно?
  • Сергей М. © (26.12.07 10:11) [9]

    > Окно у меня есть


    Оно откуда взялось ? Его какая нить создала - целевая ?
  • Black_Tomcat (26.12.07 10:17) [10]
    Я пишу на VCL окно стандартное.
    Целевая нить и основной поток это одно и тоже?
  • Сергей М. © (26.12.07 10:20) [11]
    Поток (кодовый) = нить = тред = thread.

    Если ты отправляешь сообщение основному потоку, то разумеется он является целевым потоком.
  • Сергей М. © (26.12.07 10:22) [12]
    Определись, кому ты посылаешь сообщение - потоку или окну..
  • Black_Tomcat (26.12.07 10:30) [13]
    Мне нужно отправить это сообщение в созданный поток.
    И из созданного потока обратно окну.
    Oкну можно его отправить  например так SendMessage(Form1.Handle,WM_COPYDATA,0,lParam(i)) .

    Но вот как отправить это сообщение в созданный мною поток? И как его там обработать, я не могу понять.
    Может ли мною созданный поток, выгребать сообщения из очереди сообщений окна?
  • Сергей М. © (26.12.07 10:47) [14]

    > как отправить это сообщение в созданный мною поток?


    Никак. Только окну его можно отправить.
    Меняй концепцию и логику.


    > Может ли мною созданный поток, выгребать сообщения из очереди
    > сообщений окна?


    А собссно зачем ? Поясни ..
  • Black_Tomcat (26.12.07 10:53) [15]
    Я отправляю сообщение окну.
    Поток его забирает из очереди собщений, например занимает семафор, а процедура обработки сообщения целевого потока в зависимости от состояния семаформа решает обрабатывать его или нет.
    Или я вообще неправильно думаю.
  • Сергей М. © (26.12.07 11:02) [16]

    > Поток его забирает из очереди собщений


    Его забирает тот поток, который создал окно, т.е. в твоем случае основной.

    Далее этот поток смотрит на семафор - если он занят, то делает с полученным сообщением одно действие , иначе другое.
  • Black_Tomcat (26.12.07 11:07) [17]
    Спасибо.
    Теперь пойду валить препода. :-)
  • Сергей М. © (26.12.07 11:23) [18]

    > пойду валить препода


    Как бы он тебя не завалил)
  • Black_Tomcat (28.12.07 10:45) [19]
    У меня возник еще вопросик.
    Я во втором потоке создал окно все вроде работает, но  функция обработки сообщений созданного окна выполняется в основном потоке, как ее выполнить в потоке создавшем окно?
    Вот код на всякий случай.

    unit Unit1;

    var Thread2:THandle;
    FormThread2:HWND;

    Procedure Query;

    function SecondWinProc (hWnd: THandle; nMsg: UINT;wParam, lParam: Cardinal): Cardinal; export; stdcall;
    begin
     if nMsg=WM_COPYDATA then
       //do something
      else
       if nMsg=WM_SEND_DATA then
         //do something
    end;

    var xPos,yPos,nWidth,nHeight : Integer;
    var wc : TWndClassEx;
    Msg : TMsg;
    begin
    wc.cbSize:=sizeof(wc);
    wc.style:=cs_hredraw or cs_vredraw;
    wc.lpfnWndProc:=@SecondWinProc;
    wc.cbClsExtra:=0;
    wc.cbWndExtra:=0;
    wc.hInstance:=Thread2;
    wc.hIcon:=LoadIcon(0,idi_application);
    wc.hCursor:=LoadCursor(0,idc_arrow);
    wc.hbrBackground:=COLOR_BTNFACE+1;
    wc.lpszMenuName:=nil;
    wc.lpszClassName:='SecondForm';

    RegisterClassEx(wc);
    xPos:=0;
    yPos:=0;
    nWidth:=0;
    nHeight:=0;
    FormThread2:=CreateWindowEx(
                               0,
                               'SecondForm',
                               'SecondForm',
                               ws_overlappedwindow,
                               xPos,
                               yPos,
                               nWidth,
                               nHeight,
                               0,
                               0,
                               Thread2,
                               nil
                               );

    While GetMessage(Msg,FormThread2,0,0) do
    begin
    TranslateMessage(Msg);
    DispatchMessage(Msg);
    end;

    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    Thread2:=CreateThread(nil,2048,@Query,nil,0,ThreadID2);
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
         SendMessage(FormThread2,WM_COPYDATA,0,lParam(123));
         SendMessage(FormThread2,WM_COPYDATA,0,Integer(321));
    end;



    Все я не стал копировать, но я думаю смысл от этого не изменится.
  • Сергей М. © (28.12.07 10:50) [20]

    > функция обработки сообщений созданного окна выполняется
    > в основном потоке


    Ничего подобного.
    Оконная функция выполняется в потоке, создавшем окно.
  • Сергей М. © (28.12.07 10:57) [21]
    Почему вообще WinAPI ?
    Это блажь или учебная задача ?
    Если блажь, то чья - твоя или препода ?
    Если учебная задача, то не рановато ли при таких знаниях "валить препода" ?)
  • Black_Tomcat (28.12.07 11:12) [22]
    Я проверял в режиме отладки эта функция почему-то выполняется основном потоке есть, еще одно подтверждение

    var list:Array of integer;
    Data:tagCOPYDATASTRUCT;
    begin
    Data.dwData:= 123;
    Data.cbData:= Length(List)*4;
    Data.lpData:=@list;
    SendMessage(FormThread2,WM_COPYDATA,wParam(@list),lParam(@data));


    wParam передает не указатель отправляемому окну равный тому который я передавал и он рабочий, a lParam предает модифицированный указатель предназначенный второму потоку, но при обращении к нему я не могу ничего получить.
    А WinAPI это задание на курсач типа как для ознакомления с ним, и что они вообще есть.
    А знания препода оставляют желать лучшего как вам задание передача данных меджу потоками через сообщения. И синхронизация с помощью семафора?
  • Сергей М. © (28.12.07 11:22) [23]
    type

    TMyThread = class(TThread)
    private
     FhWnd: THandle;
     procedure ThreadWndProc(var Message: TMessage);
     procedure MsgWmCopydata(var Msg: TWMCopyData); message WM_COPYDATA;
     procedure MsgWmSendata(var Msg: TWMSendData); message WM_SEND_DATA;
    ..
    protected
     procedure Execute; override;
    ..
    end;

    ..

    procedure TMyThread.MsgWmCopydata(var Msg: TWMCopyData);
    begin
     .. обработка сообщения WM_COPYDATA ..
    end;

    procedure TMyThread.MsgWmSendata(var Msg: TWMSendData);
    begin
     .. обработка сообщения WM_SEND_DATA ..
    end;

    procedure TMyThread.ThreadWndProc(var Message: TMessage);
    begin
     Dispatch(Message);
    end;

    procedure TMyThread.Execute;
    var
     Msg: TMsg;
    begin
     FhWnd := AllocateHWnd(ThreadWndProc);
     try
       while not Terminated and GetMessage(Msg, 0, 0, 0) do
          DispatchMessage(Msg);
     finally
       DeallocateHWnd(FhWnd);
     end;
    end;

  • Black_Tomcat (28.12.07 11:30) [24]
    Я бы с удовольствием сделал через класс потока, но нельзя.
    Спасибо.
    Теперь буду докуривать Джеффри Рихтера, и Windows SDK.
    Еще раз спасибо.
  • Сергей М. © (28.12.07 11:34) [25]

    > wParam передает не указатель отправляемому окну равный тому
    > который я передавал


    wParam на момент вызова SensMessage должно содержать хэндл окна-"оптавителя", а ты в этом параметре передаешь черт те что, но только не хэндл окна.


    > lParam предает модифицированный указатель


    Никакой он не "модифицированный". Обычный указатель на COPYDATASTRUCT-структуру в адресном пространстве процесса-отправителя.
    А в адресном пространстве процесса-получателя полученный lParam будет содержать совершенно другой указатель на принятую структуру, и это абсолютно нормально - адресные пространства процессов абсолютно изолированы друг от друга.
  • Сергей М. © (28.12.07 11:36) [26]

    > с удовольствием сделал через класс потока, но нельзя


    Да на здоровье. Нельзя так нельзя. Пользуй BeginThread().
  • Сергей М. © (28.12.07 11:58) [27]
    Вот тебе тоже самое, но без TThread:

    type

    TMyThread = class(TObject)
    private
    FhWnd: THandle;
    procedure ThreadWndProc(var Message: TMessage);
    procedure MsgWmCopydata(var Msg: TWMCopyData); message WM_COPYDATA;
    procedure MsgWmSendata(var Msg: TWMSendData); message WM_SEND_DATA;
    ..
    end;

    ..

    procedure TMyThread.MsgWmCopydata(var Msg: TWMCopyData);
    begin
    .. обработка сообщения WM_COPYDATA ..
    end;

    procedure TMyThread.MsgWmSendata(var Msg: TWMSendData);
    begin
    .. обработка сообщения WM_SEND_DATA ..
    end;

    procedure TMyThread.ThreadWndProc(var Message: TMessage);
    begin
    Dispatch(Message);
    end;

    function MyThreadFunc(MyThreadObject: TMyThread): Integer;
    var
    Msg: TMsg;
    begin
    with MyThreadObject do
    begin
    FhWnd := AllocateHWnd(ThreadWndProc);
    try
      while GetMessage(Msg, 0, 0, 0) do
         DispatchMessage(Msg);
    finally
      DeallocateHWnd(FhWnd);
    end;
    end;
    end;

    ..  
     
    BeginThread(nil, 0, @MyThreadFunc, Pointer(TMyThreadObject.Create), MyThreadId);

  • MetalFan © (28.12.07 14:03) [28]
    а зачем AllocateHWND???
  • MetalFan © (28.12.07 14:03) [29]
    а, ну да... тут же WM_COPYDATA
  • Black_Tomcat (18.01.08 09:51) [30]
    Спасибо за помощь я вроде разобрался маленько. Решил написать как сделал может кому-нибудь когда-нибудь пригодится.
    Кусок кода чужой, но кое-что я изменил.


    function WindowThreadProc(WND:HWND; Msg : Integer; wParam:Wparam;
    lParam:Lparam):Longint; stdcall; export;
    begin
     if Msg=WM_COPYDATA then
       begin
            //что-нибудь делаем
       end
    end;

    //второй поток
    Function Query:DWORD;
    var i:integer;
    Msg:TagMSG;
     WndClassEx: TWndClassEx;
       PQRec:PQueryRecord;
    begin
    FormThread2 := CreateWindowEx (
         ws_Ex_OverlappedWindow,
         'Message',//Специальный класс окна для обмена сообщениями
         'Plain API Demo',
         ws_OverlappedWindow,
         cw_UseDefault, 0,
         cw_UseDefault, 0,
         0,
         0,
         Thread2,
         nil);
       if FormThread2 = 0 then
         MessageBox (0, 'Window not created',
           'Plain API', MB_OK);
    //заменяю процедуру обработки сообщений окна
    SetWindowLong(FormThread2,GWL_WNDPROC,integer(@WindowThreadProc));
    while GetMessage(Msg,FormThread2,0,0) do
     begin
       TranslateMessage(Msg);
       DispatchMessage(Msg);
     end;
    end;


  • Сергей М. © (18.01.08 12:57) [31]

    > TranslateMessage(Msg);


    Эт лишнее.
  • Slym © (18.01.08 13:28) [32]
    Black_Tomcat   (18.01.08 9:51) [30]
    не забываем про DefWindowProc!
    function WindowThreadProc(WND:HWND; Msg : Integer; wParam:Wparam;
    lParam:Lparam):Longint; stdcall; export;
    begin
    if Msg=WM_COPYDATA then
      begin
           //что-нибудь делаем
      end
     else
     result:=DefWindowProc(WND,Msg,wParam,lParam);
    end;

  • Black_Tomcat (18.01.08 13:29) [33]
    Еще раз спасибо.
    Запомню.
 
Конференция "WinAPI" » Отловить сообщение во втором потоке созданным CreateThread
Есть новые Нет новых   [134431   +15][b:0][p:0.004]