NSIS: Task Scheduler: Run only if logged on checkbox - nsis

I am having issues with setting up a scheduled task with NSIS.
I will not know all of the passwords for the users I am setting up tasks for therefore I need the Run Only if Logged On checkbox checked to get around that.
I do not have access to install other pieces of software onto the computer other than setting up the task so I have to utilize the Windows Task Scheduler preferably.
The task below sets up the task, checks the checkbox however does not run the task set up. It will not run the task until I go and browse to the same file again and then click OK. Now the task wil run just fine. I asked about this behavior in another forum about JT.exe because it does the same thing and was told "It doesn't set the Log on as a batch job User Right that is set by schtasks.exe or the GUI."
I have attempted to create the task and then modify it via the command line. It still does not function.
The goal is to create a Windows XP scheduled task using NSIS (or anything for that matter) that executes properly and checks the Run Only if Logged On checkbox in Task Scheduler 1.0.
Can someone please help?
Here is the current NSIS Script
; Adds a scheduled task running as a different user than the one
; running the installer. Modified from a script by brainsucker
;
; (c) Justin Dearing <zippy1981#gmail.com>, 2006
; (c) brainsucker, 2002
Name "System Plugin Example"
OutFile "Sheduletask.exe"
; TASK_TRIGGER is the struct that sets when your task in run.
; Setting it via the NSIS System plugin is a healthy alternative to
; banging ones head against the wall.
;
; general TASK_TRIGGER structure arguments
; 1, 2 - skip
; 3,4,5 - BEGIN year, month, day
; 6,7,8 - END year, month, day (SHOULD be = 0, if 1 flag is skipped)
; 9, 10 - Start hour, minute
; 11, 12 - Duration and Interval of task in minutes. (duration - the whole
; time task will work, interval - time between runs. D = 120,
; I = 10: task will be runned every 10 minutes for 2 hours).
; 13 - flags (should be ored (|)):
; 1 - task has end date (6,7,8 defined)
; 2 - task will be killed at Duration end
; 4 - task trigger disabled
; 14 - trigger type: there are 7 different types, every one with it own
; structure
; 0 = ONCE task will be runned once
; 5 = On IDLE task will run on system IDLE (ITask->SetIdleWait)
; 6 = At System Startup
; 7 = At Logon
; these types use the following structure (so 7 means trigger at Logon):
; push "*(&l2, &i2 0, &i2 2003, &i2 9, &i2 4, &i2 0, &i2 0, &i2 0, &i2 14, &i2 20, i 0, i 0, i 0, i 7, i 0, &i2 0, i 0, &i2 0) i.s"
; 1 = DAILY - field 15 gives interval in days (here it 15)
; push "*(&l2, &i2 0, &i2 2003, &i2 9, &i2 3, &i2 0, &i2 0, &i2 0, &i2 13, &i2 10, i 0, i 0, i 0, i 1, &i2 15, i 0, i 0, &i2 0) i.s"
; 2 = WEEKLY - field 15 gives interval in weeks (here 17),
; field 16 - shows which days to run (OR them with |):
; Sunday-Saturday (0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40)
; in example monday and friday
; push "*(&l2, &i2 0, &i2 2003, &i2 9, &i2 3, &i2 0, &i2 0, &i2 0, &i2 13, &i2 10, i 0, i 0, i 0, i 2, &i2 13, &i2 0x2|0x20, &i2 0, i 0, &i2 0) i.s"
; 3 = MONTHLYDATE - field 15 bit field of days (OR them) to run
; (0x1-0x40000000),
; field 16 - bit field of month (OR them with |):
; January-December (0x1-0x800)
; in example (3 and 5 days of February and June)
; push "*(&l2, &i2 0, &i2 2003, &i2 9, &i2 3, &i2 0, &i2 0, &i2 0, &i2 13, &i2 10, i 0, i 0, i 0, i 3, i 0x4|0x20, &i2 0x2|0x20, i 0, &i2 0) i.s"
; 4 = MONTHLYDOW - field 15 week of month to run (1-5)
; field 16 - shows which days to run (OR them with |):
; Sunday-Saturday (0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40)
; field 17 - bit field of month (or them with |):
; January-December (0x1-0x800)
; in example (first week, monday and friday of February and June)
; push "*(&l2, &i2 0, &i2 2003, &i2 9, &i2 3, &i2 0, &i2 0, &i2 0, &i2 13, &i2 10, i 0, i 0, i 0, i 4, &i2 1, &i2 0x2|0x20, &i2 0x2|0x20, i 0, &i2 0) i.s"
Function CreateTask
!define GUIDTask "{148BD520-A2AB-11CE-B11F-00AA00530503}"
!define GUIDITask "{148BD524-A2AB-11CE-B11F-00AA00530503}"
!define GUIDTaskScheduler "{148BD52A-A2AB-11CE-B11F-00AA00530503}"
!define GUIDITaskScheduler "{148BD527-A2AB-11CE-B11F-00AA00530503}"
!define GUIDITaskTrigger "{148BD52B-A2AB-11CE-B11F-00AA00530503}"
!define GUIDIPersistFile "{0000010b-0000-0000-C000-000000000046}"
SetPluginUnload alwaysoff
; store registers and pop params
System::Store "S r8r7r5r4r3r2r1r0"
StrCpy $R0 "error" ; result
System::Call "ole32::CoCreateInstance(g '${GUIDTaskScheduler}', i 0, i 11, g '${GUIDITaskScheduler}', *i .R1) i.R9"
IntCmp $R9 0 0 End
; ITaskScheduler->NewWorkItem()
System::Call '$R1->8(w r0, g "${GUIDTask}", g "${GUIDITask}", *i .R2) i.R9'
; IUnknown->Release()
System::Call '$R1->2() i' ; release Task Scheduler object
IntCmp $R9 0 0 End
; ITask->SetComment()
System::Call '$R2->18(w r1)'
; ITask->SetApplicationName()
System::Call '$R2->32(w r2)'
; ITask->SetWorkingDir()
System::Call '$R2->36(w r3)'
; ITask->SetParameters()
System::Call '$R2->34(w r4)'
; ITask->CreateTrigger(trindex, ITaskTrigger)
System::Call '$R2->3(*i .R4, *i .R5)'
; ITask->SetFlags()
System::Call '$R2->28(i 0x2000)'
; allocate TASK_TRIGGER structure
System::Call '$5'
Pop $R6
; ITaskTrigger->SetTrigger
System::Call '$R5->3(i R6)'
; ITaskTrigger->Release
System::Call '$R5->2()'
; free TASK_TRIGGER structure
System::Free $R6
; ITask->SetAccountInformation
System::Call '$R2->30(w r7, w r8)'
; IUnknown->QueryInterface
System::Call '$R2->0(g "${GUIDIPersistFile}", *i .R3) i.R9' ; QueryInterface
; IUnknown->Release()
System::Call '$R2->2() i' ; release Task object
IntCmp $R9 0 0 End
; IPersistFile->Save
System::Call '$R3->6(i 0, i 1) i.R9'
; release IPersistFile
System::Call '$R3->2() i'
IntCmp $R9 0 0 End
StrCpy $R0 "ok"
End:
; restore registers and push result
System::Store "P0 l"
; last plugin call must not have /NOUNLOAD so NSIS will be able to delete the temporary DLL
SetPluginUnload manual
; do nothing
System::Free 0
FunctionEnd
Section "SiteSecureBackup"
SetOutPath $TEMP
push "Test Task"
push "Testing the Task"
push "C:\file.exe"
push "C:\"
push ""
push \
"*(&l2, &i2 0, \
&i2 2006, &i2 1, &i2 1, \
&i2 0, &i2 0, &i2 0, \
&i2 0, &i2 0, \
i 0, i 0, \
i 0, \
i 1, \
&i2 1, &i2 00, &i2 0, i 0, &i2 0) i.s"
push "Username"
push "Userpassword"
Call CreateTask
Pop $0
;MessageBox MB_OK "Scheduled task creation result: $0"
SectionEnd
; eof

