2011年6月10日金曜日

winmainの隠蔽工作

全体を通しての技術経験をつけたいと思い、
フレームワークを作っていこうと思います。
まずはじめに、プログラムを実行するにあたって一番初めに俺のフレームワークのエントリーポイント的なものを考えます。
マルチプラットホーム向けに作るつもりは無いのですが、ひとまずwinmainから書くのが嫌なので隠蔽します。
どこかのサイトで調べたのですが忘れたので、見つけたら改めて記述します。
こうすると出来るそうです。
まあ、動いています。

とにかく使い方です。
ヘッダファイルにクラス定義
class Prototype : public Framework
{
public:
 Prototype(void){}
 virtual ~Prototype(void){}
 virtual void MainLoop()
 {
 //ここに書いたものが自動で実行される
 }
}
cppファイル
Prototype theApp;


これで、
winmainなど書かなくても、自分のクラスのインスタンスをnewして誰かに渡さなくても、これだけでいきなりPrototypeのMainLoopが実行されるようになります。
からくりは以下です。
Prototypeは以下のFrameworkを継承しています。
こちらにはwinmainが書いてあり以下のようになっています。

ヘッダファイル
class Framework
{
public:
 static Framework* ms_pInstance;
 Framework(void);
 virtual ~Framework(void);
 int Boot();
}
cppファイル
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE , LPTSTR lpCmdLine, int nCmdShow)
{
 return Framework::ms_pInstance->Boot();
}

Framework* Framework::ms_pInstance = NULL;
Framework::Framework(void)
{
 ms_pInstance = this;
}
Framework::~Framework(void){}

int Framework::Boot()
{
 // おれのエントリーポイント
 MainLoop();
 return 0;
}

とにかくどこかにあるwinmainが呼ばれて起動します、そこでいきなり
Framework::ms_pInstance->Boot();
を呼ぶので継承したPrototypeのMainLoopまで来ます。
しかし、FrameworkはPrototypeが自分を継承していることがわからないのでwinmainで呼ばれるFrameworkは本来誰だかわからないはずです。
ですが、どこかで
Prototype theApp;
と記述しておくとグローバル定義のインスタンスになって、これはもちろんコンストラクタよりも早くメモリに存在するわけで。するともちろん、Prototypeのコンストラクタが動くので必然的に親クラスのコンストラクタが呼ばれ、そこでこれまたグローバルな
ms_pInstance = this;
Frameworkのポインタに継承した自分(Prototype theApp;で起動したコンストラクタから)のポインタが入って
めでたくこのグローバルなFrameworkのポインタは継承先のPrototypeを差してくれます。
なので、誰が継承したのか知らない親クラスが継承先のPrototypeに乗っ取られてうごきだしちゃいます。的なイメージでしょうか。
以降、Frameworkを継承したクラスだけ書けば勝手に動いてくれます。
めでたし。

ああ、思い出したMFCの実装がこれです。

0 件のコメント:

コメントを投稿