ちぃさいずEXE

注意:ここではある程度デモの話,C言語の基礎,WinAPIがわかるという前提で話を進めていきます。
その辺の話からよくわからない方はそういうサイトを回ってからの方が良いと思われます。
あと、VisualC++(以下VC)限定なので他の方にはあまり有効でないかもしれません。


みなさんの中には自分も64kや4kのデモをつくってみようと思い
C言語の環境を立ち上げ、とりあえずメッセージボックスあたりを出してみようと
#include <windows.h>
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
    MessageBox(NULL,"MINIEXE!","mini",MB_OK);
    return 0;
}
よしコンパイル・・・・・ん?・・・・・あれ?

なぜかその実行ファイルの大きさは20.5KB(by VC++2002)だったりしたことでしょう。
(VC6とかだともっと大きくなった気がしますが・・・覚えてません・・。)
ちょっと待て!と、64KBデモはいいとしても、4KBのデモっていったい・・・。

わかった、C言語じゃ4KBはつくれないんだ。きっとアセンブラとかいう言語をつかわないと
だめなんだー。俺には無理だ〜。と思ったあなた
いえいえそんなことはありません。
というわけでサンプルのなかのminiexe.exeを実行してみてください

ちゃんとメッセージボックスが出ますね。でサイズは・・・2KBですね
いったいこれは何をやってるのかというと
#include <windows.h>
#pragma comment(linker,"/subsystem:windows")
#pragma comment(linker,"/NODEFAULTLIB")

void WinMainCRTStartup()
{
    MessageBox(NULL,"MINIEXE!","mini",MB_OK);	
}
さっきと変わったところは#include のあとにへんな文が2行追加されたのと
なぜかWinMain()ではなく、みなれないWinMainCRTStartup()
たったこれだけでEXEのサイズが1/10になりました。

では解説していきます


#pragma comment(linker,"/subsystem:windows")
これは実はなくても良いです。これは見たことがある人も多いかもしれません
VCに今から作る実行ファイルはコンソール用ではなくWindows用だよ
と教えてやるための文です。もしVCでプロジェクトを生成するときに
Windowsアプリケーションを選択してプロジェクトを作ったのなら
この1文はなくてもかまいません。


#pragma comment(linker,"/NODEFAULTLIB")
さて、次の文です。
EXEファイルは、コンパイルしたソースソースファイル(オブジェクトファイル)と
さまざまなライブラリファイルをリンカが結合させて、EXEを作ってくれるわけですが、
このときにでデフォルトの設定では、かなりいろんなライブラリを結合してくれちゃいます
最近のリンカは頭がいいのでけっこう不要なライブラリは省いてくれますが
それでも、デバッグ用に必要なものとか、は省いてくれません。
そこで、この/NODEFAULTLIBオプションを設定すると、そういったライブラリは一切くっつけません
必要なものだけ自分でくっつけてEXEファイルをつくるという仕組みです。
こうすることで不要なものをくっつけないので実行ファイルが小さくなるという仕組みです
補足:このオプションは#pragmaとしなくてもVCのプロジェクトの設定でもできます。
リンカのオプションのところを探してみてください。


void WinMainCRTStartup()
これは先ほどの/NODEFAULTLIBで不要なライブラリをくっつけないでリンクする話をしましたが
じつはそれの関係で、WinMainではなくWinMainCRTStartupをつかわないといけなくなります。
というのは、/NODEFAULTLIBを設定して、int WinMain()とかくと、
コンパイルが通らず、コンパイラにWinMainCRTStartup()がないと怒られます。
本来WindowsアプリケーションはWinMain()から始まるとおそわっていた思いますが
実のところ、WinMainCRTStartup()から始まります(爆
しかし、決してWinMain()から始まるというのが嘘なわけでありません
どっちかというと、むしろそっちが正しいと思います。
WinMainCRTStartup()のほうは"フライング"というほうが正しいでしょう。
実は本来WinMainCRTStartup()はVCが用意するライブラリの中で宣言されていて
その関数の中ではVCデバッグ用の関数が実行されたり、C++のコンストラクタやら
デストラクタの関数の登録が行われています。
そして、これらの基本的な処理が行われた後に呼ばれるのがWinMain()というわけです。
確かにWinMainCRTStartupから始まりますが、それはまだ準備段階なのです。
補足:実はC言語のint main()もvoid mainCRTStartup()から呼ばれてたりします。


●まとめ
こうして、いらない関数やライブラリをすべて取り去ってしまったのがこのプログラムの形というわけです。
しかし、そういう関数やライブラリを取り去ってしまったがゆえに、実はかなり自由が利かない形になります。
まず、C言語の標準関数は使えません。printf,sprintf,fopen,sin,cos,strcpy・・・など
さらに、C++のコンストラクタやデストラクタがまともに機能しません。(一部を除く)
このほかにも実はVCが裏でいろいろ関数や設定を行ってやってくれていたことが
まったくないので、全部自分で設定してその機能を作るか、その機能をつかわないかという選択になってきます。

今回の内容はメッセージボックスがでるEXEを小さくするだけという、とくに意味があるわけでもない
ものでしたが、4kや64kのデモはこういう小さなことの積み重ねでできていると思います。
ほとんど、コンパイラやリンカの設定だけでしたが、これがあとからかなり効いてきます。
メガデモというとすごいプログラム技術が必要だというイメージがありますが、実はそれだけじゃなく
こういった、妙なテクもかなり必要だと思います。(VCを熟知するとか・・・)
(まぁそういったテクも含めてプログラム技術なのかもしれませんが・・・)
というわけで、今回はここまで。次回はいよいよウインドウを作っていきたいと思います



感想・質問・間違い指摘はBBSまで・・・