Variable inside string-- Is string interpolation possible in NSIS? - nsis

I'm building an installer with NSIS to help me deploy cgminer to a bunch of computers in my basement. The installer asks for two things:
mining pool URL and worker credentials
directory in which to extract cgminer
The installer uses the user provided pool URL, login name, and password to generate a simple cgminer config file.
Here's the code that writes the JSON config file:
FileOpen $9 $INSTDIR\config.conf w ;Opens a Empty File for writing
FileWrite $9 "{$\r$\n"
FileWrite $9 "$\"pools$\" : [$\r$\n"
FileWrite $9 "$\t{$\r$\n"
FileWrite $9 "$\t$\t$\"url$\" : $\"$POOL$\",$\r$\n"
FileWrite $9 "$\t$\t$\"user$\" : $\"$USER$\",$\r$\n"
FileWrite $9 "$\t$\t$\"pass$\" : $\"$PASS$\",$\r$\n"
FileWrite $9 "$\t}$\r$\n"
FileWrite $9 "],$\r$\n"
FileWrite $9 "$\r$\n"
FileWrite $9 "$\"intensity$\" : $\"d$\"$\r$\n"
FileWrite $9 "}$\r$\n"
FileClose $9 ; closes the file
This is what I'm expecting:
{
"pools" : [
{
"url" : "http://bc.minercity.org:4583",
"user" : "fizzlefazzle_miner",
"pass" : "rosebud",
}
],
"intensity" : "d"
}
However this is what I get:
{
"pools" : [
{
"url" : "1639776",
"user" : "1115594",
"pass" : "1115614",
}
],
"intensity" : "d"
}
I'm assuming I'm getting memory addresses instead of the strings I entered. Here is the code in it's entirety:
; bitcoinminer.nsi
;
; sets up a basic bitcoin miner.
; asks user for mining pool and user/pass
; installs cgminer to <OS DRIVE>\Documents and Settings\<CURRENT USER>\Local Settings\Application Data\ccc\bitcoin\cgminer
; generates cgminer config file and puts it in above dir
;
;--------------------------------
; Includes
!include nsDialogs.nsh
!include LogicLib.nsh
;--------------------------------
; The name of the installer
Name "Bitcoin Miner"
OutFile BitcoinMiner.exe
; The default installation directory
InstallDir "$PROFILE\Local Settings\Application Data\ccc\bitcoin\cgminer2"
; Request application privileges for Windows Vista
RequestExecutionLevel user
;--------------------------------
; Pages
Page Custom poolPageCreate poolPageLeave
Page directory
Page instfiles
Var POOL
Var USER
Var PASS
Function poolPageCreate
nsDialogs::Create 1018 ; creates a new dialog and returns it's HWND on the stack
Pop $0 ; HWID of new dialog stored to $0
${NSD_CreateLabel} 0 0u 75% 12u "Pool URL (ex: http://bc.minercity.org:6347)" ; create label. HWND on the stack
Pop $0 ; HWID of new label stored to $0
${NSD_CreateText} 0 13u 100% 12u 'http://bc.minercity.org:6347'
Pop $POOL
GetFunctionAddress $0 poolChange
nsDialogs::OnChange $POOL $0
${NSD_CreateLabel} 0 40u 75% 12u "Login name (ex: fizzlefazzle_miner)"
Pop $0
${NSD_CreateText} 0 53u 100% 12u 'fizzlefazzle_miner'
Pop $USER
GetFunctionAddress $0 userChange
nsDialogs::OnChange $USER $0
${NSD_CreateLabel} 0 77u 75% 12u "Password (ex: rosebud)"
Pop $0
${NSD_CreateText} 0 90u 100% 12u 'rosebud'
Pop $PASS
GetFunctionAddress $0 passChange
nsDialogs::OnChange $PASS $0
nsDialogs::Show
FunctionEnd
Function poolPageLeave
FunctionEnd
Function poolChange
Pop $0 # HWND
System::Call user32::GetWindowText(i$POOL,t.r0,i${NSIS_MAX_STRLEN})
FunctionEnd
Function userChange
Pop $0
System::Call user32::GetWindowText(i$USER,t.r0,i${NSIS_MAX_STRLEN})
FunctionEnd
Function passChange
Pop $0
System::Call user32::GetWindowText(i$PASS,t.r0,i${NSIS_MAX_STRLEN})
FunctionEnd
Section
;--------------------------------
; The stuff to install
; Set output path to the installation directory.
SetOutPath $INSTDIR
; Put file there
File /r "cgminer\"
FileOpen $9 $INSTDIR\config.conf w ;Opens a Empty File for writing
FileWrite $9 "{$\r$\n"
FileWrite $9 "$\"pools$\" : [$\r$\n"
FileWrite $9 "$\t{$\r$\n"
FileWrite $9 "$\t$\t$\"url$\" : $\"$POOL$\",$\r$\n"
FileWrite $9 "$\t$\t$\"user$\" : $\"$USER$\",$\r$\n"
FileWrite $9 "$\t$\t$\"pass$\" : $\"$PASS$\",$\r$\n"
FileWrite $9 "$\t}$\r$\n"
FileWrite $9 "],$\r$\n"
FileWrite $9 "$\r$\n"
FileWrite $9 "$\"intensity$\" : $\"d$\"$\r$\n"
FileWrite $9 "}$\r$\n"
FileClose $9 ; closes the file
SectionEnd
What am I doing wrong?

