看圖學習用D語言編寫包含資源的win32 GUI程序

這篇文章教大家用D語言寫一個具有資源文件的Win 32 GUI 程序。
如果有不會使用D語言的,請看我寫過的《看圖配置D語言集成開發環境》這篇文章。
首先了解一下基礎知識。
D語言的源代碼默認是用UTF8 編寫的。
如果
char szMsg[] = "我們";//這麼寫,就是UTF8的字符串
string sMsg="什麼";//這麼寫,就是UTF8的字符串
MessageBoxW(null,cast(char *)toUTF16(szMsg),null,MB_OK);

wchar szMsg[] = "我們";//這麼寫,就是unicode/UTF16的字符串
wstring sMsg="什麼";//這麼寫,就是unicode/UTF16的字符串
MessageBoxW(null,cast(char *)szMsg,null,MB_OK);

傳遞給win32 API 時類型不匹配,強制轉換是必須的
我的建議是不要使用A後綴的函數。

如果你要直接寫個常字符串在API調用中,有點麻煩
MessageBoxW(null,cast(char *)toUTF16(cast(char[])"我們ddd我麼"),null,MB_OK);
--------------------------------------------------------------------------------------------------------------
windows.d 的API 申明 不全,有時候我們 要自己聲明像下面這樣
//===================================================
//D語言的std.c.windows.windows沒申明的win32 API函數,要用的話自己加上。
extern (Windows)
{
 int LoadStringA(HINSTANCE hInstance,UINT uID,LPTSTR lpBuffer,int nBufferMax);
 BOOL DestroyWindow(HWND hWnd);
 BOOL Rectangle(HDC hdc,int nLeftRect,int nTopRect,int nRightRect,int nBottomRect);
}
//===================================================
--------------------------------------------------------------------------------------------------------------

建一個下圖的項目,再次提醒“項目路徑必須是已存在的目錄”


然後 去 D:/dmd/samples/d (就是放dmd編譯器的地方)目錄把 winsamp.d 的內容 複製到 我們項目中的 main.d 中。複製下面的也行。


/* Compile with:
 * dmd winsamp gdi32.lib winsamp.def
 */

import std.c.windows.windows;
import std.c.stdio;

const int IDC_BTNCLICK = 101;
const int IDC_BTNDONTCLICK = 102;

extern(Windows)
int 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)
    MessageBoxA(hWnd, "Hello, world!", "Greeting",
     MB_OK | MB_ICONINFORMATION);
   break;
      case IDC_BTNDONTCLICK:
   if (HIWORD(wParam) == BN_CLICKED)
   {
       MessageBoxA(hWnd, "You've been warned...", "Prepare to GP fault",
        MB_OK | MB_ICONEXCLAMATION);
       *(cast(int*) null) = 666;
   }
   break;
  }
  break;
     }

     case WM_PAINT:
     {
  static char[] text = "D Does Windows";
  PAINTSTRUCT ps;
  HDC dc = BeginPaint(hWnd, &ps);  
  RECT r;
  GetClientRect(hWnd, &r);
  HFONT font = CreateFontA(80, 0, 0, 0, FW_EXTRABOLD, FALSE, FALSE,
   FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
   DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial");
  HGDIOBJ old = SelectObject(dc, cast(HGDIOBJ) font);
  SetTextAlign(dc, TA_CENTER | TA_BASELINE);
  TextOutA(dc, r.right / 2, r.bottom / 2, text.ptr, text.length);
  SelectObject(dc, old);
  EndPaint(hWnd, &ps);
  break;
     }
     case WM_DESTROY:
  PostQuitMessage(0);
  break;

     default:
  break;
 }
 return DefWindowProcA(hWnd, uMsg, wParam, lParam);
}

