windresでシフトJISとUTF-8とUNICODEと戯れてみる

先人たちの戦いの記録を見ると、windresで漢字の文字化けが激しく、回避策の連続の様だ。だがしかし、今は2013年だ。対策されているに違いない(ソースもあるし)と、言うわけで、しばらく書くつもりがなかったWindowsアプリ(と言ってもメニューバーがあるだけのもの)を書いてみることにした。
結果から言えば…

MS932(≒シフトJIS)
ちょっと怪しい
UTF-8
問題なさそう
UNICODE
OKだと思われる。ただ、変人の域…

ちなみに今回使用しているのは、Windows7(64bit)上でwindres 2.23.1だ。

取りあえず何にも考えないMS932編

Hello Worldのサンプルをどっからか拾ってきて、WNDCLASS or WNDCLASSEXのlpszMenuNameにメニューバーのリソースを登録するだけなので、サンプル掲載は省略。

リソースファイル(rc)のサンプル(保存形式 ANSI=MS932)

#include "resource.h"

IDM_MAINMENU MENU
BEGIN
  POPUP "ファイル(&F)"
  BEGIN
    MENUITEM "終了(&X)", IDM_END
  END
END

windresの出力形式を明示的に指定して-O coffとかしている人がいますが、拡張子から推測されるので指定しなくてもかまいません。

>windres resource.rc resource.o
>gcc -mwindows a.c resource.o
>a.exe


ふむ、問題なさそう。では、シフトJISの苦手な途中に\コードが混じる漢字を入れてみましょうか。
と言うわけで、「ファイル(&F)」を「ファイル構成(&F)」に変更して再実行。

>windres resource.rc resource.o
resource.rc:5: unrecognized escape sequence

ダメじゃん。と言うわけで\コードが隠れている「構」の後に\文字を入れて、つまり「POPUP "ファイル構\成(&F)"」に修正して再々実行。

う〜ん、30年昔に戻ったようだ。結局のところロケールを意識できていないのか?
ソースとmakefileを覗くと、どうもロケールが使われていない…languageとかコードページとか以前の問題なので、この辺のオプションを使用しても無駄無駄無駄

結論
\コードが隠れていない漢字を使う分にはOK。隠れていたら、その末尾に\文字を追加してあげれば良い(?)。

以外にソースを読み込んだUTF-8

ソース類をUTF-8に変換し、まずは何も指定しないでトライ。
リソースファイル(rc)のサンプル(保存形式 UTF-8)

#include "resource.h"

IDM_MAINMENU MENU
BEGIN
  POPUP "ファイル構成(&F)"
  BEGIN
    MENUITEM "終了(&X)", IDM_END
  END
END


ktkr!待ってたよ!
ソースを覗くとANSIコードページに無理矢理UTF-8のコードを載せているので、楽しい出力になっている模様。たぶん--codepage(-c)オプションを指定すれば大丈夫そう。ちなみに、下の「65001」はUTF-8のコードページを示しているのです。と言うわけでやってみよう。

>windres -c 65001 resource.rc resource.o
>gcc -mwindows a.c resource.o
>a.exe


ちっ、つまらん。だが、しかし、タダでは起きん。いちいち保存形式調べて、-c 65001なんて付けたり、消したりするなんて、面倒だ。何か方法はないのか〜
と、lex(flex?)で書かれたソースを眺めていたらありましたよ。「#pragma code_page(65001)」すばらしい!!
ついでに、日本語で書いていることを明記するためにLANGUAGEキーワードも使っちゃいましょう。
リソースファイル(rc)のサンプル(保存形式 UTF-8)

#include <windows.h>
#include "resource.h"

LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
#pragma code_page(65001)

IDM_MAINMENU MENU
BEGIN
  POPUP "ファイル構成(&F)"
  BEGIN
    MENUITEM "終了(&X)", IDM_END
  END
END
>windres resource.rc resource.o
>gcc -mwindows a.c resource.o
>a.exe


Yes, Yes, Yes. これで邪魔なオプションとは、おさらば。

結論
#pragma使えば余計なオプション覚えなくて、更にシフトJISの様な変なこともしなくても良いので、これがベスト(?)。

気が狂っているとしか思えないUNICODE

ソース(コンパイラ?)がUNICODE(ワイド文字列)に対応していないのは、周知なので、リソースファイルだけUNICODEに変換して、トライ。

>windres resource.rc resource.o
resource.rc:1:4: warning: null character(s) ignored [enabled by default]
resource.rc:1:6: warning: null character(s) ignored [enabled by default]
resource.rc:1:8: warning: null character(s) ignored [enabled by default]
resource.rc:1:10: warning: null character(s) ignored [enabled by default]
resource.rc:1:12: warning: null character(s) ignored [enabled by default]
…
windres: resource.rc:1: syntax error
windres: preprocessing failed.

わははは、出わ、出わ。まあlex(flex?)で書かれたソースを読んでいたから予想はしていたが、windresはマルチバイト文字列のファイルしか受け付けないのだ。と、言うわけでUTF-8形式に戻して、やり直し、やり直し。
ちなみに、これもソースからの情報だが、"…"ではなくL"…"とした場合、マルチバイト→UNICODE変換されず、UNICODEとして扱われる様だ。と、言うわけで、取りあえずL付けてみようか。
リソースファイル(rc)のサンプル(保存形式 UTF-8)

#include <windows.h>
#include "resource.h"

LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
#pragma code_page(65001)

IDM_MAINMENU MENU
BEGIN
  POPUP L"ファイル(&F)"
  BEGIN
    MENUITEM "終了(&X)", IDM_END
  END
END

ん〜、意に反して(結果が既に予想できているから)windres普通に通りますね。じゃあ実行。

わははは、何語じゃ、いったい。では、どうすれば良かったのか?簡単(?)だよUNICODEを書けば良いのだよ。って、ANSIUTF-8で書いてるファイルの途中に、UNICODE書けるエディターなんて無いよ〜。
と、言うわけで、エスケープシーケンスで、しこしこUNICODEを書くのだ! 優しい事にASCIIは自動的に先頭\x00を自動付与してくれるから、そのままでOKだぞ(何の慰めにもならん)。
で、出来たのが下のリソースファイル。
リソースファイル(rc)のサンプル(保存形式 UTF-8)

#include <windows.h>
#include "resource.h"

LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
#pragma code_page(65001)

IDM_MAINMENU MENU
BEGIN
  POPUP L"\x30d5\x30a1\x30a4\x30eb(&F)" //ファイル(&F)
  BEGIN
    MENUITEM "終了(&X)", IDM_END
  END
END

実行すれば、ほれ、この通り。

つまり、UNICODEを使いたい奴は、UNICODEのコード表を覚えろって事だ。そんな変人見たことないな。

結論
変人には変人にしか見えない道がある。