There is no problem with string interpolation. Your problem is with the handling of the edit texts: when you state e.g.
${NSD_CreateText} 0 13u 100% 12u 'http://bc.minercity.org:6347'
Pop $POOL
GetFunctionAddress $0 poolChange
nsDialogs::OnChange $POOL $0
You correctly create an edit text and keep its handle to use in the defined callback. But later
FileWrite $9 "$\t$\t$\"url$\" : $\"$POOL$\",$\r$\n"
The file write will store the control handle in the file and not its content.
Also there are some problems with the callbacks:
you read the different values of the edits into the same $0 register, thus $0 would contain the text of the last modified field
the callbacks only trigger when the edit is changed, and if the user makes no change, they are not triggered.
I would use 3 variables for the edit handles and another 3 for the values, then read the value in the page leave callback. Also you can delete the 3 callbacks if you just want to get the final value and not want to react to a value change:
!include nsDialogs.nsh
!include LogicLib.nsh
Name "Bitcoin Miner"
OutFile BitcoinMiner.exe
RequestExecutionLevel user
Page Custom poolPageCreate poolPageLeave
Page directory
Page instfiles
Var POOLHDL
Var USERHDL
Var PASSHDL
Var POOL
Var USER
Var PASS
Function poolPageCreate
nsDialogs::Create 1018 ; creates a new dialog and returns it's HWND on the stack
Pop $0 ; HWID of new dialog stored to $0
${NSD_CreateLabel} 0 0u 75% 12u "Pool URL (ex: http://bc.minercity.org:6347)" ; create label. HWND on the stack
Pop $0 ; HWID of new label stored to $0
${NSD_CreateText} 0 13u 100% 12u 'http://bc.minercity.org:6347'
Pop $POOLHDL
${NSD_CreateLabel} 0 40u 75% 12u "Login name (ex: fizzlefazzle_miner)"
Pop $0
${NSD_CreateText} 0 53u 100% 12u 'fizzlefazzle_miner'
Pop $USERHDL
${NSD_CreateLabel} 0 77u 75% 12u "Password (ex: rosebud)"
Pop $0
${NSD_CreateText} 0 90u 100% 12u 'rosebud'
Pop $PASSHDL
nsDialogs::Show
FunctionEnd
Function poolPageLeave
${NSD_GetText} $POOLHDL $POOL
${NSD_GetText} $USERHDL $USER
${NSD_GetText} $PASSHDL $PASS
FunctionEnd
Section
SetOutPath $INSTDIR
File /r "cgminer\"
FileOpen $9 $EXEDIR\config.conf w ;Opens a Empty File for writing
FileWrite $9 "{$\r$\n"
FileWrite $9 "$\"pools$\" : [$\r$\n"
FileWrite $9 "$\t{$\r$\n"
FileWrite $9 "$\t$\t$\"url$\" : $\"$POOL$\",$\r$\n"
FileWrite $9 "$\t$\t$\"user$\" : $\"$USER$\",$\r$\n"
FileWrite $9 "$\t$\t$\"pass$\" : $\"$PASS$\",$\r$\n"
FileWrite $9 "$\t}$\r$\n"
FileWrite $9 "],$\r$\n"
FileWrite $9 "$\r$\n"
FileWrite $9 "$\"intensity$\" : $\"d$\"$\r$\n"
FileWrite $9 "}$\r$\n"
FileClose $9 ; closes the file
SectionEnd

