Chris Grimmett
Chris Grimmett

Reputation: 297

Variable inside string-- Is string interpolation possible in 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:

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?

Upvotes: 0

Views: 3341

Answers (3)

Seki
Seki

Reputation: 11465

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

Upvotes: 2

idleberg
idleberg

Reputation: 12882

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

Upvotes: 3

foobar
foobar

Reputation: 2943

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

Upvotes: 1

Related Questions