int doit()
{
 HINSTANCE hInst = GetModuleHandleA(null);
 WNDCLASS wc;
 wc.lpszClassName = "DWndClass";
 wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
 wc.lpfnWndProc = &WindowProc;
 wc.hInstance = hInst;
 wc.hIcon = LoadIconA(cast(HINSTANCE) null, IDI_APPLICATION);
 wc.hCursor = LoadCursorA(cast(HINSTANCE) null, IDC_CROSS);
 wc.hbrBackground = cast(HBRUSH) (COLOR_WINDOW + 1);
 wc.lpszMenuName = null;
 wc.cbClsExtra = wc.cbWndExtra = 0;
 auto a = RegisterClassA(&wc);
 assert(a);
 
 HWND hWnd, btnClick, btnDontClick;
 hWnd = CreateWindowA("DWndClass", "Just a window", WS_THICKFRAME |
  WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE,
  CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, HWND_DESKTOP,
  cast(HMENU) null, hInst, null);
 assert(hWnd);
 
 btnClick = CreateWindowA("BUTTON", "Click Me", WS_CHILD | WS_VISIBLE,
  0, 0, 100, 25, hWnd, cast(HMENU) IDC_BTNCLICK, hInst, null);

 btnDontClick = CreateWindowA("BUTTON", "DON'T CLICK!", WS_CHILD | WS_VISIBLE,
  110, 0, 100, 25, hWnd, cast(HMENU) IDC_BTNDONTCLICK, hInst, null);

 MSG msg;
 while (GetMessageA(&msg, cast(HWND) null, 0, 0))
 {
  TranslateMessage(&msg);
  DispatchMessageA(&msg);
 }
 
 return 1;
}

/**********************************************************/

/* Note the similarity of this code to the console D startup
 * code in /dmd/src/phobos/dmain2.d
 * You'll also need a .def file with at least the following in it:
 * EXETYPE NT
 * SUBSYSTEM WINDOWS
 */

extern (C) void gc_init();
extern (C) void gc_term();
extern (C) void _minit();
extern (C) void _moduleCtor();
extern (C) 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 = doit(); // insert user code here
    }

    catch (Object o)  // catch any uncaught exceptions
    {
 MessageBoxA(null, cast(char *)o.toString(), "Error",
      MB_OK | MB_ICONEXCLAMATION);
 result = 0;  // failed
    }

    gc_term();   // run finalizers; terminate garbage collector
    return result;
}

然後“生成並運行”,問題來了,下圖狀況。

看樣子是少個 *.lib ,看到源代碼前面的
/* Compile with:
 * dmd winsamp gdi32.lib winsamp.def
 */
了吧,少個gdi32.lib
進入“項目屬性”的導入路徑及程序庫選項卡,程序庫點擊添加 找到 gdi32

好了,“生成並運行”沒問題了,D語言的demo編譯成功了。
去這個網站 下載 Resource Builder,只有30天試用,湊合用。
http://www.resource-builder.com/download.html
http://www.onlinedown.net/soft/12422.htm

安裝了以後 把 “工具”-》“選項”-》“編譯器”裏的 "Res Tool" 指向 我們 安裝 的Resource Builder,
默認是"C:/Program Files/SiComponents/Resource Builder/Resbldr2.exe"

在Resource 上面右鍵 新建 main.res 文件,在IDE裏面把main.res關閉了。

然後雙擊 打開 Resource Builder 進行 資源 編輯。
建立菜單 和 圖標。
我這裏建立了一個圖標和一個菜單,圖標裏面含有3個子項是windows標準要求的我們要拿這個做程序及窗體上的圖標,注意ID值圖標40001,菜單40002程序中要用。這個res文件是編譯後的2進制文件了。

在程序 的 前面 加上
const int IDI_ICON = 40001;
const int IDM_MENU = 40002;
窗口結構填充處修改成
 wc.hIcon = LoadIconW(hInst,cast(wchar*)IDI_ICON);
 wc.lpszMenuName = cast(LPCSTR) IDM_MENU;

效果如下,資源 文件的 使用,請參考其他書籍。

我用D語言寫了個完整 的 《漢諾塔》遊戲,需要看源代碼的去這裏看看,我發的資源裏面也有
http://bbs.gameres.com/showthread.asp?threadid=98142

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章