Search code examples
nsis

NSIS: How to get width of text in label


I've created a label with text (the text is less than the width of the label) and I would like to create another label with text right where the text ends on the first label. In order for it to be correct on all resolutions I have to calculate where the text ends on run-time. I though of using: Gdi32::GetTextExtentPoint32 but I'm not quite sure how to get the handle to the device context hdc - here is the doc

!macro GetStringLength TEXT FONT OUT_RES
     ; this is what I need...
!macroend

...

${NSD_CreateLabel} 10u 10u 195u 7u $(FIRST_TEXT)
pop $FIRST_LABEL
!insertmacro GetStringLength $(FIRST_TEXT) $CurrentFont $R0
intop $R0 $R0 + 10 # update x
${NSD_CreateLabel} $R0u 10u 195u 7u $(SECOND_TEXT)
pop $FIRST_LABEL

Solution

  • You can use any DC, it just needs the correct font selected in it. We have a HWND so I grab it from there:

    !macro GetStringWidthInPixels txt hfont outvar
    Push $LANGUAGE ;Used as temp storage for StrLen
    System::Call 'USER32::GetDC(i $hwndparent)i.s'
    System::Call 'GDI32::SelectObject(iss,i${hfont})i.s'
    pop ${outvar} ;Used as temp storage for OrgFont
    StrLen $LANGUAGE "${txt}"
    System::Call 'GDI32::GetTextExtentPoint32(iss,t "${txt}",ia,*l.s)'
    System::Call 'GDI32::SelectObject(iss,i${outvar})'
    System::Call 'USER32::ReleaseDC(i $hwndparent,is)'
    pop ${outvar}
    System::Int64Op ${outvar} & 0xffffffff
    pop ${outvar}
    Pop $LANGUAGE
    !macroend
    

    This gets the width in pixels so you cannot use the u suffix. The code itself is a little weird looking, it uses *l as a 64 bit pointer so we don't have to allocate a SIZE struct.