Calling an Inno setup plugin from NSIS - inno-setup

I'm trying to use an Inno setup plugin called webcrtl (a web browser with more features than nsweb). I'm trying to call this dll with the system plugin.
The plugin:
http://restools.hanzify.org/article.asp?id=90
This is what I'm trying, without success:
Page custom Pre
Var hCtl_dialog
Var browser
Function Pre
InitPluginsDir
File "${BASEDIR}/Plugins/inno_webctrl_v2.1/webctrl.dll"
nsDialogs::Create 1018
Pop $hCtl_dialog
System::Call "webctrl::NewWebWnd(i $HWNDPARENT, i 100, i 100, i 200, i 200) i .s"
Pop $browser
System::Call "webctrl::DisplayHTMLPage(i '$browser', t 'http://www.google.com/') i .s"
Pop $R0
nsDialogs::Show $hCtl_neoinstaller_genericcustom
FunctionEnd
I'm getting an empty page...

DLL library function names are case sensitive, and you have used aliases instead of the function names from that InnoSetup script. Modify your script, so that will use function names with proper case sensitivity and you'll get your script to work. The name of a function to be imported, is the word before the # char from the external keyword import tail. For instance, in the following function import sample, the name of the imported function is newwebwnd, not NewWebWnd:
function NewWebWnd(hWndParent: HWND; X, Y, nWidth, nHeight: Integer): HWND;
external 'newwebwnd#files:webctrl.dll stdcall';
So in your case, modify the function names the following way and you should be fine:
...
System::Call "webctrl::newwebwnd(i $hCtl_dialog, i 0, i 0, i 150, i 150) i.s"
Pop $browser
System::Call "webctrl::displayhtmlpage(i $browser, t 'http://www.google.com/') b.s"
Pop $R0
...
The whole script for the WebCtrl control stretched inside the install page might then look like this:
!include "nsDialogs.nsh"
OutFile "Setup.exe"
RequestExecutionLevel user
InstallDir $DESKTOP\WebBrowserSetup
Page directory
Page custom InitializeWebBrowserPage
var hDialog
var hBrowser
Function InitializeWebBrowserPage
InitPluginsDir
SetOutPath $PLUGINSDIR
File "webctrl.dll"
nsDialogs::Create 1018
Pop $hDialog
; get the page client width and height
System::Call "*(i, i, i, i) i.r0"
System::Call "user32::GetClientRect(i $hDialog, i r0)"
System::Call "*$0(i, i, i.r1, i.r2)"
System::Free $0
; create a web browser window stretched to the whole page client rectangle
; and navigate somehwere; note that you should add some error handling yet
System::Call "webctrl::newwebwnd(i $hDialog, i 0, i 0, i $1, i $2) i.s"
Pop $hBrowser
System::Call "webctrl::displayhtmlpage(i $hBrowser, t 'http://www.google.com') b.s"
Pop $R0
nsDialogs::Show
FunctionEnd
Section ""
SectionEnd

Related

How to use System::Call and MessageBox when calling the C++ dll method from the NSIS script