let me just add that there is a json plugin for nsis

What you're doing wrong is that you're using the handle of the text box directly, so it will not show the actual text but the ID of the handle. To get it to work , edit your poolPageLeavefunction as below:
Function poolPageLeave
${NSD_GetText} $POOL $POOL
${NSD_GetText} $USER $USER
${NSD_GetText} $PASS $PASS
FunctionEnd

Related

NSIS install path validation

I want to validate the installation path selected by the user. I can't figure out how to check that so it will look like this:
You can't select a path with spaces (except Program Files)
When you click "Install" then it will prompt the error saying that you have to change the installation directory
For now I have this:
Function StrStr
Exch $1 ; st=haystack,old$1, $1=needle
Exch ; st=old$1,haystack
Exch $2 ; st=old$1,old$2, $2=haystack
Push $3
Push $4
Push $5
StrLen $3 $1
StrCpy $4 0
; $1=needle
; $2=haystack
; $3=len(needle)
; $4=cnt
; $5=tmp
loop:
StrCpy $5 $2 $3 $4
StrCmp $5 $1 done
StrCmp $5 "" done
IntOp $4 $4 + 1
Goto loop
done:
StrCpy $1 $2 "" $4
Pop $5
Pop $4
Pop $3
Pop $2
Exch $1
FunctionEnd
Function .onVerifyInstDir
Push "$INSTDIR"
Push " "
Call StrStr
Pop $0
StrCpy $0 $0 1
StrCmp $0 " " 0 +2
Abort
FunctionEnd
It refuses to install while there is any space in the path. I need to modify this so Program Files will be the only exception for that rule. Also, printing error message would be helpful
This restriction makes no sense to me. Some legacy applications can't handle spaces in the path but that of course also includes the Program Files folder (although the progra~1 hack can be used as a workaround if short name generation is active).
NSIS does not have a specific way to display a error/warning message directly on the page but you can change existing text in the UI and/or display a balloon.
!include WinMessages.nsh
!define /IfNDef EM_SHOWBALLOONTIP 0x1503
!define /IfNDef EM_HIDEBALLOONTIP 0x1504
!define DIRPAGE_CHANGETEXT ; Remove this line to disable the text change
!define DIRPAGE_BALLOON ; Remove this line to disable the balloon
Function .onVerifyInstDir
FindWindow $9 "#32770" "" $HWNDPARENT
!ifdef DIRPAGE_CHANGETEXT
GetDlgItem $3 $9 1006 ; IDC_INTROTEXT
LockWindow on
!endif
StrCpy $1 0
loop:
StrCpy $2 $InstDir 1 $1
StrCmp $2 '' valid ; End of string
StrCmp $2 ' ' found_space
IntOp $1 $1 + 1
Goto loop
valid:
!ifdef DIRPAGE_CHANGETEXT
SetCtlColors $3 SYSCLR:18 SYSCLR:15
SendMessage $3 ${WM_SETTEXT} "" "STR:$(^DirText)"
LockWindow off
!endif
!ifdef DIRPAGE_BALLOON
GetDlgItem $3 $9 1019
SendMessage $3 ${EM_HIDEBALLOONTIP} "" "" ; Not required?
!endif
Return
found_space:
StrLen $1 "$ProgramFiles\"
StrCpy $2 "$InstDir\" $1
StrCmp $2 "$ProgramFiles\" valid
!ifdef DIRPAGE_CHANGETEXT
SetCtlColors $3 ff0000 transparent
SendMessage $3 ${WM_SETTEXT} "" "STR:Paths with spaces are not allowed, except for $ProgramFiles for some reason!"
LockWindow off
!endif
!ifdef DIRPAGE_BALLOON
GetDlgItem $3 $9 1019
System::Call '*(&l${NSIS_PTR_SIZE},w "Bad path!", w "Spaced not allowed in path!",p 3)p.r2'
SendMessage $3 ${EM_SHOWBALLOONTIP} "" $2 ; This will only work on XP and later (and you must use "XPStyle on")
System::Free $2
!endif
Abort
FunctionEnd
XPStyle on
Page Directory
The Next button is disabled when Abort is called inside .onVerifyInstDir. If you want to display a MessageBox when the user clicks next then you can't call Abort in .onVerifyInstDir, you will have to use the page leave function callback (where you have to verify the path again and maybe call MessageBox+Abort).

