.NETにおける64ビットプロセスと32ビットプロセスについて
■1プロセスにおける32ビットと64ビットの混在
ネィティブアプリケーションの場合、プラットフォームの異なるExeとDllは共存できません。
  • x64のExeと x64のDLL ⇒動作する
  • x86のExeと x86のDLL ⇒動作する
  • x64のExeと x86のDLL ⇒動作しない
  • x86のExeと x64のDLL ⇒動作しない

ネイティブアプリケーションはビルド時に、どちらにするか指定してビルドする必要があります。


.NET の場合、ビルド時にプラットフォームに"x86","x64"以外に"Any CPU"が選択できます。

Any CPUを選択した場合次のような挙動になります。
  • Exeの場合、OSが32ビットの場合、32ビットのプロセスとして動作します。
  • Exeの場合、OSが64ビットの場合、64ビットのプロセスとして動作します。
  • DLLの場合、呼び出したExeが32ビットで動作している場合、32ビットで動作します。
  • DLLの場合、呼び出したExeが64ビットで動作している場合、64ビットで動作します。


Any CPUでExeを作成した場合、64bitOSで32bitプロセスが動作できません。
これを解決するには、以下に述べているように、CorFlags を用いてExeを修正する必要があります。
参考:64bitOSでAnyCPUでコンパイルした32bitプロセスを動かす


この問題を解決するために、.NET4.5以降では「32ビットを優先にする」というオプションを指定できます。
これはAny CPUではありますが、32bitで動作が可能な場合は32bitで動作します。

■プラットフォームの異なるプロセスの相互運用

1つのプロセスで32bitと64bitは混在して動作しないことは説明しました。
しかし、64ビット版のWindowsでは64bitプロセスと32ビットプロセス間のプロシージャコールはサポートされています。
つまり64ビットのアウトプロセスのCOMサーバーは32ビットのクライアントと通信でき、逆に32ビットのアウトプロセスのCOMサーバーは64ビットのクライアントと通信できます。

.NETでCOMサーバーを作成するのは下記を参考にしてください。
How to develop an out-of-process COM component by using Visual C++, Visual C#, or Visual Basic .NET



実際にCOMサーバーを作成するには、上記のページからCSExeCOMServerをダウンロードします。

プロジェクトのプロパティーを以下のいづれかに修正してください。

32ビットのアウトプロセスを作成する場合

「ビルド」タブのプラットフォームターゲット
x86


「ビルドイベント」タブの「ビルド後に実行するコマンドライン」
C:\Windows\Microsoft.NET\Framework\v2.0.50727\regasm.exe /tlb "$(TargetPath)"


64ビットのアウトプロセスを作成する場合

「ビルド」タブのプラットフォームターゲット
x64


「ビルドイベント」タブの「ビルド後に実行するコマンドライン」
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\regasm.exe /tlb "$(TargetPath)"

実際にビルドしてCOMを登録すると、32ビットのCOMサーバー、または64ビットのCOMサーバーどちらであっても、32ビット、64ビットの両方のクライアントから使用できることがわかります。


詳しい詳細は、ダウンロードしたReadme.txtを参考にしてください。実際の作り方が記述してあります。



なお、アウトプロセスのCOMサーバーなので以下のようにスタティックな変数を使用すれば、異なるプラットフォームのプロセス間でのデータの共有が可能です。

    public class CSSimpleObject : ReferenceCountedObject, ICSSimpleObject
    {
   
        private static int _staticVal = 0;
        private static Object thisLock = new Object();
       public int StaticValue
        {
            get
            {
                return _staticVal;
            }
            set
            {
                lock(thisLock)
                {
                    _staticVal = value;
                }
            }
        }





WindowsではこのようにアウトプロセスのCOMサーバーを利用することにより、異なるプラットフォームのプラットフォームであっても、労力をかけずに連携できると思います。

UNIXのgccで32bitプロセスと64bitプロセスの連携やったときは、きつかった。


■プラットフォームターゲットを明示する理由

プラットフォームターゲットに「Any CPU」を選択してはいけません。
COMオブジェクト作成中にアプリケーションがハングします。
PEヘッダ中のIMAGE_NT_HEADERS.FileHeader.Machineに IMAGE_FILE_MACHINE_I386がセットされているためです。
64ビットOSの場合、COMとしては32ビットとして動作することを期待していますが、実際64bitとして動作してしまうのです。

この値はVisualStdioに付属しているbumpbinを用いて確認できます。以下のようなコマンドを実行してください。

dumpbin CSExeCOMServer.exe /headers

この結果を見てみましょう

x86を明示した場合。
File Type: EXECUTABLE IMAGE

FILE HEADER VALUES
             14C machine (x86)
               3 number of sections

x64を明示した場合。
File Type: EXECUTABLE IMAGE

FILE HEADER VALUES
            8664 machine (x64)
               2 number of sections

Any Cpu
File Type: EXECUTABLE IMAGE

FILE HEADER VALUES
             14C machine (x86)
               3 number of sections
              

Any Cpuのヘッダにはx86と記述されていますが、実際、.NETとしては64ビットで動作するために不整合が出てしまいます。
アウトプロセスのCOMを作成する場合は、プラットフォームは絶対に指定してビルドをしなければなりません。





[PR]
by mima_ita | 2013-12-01 02:50 | .NET
<< .NETにおけるオブジェクトの... R.NETとExcel-DNA... >>



実験ですお
検索
カテゴリ
最新の記事
.NET4.5におけるasy..
at 2014-07-02 00:46
.NETでTwitterを検..
at 2014-06-29 00:49
Redmineのプラグインで..
at 2014-06-28 03:29
IO.popenのwrite..
at 2014-06-28 03:25
RedmineのWikiでU..
at 2014-06-28 03:16
以前の記事
最新のトラックバック
その他のジャンル
ブログパーツ