none
Win32Exceptionクラスを急遽使いたくなったのですが・・・。 RRS feed

  • 質問

  • DLLを書いていて、挙動が不安定に感じた為、例外処理で不具合解析を行おうと思ったのですが、アプリケーションの設定の何処をどう変えていいのか解りません。

    DLLはWin32コンソールアプリケーションから作成したプロジェクトで、とりあえず、

    try{

     }catch(System::ComponentModel::Win32Exception^ w ){

     } 

    として見たところ、

     : error C2653: 'System' : 識別子がクラス名でも名前空間名でもありません。
     : error C2061: 構文エラー : 識別子 'Win32Exception'
     : error C2310: catch ハンドラは型を明確にしてください。
     : error C2317: '55' 行目で始まっている 'try' ブロックには catch ハンドラがありません。

    という様なエラーに遭遇しました。プロジェクト作成時点でCLRとWin32でカテゴリが分かれているので、VisualStudioの設定の話だと思うのですが、何処をどう設定すべきか分かる人いますか?

    2010年4月4日 6:05

回答

  • 以前、ネイティブ C++ で例外発生時にスタック トレースや Win32 エラー コード&メッセージをログに吐き出す仕組みを組み込んだことがありますが、
    この時には次のどちらかの書籍を大いに参考にしました。(どちらも売り切れみたいですが...)

     Amazon.co.jp: Windowsプログラマのためのデバッグテクニック徹底解説 (マイクロソフト公式解説書): ジョン ロビンズ, John Robbins, 豊田 孝: 本
     http://www.amazon.co.jp/dp/4891001860

     Amazon.co.jp: .NET&Windowsプログラマのためのデバッグテクニック徹底解説 (マイクロソフト公式解説書): ジョン ロビンズ, John Robbins, 豊田 孝: 本
     http://www.amazon.co.jp/dp/4891003529

    著者名(John Robbins)と API(SetUnhandledExceptionFilter)で検索すると、それなりにサンプル コードはヒットはしますね。
    ただし、例外ハンドラーを張り替えてしまうので、ちゃんと仕組みを理解しないと、大怪我の元ですが。

    もしかしたら、Joel on Software の第1弾の方にもサンプル コードが入っていたかも。

    2010年4月6日 9:55
  • 例外処理自体を.NETの例外処理にした方が扱いやすいのかなと感じた為です。
    NativeErrorCode と Source が扱いやすそうだと感じた為になります。

    マネージコードとして実行されるようにしない限り、得られる情報はそんなにないはずです。

    おそらくですが、ネイティブコードの外側を try-catch(Win32Exception^ e) と書くだけでは、catch できません。
    Win32Exception ではなく、SEHException など、別の例外としてスローされるからです。
    また、ネイティブコード部分で発生した例外について、Source プロパティの情報はほしいと思ったものにはならないと思われます。
    (マネージコード部分の何かが示されるだけで、本当に知りたいオブジェクトの情報は出てこないと思われるため)

    ”ちょっと使う”という考え方では大変かなと思っています。
    本格的に使うために、C++/CLI として作り替えるのであれば使えるようになってきますが、先にも書きましたように実行環境への要件が変更になること、そのモジュールを含むアプリケーションのテストをし直す必要が出てくることから、相当のコストをかける判断が必要です。

     

    totojo さんが書かれているように、ネイティブコードでもスタックトレースを得ることは可能です。
    その方面でまずは検討された方が良いかもしれません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年4月6日 14:39
    モデレータ
  • 戻り値で分岐するコードを極力書かずに、アプリケーション外の要因で起きる誤動作まで一括して取り扱えるのであれば、例外処理も円理想だと感じて興味を持ったという背景です。 
    例外処理は重いから、通常起きうるエラー処理では使わない方が良いとは言われています。
    なぜかまで説明できるほどではないので、調べてみてください。
    API毎に例外スローを書くものでしょうか・・・。

    .NET Framework のクラスライブラリではそういう実装があるからこそ、マネージ例外として catch できるのでしょう。

    分岐のコストとかを少し気にしてしまいます。

    通常、API の戻り値や GetLastError の戻り値で分岐処理しますよね。
    そう考えると、なぜ分岐のコストを気にしているのかわかりません。

    それよりも、例外処理のコストがプラスでかかると捉えるべきかもしれません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年4月7日 14:21
    モデレータ
  • いえいえ、自分の方が浅知恵ですので・・・。マネージコードで書くようにするのもいいかなと思いつつありますが、ただ、各メソッドが発生し得る例外の範囲って何を見て調べていますか?


    例外の種類は、MSDNライブラリの「.NET Framework クラス ライブラリ」で目的のメソッドをお調べ下さい。「例外」の欄に載っています。

    2010年4月8日 4:01
  • マネージドかアンマネージドかは DLL の一存だけで決められません。
    ホストの EXE がアンマネージドの場合は、EXE 側で特別なことをしてもらわねばなりません。
    EXE と DLL の間に MFC 拡張 DLL を挟んで、ワンクッション入れるという方法もありますが、

     Visual Studio Coder: Call Managed DLL From Unmanaged EXE
     http://visualstudiocoder.blogspot.com/2009/02/call-managed-dll-from-unmanaged-exe.html

    この場合でも EXE 側で何らかの対応をする必要が出てくると思います。

    2010年4月8日 7:45
  • とても単純に考えるとWin32API自体は.NET Framework以前からあったわけですし、
    ステータスのやり取りにしても関数の返却値とGetLastErrorで引き取るのがそもそものスタイルですから
    例外を投げないとしてもなんら不思議はないように感じます。
    ましてや.NET Frameworkの例外ならそれがWin32APIのレベルで送出されると言うのは考えにくいと思います。

    .NET Frameworkを使用してWin32APIの機能を呼び出したときにエラーを検出したタイミングで
    .NET Frameworkが例外を送出していると考えるのがリーズナブルだと思います。

     


    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    2010年4月9日 1:27

