2016-05-16 10 views
0

Я пишу приложение, которое взаимодействует с Windows API из службы Windows.Вызов EnumServicesStatusEx в Go, выделение памяти?

После загрузки справки от @chowey here, я как бы повесил вещи и основал базовую библиотеку, которую я надел GitHub here.

Теперь я перешел к «Службам», с требованием перечислить все службы Windows на машине, запустить, остановить, перезапустить их. Запуск/останов/перезапуск выглядят довольно прямолинейно, когда у вас есть служебный дескриптор, с которым я работаю, но я боюсь получить список установленных сервисов.

EnumServicesStatusEx в Advapi32.dll - это функция, которую мне нужно вызвать, но для этого требуется указатель на предварительно выделенную память для массива из ENUM_SERVICE_STATUS_PROCESS structs.

Вы можете вызвать функцию с помощью нулевого указателя, и она вернет требуемый размер выделения памяти, но я не верю, что есть способ напрямую выделить память в Go.

Сначала я думал, что могу получить требование распределения памяти, делить его на SizeOf на структуру, используя небезопасный пакет, создать срез, содержащий это число элементов, а затем передать указатель на первый элемент функции, но он говорит, что память должна включать в себя пространство для строковых данных, чего не было бы.

Кто-нибудь знает, как это может быть выполнено, пожалуйста? :).

+0

От EnumServicesStatusEx DOCO: 'lpServices [из факультативные] Указатель на буфер, который получает информацию о состоянии. ... Чтобы определить требуемый размер, укажите NULL для этого параметра и 0 для параметра cbBufSize. Функция завершится с ошибкой, и GetLastError вернет ERROR_MORE_DATA. Параметр pcbBytesNeeded получит требуемый размер. '. Как только вы узнаете, насколько велик ваш буфер, снова вызовите EnumServicesStatusEx с буфером такого размера. – alex

+0

Здравствуйте, @alex, как описано выше, я не знаю, как сделать Go напрямую распределять память. Вы должны предоставить ему структуру данных, чтобы сделать ее выделенной памятью, а затем разоблачить эту память через небезопасный пакет. – iamacarpet

+1

вы сами сказали: 'создайте срез, содержащий это число элементов, а затем передайте указатель на первый элемент функции'. From EnumServicesStatusEx doco: 'cbBufSize [in] Размер буфера, на который указывает параметр lpServices, в байтах. Поэтому вы можете создать массив байтов cbBufSize и передать адрес первого элемента этого массива в EnumServicesStatusEx. Например, https://github.com/golang/go/blob/master/src/internal/syscall/windows/registry/value.go#L71. В отличие от примера, вы должны начать с передачи lpServices = nil в соответствии с EnumServicesStatusEx doco. – alex

ответ

0

После предложений от @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.") 
    } 

 Смежные вопросы

  • Нет связанных вопросов^_^