How to read into byte array file contents and then update them and write into another file?

I want in nsis to be able to read from file contents into byte array, update the array and then write the contents of the buffer into another file.
My Code
System::Call "kernel32::GetFileSize(i$0,i0)i.s"
Pop $7
System::Alloc $7 ;Reading file contents into a buffer
Pop $buffer
System::Call "kernel32::ReadFile(i$0,i$buffer,i$7,*i.r6,i0)i.s"
loop2:
StrCpy $2 $buffer 1 $1
StrCmp $2 '' end
IntOp $1 $1 + 1
goto loop2
I wanted to be able to iterate over the byte array that i read from the file and to be able to change its contents. (OR bytes for instance) and i wanted to save time from reading byte from a file directly and then writing single byte to a new file. So thats why wanted to use buffer byte array allocated.
Is that possible? I saw that nsis does not support arrays natively.
NSIS does not support byte arrays but the System plug-in struct syntax allows you to access raw bytes in a memory buffer:
!include LogicLib.nsh
!include Util.nsh
ShowInstDetails show
!macro DisplayTestFile
FileOpen $0 "$PluginsDir\Test.txt" r
FileRead $0 $1
FileClose $0
DetailPrint Line1=$1
!macroend
Section
InitPluginsDir
FileOpen $0 "$PluginsDir\Test.txt" w
${If} $0 P<> 0
FileWrite $0 "HELLO World$\r$\n"
FileClose $0
${EndIf}
!insertmacro DisplayTestFile
FileOpen $0 "$PluginsDir\Test.txt" a
${If} $0 P<> 0
FileSeek $0 0 Set
System::Call "KERNEL32::GetFileSize(pr0,p0)i.r1"
${IfThen} $1 = -1 ${|} Abort "Could not get file size" ${|}
System::Call '*(&i$1,i0)p.r2' ; Allocate the file size + a zero terminator just in case
${If} $2 P<> 0
System::Call "KERNEL32::ReadFile(pr0,pr2,ir1,*i,p0)i.r3"
${If} $3 <> 0
${For} $3 0 5 ; Change byte 0..5
System::Call '*$2(&i$3,&i1.r4)' ; Read a byte
IntOp $4 $4 | 32
System::Call '*$2(&i$3,&i1 r4)' ; Write a byte
${Next}
FileSeek $0 0 Set
System::Call "KERNEL32::WriteFile(pr0,pr2,ir1,*i,p0)i.r3"
${EndIf}
System::Free $2
${EndIf}
FileClose $0
${EndIf}
!insertmacro DisplayTestFile
SectionEnd

How do I redirect the output of commands to file in silent mode in NSIS?