すべての返信

  • Win32 のコンソールアプリケーションとして作成されたアプリケーションを、不具合解析を理由に CLR プロジェクトに変換しようとしているのでしょうか?
    正直なところ、その目的で変えることは不自然ですし、苦労の割に解析の役に立つとは思えません。

    ところで何がしたかったのでしょうか?
    何でもよいから catch して、そこでログを出したいというのであれば catch(...) などと書けますが、あまりおすすめはしません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年4月4日 8:06
    モデレータ
  • 1.C++ネイティブの例外を使いたい。
    2.CLR(=.Net)のWin32Exceptionが使いたい。
    のどちらですか。

    現状のエラーは、CLRのコードをC++ネイティブでコンパイルしている
    ように思えます。

    2010年4月5日 1:33
  • Win32Exceptionを使ってみたいという事です。

    win32で同レベルの事を簡単に行えそうな構成を思いつかないので。

    また、2008のExpress sp1 を使用していますが

    System::

    の配下にComponentModelを見つける事が出来ないのですが、各インターフェースの対応状況はMSDNの何処を確認すれば良いのでしょうか?

    2010年4月5日 4:45
  • Win32Exceptionを使った例外処理の実装が、今、目的としている所です。

    空のCLRプロジェクトを作成し、コードを読み込みなおすとスコープは解決出来ますが、別のエラーが大量に発生してしまい、どちらからアプローチしても同じかなという状況になっています。

    2010年4月5日 4:49
  • どうしても Win32Exception を使いたいというのであれば、空の CLR プロジェクトの方の大量のエラーを潰すのが近道ではないかと思いますが、
    例外発生時のレジスタ値やスタック トレースを取りたいだけであれば、マネージド コードを使わなくてもネイティブ コードだけでできます。
    (実行環境に .NET Framework をインストールする必要がありません。)

     Several classes for exception handling - CodeProject
     http://www.codeproject.com/KB/cpp/exception.aspx

    あるいは、「SetUnhandledExceptionFilter _set_se_translator」あたりで検索してみるとヒントが見つかります。

    2010年4月5日 8:42
  • Win32Exceptionを使った例外処理の実装が、今、目的としている所です。

    「不具合解析」は目的ではないのでしょうか?
    「不具合解析(不具合修正)」という目的を達するために、「Win32Exception を使った例外処理の実装」が手段ではないのでしょうか?

    すでに何度も書かれていますように、Win32Exception は .NET Framework を使って作成されたプロジェクトで利用するものです。
    その前提がないプロジェクトでは利用できませんし、そのためだけに .NET Framework に依存させることは考えづらいです。

    仮に .NET Framework に依存させる方向で進めるとしても、実行環境として必要な要件が増えますが、良いのでしょうか?
    (.NET Framework が入っていない環境では動かなくなります)


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年4月5日 14:15
    モデレータ
  • 追加で質問します。

    Win32Exception のどの機能に魅力を感じて使いたいとお考えなのでしょうか?
    このクラスを引っ張り出してきたからには、どういう風に使おうか考えていたのだと思いますので、ぜひお聞かせください。

    # 結果次第で代案が出るか、解決困難となるかは変わってきます。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年4月5日 14:17
    モデレータ
  • ご紹介有難う御座います。確認してみます。

    2010年4月6日 9:11
  • 例外処理自体を.NETの例外処理にした方が扱いやすいのかなと感じた為です。

    NativeErrorCode と Source が扱いやすそうだと感じた為になります。

    例外処理を実装しようと思い立ったのが初という理由もあるのですが、現状知っている限りで同じ機能を実装する方法を思いつかなかった事が理由になります。Win32で方法が見つかると最も良いのですが、まず使ってみようと思いまして・・・。

    以上、どうぞ宜しくお願い致します。

    2010年4月6日 9:22
  • 以前、ネイティブ C++ で例外発生時にスタック トレースや Win32 エラー コード&メッセージをログに吐き出す仕組みを組み込んだことがありますが、
    この時には次のどちらかの書籍を大いに参考にしました。(どちらも売り切れみたいですが...)

     Amazon.co.jp: Windowsプログラマのためのデバッグテクニック徹底解説 (マイクロソフト公式解説書): ジョン ロビンズ, John Robbins, 豊田 孝: 本
     http://www.amazon.co.jp/dp/4891001860

     Amazon.co.jp: .NET&Windowsプログラマのためのデバッグテクニック徹底解説 (マイクロソフト公式解説書): ジョン ロビンズ, John Robbins, 豊田 孝: 本
     http://www.amazon.co.jp/dp/4891003529

    著者名(John Robbins)と API(SetUnhandledExceptionFilter)で検索すると、それなりにサンプル コードはヒットはしますね。
    ただし、例外ハンドラーを張り替えてしまうので、ちゃんと仕組みを理解しないと、大怪我の元ですが。

    もしかしたら、Joel on Software の第1弾の方にもサンプル コードが入っていたかも。

    2010年4月6日 9:55
  • 例外処理自体を.NETの例外処理にした方が扱いやすいのかなと感じた為です。
    NativeErrorCode と Source が扱いやすそうだと感じた為になります。

    マネージコードとして実行されるようにしない限り、得られる情報はそんなにないはずです。

    おそらくですが、ネイティブコードの外側を try-catch(Win32Exception^ e) と書くだけでは、catch できません。
    Win32Exception ではなく、SEHException など、別の例外としてスローされるからです。
    また、ネイティブコード部分で発生した例外について、Source プロパティの情報はほしいと思ったものにはならないと思われます。
    (マネージコード部分の何かが示されるだけで、本当に知りたいオブジェクトの情報は出てこないと思われるため)

    ”ちょっと使う”という考え方では大変かなと思っています。
    本格的に使うために、C++/CLI として作り替えるのであれば使えるようになってきますが、先にも書きましたように実行環境への要件が変更になること、そのモジュールを含むアプリケーションのテストをし直す必要が出てくることから、相当のコストをかける判断が必要です。

     

    totojo さんが書かれているように、ネイティブコードでもスタックトレースを得ることは可能です。
    その方面でまずは検討された方が良いかもしれません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年4月6日 14:39
    モデレータ
  • Win32ExceptionなのにWin32の例外を捕捉しないのですか?

    例えば、WriteFile(Win32)中に起きたIOアクセスに関する例外は、Win32ExceptionでなくSEHExceptionであるという事を言っていますか?

    だとすると、例外クラスを適用できる領域がイメージし辛くなるんですが、明確に適用領域を知るためにはMSDNの情報の何処を参考とすればよいのでしょう?

    2010年4月7日 0:36
  • 著書のご紹介有難う御座います。読んでみようと思います。良書の紹介は特に有難いです。参考にします。
    2010年4月7日 0:41
  • hystrix-cristataさま、こんにちは。

    Win32Exceptionを捕捉するには、tryブロック内に次のどちらかが必要になると思います。

    A Win32Exceptionをスローするマネージコード
    B Win32Exceptionをスローするように書かれたマネージ混在コード

    純粋なネイティブコードからマネージ例外(Win32Exceptionを含む)がスローされることはなく、従ってWin32のエラーや例外が自動的にWin32Exceptionとしてスローされることもないと思います。
    (混在コードで、ネイティブエラーからマネージ例外をスローするには、System::Runtime::InteropServices::Marshal::ThrowExceptionForHR()を利用するか、ご自身でお書きになる必要があります。)

    ビルドするだけでしたら、System.dll(Win32Exceptionを含む.NETアセンブリ)への参照をプロジェクトに追加して、/clrコンパイラオプションを付ければなんとかなると思います(が、それだけで意図しておられるような結果にはならないでしょう)。

    (追記)
    例えば、WriteFileの場合でしたら、GetLastError関数でエラーの種類を調べ、その内容に応じたマネージ例外をスローするようなコードが必要になると思います。Win32Exceptionやマネージ例外にこだわる必要がなければ、GetLastErrorだけでもよさそうな気がしますが、いかがでしょうか。

    • 編集済み Alfred360 2010年4月9日 3:05
    2010年4月7日 3:45
  • 戻り値で分岐するコードを極力書かずに、アプリケーション外の要因で起きる誤動作まで一括して取り扱えるのであれば、例外処理も円理想だと感じて興味を持ったという背景です。API毎に例外スローを書くものでしょうか・・・。分岐のコストとかを少し気にしてしまいます。
    2010年4月7日 10:42
  • 戻り値で分岐するコードを極力書かずに、アプリケーション外の要因で起きる誤動作まで一括して取り扱えるのであれば、例外処理も円理想だと感じて興味を持ったという背景です。 
    例外処理は重いから、通常起きうるエラー処理では使わない方が良いとは言われています。
    なぜかまで説明できるほどではないので、調べてみてください。
    API毎に例外スローを書くものでしょうか・・・。

    .NET Framework のクラスライブラリではそういう実装があるからこそ、マネージ例外として catch できるのでしょう。

    分岐のコストとかを少し気にしてしまいます。

    通常、API の戻り値や GetLastError の戻り値で分岐処理しますよね。
    そう考えると、なぜ分岐のコストを気にしているのかわかりません。

    それよりも、例外処理のコストがプラスでかかると捉えるべきかもしれません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年4月7日 14:21
    モデレータ
  • 戻り値で分岐するコードを極力書かずに、アプリケーション外の要因で起きる誤動作まで一括して取り扱えるのであれば、例外処理も円理想だと感じて興味を持ったという背景です。API毎に例外スローを書くものでしょうか・・・。分岐のコストとかを少し気にしてしまいます。


    なるほど。

    本末転倒かもしれませんが、一部だけでも.NET Frameworkのクラスを利用するのはダメでしょうか。
    (例えば、WriteFileではなく、System::IO::FileStreamオブジェクトのWriteメソッドを使う)

    これならご自身で例外スローのコードを書く必要は少なく、しかもエラーはマネージ例外としてスローされるので、おっしゃるような便利さを享受できると思います。

    (浅知恵でしたら申し訳ございません)

    2010年4月7日 14:33
  • GetLastErrorを使うときだけ分岐しています。(小規模の物なので)。マネージコードが内部で分岐した上で例外を投げるなら同じかもしれません。システム要因の例外は、システム?カーネル?がアプリケーションに通知する様なイメージでした。

    取り敢えず、構造化例外処理の方からバイナリ見つつ不具合解析出来る様にしようと思います。

    2010年4月8日 0:30
  • いえいえ、自分の方が浅知恵ですので・・・。マネージコードで書くようにするのもいいかなと思いつつありますが、ただ、各メソッドが発生し得る例外の範囲って何を見て調べていますか?
    2010年4月8日 0:33
  • いえいえ、自分の方が浅知恵ですので・・・。マネージコードで書くようにするのもいいかなと思いつつありますが、ただ、各メソッドが発生し得る例外の範囲って何を見て調べていますか?


    例外の種類は、MSDNライブラリの「.NET Framework クラス ライブラリ」で目的のメソッドをお調べ下さい。「例外」の欄に載っています。

    2010年4月8日 4:01
  • マネージドかアンマネージドかは DLL の一存だけで決められません。
    ホストの EXE がアンマネージドの場合は、EXE 側で特別なことをしてもらわねばなりません。
    EXE と DLL の間に MFC 拡張 DLL を挟んで、ワンクッション入れるという方法もありますが、

     Visual Studio Coder: Call Managed DLL From Unmanaged EXE
     http://visualstudiocoder.blogspot.com/2009/02/call-managed-dll-from-unmanaged-exe.html

    この場合でも EXE 側で何らかの対応をする必要が出てくると思います。

    2010年4月8日 7:45
  • なるほど。参考になります。安易にマネージドへ移行する事も出来ない訳ですね。一読してみます。

    2010年4月9日 0:30
  • 記載されていたとは知りませんでした。Win32 API の方ばかり見ていたので・・・こちらに例外の記述が無いという事は、つまりこのWin32自体が例外を投げないという事でしょうか???

    少し消化不良気味ですが、紹介頂いた書籍を参考にしつつ勉強してみます。

    2010年4月9日 0:35
  • とても単純に考えるとWin32API自体は.NET Framework以前からあったわけですし、
    ステータスのやり取りにしても関数の返却値とGetLastErrorで引き取るのがそもそものスタイルですから
    例外を投げないとしてもなんら不思議はないように感じます。
    ましてや.NET Frameworkの例外ならそれがWin32APIのレベルで送出されると言うのは考えにくいと思います。

    .NET Frameworkを使用してWin32APIの機能を呼び出したときにエラーを検出したタイミングで
    .NET Frameworkが例外を送出していると考えるのがリーズナブルだと思います。

     


    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    2010年4月9日 1:27
  • マネージコードでのGetLastErrorの使用に関して重要なことを失念していました。

    マネージコードでは、Win32のGetLastErrorを直接使う代わりに、System::Runtime::InteropServices::Marshal::GetLastWin32Error()を使う必要があります。
    C++ マネージ拡張に関してよく寄せられる質問 の一番最後の記事が参考になると思います)

    Win32 API の方ばかり見ていたので・・・こちらに例外の記述が無いという事は、つまりこのWin32自体が例外を投げないという事でしょうか???

    GetExceptionCodeで説明されているようなアンマネージ例外でしたらあるかもしれません(まれだと思います)。
    それ以外は、関数の戻り値やGetLastErrorを調べることの方が多いように思います。

    2010年4月9日 2:52
  • 全然的外れかもしれませんが...例外処理を確認したいのであれば、以下の API 使えば良いのでは?...と思うのですが。

    SetUnhandledExceptionFilter

    http://msdn.microsoft.com/ja-jp/library/cc428992.aspx

    全然違ってたらゴメンナサイ。。。

    2010年4月9日 7:15
  • もし、とにかくWin32エラーをマネージ例外としてスローしてみたいということでしたら、とりあえず次のようなコードをご自身で用意してみるのはいかがでしょうか。

    throw gcnew System::ComponentModel::Win32Exception(
     System::Runtime::InteropServices::Marshal::GetLastWin32Error()
     );

    要するに、自分で投げるんですが。
    エラーを検出したところでGetLastErrorの代わりに使えばよいかと思います。

    2010年4月9日 23:07
  • アドバイス頂き有難う御座います。

    本が届くまでに少し時間が掛かる事と、いろいろ試すまで少し時間が掛かるのでここで打ち切らせて下さい。

    後で、また質問させて下さい。宜しくお願い致します。

    2010年4月15日 0:08