Unmanaged Assemblies
昨日のVisual C++ 2005(というかコンパイラ、リンカ)の変更についてフォロー。
足し算、引き算をするライブラリ(math.cpp)を作ってみます。
#include <stdio.h> extern "C" __declspec (dllexport) void add (int x, int y) { printf ("%d + %d = %d\n", x, y, x + y); } extern "C" __declspec (dllexport) void subtract (int x, int y) { printf ("%d - %d = %d\n", x, y, x - y); }
で、コンパイル。
$ cl /LD /MD math.dll
すると、
- math.dll
- math.dll.manifest
- math.exp
- math.lib
- math.obj
これらのファイルが生成されます。.manifestという馴染みのファイルが混じっていますが、取りあえず今は気にしないことに。で、これを呼び出すプログラムを書きます。(app.cpp)
#include <stdio.h> #pragma comment (lib, "math.lib") extern "C" void add (int x, int y); extern "C" void subtract (int x, int y); void main () { add (10, 20); subtract (10, 20); }
これも何の変哲もないコードですね。で、コンパイル。
$ cl app.cpp
問題なくコンパイルされます。これを実行すれば、
10 + 20 = 30 10 - 20 = -10
が表示されるはずですよね。ところが、実行エラーになるんですよね。「app.exe - エントリ ポイントが見つかりません」とか言って。(^^;
ここで、先ほどのmath.dll.manifestを覗いてみましょう。
<?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> <dependency> <dependentAssembly> <assemblyIdentity type='win32' name='Microsoft.VC80.CRT' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' /> </dependentAssembly> </dependency> </assembly>
Microsoft.VC80.CRTがmsvcrt80.dllの事で、このマニフェストが無いと共有アセンブリであるmsvcrt80.dllを読み込んでくれないのです・・・て、マニフェストあるだろっ!(^^; 実は、.dllの場合、リソースとして.dllに埋め込んでやる必要があるのです。
$ mt /manifest math.dll.manifest /outputresource:math.dll;#2
最後の#2はリソースIDで、.dllの時は必ず2になります。改めてapp.exeを実行すると今度は実行されます。
知らないと結構嵌りそうですね〜(^^;
アパートの続き
同時に同じアパートで実行されるスレッドは1つだけである。
素直に考えればこの説明はSTAだけのことを言っているんだろうなぁ。でないと、MTAの時にロックが云々という話にならないだろうし。ところで、WinFormsなアプリ書くときに、Mainに
[STAThread] static void Main()
と、STAThread属性を付けてSTAアパートにしますが、最初、これがよく分からなかったです。(というか今も分かってないけど)。「WinFormsはSTAじゃないと動かないので云々」という説明は見かけるのですが、別に付けなくても動くし・・・(.NET1.0ではバグの所為で一部問題があったようですが)。COMのアパートの考えが有効でしたら、異なるThreadingモデル(デフォルトはMTA)の場合、アパートを越えたアクセスにはプロキシが必要でかつ、スレッドの切り替えはコストが掛かるので、STAThread属性を付けないとパフォーマンス的に無駄って結論になりますが、これであっているのでしょうか?(^^;
んー、WinForms用にSTAが作られる(ホント?)のだから、MainからApplication.RunするだけのMTAが無駄というのもあるか。何かこんがらがってきた。(^^;
(追記)
なんか最初から間違っていた気が。もし、WinFormsがアパートに影響されるのなら、(STAにしておけば)別スレッドからコントロールのメソッド呼ぶのにわざわざInvokeなんか使う必要ないだろう。多分、WinForms関連のクラスでCOM呼んでいるヤツがいて、もし、それを使うならSTAにしておいた方が都合がよい、って程度じゃないかな。
11/27
・http://www.grimes.demon.co.uk/dotnet/vistaAndDotnet.htm
Windows VistaでManaged Codeは重要な役割を果たすことはないという話。この頃が懐かしいなぁ。(^^;