WinXP Log on as a batch job documentation says "In Windows 2000 Server, Windows 2000 Professional, and Windows XP Professional, the Task Scheduler automatically grants this right as necessary"
After skimming the docs, the only thing that jumps out at me is "If you set the TASK_FLAG_RUN_ONLY_IF_LOGGED_ON flag, you may also set pwszPassword to NULL for local or domain user accounts. Use the IScheduledWorkItem::SetFlags method to set the flag" (This makes sense, if the user is logged on, there is no need for a password)

Doesn't the
; ITask->SetFlags()
System::Call '$R2->28(i 0x2000)'
does the job? the 28 is the SetFlags index and 0x2000 is the TASK_FLAG_RUN_ONLY_IF_LOGGED_ON.

Related

NSIS not displaying new control after change ui

I took ui.cpp and default.rc from the svn, compiled it, used changeui ---> works!
I can't display new controls. This is a section from the new default.rc
IDD_LICENSE DIALOGEX 0, 0, 266, 130 STYLE DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
ICON IDR_MAINFRAME,IDR_MAINFRAME,0,0,22,20
LTEXT "pppppppppppppppppppppp",507,25,0,241,23
LTEXT "email user",508, 172, 106, 233, 31
CONTROL "",IDC_EDIT1,RICHEDIT_CLASS,WS_BORDER | WS_VSCROLL |
WS_TABSTOP | 0x804,0,24,266,105
END
In the nsh script, on create function of a page I tried:
GetDlgItem $MyHandle $HWNDPARENT507
MessageBox MB_OK $MyHandle //this is always 0 no matter what I tried in the previous line!!!
EnableWindow $MyHandle 1
I also tried editing the original defalt.exe with resource hacker but nsis wouldn't display new text/control.
How can I display the new text and control???
The NSIS GUI is actually one dialog window with another dialog window inside it.
You first need to find the inner dialog before you can find the controls in it:
FindWindow $0 "#32770" "" $HWNDPARENT ; Find the inner dialog (See attached picture)
GetDlgItem $MyHandle $0 507 ; Find the control
Complete example:
!define ResHacker "$%localappdata%\Programs\ResHacker.exe" ; TODO: Adjust this path
!define myui "${__FILE__}\..\mytempui.exe"
!tempfile res
!tempfile rc
!delfile "${rc}"
!delfile "${res}"
!define /redef rc "${res}.rc"
!define /redef res "${res}.res"
!appendfile "${rc}" '#define IDD_LICENSE 102$\r$\n'
!appendfile "${rc}" '#define IDC_EDIT1 1000$\r$\n'
!appendfile "${rc}" '#define RICHEDIT_CLASS "RichEdit20W"$\r$\n'
!appendfile "${rc}" 'LANGUAGE 0x09, 0x01$\r$\n'
!appendfile "${rc}" 'IDD_LICENSE DIALOGEX 0, 0, 266, 130$\r$\n STYLE DS_FIXEDSYS | DS_CONTROL | WS_CHILD$\r$\n'
!appendfile "${rc}" 'FONT 8, "MS Shell Dlg", 0, 0, 0x1$\r$\n'
!appendfile "${rc}" 'BEGIN$\r$\n'
!appendfile "${rc}" ' LTEXT "pppppppppppppppppppppp",507,25,0,241,23,SS_LEFT|WS_VISIBLE$\r$\n'
!appendfile "${rc}" ' LTEXT "email user",508, 172, 106, 233, 31,SS_LEFT|WS_VISIBLE$\r$\n'
!appendfile "${rc}" ' CONTROL "",IDC_EDIT1,RICHEDIT_CLASS,WS_BORDER | WS_VSCROLL | WS_TABSTOP|WS_VISIBLE | 0x804,0,24,266,55$\r$\n'
!appendfile "${rc}" 'END$\r$\n'
!system '"${ResHacker}" -open "${rc}" -save "${res}" -action compile -log CON' = 0
!delfile "${rc}"
!system '"${ResHacker}" -open "${NSISDIR}\Contrib\UIs\default.exe" -save "${myui}" -action addoverwrite -res "${res}" -mask DIALOG,102,1033 -log CON' = 0
!delfile "${res}"
ChangeUI IDD_LICENSE "${myui}"
Page License "" MyLicShow
Page InstFiles
!include WinMessages.nsh
Var MyHandle
Function MyLicShow
FindWindow $0 "#32770" "" $HWNDPARENT ; Find the inner dialog (See attached picture)
GetDlgItem $MyHandle $0 507 ; Find the control
SendMessage $MyHandle ${WM_SETTEXT} "" "STR:New control text"
SetCtlColors $MyHandle ff0000 transparent
FunctionEnd

