- 追加された行はこの色です。
- 削除された行はこの色です。
[[MinGWによるWindows Programming]]
ここではMingGWを使って日本語Windows Programmingを行う際の
注意点を述べる。
一般に Windows で多国語対応の programming を行う場合は
<tchar.h> を include して _Tマクロを使うことが多い。
これによりnaitive code の
実行イメージ用でも Unicode の実行イメージ用でも
* _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;
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 の日本語問題 [#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 complier を使う方法 [#gc99fc0e]
とりあえず、別の 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 でも
うまくいくだろう。
** 漢字プリプロセッサを通す方法 [#n6aa2e99]
上記方法でうまくいくのではあるが、MinGW (GNU)以外のツールを使う
ということで少し悔しい。別の方法を考えてみよう。
もう一つの方法は、昔(1986年頃--20年前!)
よくやられたいわゆる漢字プリプロセッサをかませる方法で
ある。漢字プリプロセッサは例えばソース中にある
表示
は
\225\134\216\246
に置き換える。こうすれば windres で正しく扱えることは確認した。
一応漢字プリプロセッサの論理をまとめておくと
- 1バイト(第1バイト目)を読む。
- 0x00-0x7f であれば、そのまま出力して最初に戻る。
そうでなければ octal 表示で出力する。
- 第1バイト目が0x81-0x9f または 0xe0-0xfc の範囲にあれば次の1バイト(第2バイト目)を読む。
そうでなければ最初に戻る。
- 第2バイト目が 0x40-0x7e または 0x80-0xfc の範囲にあれば octal 表示で出力し最初に戻る。そうでなければ第2バイト目が 0x00-0x7f で
あれば、そのまま出力、そうでなけれ octal 表示で出力して最初に戻る。
でよい(はず)。
で、昔作ったプログラムを見つけようとしたが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ではダメ)。