2012-02-08 6 views
17

私はCLRはいくつかのケースでマーシャリング行う必要があることを理解し、しかし、のは、私が持っているとしましょう:「ネイティブに管理された移行」の間に正確に何が起こるのですか?

using System.Runtime.InteropServices; 
using System.Security; 

[SuppressUnmanagedCodeSecurity] 
static class Program 
{ 
    [DllImport("kernel32.dll", SetLastError = false)] 
    static extern int GetVersion(); 

    static void Main() 
    { 
     for (; ;) 
      GetVersion(); 
    } 
} 

私は、デバッガでこのプログラムに侵入すると、私はいつも見る:

(右?)に行われる必要がある何のマーシャリングが存在しないことを考えると、誰かが実際には、この「管理ツーネイティブの移行」でが起き、そしてなぜそれが必要である何説明してくださいだろうか?

+6

たぶん、呼び出しスタック内のその行は、あなたが –

+0

@DavidHeffernanに移行したときに、あなたが知っているように、単に有益である:ああ.......私はそれがあまりにも作品を推測します..しかし、何か他にも起こっている気がします(私は間違っていることが分かりますが!)。 – Mehrdad

+0

@DavidHeffernan: 'kernel32.dll'から' mscoree.dll'へ行くときに同じことを言っていないのは面白いことですが、実際には何かが起こっていると思われます。 – Mehrdad

答えて

10

まず、STDCALLを実行できるようにコールスタックを設定する必要があります。これはWin32の呼び出し規約です。

次のランタイムは、いわゆる実行フレームをプッシュします。フレームの多くの異なる種類があります:セキュリティがアサートされ、GC保護地域、ネイティブコードの呼び出し、...

は、ランタイムは現在、ネイティブコードが実行されていることを追跡するために、このようなフレームを使用しています。これは潜在的に並行してガベージコレクションに影響を与える可能性があります。また、デバッガにも役立ちます。

ここで実際には多くは起こっていません。かなりスリムなコードパスです。

+3

+1これはすばらしい答えです。 – Mehrdad

0

dllを呼び出しているので。管理された環境から外出する必要があります。それはWindowsコアに入ります。あなたは.netの壁を壊し、.NETと同じように動作しないWindowsのコードに入ります。

+12

冗談はありません! ... – Mehrdad

+1

あまり有益ではありません。あなたはただ質問を言い換えているだけです。 :) – jalf

+2

@ jalfしかし、 ".NETの壁を壊す"という言い分がいいです。 – phoog

1

私は本当にそれが必要であるとは思えません。私は、あなたの呼び出しスタックの一部がネイティブ関数を示していることと、IDEとデバッガがその遷移を通って異なって振る舞うかもしれないことを示すことが主に有益だと思われます。(マネージコードはデバッガで非常に異なって扱われるので、あなたが期待する一部の機能が動作しない場合があります)

しかし、私はあなたがトランジションの周りの解体を検査するだけで見つけることができるはずですね。珍しいことがあるかどうか確認してください。

+0

逆アセンブリを調べるのは難しいです:VSは私のC#コードの命令は 'call 0xFFEFBFAC'ですが、そのアドレスには何もありません - 私がその関数に入ると自動的に' _GetVersionStub @ 0'に行きます。これは「75834437」にあります。それで明らかにいくつかのコードをスキップしています。しかし、私はWinDbgでそれを行うことができますか?わからない、私はそれを試してみることができます。 – Mehrdad

2

あなたのためのパラメータを変換し、呼び出し規約を考え出すための責任があるマーシャリング層、ほかに、ランタイムは、一貫性のある内部状態を維持するために、いくつかの他の事をする必要があります。

セキュリティコンテキストは、呼び出し元のコードがネイティブメソッドにアクセスすることを許可されていることを確認するために、チェックする必要があります。現在のマネージドスタックフレームを保存する必要があるため、ランタイムはデバッグや例外処理(マネージコールバックを呼び出すネイティブコードはもちろん)などのスタックウォークバックを行うことができます。現在のネイティブコードを実行していることを示すために、内部の状態ビットを設定する必要があります。

また、レジスタが追跡されると呼び出し規約によって復元されることが保証される必要があるかに応じて、保存する必要があるかもしれません。レジスタ(ローカル)にあるGCルーツは、ネイティブメソッドでガベージコレクションされないように、何らかの方法でマークする必要があります。

だから主にでスローされ、いくつかのセキュリティ上のもので、ハンドリングとタイプのマーシャリングを積み重ねています。それはものの膨大な量ではないのですけれども、それは小さなネイティブメソッドを呼び出すことに対する重大な障壁を表します。たとえば、最適化された数学ライブラリにP/Invokeを実行しようとすると、オーバーヘッドが潜在的な利益を無効にするのに十分なので、パフォーマンス上の勝利はほとんどありません。一部のパフォーマンスプロファイリング結果については、hereを参照してください。

2

私はこれに答えていることを認識していますが、デバッグウィンドウに外部コードを表示するよう提案した人はいません。 [Native to Managed Transition]行を右クリックしてShow External Codeオプションをチェックすると、移行でどの.NETメソッドが呼び出されているかが正確にわかります。これはあなたに良いアイデアを与えるかもしれません。次に例を示します。

Displaying a Native to Managed Transition

関連する問題