Вызов 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.")
    }
Другие вопросы по тегам