Reading Message Table resources from DLL files

From NSIS Wiki
Jump to navigationJump to search
Author: CancerFace (talk, contrib)


NSIS forum thread

Description

DLL files can contain Message Table resources with various strings that may be useful. How can these strings be extracted and used from within an NSIS installer? What if those strings are localized and contain unicode text? Using the FormatMessage API call one can get strings out of DLL files and use them directly

Usage

Call the macro from within your script passing the full path and name of the DLL file containing the Message Table, the ID of the string to get out as well as a variable that will accept the output:

Var "StringFromDLL"
!insertmacro ReadStringFromDLL "<path_to_dll>\<filename.dll>" <String_ID> $StringFromDLL

Macro

If you want to get the string into a variable use the following macro:

!define FORMAT_MESSAGE_ALLOCATE_BUFFER	0x00000100
!define FORMAT_MESSAGE_IGNORE_INSERTS	0x00000200
!define FORMAT_MESSAGE_FROM_HMODULE	0x00000800
!define FORMAT_MESSAGE_MAX_WIDTH_MASK	0x000000FF
 
!macro ReadStringFromDLL LIBRARY STRING_ID VAR
   System::Call 'kernel32::GetSystemDefaultLangID(i v)i .R0'
   System::Call 'kernel32::LoadLibraryExW(w "${LIBRARY}", i n, i 2) i .R1'
   StrCpy $0 ${FORMAT_MESSAGE_FROM_HMODULE}
   IntOp $0 $0 + ${FORMAT_MESSAGE_ALLOCATE_BUFFER}
   IntOp $0 $0 + ${FORMAT_MESSAGE_IGNORE_INSERTS}
   IntOp $0 $0 + ${FORMAT_MESSAGE_MAX_WIDTH_MASK}
   System::Call 'kernel32::FormatMessageW(i r0, i R1, i ${STRING_ID}, i R0, *w .R2, i 0, i n) i .R3'
   System::Call 'kernel32::FreeLibrary(i R1)i .R8'
   StrCpy ${VAR} $R2
!macroend

If you want to get the string into a buffer and use it directly from the buffer in order to avoid placing unicode characters into an NSIS variable use the following macro:

!define FORMAT_MESSAGE_IGNORE_INSERTS	0x00000200
!define FORMAT_MESSAGE_FROM_HMODULE	0x00000800
!define FORMAT_MESSAGE_MAX_WIDTH_MASK	0x000000FF
 
!macro ReadStringFromDLL LIBRARY STRING_ID BUFFER_VAR
   System::Call 'kernel32::GetSystemDefaultLangID(i v)i .R0'
   System::Call 'kernel32::LoadLibraryExW(w "${LIBRARY}", i n, i 2) i .R1'
   StrCpy $0 ${FORMAT_MESSAGE_FROM_HMODULE}
   IntOp $0 $0 + ${FORMAT_MESSAGE_IGNORE_INSERTS}
   IntOp $0 $0 + ${FORMAT_MESSAGE_MAX_WIDTH_MASK}
   System::Call '*(&w${NSIS_MAX_STRLEN})i.R2'
   System::Call 'kernel32::FormatMessageW(i r0, i R1, i ${STRING_ID}, i R0, i R2, i ${NSIS_MAX_STRLEN}, i n) i .R3'
   System::Call 'kernel32::FreeLibrary(i R1)i .R8'
   StrCpy ${BUFFER_VAR} $R2
!macroend

Now ${BUFFER_VAR} will be a pointer to an address containing the wide string. This address can be directly passed to other APIs without exporting the string to an NSIS variable.

Notes

  • The FormatMessage function used in the above macros exports to $R3 the size of the string that has been read from the library expressed as TCHARS.
  • If the ${FORMAT_MESSAGE_ALLOCATE_BUFFER} parameter is not used when calling the FormatMessage API, the user should provide the size of the buffer to be allocated (6th parameter of the FormatMessage call) in TCHARS.

Resources and Links


API Functions used: