#LuaJIT通过ffi调用win32 API完成窗口版HelloWorld示例
`LuaJIT`也玩了这么长时间了,该玩点比较上档次的东西了~上一次[用`tcc`编译了一个简单记事本程序](../tcc_complier_notepad/detail.html "用`tcc`编译了一个简单记事本程序"),感觉足够炫酷呀~
难道这种窗口程序,用`LuaJIT`就不能也套套近乎么……当然,之前用`wxLua`做的小东西也是不错的……
我说的是更Geek点的东西~调用动态链接库神马的,当时是以能够调用`底层系统API`为终极目标的~
这种事情表面上看是有点画蛇添足的,能用C调为啥要用lua?但是如果是成型的产品做二次开发扩展的话,这些东西就变得尤为重要了……
当然,系统调用的结果当然是使得应用的平台可移植性变窄了,但是从hack某些东西的角度来看,这方面是不必考虑的……
看网上关于`LuaJIT`调用`Win32 API函数`的示例除了蹦对话框,就是调一些简单的修改标题之类的函数来演示……就不能绘制一个完整的窗口,有一个完整的消息循环么?
所以说,这种没人去干的事,当然就有我这样闲的蛋疼的程序媛去完成了……
要写一个`LuaJIT`通过`ffi`调用`win32 API`的窗口版的`Hello World`程序,当然还是得照着C语言的例子来,C语言的`win32`窗口版`Hello World`大约200来行……
本程序一部分来自`tcc`的示例程序`HelloWin.c`,还有一部分参考自`《Windows程序设计》`这本书的`HelloWin`示例程序……
用C调win32 API写过程序的人大约都对微软的这一套匈牙利命名方式还有什么宽字符规则是又爱又恨……
还有就是这套API的成片参数也是够够的……现在再去回顾这套API体系,感觉跟`ODBC API`一样……自由灵活而又繁复复杂……果然是一个公司出的东西……
废话少说,上代码,`hellowin_h.lua`的文件内容:
```lua
local bit = require'bit'
local ffi = require'ffi'
ffi.cdef[[
typedef void *HANDLE;
typedef void *LPVOID;
typedef HANDLE HMODULE;
typedef HANDLE HWND;
typedef HANDLE HINSTANCE;
typedef HANDLE HICON;
typedef HICON HCURSOR;
typedef HANDLE HBRUSH;
typedef HANDLE HMENU;
typedef unsigned char BYTE;
typedef unsigned int UINT,*PUINT,*LPUINT;
typedef unsigned int UINT_PTR, *PUINT_PTR;
typedef UINT_PTR WPARAM;
typedef long LONG_PTR, *PLONG_PTR;
typedef LONG_PTR LPARAM;
typedef LONG_PTR LRESULT;
typedef unsigned long DWORD;
typedef int WINBOOL,*PWINBOOL,*LPWINBOOL;
typedef WINBOOL BOOL;
typedef long LONG;
typedef char CHAR;
typedef struct tagPOINT {
LONG x;
LONG y;
} POINT,POINTL,*PPOINT,*LPPOINT,*PPOINTL,*LPPOINTL;
typedef LRESULT(*WNDPROC)(HWND,UINT,WPARAM,LPARAM);
typedef const CHAR *LPCCH,*PCSTR,*LPCSTR;
typedef struct _WNDCLASSA {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
} WNDCLASSA,*LPWNDCLASSA,*PWNDCLASSA;
typedef WNDCLASSA WNDCLASS,*LPWNDCLASS,*PWNDCLASS;
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG,*LPMSG,*PMSG;
HMODULE GetModuleHandleA(LPCSTR);
HICON LoadIconA(HINSTANCE,LPCSTR);
HCURSOR LoadCursorA(HINSTANCE,LPCSTR);
HCURSOR LoadCursorFromFileA(LPCSTR);
typedef void *HGDIOBJ;
HGDIOBJ GetStockObject(int);
typedef unsigned short WORD;
typedef WORD ATOM;
ATOM RegisterClassA(const WNDCLASSA*);
int MessageBoxA(HWND,LPCSTR,LPCSTR,UINT);
HWND CreateWindowExA(DWORD,LPCSTR,LPCSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID);
BOOL ShowWindow(HWND,int);
BOOL UpdateWindow(HWND);
BOOL GetMessageA(LPMSG,HWND,UINT,UINT);
BOOL TranslateMessage(const MSG*);
LONG DispatchMessageA(const MSG*);
LRESULT DefWindowProcA(HWND,UINT,WPARAM,LPARAM);
typedef struct tagRECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT,*PRECT,*LPRECT;
typedef HANDLE HDC;
typedef struct tagPAINTSTRUCT {
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32];
} PAINTSTRUCT,*LPPAINTSTRUCT;
BOOL GetClientRect(HWND,LPRECT);
typedef DWORD COLORREF;
COLORREF SetTextColor(HDC,COLORREF);
int SetBkMode(HDC,int);
int DrawTextA(HDC,LPCSTR,int,LPRECT,UINT);
HDC BeginPaint(HWND,LPPAINTSTRUCT);
BOOL EndPaint(HWND,const PAINTSTRUCT*);
void PostQuitMessage(int);
HANDLE LoadImageA(HINSTANCE,LPCSTR,UINT,int,int,UINT);
]];
local WINAPI = {
NULL = 0,
FALSE=0,
TRUE=1,
RGB=function(r,g,b)
return bit.bor(r,bit.lshift(g,8),bit.lshift(b,16));
end,
IDI_APPLICATION=32512,
IDI_HAND=32513,
IDI_QUESTION=32514,
IDI_EXCLAMATION=32515,
IDI_ASTERISK=32516,
IDI_WINLOGO=32517,
CS_BYTEALIGNCLIENT=4096,
CS_BYTEALIGNWINDOW=8192,
CS_KEYCVTWINDOW=4,
CS_NOKEYCVT=256,
CS_CLASSDC=64,
CS_DBLCLKS=8,
CS_GLOBALCLASS=16384,
CS_HREDRAW=2,
CS_NOCLOSE=512,
CS_OWNDC=32,
CS_PARENTDC=128,
CS_SAVEBITS=2048,
CS_VREDRAW=1,
CS_IME=0x10000,
CS_DROPSHADOW=0x20000,
BLACK_BRUSH=4,
DKGRAY_BRUSH=3,
GRAY_BRUSH=2,
HOLLOW_BRUSH=5,
LTGRAY_BRUSH=1,
NULL_BRUSH=5,
WHITE_BRUSH=0,
DC_BRUSH=18,
DC_PEN=19,
BLACK_PEN=7,
NULL_PEN=8,
WHITE_PEN=6,
ANSI_FIXED_FONT=11,
ANSI_VAR_FONT=12,
DEVICE_DEFAULT_FONT=14,
DEFAULT_GUI_FONT=17,
OEM_FIXED_FONT=10,
SYSTEM_FONT=13,
SYSTEM_FIXED_FONT=16,
DEFAULT_PALETTE=15,
SW_HIDE=0,
SW_NORMAL=1,
SW_SHOWNORMAL=1,
SW_SHOWMINIMIZED=2,
SW_MAXIMIZE=3,
SW_SHOWMAXIMIZED=3,
SW_SHOWNOACTIVATE=4,
SW_SHOW=5,
SW_MINIMIZE=6,
SW_SHOWMINNOACTIVE=7,
SW_SHOWNA=8,
SW_RESTORE=9,
SW_SHOWDEFAULT=10,
SW_FORCEMINIMIZE=11,
SW_MAX=11,
WS_BORDER=0x800000,
WS_CAPTION=0xc00000,
WS_CHILD=0x40000000,
WS_CHILDWINDOW=0x40000000,
WS_CLIPCHILDREN=0x2000000,
WS_CLIPSIBLINGS=0x4000000,
WS_DISABLED=0x8000000,
WS_DLGFRAME=0x400000,
WS_GROUP=0x20000,
WS_HSCROLL=0x100000,
WS_ICONIC=0x20000000,
WS_MAXIMIZE=0x1000000,
WS_MAXIMIZEBOX=0x10000,
WS_MINIMIZE=0x20000000,
WS_MINIMIZEBOX=0x20000,
WS_OVERLAPPED=0,
WS_OVERLAPPEDWINDOW=0xcf0000,
WS_POPUP=0x80000000,
WS_POPUPWINDOW=0x80880000,
WS_SIZEBOX=0x40000,
WS_SYSMENU=0x80000,
WS_TABSTOP=0x10000,
WS_THICKFRAME=0x40000,
WS_TILED=0,
WS_TILEDWINDOW=0xcf0000,
WS_VISIBLE=0x10000000,
WS_VSCROLL=0x200000,
CW_USEDEFAULT=0x80000000,
MB_USERICON=128,
MB_ICONASTERISK=64,
MB_ICONEXCLAMATION=0x30,
MB_ICONWARNING=0x30,
MB_ICONERROR=16,
MB_ICONHAND=16,
MB_ICONQUESTION=32,
MB_OK=0,
MB_ABORTRETRYIGNORE=2,
MB_APPLMODAL=0,
MB_DEFAULT_DESKTOP_ONLY=0x20000,
MB_HELP=0x4000,
MB_RIGHT=0x80000,
MB_RTLREADING=0x100000,
MB_TOPMOST=0x40000,
MB_DEFBUTTON1=0,
MB_DEFBUTTON2=256,
MB_DEFBUTTON3=512,
MB_DEFBUTTON4=0x300,
MB_ICONINFORMATION=64,
MB_ICONSTOP=16,
MB_OKCANCEL=1,
MB_RETRYCANCEL=5,
MB_SERVICE_NOTIFICATION=0x00040000,
MB_SERVICE_NOTIFICATION_NT3X=0x00040000,
MB_SETFOREGROUND=0x10000,
MB_SYSTEMMODAL=4096,
MB_TASKMODAL=0x2000,
MB_YESNO=4,
MB_YESNOCANCEL=3,
MB_ICONMASK=240,
MB_DEFMASK=3840,
MB_MODEMASK=0x00003000,
MB_MISCMASK=0x0000C000,
MB_NOFOCUS=0x00008000,
MB_TYPEMASK=15,
MB_TOPMOST=0x40000,
MB_CANCELTRYCONTINUE=6,
WM_APP=32768,
WM_ACTIVATE=6,
WM_ACTIVATEAPP=28,
WM_AFXFIRST=864,
WM_AFXLAST=895,
WM_ASKCBFORMATNAME=780,
WM_CANCELJOURNAL=75,
WM_CANCELMODE=31,
WM_CAPTURECHANGED=533,
WM_CHANGECBCHAIN=781,
WM_CHAR=258,
WM_CHARTOITEM=47,
WM_CHILDACTIVATE=34,
WM_CLEAR=771,
WM_CLOSE=16,
WM_COMMAND=273,
WM_COMMNOTIFY=68,
WM_COMPACTING=65,
WM_COMPAREITEM=57,
WM_CONTEXTMENU=123,
WM_COPY=769,
WM_COPYDATA=74,
WM_CREATE=1,
WM_CTLCOLORBTN=309,
WM_CTLCOLORDLG=310,
WM_CTLCOLOREDIT=307,
WM_CTLCOLORLISTBOX=308,
WM_CTLCOLORMSGBOX=306,
WM_CTLCOLORSCROLLBAR=311,
WM_CTLCOLORSTATIC=312,
WM_CUT=768,
WM_DEADCHAR=259,
WM_DELETEITEM=45,
WM_DESTROY=2,
WM_DESTROYCLIPBOARD=775,
WM_DEVICECHANGE=537,
WM_DEVMODECHANGE=27,
WM_DISPLAYCHANGE=126,
WM_DRAWCLIPBOARD=776,
WM_DRAWITEM=43,
WM_DROPFILES=563,
WM_ENABLE=10,
WM_ENDSESSION=22,
WM_ENTERIDLE=289,
WM_ENTERMENULOOP=529,
WM_ENTERSIZEMOVE=561,
WM_ERASEBKGND=20,
WM_EXITMENULOOP=530,
WM_EXITSIZEMOVE=562,
WM_FONTCHANGE=29,
WM_GETDLGCODE=135,
WM_GETFONT=49,
WM_GETHOTKEY=51,
WM_GETICON=127,
WM_GETMINMAXINFO=36,
WM_GETTEXT=13,
WM_GETTEXTLENGTH=14,
WM_HANDHELDFIRST=856,
WM_HANDHELDLAST=863,
WM_HELP=83,
WM_HOTKEY=786,
WM_HSCROLL=276,
WM_HSCROLLCLIPBOARD=782,
WM_ICONERASEBKGND=39,
WM_INITDIALOG=272,
WM_INITMENU=278,
WM_INITMENUPOPUP=279,
WM_INPUT=0x00FF,
WM_INPUTLANGCHANGE=81,
WM_INPUTLANGCHANGEREQUEST=80,
WM_KEYDOWN=256,
WM_KEYUP=257,
WM_KILLFOCUS=8,
WM_MDIACTIVATE=546,
WM_MDICASCADE=551,
WM_MDICREATE=544,
WM_MDIDESTROY=545,
WM_MDIGETACTIVE=553,
WM_MDIICONARRANGE=552,
WM_MDIMAXIMIZE=549,
WM_MDINEXT=548,
WM_MDIREFRESHMENU=564,
WM_MDIRESTORE=547,
WM_MDISETMENU=560,
WM_MDITILE=550,
WM_MEASUREITEM=44,
WM_GETOBJECT=0x003D,
WM_CHANGEUISTATE=0x0127,
WM_UPDATEUISTATE=0x0128,
WM_QUERYUISTATE=0x0129,
WM_UNINITMENUPOPUP=0x0125,
WM_MENURBUTTONUP=290,
WM_MENUCOMMAND=0x0126,
WM_MENUGETOBJECT=0x0124,
WM_MENUDRAG=0x0123,
WM_APPCOMMAND=0x0319,
WM_MENUCHAR=288,
WM_MENUSELECT=287,
WM_NEXTMENU=531,
WM_MOVE=3,
WM_MOVING=534,
WM_NCACTIVATE=134,
WM_NCCALCSIZE=131,
WM_NCCREATE=129,
WM_NCDESTROY=130,
WM_NCHITTEST=132,
WM_NCLBUTTONDBLCLK=163,
WM_NCLBUTTONDOWN=161,
WM_NCLBUTTONUP=162,
WM_NCMBUTTONDBLCLK=169,
WM_NCMBUTTONDOWN=167,
WM_NCMBUTTONUP=168,
WM_NCXBUTTONDOWN=171,
WM_NCXBUTTONUP=172,
WM_NCXBUTTONDBLCLK=173,
WM_NCMOUSEHOVER=0x02A0,
WM_NCMOUSELEAVE=0x02A2,
WM_NCMOUSEMOVE=160,
WM_NCPAINT=133,
WM_NCRBUTTONDBLCLK=166,
WM_NCRBUTTONDOWN=164,
WM_NCRBUTTONUP=165,
WM_NEXTDLGCTL=40,
WM_NEXTMENU=531,
WM_NOTIFY=78,
WM_NOTIFYFORMAT=85,
WM_NULL=0,
WM_PAINT=15,
WM_PAINTCLIPBOARD=777,
WM_PAINTICON=38,
WM_PALETTECHANGED=785,
WM_PALETTEISCHANGING=784,
WM_PARENTNOTIFY=528,
WM_PASTE=770,
WM_PENWINFIRST=896,
WM_PENWINLAST=911,
WM_POWER=72,
WM_POWERBROADCAST=536,
WM_PRINT=791,
WM_PRINTCLIENT=792,
WM_QUERYDRAGICON=55,
WM_QUERYENDSESSION=17,
WM_QUERYNEWPALETTE=783,
WM_QUERYOPEN=19,
WM_QUEUESYNC=35,
WM_QUIT=18,
WM_RENDERALLFORMATS=774,
WM_RENDERFORMAT=773,
WM_SETCURSOR=32,
WM_SETFOCUS=7,
WM_SETFONT=48,
WM_SETHOTKEY=50,
WM_SETICON=128,
WM_SETREDRAW=11,
WM_SETTEXT=12,
WM_SETTINGCHANGE=26,
WM_SHOWWINDOW=24,
WM_SIZE=5,
WM_SIZECLIPBOARD=779,
WM_SIZING=532,
WM_SPOOLERSTATUS=42,
WM_STYLECHANGED=125,
WM_STYLECHANGING=124,
WM_SYSCHAR=262,
WM_SYSCOLORCHANGE=21,
WM_SYSCOMMAND=274,
WM_SYSDEADCHAR=263,
WM_SYSKEYDOWN=260,
WM_SYSKEYUP=261,
WM_TCARD=82,
WM_THEMECHANGED=794,
WM_TIMECHANGE=30,
WM_TIMER=275,
WM_UNDO=772,
WM_USER=1024,
WM_USERCHANGED=84,
WM_VKEYTOITEM=46,
WM_VSCROLL=277,
WM_VSCROLLCLIPBOARD=778,
WM_WINDOWPOSCHANGED=71,
WM_WINDOWPOSCHANGING=70,
WM_WININICHANGE=26,
WM_KEYFIRST=256,
WM_KEYLAST=265,
WM_UNICHAR=265,
UNICODE_NOCHAR=0xffff,
WM_SYNCPAINT=136,
WM_MOUSEACTIVATE=33,
WM_MOUSEMOVE=512,
WM_LBUTTONDOWN=513,
WM_LBUTTONUP=514,
WM_LBUTTONDBLCLK=515,
WM_RBUTTONDOWN=516,
WM_RBUTTONUP=517,
WM_RBUTTONDBLCLK=518,
WM_MBUTTONDOWN=519,
WM_MBUTTONUP=520,
WM_MBUTTONDBLCLK=521,
WM_MOUSEWHEEL=522,
WM_MOUSEFIRST=512,
WM_XBUTTONDOWN=523,
WM_XBUTTONUP=524,
WM_XBUTTONDBLCLK=525,
WM_MOUSELAST=525,
WM_MOUSEHOVER=0x2A1,
WM_MOUSELEAVE=0x2A3,
WHEEL_DELTA=120,
WHEEL_PAGESCROLL=UINT_MAX,
WM_TOUCHMOVE=576,
WM_TOUCHDOWN=577,
WM_TOUCHUP=578,
DT_BOTTOM=8,
DT_CALCRECT=1024,
DT_CENTER=1,
DT_EDITCONTROL=8192,
DT_END_ELLIPSIS=32768,
DT_PATH_ELLIPSIS=16384,
DT_WORD_ELLIPSIS=0x40000,
DT_EXPANDTABS=64,
DT_EXTERNALLEADING=512,
DT_LEFT=0,
DT_MODIFYSTRING=65536,
DT_NOCLIP=256,
DT_NOPREFIX=2048,
DT_RIGHT=2,
DT_RTLREADING=131072,
DT_SINGLELINE=32,
DT_TABSTOP=128,
DT_TOP=0,
DT_VCENTER=4,
DT_WORDBREAK=16,
DT_INTERNAL=4096,
IMAGE_BITMAP=0,
IMAGE_ICON=1,
IMAGE_CURSOR=2,
IMAGE_ENHMETAFILE=3,
LR_DEFAULTCOLOR=0,
LR_MONOCHROME=1,
LR_COLOR=2,
LR_COPYRETURNORG=4,
LR_COPYDELETEORG=8,
LR_LOADFROMFILE=16,
LR_LOADTRANSPARENT=32,
LR_LOADREALSIZE=128,
LR_DEFAULTSIZE=0x0040,
LR_VGACOLOR=0x0080,
LR_LOADMAP3DCOLORS=4096,
LR_CREATEDIBSECTION=8192,
LR_COPYFROMRESOURCE=0x4000,
LR_SHARED=32768,
OPAQUE=2,
TRANSPARENT=1,
BLACKONWHITE=1,
WHITEONBLACK=2,
COLORONCOLOR=3,
HALFTONE=4,
MAXSTRETCHBLTMODE=4
};
return WINAPI;
```
这个文件中包含了基本数据类型、数据结构以及一些常量,在此特别郑重的说明:
**这些定义即便是在`windows平台`下,也是存在平台差异的,不同的平台对于某些常量的定义有细微的差别,而这些差别就是`win32 API`编程过程中的一些坑,在此进行免责,以免大家拿这代码去就用,然后回来说我坑大家……**
这里面除了我们要用到的一些`数据结构`和`API`之外,还包括了其中用到的一些同类型的常量,比如说`WM消息常量`、`窗口类型常量`、`资源ID常量`等,`Hello world`的目的在于扩展成更大的程序,这些常量的引入或许会为这个简单窗口的扩展带来一些便利吧(然而,也许是带来一些坑),比如说添加一些消息监听类型神马的……
上面这些定义有了之后,这个`HelloWorld`程序已经完成一大半了……剩下的就是依次调用了……
`hellowin.lua`的文件内容:
```lua
local bit = require'bit'
local ffi = require'ffi'
local WINAPI = require'hellowin_h'
local kernel32 = ffi.load"kernel32";
local user32 = ffi.load"user32";
local gdi32 = ffi.load"gdi32";
local NULL=0;
local FALSE=0;
local TRUE=1;
local PNULL = ffi.cast("void *",NULL);
--WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
function WndProc(hwnd, message, wParam, lParam)
if message == WINAPI.WM_PAINT then
local ps = ffi.new("PAINTSTRUCT[1]");
local hdc = user32.BeginPaint(hwnd, ps) ;
local rect = ffi.new("RECT[1]");
user32.GetClientRect(hwnd, rect) ;
gdi32.SetTextColor(hdc,WINAPI.RGB(155,130,70));
gdi32.SetBkMode(hdc,WINAPI.TRANSPARENT);
user32.DrawTextA(hdc, "Hello, Windows!", -1, rect,
bit.bor(WINAPI.DT_SINGLELINE , WINAPI.DT_CENTER , WINAPI.DT_VCENTER));
user32.EndPaint (hwnd, ps) ;
return 0 ;
elseif message == WINAPI.WM_DESTROY then
user32.PostQuitMessage(0) ;
return 0 ;
else
return user32.DefWindowProcA(hwnd, message, wParam, lParam);
end
end
local wc = ffi.new("WNDCLASS[1]");
local szAppName = "Hello World!";
local szTitle = "HelloWin";
local hInstance = kernel32.GetModuleHandleA(PNULL);
wndclass = wc[0];
wndclass.style = bit.bor(WINAPI.CS_HREDRAW , WINAPI.CS_VREDRAW) ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
--failed using default method to load icon,use other icon to instead
--wndclass.hIcon = user32.LoadIconA(PNULL, ffi.cast("LPCSTR",WINAPI.IDI_WINLOGO)) ;
--wndclass.hCursor = user32.LoadCursorA(PNULL, ffi.cast("LPCSTR",WINAPI.IDC_ARROW)) ;
--can use,but not beautiful
--wndclass.hIcon = user32.LoadCursorFromFileA("favicon.ico");
wndclass.hIcon = user32.LoadImageA(PNULL, "favicon.ico", WINAPI.IMAGE_ICON, 0, 0, bit.bor(WINAPI.LR_DEFAULTSIZE , WINAPI.LR_LOADFROMFILE));
wndclass.hCursor = user32.LoadCursorFromFileA("default.cur");
wndclass.hbrBackground= ffi.cast("HBRUSH",gdi32.GetStockObject (WINAPI.WHITE_BRUSH));
wndclass.lpszMenuName = PNULL;
wndclass.lpszClassName= szAppName ;
if FALSE == user32.RegisterClassA(wc) then
user32.MessageBoxA(PNULL,"This program requires Windows NT!",szAppName, WINAPI.MB_ICONERROR) ;
return 0 ;
end
local hwnd = user32.CreateWindowExA(0,
szAppName,
szTitle,
bit.bor(WINAPI.WS_OVERLAPPEDWINDOW,WINAPI.WS_VISIBLE),
WINAPI.CW_USEDEFAULT,
WINAPI.CW_USEDEFAULT,
WINAPI.CW_USEDEFAULT,
WINAPI.CW_USEDEFAULT,
PNULL,
PNULL,
hInstance,
PNULL);
if PNULL == hwnd then
user32.MessageBoxA(PNULL, "Create Window Handle ERROR!", szAppName, WINAPI.MB_ICONERROR) ;
return 0;
end;
user32.ShowWindow (hwnd, WINAPI.SW_SHOWNORMAL) ;
user32.UpdateWindow (hwnd) ;
local msg = ffi.new("MSG[1]");
while user32.GetMessageA(msg, PNULL, 0, 0) > 0 do
user32.TranslateMessage(msg);
user32.DispatchMessageA(msg);
end
return msg[0].wParam;
```
程序主体只有80行,整个调用过程还是挺清晰的:
先是定义一个消息回调函数,负责监听消息,这里面只定义了两个消息,一个是窗口绘制,一个是窗口的销毁。
正规的C语言的消息回调函数都是用`switch...case`的,但是`lua`里面没有`switch...case`关键字,更好的用法是使用表映射相应的函数进行回调,但是由于此处处理的消息实在是太少了,就不大炮打蚊子了……规规矩矩的`else...if`了……
然后就是主程序,先给窗口类结构体赋值,然后注册窗口类,创建窗口描述句柄,显示窗口,进入消息循环,然后over了~
这个地方需要说一说的地方是窗口类结构体中`hIcon`和`hCursor`的赋值,大家可以看到,这一块注释比较多……
最开始使用的是C示例程序中的`LoadIconA`和`LoadCursorA`,然而无论如何,好像获取不到这个资源,也许是与我`LuaJIT`的编译方式有关……
然而不想再拘泥于这两个函数,用文件加载图标的方式也是可以的啊,随手从机器里找了两个可以用的图标充数,然后就是方法,我找到了`LoadCursorFromFileA`方法,加载鼠标是可以的,其实用来加载窗口图标也是可以的,但是我觉得这样不好,用加载鼠标的方法加载了图标……既然是图标,自然需要用加载图标的正确方法……
后来我又找到了`LoadImageA`方法,这个可以用来加载图标文件资源,用上之后感觉还可以……大家可以试试……
然后就是另一个要说的,`hInstance`程序实例句柄,这个按理说应该是`WinMain`函数入口传递的一个句柄……
但是`lua`可没有这么个函数入口啊……那这个`hInstance`怎么来啊……找了一些方法来获取本程序的程序实例句柄……
后来在网上找到`GetModuleHandleA`是可以用的……试了一下还行,但是并不知道这个方法的调用是否正确……
希望有对`Win32 API`系统了解全面的人来解释一下……
整个示例程序就是这样,总共五百多行,有三四百行在常量定义上……我自我感觉我莫非是第一个闲的蛋疼写出这个程序来的人?
好了,整个程序就是这样,分享出来,给对`win32 API`怀有特殊情结的人们~
想要玩的同学[可以从这个地址下载下来玩](http://pan.baidu.com/s/1jInxX8E "可以从这个地址下载下来玩")……
最后,放上本程序的运行效果图来镇楼:
![运行效果图](demo.png "运行效果图")