Announcement

Collapse
No announcement yet.

need help/guidance on Ben Clark's make program a service

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • need help/guidance on Ben Clark's make program a service

    Ben Clark posted a way to make a program a service.
    posted here
    User to user discussions about the PB/Win (formerly PB/DLL) product line. Discussion topics include PowerBASIC Forms, PowerGEN and PowerTree for Windows.


    to be brief i have a need to reboot when the system date changes.
    i found code to reboot here by Tonny Bjorn


    i am having a difficult time merging the code to get what i need.
    the program needs to be a service, because i do not want the users to kill my program through the task manager.

    if i can get an example of another program using this Clark's program that would probably help me.

    here is my program below

    my program is a gui.
    the program compares the date from the date against the date when the program started every 10 seconds, when it sees the date change, it forces a reboot.

    the program below as written will not reboot, as i have remarked that line of code out and i added a line of code that just says "rebooted" for testing purposes.



    A little background for the main purpose of this program. We run virtual machines with a windows guest operating system, and we use these virtual machines to let users access the internet freely. The other day, one employee's child came in and they let the child on the computer or maybe did not know it. We are like a lot places where you really do not want to put passwords everywhere but i am going to implement some. The problem arises when a virtual machine is not shutdown, but put into a saved state, sort of like hibernation. I would never ever hibernate a computer due to all the problems one can have, but this is different. So, when a user places the virtual machine in a saved state mode, the person can come up to the computer and restart the virtual computer from where it was left off, and i want our users to shutdown the virtual machines when they go home and if the virtual computer is in a saved state the next day, meaning anybody can use the virtual computer to go anywhere they want and not have to provide any passwords. it would serve me well to just have the virtual computer reboot by itself the next day if they bring the virtual computer out of a saved state. The virtual computers will have a password upon startup and each user will have their own password.

    Also i am going to implement a program, not this program that keeps track to where the users go on the internet and store that information somehow to be viewed by the management.

    if there are any suggestions to run this program from startup or any such ways where a non administrator user can remove this program, that will not work for me.

    i have preset the start date to be 03-23-2008 to make the program simulate the condition to where the program will want to reboot.

    Code:
    'program to reboot computer when the date changes
    'vmshutdown.bas
    'pbwin 8.04
    
    #COMPILE EXE
    #DIM ALL
    
    
    #INCLUDE "WIN32API.INC"
    %IDC_DIALOG1  =  101
    %IDC_LABEL1   = 1001
    %IDC_TEXTBOX1 = 1002
    %IDC_BUTTON1  = 1003
    
    GLOBAL glastbooted AS STRING
    GLOBAL hDlg AS DWORD
    
    
    
     SUB ShutDownNT(BYVAL DoWhat AS LONG)
        LOCAL OSVersion         AS OSVERSIONINFO
        LOCAL ProcessHandle     AS LONG
        LOCAL TokenHandle       AS LONG
        LOCAL TempLUID          AS LUID
        LOCAL TokenPrivilleges  AS TOKEN_PRIVILEGES
        LOCAL TKPDummy          AS TOKEN_PRIVILEGES
        LOCAL lReturnLength     AS LONG
    
        OSVersion.dwOSVersionInfoSize = SIZEOF(OSVersion)
    
        IF GetVersionEx(OSVersion) <> 0 THEN
    
            IF OSVersion.dwPlatformId = %VER_PLATFORM_WIN32_NT THEN
    
                ProcessHandle = GetCurrentProcess()
                CALL OpenProcessToken(ProcessHandle, %TOKEN_ADJUST_PRIVILEGES OR %TOKEN_QUERY, TokenHandle)
                CALL LookupPrivilegeValue("", "SeShutdownPrivilege", TempLUID)
    
                TokenPrivilleges.PrivilegeCount = 1
                TokenPrivilleges.Privileges(0).pLuid = TempLUID
                TokenPrivilleges.Privileges(0).Attributes = %SE_PRIVILEGE_ENABLED
    
                IF AdjustTokenPrivileges(TokenHandle, %FALSE, TokenPrivilleges, LEN(TKPDummy), TKPDummy, lReturnLength) THEN
    
                    ' Flags: %EWX_LOGOFF, %EWX_SHUTDOWN, %EWX_REBOOT, %EWX_FORCE, %EWX_POWEROFF
                    SELECT CASE DoWhat
    
                        CASE 1
    
                            ' Force Shut Down and ReBoot
                            CALL ExitWindowsEx(%EWX_FORCE OR %EWX_SHUTDOWN OR %EWX_REBOOT, 0)
    
                        CASE 2
    
                            ' Force Logoff user' Force Logoff user
                            CALL ExitWindowsEx(%EWX_FORCE OR %EWX_LOGOFF, 0)
    
                        CASE ELSE
    
                            ' Force Shut Down and Power Off
                            CALL ExitWindowsEx(%EWX_FORCE OR %EWX_SHUTDOWN OR %EWX_POWEROFF, 0)
    
                    END SELECT
    
                END IF
    
            END IF
    
        END IF
    
    END SUB
    
    
    FUNCTION TimerProc( BYVAL hDlg AS LONG, BYVAL Msg AS LONG, BYVAL EvntID AS LONG, BYVAL Time AS LONG ) AS LONG
    STATIC t AS LONG
    INCR T
    CONTROL SET TEXT hDlg, %IDC_LABEL1, STR$(31-T)+" seconds left"
    IF T=31 THEN  DIALOG END HDLG
    END FUNCTION 'TimerProc
    
    
    
    CALLBACK FUNCTION ShowDIALOG1Proc()
    STATIC hTimer AS LONG
    
        SELECT CASE AS LONG CBMSG
            CASE %WM_INITDIALOG
                ' Initialization handler
                hTimer = SetTimer( hDlg, 1, 1000, CODEPTR(TimerProc) )
    
    
             CASE %WM_DESTROY
                 IF hTimer THEN KillTimer hDlg, hTimer
    
            CASE %WM_NCACTIVATE
                STATIC hWndSaveFocus AS DWORD
                IF ISFALSE CBWPARAM THEN
                    ' Save control focus
                    hWndSaveFocus = GetFocus()
                ELSEIF hWndSaveFocus THEN
                    ' Restore control focus
                    SetFocus(hWndSaveFocus)
                    hWndSaveFocus = 0
                END IF
    
    
    
    
             CASE %WM_COMMAND
                ' Process control notifications
                 SELECT CASE AS LONG CBCTL
                   CASE %IDC_BUTTON1
                    DIALOG END HDLG
    
                 END SELECT
    
    
        END SELECT
    END FUNCTION
    
    
    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
        LOCAL lRslt  AS LONG
        LOCAL hFont1 AS DWORD
        LOCAL message AS STRING
    
        message="A forced shutdown is scheduled in 30 seconds."+$CRLF+_
                "This virtual machine needs restarting daily."+$CRLF+_
                "The last time it was booted was on "+glastbooted+"."
        DIALOG FONT "",10
        DIALOG NEW hParent, "", 70, 70, 165, 42,   %WS_POPUP OR _
            %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR _
            %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_LEFT _
            OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
        CONTROL ADD BUTTON,  hDlg, %IDC_BUTTON1, "Reboot Now", 102, 32, 50, 10
        CONTROL ADD LABEL,   hDlg, %IDC_LABEL1, "", 5, 32, 90, 10
        CONTROL ADD TEXTBOX, hDlg, %IDC_TEXTBOX1, message, 5, 5, 155, 25,%ES_MULTILINE
    
        DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
        FUNCTION = lRslt
    END FUNCTION
     FUNCTION PBMAIN()
    
         glastbooted=DATE$
         glastbooted="03-23-2008"
         CHECKTHEDATE:
         IF glastbooted=DATE$ THEN SLEEP 10000:GOTO checkthedate
    
        ShowDIALOG1 %HWND_DESKTOP
        MSGBOX "rebooted "
      '  CALL ShutDownNT(1)
    
    END FUNCTION
    Last edited by Paul Purvis; 24 Mar 2008, 02:02 PM.
    p purvis

  • #2
    the program compares the date from the date against the date when the program started every 10 seconds, when it sees the date change, it forces a reboot
    Search source code forum for "waitable timer object demo." Much more efficient. Assuming you get this running as a service your users will thank you.
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      thanks Michael,
      i will have to work on the suggestion, i looked it over and it was more than i can handle at the time, but i will surely look back at it in the future, because i am starting to have more programs that use pause states and really the program above is the second time i used a timer in a program.

      well i have achieved the end results of rebooting an os from a service and it will be ok while i am learning about services.
      i was not able to run my gui, which i wanted to in order to let the user see what was going on. i also tried to shell to the gui program using shellexecute, but that did not work as well as having the gui in the service.

      this program will serve a good purpose to reboot an os after midnight, or there can be changes made to shutdown the computer or logoff.

      here is the code and if this program is compared to the demo, then a person can learn how to make a service with the demo.
      very little changes needed to be made. look at lines with WINMAINX.
      thanks to Ben Clark,suppling this piece of code, this was not a hard task once i caught on, and the service ran proper all the way. It loaded the service, unloaded the service, stopped and started the service.

      Code:
      'pbwin 8.04
      'RBTMIDNT.BAS
      'PROGRAM TO RUN AS A SERVICE AND REBOOT THE OS SHORTLY AFTER MIDNIGHT OR
      '    OR IF OS DATE DOES NOT MATCH THE LAST REBOOTED DATE.
      '
      '------------------------------------------------------------------------------
      '
      '   NT SERVICE Template for 32-bit PB/DLL
      '   Copyright (c) 2001 by ClarkSoft.Com Inc
      '
      '  Let me know if you find any errors or have any suggestions
      '  [email protected]
      '
      '  DISCLAIMER:
      '  This code may be distributed on the condition that no fee is charged for
      '  such distribution with the exception of reasonable shipping and media
      '  charged. In addition, the code in this program may be incorporated
      '  into your own programs and the resulting programs may be distributed
      '  without payment of royalties.  The author of this code is not
      '  responsible for the success or failure of any resultant usage
      '  of the code giving within this file.  You are free to modify any code
      '  found within this file, but the author is not responsible for any changes
      '  to the base code file.
      '
      '-------------------------------------------------------------------------------
      
      #COMPILE EXE "RBTMIDNT.EXE"
      
      '$RESOURCE "RESOURCE.PBR" ' Embed the resources into the exe
      
      #DIM ALL ' Force ALL vars to have to be declared
      
      
      #INCLUDE "WIN32API.INC"
      ' My includes actually have the WinAPI includes in them.
      
      GLOBAL hWindow AS LONG ' You should set this in your WINMAINX to the handle
      ' of your main window.
      
      
      
      SUB ShutDownNT(BYVAL DoWhat AS LONG)
          LOCAL OSVersion         AS OSVERSIONINFO
          LOCAL ProcessHandle     AS LONG
          LOCAL TokenHandle       AS LONG
          LOCAL TempLUID          AS LUID
          LOCAL TokenPrivilleges  AS TOKEN_PRIVILEGES
          LOCAL TKPDummy          AS TOKEN_PRIVILEGES
          LOCAL lReturnLength     AS LONG
          OSVersion.dwOSVersionInfoSize = SIZEOF(OSVersion)
          IF GetVersionEx(OSVersion) <> 0 THEN
              IF OSVersion.dwPlatformId = %VER_PLATFORM_WIN32_NT THEN
                  ProcessHandle = GetCurrentProcess()
                  CALL OpenProcessToken(ProcessHandle, %TOKEN_ADJUST_PRIVILEGES OR %TOKEN_QUERY, TokenHandle)
                  CALL LookupPrivilegeValue("", "SeShutdownPrivilege", TempLUID)
                  TokenPrivilleges.PrivilegeCount = 1
                  TokenPrivilleges.Privileges(0).pLuid = TempLUID
                  TokenPrivilleges.Privileges(0).Attributes = %SE_PRIVILEGE_ENABLED
                  IF AdjustTokenPrivileges(TokenHandle, %FALSE, TokenPrivilleges, LEN(TKPDummy), TKPDummy, lReturnLength) THEN
                      ' Flags: %EWX_LOGOFF, %EWX_SHUTDOWN, %EWX_REBOOT, %EWX_FORCE, %EWX_POWEROFF
                      SELECT CASE DoWhat
                          CASE 1
                              ' Force Shut Down and ReBoot
                              CALL ExitWindowsEx(%EWX_FORCE OR %EWX_SHUTDOWN OR %EWX_REBOOT, 0)
                          CASE 2
                              ' Force Logoff user' Force Logoff user
                              CALL ExitWindowsEx(%EWX_FORCE OR %EWX_LOGOFF, 0)
                          CASE ELSE
                              ' Force Shut Down and Power Off
                              CALL ExitWindowsEx(%EWX_FORCE OR %EWX_SHUTDOWN OR %EWX_POWEROFF, 0)
                      END SELECT
                  END IF
              END IF
          END IF
      END SUB
      
      
      
      FUNCTION winmainx() AS LONG
      LOCAL lastbooted AS STRING
      SLEEP 60000
      lastbooted=DATE$
      CHECKTHEDATE:
      IF lastbooted=DATE$ THEN SLEEP 10000:GOTO checkthedate
      SLEEP 30000
      CALL ShutDownNT(1)
      
      END FUNCTION
      
      
      '#INCLUDE "MYINC.INC" ' This was the main Bas file for my executable
      
      ' ---------------------
      ' CONSTANT DECLARATIONS
      ' ---------------------
      %EVENTLOG_AUDIT_FAILURE = 16
      %EVENTLOG_AUDIT_SUCCESS = 8
      %EVENTLOG_ERROR_TYPE = 1
      %EVENTLOG_INFORMATION_TYPE = 4
      %EVENTLOG_SUCCESS = 0
      %EVENTLOG_WARNING_TYPE = 2
      
      ' This constant is used to set logging status.
      %EVENTLOG_LEVEL = %EVENTLOG_AUDIT_FAILURE + %EVENTLOG_AUDIT_SUCCESS + %EVENTLOG_ERROR_TYPE + _
      %EVENTLOG_INFORMATION_TYPE + %EVENTLOG_SUCCESS + %EVENTLOG_WARNING_TYPE
      %SERVICE_WIN32_OWN_PROCESS = &H10&
      %SERVICE_WIN32_SHARE_PROCESS = &H20&
      %SERVICE_WIN32 = %SERVICE_WIN32_OWN_PROCESS + %SERVICE_WIN32_SHARE_PROCESS
      %SERVICE_DEMAND_START = &H3&
      %SERVICE_ERROR_NORMAL = &H1&
      %WAIT_OBJECT_0 = 0&
      
      ' -------------------------
      ' FUNCTION/SUB DECLARATIONS
      ' -------------------------
      DECLARE FUNCTION Install() AS LONG
      DECLARE FUNCTION InitService() AS LONG
      DECLARE FUNCTION Uninstall() AS LONG
      DECLARE FUNCTION WinErrorMessage(BYVAL ErrNumber AS LONG) AS STRING
      DECLARE FUNCTION SendStatus(BYVAL CurrentStatus AS DWORD, BYVAL ExitCode AS DWORD, ServiceSpecificExitCode AS LONG, BYVAL Checkpoint AS DWORD, BYVAL WaitHint AS DWORD) AS LONG
      DECLARE FUNCTION ServiceThread(ID AS LONG) AS LONG
      DECLARE SUB Handler(BYVAL ControlValue AS DWORD)
      DECLARE SUB LogNTEvent(Message AS STRING, LogCode AS LONG)
      DECLARE SUB ServiceMain(BYVAL dwArgs AS DWORD, BYVAL lpszArgv AS DWORD)
      DECLARE SUB Terminate(ErrCode AS DWORD)
      DECLARE SUB StopService()
      DECLARE SUB PauseService()
      DECLARE SUB ResumeService()
      
      ' ----------------
      ' GLOBAL VARIABLES
      ' ----------------
      GLOBAL gascServiceName AS ASCIIZ * 8
      GLOBAL gascServiceDisplayName AS ASCIIZ * 256
      GLOBAL gdwdhStatus AS DWORD
      GLOBAL gdwdServiceState AS DWORD
      GLOBAL gdwdServiceStatus AS DWORD
      GLOBAL glnghInstance AS LONG
      GLOBAL glnghPrvInst AS LONG
      GLOBAL glnghTerminateEvent AS LONG
      GLOBAL glnghServiceThread AS LONG
      GLOBAL glngThreadResult AS LONG
      GLOBAL glngRunningService AS LONG
      GLOBAL glngPauseService AS LONG
      GLOBAL glngCmdShow AS LONG
      GLOBAL ptrCmdLine AS ASCIIZ PTR
      
      ' FUNCTION: WinMain
      FUNCTION WINMAIN(BYVAL hCurInst AS LONG, BYVAL hPrvInst AS LONG, BYVAL CmdLine AS ASCIIZ PTR, BYVAL CmdShow AS LONG) EXPORT AS LONG
      DIM Result AS LONG
      DIM CmdParm AS STRING
      DIM udtSTE AS SERVICE_TABLE_ENTRY
      
      ' Set the service name and display name here.
      gascServiceName = "RBTMIDNT SERVICE"
      gascServiceDisplayName = "Restart After Midnight"
      glngHInstance = hCurInst
      glnghPrvInst = hPrvInst
      glngCmdShow = CmdShow
      ptrCmdLine = CmdLine
      
      ' Get the Command Line parms
      CmdParm = UCASE$(EXTRACT$(@CmdLine, ANY " ,." + CHR$(9)))
      ' Get rid of any seperators
      CmdParm = REMOVE$(CmdParm, ANY "-\/")
      
      ' If the exe was executed with the Install parm then we just install and quit
      IF CmdParm = "INSTALL" THEN
      ' Install the service.
      Result = Install()
      IF ISFALSE Result THEN
      MSGBOX "An error occured while trying to install this service
      END IF
      ' If the exe was executed with the UnInstall parm then we just uninstall and quit
      ELSEIF CmdParm = "UNINSTALL" THEN
      ' Uninstall the service.
      Result = Uninstall()
      IF ISFALSE Result THEN
      MSGBOX "An error occured while trying to uninstall this service
      END IF
      
      ' No parms were given that we want so start up as service
      ' This should only happen when the service control manager starts us
      ELSE
      
      udtSTE.lpServiceName = VARPTR(gascServiceName)
      udtSTE.lpServiceProc = CODEPTR(ServiceMain)
      
      Result = StartServiceCtrlDispatcher(udtSTE)
      
      IF Result = 0 THEN
      ExitProcess GetLastError()
      END IF
      
      END IF
      
      FUNCTION = 0
      
      END FUNCTION
      
      ' Install the service into windows
      FUNCTION Install() AS LONG
      DIM dwdRet AS DWORD
      DIM lngDQEnd AS LONG
      DIM lngDQStart AS LONG
      DIM lngHSCManager AS LONG
      DIM lngHService AS LONG
      DIM ascEXE AS ASCIIZ * %MAX_PATH
      
      ON ERROR GOTO Error_Install
      
      ' Assume a failure for now.
      FUNCTION = %FALSE
      
      lngHSCManager = OpenSCManager(BYVAL %NULL, BYVAL %NULL, %SC_MANAGER_CREATE_SERVICE)
      
      IF lngHSCManager <> %NULL THEN
      ' OK, we have a handle to the SCM.
      ' Get the full EXE file path.
      dwdRet = GetModuleFileName(glngHInstance, ascEXE, %MAX_PATH)
      IF dwdRet <> 0 THEN
      ' Install the service.
      lngHService = CreateService(lngHSCManager, gascServiceName, gascServiceDisplayName, _
      %SERVICE_ALL_ACCESS, %SERVICE_WIN32_OWN_PROCESS, _
      %SERVICE_AUTO_START, %SERVICE_ERROR_NORMAL, _
      ascEXE, BYVAL %NULL, BYVAL %NULL, _
      BYVAL %NULL, BYVAL %NULL, BYVAL %NULL)
      ' Close any service handles.
      IF lngHService <> %NULL THEN
      ' Success!
      FUNCTION = %TRUE
      CloseServiceHandle lngHService
      END IF
      CloseServiceHandle lngHSCManager
      END IF
      END IF
      
      FUNCTION = %TRUE
      
      EXIT FUNCTION
      
      Error_Install:
      
      FUNCTION = -1& * ERR
      
      ON ERROR RESUME NEXT
      
      ' Close any service handles.
      IF lngHService <> %NULL THEN
      CALL CloseServiceHandle(lngHService)
      END IF
      
      IF lngHSCManager <> %NULL THEN
      CALL CloseServiceHandle(lngHSCManager)
      END IF
      
      END FUNCTION
      
      ' Unistall the service
      FUNCTION Uninstall() AS LONG
      DIM lngHSCManager AS LONG
      DIM lngHService AS LONG
      
      ON ERROR GOTO Error_Uninstall
      
      ' Assume a failure for now.
      FUNCTION = %FALSE
      
      lngHSCManager = OpenSCManager(BYVAL %NULL, BYVAL %NULL, %SC_MANAGER_CREATE_SERVICE)
      
      IF lngHSCManager <> %NULL THEN
      ' OK, we have a handle to the SCM.
      ' Now open our service.
      lngHService = OpenService(lngHSCManager, gascServiceName, %SERVICE_ALL_ACCESS)
      IF lngHService <> %NULL THEN
      ' Delete the service.
      IF DeleteService(lngHService) <> %NULL THEN
      ' Success!
      FUNCTION = %TRUE
      END IF
      CloseServiceHandle lngHService
      END IF
      CloseServiceHandle lngHSCManager
      END IF
      
      EXIT FUNCTION
      
      Error_Uninstall:
      
      FUNCTION = -1& * ERR
      
      ON ERROR RESUME NEXT
      
      ' Close any service handles.
      IF lngHService <> %NULL THEN
      CloseServiceHandle lngHService
      END IF
      
      IF lngHSCManager <> %NULL THEN
      CloseServiceHandle lngHSCManager
      END IF
      
      END FUNCTION
      
      ' Start up the service
      FUNCTION InitService() AS LONG
      DIM lngRet AS LONG
      DIM ID AS LONG
      DIM udtSTE AS SERVICE_TABLE_ENTRY
      DIM lpThreadAttributes AS SECURITY_ATTRIBUTES
      
      ' Start the main thread for this service
      glnghServiceThread = CreateThread(lpThreadAttributes, 0, CODEPTR(ServiceThread), 0, 0, ID)
      
      ' Did the thread start OK
      IF glnghServiceThread = 0 THEN
      FUNCTION = %FALSE
      EXIT FUNCTION
      ELSE
      ' Set the global to running
      glngRunningService = %TRUE
      
      FUNCTION = %TRUE
      EXIT FUNCTION
      END IF
      
      END FUNCTION
      
      SUB PauseService()
      
      ' Set the global indicating that we are not paused
      glngPauseService = %TRUE
      
      ' Let er rip
      SuspendThread glnghServiceThread
      
      END SUB
      
      SUB ResumeService()
      
      ' Set the global indicating that we are not paused
      glngPauseService = %FALSE
      
      ' Let er rip
      ResumeThread glnghServiceThread
      
      END SUB
      
      SUB StopService()
      
      ' Set the global flag indicating that the service is not running
      glngRunningService = %FALSE
      
      ' Set the event so the service will stop
      SetEvent glnghTerminateEvent
      
      END SUB
      
      FUNCTION SendStatus(BYVAL CurrentStatus AS DWORD, BYVAL ExitCode AS DWORD, ServiceSpecificExitCode AS LONG, BYVAL Checkpoint AS DWORD, BYVAL WaitHint AS DWORD) AS LONG
      DIM udtSS AS SERVICE_STATUS
      
      ' Reset the global service status value.
      gdwdServiceStatus = CurrentStatus
      
      ' Setup the UDT.
      udtSS.dwServiceType = %SERVICE_WIN32_OWN_PROCESS
      udtSS.dwCurrentState = CurrentStatus
      
      ' If we are the process of starting, then don't accept control events
      IF CurrentStatus = %SERVICE_START_PENDING THEN
      udtSS.dwControlsAccepted = 0
      ELSE
      ' Take what was given
      udtSS.dwControlsAccepted = %SERVICE_ACCEPT_STOP + %SERVICE_ACCEPT_PAUSE_CONTINUE + %SERVICE_ACCEPT_SHUTDOWN
      END IF
      
      ' If a specific ServiceSpecificExitCode is defined, setup the Win32 exit code properly
      IF ServiceSpecificExitCode = 0 THEN
      udtSS.dwWin32ExitCode = ExitCode
      ELSE
      udtSS.dwWin32ExitCode = %ERROR_SERVICE_SPECIFIC_ERROR
      END IF
      
      ' Specific Exit Code
      udtSS.dwServiceSpecificExitCode = ServiceSpecificExitCode
      
      udtSS.dwCheckPoint = Checkpoint
      udtSS.dwWaitHint = WaitHint
      
      IF SetServiceStatus(gdwdHStatus, udtSS) = 0 THEN
      ' Something went wrong so stop the service
      StopService
      FUNCTION = %FALSE
      ELSE
      FUNCTION = %TRUE
      END IF
      
      END FUNCTION
      
      SUB ServiceMain(BYVAL dwArgs AS DWORD, BYVAL lpszArgv AS DWORD)
      LOCAL Result AS LONG
      LOCAL lpEventAttributes AS SECURITY_ATTRIBUTES
      
      ' Register with the SCM
      gdwdHStatus = RegisterServiceCtrlHandler(gascServiceName, CODEPTR(Handler))
      ' Did it work
      IF gdwdHStatus = 0 THEN
      ' No, so terminate
      Terminate GetLastError()
      EXIT SUB
      END IF
      
      ' Service has been registered and startup is pending
      IF ISFALSE SendStatus(%SERVICE_START_PENDING, %NO_ERROR, 0, 1, 5000) THEN
      Terminate GetLastError()
      EXIT SUB
      END IF
      
      ' Create the termination event
      glnghTerminateEvent = CreateEvent(lpEventAttributes, %TRUE, %FALSE, "")
      IF glnghTerminateEvent = 0 THEN
      Terminate GetLastError()
      EXIT SUB
      END IF
      
      ' Service startup is still pending
      IF ISFALSE SendStatus(%SERVICE_START_PENDING, %NO_ERROR, 0, 2, 1000) THEN
      Terminate GetLastError()
      EXIT SUB
      END IF
      
      ' Start the service
      Result = InitService()
      IF ISFALSE Result THEN
      ' Oops
      Terminate GetLastError()
      EXIT SUB
      END IF
      
      ' Service is now running
      IF ISFALSE SendStatus(%SERVICE_RUNNING, %NO_ERROR, 0, 0, 0) THEN
      Terminate GetLastError()
      EXIT SUB
      END IF
      
      ' Wait for the signal to end
      WaitForSingleObject glnghTerminateEvent, %INFINITE
      
      Terminate 0
      
      EXIT SUB
      
      END SUB
      
      SUB Terminate(ErrCode AS DWORD)
      
      ' If the Terminate Event has already been created then destroy it
      IF glnghTerminateEvent <> 0 THEN
      CloseHandle glnghTerminateEvent
      END IF
      
      IF gdwdHStatus <> 0 THEN
      ' Send a message to the SCM and tell them that we are stopping
      SendStatus %SERVICE_STOPPED, ErrCode, 0&, 0&, 0&
      END IF
      
      ' If the thread has started, then kill it
      IF glnghServiceThread <> 0 THEN
      ' Not normally here in a service
      ' However, this program was written as an executable first and converted into a service
      ' There is a global hWindow that is set in the WINMAINX when we start
      ' We need to destroy the window so the WINMAINX will come back to us
      ' Is it a valid window
      IF IsWindow(hWindow) THEN
      ' Yes so destroy it
      DestroyWindow hWindow
      ' This will cause the Message Loop in your WINMAINX to exit and return
      END IF
      
      ' Close the thread
      CloseHandle glnghServiceThread
      END IF
      
      END SUB
      
      SUB Handler(BYVAL ControlValue AS DWORD)
      ' This procedure (by its' name) handles all service requests.
      LOCAL Result AS LONG
      
      ON ERROR RESUME NEXT
      
      ' There is no Start option because the ServiceMain takes care of starting the service
      SELECT CASE ControlValue
      CASE %SERVICE_CONTROL_STOP
      ' Set the global Status
      gdwdServiceState = %SERVICE_STOP_PENDING
      
      ' Tell the SCM that we are stopping
      SendStatus %SERVICE_STOP_PENDING, %NO_ERROR, 0&, 1, 5000
      
      ' Stop the service
      StopService
      CASE %SERVICE_CONTROL_PAUSE
      ' Are we running and not paused
      IF (ISTRUE glngRunningService) AND (ISFALSE glngPauseService) THEN
      ' Tell the SCM that we are pausing
      SendStatus %SERVICE_PAUSE_PENDING, %NO_ERROR, 0, 1, 1000
      
      ' Pause it
      PauseService
      
      ' Set the current state
      gdwdServiceState = %SERVICE_PAUSED
      END IF
      CASE %SERVICE_CONTROL_CONTINUE
      ' Are we running and paused
      IF (ISTRUE glngRunningService) AND (ISTRUE glngPauseService) THEN
      ' Tell the SCM that we are un pausing
      SendStatus %SERVICE_CONTINUE_PENDING, %NO_ERROR, 0, 1, 1000
      
      ' Resume the service
      ResumeService
      
      ' Set the current state
      gdwdServiceState = %SERVICE_RUNNING
      END IF
      CASE %SERVICE_CONTROL_INTERROGATE
      ' Don't need to do anything
      ' We will send the current status below
      CASE %SERVICE_CONTROL_SHUTDOWN
      ' We don't do anything with a shutdown
      EXIT SUB
      END SELECT
      
      ' Tell the SCM the new status
      SendStatus gdwdServiceState, %NO_ERROR, 0, 0, 0
      
      END SUB
      
      FUNCTION ServiceThread(ID AS LONG) EXPORT AS LONG
      LOCAL Result AS LONG
      LOCAL Msg AS tagMsg
      
      ' Run until we are killed
      Result = WINMAINX()
      ' I had written a program and compiled it as an exe
      ' To make it a service, I just renamed the WINMAIN to WINMAINX and then
      ' call it like you see above
      
      END FUNCTION
      [
      Last edited by Paul Purvis; 24 Mar 2008, 08:10 PM.
      p purvis

      Comment


      • #4
        If you have FireFly, see- http://planetsquires.com/support/ind...3&topic=2227.0

        I've been doing all kinds of things lately. Been a while since I've played with the example posted. My Services now all properly log to the event log which includes a message resource in the EXE to not get the error in the event description...for some reason the message compiler isn't included in PB though, so you have to find it. They also add the Description field to the registry that adding the service misses and on uninstall stops the service if running and removes the extra registry entries too. I also handle the error many of the templates and even Microsoft Services don't if the exe is started by someone clicking the exe file and it warns the user of it being a service and how to install it and exits. I haven't had much luck with interactive services shutting down properly on Windows Shutdown/Restart, but non-interactive work fine.

        Also, there is an API call that shuts down with warning too much like when you install an application. Or you could show the timed shutdown, etc. There is a flag for message boxes to show from a non-interactive service too.
        Last edited by Roger Garstang; 24 Mar 2008, 09:59 PM.
        sigpic
        Mobile Solutions
        Sys Analyst and Development

        Comment


        • #5
          The MS message compiler was included with my Feb 2003 version of the Platform SDK. It also included a HLP file for the compiler. Of course, I cannot guarantee that the MC comes with all versions of the PSDK, but it's worth a look. It's been quite a while since I messed with using the MC in my PB programs, but if you need assistance with it, I think I can remember enough to help out, just ask.

          Comment


          • #6
            Thanks Clay,

            i have messenger turned off on all our computers, i may have turn it on and use this to send a notification.
            User to user discussions about the PB/Win (formerly PB/DLL) product line. Discussion topics include PowerBASIC Forms, PowerGEN and PowerTree for Windows.


            which raises a question, can a service undisable a service then start it, i am referring to messenger.

            i can use msgbox with like this below in a service.
            MSGBOX "a forced reboot in 30 seconds", %MB_SERVICE_NOTIFICATION, "powerbasic"

            but i belive it needs to be in its own thread, to allow program to continue on.

            i appreciate any help i can get, thanks.

            paul
            Last edited by Paul Purvis; 25 Mar 2008, 03:02 AM.
            p purvis

            Comment


            • #7
              I am sorry, I'd rather not attempt to give help on services themselves. I only did a little bit of work with them, a purely educational venture, nothing really for realworld production use. I did start out using them in production mode, but I ran into snags which I am sure occurred because of my naivete about them. For things concerning services, I prefer to refer folks to people who actually have experience/knowledge about them, such as Roger, et al.

              Comment


              • #8
                which raises a question, can a service undisable a service then start it, i am referring to messenger.
                There is no additional restriction other than any regular executable has (user rights), that would a service restrict from doing so.

                Comment


                • #9
                  placed updated code in the source code section




                  program now has a message to the user by creating a thread and using msgbox to display a message that os is going to reboot.
                  other small alterations made.

                  it still would be nice to find a way to spawn a program from a service, and in time i guess i will find that way.

                  paul
                  p purvis

                  Comment


                  • #10
                    program now has a message to the user by creating a thread and using msgbox to display a message that os is going to reboot.
                    other small alterations made.
                    Services that need to somehow interact with the user are typically split in two different applications:

                    - The service itself. Does its job and sits and listens for its controlling client.

                    - The "service controling client". Often implemented for sitting in the Sytray and signaling service states via changes of its icon. Full user interactable, communicating back and forth any user actions to the service

                    Typical client/server constellation.

                    Comment

                    Working...
                    X
                    😀
                    🥰
                    🤢
                    😎
                    😡
                    👍
                    👎