In GUI mode, commands like CopyFiles , Delete , etc. output their data to GUI (may be using DetailPrint) and their is a function available on NSIS forums to copy that data (at the end of section) to a file.
Queries:
If the installer is being run in silent mode, how do I get the same data (which was being directed to GUI in non-silent mode) to the file?
In GUI mode, since I am directing custom logs through DetailPrint to the log file with the help of function so that all the logs are received in order. Here the issue is that line breaks are removed from the custom logs. May be DetailPrint removes it. How shall I avoid this?
Example:
DetailPrint "This is a custom log1"
DetailPrint "$\r$\nThis is a custom log2"
/*
Dumped these logs using function mentioned above
Output in logs(with no line breaks):
This is a custom log1
This is a custom log2
Required output:
This is a custom log1
This is a custom log2
*/
Your Second query is Solved.
!include "MUI2.nsh"
section
StrCpy $0 "$EXEDIR\install.log"
Push $0
DetailPrint "This is a custom log1"
DetailPrint "This is a custom log2"
Call DumpLog
sectionend
;!define LVM_GETITEMCOUNT 0x1004
!define LVM_GETITEMTEXT 0x102D
Function DumpLog
Exch $5
Push $0
Push $1
Push $2
Push $3
Push $4
Push $6
FindWindow $0 "#32770" "" $HWNDPARENT
GetDlgItem $0 $0 1016
StrCmp $0 0 exit
FileOpen $5 $5 "w"
StrCmp $5 "" exit
SendMessage $0 ${LVM_GETITEMCOUNT} 0 0 $6
System::Alloc ${NSIS_MAX_STRLEN}
Pop $3
StrCpy $2 0
System::Call "*(i, i, i, i, i, i, i, i, i) i \
(0, 0, 0, 0, 0, r3, ${NSIS_MAX_STRLEN}) .r1"
loop: StrCmp $2 $6 done
System::Call "User32::SendMessageA(i, i, i, i) i \
($0, ${LVM_GETITEMTEXT}, $2, r1)"
System::Call "*$3(&t${NSIS_MAX_STRLEN} .r4)"
FileWrite $5 "$4$\r$\n"
FileWrite $5 "$\r$\n"
IntOp $2 $2 + 1
Goto loop
done:
FileClose $5
System::Free $1
System::Free $3
exit:
Pop $6
Pop $4
Pop $3
Pop $2
Pop $1
Pop $0
Exch $5
FunctionEnd
Your sample code is works for me. Its gives me output as your requirement.
Dont put "$\r$\n" in Detailprint. Add FileWrite $5 "$\r$\n" in DumpLog function as i did. By this you will not have to put $\r$\n in each detail print.

NSIS: How to validate IP address box

