[[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 表示で出力

でよい(はず)。

トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS