Talk:NSIS Service Lib: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
No edit summary
m (replaced <pre> with <highlight-nsis>)
 
(9 intermediate revisions by 5 users not shown)
Line 170: Line 170:
       StrCmp $6 0 lbl_done lbl_good
       StrCmp $6 0 lbl_done lbl_good
</highlight-nsis>
</highlight-nsis>
= Usage Examples =
* Stop a service whose name defined in macro
<pre>
!insertmacro SERVICE stop "${SERVICE_NAME}" ""
</pre>
* Create a service using macros for name; no newlines in the arguments
<pre>
!insertmacro SERVICE create "${SERVICE_NAME}" "path=$INSTDIR\x-win32.exe;autostart=1;interact=0;display=${SERVICE_DISPLAYNAME};description=${SERVICE_DESCRIPTION};"
</pre>
----
The code currently uses the t text type and a forced A function suffix, these don't match in the unicode build! All it takes is to remove the A suffix probably (And test that the code still works)
--[[User:Anders|Anders]] 16:46, 5 August 2010 (UTC)
----
----
To whomever maintains this code.
There is an easy way to get rid of the following define lines:
!ifndef UN
    !define UN ""
!endif
1) Just add another parameter (UN) to the SERVICE macro (line just below the above)...
CHANGE FROM:
!macro SERVICE ACTION NAME PARAM
TO:
!macro SERVICE ACTION NAME PARAM UN
This macro already uses the global value of the UN define; with the above change, it will use the local value.
2) Similarly, change the CALL_GETPARAM macro by also adding the (UN) parameter
CHANGE FROM:
!macro CALL_GETPARAM VAR NAME DEFAULT LABEL
TO:
!macro CALL_GETPARAM VAR NAME DEFAULT LABEL UN
3) Finally, change all the calls to the CALL_GETPARAM to add the (UN) parameter.  In the code, all those calls are made from the FUNC_SERVICE macro and this one already has the (UN) parameter but doesn't make any use of it!  There are 11 such calls in FUNC_SERVICE...  So for example, change the following call:
CHANGE FROM:
    !insertmacro CALL_GETPARAM $R1 "depend" "n" "lbl_depend"
TO:
    !insertmacro CALL_GETPARAM $R1 "depend" "n" "lbl_depend" "${UN}"
What those changes buy you is the ability to call this code from your installer either in regular install or in uninstall code (I believe the global DEFINE only lets you call this code in one of those context)!  For example, you can create and start a service in your install code using the following line:
!insertmacro SERVICE "create" <Service Name> "<params>" ""
!insertmacro SERVICE "start" <Service Name> "" ""
and you can stop and delete it in your uninstall code using the following line:
!insertmacro SERVICE "stop" <Service Name> "" "un."
!insertmacro SERVICE "delete" <Service Name> "" "un."
----
== Error in lbl_description ==
The line
strcmp $R7 "error" 0 lbl_descriptioncomplete
after label lbl_description is incorrect. ChangeServiceConfig2 returns a boolean. Thus you have to change it to
strcmp $R7 0 0 lbl_descriptioncomplete
Claus Henning ([[Special:Contributions/195.226.184.202|195.226.184.202]]) 12:33, 6 January 2011 (UTC)
== Added function: waitfor ==
I added a function to servicelib that waits for the service to reach a specific state. This function takes two parameters:
; status
: Can be ''running'', ''stopped'' or ''paused'' and specifies for which state the function should wait.
; timeout
: Specifies the maximum time to wait (in seconds). It the timeout is reached before the service enters the desired state, "timeout" is returned in ''$0''
<highlight-nsis>
    lbl_waitfor:
      !insertmacro CALL_GETPARAM $7 "status" "n" "lbl_done"  ; $7 is status as string
      StrCpy $8 ${SERVICE_RUNNING}  ; $8 is status as hex int
      StrCmp $7 "running" lbl_waitforstatus
      StrCpy $8 ${SERVICE_STOPPED}
      StrCmp $7 "stopped" lbl_waitforstatus
      StrCpy $8 ${SERVICE_PAUSED}
      StrCmp $7 "paused" lbl_waitforstatus
      StrCpy $0 "false"    ; illegal parameter "status"
      Goto lbl_done
      lbl_waitforstatus:
     
      !insertmacro CALL_GETPARAM $9 "timeout" "30" "lbl_waitfortimeout"  ; $9 is timeout in seconds
      lbl_waitfortimeout:
      Push $R1 ; SERVICE_STATUS structure
      StrCpy $0 "timeout"  ; in case we reach timeout
      lbl_waitforloop:
        Sleep 1000
        System::Call '*(i,i,i,i,i,i,i) i.R1'
        System::Call 'advapi32::QueryServiceStatus(i r5, i $R1) i'
        System::Call '*$R1(i, i .r6)'  ; $6 is now service status from QueryServiceStatus()
        System::Free $R1
        IntOp $9 $9 - 1
        StrCmp $9 0 lbl_done  ; timeout reached
        IntFmt $6 "0x%X" $6
        IntCmp $6 $8 0 lbl_waitforloop lbl_waitforloop
      Pop $R1
      Goto lbl_good
</highlight-nsis>
I hope you find this useful, however it's up to you to add it to the 'official' library. I just wanted to contribute my work because your library has helped me a lot!
--[[User:Christifuzius|Christifuzius]] 14:51, 10 January 2012 (UTC)

Latest revision as of 14:53, 10 January 2012

I noticed that I couldn't create an "interactive" service using your otherwise excellent lib...here's the fix!

Old code:


199      !insertmacro CALL_GETPARAM $R4 "interact" "0x10" "lbl_interact"
200        StrCpy $6 0x10
201        IntCmp $R4 0 +2
202        IntOp $R4 $6 | 0x100
203        StrCpy $R4 $6
204      lbl_interact:

New code:


199      !insertmacro CALL_GETPARAM $R4 "interact" "0x10" "lbl_interact"
200        StrCpy $6 0x10
201        IntCmp $R4 0 +2
202        IntOp  $6 $6 | 0x100
203        StrCpy $R4 $6
204      lbl_interact:

The (very slight) change is on line 202.

Thanks again,

Nathan Probst

You're correct. I've applied the fix, thanks.
--kichik 09:12, 5 January 2006 (PST)

There is a tiny bug that makes the original registers swapped after the function Old code:


321    Pop $5
322    Pop $6
323    Pop $7
324    Exch $0
325  !macroend

New code:


321    Pop $5
322    Pop $7
323    Pop $6
324    Exch $0
325  !macroend

--Charlesb 05:25, 22 February 2006 (PST)

Correct. I've applied the fix, thanks.
--kichik 10:34, 23 February 2006 (PST)

I use this patch to avoid some possible quote problem and that add a setdesc to set description (CreateService threat empty dependencies and empty password as NULLs) Also I used some Unicode versions instead of ANSI

--- C:\myprog\srv\PopupService\installer\mao.nsh	Thu Dec 14 15:27:41 2006
+++ C:\myprog\srv\PopupService\installer\servicelib.nsh	Thu Dec 14 15:25:31 2006
@@ -20,10 +20,11 @@
 ;                interact    - interact with the desktop ie. 1|0
 ;                depend      - service dependencies
 ;                user        - user that runs the service
 ;                password    - password of the above user
 ;                display     - display name in service's console
+;   setdesc     - set service description
 ;
 ;   delete     - deletes a windows service
 ;   start      - start a stopped windows service
 ;   stop       - stops a running windows service
 ;   pause      - pauses a running windows service
@@ -164,11 +165,11 @@
 
     StrCpy $0 "false"
     System::Call 'advapi32::OpenSCManagerA(n, n, i ${SC_MANAGER_ALL_ACCESS}) i.r4'
     IntCmp $4 0 lbl_done
     StrCmp $3 "create" lbl_create
-    System::Call 'advapi32::OpenServiceA(i r4, t r2, i ${SERVICE_ALL_ACCESS}) i.r5'
+    System::Call 'advapi32::OpenServiceW(i r4, w r2, i ${SERVICE_ALL_ACCESS}) i.r5'
     IntCmp $5 0 lbl_done
 
     lbl_select:
     StrCmp $3 "delete" lbl_delete
     StrCmp $3 "start" lbl_start
@@ -176,10 +177,11 @@
     StrCmp $3 "pause" lbl_pause
     StrCmp $3 "continue" lbl_continue
     StrCmp $3 "installed" lbl_installed
     StrCmp $3 "running" lbl_running
     StrCmp $3 "status" lbl_status
+    StrCmp $3 "setdesc" lbl_setdesc
     Goto lbl_done
 
     ; create service
     lbl_create:
       Push $R1 ;depend
@@ -187,25 +189,24 @@
       Push $R3 ;password
       Push $R4 ;interact
       Push $R5 ;autostart
       Push $R6 ;path
       Push $R7 ;display
+      Push $R8 ;user type
 
-      !insertmacro CALL_GETPARAM $R1 "depend" "n" "lbl_depend"
-        StrCpy $R1 't "$R1"'
+      !insertmacro CALL_GETPARAM $R1 "depend" "" "lbl_depend"
       lbl_depend:
-      StrCmp $R1 "n" 0 lbl_machine ;old name of depend param
-      !insertmacro CALL_GETPARAM $R1 "machine" "n" "lbl_machine"
-        StrCpy $R1 't "$R1"'
+      StrCmp $R1 "" 0 lbl_machine ;old name of depend param
+      !insertmacro CALL_GETPARAM $R1 "machine" "" "lbl_machine"
       lbl_machine:
 
+      StrCpy $R8 "n"
       !insertmacro CALL_GETPARAM $R2 "user" "n" "lbl_user"
-        StrCpy $R2 't "$R2"'
+        StrCpy $R8 "w R2"
       lbl_user:
 
-      !insertmacro CALL_GETPARAM $R3 "password" "n" "lbl_password"
-        StrCpy $R3 't "$R3"'
+      !insertmacro CALL_GETPARAM $R3 "password" "" "lbl_password"
       lbl_password:
 
       !insertmacro CALL_GETPARAM $R4 "interact" "0x10" "lbl_interact"
         StrCpy $6 0x10
         IntCmp $R4 0 +2
@@ -224,21 +225,32 @@
       lbl_path:
 
       !insertmacro CALL_GETPARAM $R7 "display" "$2" "lbl_display"
       lbl_display:
 
-      System::Call 'advapi32::CreateServiceA(i r4, t r2, t R7, i ${SERVICE_ALL_ACCESS}, \
-                                             i R4, i R5, i 0, t R6, n, n, $R1, $R2, $R3) i.r6'
+      System::Call 'advapi32::CreateServiceW(i r4, w r2, w R7, i ${SERVICE_ALL_ACCESS}, \
+                                             i R4, i R5, i 0, w R6, n, n, w R1, $R8, w R3) i.r6'
+      Pop $R8
       Pop $R7
       Pop $R6
       Pop $R5
       Pop $R4
       Pop $R3
       Pop $R2
       Pop $R1
       StrCmp $6 0 lbl_done lbl_good
 
+    ; set description
+    lbl_setdesc:
+      Push $R1
+      System::Call '*(w r1) i.R1'
+      StrCpy $6 '1'
+      System::Call 'advapi32::ChangeServiceConfig2W(i r5, i 1, i $R1) i.r6'
+      System::Free $R1
+      Pop $R1
+      StrCmp $6 0 lbl_done lbl_good
+
     ; delete service
     lbl_delete:
       System::Call 'advapi32::DeleteService(i r5) i.r6'
       StrCmp $6 0 lbl_done lbl_good

Usage Examples

  • Stop a service whose name defined in macro
!insertmacro SERVICE stop "${SERVICE_NAME}" ""
  • Create a service using macros for name; no newlines in the arguments
!insertmacro SERVICE create "${SERVICE_NAME}" "path=$INSTDIR\x-win32.exe;autostart=1;interact=0;display=${SERVICE_DISPLAYNAME};description=${SERVICE_DESCRIPTION};"



The code currently uses the t text type and a forced A function suffix, these don't match in the unicode build! All it takes is to remove the A suffix probably (And test that the code still works) --Anders 16:46, 5 August 2010 (UTC)



To whomever maintains this code.

There is an easy way to get rid of the following define lines:

!ifndef UN
   !define UN ""
!endif

1) Just add another parameter (UN) to the SERVICE macro (line just below the above)...

CHANGE FROM:

!macro SERVICE ACTION NAME PARAM

TO:

!macro SERVICE ACTION NAME PARAM UN

This macro already uses the global value of the UN define; with the above change, it will use the local value.

2) Similarly, change the CALL_GETPARAM macro by also adding the (UN) parameter

CHANGE FROM:

!macro CALL_GETPARAM VAR NAME DEFAULT LABEL

TO:

!macro CALL_GETPARAM VAR NAME DEFAULT LABEL UN

3) Finally, change all the calls to the CALL_GETPARAM to add the (UN) parameter. In the code, all those calls are made from the FUNC_SERVICE macro and this one already has the (UN) parameter but doesn't make any use of it! There are 11 such calls in FUNC_SERVICE... So for example, change the following call:

CHANGE FROM:

    !insertmacro CALL_GETPARAM $R1 "depend" "n" "lbl_depend"

TO:

    !insertmacro CALL_GETPARAM $R1 "depend" "n" "lbl_depend" "${UN}"

What those changes buy you is the ability to call this code from your installer either in regular install or in uninstall code (I believe the global DEFINE only lets you call this code in one of those context)! For example, you can create and start a service in your install code using the following line:

!insertmacro SERVICE "create" <Service Name> "<params>" ""

!insertmacro SERVICE "start" <Service Name> "" ""

and you can stop and delete it in your uninstall code using the following line:

!insertmacro SERVICE "stop" <Service Name> "" "un."

!insertmacro SERVICE "delete" <Service Name> "" "un."



Error in lbl_description

The line

strcmp $R7 "error" 0 lbl_descriptioncomplete

after label lbl_description is incorrect. ChangeServiceConfig2 returns a boolean. Thus you have to change it to

strcmp $R7 0 0 lbl_descriptioncomplete

Claus Henning (195.226.184.202) 12:33, 6 January 2011 (UTC)

Added function: waitfor

I added a function to servicelib that waits for the service to reach a specific state. This function takes two parameters:

status
Can be running, stopped or paused and specifies for which state the function should wait.
timeout
Specifies the maximum time to wait (in seconds). It the timeout is reached before the service enters the desired state, "timeout" is returned in $0
    lbl_waitfor:
      !insertmacro CALL_GETPARAM $7 "status" "n" "lbl_done"   ; $7 is status as string
      StrCpy $8 ${SERVICE_RUNNING}  ; $8 is status as hex int
      StrCmp $7 "running" lbl_waitforstatus
      StrCpy $8 ${SERVICE_STOPPED}
      StrCmp $7 "stopped" lbl_waitforstatus
      StrCpy $8 ${SERVICE_PAUSED}
      StrCmp $7 "paused" lbl_waitforstatus
      StrCpy $0 "false"     ; illegal parameter "status"
      Goto lbl_done
      lbl_waitforstatus:
 
      !insertmacro CALL_GETPARAM $9 "timeout" "30" "lbl_waitfortimeout"  ; $9 is timeout in seconds
      lbl_waitfortimeout:
 
      Push $R1 ; SERVICE_STATUS structure
      StrCpy $0 "timeout"  ; in case we reach timeout
      lbl_waitforloop:
        Sleep 1000
        System::Call '*(i,i,i,i,i,i,i) i.R1'
        System::Call 'advapi32::QueryServiceStatus(i r5, i $R1) i'
        System::Call '*$R1(i, i .r6)'   ; $6 is now service status from QueryServiceStatus()
        System::Free $R1
        IntOp $9 $9 - 1
        StrCmp $9 0 lbl_done   ; timeout reached
        IntFmt $6 "0x%X" $6
        IntCmp $6 $8 0 lbl_waitforloop lbl_waitforloop
      Pop $R1
      Goto lbl_good

I hope you find this useful, however it's up to you to add it to the 'official' library. I just wanted to contribute my work because your library has helped me a lot!

--Christifuzius 14:51, 10 January 2012 (UTC)