Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.12.12;
Скачать: CL | DM;

Вниз

Почему DispatchMessage выдает AV?   Найти похожие ветки 

 
Aleksandr.   (2004-10-26 13:29) [0]

в процерурке создается apiшное окошко для текстов сообщений, отдельный поток, ему передается эвент, и основной поток переходит в ожидание установки события:

 P:=StrNew(PChar("UpdThread"));
 try
   A:=CreateEvent(nil,true,false,P);
   try
     try
       FUpdator.StopEvent:=A;
       FUpdator.Resume;
       repeat
         case MsgWaitForMultipleObjects(1,A,false,2000,QS_AllINPUT) of
           Wait_Object_0     : if FUpdator.Stopped then
                                 Break;
           else while Peekmessage(M, 0, 0, 0, PM_REMOVE) do begin
                  TranslateMessage(M);
                  DispatchMessage(M)
                end;
         end
       until FUpdator.Stopped
     finally
       CloseHandle(A)
     end

Так вот DispatchMessage в какой-то момент начинает выдавать EAccessViolation. Сообщение, которое при этом обрабатывается, является пользовательским UM_SetUserText, пересылаемым окну, рисующему сообщения. Сообщения посылаются из потока Updator в его методах к главному окну программы:

procedure TUpdator.DoOnStart(Msg: string; Step: Integer;
 const Cnt: Integer);
var
 s : string;
begin
 s:=Msg+"$"+IntToStr(Step)+":"+IntToStr(Cnt);
 if FMsgHandle<>0 then
  PostStrThreadMessage(FMsgHandle,UM_UpdatorStep,s)
end;
, PostStrThreadMessage - надстройка над PostThreadMessage, переделывающая строку в PChar (StrNew), а уж в WndProc главного окна посылается сообщение UM_SetUserText в apiшное окошко:

 if WaitFormHandle<>0 then begin
   PostStrMessage(WaitFormHandle,WM_SetUserText,MsgText);
   PostMessage(WaitFormHandle,WM_Paint,0,0)
 end

которое просто рисует полученный PChar и освобождает его. Никак не могу допереть, почему DispatchMessage в итоге всего этого выдает AV.


 
Digitman ©   (2004-10-26 13:38) [1]

у тебя s - лок.переменная, время жизни которой равно времени жизни п/программы, где она объявлена

в то же время п/программа выполняет асинхр.вызов PostMessage, передавая параметром адрес этой переменной

поскольку PostMessage - асинхр.ф-ция, она ставит сообщение в очередь адресата и тут же завершается, в рез-те чего переменная s перестает существовать

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

для подобных целей следует использовать синхронную посылку сообщений (SendMessage)


 
Aleksandr.   (2004-10-26 13:50) [2]

Digitman © :
Так я же строку переделываю в PChar:

procedure PostStrMessage(aHandle : HWND; Msg : integer; S : string; const wP : integer=0);
var
 P : PChar;
begin
 P:=StrNew(PChar(s));
 PostMessage(aHandle,Msg,wP,Integer(P))
end;

Разве выделенная StrNew память тоже убъется?


 
Digitman ©   (2004-10-26 14:01) [3]

здесь - нет

приведи точную декларацию/реализацию PostStrThreadMessage()


 
Aleksandr.   (2004-10-26 14:21) [4]

Сорри, соседнюю процедурку скопировал. Код тот же:

procedure PostStrThreadMessage(aHandle : HWND; Msg : integer; S : string; const wP : integer=0);
var
P : PChar;
begin
P:=StrNew(PChar(s));
PostThreadMessage(aHandle,Msg,wP,Integer(P))
end;


 
clickmaker ©   (2004-10-26 14:41) [5]


> [4] Aleksandr.   (26.10.04 14:21)

Вроде все верно. Попробуй LocalAlloc + CopyMemory вместо StrNew


 
Digitman ©   (2004-10-26 14:45) [6]


> Сообщение, которое при этом обрабатывается, является пользовательским
> UM_SetUserText


приводи полный код обработчика


 
Aleksandr.   (2004-10-26 15:31) [7]

Digitman ©  :
Привожу. Функция, сажаемая апишному окну на обработчик. В interface объявлены глобальные переменные MainHandle, WaitFormHandle - при создании формы в них заносится хэндл родительского окна апишного окошка, и непосредственно API-окошка. В implementation глобальная типизированная константа FWaitText, хранящая содержимое последнего выведенного текста, и WaitWidth, хранящая заданную при создании ширину.


implementation

const
 FWaitText : string="";
 WaitWidth : integer=300;

function WindowProc(wnd:HWND; Msg : Integer; Wparam:Wparam; Lparam:Lparam) : Lresult; stdcall;
var
 R   : TRect;
 DC  : HDC;
 rgn : HRGN;
 s   : string;
 P   : size;
 Buf : PChar;
