// 基于 CFFI 的 Windows GUI 编程
// 仓颉语言团队 刘俊杰 2024.11.04
package windows
import std.math.sin
unsafe main() {
let instance = GetModuleHandleA(EMPTY_STRING)
// 注册窗口类
let className = LibC.mallocCString('Cangjie Window')
var windowClass = WNDCLASSEX(lpszClassName: className,
hInstance: instance,
lpfnWndProc: onMessage,
hbrBackground: CreateSolidBrush(0x00FFFFFF)
)
if (RegisterClassExA(inout windowClass) == 0) {
println('RegisterClass Failed: ${GetLastError()}')
return
}
// 创建窗口实例
let windowName = LibC.mallocCString('Cangjie')
let window = CreateWindowExA(
0, // 扩展样式
className, // 窗口类名
windowName, // 窗口标题
WS_OVERLAPPEDWINDOW, // 窗口风格
CW_USEDEFAULT, CW_USEDEFAULT, // 窗口位置
500, 500, // 窗口大小
NULL, // 父窗口句柄
NULL, // 菜单句柄
instance, // 实例句柄
NULL // 附加参数
)
if (window.isNull()) {
println('CreateWindow Failed: ${GetLastError()}')
return
}
// 显示窗口
ShowWindow(window, SW_SHOWNORMAL)
UpdateWindow(window)
// 启动消息循环
var message = MSG()
while (GetMessageA(inout message, NULL, 0, 0)) {
TranslateMessage(inout message)
DispatchMessageA(inout message)
}
// 退出消息循环
println('Out of Message Loop')
LibC.free(className)
LibC.free(windowName)
}
func paint(hWnd: Handle, draw: (hDC: Handle) -> Unit) {
var ps = PAINTSTRUCT()
let hDC = unsafe { BeginPaint(hWnd, inout ps) }
draw(hDC)
unsafe { EndPaint(hWnd, inout ps) }
}
let points = fractal(100000, 80.0) // 分形树坐标数组
unsafe func process(hWnd: Handle, msg: UInt32,
wParam: UInt64, lParam: UInt64) {
var result = 0
if (msg == WM_PAINT) {
paint(hWnd) { hDC =>
var rect = RECT()
GetClientRect(hWnd, inout rect)
let (width, height) = (rect.right, rect.bottom)
for ((x, y) in points) {
let u = Int32(x) + width / 2
let v = height - Int32(y) - 50
SetPixel(hDC, u, v, 0x559690)
}
}
} else if (msg == WM_KEYDOWN && wParam == UInt64(VK_ESCAPE)) {
DestroyWindow(hWnd)
} else if (msg == WM_DESTROY) {
PostQuitMessage(0)
} else {
result = DefWindowProcA(hWnd, msg, wParam, lParam)
}
return result
}
@C
@CallingConv[STDCALL]
func onMessage(hWnd: Handle, msg: UInt32,
wParam: UInt64, lParam: UInt64): Int64 {
unsafe { process(hWnd, msg, wParam, lParam) }
}