.net - 回避 - 例外設定ウィンドウ




管理されたC++.NETアプリケーションで処理されない管理例外のアクセス違反の問題 (2)

これは実際には解決された問題ですが、それは非常に難解です。私は他のユーザーと共有すると思っていました。

他の人が理由を示唆するかもしれない?

とにかく、私は管理されたC ++で書かれた "混合モード"の.NETアプリケーションに取り組んでいますが、既存のネイティブライブラリへのリンクが豊富です。

問題は、未処理の管理例外がWin32アクセス違反として終了したことです。 私がこれを意味するのは、素敵な.NETダイアログを表示するのではなく、未処理の管理例外が表示される代わりに、古いスタイルの "Unhandled win32 exception occurred in ..."というメッセージが表示されるということです。

興味深いのは次のとおりです。デバッガでアプリケーションを起動すると、スローされたマネージ例外が正しく取得されます。 つまり、デバッガは私にその行を表示します。

ただし、正常に実行されると、このアクセス違反になります。 その時点でデバッガをアタッチすると、有用な情報が得られません(スタックトレースがわかりにくい)。

だから私には、未処理のマネージ例外が例外ハンドラに達する直前にネイティブコードで何かが起きていることが示唆されています。

とにかく、私はVisual Studio 2008で生成されたクリーンな新しいC ++管理プロジェクトと私のプロジェクトを比較することで、この問題を解決することができました。

修正は以下を行うことでした:

  1. / SUBSYSTEM:WINDOWS から "Not Set"に/ SUBSYSTEMフラグ(プロジェクトプロパティ - >リンカ - >システム - >サブシステム) 変更します。

  2. 古いスタイルのWinMain()を新しいスタイルのmain()に変更しました。

それは以前は

  int APIENTRY _tWinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPTSTR    lpCmdLine,
                       int       nCmdShow)

そして今は

int main(array<System::String ^> ^args)

[私はなぜこの奇妙な_TWinMainを使用していますか? これは、何年も前にサンプルの混合モードWindowsアプリケーションを作成するときにVisual Studio .NET IDEによって生成されたものでした。 それはいつもうまくいきました(今まで)ので、私はそれを変えることを心配しませんでした。 _tWinMainはWinMainの単なるマクロです]

私はこの変更を行い、問題は消えます。 未処理の.NET例外が正しくトラップされるようになりましたので、実際にそれらをデバッグできるようになりました。

私はまた、クリーンなサンプルC ++アプリケーションに逆の変更を加え、それが原因であることを証明しました。

だから、本当に私の質問は、一体何が起こっているのですか?

新しいmain(array <String^>^)代わりに、古いスタイルのWinMainを使用していただけですか?

私は多分これをMicrosoftに報告すべきでしょうか(誰でも気にします;-))?


私は.NETやマネージドコードでこのような経験はありませんが、ネイティブ側でかなりの経験があります。

私はエントリーポイント(メインとメイン)とサブシステム(win32とコンソールとの間)をどのように変更するのがなぜこれに影響するのか見当たりません。 私はそれが根本的な原因ではないことを言っているわけではありません。 (別名:どのサブシステムが「設定されていません」ということはわかりません。リンカーが知っている実行可能ファイルのスタンプであるサブシステムが何かに設定されている必要があります。コンソールサブシステムのアプリケーションは、通常の方法でGUIとやりとりすることができますが、常にコンソールウィンドウが付いています。コンソールウィンドウの外から起動すると、コンソールウィンドウが作成されます。これはあなた自身以外の誰にでも発送するアプリにとっては通常はお勧めできません。)

Win32 APIレベルでは、この種の動作は次のように制御されます。

おそらく古いWinMain()やそこから呼び出されたもの、あるいはWinMainより前に実行される.NET管理のgoo(ネイティブC / C ++でも、デフォルトのMSVC設定でWinMainは実際のエントリポイントではありませんリンカは懸念されています - MSVCのCランタイムライブラリによって提供されるラッパー関数があります。これは実際のエントリポイントであり、WinMainを呼び出します.Netは同じことをしますが、もっとそうです)、SetUnhandledExceptionFilter(NULL)あなたの固定バージョンでは、もはや起こっていません。

どのような関数が「処理されていない管理例外を持つ素敵な.NETダイアログを作成するか」を知っていれば、それをSetUnhandledExceptionFilter()に渡すことができますが、アンマネージコードの例外に対して呼び出すのは良い考えではないでしょう。

これに関する別の理論:古いスタイルの "未処理win32例外が発生しました..." "ダイアログは実際にアクセス違反と言って、それを意味しましたか? また、.NET例外ハンドラが何らかの理由で蹴られ、実際にクラッシュする可能性があります。 そうであれば、それをデバッグすることが可能でなければなりませんが、それはもっと多くの情報を必要とします。


私は本当に驚いていない。

トップレベルmainをマネージコードで記述すると、マネージコードによって処理されるマネージ例外が発生します。 C#と同じです。 これは、OSがint main(array<System::String ^> ^args)関数を直接呼び出さないためです。 これは、.netの一部であるか、コンパイル時に挿入されるマネージコードによって行われます。 これは、エスケープする.net例外を通知して処理するコードです。

独自のネイティブWinMainを記述すると、この関数には.netコードが呼び出されないため、管理例外を処理できる管理コードもありません。 マネージ例外がスローされると、他のネイティブウィンドウ例外としてOSに表示されます。

これは、main / WinMainがどのように呼び出されるかの正確な説明ではないことに注意してください。 あなたの問題の記述と少しの経験に基づいて、推測された推測です。 私は、私が知っているいくつかの細部、そしておそらく私が全く気づいていない細部も除外しました。 しかし、私はこれが物語の本質であると確信しています。







mixed-mode