begin
 case msg of
   wm_Destroy : begin
                  ...
                  FWaitText:="";
                  MainHandle:=0;
                  WaitFormHandle:=0
                end;
  wm_Activate,
  wm_SetFocus,
  wm_ActivateApp,
  wm_MouseActivate,
  wm_NCLButtonDown :
                 begin
                   PostMessage(WaitformHandle,wm_SetUserText,Integer(StrNew(PChar(FWaitText))),0);
                   Result:=0
                 end;
   um_SetUserText :
                 begin
                   Result:=0;
                   DC:=GetDC(WaitFormHandle);
                   try
                     rgn:=CreateRectRgn(0,0,WaitWidth,70);
                     try
                       SetWindowRgn(WaitFormHandle,rgn,false);
                       FillRgn(DC,rgn,RGB(255, 0, 0));
                       R.Left:=0;
                       R.Top:=10;
                       R.Right:=WaitWidth;
                       R.Bottom:=70;
                       s:="";
                       repeat
                         s:=s+" ";
                         Buf:=StrNew(PChar(S));
                         try
                           GetTextExtentPoint32(DC,Buf,length(s),P)
                         finally
                           StrDispose(Buf)
                         end
                       until P.cx>=WaitWidth-2;
                       Buf:=StrNew(PChar(s));
                       try
                         DrawText(DC,PChar(Buf),-1,R,dt_Center+dt_VCenter);
                       finally
                         StrDispose(Buf)
                       end;
// залили пробелами по ширине, а то мусор от прежней записи остается
                       s:=StrPas(PChar(wParam));
                       StrDispose(PChar(wParam));
// получили текст сообщения
                       FWaitText:=s;
                       Buf:=StrNew(PChar(s));
                       try
                         DrawText(DC,Buf,-1,R,dt_Center+dt_VCenter+DT_END_ELLIPSIS)
                       finally
                         StrDispose(Buf)
                       end    
                     finally
                       DeleteObject(RGN)
                     end
                   finally
                     ReleaseDC(Wnd,DC)
                   end;
                   PostMessage(WaitFormHandle,wm_LButtonDown,0,0)// а это сообщение, чтобы она фокус получила
                 end
   else
     Result:=DefWindowProc(wnd,msg,wparam,lparam)
 end
End;


 
Digitman ©   (2004-10-26 16:01) [8]

ты трассировал пошагово тело обработчика um_SetUserText в контексте Windowproc() ? какая конкретно строчка возбуждает искл-е ?


 
clickmaker ©   (2004-10-26 16:15) [9]


> PostMessage(aHandle,Msg,wP,Integer(P))


> s:=StrPas(PChar(wParam));

Передаешь строку в lParam, а ловишь в wParam


 
Aleksandr.   (2004-10-26 16:29) [10]

clickmaker © :
Опять ввел в заблуждение. Когда комментарии писал, потер текст и добил вручную. Конечно lParam:

   s:=StrPas(PChar(lParam));
   StrDispose(PChar(lParam));
// получили текст сообщения


Digitman © :
В том-то и дело, что она там не создает ошибок. В смысле, я ставлю точку остановка на DispatchMessage, жму F7, и он тупо проскакивает на следующую строчку. А DispatchMessage разве тоже вызовет этот обработчик?


 
Digitman ©   (2004-10-26 16:29) [11]


> clickmaker ©   (26.10.04 16:15) [9]


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


 
Digitman ©   (2004-10-26 16:31) [12]


> А DispatchMessage разве тоже вызовет этот обработчик?


а какой еще обработчик он, по-твоему, вызовет, кроме этого ?
какой установлен, такой и вызовет ..


 
Aleksandr.   (2004-10-26 16:31) [13]

Digitman © :
Лозунг коммунистов знаете? Богатый должен делиться :). Кому Бог дал больше мозгов и меньше работы, тот и делится.


 
Aleksandr.   (2004-10-26 16:32) [14]

Digitman ©  :
Я-то, наивный, полагал, что TranslateMessage...


 
clickmaker ©   (2004-10-26 16:55) [15]


> [14] Aleksandr.   (26.10.04 16:32)
> Digitman ©  :
> Я-то, наивный, полагал, что TranslateMessage...

TranslateMessage переводит виртуальные коды клавиш (те, что VK_) в символьные. Основную работу делает DispatchMessage


 
Aleksandr.   (2004-10-26 17:48) [16]

clickmaker ©  :
Век живи, век учись. Буду знать...



Страницы: 1 вся ветка

Текущий архив: 2004.12.12;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.027 c
14-1100796664
matt
2004-11-18 19:51
2004.12.12
InterBase 6


1-1101428089
Rand
2004-11-26 03:14
2004.12.12
DrawGrid


1-1100789422
TankMan
2004-11-18 17:50
2004.12.12
Написание обработчика исключительных ситуаций...


14-1101103150
speed
2004-11-22 08:59
2004.12.12
Управление БД SQL-запросами


11-1083640084
FR!
2004-05-04 07:08
2004.12.12
проблема с установкой soundin компонента