*!* ServiceInstall() Local m.llRetVal As Boolean m.llRetVal = FALSE If This._OpenManager() = TRUE Then m.lnManagerHandle = This._ManagerHandle m.lcServiceName = This.ServiceName + NULCHAR m.lcDisplayName = This.ServiceDisplayName + NULCHAR m.lnDesiredAccess = SERVICE_ALL_ACCESS m.lnServiceType = SERVICE_WIN32_OWN_PROCESS If This.ServiceInteractive = TRUE Then m.lnServiceType = m.lnServiceType + SERVICE_INTERACTIVE_PROCESS Endif m.lnStartType = This.ServiceStartType m.lnErrorControl = SERVICE_ERROR_NORMAL m.lcBinaryPathName = Lower(Getenv("windir")) + "\system32\srvany.exe" + NULCHAR m.lcLoadOrderGroup = Null m.lcTagId = Null m.lcDependencies = Null If This.ServiceUseSystemAccount = TRUE Then m.lcServiceStartName = Null m.lcPassword = Null Else m.lcServiceStartName = This.ServiceAccount + NULCHAR m.lcPassword = This.ServicePassword + NULCHAR Endif This._ServiceHandle = CreateService( ; m.lnManagerHandle, ; m.lcServiceName, ; m.lcDisplayName,; m.lnDesiredAccess, ; m.lnServiceType, ; m.lnStartType, ; m.lnErrorControl,; m.lcBinaryPathName, ; m.lcLoadOrderGroup, ; m.lcTagId, ; m.lcDependencies, ; m.lcServiceStartName, ; m.lcPassword) If This._ServiceHandle <> 0 Then m.llRetVal = TRUE This._SetServiceDescription() This._AddRegEntries() Else This._GetLastError() Endif This._CloseHandles() Endif Return m.llRetVal **************************************************************************** *!* SetServiceDescription() If This._OpenService() = TRUE m.lnService = This._ServiceHandle m.lnInfoLevel = SERVICE_CONFIG_DESCRIPTION m.lcInfo = This.ServiceDescription + NULCHAR m.lnHeap = GetProcessHeap() m.lnLen = Len(m.lcInfo) *!* Allocate memory to hold m.lcInfo string: m.lnInfo = HeapAlloc(m.lnHeap, HEAP_ZERO_MEMORY, m.lnLen) *!* If memory allocation succeeded: If m.lnInfo <> 0 Then *!* Copy lcInfo string to allocated memory Sys(2600, m.lnInfo, m.lnLen, m.lcInfo) ChangeServiceConfig2(m.lnService, m.lnInfoLevel, @m.lnInfo) *!* Release allocated memory HeapFree(m.lnHeap, 0, m.lnInfo) Endif Endif **************************************************************************** *!* _AddRegEntries() Local ; m.lcServiceAppDirectory As String, ; m.lcServiceApplication As String This.oRegistry.ctlKey = "HKEY_LOCAL_MACHINE" This.oRegistry.ctlSubKey = "SYSTEM\CurrentControlSet\Services\" + This.ServiceName + "\Parameters" m.lcServiceAppDirectory = This.ServiceAppDirectory This.oRegistry.ctlValueSet("AppDirectory", m.lcServiceAppDirectory, REG_SZ) If Not Empty(This.ServiceAppEnvironment) Then This.oRegistry.ctlValueSet("AppEnvironment", This.ServiceAppEnvironment, REG_MULTI_SZ) Endif m.lcServiceApplication = This.ServiceApplication This.oRegistry.ctlValueSet("Application", m.lcServiceApplication, REG_SZ) If Not Empty(This.ServiceAppParameters) Then This.oRegistry.ctlValueSet("AppParameters", This.ServiceAppParameters, REG_SZ) Endif ****************************************************************************As you can see. I have added a parameter that will be passed to the exe: This.ServiceAppParameters, that has a value of "-service"
If Upper(Transform(m.param1)) = "-SERVICE" Then Do Form Service_Program NOSHOW Else Do Form Service_Control Endif Read EventsThis makes it possible to have only one exe that acts as the service and the monitoring/control/config program
*!* ServiceStatus() *!* typedef struct _SERVICE_STATUS { *!* DWORD dwServiceType; 4 *!* DWORD dwCurrentState; 4 *!* DWORD dwControlsAccepted; 4 *!* DWORD dwWin32ExitCode; 4 *!* DWORD dwServiceSpecificExitCode; 4 *!* DWORD dwCheckPoint; 4 *!* DWORD dwWaitHint; } SERVICE_STATUS, 4 *!* *LPSERVICE_STATUS; 28 *!* #DEFINE SERVICE_CONTINUE_PENDING 0x5 *!* #DEFINE SERVICE_PAUSE_PENDING 0x6 *!* #DEFINE SERVICE_PAUSED 0x7 *!* #DEFINE SERVICE_RUNNING 0x4 *!* #DEFINE SERVICE_START_PENDING 0x2 *!* #DEFINE SERVICE_STOP_PENDING 0x3 *!* #DEFINE SERVICE_STOPPED 0x1 *!* #Define ERROR_ACCESS_DENIED 5 *!* #DEFINE ERROR_SERVICE_NOT_FOUND 1243 *!* #Define ERROR_INVALID_HANDLE 6 *!* #Define ERROR_INVALID_NAME 123 *!* #DEFINE ERROR_SERVICE_DOES_NOT_EXIST 1060 Local ; m.lnRetVal As Integer, ; m.lnApiRetVal As Integer, ; m.lnService As Integer, ; m.lcServiceStatus As String m.lnRetVal = 0 If This._OpenService() = TRUE m.lnService = This._ServiceHandle m.lcServiceStatus = Replicate(NULCHAR, 28) m.lnApiRetVal = QueryServiceStatus(m.lnService, @m.lcServiceStatus) If m.lnApiRetVal <> 0 Then m.lnRetVal = CToBin(Substr(m.lcServiceStatus, 5, 4), "4RS") Else This._GetLastError() Endif This._CloseHandles() Else m.lnRetVal = This.ServiceErrorCode Endif Return m.lnRetVal ********************************************************************* *!* ServiceStart() Local ; m.llRetVal As Boolean, ; m.lnApiRetVal As Integer m.llRetVal = FALSE If This._OpenService() = TRUE m.lnApiRetVal = StartService(This._ServiceHandle, 0, 0) If m.lnApiRetVal <> 0 Then m.llRetVal = TRUE Else This._GetLastError() Endif This._CloseHandles() Endif Return m.llRetVal ********************************************************************** *!* ServiceStop() *!* typedef struct _SERVICE_STATUS { *!* DWORD dwServiceType; 4 *!* DWORD dwCurrentState; 4 *!* DWORD dwControlsAccepted; 4 *!* DWORD dwWin32ExitCode; 4 *!* DWORD dwServiceSpecificExitCode; 4 *!* DWORD dwCheckPoint; 4 *!* DWORD dwWaitHint; } SERVICE_STATUS, 4 *!* *LPSERVICE_STATUS; 28 Local ; m.llRetVal As Boolean, ; m.lnApiRetVal As Integer, ; m.lnService As Integer, ; m.lnControl As Integer, ; m.lcServiceStatus As String m.llRetVal = FALSE If This._OpenService() = TRUE m.lnService = This._ServiceHandle m.lnControl = SERVICE_CONTROL_STOP m.lcServiceStatus = Replicate(NULCHAR, 28) m.lnApiRetVal = ControlService(m.lnService, m.lnControl, @m.lcServiceStatus) If m.lnApiRetVal <> 0 Then m.llRetVal = TRUE Else This._GetLastError() Endif This._CloseHandles() Endif Return m.llRetVal ***************************************************************************** *!* ServiceUninstall() *!* First try to stop service: If This.ServiceStatus() = SERVICE_RUNNING Then This.ServiceStop() Endif Local ; m.llRetVal As Boolean ; m.lnApiRetVal As Integer m.llRetVal = FALSE If This._OpenService() = TRUE m.lnApiRetVal = DeleteService(This._ServiceHandle) If m.lnApiRetVal <> 0 Then m.llRetVal = TRUE Else This._GetLastError() Endif This._CloseHandles() Endif Return m.llRetVal ***************************************************************************** *!* _CloseHandles() If This._ServiceHandle <> 0 Then CloseServiceHandle( This._ServiceHandle) This._ServiceHandle = 0 Endif If This._ManagerHandle <> 0 Then CloseServiceHandle(This._ManagerHandle) This._ManagerHandle = 0 Endif ***************************************************************************** *!* _DeclareDlls() Declare Integer ChangeServiceConfig In advapi32 ; Integer hService, ; Integer dwServiceType, ; Integer dwStartType, ; Integer dwErrorControl, ; String lpBinaryPathName, ; String lpLoadOrderGroup, ; String lpdwTagId, ; String lpDependencies, ; String lpServiceStartName, ; String lpPassword, ; String lpDisplayName Declare Integer ChangeServiceConfig2 In advapi32 ; Integer hService, ; Integer dwInfoLevel, ; Integer @lpInfo Declare Integer CloseServiceHandle In advapi32 ; Integer hSCObject Declare Integer ControlService In advapi32; Integer hService,; Integer dwControl,; String @lpServiceStatus Declare Integer CreateService In advapi32 ; Integer hSCManager,; String lpServiceName,; String lpDisplayName,; Integer dwDesiredAccess,; Integer dwServiceType,; Integer dwStartType,; Integer dwErrorControl,; String lpBinaryPathName,; String lpLoadOrderGroup,; String lpdwTagId,; String lpDependencies,; String lpServiceStartName,; String lpPassword Declare Integer DeleteService In advapi32 ; Integer hService Declare Integer FormatMessage In Win32api ; Integer dwFlags,; Integer lpSource,; Integer dwMessageId,; Integer dwLanguageId,; String @lpBuffer,; Integer nSize, ; Integer Arguments Declare Integer GetLastError In win32api Declare Integer GetModuleHandle In Win32api ; String lpModule Declare Integer GetProcessHeap In win32api Declare Integer HeapAlloc In win32api ; Integer hHeap, ; Integer dwFlags, ; Integer dwBytes Declare Integer HeapFree In win32api ; Integer hHeap, ; Integer dwFlags, ; Integer lpMem Declare Integer OpenSCManager In advapi32 ; String lpMachineName,; String lpDatabaseName,; Integer dwDesiredAccess Declare Integer OpenService In advapi32 ; Integer hSCManager,; String lpServiceName,; Integer dwDesiredAccess Declare Integer QueryServiceStatus In advapi32 ; Integer hService,; String @lpServiceStatus Declare Integer StartService In advapi32; Integer hService,; Integer dwNumServiceArgs,; Integer lpServiceArgVectors ***************************************************************** *!* #Define ERROR_ACCESS_DENIED 5 *!* #DEFINE ERROR_SERVICE_NOT_FOUND 1243 *!* #Define ERROR_INVALID_HANDLE 6 *!* #Define ERROR_INVALID_NAME 123 *!* #DEFINE ERROR_SERVICE_DOES_NOT_EXIST 1060 *!* _OpenService() Local ; m.llRetVal As Boolean, ; m.lnManagerHandle As String, ; m.lcServiceName As String, ; m.lnDesiredAccess As Integer m.llRetVal = FALSE If This._OpenManager() = TRUE Then If This._ServiceHandle = 0 Then m.lnManagerHandle = This._ManagerHandle m.lcServiceName = This.ServiceName + NULCHAR m.lnDesiredAccess = SERVICE_ALL_ACCESS This._ServiceHandle = OpenService(m.lnManagerHandle, m.lcServiceName, m.lnDesiredAccess) Endif If This._ServiceHandle <> 0 Then m.llRetVal = TRUE Else This._GetLastError() Endif Endif Return m.llRetVal ************************************************************************ *!* _OpenManager() Local ; m.llRetVal As Boolean, ; m.lcMachineName As String, ; m.lcDatabaseName As String, ; m.lnDesiredAccess As Integer m.llRetVal = FALSE If This._ManagerHandle = 0 Then m.lcMachineName = Null m.lcDatabaseName = Null m.lnDesiredAccess = SC_MANAGER_ALL_ACCESS This._ManagerHandle = OpenSCManager(m.lcMachineName, m.lcDatabaseName, m.lnDesiredAccess) Endif If This._ManagerHandle <> 0 Then m.llRetVal = TRUE Else This._GetLastError() Endif Return m.llRetVal *******************************************************************This is not a complete, ready to use solution, but I think you may be able to get some good ideas from this code.