15

This is actually a solved problem, but it's so esoteric I thought I'd share it for other users.

Also perhaps others might suggest reasons?

Anyway, I'm working on a "mixed mode" .NET application written in managed C++, but with heavy links into existing native libraries.

The problem was, unhandled managed exceptions ended up as Win32 Access Violations. What I mean by this is that instead of showing the nice .NET dialog one gets with an unhandled managed exception, instead I would get the older style "Unhandled win32 exception occurred in..." message.

Here's the interesting thing: if I start the app in the debugger, then the thrown managed exception gets correctly picked up. i.e., the debugger shows me the line.

However, when executing normally, it would turn into this Access Violation. Attaching the debugger at that point would produce little useful information (it wouldn't even show a sensible stack trace).

So, to me it suggests that something is happening in native code just before the unhandled managed exception reaches the exception handler.

So anyway, I managed to solve the issue by comparing my project to a clean new C++ managed project generated by Visual Studio 2008.

The fix was to do the following:

  1. Change the /SUBSYSTEM flag (Project properties->Linker->System->SubSystem) from /SUBSYSTEM:WINDOWS to "Not Set"

  2. Switched from using old style WinMain() to using the new style main().

i.e. it used to be

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

And it is now

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

[Why am I using this weird _tWinMain? This was what got generated by the Visual Studio .NET IDE many years ago when you create a sample mixed mode Windows app. It's always worked fine (until now) so I never bothered changing it. _tWinMain is just a macro to WinMain]

I made this change and the problem disappears. Unhandled .NET exceptions now get properly trapped so I can now actually debug them.

I also made the inverse change to the clean sample C++ app and proved that it was the cause.

So, really my questions is, what the heck is going on?

Was it just that I was using the old style WinMain instead of the new main(array <String^>^)?

Should I maybe report this to Microsoft (will anyone care ;-) )?

4

2 に答える 2

2

私は本当に驚かない。

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

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

これは、main/WinMain の呼び出し方法の正確な説明ではないことに注意してください。これは、問題の説明と少しの経験に基づいた経験に基づいた推測です。私が知っているいくつかの詳細と、おそらく私がまったく気付いていない詳細も省略しました. しかし、これが物語の本質であることは間違いありません。

于 2011-01-25T20:22:50.790 に答える
0

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

エントリ ポイント (メイン vs WinMain) またはサブシステム (win32 vs コンソール vs none) の変更がこれにどのように、またはなぜ影響するのかわかりません。なかったとは言いませんが、根本的な原因ではないというだけです。(余談ですが、subsystem:"not set" が何を意味するのかわかりません。リンカが認識して実行可能ファイルにスタンプするサブシステムは、何かに設定する必要があり、エントリ ポイントがmain(), おそらくコンソールに設定されています. コンソール サブシステム アプリは通常の方法で GUI とやり取りできますが, 常にコンソール ウィンドウが接続されており, コンソール ウィンドウの外からアプリを起動すると, コンソール ウィンドウが作成されます.これは通常、自分以外の人に出荷する予定のアプリには適していません)。

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

おそらく、古い WinMain() 内の何か、またはそこから呼び出される何か、または WinMain の前に実行される .NET 管理の goo (デフォルトの MSVC セットアップを使用するネイティブ C/C++ であっても、WinMain は実際のエントリ ポイントではありません。リンカーが関係しています-MSVCのCランタイムライブラリによって提供されるラッパー関数があります. 、そしてあなたの修正版ではもう起こっていません。

「ハンドルされていないマネージ例外で取得する素敵な .NET ダイアログ」を表示する役割を担う関数がわかっている場合は、それを SetUnhandledExceptionFilter() に渡すことができますが、アンマネージ コードの例外に対してそれを呼び出すことはおそらくお勧めできません。

このすべての別の理論: 「古いスタイルの「ハンドルされていない win32 例外が発生しました...」ダイアログは、実際にはアクセス違反と言って、それを意味していたのでしょうか? また、.NET 例外ハンドラーが開始され、何らかの理由で実際にクラッシュした可能性もあります。その場合、それをデバッグできるはずですが、それにはさらに多くの情報が必要になります。

于 2011-01-12T19:26:56.843 に答える