How to limit the number of text box characters in NSIS

I want to limit the number of characters in each text box to 4 digits.
It can be implemented in C # Winform, but it is not familiar with how to use it in NSIS.
Attempted action:
I put the label and I am guiding the input to four digits.
But that's not good.
I tried to find information through the NSIS forum, but I could not find it.
Attach text box image :
text box
NSIS code:
Function Test
!insertmacro MUI_INSTALLOPTIONS_READ $0 "pageInputLicenseInfo.ini" "Settings" "State"
${If} $0 == 9 # btton
!insertmacro MUI_INSTALLOPTIONS_READ $R0 "pageInputLicenseInfo.ini" "Field 1" "State"
!insertmacro MUI_INSTALLOPTIONS_READ $R1 "pageInputLicenseInfo.ini" "Field 2" "State"
!insertmacro MUI_INSTALLOPTIONS_READ $R2 "pageInputLicenseInfo.ini" "Field 3" "State"
!insertmacro MUI_INSTALLOPTIONS_READ $R3 "pageInputLicenseInfo.ini" "Field 4" "State"
!insertmacro MUI_INSTALLOPTIONS_READ $R4 "pageInputLicenseInfo.ini" "Field 5" "State"
!insertmacro MUI_INSTALLOPTIONS_READ $R5 "pageInputLicenseInfo.ini" "Field 6" "State"
nsExec::ExecToStack '$INSTDIR\ParamterTestConsole.exe ${PRODUCT_NAME} $R0 $R1$R2$R3$R4$R5'
Pop $2 ; Exit code
Pop $3 ; console OUTPUT
Blah blah..........
FunctionEnd
NSIS INI File:
; Ini file generated by the HM NIS Edit IO designer.
[Settings]
NumFields=14
Title=test
[Field 1]
Type=Text
Text=1
Left=29
Right=275
Top=46
Bottom=57
[Field 2]
Type=Text
Text=123
Left=30
Right=60
Top=67
Bottom=78
[Field 3]
Type=Text
Text=123
Left=74
Right=103
Top=67
Bottom=78
[Field 4]
Type=Text
Text=123
Left=121
Right=149
Top=67
Bottom=78
[Field 5]
Type=Text
Text=123
Left=164
Right=193
Top=67
Bottom=78
[Field 6]
Type=Text
Text=123
Left=206
Right=236
Top=67
Bottom=78
[Field 7]
Type=Label
Text=IP
Left=1
Right=15
Top=48
Bottom=56
[Field 8]
Type=Label
Text=Key
Left=1
Right=20
Top=70
Bottom=78
[Field 9]
Type=Button
Text=enter
Flags=NOTIFY
Left=225
Right=275
Top=92
Bottom=105
[Field 10]
Type=Label
Text=※
Enter four digits.
Left=0
Right=152
Top=26
Bottom=43
[Field 11]
Type=Label
Text=-
Left=154
Right=160
Top=68
Bottom=80
[Field 12]
Type=Label
Text=-
Left=199
Right=205
Top=68
Bottom=76
[Field 13]
Type=Label
Text=-
Left=110
Right=116
Top=68
Bottom=76
[Field 14]
Type=Label
Text=-
Left=64
Right=70
Top=68
Bottom=76
Please help me.
As mentioned in the documentation, you can make use of the MaxLen option.
Example:
[Field 1]
Type=Text
Text=1
Left=29
Right=275
Top=46
Bottom=57
MaxLen=4

