cygwinでWIN32 APIプログラミング(日本語使用で)

cygwingccmingwですが、Cソースにutf8を使えば日本語も使えました。しかしrcファイルをコンパイルするwindresはUTF8を受け付けませんでした(rc中の文字列をSJISで書いた場合、そのまま使えるっぽいけれど「表」のように'\'と同じ値を2バイト目に持つものは、\を入れてエスケープすることになるようです)。

適当に試すのに使ったコード

// showwindow.c
// [build]
// windres -o showwindowres.o showwindowres.rc
// gcc -std=c99 -W -Wall -mwindows -mno-cygwin -c showwindow.c
// gcc -W -Wall -mwindows -mno-cygwin -o showwindow showwindow.o showwindowres.o
#define UNICODE
#define _UNICODE
#if defined(__GNUC__)
#  define UNUSED(name) __attribute__((unused)) name
#else
#  define UNUSED(name) name
#endif
#include <windows.h>
#include <windowsx.h>
#include "showwindowres.h"

static HRESULT CALLBACK 
callback(HWND handle, UINT event, WPARAM wparam, LPARAM lparam);
static void register_class(HINSTANCE process, LPWSTR className);

int APIENTRY WinMain(HINSTANCE process,
                     HINSTANCE UNUSED(_),
                     LPSTR UNUSED(commandlineArgs),
                     int showFlag) {
  LPWSTR className = TEXT("Show Window");
  register_class(process, className);

  HWND handle = CreateWindowW(
    className,
    TEXT("窓オープン"),
    WS_OVERLAPPEDWINDOW,
    0, 0,
    800, 600,
    NULL, NULL,
    process,
    NULL);
  ShowWindow(handle, showFlag);
  UpdateWindow(handle);

  MSG message;
  while (GetMessageW(&message, NULL, 0, 0)) {
    TranslateMessage(&message);
    DispatchMessage(&message);
  }
  return message.wParam;
}
void register_class(HINSTANCE process, LPWSTR className) {
  WNDCLASSEXW window;
  window.cbSize = sizeof(WNDCLASSEXW);
  window.style = CS_HREDRAW | CS_VREDRAW;
  window.lpfnWndProc = callback;
  window.cbClsExtra = window.cbWndExtra = 0;
  window.hInstance = process;
  window.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  window.hCursor = LoadCursor(NULL, IDC_ARROW);
  window.hbrBackground = GetStockBrush(GRAY_BRUSH);
  window.lpszMenuName = TEXT("MY_MAIN_MENU");
  window.lpszClassName = className;
  window.hIconSm = window.hIcon;
  RegisterClassExW(&window);
}
HRESULT CALLBACK 
callback(HWND handle, UINT event, WPARAM wparam, LPARAM lparam) {
  switch (event) {
  case WM_CREATE: ;
    HMENU menu = GetMenu(handle);
    MENUITEMINFOW menuiteminfo;
    menuiteminfo.cbSize = sizeof(MENUITEMINFOW);
    menuiteminfo.fMask = MIIM_STRING;
    menuiteminfo.dwTypeData = TEXT("ダイアログ表示");
    SetMenuItemInfoW(menu, ID_MENU_OPEN_DIALOG, FALSE, &menuiteminfo);
    menuiteminfo.dwTypeData = TEXT("終了");
    SetMenuItemInfoW(menu, ID_MENU_EXIT, FALSE, &menuiteminfo);
    break;
  case WM_DESTROY:
    PostQuitMessage(0);
    return 0;
  case WM_PAINT:
    break;
  case WM_COMMAND:
    switch (LOWORD(wparam)) {
    case ID_MENU_EXIT:
      SendMessage(handle, WM_CLOSE, 0, 0);
      return 0;
    case ID_MENU_OPEN_DIALOG:
      MessageBoxW(NULL, TEXT("こんにちは世界!"), TEXT("Dialog"), MB_OK);
      return 0;
    }
    break;
  }
  return DefWindowProc(handle, event, wparam, lparam);
}

showwindowres.h

#define ID_MENU_OPEN_DIALOG 40001
#define ID_MENU_EXIT 40002

showwindowres.rc

#include "showwindowres.h"
MY_MAIN_MENU MENU {
  POPUP "Main Menu" {
    MENUITEM "Show Dialog", ID_MENU_OPEN_DIALOG
    MENUITEM SEPARATOR
    MENUITEM "Exit", ID_MENU_EXIT
  }
}

WIN32 APIってちょっとばかり書こうとするやりかただときれいに使えないのがどうも。どうせ非互換な拡張してるなら、API設計も見直せばいいのにと思っていたのだが...

メニューを日本語に入れ替えようと思ってModifyMenuを見つけてMSDNのページでしらべたら、ModifyMenuは取って代わられたらしく、SetMenuItemInfoを使え、とか出るのだが、そのアップデートしたAPIがこれだよ!

追記: Platform SDK/Windows SDKのRC.Exeを使う方法

より、

SJISで書いた.rcファイルをWindows SDK付属のRC.Exeによって、.RESファイルにすることで、そこからwindresを使うと、きちんとリソースに日本語が利用できるようになりました。

/cygdrive/c/Program\ Files/Microsoft\ SDKs/Windows/v6.0/Bin/RC.Exe showwindowres.rc
windres -o showwindowres.o showwindowres.RES
...以下同