First commit with working windows service.
This commit is contained in:
@@ -0,0 +1,55 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"../../service"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var displayName = "Go Service Test2"
|
||||||
|
var ws = service.NewService("GoServiceTest2", displayName)
|
||||||
|
|
||||||
|
if len(os.Args) > 1 {
|
||||||
|
var err error
|
||||||
|
verb := os.Args[1]
|
||||||
|
switch verb {
|
||||||
|
case "install":
|
||||||
|
err = ws.Install()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to install: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("Service \"%s\" installed.\n", displayName)
|
||||||
|
case "remove":
|
||||||
|
err = ws.Remove()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to remove: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("Service \"%s\" removed.", displayName)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := ws.Run(func() error {
|
||||||
|
// start
|
||||||
|
go doWork()
|
||||||
|
ws.LogInfo("I'm Running!")
|
||||||
|
return nil
|
||||||
|
}, func() error {
|
||||||
|
// stop
|
||||||
|
stopWork()
|
||||||
|
ws.LogInfo("I'm Stopping!")
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ws.LogError(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doWork() {
|
||||||
|
|
||||||
|
}
|
||||||
|
func stopWork() {
|
||||||
|
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
Install() error
|
||||||
|
Remove() error
|
||||||
|
Run(onStart, onStop func() error) error
|
||||||
|
|
||||||
|
LogError(text string) error
|
||||||
|
LogWarning(text string) error
|
||||||
|
LogInfo(text string) error
|
||||||
|
}
|
||||||
@@ -0,0 +1,246 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
SERVICE_STATUS gSvcStatus;
|
||||||
|
SERVICE_STATUS_HANDLE gSvcStatusHandle;
|
||||||
|
HANDLE ghSvcStopEvent = NULL;
|
||||||
|
|
||||||
|
void SvcInstall(void);
|
||||||
|
void WINAPI SvcCtrlHandler( DWORD );
|
||||||
|
void WINAPI SvcMain( DWORD, LPTSTR * );
|
||||||
|
|
||||||
|
void ReportSvcStatus( DWORD, DWORD, DWORD );
|
||||||
|
|
||||||
|
static char *goServiceName;
|
||||||
|
|
||||||
|
int goSigStart = 0;
|
||||||
|
int goAckStart = 0;
|
||||||
|
HANDLE goWaitStart = NULL;
|
||||||
|
|
||||||
|
int goSigStop = 0;
|
||||||
|
int goAckStop = 0;
|
||||||
|
HANDLE goWaitStop = NULL;
|
||||||
|
|
||||||
|
int goSigError = 0;
|
||||||
|
char *errorText;
|
||||||
|
|
||||||
|
void
|
||||||
|
continueStart(int response) {
|
||||||
|
goSigStart = 0;
|
||||||
|
goAckStart = response;
|
||||||
|
SetEvent(goWaitStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
continueStop(int response) {
|
||||||
|
goSigStop = 0;
|
||||||
|
goAckStop = response;
|
||||||
|
SetEvent(goWaitStop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
signalError(char *text) {
|
||||||
|
errorText = text;
|
||||||
|
goSigError = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
initService(char *serviceName) {
|
||||||
|
if(!goServiceName) {
|
||||||
|
free(goServiceName);
|
||||||
|
}
|
||||||
|
goServiceName = serviceName;
|
||||||
|
SERVICE_TABLE_ENTRY DispatchTable[] = {
|
||||||
|
{ serviceName, (LPSERVICE_MAIN_FUNCTION) SvcMain },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
// This call returns when the service has stopped.
|
||||||
|
// The process should simply terminate when the call returns.
|
||||||
|
if (!StartServiceCtrlDispatcher( DispatchTable )) {
|
||||||
|
signalError("StartServiceCtrlDispatcher");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry point for the service
|
||||||
|
// dwArgc - Number of arguments in the lpszArgv array
|
||||||
|
// lpszArgv - Array of strings. The first string is the name of
|
||||||
|
// the service and subsequent strings are passed by the process
|
||||||
|
// that called the StartService function to start the service.
|
||||||
|
VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )
|
||||||
|
{
|
||||||
|
// Register the handler function for the service
|
||||||
|
|
||||||
|
gSvcStatusHandle = RegisterServiceCtrlHandler(
|
||||||
|
goServiceName,
|
||||||
|
SvcCtrlHandler);
|
||||||
|
|
||||||
|
if( !gSvcStatusHandle ) {
|
||||||
|
signalError("RegisterServiceCtrlHandler");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These SERVICE_STATUS members remain as set here
|
||||||
|
gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||||
|
gSvcStatus.dwServiceSpecificExitCode = 0;
|
||||||
|
|
||||||
|
// Report initial status to the SCM
|
||||||
|
ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );
|
||||||
|
|
||||||
|
goWaitStart = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
goWaitStop = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
|
||||||
|
// signal go to start
|
||||||
|
// wait for go to confirm
|
||||||
|
goSigStart = 1;
|
||||||
|
WaitForSingleObject(goWaitStart, INFINITE);
|
||||||
|
if(goAckStart != 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Declare and set any required variables.
|
||||||
|
// Be sure to periodically call ReportSvcStatus() with
|
||||||
|
// SERVICE_START_PENDING. If initialization fails, call
|
||||||
|
// ReportSvcStatus with SERVICE_STOPPED.
|
||||||
|
|
||||||
|
// Create an event. The control handler function, SvcCtrlHandler,
|
||||||
|
// signals this event when it receives the stop control code.
|
||||||
|
ghSvcStopEvent = CreateEvent(
|
||||||
|
NULL, // default security attributes
|
||||||
|
TRUE, // manual reset event
|
||||||
|
FALSE, // not signaled
|
||||||
|
NULL); // no name
|
||||||
|
|
||||||
|
if ( ghSvcStopEvent == NULL)
|
||||||
|
{
|
||||||
|
ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report running status when initialization is complete.
|
||||||
|
ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
|
||||||
|
WaitForSingleObject(ghSvcStopEvent, INFINITE);
|
||||||
|
|
||||||
|
// Signal service Stopped
|
||||||
|
ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the current service status and reports it to the SCM.
|
||||||
|
// dwCurrentState - The current state (see SERVICE_STATUS)
|
||||||
|
// dwWin32ExitCode - The system error code
|
||||||
|
// dwWaitHint - Estimated time for pending operation, in milliseconds
|
||||||
|
VOID ReportSvcStatus( DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) {
|
||||||
|
static DWORD dwCheckPoint = 1;
|
||||||
|
|
||||||
|
// Fill in the SERVICE_STATUS structure.
|
||||||
|
gSvcStatus.dwCurrentState = dwCurrentState;
|
||||||
|
gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
|
||||||
|
gSvcStatus.dwWaitHint = dwWaitHint;
|
||||||
|
|
||||||
|
if (dwCurrentState == SERVICE_START_PENDING) {
|
||||||
|
gSvcStatus.dwControlsAccepted = 0;
|
||||||
|
} else {
|
||||||
|
gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED) ) {
|
||||||
|
gSvcStatus.dwCheckPoint = 0;
|
||||||
|
} else {
|
||||||
|
gSvcStatus.dwCheckPoint = dwCheckPoint++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report the status of the service to the SCM.
|
||||||
|
SetServiceStatus( gSvcStatusHandle, &gSvcStatus );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by SCM whenever a control code is sent to the service
|
||||||
|
// using the ControlService function.
|
||||||
|
VOID WINAPI SvcCtrlHandler( DWORD dwCtrl ) {
|
||||||
|
// Handle the requested control code.
|
||||||
|
switch(dwCtrl) {
|
||||||
|
case SERVICE_CONTROL_STOP:
|
||||||
|
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
|
||||||
|
|
||||||
|
goSigStop = 1;
|
||||||
|
WaitForSingleObject(goWaitStop, INFINITE);
|
||||||
|
if(goAckStop != 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now signal on the initial thread to stop blocking.
|
||||||
|
SetEvent(ghSvcStopEvent);
|
||||||
|
return;
|
||||||
|
case SERVICE_CONTROL_INTERROGATE:
|
||||||
|
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Starts a windows service routine. Service must be registered first.
|
||||||
|
// Call blocks until an error occurs or the service stops. If onStart returns
|
||||||
|
// an error, service will not start. If onStop returns an error, the service will
|
||||||
|
// not stop.
|
||||||
|
func runService(serviceName string, onStart, onStop func() error) error {
|
||||||
|
// We alloc a c string here, but do not free it here
|
||||||
|
cname := C.CString(serviceName)
|
||||||
|
|
||||||
|
retErr := make(chan error, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
// Check C vars on timer.
|
||||||
|
ticker := time.NewTicker(time.Second * 1)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for _ = range ticker.C {
|
||||||
|
if C.goSigStart == 1 {
|
||||||
|
err := onStart()
|
||||||
|
if err != nil {
|
||||||
|
// An error was returned.
|
||||||
|
// Signal to NOT start the service.
|
||||||
|
C.continueStart(-1)
|
||||||
|
retErr <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
C.continueStart(1)
|
||||||
|
} else if C.goSigStop == 1 {
|
||||||
|
err := onStop()
|
||||||
|
if err != nil {
|
||||||
|
// An error was returned.
|
||||||
|
// Signal to NOT stop the service.
|
||||||
|
C.continueStop(-1)
|
||||||
|
retErr <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
C.continueStop(1)
|
||||||
|
retErr <- nil
|
||||||
|
} else if C.goSigError == 1 {
|
||||||
|
// Check for service errors.
|
||||||
|
errText := "SERVICE ERROR: "
|
||||||
|
if C.errorText != nil {
|
||||||
|
errText += C.GoString(C.errorText)
|
||||||
|
}
|
||||||
|
retErr <- errors.New(errText)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
C.initService(cname)
|
||||||
|
|
||||||
|
return <-retErr
|
||||||
|
}
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unicode/utf16"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewService(name, displayName string) Service {
|
||||||
|
return &windowsService {
|
||||||
|
name: name,
|
||||||
|
displayName: displayName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type windowsService struct {
|
||||||
|
name, displayName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *windowsService) Install() error {
|
||||||
|
pathToBinary, err := GetModuleFileName()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
scmManagerHandle, err := OpenSCManager()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer CloseServiceHandle(scmManagerHandle)
|
||||||
|
|
||||||
|
serviceHandle, err := CreateService(scmManagerHandle, ws.name, ws.displayName, pathToBinary)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer CloseServiceHandle(serviceHandle)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *windowsService) Remove() error {
|
||||||
|
scmManagerHandle, err := OpenSCManager()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer CloseServiceHandle(scmManagerHandle)
|
||||||
|
|
||||||
|
serviceHandle, err := OpenService(scmManagerHandle, ws.name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer CloseServiceHandle(serviceHandle)
|
||||||
|
|
||||||
|
err = DeleteService(serviceHandle)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *windowsService) Run(onStart, onStop func() error) error {
|
||||||
|
return runService(ws.name, onStart, onStop)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *windowsService) LogError(text string) error {
|
||||||
|
return writeToEventLog(ws.name, text, levelError)
|
||||||
|
}
|
||||||
|
func (ws *windowsService) LogWarning(text string) error {
|
||||||
|
return writeToEventLog(ws.name, text, levelWarning)
|
||||||
|
}
|
||||||
|
func (ws *windowsService) LogInfo(text string) error {
|
||||||
|
return writeToEventLog(ws.name, text, levelInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
advapi = syscall.MustLoadDLL("advapi32.dll")
|
||||||
|
|
||||||
|
createServiceProc = advapi.MustFindProc("CreateServiceW")
|
||||||
|
openServiceProc = advapi.MustFindProc("OpenServiceW")
|
||||||
|
deleteServiceProc = advapi.MustFindProc("DeleteService")
|
||||||
|
closeServiceHandleProc = advapi.MustFindProc("CloseServiceHandle")
|
||||||
|
|
||||||
|
openEventLogProc = advapi.MustFindProc("OpenEventLogW")
|
||||||
|
registerEventSourceProc = advapi.MustFindProc("RegisterEventSourceW")
|
||||||
|
deregisterEventSourceProc = advapi.MustFindProc("DeregisterEventSource")
|
||||||
|
reportEventProc = advapi.MustFindProc("ReportEventW")
|
||||||
|
|
||||||
|
openSCManagerProc = advapi.MustFindProc("OpenSCManagerW")
|
||||||
|
|
||||||
|
kernel = syscall.MustLoadDLL("kernel32.dll")
|
||||||
|
|
||||||
|
getModuleFileNameProc = kernel.MustFindProc("GetModuleFileNameW")
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_STANDARD_RIGHTS_REQUIRED = 0x000F0000
|
||||||
|
_SERVICE_WIN32_OWN_PROCESS = 0x00000010
|
||||||
|
_SERVICE_DEMAND_START = 0x00000003
|
||||||
|
_SERVICE_ERROR_NORMAL = 0x00000001
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_SC_MANAGER_CONNECT = 0x0001
|
||||||
|
_SC_MANAGER_CREATE_SERVICE = 0x0002
|
||||||
|
_SC_MANAGER_ENUMERATE_SERVICE = 0x0004
|
||||||
|
_SC_MANAGER_LOCK = 0x0008
|
||||||
|
_SC_MANAGER_QUERY_LOCK_STATUS = 0x0010
|
||||||
|
_SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020
|
||||||
|
|
||||||
|
_SC_MANAGER_ALL_ACCESS = (
|
||||||
|
_STANDARD_RIGHTS_REQUIRED |
|
||||||
|
_SC_MANAGER_CONNECT |
|
||||||
|
_SC_MANAGER_CREATE_SERVICE |
|
||||||
|
_SC_MANAGER_ENUMERATE_SERVICE |
|
||||||
|
_SC_MANAGER_LOCK |
|
||||||
|
_SC_MANAGER_QUERY_LOCK_STATUS |
|
||||||
|
_SC_MANAGER_MODIFY_BOOT_CONFIG)
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_SERVICE_QUERY_CONFIG = 0x0001
|
||||||
|
_SERVICE_CHANGE_CONFIG = 0x0002
|
||||||
|
_SERVICE_QUERY_STATUS = 0x0004
|
||||||
|
_SERVICE_ENUMERATE_DEPENDENTS = 0x0008
|
||||||
|
_SERVICE_START = 0x0010
|
||||||
|
_SERVICE_STOP = 0x0020
|
||||||
|
_SERVICE_PAUSE_CONTINUE = 0x0040
|
||||||
|
_SERVICE_INTERROGATE = 0x0080
|
||||||
|
_SERVICE_USER_DEFINED_CONTROL = 0x0100
|
||||||
|
|
||||||
|
_SERVICE_ALL_ACCESS = (
|
||||||
|
_STANDARD_RIGHTS_REQUIRED |
|
||||||
|
_SERVICE_QUERY_CONFIG |
|
||||||
|
_SERVICE_CHANGE_CONFIG |
|
||||||
|
_SERVICE_QUERY_STATUS |
|
||||||
|
_SERVICE_ENUMERATE_DEPENDENTS |
|
||||||
|
_SERVICE_START |
|
||||||
|
_SERVICE_STOP |
|
||||||
|
_SERVICE_PAUSE_CONTINUE |
|
||||||
|
_SERVICE_INTERROGATE |
|
||||||
|
_SERVICE_USER_DEFINED_CONTROL)
|
||||||
|
)
|
||||||
|
|
||||||
|
type eventLevel uint32
|
||||||
|
const (
|
||||||
|
levelError eventLevel = 0x0001
|
||||||
|
levelWarning eventLevel = 0x0002
|
||||||
|
levelInfo eventLevel = 0x0004
|
||||||
|
)
|
||||||
|
|
||||||
|
func writeToEventLog(title, text string, level eventLevel) error {
|
||||||
|
eventSource, err := registerEventSource(title)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = reportEvent(eventSource, title, text, level)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = deregisterEventSource(eventSource)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerEventSource(title string) (syscall.Handle, error) {
|
||||||
|
r0, _, e1 := registerEventSourceProc.Call(
|
||||||
|
0,
|
||||||
|
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(title))))
|
||||||
|
if r0 == 0 {
|
||||||
|
return syscall.Handle(0), e1
|
||||||
|
}
|
||||||
|
return syscall.Handle(r0), nil
|
||||||
|
}
|
||||||
|
func deregisterEventSource(eventSrouce syscall.Handle) error {
|
||||||
|
r0, _, e1 := deregisterEventSourceProc.Call(uintptr(eventSrouce))
|
||||||
|
if r0 == 0 {
|
||||||
|
return e1
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
const (
|
||||||
|
_EVENTLOG_ERROR_TYPE = 0x0001
|
||||||
|
_EVENTLOG_WARNING_TYPE = 0x0002
|
||||||
|
_EVENTLOG_INFORMATION_TYPE = 0x0004
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
|
||||||
|
func reportEvent(eventSource syscall.Handle, title, text string, level eventLevel) error {
|
||||||
|
msg := [...]uintptr{
|
||||||
|
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(title))),
|
||||||
|
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text)))}
|
||||||
|
r0, _, e1 := reportEventProc.Call(
|
||||||
|
uintptr(eventSource),
|
||||||
|
uintptr(level), //type
|
||||||
|
uintptr(0), //category
|
||||||
|
//uintptr(0xC0020001), //eventID
|
||||||
|
uintptr(3), //eventID
|
||||||
|
uintptr(0),
|
||||||
|
uintptr(2),
|
||||||
|
uintptr(0),
|
||||||
|
uintptr(unsafe.Pointer(&msg[0])),
|
||||||
|
0)
|
||||||
|
if r0 == 0 {
|
||||||
|
return e1
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CloseServiceHandle(service syscall.Handle) error {
|
||||||
|
r0, _, e1 := closeServiceHandleProc.Call(uintptr(service))
|
||||||
|
if r0 == 0 {
|
||||||
|
return e1
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func CreateService(scManager syscall.Handle, serviceName, serviceDisplayName, pathToBinary string) (syscall.Handle, error) {
|
||||||
|
r0, _, e1 := createServiceProc.Call(
|
||||||
|
uintptr(scManager),
|
||||||
|
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(serviceName))),
|
||||||
|
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(serviceDisplayName))),
|
||||||
|
uintptr(uint32(_SERVICE_ALL_ACCESS)),
|
||||||
|
uintptr(uint32(_SERVICE_WIN32_OWN_PROCESS)),
|
||||||
|
uintptr(uint32(_SERVICE_DEMAND_START)),
|
||||||
|
uintptr(uint32(_SERVICE_ERROR_NORMAL)),
|
||||||
|
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(pathToBinary))),
|
||||||
|
0, 0, 0, 0, 0) //+4 optional params not here
|
||||||
|
if r0 == 0 {
|
||||||
|
return syscall.Handle(0), e1
|
||||||
|
}
|
||||||
|
return syscall.Handle(r0), nil
|
||||||
|
}
|
||||||
|
func DeleteService(serviceHandle syscall.Handle) error {
|
||||||
|
r0, _, e1 := deleteServiceProc.Call(uintptr(serviceHandle))
|
||||||
|
if r0 == 0 {
|
||||||
|
return e1
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func OpenService(scManager syscall.Handle, serviceName string) (syscall.Handle, error) {
|
||||||
|
r0, _, e1 := openServiceProc.Call(uintptr(scManager), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(serviceName))), uintptr(uint32(_SC_MANAGER_ALL_ACCESS)))
|
||||||
|
if r0 == 0 {
|
||||||
|
return syscall.Handle(0), e1
|
||||||
|
}
|
||||||
|
return syscall.Handle(r0), nil
|
||||||
|
}
|
||||||
|
func GetModuleFileName() (string, error) {
|
||||||
|
var n uint32
|
||||||
|
b := make([]uint16, syscall.MAX_PATH)
|
||||||
|
size := uint32(len(b))
|
||||||
|
|
||||||
|
r0, _, e1 := getModuleFileNameProc.Call(0, uintptr(unsafe.Pointer(&b[0])), uintptr(size))
|
||||||
|
n = uint32(r0)
|
||||||
|
if n == 0 {
|
||||||
|
return "", e1
|
||||||
|
}
|
||||||
|
return string(utf16.Decode(b[0:n])), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func OpenSCManager() (syscall.Handle, error) {
|
||||||
|
r0, _, e1 := openSCManagerProc.Call(uintptr(0), uintptr(0), uintptr(uint32(_SC_MANAGER_ALL_ACCESS)))
|
||||||
|
if r0 == 0 {
|
||||||
|
return syscall.Handle(0), e1
|
||||||
|
}
|
||||||
|
return syscall.Handle(r0), nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user