WideStudio Programming (1-3)~windows.hで困った話

windows.hをインクルードすると、大量のマクロ定義がオマケに付いてきます。記号定数が衝突することは希だし衝突すれば大抵(再defineされたところかenum宣言したところで)コンパイルエラーになるので分かりますが、APIの名前に関してはどんな名前があってどんな風にdefineされているのか分からないし、やっかいなのは、衝突していてもぱっと見わからないことです。

とは言え、windows向けのプログラムを書いているとは言っても、WideStudio/MWTを使った開発では、Windows API を直接呼び出すようなコードを書かない限り windows.h なんてインクルードされないだろうと、普通は思いますよね?

そこに落とし穴があったんですね。なんと、wscom.h でインクルードされているんです。こんな感じで。
#ifdef MSW //if not unix system
#include <windows.h>
.....

他にも、データベース操作関連の複数のヘッダファイルでwindows.hをインクルードしています。

さて、私のやった失敗は、関数に分かり易い名前を付けようとして、MessageBox という名前の関数を作ってしまったことです。
いつものように.hppにはMessageBox関数の宣言、.cppにはMessageBox関数の定義を書いた訳ですが、wscom.hは.cppの方だけでインクルードしてました。
Windows には MessageBoxという関数がありますが、これ、UNICODE対応のソースならMessageBoxW、そうでないならMessageBoxAという名前に付け替えられます。
なので、.cppの方に書いた”MessageBox”は実は “MessageBox” ではなくなっていますが、classのメンバ関数でなければコンパイルは通ります。windows.hの中にある MessageBoxA / MessageBoxW のプロトタイプ宣言とも違う引数並びですが、c++だからそんなの問題になりません。

問題が発覚するのはlinkの段階、MessageBoxを呼び出しているところで、シンボルが未定義というエラーになりました。分かってみれば当たり前なんですけど、よもやwindows.hがインクルードされていると思ってなかった私は随分悩みましたね。

windows.hに限らず、ヘッダファイルの中でマクロを定義しているもの、特に名前の付け替えをやっているものとか、関数マクロを定義しているものとかは、要注意です。