D言語の windows.h その他もろもろのポーティング win32.windows が,UNICODEでもANSIでも使えた.必要なものは以下の通り.
- win32.windows を 書き換える.自分は後者にした
// 2chの中の人に多謝 winnt.dの const uint SECURITY_DESCRIPTOR_MIN_LENGTH = SECURITY_DESCRIPTOR.sizeof; を const uint SECURITY_DESCRIPTOR_MIN_LENGTH = 20; とか const uint SECURITY_DESCRIPTOR_MIN_LENGTH = _SECURITY_DESCRIPTOR.sizeof; に書き換える
- windows.d, windef.d, winbase.d, winnt.d, winver.d, winuser.d の1行目の module 文の直後に "public {" を,最後に "}" を書き加える.ANSI版のファイルも同様.
- UTF8で書いたソース hello.d
import std.utf; // std.windows.charset.toMBSz でのやり方がわからない (T-T // 参考にしたコードを書かれたやねうらお様に多謝 char[] toMBS(wchar[] s) { char[] result; result.length = WideCharToMultiByte( 0, 0, cast(wchar*)(s~"\0"), s.length, null, 0, null, null); WideCharToMultiByte( 0, 0, cast(wchar*)(s~"\0"), s.length, result, result.length, null, null); return result; } // win32.windowsの作者様に多謝 version(ANSI) { import win32.ansi.windows; char[] toT(wchar[] t) { return toMBS(t); } char[] toT(char[] t) { return t; } } else // if version(UNICODE) { import win32.windows; wchar[] toT(char[] t) { return toUTF16(t); } wchar[] toT(wchar[] t) { return t; } } static const uint IDC_BTNCLICK = 101; static const uint IDC_BTNDONTCLICK = 102; // ユーザーコード int user_main() { HINSTANCE hInst = GetModuleHandle(null); WNDCLASS wc; wc.lpszClassName = "DFRAME"; wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = &WindowProc; wc.hInstance = hInst; wc.hIcon = LoadIcon(null, IDI_APPLICATION); wc.hCursor = LoadCursor(null, IDC_CROSS); wc.hbrBackground = cast(HBRUSH) (COLOR_WINDOW + 1); wc.lpszMenuName = null; wc.cbClsExtra = wc.cbWndExtra = 0; ATOM r = RegisterClass(&wc); assert(r); auto frame = createFrame("win32.windows using dmd 0.165", 100, 100, 400, 300, 0, null); auto buttonClick = createButton("Click Me", 0, 0, 150, 25, IDC_BTNCLICK, frame); auto buttonDontClick = createButton("DONT'T CLICK!", 160, 0, 150, 25, IDC_BTNDONTCLICK, frame); MSG msg; while (GetMessage(&msg, null, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return -1; } HWND createButton(TCHAR[] title, int x, int y, int width, int height, int idc, HWND parent = null) { auto hInst = GetModuleHandle(null); auto hWnd = CreateWindow("BUTTON", title, WS_CHILD | WS_VISIBLE, x, y, width, height, parent, cast(HMENU)idc, hInst, null); return hWnd; } HWND createFrame(TCHAR[] title, int x, int y, int width, int height, int idc, HWND parent = null) { auto hInst = GetModuleHandle(null); auto hWnd = CreateWindow("DFRAME", title, WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, width, height, HWND_DESKTOP, cast(HMENU)idc, hInst, null); assert(hWnd); return hWnd; } extern(Windows) uint WindowProc(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_COMMAND: { switch (LOWORD(wParam)) { case IDC_BTNCLICK: if (HIWORD(wParam) == BN_CLICKED) { MessageBox(hWnd, "Hello, world!", toT("こんにちは"w), MB_OK | MB_ICONINFORMATION); } break; case IDC_BTNDONTCLICK: if (HIWORD(wParam) == BN_CLICKED) { MessageBox(hWnd, toT("わざとメモリ保護違反を出します"w), toT("メモリ保護違反出すよー"w), MB_OK | MB_ICONEXCLAMATION); *(cast(int*) null) = 666; } break; default: break; } break; } case WM_PAINT: { TCHAR[] text = toT("D言語はWindowsも出来る"w); PAINTSTRUCT ps; HDC dc = BeginPaint(hWnd, &ps); RECT r; GetClientRect(hWnd, &r); HFONT font = CreateFont(80, 0, 0, 0, FW_EXTRABOLD, FALSE, FALSE, FALSE, /*ANSI_CHARSET*/ SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, toT("MS明朝"w)); HGDIOBJ old = SelectObject(dc, font); SetTextAlign(dc, TA_CENTER | TA_BASELINE); TextOut(dc, r.right / 2, r.bottom / 2, text, text.length); SelectObject(dc, old); EndPaint(hWnd, &ps); break; } case WM_DESTROY: PostQuitMessage(0); break; default: break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } // 以下、windows用のスタートアップコード // \dmd\src\phobos\dmain2.dにある // コンソール版のD言語のスタートアップコードと比較してみてください。 // // .defファイルとして、最低限以下のことを書いたファイルを用意して // コンパイル時に、そのdefファイルを指定してください。 // EXETYPE NT // SUBSYSTEM WINDOWS extern (C) { void gc_init(); void gc_term(); void _minit(); void _moduleCtor(); void _moduleUnitTests(); } extern (Windows) int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int result; gc_init(); // initialize garbage collector _minit(); // initialize module constructor table try { _moduleCtor(); // call module constructors _moduleUnitTests(); // run unit tests (optional) result = user_main(); // ユーザーコードはここに入れる } catch (Object o) // catch any uncaught exceptions { TCHAR[] error = toT(o.toString() ~ "\0"); MessageBox(null, error, "Error", MB_OK | MB_ICONEXCLAMATION); result = 0; // failed } gc_term(); // run finalizers; terminate garbage collector return result; }
- 以下の内容を書いたテキストファイル win32.def
EXETYPE NT SUBSYSTEM WINDOWS
- メイクファイル makefile
# ここでソースを指定してやる # ご自分の環境に合わせてください SRC = hello.d C:/D/dm/lib/Gdi32.lib win32.def UNICODE = C:/D/dmd/src/phobos/win32.lib ANSI = C:/D/dmd/src/phobos/win32a.lib # 出力ファイル名 OUT = hello OUTA = hello_ansi # コンパイルオプション # リリース時 DFLAGS = -w -O -release # デバッグ時 #DFLAGS = -w -debug -g # 依存関係 # UNICODE版とANSI版を一緒にビルドします all : $(SRC) dmd $(SRC) $(UNICODE) $(DFLAGS) -of$(OUT) -version=UNICODE dmd $(SRC) $(ANSI) $(DFLAGS) -of$(OUTA) -version=ANSI
以上を揃えます.make コマンドが使える場合はコマンドラインから make を実行.使えない場合はパスを自分の環境に合わせて変更してから,
dmd hello.d C:/D/dm/lib/Gdi32.lib win32.def C:/D/dmd/src/phobos/win32.lib -w -O -release -ofhello -version=UNICODE dmd hello.d C:/D/dm/lib/Gdi32.lib win32.def C:/D/dmd/src/phobos/win32a.lib -w -O -release -ofhello_ansi -version=UNICODE
とでもコマンドラインにたたき込んでください.dmdのインストールやパスの設定が正しくできていればUNICODE版とANSI版の両方の実行ファイルが作られるはずです.
ところで,昨日の http://d.hatena.ne.jp/haru-s/20060828/1156780825 で書いた,下のコードがコンパイルできない理由はとっても簡単だった.ANSIビルドをしたいからってソースまでANSIに変換してしまっていた(^^; それをやったらそりゃあいろいろとエラーも出るだろう・・・.修正したコードでは,
static const TCHAR[] text = "D言語はWindowsも出来る";
こうじゃなくて, C++ での _T() の代用品 toT() を介して TCHAR[] に代入する.なお,ソースが UTF8 なので文字列リテラルを wchar 型と明示するために最後に "w" を付ける.
TCHAR[] text = toT("D言語はWindowsも出来る"w);
toT() は,version(UNICODE)なのかversion(ANSI)なのかで動作が変化し,何もしないで受け取った引数をそのまま返したり,マルチバイト文字列へ toMBS() を使って変換して返したりしてくれる.
とりあえず,こんなもんでしょうか.間違ってる部分はあると思います.直してみてください(^^;