2009-04-18 8 views
9

属性:DLLIMPORTはPreserverSigとSetLastErrorは、私は2つの属性に対して以下のような記述を見つけたMSDNで

PreserveSig直接HRESULTまたはretvalの値を使用して管理されていない署名を変換するためにtrueにPreserveSigフィールドを設定します。 falseに設定すると、HRESULTまたはretvalの値が自動的に例外に変換されます。既定では、PreserveSigフィールドはtrueです。

SetLastError呼び出し元がMarshal.GetLastWin32Error API関数を使用して、メソッドの実行中にエラーが発生したかどうかを判断できるようにします。 Visual Basicでは、既定値はtrueです(オーバーヘッドが追加されます)。 C#とC++では、デフォルトはfalseです。

私の質問は次のとおりです。これらの2つはどう関係していますか? PreserveSigを 'false'に設定したとします。つまり、HRESULTを例外に変換する必要があります。アンマネージ関数がエラーを示す整数を返すか、エラーが発生しなかった場合、どのようにして例外に変換できますか?

また、私は何とかPreserveSigを使用して例外を抽出できたら、なぜGetLastWin32Errorメソッドを呼び出す必要がありますか?

種類は PK

答えて

14

Win32関数は、HRESULTを返すことはほとんどないみなします。代わりにBOOLを返すか、エラーを示す特別な値を使用してください(例:CreateFileINVALID_HANDLE_VALUEを返します)。エラーコードはスレッドごとの変数に格納されます。この変数はGetLastError()で読み取ることができます。 SetLastError=trueは、マーシャラに、ネイティブ関数が戻った後にこの変数を読み取るように指示し、後でMarshal.GetLastWin32Error()で読み取れるエラーコードを隠します。アイデアは、.NETランタイムが、p/invoke呼び出しからのエラーコードを調べるチャンスを得る前に、そのコードを混乱させている裏のWin32関数を呼び出してしまうことです。

HRESULT(または同等のもの、たとえばNTSTATUS)を返す関数は、Win32関数とは異なる抽象レベルに属します。一般に、これらの関数はCOM関連(Win32より上)またはntdll(Win32より下)から、Win32の最後のエラーコードを使用しません(内部でWin32関数を呼び出すかもしれません)。

PreserveSig=falseは、戻り値HRESULTをチェックし、成功コードでない場合は、HRESULTを含む例外を作成してスローするようマーシャラーに指示します。 DllImport ed関数の管理宣言の戻り値の型はvoidです。

C#コンパイラまたはVBコンパイラは、ed関数のアンマネージシグネチャをチェックすることができないので、あなたがそれを伝えてもそれを信頼する必要があります。 HRESULT以外を返す関数にPreserveSig=falseを指定すると、奇妙な結果(ランダム例外など)が発生します。最後のWin32エラーコードを設定しない関数にSetLastError=trueを指定すると、便利なエラーコードの代わりにガーベッジが表示されます。

+0

私はCOMオブジェクトの経験がありませんので、メソッドシグネチャの作成に関するもう1つ質問してください。問題は、COM関数がHRESULTを返すと、私のメソッドをvoidを返すようにマークし、PreserveSig = false(あなたの言ったように)を設定するかPreserveSig = trueに設定し、IntPtrを返して、 – pkolodziej

+0

はい、正しいですが、HRESULTはUInt32でありIntPtrsではありません。 –

+0

ありがとうございます - あなたはとても役に立ちました。 – pkolodziej

関連する問題