2016-09-08 8 views
0

У меня есть машина VirtualBox с Ubuntu, к которой прикреплен мостовой адаптер.Не удается получить IP-адрес машины VirtualBox с помощью API VBox

То, что я пытаюсь сделать, это получить IP-адрес машины.

Если я запустить машину вручную и с помощью утилиты VBoxManage так:

VBoxManage guestproperty get "Ubuntu Test Machine" /VirtualBox/GuestInfo/Net/0/V4/IP 

он работает нормально.

Тем не менее, мне нужно получить программный IP-адрес с помощью VBox SDK. Вот самая важная часть кода (я выложу весь код ниже в конце):

HRESULT hr = machine->GetGuestPropertyValue(L"/VirtualBox/GuestInfo/Net/0/V4/IP", &ip); 
if (SUCCEEDED(hr)) 
{ 
    printf("The machine's IP is: %s", ip); 
} 
else 
    printf("Error retrieving machine IP! rc = 0x%x\n", hr); 

Я получаю следующее сообщение об ошибке:

Error retrieving machine IP! rc = 0x80070057 

Видимо, что код ошибки означает недействительный параметр.

Может ли кто-нибудь сказать мне, что не так с этим параметром? Или если я делаю что-то еще неправильно?

Вот весь код (это в основном пример кода из каталога образцов VBox SDK с некоторыми изменениями):

int testStartVM(IVirtualBox *virtualBox) 
{ 
    HRESULT rc; 

    IMachine *machine = NULL; 
    BSTR machineName = SysAllocString(L"Ubuntu Test Machine"); 

    rc = virtualBox->FindMachine(machineName, &machine); 

    if (FAILED(rc)) 
    { 
     // this code is verbose and not relevant 
    } 
    else 
    { 
     ISession *session = NULL; 
     IConsole *console = NULL; 
     IProgress *progress = NULL; 
     BSTR sessiontype = SysAllocString(L"headless"); 
     BSTR guid; 

     do 
     { 
      rc = machine->get_Id(&guid); /* Get the GUID of the machine. */ 
      if (!SUCCEEDED(rc)) 
      { 
       printf("Error retrieving machine ID! rc = 0x%x\n", rc); 
       break; 
      } 

      /* Create the session object. */ 
      rc = CoCreateInstance(CLSID_Session,  /* the VirtualBox base object */ 
            NULL,     /* no aggregation */ 
            CLSCTX_INPROC_SERVER, /* the object lives in a server process on this machine */ 
            IID_ISession,   /* IID of the interface */ 
            (void**)&session); 
      if (!SUCCEEDED(rc)) 
      { 
       printf("Error creating Session instance! rc = 0x%x\n", rc); 
       break; 
      } 

      /* Start a VM session using the delivered VBox GUI. */ 
      rc = machine->LaunchVMProcess(session, sessiontype, 
              NULL, &progress); 
      if (!SUCCEEDED(rc)) 
      { 
       printf("Could not open remote session! rc = 0x%x\n", rc); 
       break; 
      } 

      /* Wait until VM is running. */ 
      printf("Starting VM, please wait ...\n"); 
      rc = progress->WaitForCompletion(-1); 

      /* Get console object. */ 
      session->get_Console(&console); 

      /* Bring console window to front. */ 
      machine->ShowConsoleWindow(0); 

      // give it a few seconds just to be sure everything has been started 
      Sleep(40 * 1000); 
      BSTR ip; 

      **// this line fails** 
      HRESULT hr = machine->GetGuestPropertyValue(L"/VirtualBox/GuestInfo/Net/0/V4/IP", &ip); 
      if (SUCCEEDED(hr)) 
      { 
       printf("The machine's IP is: %s", ip); 
      } 
      else 
       printf("Error retrieving machine IP! rc = 0x%x\n", hr); 

      printf("Press enter to power off VM and close the session...\n"); 
      getchar(); 

      /* Power down the machine. */ 
      rc = console->PowerDown(&progress); 

      /* Wait until VM is powered down. */ 
      printf("Powering off VM, please wait ...\n"); 
      rc = progress->WaitForCompletion(-1); 

      /* Close the session. */ 
      rc = session->UnlockMachine(); 

     } while (0); 

     SAFE_RELEASE(console); 
     SAFE_RELEASE(progress); 
     SAFE_RELEASE(session); 
     SysFreeString(guid); 
     SysFreeString(sessiontype); 
     SAFE_RELEASE(machine); 
    } 

    SysFreeString(machineName); 

    return 0; 
} 


