[[MinGWによるWindows Programming]]
ここではMingGWを使って日本語Windows Programmingを行う際の
注意点を述べる。
* _Tマクロの利用 [#tf9d5a9e]
一般に 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;
WNDCLASS wc;
HWND hwnd;
/* Register the window class for the main window. */
if( hPrevInstance == NULL )
{
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( (HINSTANCE)NULL, IDI_APPLICATION );
wc.hCursor = LoadCursor( (HINSTANCE)NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
wc.lpszMenuName = _T("MyMenu");
wc.lpszClassName = MY_CLASS_NAME;
if ( RegisterClass( &wc ) == 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 ...
* windres の日本語問題 [#pa4f1f9e]
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 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
もう一つの方法は、昔よくやられたいわゆる漢字プリプロセッサをかませる方法で
ある。漢字プリプロセッサは例えばソース中にある
表示
は
\225\134\216\246
に置き換える。こうすれば windres で正しく扱えることは確認した。
一応漢字プリプロセッサの論理をまとめておくと
- 1バイトを読む。
- 0x00-0x7f であれば、そのまま出力して最初に戻る。
- 0x81-0x9f または 0xe0-0xfc の範囲にあれば次の1バイトを読む。
- そうでなければ現在の1バイトを octal 表示で出力して最初に戻る。
- 第2バイト目が 0x40-0x7e または 0x80-0xfc の範囲にあれば第1バイト、第2バイト
ともに各々 octal 表示で出力し最初に戻る。
- そうでなければ第1バイト目は octal 表示で出力し、第2バイト目が 0x00-0x7f で
あれば、そのまま出力、そうでなければ第2バイト目も octal 表示で出力
でよい(はず)。