Update to not use cgo but to use Alex's winsvc
This commit is contained in:
+5
-4
@@ -1,17 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"../../service"
|
||||
"bitbucket.org/kardianos/service"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var displayName = "Go Service Test2"
|
||||
var name = "GoServiceTest"
|
||||
var displayName = "Go Service Test"
|
||||
var desc = "This is a test Go service. It is designed to run well."
|
||||
var ws, err = service.NewService("GoServiceTest2", displayName, desc)
|
||||
var ws, err = service.NewService(name, displayName, desc)
|
||||
|
||||
if(err != nil) {
|
||||
if err != nil {
|
||||
fmt.Printf("%s unable to start: %s", displayName, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
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) {
|
||||
ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
|
||||
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) {
|
||||
ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
|
||||
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
|
||||
// stop and return that error.
|
||||
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.
|
||||
// Will signal to stop 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
|
||||
}
|
||||
+87
-365
@@ -5,6 +5,9 @@ import (
|
||||
"unicode/utf16"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
"code.google.com/p/winsvc/svc"
|
||||
"code.google.com/p/winsvc/mgr"
|
||||
"code.google.com/p/winsvc/eventlog"
|
||||
)
|
||||
|
||||
func newService(name, displayName, description string) (*windowsService, error) {
|
||||
@@ -17,91 +20,127 @@ func newService(name, displayName, description string) (*windowsService, error)
|
||||
|
||||
type windowsService struct {
|
||||
name, displayName, description string
|
||||
onStart, onStop func() error
|
||||
logger *eventlog.Log
|
||||
}
|
||||
|
||||
func (ws *windowsService) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
|
||||
const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown
|
||||
changes <- svc.Status{State: svc.StartPending}
|
||||
|
||||
if err := ws.onStart(); err != nil {
|
||||
ws.LogError(err.Error())
|
||||
return true, 1
|
||||
}
|
||||
|
||||
changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
|
||||
loop:
|
||||
for {
|
||||
c := <-r
|
||||
switch c.Cmd {
|
||||
case svc.Interrogate:
|
||||
changes <- c.CurrentStatus
|
||||
case svc.Stop, svc.Shutdown:
|
||||
changes <- svc.Status{State: svc.StopPending}
|
||||
if err := ws.onStop(); err != nil {
|
||||
ws.LogError(err.Error())
|
||||
changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
|
||||
continue loop
|
||||
}
|
||||
break loop
|
||||
default:
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (ws *windowsService) Install() error {
|
||||
pathToBinary, err := getModuleFileName()
|
||||
exepath, err := getExePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scmManagerHandle, err := openSCManager()
|
||||
m, err := mgr.Connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeServiceHandle(scmManagerHandle)
|
||||
|
||||
serviceHandle, err := createService(scmManagerHandle, ws.name, ws.displayName, pathToBinary)
|
||||
defer m.Disconnect()
|
||||
s, err := m.OpenService(ws.name)
|
||||
if err == nil {
|
||||
s.Close()
|
||||
return fmt.Errorf("service %s already exists", ws.name)
|
||||
}
|
||||
s, err = m.CreateService(ws.name, exepath, mgr.Config{
|
||||
DisplayName: ws.displayName,
|
||||
Description: ws.description,
|
||||
StartType: mgr.StartAutomatic,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeServiceHandle(serviceHandle)
|
||||
|
||||
err = changeServiceDescription(serviceHandle, ws.description)
|
||||
defer s.Close()
|
||||
err = eventlog.InstallAsEventCreate(ws.name, eventlog.Error|eventlog.Warning|eventlog.Info)
|
||||
if err != nil {
|
||||
return err
|
||||
s.Delete()
|
||||
return fmt.Errorf("InstallAsEventCreate() failed: %s", err)
|
||||
}
|
||||
|
||||
regKey, err := regCreateKey(`SYSTEM\CurrentControlSet\Services\Eventlog\Application\` + ws.name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer regCloseKey(regKey)
|
||||
|
||||
regSetKeyValue(regKey, "EventMessageFile", `%SystemRoot%\System32\EventCreate.exe`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
regSetKeyValue(regKey, "CustomSource", uint32(1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
regSetKeyValue(regKey, "TypesSupported", uint32(7))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ws *windowsService) Remove() error {
|
||||
scmManagerHandle, err := openSCManager()
|
||||
m, err := mgr.Connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeServiceHandle(scmManagerHandle)
|
||||
|
||||
serviceHandle, err := openService(scmManagerHandle, ws.name)
|
||||
defer m.Disconnect()
|
||||
s, err := m.OpenService(ws.name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("service %s is not installed", ws.name)
|
||||
}
|
||||
defer s.Close()
|
||||
err = s.Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeServiceHandle(serviceHandle)
|
||||
|
||||
err = deleteService(serviceHandle)
|
||||
err = eventlog.Remove(ws.name)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("RemoveEventLogSource() failed: %s", err)
|
||||
}
|
||||
|
||||
err = regDeleteKey(`SYSTEM\CurrentControlSet\Services\Eventlog\Application\` + ws.name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ws *windowsService) Run(onStart, onStop func() error) error {
|
||||
return runService(ws.name, onStart, onStop)
|
||||
elog, err := eventlog.Open(ws.name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer elog.Close()
|
||||
|
||||
ws.logger = elog
|
||||
|
||||
ws.onStart = onStart
|
||||
ws.onStop = onStop
|
||||
return svc.Run(ws.name, ws)
|
||||
}
|
||||
|
||||
func (ws *windowsService) LogError(format string, a ...interface{}) error {
|
||||
return writeToEventLog(ws.name, fmt.Sprintf(format, a ...), levelError)
|
||||
if ws.logger == nil {
|
||||
return nil
|
||||
}
|
||||
return ws.logger.Error(3, fmt.Sprintf(format, a...))
|
||||
}
|
||||
func (ws *windowsService) LogWarning(format string, a ...interface{}) error {
|
||||
return writeToEventLog(ws.name, fmt.Sprintf(format, a ...), levelWarning)
|
||||
if ws.logger == nil {
|
||||
return nil
|
||||
}
|
||||
return ws.logger.Warning(2, fmt.Sprintf(format, a...))
|
||||
}
|
||||
func (ws *windowsService) LogInfo(format string, a ...interface{}) error {
|
||||
return writeToEventLog(ws.name, fmt.Sprintf(format, a ...), levelInfo)
|
||||
if ws.logger == nil {
|
||||
return nil
|
||||
}
|
||||
return ws.logger.Info(1, fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
func getExePath() (exePath string, err error) {
|
||||
@@ -109,185 +148,12 @@ func getExePath() (exePath string, err error) {
|
||||
}
|
||||
|
||||
var (
|
||||
advapi = syscall.MustLoadDLL("advapi32.dll")
|
||||
kernel = syscall.MustLoadDLL("kernel32.dll")
|
||||
|
||||
//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")
|
||||
changeServiceConfig2Proc = advapi.MustFindProc("ChangeServiceConfig2W")
|
||||
|
||||
// Registry
|
||||
regCloseKeyProc = advapi.MustFindProc("RegCloseKey")
|
||||
regSetKeyValueExProc = advapi.MustFindProc("RegSetValueExW")
|
||||
regCreateKeyExProc = advapi.MustFindProc("RegCreateKeyExW")
|
||||
regDeleteKeyProc = advapi.MustFindProc("RegDeleteKeyW")
|
||||
|
||||
// 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(text)))}
|
||||
r0, _, e1 := reportEventProc.Call(
|
||||
uintptr(eventSource),
|
||||
uintptr(level), //type
|
||||
uintptr(0), //category
|
||||
uintptr(1), //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)
|
||||
@@ -300,147 +166,3 @@ func getModuleFileName() (string, error) {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
const (
|
||||
_SERVICE_CONFIG_DESCRIPTION = 1
|
||||
)
|
||||
|
||||
func changeServiceDescription(h syscall.Handle, desc string) error {
|
||||
msg := &struct {
|
||||
desc uintptr
|
||||
}{
|
||||
desc: uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(desc))),
|
||||
}
|
||||
r0, _, e1 := changeServiceConfig2Proc.Call(
|
||||
uintptr(h),
|
||||
uintptr(_SERVICE_CONFIG_DESCRIPTION),
|
||||
uintptr(unsafe.Pointer(msg)),
|
||||
)
|
||||
if r0 == 0 {
|
||||
return e1
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// registry functions
|
||||
|
||||
/*
|
||||
LONG WINAPI RegCloseKey(
|
||||
__in HKEY hKey
|
||||
);
|
||||
LONG WINAPI RegSetValueExW(
|
||||
__in HKEY hKey,
|
||||
__in_opt LPCTSTR lpValueName,
|
||||
__reserved DWORD Reserved,
|
||||
__in DWORD dwType,
|
||||
__in const BYTE *lpData,
|
||||
__in DWORD cbData
|
||||
);
|
||||
LONG WINAPI RegCreateKeyExW(
|
||||
__in HKEY hKey,
|
||||
__in LPCTSTR lpSubKey,
|
||||
__reserved DWORD Reserved,
|
||||
__in_opt LPTSTR lpClass,
|
||||
__in DWORD dwOptions,
|
||||
__in REGSAM samDesired,
|
||||
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
__out PHKEY phkResult,
|
||||
__out_opt LPDWORD lpdwDisposition
|
||||
);
|
||||
LONG WINAPI RegDeleteKeyExW(
|
||||
__in HKEY hKey,
|
||||
__in LPCTSTR lpSubKey,
|
||||
__in REGSAM samDesired,
|
||||
__reserved DWORD Reserved
|
||||
);
|
||||
*/
|
||||
|
||||
func StringToUTF16PtrLen(s string) (ptr uintptr, l uintptr) {
|
||||
u := syscall.StringToUTF16(s)
|
||||
l = uintptr(len(u) * 2) //size in uint8, length of uint16
|
||||
ptr = uintptr(unsafe.Pointer(&u[0]))
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
_HKEY_LOCAL_MACHINE = 0x80000002
|
||||
|
||||
_REG_SZ = 1
|
||||
_REG_DWORD = 4
|
||||
|
||||
_KEY_ALL_ACCESS = 0xF003F
|
||||
)
|
||||
|
||||
func regCloseKey(h syscall.Handle) error {
|
||||
r0, _, e1 := regCloseKeyProc.Call(
|
||||
uintptr(h),
|
||||
)
|
||||
if r0 != 0 {
|
||||
return e1
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func regSetKeyValue(h syscall.Handle, keyName string, data interface{}) error {
|
||||
var dataPtr, dataLen, dataType uintptr
|
||||
switch v := data.(type) {
|
||||
case uint32:
|
||||
dataPtr, dataLen = uintptr(unsafe.Pointer(&v)), 4
|
||||
dataType = _REG_DWORD
|
||||
case string:
|
||||
// The comment on MSDN regarding escaping back-slashes, are c-lang specific.
|
||||
// The API just takes a normal NUL terminated string, no special escaping required.
|
||||
dataPtr, dataLen = StringToUTF16PtrLen(v)
|
||||
dataType = _REG_SZ
|
||||
}
|
||||
r0, _, e1 := regSetKeyValueExProc.Call(
|
||||
uintptr(h),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(keyName))),
|
||||
0,
|
||||
dataType,
|
||||
dataPtr,
|
||||
dataLen,
|
||||
)
|
||||
if r0 != 0 {
|
||||
return e1
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func regCreateKey(keyName string) (h syscall.Handle, err error) {
|
||||
r0, _, e1 := regCreateKeyExProc.Call(
|
||||
uintptr(_HKEY_LOCAL_MACHINE),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(keyName))),
|
||||
0,
|
||||
0, //class
|
||||
0, //no options
|
||||
uintptr(_KEY_ALL_ACCESS),
|
||||
0, //no security
|
||||
uintptr(unsafe.Pointer(&h)),
|
||||
0, //can return if created or opened
|
||||
)
|
||||
if r0 != 0 {
|
||||
err = e1
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func regDeleteKey(keyName string) error {
|
||||
r0, _, e1 := regDeleteKeyProc.Call(
|
||||
uintptr(_HKEY_LOCAL_MACHINE),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(keyName))),
|
||||
)
|
||||
if r0 != 0 {
|
||||
return e1
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user