1// Copyright 2010-2012 The W32 Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// +build windows
6
7package w32
8
9import (
10	"errors"
11	"fmt"
12	"syscall"
13	"unsafe"
14)
15
16var (
17	modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
18
19	procRegCreateKeyEx = modadvapi32.NewProc("RegCreateKeyExW")
20	procRegOpenKeyEx   = modadvapi32.NewProc("RegOpenKeyExW")
21	procRegCloseKey    = modadvapi32.NewProc("RegCloseKey")
22	procRegGetValue    = modadvapi32.NewProc("RegGetValueW")
23	procRegEnumKeyEx   = modadvapi32.NewProc("RegEnumKeyExW")
24	//	procRegSetKeyValue     = modadvapi32.NewProc("RegSetKeyValueW")
25	procRegSetValueEx      = modadvapi32.NewProc("RegSetValueExW")
26	procOpenEventLog       = modadvapi32.NewProc("OpenEventLogW")
27	procReadEventLog       = modadvapi32.NewProc("ReadEventLogW")
28	procCloseEventLog      = modadvapi32.NewProc("CloseEventLog")
29	procOpenSCManager      = modadvapi32.NewProc("OpenSCManagerW")
30	procCloseServiceHandle = modadvapi32.NewProc("CloseServiceHandle")
31	procOpenService        = modadvapi32.NewProc("OpenServiceW")
32	procStartService       = modadvapi32.NewProc("StartServiceW")
33	procControlService     = modadvapi32.NewProc("ControlService")
34)
35
36func RegCreateKey(hKey HKEY, subKey string) HKEY {
37	var result HKEY
38	ret, _, _ := procRegCreateKeyEx.Call(
39		uintptr(hKey),
40		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
41		uintptr(0),
42		uintptr(0),
43		uintptr(0),
44		uintptr(KEY_ALL_ACCESS),
45		uintptr(0),
46		uintptr(unsafe.Pointer(&result)),
47		uintptr(0))
48	_ = ret
49	return result
50}
51
52func RegOpenKeyEx(hKey HKEY, subKey string, samDesired uint32) HKEY {
53	var result HKEY
54	ret, _, _ := procRegOpenKeyEx.Call(
55		uintptr(hKey),
56		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
57		uintptr(0),
58		uintptr(samDesired),
59		uintptr(unsafe.Pointer(&result)))
60
61	if ret != ERROR_SUCCESS {
62		panic(fmt.Sprintf("RegOpenKeyEx(%d, %s, %d) failed", hKey, subKey, samDesired))
63	}
64	return result
65}
66
67func RegCloseKey(hKey HKEY) error {
68	var err error
69	ret, _, _ := procRegCloseKey.Call(
70		uintptr(hKey))
71
72	if ret != ERROR_SUCCESS {
73		err = errors.New("RegCloseKey failed")
74	}
75	return err
76}
77
78func RegGetRaw(hKey HKEY, subKey string, value string) []byte {
79	var bufLen uint32
80	var valptr unsafe.Pointer
81	if len(value) > 0 {
82		valptr = unsafe.Pointer(syscall.StringToUTF16Ptr(value))
83	}
84	procRegGetValue.Call(
85		uintptr(hKey),
86		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
87		uintptr(valptr),
88		uintptr(RRF_RT_ANY),
89		0,
90		0,
91		uintptr(unsafe.Pointer(&bufLen)))
92
93	if bufLen == 0 {
94		return nil
95	}
96
97	buf := make([]byte, bufLen)
98	ret, _, _ := procRegGetValue.Call(
99		uintptr(hKey),
100		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
101		uintptr(valptr),
102		uintptr(RRF_RT_ANY),
103		0,
104		uintptr(unsafe.Pointer(&buf[0])),
105		uintptr(unsafe.Pointer(&bufLen)))
106
107	if ret != ERROR_SUCCESS {
108		return nil
109	}
110
111	return buf
112}
113
114func RegSetBinary(hKey HKEY, subKey string, value []byte) (errno int) {
115	var lptr, vptr unsafe.Pointer
116	if len(subKey) > 0 {
117		lptr = unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))
118	}
119	if len(value) > 0 {
120		vptr = unsafe.Pointer(&value[0])
121	}
122	ret, _, _ := procRegSetValueEx.Call(
123		uintptr(hKey),
124		uintptr(lptr),
125		uintptr(0),
126		uintptr(REG_BINARY),
127		uintptr(vptr),
128		uintptr(len(value)))
129
130	return int(ret)
131}
132
133func RegGetString(hKey HKEY, subKey string, value string) string {
134	var bufLen uint32
135	procRegGetValue.Call(
136		uintptr(hKey),
137		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
138		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(value))),
139		uintptr(RRF_RT_REG_SZ),
140		0,
141		0,
142		uintptr(unsafe.Pointer(&bufLen)))
143
144	if bufLen == 0 {
145		return ""
146	}
147
148	buf := make([]uint16, bufLen)
149	ret, _, _ := procRegGetValue.Call(
150		uintptr(hKey),
151		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
152		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(value))),
153		uintptr(RRF_RT_REG_SZ),
154		0,
155		uintptr(unsafe.Pointer(&buf[0])),
156		uintptr(unsafe.Pointer(&bufLen)))
157
158	if ret != ERROR_SUCCESS {
159		return ""
160	}
161
162	return syscall.UTF16ToString(buf)
163}
164
165/*
166func RegSetKeyValue(hKey HKEY, subKey string, valueName string, dwType uint32, data uintptr, cbData uint16) (errno int) {
167	ret, _, _ := procRegSetKeyValue.Call(
168		uintptr(hKey),
169		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
170		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(valueName))),
171		uintptr(dwType),
172		data,
173		uintptr(cbData))
174
175	return int(ret)
176}
177*/
178
179func RegEnumKeyEx(hKey HKEY, index uint32) string {
180	var bufLen uint32 = 255
181	buf := make([]uint16, bufLen)
182	procRegEnumKeyEx.Call(
183		uintptr(hKey),
184		uintptr(index),
185		uintptr(unsafe.Pointer(&buf[0])),
186		uintptr(unsafe.Pointer(&bufLen)),
187		0,
188		0,
189		0,
190		0)
191	return syscall.UTF16ToString(buf)
192}
193
194func OpenEventLog(servername string, sourcename string) HANDLE {
195	ret, _, _ := procOpenEventLog.Call(
196		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(servername))),
197		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(sourcename))))
198
199	return HANDLE(ret)
200}
201
202func ReadEventLog(eventlog HANDLE, readflags, recordoffset uint32, buffer []byte, numberofbytestoread uint32, bytesread, minnumberofbytesneeded *uint32) bool {
203	ret, _, _ := procReadEventLog.Call(
204		uintptr(eventlog),
205		uintptr(readflags),
206		uintptr(recordoffset),
207		uintptr(unsafe.Pointer(&buffer[0])),
208		uintptr(numberofbytestoread),
209		uintptr(unsafe.Pointer(bytesread)),
210		uintptr(unsafe.Pointer(minnumberofbytesneeded)))
211
212	return ret != 0
213}
214
215func CloseEventLog(eventlog HANDLE) bool {
216	ret, _, _ := procCloseEventLog.Call(
217		uintptr(eventlog))
218
219	return ret != 0
220}
221
222func OpenSCManager(lpMachineName, lpDatabaseName string, dwDesiredAccess uint32) (HANDLE, error) {
223	var p1, p2 uintptr
224	if len(lpMachineName) > 0 {
225		p1 = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpMachineName)))
226	}
227	if len(lpDatabaseName) > 0 {
228		p2 = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDatabaseName)))
229	}
230	ret, _, _ := procOpenSCManager.Call(
231		p1,
232		p2,
233		uintptr(dwDesiredAccess))
234
235	if ret == 0 {
236		return 0, syscall.GetLastError()
237	}
238
239	return HANDLE(ret), nil
240}
241
242func CloseServiceHandle(hSCObject HANDLE) error {
243	ret, _, _ := procCloseServiceHandle.Call(uintptr(hSCObject))
244	if ret == 0 {
245		return syscall.GetLastError()
246	}
247	return nil
248}
249
250func OpenService(hSCManager HANDLE, lpServiceName string, dwDesiredAccess uint32) (HANDLE, error) {
251	ret, _, _ := procOpenService.Call(
252		uintptr(hSCManager),
253		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpServiceName))),
254		uintptr(dwDesiredAccess))
255
256	if ret == 0 {
257		return 0, syscall.GetLastError()
258	}
259
260	return HANDLE(ret), nil
261}
262
263func StartService(hService HANDLE, lpServiceArgVectors []string) error {
264	l := len(lpServiceArgVectors)
265	var ret uintptr
266	if l == 0 {
267		ret, _, _ = procStartService.Call(
268			uintptr(hService),
269			0,
270			0)
271	} else {
272		lpArgs := make([]uintptr, l)
273		for i := 0; i < l; i++ {
274			lpArgs[i] = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpServiceArgVectors[i])))
275		}
276
277		ret, _, _ = procStartService.Call(
278			uintptr(hService),
279			uintptr(l),
280			uintptr(unsafe.Pointer(&lpArgs[0])))
281	}
282
283	if ret == 0 {
284		return syscall.GetLastError()
285	}
286
287	return nil
288}
289
290func ControlService(hService HANDLE, dwControl uint32, lpServiceStatus *SERVICE_STATUS) bool {
291	if lpServiceStatus == nil {
292		panic("ControlService:lpServiceStatus cannot be nil")
293	}
294
295	ret, _, _ := procControlService.Call(
296		uintptr(hService),
297		uintptr(dwControl),
298		uintptr(unsafe.Pointer(lpServiceStatus)))
299
300	return ret != 0
301}
302