【问题标题】:Cannot get VirtualBox machine's IP using the VBox API无法使用 VBox API 获取 VirtualBox 机器的 IP
【发布时间】:2016-09-08 13:51:06
【问题描述】:

我有一台装有 Ubuntu 的 VirtualBox 机器,它连接了一个桥接适配器。

我要做的是获取机器的IP。

如果我手动启动机器并像这样使用 VBoxManage 实用程序:

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

一切正常。

但是,我需要的是使用 VBox SDK 以编程方式获取 IP。 这是代码中最重要的部分(我将在最后发布整个代码):

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;
}

【问题讨论】:

  • 将不同的字符串类型传递给 API 很奇怪。 GetGuestPropertyValue 是否将 const wchar_t* 作为输入和 BSTR* 作为输出?该接口的文档在哪里?
  • 首先,您应该检查机器是否已经启动,其次 - 您是否尝试过轮询?可能VBox这样响应是因为网络栈还没起来?

标签: c++ winapi virtual-machine virtualbox invalid-argument


【解决方案1】:

我发现了问题。显然 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);

【讨论】:

  • 没有人知道“如何自动将 wchar_t* 转换为 BSTR”;这种转换需要你通灵,因为 a) BSTR 具有与 C 字符串非常相似的存储格式但不一样,并且 b) BSTR 有自己的分配器;混搭不好。而且很可能您的 COM 对象完全代理了另一个进程; RPC 系统需要一个真正的BSTR 来编组,而这发生在 VirtualBox 的代码甚至运行之前。您将始终需要自己进行转换。
  • 如果您不想手动管理您的BSTRs,请使用包装类之一,例如CComBSTR_bstr_t。这使您可以编写如下代码:machine->GetGuestPropertyValue(CComBSTR(L"/VirtualBox/GuestInfo/Net/0/V4/IP"), &ip).
  • 无论何时处理 COM 接口,所有字符串都必须是真实的BSTRs,除非另有说明。 BSTR 是 COM 原生知道的唯一字符串类型。人们遇到这个问题的原因是因为BSTR 在 C/C++ 编译器的wtypes.h 中被定义为WCHAR*,因此它们无法执行正确的类型验证,从而允许 any 宽要在预期 BSTR 的地方传递的字符串,即使它是错误的。遗憾的是,微软从未提出类似STRICT 的方式来解决此冲突。
猜你喜欢
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-18
相关资源
最近更新 更多