Вызов EnumServicesStatusEx в Go, выделение памяти?
Я пишу приложение, которое взаимодействует с Windows API из службы Windows.
После огромного количества помощи от @chowey, я вроде как освоился и запустил базовую библиотеку, которую я поместил здесь на GitHub.
Теперь я перешел к "Службам" с требованием перечислить все службы Windows на компьютере, запускать, останавливать, перезапускать их. Запуск / остановка / перезапуск выглядят довольно просто, если у вас есть дескриптор сервиса для работы, но я пытаюсь получить список установленных сервисов.
EnumServicesStatusEx в Advapi32.dll - это функция, которую мне нужно вызвать, но для нее требуется указатель на предварительно выделенную память для массива структур ENUM_SERVICE_STATUS_PROCESS.
Вы можете вызвать функцию с нулевым указателем, и она вернет требуемый размер выделения памяти, но я не верю, что есть способ напрямую выделить память в Go.
Сначала я подумал, что смогу получить требование выделения памяти, разделить его на SizeOf структуры, используя небезопасный пакет, создать срез, содержащий это количество элементов, а затем передать указатель на первый элемент функции, но он говорит, что память необходимо включить пространство для строковых данных, чего бы не произошло.
Кто-нибудь знает, как это можно сделать, пожалуйста?:).
1 ответ
После предложений @alex у меня работает следующий пример кода.
Похоже, мы создаем кусочек байта правильного размера, а затем используем небезопасный класс для приведения к нашему типу структуры.
_, _, _ = svcEnumServicesStatusEx.Call(
uintptr(handle),
uintptr(uint32(SVC_SC_ENUM_PROCESS_INFO)),
uintptr(uint32(SVC_SERVICE_WIN32)),
uintptr(uint32(SVC_SERVICE_STATE_ALL)),
uintptr(0),
0,
uintptr(unsafe.Pointer(&bytesReq)),
uintptr(unsafe.Pointer(&numReturned)),
uintptr(unsafe.Pointer(&resumeHandle)),
uintptr(0),
)
if bytesReq > 0 {
var buf []byte = make([]byte, bytesReq)
ret, _, _ := svcEnumServicesStatusEx.Call(
uintptr(handle),
uintptr(uint32(SVC_SC_ENUM_PROCESS_INFO)),
uintptr(uint32(SVC_SERVICE_WIN32)),
uintptr(uint32(SVC_SERVICE_STATE_ALL)),
uintptr(unsafe.Pointer(&buf[0])),
uintptr(bytesReq),
uintptr(unsafe.Pointer(&bytesReq)),
uintptr(unsafe.Pointer(&numReturned)),
uintptr(unsafe.Pointer(&resumeHandle)),
uintptr(0),
)
if ret > 0 {
var sizeTest ENUM_SERVICE_STATUS_PROCESS
iter := uintptr(unsafe.Pointer(&buf[0]))
for i := uint32(0); i < numReturned; i++ {
var data *ENUM_SERVICE_STATUS_PROCESS = (*ENUM_SERVICE_STATUS_PROCESS)(unsafe.Pointer(iter))
fmt.Printf("Service Name: %s - Display Name: %s - %#v\r\n", syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(data.lpServiceName))[:]), syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(data.lpDisplayName))[:]), data.ServiceStatusProcess)
iter = uintptr(unsafe.Pointer(iter + unsafe.Sizeof(sizeTest)))
}
} else {
return nil, fmt.Errorf("Failed to get Service List even with allocated memory.")
}
} else {
return nil, fmt.Errorf("Unable to get size of required memory allocation.")
}