My requirement is I need to test "If the device is present before we try to disable the Native Power" from the system.
For that I need to call the below function that is there in testutil.dll
BOOL IsTherePower()
Below is the NSIS script to call this function:
Name "PowerTest"
OutFile "PowerTest.exe"
InstallDir $PROGRAMFILES\PowerTest
Section "PowerTest(required)"
SectionIn RO
DetailPrint "PowerTest"
; Set output path to the installation directory. Here is the path C:\Program Files\PowerTest
SetOutPath $INSTDIR
; Give the dll path
File E:\Code\Source\Validatepower.exe
File E:\Code\Source\testutil.dll
File E:\Code\Source\ntutil.dll
File E:\Code\Source\dlgdll.dll
System::Call "$INSTDIR\testutil.dll::IsTherePower() i.r0"
Pop $0
MessageBox MB_OK "Return value = $R0, lasterr = $0"
IntCmp $R0 1 OkToInstall CancelInstall
CancelInstall:
Abort "Not allowed to install"
OkToInstall:
Do the install
With the above code when i run the application i am getting "Return value=, lasterr = error". I am not sure why i am getting the "Return value" blank (null). Did I miss anything here?
I have written "System::Call" and "MessageBox" but not sure what they are doing.
Here I want to know what is "i.r0" from System::Call
And also what is "Pop $0"?
You are using the wrong register. r0 in System syntax is $0, not $R0 (R0 and r10 is $R0). System::Call "$INSTDIR\drvutil.dll::IsUPSPresent() i.r0" puts the INT32 return value in $0 and then you overwrite $0 with the Pop and your stack happened to be empty.
If you need to call GetLastError() then you must append the ?e option:
System::Call "$INSTDIR\drvutil.dll::IsUPSPresent() i.r0 ?e" ; Pushes error code on top of the stack
Pop $1 ; Get error code
DetailPrint "Return=$0 LastError=$1"
?e pushes the last error on the stack and Pop extracts the top item on the stack.
I can confirm that my code works, I tested in on a dummy .DLL. If it does not work for you then System::Call is unable to load the .DLL or find the exported function. The most likely issue is that you have not exported the function correctly in your .DLL.
Inspect your .DLL with Dependency Walker, it is supposed to look like this:
not
You can also try do verify it manually in NSIS:
!include LogicLib.nsh
Section
SetOutPath $InstDir
File drvutil.dll
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\drvutil.dll")p.r8 ?e'
Pop $7
${If} $8 P<> 0
MessageBox MB_OK 'Successfully loaded "$InstDir\drvutil.dll" # $8'
System::Call 'KERNEL32::GetProcAddress(pr8, m "IsUPSPresent")p.r9 ?e'
Pop $7
${If} $9 P<> 0
MessageBox MB_OK 'Successfully found "IsUPSPresent" # $9'
${Else}
MessageBox MB_ICONSTOP 'Unable to find "IsUPSPresent", error $7'
${EndIf}
System::Call 'KERNEL32::FreeLibrary(pr8)'
${Else}
MessageBox MB_ICONSTOP 'Unable to load "$InstDir\drvutil.dll", error $7'
${EndIf}

Creating shortcut to console application in NSIS with particular font

I have an NSIS script which can create a shortcut to an application with CreateShortCut.
The application that the shortcut points to is a console application, but one which works much better if there is something other than the default font chosen. Of course, the user can be told to follow instructions like https://www.isunshare.com/windows-10/change-font-and-font-size-in-windows-10-command-prompt.html to change to a different font on the shortcut, but my quetsion is whether that can be automated in NSIS? That is, check if a particular font is available and then have the shortcut start a console with that font.
If that is impossible in NSIS for a particular shortcut, is there a way to give users the option to have a system-wide change to the font used in all terminals?
The CreateShortcut instruction only supports basic shortcut properties, it does not support console properties set by IShellLinkDataList.
Setting the NT_CONSOLE_PROPS data has two issues:
It is all or nothing, you have to set the size, color and edit options in addition to the font.
Ideally you should provide the "index of the font in the system's console font table" but that index is not really documented and I don't know how to map from a font name to the index.
If you still want to do it then you must use the System plug-in:
!include LogicLib.nsh
!include Win\COM.nsh ; NSIS v3
!define /ifndef LF_FACESIZE 32
!define /ifndef NT_CONSOLE_PROPS_SIG 0xA0000002
Section
StrCpy $R1 "$Desktop\MyApp.lnk" ; .Lnk path
StrCpy $R3 "Consolas" ; Font name
StrCpy $R5 i0x36 ; tmPitchAndFamily?
StrCpy $R6 400 ; "The weight can range from 100 to 1000, in multiples of 100. For example, the normal weight is 400, while 700 is bold"
StrCpy $R7 0xc0000 ; dwFontSize packed COORD
StrCpy $R8 0x200060 ; dwWindowSize packed COORD
System::Call '*(&l4,i${NT_CONSOLE_PROPS_SIG}, i0xf50007,i0x3e70050,i$R8,i0x0,i0x0,i0x0,i$R7,i$R5,i$R6, &w${LF_FACESIZE}"$R3", i0x19,i0x0,i0x1,i0x1,i0x1,i0x32,i0x4,i0x1,i0x0,i0x800000,i0x8000,i0x808000,i0x80,i0x800080,i0x8080,i0xc0c0c0,i0x808080,i0xff0000,i0xff00,i0xffff00,i0xff,i0xff00ff,i0xffff,i0xffffff)p.R2'
!insertmacro ComHlpr_CreateInProcInstance ${CLSID_ShellLink} ${IID_IShellLink} r0 ""
${If} $0 P<> 0
${IShellLink::SetPath} $0 '("%COMSPEC%").r1'
${IShellLink::SetArguments} $0 '("/k echo HelloWorld").r2'
${If} $1 = 0
${AndIf} $2 = 0
${IUnknown::QueryInterface} $0 '("${IID_IShellLinkDataList}",.r1)'
${If} $1 P<> 0
${IShellLinkDataList::AddDataBlock} $1 '(pR2).r2'
${IUnknown::Release} $1 ""
${EndIf}
${IUnknown::QueryInterface} $0 '("${IID_IPersistFile}",.r1)'
${If} $1 P<> 0
${IPersistFile::Save} $1 '("$R1",1).r2'
${IUnknown::Release} $1 ""
${EndIf}
${EndIf}
${IUnknown::Release} $0 ""
${EndIf}
System::Free $R2 ; Free NT_CONSOLE_PROPS
SectionEnd

