可以在 NSIS 中绘制到 window,如何声明类型的 WinAPI 变量?

Possible to paint to window in NSIS, How to declare WinAPI variable of type?

是否可以在 NSIS 中绘制静态控件?如果是,我该如何声明变量,例如 PAINTSTRUCT 等?我可以在常规 C 中轻松完成此操作,但使用 NSIS 和汇编类型语言让我很困惑。

下面我正在尝试在静态控件上绘制边框:

Var MainWndSubProc
Function MainWndSubProc
    ${If}  = ${WM_DRAWITEM}
        # I'm assuming  = the WPARAM and  = LPARAM?

        $LOWORD $R0  # get id of window we are painting
        ${If} $R0 == $myStaticId
            # C code which works: how to translate to NSIS 'assembly'?
            HDC hdc;
            PAINTSTRUCT ps;
            hdc = BeginPaint(args.hwnd, &ps);

            RECT mRect;
            GetClientRect(args.hwnd, &mRect);

            HBRUSH brush = CreateSolidBrush(RGB(50, 50, 50));
            HPEN pen = CreatePen(PS_SOLID, 5, RGB(191, 191, 191));
            SelectObject(hdc, pen);
            SelectObject(hdc, brush);
            Rectangle(hdc, 0, 0, mRect.right, mRect.bottom);
            DeleteObject(pen);
            DeleteObject(brush);

            EndPaint(args.hwnd, &ps);


            # NSIS translation
            # how to declare PAINTSTRUCT
            $LOWORD $R0 
            System::Call `user32::BeginPaint(i $R0, i R1)`
            .. ?
        ${EndIf}
    ${EndIf}
FunctionEnd

Function MyGUIInit
    ${WndSubclass_Subclass} $HWNDPARENT MainWndSubProc $MainWndSubProc $MainWndSubProc
FunctionEnd

<= 64 位的类型在普通 NSIS 变量中存储为字符串。对于较大的类型,您需要使用系统插件结构语法:

OutFile test.exe
RequestExecutionLevel user

Page InstFiles

!include WinMessages.nsh
!include nsDialogs.nsh
!include LogicLib.nsh
!include Colors.nsh
!include WndSubclass.nsh

Var MainWndSubProc
Var hStaticCtrl
Function MainWndSubProc
${If}  = ${WM_DRAWITEM}
    System::Call '*(i,i,i,i,i,i.r5,i.r6,i,i,i.r8,i.r9)' ; Get HWND, HDC and size from DRAWITEMSTRUCT
    ${If} $hStaticCtrl = 
        System::Call 'GDI32::CreateSolidBrush(i 0x2277ee)i.s' ; Just made up a color here
        System::Call 'GDI32::SelectObject(ir6,is)i.s'
        ${RGB}  191 191 191
        System::Call 'GDI32::CreatePen(i${PS_SOLID}, i5, i "0x")i.s'
        System::Call 'GDI32::SelectObject(ir6,is)i.s'
        System::Call 'GDI32::Rectangle(ir6, i0, i0, ir8, ir9)'
        System::Call 'GDI32::SelectObject(ir6,is)i.s'
        System::Call 'GDI32::DeleteObject(is)'
        System::Call 'GDI32::SelectObject(ir6,is)i.s'
        System::Call 'GDI32::DeleteObject(is)'
    ${EndIf}
${EndIf}
FunctionEnd

Function .onGUIInit
; Your example failed to show how you create the static control so I'm forced to just create one here at run-time
GetDlgItem [=10=] $hwndparent 2 ; Find cancel button so we can put our control there
ShowWindow [=10=] 0
System::Call '*(i,i,i,i)i.r1'
System::Call 'USER32::GetWindowRect(ir0,ir1)'
System::Call 'USER32::MapWindowPoints(i0,i$hwndparent,ir1,i2)'
System::Call '*(i.r4,i.r5,i.r6,i.r7)'
System::Free 
IntOp   - 
IntOp   - 
System::Call 'USER32::CreateWindowEx(i0, t "Static", i0, i${WS_CHILD}|${WS_VISIBLE}|${SS_OWNERDRAW}, ir4, ir5, ir6, ir7, i$hwndparent, i0, i0, i0)i.r0'
StrCpy $hStaticCtrl [=10=]
${WndSubclass_Subclass} $HWNDPARENT MainWndSubProc $MainWndSubProc $MainWndSubProc
FunctionEnd

Section
SectionEnd

你的 C 代码质量让我相信你还没有准备好编写这种代码。如果您查看 DRAWITEMSTRUCT 的文档,您会看到 hDC 成员的评论:"this device context must be used when performing drawing operations on the control." 但您决定调用 BeginPaint!您也无法恢复 DC,并且删除了选择到 DC 中但不允许的对象。