int main(int argc, char *argv[]) 
{ 
    HRESULT rc; 
    IVirtualBox *virtualBox; 

    /* Initialize the COM subsystem. */ 
    CoInitialize(NULL); 

    /* Instantiate the VirtualBox root object. */ 
    rc = CoCreateInstance(CLSID_VirtualBox,  /* the VirtualBox base object */ 
          NULL,     /* no aggregation */ 
          CLSCTX_LOCAL_SERVER, /* the object lives in a server process on this machine */ 
          IID_IVirtualBox,  /* IID of the interface */ 
          (void**)&virtualBox); 

    if (!SUCCEEDED(rc)) 
    { 
     printf("Error creating VirtualBox instance! rc = 0x%x\n", rc); 
     return 1; 
    } 

    listVMs(virtualBox); 

    testStartVM(virtualBox); 

    /* Release the VirtualBox object. */ 
    virtualBox->Release(); 

    CoUninitialize(); 

    getchar(); 
    return 0; 
} 
+1

Передача различных типов строк к API нечетное. Использует ли 'GetGuestPropertyValue'' const wchar_t * 'как входной и' BSTR * 'как вывод? Где находится документация для этого интерфейса? – IInspectable

+0

Во-первых, вы должны проверить, запущена ли машина вообще, а вторая - вы пробовали опрос? Может быть, VBox отвечает таким образом, потому что сетевой стек еще не встал? –

ответ

0

Я нашел проблему. По-видимому, функция GetGuestPropertyValue не знает, как автоматически конвертировать wchar_t * в BSTR. Мне нужно дать ему настоящий BSTR.

Вот правильный путь:

BSTR val = SysAllocString(L"/VirtualBox/GuestInfo/Net/0/V4/IP"); 

HRESULT hr = machine->GetGuestPropertyValue(val, &ip); 
if (SUCCEEDED(hr)) 
{ 
    wprintf(L"The machine's IP is: %s", ip); 
} 
else 
    printf("Error retrieving machine IP! rc = 0x%x\n", hr); 

SysFreeString(val); 
+2

Ничего не известно «как автоматически конвертировать wchar_t * в BSTR»; это преобразование потребует от вас быть психическим, так как a) 'BSTR' имеет очень похожий формат хранения для строки C, но не является тем же, и b)' BSTR' имеет свой собственный распределитель; смешение и сопоставление - это плохо. И вполне возможно, что ваш объект COM полностью прокси-сервер к другому процессу; RPC-система нуждается в реальном BSTR для маршала, и это происходит до того, как код VirtualBox даже запускается. Вам всегда нужно будет сделать преобразование самостоятельно. – andlabs

+2

Если вы не хотите вручную управлять своими 'BSTR', используйте один из классов-оболочек, например [CComBSTR] (https://msdn.microsoft.com/en-us/library/zh7x9w3f.aspx), или [_bstr_t] (https://msdn.microsoft.com/en-us/library/zthfhkd6.aspx). Это позволяет вам писать код следующим образом: 'machine-> GetGuestPropertyValue (CComBSTR (L"/VirtualBox/GuestInfo/Net/0/V4/IP "), & ip)'. – IInspectable

+2

Всякий раз, когда вы имеете дело с COM-интерфейсами, ** все строки ** должны быть реальными 'BSTR', если не указано иное. 'BSTR' - единственный тип строки, о котором COM знает. Причина, по которой люди сталкиваются с этим, заключается в том, что 'BSTR' определяется как' WCHAR * 'в' wtypes.h' для компиляторов C/C++, поэтому они не могут выполнять правильную проверку типов, тем самым позволяя * любую * широкую строку передаваться там, где ожидается «BSTR», даже если он ошибочен. Стыдно, что Microsoft никогда не сталкивалась с «STRICT» -подобным способом решения этого конфликта. –