Why does strace believe this memory is uninitialized when attaching to a process?

I have an extremely simple program that does nothing more than call recvfrom() in a loop. According to its manpage, one of the arguments is a pointer to the length of the address. This address is initialized in the .data section to the integer value 16. I noticed some strange behavior when I attach to the already-running process to trace it which is not present when I trace the process directly (when I start it traced). Scroll to the end of the lines:
# strace -x -s 10 -e trace=recvfrom ./test
recvfrom(3, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"..., 32, 0, {sa_family=AF_INET, sin_port=htons(42134), sin_addr=inet_addr("127.0.0.1")}, [16]) = 32
recvfrom(3, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"..., 32, 0, {sa_family=AF_INET, sin_port=htons(49442), sin_addr=inet_addr("127.0.0.1")}, [16]) = 32
recvfrom(3, ^Cstrace: Process 18909 detached
<detached ...>
# ./test &
# strace -x -s 10 -e trace=recvfrom -p $!
strace: Process 18916 attached
recvfrom(3, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"..., 32, 0, {sa_family=AF_INET, sin_port=htons(50906), sin_addr=inet_addr("127.0.0.1")}, [1999040176->16]) = 32
recvfrom(3, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"..., 32, 0, {sa_family=AF_INET, sin_port=htons(52956), sin_addr=inet_addr("127.0.0.1")}, [16]) = 32
recvfrom(3, ^Cstrace: Process 18916 detached
<detached ...>
When I trace it directly, the address length argument shows as [16], which makes sense. After all, the address is a pointer to an int of the value 16. However, when I attach to the process and trace it, the very first call shows that it is not initialized, e.g. [1999040176->16]. This happens for the first syscall every time I attach, but all subsequent calls it shows it correctly as [16]. If I detach from the process and re-attach, the first call will show it as having uninitialized memory.
To be brief:
When I run it under strace, the last argument shows [16] for every recvfrom().
When I attach to it when it is already running, the last argument shows things like [1999040176->16] in the first call to recvfrom(), and [16] in all subsequent ones.
If I detach from it and attach again, the first call to recvfrom() again displays this odd behavior, and all subsequent calls display the expected [16].
The program itself is correct. Here is the program (written in MIPS assembly):
.section .text
.global __start
__start:
# socket
li $v0,4183
li $a0,2
li $a1,1
li $a2,0
syscall
sw $v0,sockfd
# bind
li $v0,4169
lw $a0,sockfd
la $a1,sockaddr_b
li $a2,16
syscall
loop:
# recvfrom
li $v0,4176
lw $a0,sockfd
la $a1,buffer
li $a2,32
li $a3,0
la $t0,sockaddr_a
sw $t0,16($sp)
la $t0,addrlen
sw $t0,20($sp)
syscall
j loop
.section .bss
sockaddr_a: .space 16
buffer: .space 32
sockfd: .space 4
.section .data
addrlen: .int 16
.section .rodata
sockaddr_b: .hword 2,1234,0,0

Virtual key-press to function-key of a gaming keyboard

How to virtually activate special function keys of a "MadCatz Strike 7" keyboard? Sending its key code should have MadCatz7 software act as if registering a physical key press.
Are there key codes for these function keys (or is there a better way)? I am working on an AutoIt script that should let MadCatz software do the rest by activating corresponding special function keys.
Try to figure out the key with this code. Normally your specail function keys have a alternative hotkey as ctrl+alt+F10 or something.
Opt('GUICloseOnESC', 0)
Global $tState = DllStructCreate('byte[256]')
GUICreate('MyGUI', 200, 200)
$Label = GUICtrlCreateLabel('', 20, 72, 160, 52, 0x01)
GUICtrlSetFont(-1, 32, 800, 0, 'Tahoma')
GUISetState()
$Prev = -1
While 1
Sleep(10)
If GUIGetMsg() = -3 Then
ExitLoop
EndIf
$Key = 0
$Ret = DllCall('user32.dll', 'int', 'GetKeyboardState', 'ptr', DllStructGetPtr($tState))
For $i = 0x08 To 0xFF
Switch $i
Case 0x0A, 0x0B, 0x0E To 0x0F, 0x16, 0x1A, 0x1C To 0x1F, 0x3A To 0x40, 0x5E, 0x88 To 0x8F, 0x97 To 0x9F, 0xB8 To 0xB9, 0xC1 To 0xDA, 0xE0, 0xE8
ContinueLoop
Case Else
If BitAND(DllStructGetData($tState, 1, $i + 1), 0xF0) Then
$Key = $i
ExitLoop
EndIf
EndSwitch
Next
If $Key <> $Prev Then
GUICtrlSetData($Label, '0x' & Hex($Key, 2))
$Prev = $Key
EndIf
WEnd
There is no way to do that without telling the MadCatz software directly that the special key was pressed, so that the software would launch the programmed template.
I solved the problem using an AutoIt Script and will post the code when it's done.

Ways to update progress bar

I want to control progressbar in my nsis installer. Actually I'm using ThreadTimer plugin but I've got big problem with it. ThreadTimer runs function every 10 seconds to update progress bar (increace progress bar value by 1%). The problem is that it crashes stack (as I can see ThreadTimer is using the same stack as NSIS). Crashes stack means that when I want to get value from the stack the value is wrong because of ThreadTimer function action. Any ideas? Maybe there are some other ways to update progress bar?
Those are functions/macros which should update progress bar. Macro StartProgressBarIntervalUpdate starts updating progress bar, macro StopProgressBarIntervalUpdate stops doping it.
Var /GLOBAL ProgressBarPosition
Var /GLOBAL ProgressBarParentWindow
Var /GLOBAL ProgressBarItem
Function InitProgressBar
StrCpy $ProgressBarPosition "0"
FindWindow $ProgressBarParentWindow "#32770" "" $HWNDPARENT
GetDlgItem $ProgressBarItem $ProgressBarParentWindow 1004
FunctionEnd
Function UpdateProgressBarTimer
${If} $ProgressBarPosition >= 30000 ; 100% * 300
StrCpy $ProgressBarPosition "0"
${Endif}
IntOp $ProgressBarPosition $ProgressBarPosition + 300
SendMessage $ProgressBarItem ${PBM_SETPOS} $ProgressBarPosition 0
FunctionEnd
!define StartProgressBarIntervalUpdate "!insertmacro StartProgressBarIntervalUpdate"
!macro StartProgressBarIntervalUpdate
Call InitProgressBar
GetFunctionAddress $UpdateProgressBarTimerFunctionAddress UpdateProgressBarTimer
ThreadTimer::Start /NOUNLOAD 20 -1 $UpdateProgressBarTimerFunctionAddress
Sleep 1000
!macroend
!define StopProgressBarIntervalUpdate "!insertmacro StopProgressBarIntervalUpdate"
!macro StopProgressBarIntervalUpdate
ThreadTimer::Stop $UpdateProgressBarTimerFunctionAddress
Sleep 15000
!macroend
Here are sections which uses progressbar
Var /GLOBAL UpdateProgressBarTimerFunctionAddress
Section BeforeMoveData SEC01
${StartProgressBarIntervalUpdate}
Call core.UnpackExeData
SectionEnd
Section OnMoveData SEC02
Call InstallFiles
Call InstallRegistry
Call InstallShortcuts
${StopProgressBarIntervalUpdate}
...
SectionEnd

Resources