ここではMingGWを使って日本語Windows Programmingを行う際の 注意点を述べる。 _Tマクロの利用 †一般に Windows で多国語対応の programming を行う場合は<tchar.h> を include して文字列に対し _Tマクロを使う。 これによりlocal code の 実行イメージ用でも UNICODE の実行イメージ用でも 共通のコードを書くことができるようになる。 例えばMinGWによるWindows Programmingに示した winmain.c に 対応するものは #define STRICT #include <windows.h> #include <tchar.h> #define MY_CLASS_NAME _T("MyClass") #define MY_WINDOW_TITLE _T("MyTitle") /* Prototype */ LRESULT CALLBACK WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { MSG msg; WNDCLASSEX wcex; HWND hwnd; /* Register the window class for the main window. */ if( hPrevInstance == NULL ) { wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = _T("MyMenu"); wcex.lpszClassName = MY_CLASS_NAME; wcex.hIconSm = 0; if ( RegisterClassEx( &wcex ) == 0 ) return 0; } /* Create our window. */ hwnd = CreateWindow( MY_CLASS_NAME, MY_WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, (HWND)NULL, (HMENU)NULL, hInstance, (LPVOID)NULL ); /* * If the window cannot be created, terminate * the application. */ if( hwnd == NULL ) return 0; /* Show the window and paint its contents. */ ShowWindow( hwnd, nCmdShow ); UpdateWindow( hwnd ); /* Start the message loop. */ while( GetMessage( &msg, (HWND)NULL, 0, 0 ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } /* Return the exit code to the system. */ return msg.wParam; } という具合である。 UNICODE の実行イメージを生成するには、compile 時に UNICODE と _UNICODE を define する。 gcc -mwindows -DUNICODE -D_UNICODE winmain.c wndproc.c myapp.o windres の日本語問題 †windres は一般に2バイトコードの片方に 0x5C となるコードが含まれている場合、 正しく扱えない。 SHIFT-JIS コードでは、例えばメニューによくある「表示」の 「表」の字が問題を引き起こす。 一方出力は、res file 中の文字列は UCS-2LE であり、 ソースをざっと眺めた感じでは、 UNICODEへの変換には MutiByteToWideChar?() が呼ばれていて、ソース文字列の コードは CP_ACP に固定されているので、上の 0x5C 問題さえなければ local code のソースで正しく変換される(逆に言えば、local code にしないと いけない)ようである。 日本語版 windres なるものが存在するが、実装の仕方が悪い(日本語を 特別扱いする)ので正式版に入れてもらえるかどうか疑問である。 元の(日本語版でない)ソースコードを見る限り、UTF-8 対応にすることは 容易にできそうである。 UTF-8 では 0x00-0x7F は ASCII 文字(制御コードを含む)だし、 そうでないコードは 0x00-0x7F は含まないので、特に新たな論理を作らなくても 問題を引き起こさないと思われる。また日本語だけでなく他の言語に対しても 有効である。ざっと眺めた感じでは UTF-8 の string を UCS-2LE に変換する関数を用意し(これは単なる encoding の変更なので自明)string を UNICODE で出力している部分で その関数を呼ぶようにすればよいだけと思われる。試してみたいところだが どうやら再build には yacc なども設定しないといけないみたいで、 開発環境を整えるのに時間がかかりそうなので後回し。 別の resource complier を使う方法 †とりあえず、別の resource compiler を使って .res file を作り、 その .res file を windres で .o file にする(.o file にしないと ld が受け付けない)。で、 resource compiler としては Microsoft が無償提供している Windows Platform SDK に付属の resource compiler である rc を使ってみた。 rc myapp.rc windres myapp.res myapp.o gcc -mwindows ... myapp.o この方法はうまくいく。多分 Borland の resource compiler でも うまくいくだろう。 漢字プリプロセッサを通す方法 †上記方法でうまくいくのではあるが、MinGW (GNU)以外のツールを使う ということで少し悔しい。別の方法を考えてみよう。 もう一つの方法は、昔(1986年頃--20年前!) よくやられたいわゆる漢字プリプロセッサをかませる方法で ある。漢字プリプロセッサは例えばソース中にある 表示 は \225\134\216\246 に置き換える。こうすれば windres で正しく扱えることは確認した。 一応漢字プリプロセッサの論理をまとめておくと
でよい(はず)。 で、昔作ったプログラムを見つけようとしたが3分で見つからなかったので 書いたほうが早いということで書きなぐってみた。 名づけて sjisto7.c。とりあえず標準入力、標準出力だが、 ファイル指定の改造もしやすいように fxxx シリーズの関数を使っておく。 /* sjisto7 */ #include <stdio.h> void octprint(int c, FILE* fp) { fprintf( fp, "\\%03o", c ); } int main() { FILE* src; FILE* dst; int c1, c2; src = stdin; dst = stdout; while((c1 = fgetc( src )) != EOF) { if((c1 >= 0x00) && (c1 <= 0x7f)) fputc( c1, dst ); else { octprint( c1, dst ); if(((c1 >= 0x81) && (c1 <= 0x9f)) || ((c1 >= 0xe0) && (c1 <= 0xfc))) { c2 = fgetc( src ); if(c2 == EOF) return 1; if(((c2 >= 0x40) && (c2 <= 0x7e)) || ((c2 >= 0x80) && (c2 <= 0xfc))) octprint( c2, dst ); else if((c2 >= 0x00) && (c2 <= 0x7f)) fputc( c2, dst ); else octprint( c2, dst ); } } } return 0; } これを使って sjisto7 < myapp.rc | windres -o myapp.o とすれば MinGW だけで無事できあがり(もちろん sjisto7.exe も MinGW で作る)。 ただし、この方法でも DIALOG の TEXT などに日本語が含まれる場合、 新しい windres(GNU windres 2.16.91 20050827) でないと、正しく生成されなかった(GNU windres 2.15.91 20040904ではダメ)。 |