I have added a ${NSD_CreateIPaddress} box in my nsi script, but while validating each field of IP is come up with by default to 0. I am getting the IP address value by using ${GetText}.
Is there any way to remove default value 0 and validate each field of IP address. Please help me out.
I'm not really sure what you are asking about. If you want to tell the difference between a blank address and the valid "0.0.0.0" address you can use the IPM_ISBLANK message. There should be no need to validate the individual fields because they are already limited to 0..255 and you can even set a custom range with IPM_SETRANGE.
If you still feel the need to look at the individual fields you can
A) Manually parse the string you get from ${NSD_GetText} yourself.
or
B) Unpack the 32-bit address you get from IPM_GETADDRESS:
Page Custom myPage myPageLeave
Page InstFiles
!include nsDialogs.nsh
; Using custom version of http://nsis.sourceforge.net/NsDialogs_CreateIPaddress
!ifndef NSD_CreateIPaddress
!define NSD_CreateIPaddress "!insertmacro NSD_CreateIPaddress "
!include LogicLib.nsh
!include WinMessages.nsh
!ifndef ICC_INTERNET_CLASSES
!define ICC_INTERNET_CLASSES 0x00000800
!endif
Function CCInitIP
!insertmacro _LOGICLIB_TEMP
System::Call '*(i8,i${ICC_INTERNET_CLASSES})p.s' ; NSIS 2.50+
System::Call 'COMCTL32::InitCommonControlsEx(pss)'
Pop $_LOGICLIB_TEMP
System::Free $_LOGICLIB_TEMP
FunctionEnd
!macro NSD_CreateIPaddress x y w h t
!insertmacro _LOGICLIB_TEMP
Call CCInitIP
nsDialogs::CreateControl "SysIPAddress32" ${DEFAULT_STYLES}|${WS_TABSTOP} 0 ${x} ${y} ${w} ${h} "${t}"
Exch $0
CreateFont $_LOGICLIB_TEMP "$(^Font)" "$(^FontSize)"
SendMessage $0 ${WM_SETFONT} $_LOGICLIB_TEMP 1
Exch $0
!macroend
!define /math IPM_GETADDRESS ${WM_USER} + 102
!define /math IPM_ISBLANK ${WM_USER} + 105
!endif
Function OnIPNotify ; This function displays some information about the IP
Pop $0 ; Not used
${NSD_GetText} $1 $3
StrCpy $4 "NSD_GetText: $3"
SendMessage $1 ${IPM_ISBLANK} 0 0 $0
StrCpy $4 "$4$\nIPM_ISBLANK: $0"
System::Call 'USER32::SendMessage(pr1, i ${IPM_GETADDRESS}, p 0, *i0 r3)p.r0' ; NSIS 2.50+
IntFmt $5 "0x%.8x" $3
StrCpy $4 "$4$\nIPM_GETADDRESS: ValidFields=$0 PackedIP=$5"
IntOp $0 $3 >> 24
IntOp $0 $0 & 0xff
StrCpy $4 "$4$\n$\t Field1=$0"
IntOp $0 $3 >> 16
IntOp $0 $0 & 0xff
StrCpy $4 "$4$\n$\t Field2=$0"
IntOp $0 $3 >> 8
IntOp $0 $0 & 0xff
StrCpy $4 "$4$\n$\t Field3=$0"
IntOp $0 $3 & 0xff
StrCpy $4 "$4$\n$\t Field4=$0"
${NSD_SetText} $2 $4
FunctionEnd
Function myPage
nsDialogs::Create 1018
Pop $0
${NSD_CreateIPaddress} 1% 0 50% 12u ""
Pop $1
${NSD_CreateLabel} 1% 20u 98% -20u "Enter an IP address to see information here..."
Pop $2
${NSD_OnNotify} $1 OnIPNotify ; Display some information when the control is changed
nsDialogs::Show
FunctionEnd
Function myPageLeave
Push 0
Call OnIPNotify
MessageBox mb_ok $4
FunctionEnd

How to retain data on custom page when back/next button clicked when the data is taken from a file?