Three choices in shortcut options

we have our installer where are some choices to create shortcuts
1) create shortcut for current user
2) create shortcut for all users
3) do not create any shortcut
The first option is checked as default, if I check any other it work well..the problem is that if I check for example 3rd option, move to next page and come back there are 2 choices checked - 1st (default) and 3rd (selected).
I am very new to NSIS and can't find better way than I did it as the code is not very friendly for me.
I would appreciate advice.
Thanks,
This is what I have in my installation options .ini :
[Field 5]
Type=GroupBox
Left=1
Right=-1
Top=80
Bottom=144
Text="Choice of shortcuts:"
State=""
[Field 6]
Type=RadioButton
Left=10
Right=-10
Top=96
Bottom=108
Text="Create shortcuts for all users"
State=1
Flags=GROUP|NOTIFY
[Field 7]
Type=RadioButton
Left=10
Right=-10
Top=112
Bottom=124
Text="Create shortcuts only for a current user"
State=0
Flags=NOTIFY
[Field 8]
Type=RadioButton
Text="Do not create shortcut"
Flags=NOTIFY
State=0
Left=10
Right=-10
Top=128
Bottom=140
Then later in nsis script:
IntCmp $ShortcutsForAllUsers 1 ShortcutsForAll ShortcutsForCurrentUser ShortcutsForCurrentUser
ShortcutsForAll:
SetShellVarContext all
goto done
ShortcutsForCurrentUser:
SetShellVarContext current
goto done
NoShortcuts:
goto done
done:
FunctionEnd
The InstallOptions page should remember its state as long as you don't extract it every time in the page create callback function.
!include LogicLib.nsh
!include InstallOptions.nsh
ChangeUI All "${NSISDIR}\Contrib\UIs\modern.exe"
Function .onInit
!insertmacro INSTALLOPTIONS_EXTRACT_AS "...\test.ini" "iosp.ini"
FunctionEnd
Var ShortcutMode
Page Custom MyShortcutPageCreate MyShortcutPageLeave
Page Components
Page InstFiles
Function MyShortcutPageCreate
!insertmacro INSTALLOPTIONS_DISPLAY "iosp.ini"
FunctionEnd
Function MyShortcutPageLeave
!insertmacro INSTALLOPTIONS_READ $0 "iosp.ini" "Settings" "State"
${If} $0 > 0
IntOp $ShortcutMode $0 - 6 ; Map .ini Field Id to 0 (or empty), 1 or 2
Abort
${EndIf}
FunctionEnd
Section
${If} $ShortcutMode = 0
SetShellVarContext all
${ElseIf} $ShortcutMode = 1
SetShellVarContext current
${EndIf}
...
SectionEnd
There is a problem with this design, SetShellVarContext current might not map $SMPrograms to the correct startmenu folder because UAC can elevate a process with a different Administrator user...

