2012-09-24 60 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()都會將越來越多的數據推入堆棧,直到堆棧溢出。 –