2012-09-24 44 views
6

这是一个Delphi应用程序,但我想这是一个通用的Windows编程问题。我不明白堆栈溢出错误在调用堆栈中重复DispatchMessageW

我离开我的应用程序运行(在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 

因此,一个计时器到期,我创建一个新的对象(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 

随着该块重复3条thoussand线(!)我不知道它是什么,或者它在做什么。它然后结束

StoreRoom.StoreRoom 
:75c4339a kernel32.BaseThreadInitThunk + 0x12 
:77eb9ef2 ntdll.RtlInitializeExceptionChain + 0x63 
:77eb9ec5 ntdll.RtlInitializeExceptionChain + 0x36 

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

(以及你们谁发现我的异常处理是显示一个对话框的astutute,也就是当用户点击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() 
+4

+1堆栈溢出问题。 – lkessler

+2

为什么需要每次创建连接类而不是使用ADConnection.Connected True/False?数据库连接设置在运行时是否更改? – pani

+0

这个问题是Orignally题为“我不懂stackoverflow”,但唉有人编辑它(+1对所有的相似者) – Mawg

回答

15

你的筹码溢出归因于MessageBox()被重复调用以响应重复窗口消息。在内部,MessageBox()运行它自己的消息循环,这显然处理和反复调度相同的消息。这可能表明一个误入歧途的计时器。我强烈建议您在首次输入事件处理程序时禁用计时器,然后在退出之前重新启用计时器。

单独注意,StopTheApplication()不应直接致电ExitProcess()(或甚至Halt())。改为使用Application.Terminate()

+0

+1 Thanks,@Remy。我没有提到我在IDE中运行。对MessageBox()的调用可以来自那个吗?我根本不称它。我确实调用MessageDlg(),但不是在任何定时器处理程序中 - 在我创建并显示自定义错误表单的那些处理程序中。我只有三个计时器,其他两个的处理程序代码比我发布的时间短。我关于禁用/启用定时器的观点,但最短(显示的)是8秒。少数d/b访问不能持续8秒。 – Mawg

+0

等等...我不调用MessageBox(),但也许AnyDac代码会这样做,如果出现数据库错误...但即使如此,为什么它会循环? AnyDac现在已经过很好的测试。我将在定时器禁用/启用代码中再次运行它,并且会缩短计时器长度,以便在再次出现问题时加速问题 – Mawg

+2

'MessageBox()'可能会被Application.MessageBox()调用,因为它被调用堆栈中的一些VCL代码调用。例如,Application.MessageBox()有时被异常处理程序调用。很难说,因为您的调用堆栈不显示VCL的函数名称。你正在编译发布而不是调试吗?在任何情况下,无论调用MessageBox()都显然不是可重入的,而是陷入递归循环中,每次嵌套调用MessageBox()都会将越来越多的数据推入堆栈,直到堆栈溢出。 –