2015-01-22 12 views
1

Windows API 용 루아 바인딩에서 작업하고 있습니다. 지금까지 나는 목록 상자 컨트롤을 기본 윈도우를 생성 할 수있었습니다 : 그것은 만들고 창을 표시하지만, 화면이 제대로 다시 그리기하지 않습니다Windows API : 간단한 창이 올바르게 다시 그려지지 않습니다.

require('Alien') 
package.path = 'libs\\?.lua;libs\\?\\init.lua;' .. package.path 

local function printf(...) io.write(string.format(...)) end 

Windows = require('Windows') 
local W = Windows 

print("loaded OK") 
print("Command line=", W.GetCommandLine()) 


local windowClassName = "testWindow" 
local windowClass, window 
local hInstance = assert(W.GetModuleHandle(nil)) 

assert(W.WM_CREATE) 
assert(W.WM_CLOSE) 
assert(W.WM_DESTROY) 
assert(W.DefWindowProc) 
assert(W.DestroyWindow) 
assert(W.PostQuitMessage) 

local msgID = {} 
for k, v in pairs(Windows) do 
    if k:match('^WM_') then msgID[v] = k end 
end 

local function wndProc(hWnd, msg, wParam, lParam) 
    local id = msgID[msg] or ('%08X'):format(msg) 
    printf('wndProc(%08X, %20s, %08X, %08X\n', 
     hWnd,id, wParam, lParam) 

    if msg == W.WM_CREATE then 
     printf("window %08X create\n", hWnd) 

    elseif msg == W.WM_CLOSE then W.DestroyWindow(hWnd) 
    elseif msg == W.WM_DESTROY then W.PostQuitMessage(0) 
    else return W.DefWindowProc(hWnd, msg, wParam, lParam) 
    end 
    return 0 
end 


local wndProcCB = alien.callback(wndProc, 
    assert(W.LRESULT), assert(W.HWND), 
    assert(W.UINT), assert(W.WPARAM), assert(W.LPARAM)) 


windowClass = assert(W.WNDCLASSEX:new { 
    cbSize  = assert(W.WNDCLASSEX.size), 
    style   = bit.bor(W.CS_HREDRAW, W.CS_VREDRAW), 
    lpfnWndProc = assert(wndProcCB), 
    cbClsExtra = 0, 
    cbWndExtra = 0, 
    hInstance  = assert(hInstance), 
    hIcon   = nil, 
    hCursor  = nil, 
    hbrBackground = assert(W.COLOR_APPWORKSPACE)+1, 
    lpszMenuName = nil, 
    lpszClassName = assert(windowClassName), 
    hIconSm  = nil, 
}) 
assert(W.RegisterClassEx(windowClass)) 


local dwExStyle = bit.bor(
    W.WS_EX_TOOLWINDOW, 
    W.WS_EX_OVERLAPPEDWINDOW) 

local dwStyle = bit.bor(
    W.WS_OVERLAPPEDWINDOW, 
    W.WS_CLIPSIBLINGS, 
    W.WS_CLIPCHILDREN) 

window = assert(W.CreateWindowEx(
    assert(dwExStyle),  --dwExStyle 
    assert(windowClassName), --lpClassName 
    "Test Window",   --lpWindowName 
    assert(dwStyle),   --dwStyle 
    assert(W.CW_USEDEFAULT), --x 
    assert(W.CW_USEDEFAULT), --y 
    420, 314,   --width, height 
    nil, nil, assert(hInstance), nil)) --hWndParent, hMenu, hInstance, lpParam 


local SWP_SHOW_ONLY = bit.bor(
    W.SWP_ASYNCWINDOWPOS, 
    W.SWP_SHOWWINDOW, 
    W.SWP_NOACTIVATE, 
    W.SWP_NOMOVE, 
    W.SWP_NOSIZE, 
    W.SWP_NOZORDER) 
W.SetWindowPos(assert(window), nil, 0, 0, 0, 0, assert(SWP_SHOW_ONLY)) 


local msg = assert(W.MSG:new()) 
while W.GetMessage(msg, 0, 0, 0) do 
    W.TranslateMessage(msg) 
    W.DispatchMessage(msg) 
end 

. 콘솔 출력에서 ​​DefWindowProc에 전달하는 WM_PAINT, WM_ERASEBKGND, WM_NCPAINT 등을 많이 볼 수 있지만 핸들링하지 않는 것 같습니다.

예 스크린 : Example

윈도우가 처음 나타나는 , 이는 (이 경우에서와 같이) 그 배후대로의 화상을 얻어 또는 솔리드 회색으로 표시하거나. 그것은 주변을 끌고 가면서, 그 이미지를 유지하고 그 위에 드래그되는 모든 것은 유령 이미지 뒤에 남습니다. (제목 표시 줄에서 볼 수 있습니다. 활성화 된 창 뒤의 작은 흰색 버튼이 있습니다.) 화면에서 조금 끌면 더 이상 눈에 띄지는 않지만 성공적으로 다시 칠하기는 어렵습니다.

WM_PAINT, WM_ERASEBKGND 등의 다양한 처리 방법을 시도했지만 아무런 효과가 없었습니다. 예제에서는이 메시지가 처리되는 것을 표시하지 않습니다. 내가 잘못하고있는 것이 있습니까, 아니면 제가해야 할 일이 있습니까?

+1

DefWindowProc에 메시지를 전달하지 않고 단순히 WndProc에서 0을 반환 할 수 있습니다. 다른 메시지 처리 – user1793036

+0

@ user1793036'else return W.DefWindowProc (hWnd, msg, wParam, lParam)' – andlabs

답변

1

글쎄, 나는 Rohitab API 모니터의 도움으로이 문제를 발견했다. 실제로 루아 바인딩에 문제가있었습니다 : DefWindowProc에 4 개의 int 매개 변수를 사용하도록 선언했습니다. 0x39FFFFFFF 인 wParam (장치 컨텍스트에 대한 핸들)이있는 WM_ERASEBKGND 메시지가 나타날 때까지 DefWindowProc을 호출하면 int으로 변환되고 잘못된 값이 전달됩니다. 따라서 창은 특정 항목을 올바른 장치 컨텍스트로 렌더링하지 않습니다. 필자의 디버그 로깅 (Windows API 함수를 매개 변수를 콘솔에 인쇄하기 위해 래핑하는)은이 값을 로깅하기 전에 값을 기록했기 때문에이 값도 잡아 내지 못했습니다.

uint을 사용하는 선언을 변경하면 문제가 해결 된 것으로 보입니다. (어쩌면 나는 내 바인딩에 대한 API 모니터의 정의 파일을 사용할 수 있습니다. 다소 부정확 한 것 같습니다.)