Find a string pattern in a file from an NSIS script

In an NSIS installer script, I'm trying to check if a given httpd.conf file contains the following line :
Include "c:\xxx\yyy.conf"
If so, then my installer script would not append it to the file, otherwise, it would append it.
I've come through {LineFind} but not sure this really makes what i'm trying to achieve.
What could be the simplest way to do a kind of "grep" on a text file from an NSIS script ?
Thank you !
Here is a sample for searching for a given line into a file, using the LogicLib for ease of syntax. The search is stopped as soon as the line is found. This sample works on the sample script itself:
# find.nsi : sample for LineFind from TextFunc.nsh
!include "textfunc.nsh"
!include "logiclib.nsh"
OutFile "find.exe"
!define lookfor `Section` ;will find
;!define lookfor `Sectionn` ;will not find
Var found
Section
StrCpy $found 0
${LineFind} "find.nsi" "/NUL" "1:-1" "GrepFunc"
${if} $found = 1
MessageBox MB_OK "string found"
${else}
MessageBox MB_OK "string NOT found"
${endIf}
SectionEnd
Function GrepFunc
${TrimNewLines} '$R9' $R9
DetailPrint "test for line $R8 `$R9`"
${if} $R9 == "${lookfor}"
StrCpy $found 1 ;set flag
Push "StopLineFind" ;stop find
${else}
Push 0 ;ignore -> continue
${endIf}
FunctionEnd

NSIS: How to add custom button to left bottom corner and handle it's click?

I tried the ButtonEvent plugin, but when I run compiled example, it fails with memory access error. Maybe it is able to do with System plugin via Windows API or something else? Can anyone show how it can be done?
UPD: Error was appeared because I tried to use non-unicode ButtonEvent on Unicode NSIS. Now example compiles and executes OK, but when I click on TryMe button, callback function is not called and nothing happens. How to determine what is the problem? Can anyone compile ButtonEventMUI.nsi and click on TryMe button? I downloaded latest ButtonEvent version. Using NSIS 2.46 Unicode
The system plugin cannot do this because it cannot subclass windows.
The ButtonEvent plugin works fine for me (NSIS 2.46):
Name BtnTest
Outfile test.exe
Installdir "$temp"
RequestExecutionLevel user
BrandingText " " ;Button covers this text
!include nsDialogs.nsh ;For WS_*
Function .onGuiInit
; You are supposed to use ChangeUI (or MUI_UI) and a modified ui file to add new buttons but this example adds the button at run-time...
GetDlgItem $0 $hwndparent 2 ; Find cancel button
System::Call *(i,i,i,i)i.r1
System::Call 'USER32::GetWindowRect(ir0,ir1)'
System::Call *$1(i.r2,i.r3,i.r4,i.r5)
IntOp $5 $5 - $3 ;height
IntOp $4 $4 - $2 ;width
System::Call 'USER32::ScreenToClient(i$hwndparent,ir1)'
System::Call *$1(i.r2,i.r3)
System::Free $1
IntOp $2 $2 + $4 ;x
IntOp $2 $2 + 8 ;x+padding
System::Call 'USER32::CreateWindowEx(i0,t "Button",t "Click Me",i${WS_CHILD}|${WS_VISIBLE}|${WS_TABSTOP},ir2,ir3,ir4,ir5,i $hwndparent,i 0x666,i0,i0)i.r0'
SendMessage $hwndparent ${WM_GETFONT} 0 0 $1
SendMessage $0 ${WM_SETFONT} $1 1
GetFunctionAddress $0 onmybtnclick
ButtonEvent::AddEventHandler 0x666 $0
FunctionEnd
Function onmybtnclick
MessageBox mb_ok "You clicked me!"
FunctionEnd
Page Directory
Page Instfiles
Section
SectionEnd

Resources