I have written a custom component page which is having a rich text box and that text box shows the information which is read from the "component.rtf" file. When I go first time on my custom page it shows me rich text box filled with data, but when I click next or back button and come back to custom page again at that time it shows me the rich text box as blank. It shows nothing.
I have written following code for my custom page-
;-------Custom page variables---------
Var Dialog
Var CustomHeaderText
Var CustomSubText
Var path
Var temp1
Var CONTROL
;-------------------------------------
Page custom nsDialogsPage
;------Custom page function----------
Function nsDialogsPage
StrCpy $CustomHeaderText "Components of My Installer"
StrCpy $CustomSubText "Detail list of components are"
!insertmacro MUI_HEADER_TEXT $CustomHeaderText $CustomSubText
!define SF_RTF 2
!define EM_STREAMIN 1097
nsDialogs::Create /NOUNLOAD 1018
Pop $Dialog
${If} $Dialog == error
Abort
${EndIf}
nsDialogs::CreateControl /NOUNLOAD "RichEdit20A" ${ES_READONLY}|${WS_VISIBLE}|${WS_CHILD}|${WS_TABSTOP}|${WS_VSCROLL}|${ES_MULTILINE}|${ES_WANTRETURN} ${WS_EX_STATICEDGE} 0 10u 100% 110u ''
Pop $CONTROL
FileOpen $4 "$path\components.rtf" r
StrCpy $0 $CONTROL
SendMessage $CONTROL ${EM_EXLIMITTEXT} 0 0x7fffffff
; set EM_AUTOURLDETECT to detect URL automatically
SendMessage $CONTROL 1115 1 0
System::Get /NoUnload "(i, i .R0, i .R1, i .R2) iss"
Pop $2
System::Call /NoUnload "*(i 0, i 0, k r2) i .r3"
System::Call /NoUnload "user32::SendMessage(i r0, i ${EM_STREAMIN}, i ${SF_RTF}, i r3) i.s"
loop:
Pop $0
StrCmp $0 "callback1" 0 done
System::Call /NoUnload "kernel32::ReadFile(i $4, i $R0, i $R1, i $R2, i 0)"
Push 0 # callback's return value
System::Call /NoUnload "$2"
goto loop
done:
System::Free $2
System::Free $3
FileClose $4
nsDialogs::Show
FunctionEnd
;--------Custom page function end------------
In above code it reads the file "components.rtf" and displays it. Can someone tell me how to write the code which will retain this data when I will click Back/Next button on component page.?
It works fine for me. Perhaps you are overwriting $path on another page? Add MessageBox MB_OK $4 after FileOpen to make sure you are able to open the file.
!include MUI2.nsh
Var Dialog
Var CustomHeaderText
Var CustomSubText
Var path
#Var temp1
Var CONTROL
;-------------------------------------
Page custom nsDialogsPage
;------Custom page function----------
Function nsDialogsPage
StrCpy $CustomHeaderText "Components of My Installer"
StrCpy $CustomSubText "Detail list of components are"
!insertmacro MUI_HEADER_TEXT $CustomHeaderText $CustomSubText
!define SF_RTF 2
!define EM_STREAMIN 1097
nsDialogs::Create /NOUNLOAD 1018
Pop $Dialog
${If} $Dialog == error
Abort
${EndIf}
nsDialogs::CreateControl /NOUNLOAD "RichEdit20A" ${ES_READONLY}|${WS_VISIBLE}|${WS_CHILD}|${WS_TABSTOP}|${WS_VSCROLL}|${ES_MULTILINE}|${ES_WANTRETURN} ${WS_EX_STATICEDGE} 0 10u 100% 110u ''
Pop $CONTROL
FileOpen $4 "$path\components.rtf" r
StrCpy $0 $CONTROL
SendMessage $CONTROL ${EM_EXLIMITTEXT} 0 0x7fffffff
; set EM_AUTOURLDETECT to detect URL automatically
SendMessage $CONTROL 1115 1 0
System::Get /NoUnload "(i, i .R0, i .R1, i .R2) iss"
Pop $2
System::Call /NoUnload "*(i 0, i 0, k r2) i .r3"
System::Call /NoUnload "user32::SendMessage(i r0, i ${EM_STREAMIN}, i ${SF_RTF}, i r3) i.s"
loop:
Pop $0
StrCmp $0 "callback1" 0 done
System::Call /NoUnload "kernel32::ReadFile(i $4, i $R0, i $R1, i $R2, i 0)"
Push 0 # callback's return value
System::Call /NoUnload "$2"
goto loop
done:
System::Free $2
System::Free $3
FileClose $4
nsDialogs::Show
FunctionEnd
Function .onInit
; Create a RTF file
InitPluginsDir
StrCpy $path "$PluginsDir" ; Set $path used by the custom page
FileOpen $0 "$path\components.rtf" w
FileWrite $0 '{\rtf1\ansi{\fonttbl\f0\fswiss Helvetica;}\f0\pard{Show {\b Me}}\par{http://example.com/#Funny}\par{Goodbye}}'
FileClose $0
FunctionEnd
!insertmacro MUI_PAGE_COMPONENTS
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Section
SectionEnd

Resources