Reading Message Table resources from DLL files
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
- NSIS forum thread
API Functions used: