我不理解在调用堆栈中重复DispatchMessageW的堆栈溢出错误

Maw*_*awg 6 windows stack-overflow delphi

这是一个Delphi应用程序,但我想这是一个常见的Windows编程问题.

我在周末离开了我的应用程序(在Delphi IDE中)并且刚刚回来找到堆栈溢出.

堆栈就像这样......

:75c4417e kernel32.GetDriveTypeW + 0x23
:75c452ae kernel32.IsProcessorFeaturePresent + 0xa9
:75c45272 kernel32.IsProcessorFeaturePresent + 0x6d
:75c45248 kernel32.IsProcessorFeaturePresent + 0x43
:7678410b KERNELBASE.LoadStringBaseExW + 0xc7
:76678ed2 USER32.LoadStringW + 0x19
:0040c4ae LoadResString + $4A
uADStanDef.TADDefinition.Create(nil)
uADStanDef.TADDefinition.CreateTemporary
uADStanDef.TADConnectionDefTemporaryFactory.CreateObject
uADStanFactory.TADManager.CreateInterface((1050358107, 62550, 16757, (168, 100, 178, 87, 60, 74, 32, 21)),(no value),True)
uADStanFactory.ADCreateInterface((1050358107, 62550, 16757, (168, 100, 178, 87, 60, 74, 32, 21)),(no value),True)
uADCompClient.TADCustomConnection.Create($2DB7EB0)
fMainForm.TMainForm.ServerAliveTimerTimer($2E8DE38)    <========== my code
:004f1546 Winapi + $4F1546
:00461316 Winapi + $461316
:766762fa ; C:\Windows\syswow64\USER32.dll
:76676d3a USER32.GetThreadDesktop + 0xd7
:766777c4 ; C:\Windows\syswow64\USER32.dll
:7667788a USER32.DispatchMessageW + 0xf
Run Code Online (Sandbox Code Playgroud)

因此,计时器即将到期,我正在创建一个新对象(AnyDac组件)并且堆栈溢出.代码肯定会释放对象.我已经在下面附上了那些想要检查的人,但我不认为这是我的问题.

然后堆栈继续

:7669cdfd ; C:\Windows\syswow64\USER32.dll
:7669cf5c ; C:\Windows\syswow64\USER32.dll
:766cf73c ; C:\Windows\syswow64\USER32.dll
:766cfa18 ; C:\Windows\syswow64\USER32.dll
:766cfb1f USER32.MessageBoxTimeoutW + 0x52
:766cfd15 USER32.MessageBoxExW + 0x1b
:766cfd57 USER32.MessageBoxW + 0x18
:00549986 Vcl + $549986
:00549aa2 Vcl + $549AA2
:00549873 Vcl + $549873
:00461316 Winapi + $461316
:766762fa ; C:\Windows\syswow64\USER32.dll
:76676d3a USER32.GetThreadDesktop + 0xd7
:766777c4 ; C:\Windows\syswow64\USER32.dll
:7667788a USER32.DispatchMessageW + 0xf
Run Code Online (Sandbox Code Playgroud)

随着那个块重复三个thouss和line(!)我不知道它是什么或它在做什么.然后结束

StoreRoom.StoreRoom
:75c4339a kernel32.BaseThreadInitThunk + 0x12
:77eb9ef2 ntdll.RtlInitializeExceptionChain + 0x63
:77eb9ec5 ntdll.RtlInitializeExceptionChain + 0x36
Run Code Online (Sandbox Code Playgroud)

我不会重复所有重复的堆栈 - 任何人都可以建议吗?

(对于那些注意到我的异常处理显示对话框的人来说,这是一个当用户点击OK时关闭的TForm)

我的代码:

procedure TMainForm.ServerAliveTimerTimer(Sender: TObject);
begin
   try
      ADConnection := TADConnection.Create(Self);  <======= stack overflow here
      ADConnection.DriverName := 'mysql';
      ADConnection.Params.Add('Server=' + MAIN_STOREROOM_IP_ADDRESS);  
      // other params, such as password, removed for posting
      ADConnection.Connected := True;

   except
      on E : Exception do
      begin
         ADConnection.Free();
         theDialogForm := TDialogFormForm.Create(Nil);
         theDialogForm.ShowTheForm('Database problem'+#13+#10+''+#13+#10+
                                   E.ClassName+#13+#10+E.Message);    
         StopTheApplication();   <===== just calls ExitProcess(0);
         Exit;                     as I had problems with Halt elsewhere in the code
      end;
   end;

   if isMainStoreRoom then
   begin
      CheckIfStoreRoomIsAlive(SECONDARY_STOREROOM_IP_ADDRESS);
   end
   else
   begin
      CheckIfStoreRoomIsAlive(MAIN_STOREROOM_IP_ADDRESS);
   end;

   try    // Now, update our own timestamp
      timestamp  := GetCurrentUnixTimeStamp();
      ADConnection.ExecSQL('UPDATE server_status SET alive_timestamp="' + IntToStr(timestamp) + '" WHERE ip_address="' + ipAddress + '"');

   except
      on E : Exception do
      begin
         ADConnection.Free();
         Exit;
      end;
   end;

   ADConnection.Free();
end;     // ServerAliveTimerTimer()
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 15

堆栈溢出是由于MessageBox()响应重复的窗口消息而被一遍又一遍地调用.在内部,MessageBox()运行自己的消息循环,这显然是一遍又一遍地处理和分派相同的消息.这可能表明一个误入歧途的计时器.我强烈建议您在首次进入OnTimer事件处理程序时禁用计时器,然后在退出之前重新启用计时器.

另外,StopTheApplication()不应该直接调用ExitProcess()(甚至Halt()).请Application.Terminate()改用.

  • @Mawg - 当它工作时似乎不是问题,但是当失败时.至少在异常块中停止计时器,在显示对话框之前,应用程序仍在退出. (4认同)
  • 对话框=模态消息循环=重入,对吗? (3认同)
  • `MessageBox()`可能会被`Application.MessageBox()`调用,因为它是由调用堆栈中的某些VCL代码调用的.例如,"Application.MessageBox()"有时会被异常处理程序调用.很难说,因为您的调用堆栈不显示VCL的函数名称.你在编译Release而不是Debug吗?在任何情况下,调用`MessageBox()`的任何东西显然都不是可重入的,而是陷入递归循环中,每次嵌套调用`MessageBox()`就会将越来越多的数据压入堆栈,直到堆栈溢出. (2认同)
  • 什么是计时器间隔?如果此代码运行的时间比计时器间隔长,并且有一些调用ProcessMessages,则这将是可重入的. (2认同)