2012-09-24 11 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

質問は、「私はstackoverflowを理解していません」と題名されていましたが、誰かがそれを編集しました(すべての恋人に+1) – Mawg

答えて

15

あなたのスタックオーバーフローは、反復ウィンドウメッセージに応答して、MessageBox()が何度も繰り返し呼び出されているためです。内部的には、MessageBox()は独自のメッセージループを実行します。これは、明らかに同じメッセージを何度も処理し、ディスパッチしています。それは迷子になったタイマーを示すかもしれません。 OnTimerイベントハンドラを初めて入力したときにタイマーを無効にし、終了する前にタイマーを再度有効にすることを強くお勧めします。

StopTheApplication()は、ExitProcess()(またはHalt())を直接呼び出すべきではありません。代わりにApplication.Terminate()を使用してください。

+0

+1ありがとう、@レミー。私はIDEで動いていると言いませんでした。 MessageBox()への呼び出しはそれからできますか?私はまったくそれを呼んでいない。私はMessageDlg()を呼び出しますが、どのタイマーハンドラでも呼び出さないでください - カスタムエラーフォームを作成して表示します。私は3つのタイマしか持っておらず、他の2つのハンドラコードは私が投稿したものよりも短いです。私はあなたのポイントを無効にする/タイマーを有効にしますが、最短(表示)は8秒です。いくつかのd/bアクセスは8秒かかることはありません。 – Mawg

+0

待って...私はMessageBox()を呼び出さないが、データベースエラーがあった場合はおそらくAnyDacのコードが...それでも、なぜそれがループするのだろうか? AnyDacはこれまでによくテストされています。私はもう一度タイマーの無効化/有効化コードを付けて実行し、再度発生した場合に問題を早めるためにタイマーの長さを短くします。 – Mawg

+2

'MessageBox()'は 'Application.MessageBox()'によって呼び出される可能性があります呼び出しスタック内のVCLコードによって呼び出されています。 'Application.MessageBox()'は、例外ハンドラなどで呼び出されることがあります。あなたのコールスタックはVCLの関数名を表示しないので、言うことは難しいです。デバッグの代わりにリリース用にコンパイルしていますか?いずれにせよ、 'MessageBox()'を呼んでいるものは明らかに再入可能であると書かれておらず、スタックがオーバーフローするまで、 'MessageBox()'への各ネストされた呼び出しで、 。 –

関連する問題