maison
Top.Mail.Ru Yandeks.Metrika
Forum: "WinAPI";
Archive actuelle: 2004.12.12;
Télécharger: [xml.tar.bz2];

vers le bas

Pourquoi DispatchMessage envoie-t-il un AV? Trouver des branches similaires


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 ©  :
Век живи, век учись. Буду знать...



Pages: 1 branche entière

Forum: "WinAPI";
Archive actuelle: 2004.12.12;
Télécharger: [xml.tar.bz2];

à l'étage









Mémoire: 0.89 MB
Heure: 0.092 c
14-1101323625
NetAnton
2004-11-24 22:13
2004.12.12
Rus Compact


1-1101740956
Wolffgang
2004-11-29 18:09
2004.12.12
La relation entre les nombres


10-1072609904
KPN
2003-12-28 14:11
2004.12.12
Puis-je me connecter et travailler avec le serveur CORBA à partir du client VB?


1-1101717384
cactus
2004-11-29 11:36
2004.12.12
Comment créer un fichier Unicode?


4-1098931561
DelphiN!
2004-10-28 06:46
2004.12.12
Réduire toutes les fenêtres





afrikaans albanais Arabic arménien azerbaïdjanais basque Biélorusse Bulgare catalan Chinois simplifié) Chinois (traditionnel) croate Tchèque Danois Néerlandais English estonien Filipino Finlandais Français
galicien géorgien Allemand Grecque Créole haïtien hébreu Hindi Hongrois Islandais Indonesian irlandais Italien japonais Coréen letton lituanien macédonien Malay maltais Norvégien
persan Polonais Portugais roumain Russe serbe Slovaque Slovène Espagnol Swahili Suédois Thai turc ukrainien Urdu vietnamien gallois yiddish bengali bosniaque
Cebuano espéranto gujarati Hause hmong Igbo Javanais Kannada Khmer lao latin maori Marathi mongol népalais punjabi somali tamil telugu yoruba
zoulou
Английский Français Allemand Italien Португальский Русский Espagnol