Ejemplo n.º 1
0
/* Sends the given event to the UI thread.  Assumes aEventID never goes out
 * of scope (static strings are ideal).
 */
nsresult
nsNotifyAddrListener::SendEventToUI(const char *aEventID)
{
    nsresult rv;

    if (!aEventID) return NS_ERROR_NULL_POINTER;

    nsCOMPtr<nsIEventQueue> eq;
    rv = NS_GetMainEventQ(getter_AddRefs(eq));
    if (NS_FAILED(rv))
        return rv;

    ChangeEvent *event = new ChangeEvent(aEventID);
    if (!event)
        return NS_ERROR_OUT_OF_MEMORY;
    // AddRef this because it is being placed in the PLEvent; it'll be Released
    // when DestroyInterfaceEvent is called
    NS_ADDREF_THIS();
    PL_InitEvent(event, this, HandleInterfaceEvent, DestroyInterfaceEvent);

    if (NS_FAILED(rv = eq->PostEvent(event))) {
        NS_ERROR("failed to post event to UI EventQueue");
        PL_DestroyEvent(event);
    }
    return rv;
}
Ejemplo n.º 2
0
/* static */
int NativeEventQueue::init()
{
    Assert(sMainQueue == NULL);
    Assert(RTThreadIsMain(RTThreadSelf()));

    try
    {
        sMainQueue = new NativeEventQueue();
        AssertPtr(sMainQueue);
#ifdef VBOX_WITH_XPCOM
        /* Check that it actually is the main event queue, i.e. that
           we're called on the right thread. */
        nsCOMPtr<nsIEventQueue> q;
        nsresult rv = NS_GetMainEventQ(getter_AddRefs(q));
        AssertComRCReturn(rv, VERR_INVALID_POINTER);
        Assert(q == sMainQueue->mEventQ);

        /* Check that it's a native queue. */
        PRBool fIsNative = PR_FALSE;
        rv = sMainQueue->mEventQ->IsQueueNative(&fIsNative);
        Assert(NS_SUCCEEDED(rv) && fIsNative);
#endif // VBOX_WITH_XPCOM
    }
    catch (std::bad_alloc &ba)
    {
        NOREF(ba);
        return VERR_NO_MEMORY;
    }

    return VINF_SUCCESS;
}
Ejemplo n.º 3
0
 ~nsUrlClassifierCallbackWrapper()
 {
   nsCOMPtr<nsIEventQueue> mainEventQ;
   NS_GetMainEventQ(getter_AddRefs(mainEventQ));
   if (mainEventQ) {
     NS_ProxyRelease(mainEventQ, mInner);
   } else {
     NS_WARNING("unable to get main event queue");
   }
 }
Ejemplo n.º 4
0
int main(int argc, char **argv)
{
  if (test_common_init(&argc, &argv) != 0)
    return -1;

  if (argc < 2) {
    printf("usage: %s <url>\n", argv[0]);
    return -1;
  }

#if defined(PR_LOGGING)
  gTestLog = PR_NewLogModule("Test");
#endif

  nsresult rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
  if (NS_FAILED(rv))
    return -1;

  {
    // Create the Event Queue for this thread...
    rv = NS_GetMainEventQ(&gEventQ);
    if (NS_FAILED(rv))
      return -1;

    nsCOMPtr<nsIURI> uri;
    rv = NS_NewURI(getter_AddRefs(uri), nsDependentCString(argv[1]));
    if (NS_FAILED(rv))
      return -1;

    nsCOMPtr<nsIChannel> chan;
    rv = NS_NewChannel(getter_AddRefs(chan), uri);
    if (NS_FAILED(rv))
      return -1;

    nsCOMPtr<nsIStreamLoaderObserver> observer = new MyStreamLoaderObserver();
    if (!observer)
      return -1;

    nsCOMPtr<nsIStreamLoader> loader;
    rv = NS_NewStreamLoader(getter_AddRefs(loader), chan, observer, nsnull);
    if (NS_FAILED(rv))
      return -1;

    // Enter the message pump to allow the URL load to proceed.
    while (gKeepRunning) {
      PLEvent *e;
      gEventQ->WaitForEvent(&e);
      gEventQ->HandleEvent(e);
    }
  } // this scopes the nsCOMPtrs
  // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
  NS_ShutdownXPCOM(nsnull);
  return rv;
}
Ejemplo n.º 5
0
bool VirtualBoxBridge::initXPCOM()
{
	nsresult rc;

	/*
	 * This is the standard XPCOM init procedure.
	 * What we do is just follow the required steps to get an instance
	 * of our main interface, which is IVirtualBox.
	 *
	 * Note that we scope all nsCOMPtr variables in order to have all XPCOM
	 * objects automatically released before we call NS_ShutdownXPCOM at the
	 * end. This is an XPCOM requirement.
	 */
	rc = NS_InitXPCOM2(getter_AddRefs(nsCOM_serviceManager), nsnull, nsnull);
	if (NS_FAILED(rc))
	{
		std::cerr << "Error: XPCOM could not be initialized! rc=0x" << std::hex << rc << std::dec << std::endl;
		return false;
	}

	/*
	 * Make sure the main event queue is created. This event queue is
	 * responsible for dispatching incoming XPCOM IPC messages. The main
	 * thread should run this event queue's loop during lengthy non-XPCOM
	 * operations to ensure messages from the VirtualBox server and other
	 * XPCOM IPC clients are processed. This use case doesn't perform such
	 * operations so it doesn't run the event loop.
	 */
	rc = NS_GetMainEventQ(getter_AddRefs(nsCOM_eventQ));
	if (NS_FAILED(rc))
	{
		std::cerr << "Error: could not get main event queue! rc=0x" << std::hex << rc << std::dec << std::endl;
		return false;
	}

	/*
	 * Now XPCOM is ready and we can start to do real work.
	 * All interfaces will be retrieved from the XPCOM component manager.
	 * We use the XPCOM provided smart pointer nsCOMPtr for all objects
	 * because that's very convenient and removes the need deal with
	 * reference counting and freeing.
	 */
	rc = NS_GetComponentManager(getter_AddRefs(nsCOM_manager));
	if (NS_FAILED(rc))
	{
		std::cerr << "Error: could not get component manager! rc=0x" << std::hex << rc << std::dec << std::endl;
		return false;
	}

	return true;
}
Ejemplo n.º 6
0
/* static */
int EventQueue::init()
{
    Assert(sMainQueue == NULL);
    Assert(RTThreadIsMain(RTThreadSelf()));
    sMainQueue = new EventQueue();

#ifdef VBOX_WITH_XPCOM
    /* Check that it actually is the main event queue, i.e. that
       we're called on the right thread. */
    nsCOMPtr<nsIEventQueue> q;
    nsresult rv = NS_GetMainEventQ(getter_AddRefs(q));
    Assert(NS_SUCCEEDED(rv));
    Assert(q == sMainQueue->mEventQ);

    /* Check that it's a native queue. */
    PRBool fIsNative = PR_FALSE;
    rv = sMainQueue->mEventQ->IsQueueNative(&fIsNative);
    Assert(NS_SUCCEEDED(rv) && fIsNative);
#endif // VBOX_WITH_XPCOM

    return VINF_SUCCESS;
}
Ejemplo n.º 7
0
int main(int argc, char *argv[])
{
    /*
     * Check that PRUnichar is equal in size to what compiler composes L""
     * strings from; otherwise NS_LITERAL_STRING macros won't work correctly
     * and we will get a meaningless SIGSEGV. This, of course, must be checked
     * at compile time in xpcom/string/nsTDependentString.h, but XPCOM lacks
     * compile-time assert macros and I'm not going to add them now.
     */
    if (sizeof(PRUnichar) != sizeof(wchar_t))
    {
        printf("Error: sizeof(PRUnichar) {%lu} != sizeof(wchar_t) {%lu}!\n"
               "Probably, you forgot the -fshort-wchar compiler option.\n",
               (unsigned long) sizeof(PRUnichar),
               (unsigned long) sizeof(wchar_t));
        return -1;
    }

    nsresult rc;

    /*
     * This is the standard XPCOM init procedure.
     * What we do is just follow the required steps to get an instance
     * of our main interface, which is IVirtualBox.
     */
#if defined(XPCOM_GLUE)
    XPCOMGlueStartup(nsnull);
#endif

    /*
     * Note that we scope all nsCOMPtr variables in order to have all XPCOM
     * objects automatically released before we call NS_ShutdownXPCOM at the
     * end. This is an XPCOM requirement.
     */
    {
        nsCOMPtr<nsIServiceManager> serviceManager;
        rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), nsnull, nsnull);
        if (NS_FAILED(rc))
        {
            printf("Error: XPCOM could not be initialized! rc=0x%x\n", rc);
            return -1;
        }

#if 0
        /*
         * Register our components. This step is only necessary if this executable
         * implements XPCOM components itself which is not the case for this
         * simple example.
         */
        nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(serviceManager);
        if (!registrar)
        {
            printf("Error: could not query nsIComponentRegistrar interface!\n");
            return -1;
        }
        registrar->AutoRegister(nsnull);
#endif

        /*
         * Make sure the main event queue is created. This event queue is
         * responsible for dispatching incoming XPCOM IPC messages. The main
         * thread should run this event queue's loop during lengthy non-XPCOM
         * operations to ensure messages from the VirtualBox server and other
         * XPCOM IPC clients are processed. This use case doesn't perform such
         * operations so it doesn't run the event loop.
         */
        nsCOMPtr<nsIEventQueue> eventQ;
        rc = NS_GetMainEventQ(getter_AddRefs (eventQ));
        if (NS_FAILED(rc))
        {
            printf("Error: could not get main event queue! rc=%08X\n", rc);
            return -1;
        }

        /*
         * Now XPCOM is ready and we can start to do real work.
         * IVirtualBox is the root interface of VirtualBox and will be
         * retrieved from the XPCOM component manager. We use the
         * XPCOM provided smart pointer nsCOMPtr for all objects because
         * that's very convenient and removes the need deal with reference
         * counting and freeing.
         */
        nsCOMPtr<nsIComponentManager> manager;
        rc = NS_GetComponentManager (getter_AddRefs (manager));
        if (NS_FAILED(rc))
        {
            printf("Error: could not get component manager! rc=%08X\n", rc);
            return -1;
        }

        nsCOMPtr<IVirtualBox> virtualBox;
        rc = manager->CreateInstanceByContractID (NS_VIRTUALBOX_CONTRACTID,
                nsnull,
                NS_GET_IID(IVirtualBox),
                getter_AddRefs(virtualBox));
        if (NS_FAILED(rc))
        {
            printf("Error, could not instantiate VirtualBox object! rc=0x%x\n", rc);
            return -1;
        }
        printf("VirtualBox object created\n");

        ////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////


        listVMs(virtualBox);

        createVM(virtualBox);


        ////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////

        /* this is enough to free the IVirtualBox instance -- smart pointers rule! */
        virtualBox = nsnull;

        /*
         * Process events that might have queued up in the XPCOM event
         * queue. If we don't process them, the server might hang.
         */
        eventQ->ProcessPendingEvents();
    }

    /*
     * Perform the standard XPCOM shutdown procedure.
     */
    NS_ShutdownXPCOM(nsnull);
#if defined(XPCOM_GLUE)
    XPCOMGlueShutdown();
#endif
    printf("Done!\n");
    return 0;
}
Ejemplo n.º 8
0
HRESULT Shutdown()
{
    HRESULT rc = S_OK;

#if !defined(VBOX_WITH_XPCOM)

    /* EventQueue::uninit reference counting fun. */
    RTTHREAD hSelf = RTThreadSelf();
    if (    hSelf == gCOMMainThread
        &&  hSelf != NIL_RTTHREAD)
    {
        if (-- gCOMMainInitCount == 0)
        {
            EventQueue::uninit();
            ASMAtomicWriteHandle(&gCOMMainThread, NIL_RTTHREAD);
        }
    }

    CoUninitialize();

#else /* !defined (VBOX_WITH_XPCOM) */

    nsCOMPtr<nsIEventQueue> eventQ;
    rc = NS_GetMainEventQ(getter_AddRefs(eventQ));

    if (NS_SUCCEEDED(rc) || rc == NS_ERROR_NOT_AVAILABLE)
    {
        /* NS_ERROR_NOT_AVAILABLE seems to mean that
         * nsIEventQueue::StopAcceptingEvents() has been called (see
         * nsEventQueueService.cpp). We hope that this error code always means
         * just that in this case and assume that we're on the main thread
         * (it's a kind of unexpected behavior if a non-main thread ever calls
         * StopAcceptingEvents() on the main event queue). */

        PRBool isOnMainThread = PR_FALSE;
        if (NS_SUCCEEDED(rc))
        {
            rc = eventQ->IsOnCurrentThread(&isOnMainThread);
            eventQ = nsnull; /* early release before shutdown */
        }
        else
        {
            isOnMainThread = PR_TRUE;
            rc = NS_OK;
        }

        if (NS_SUCCEEDED(rc) && isOnMainThread)
        {
            /* only the main thread needs to uninitialize XPCOM and only if
             * init counter drops to zero */
            if (--gXPCOMInitCount == 0)
            {
                EventQueue::uninit();
                rc = NS_ShutdownXPCOM(nsnull);

                /* This is a thread initialized XPCOM and set gIsXPCOMInitialized to
                 * true. Reset it back to false. */
                bool wasInited = ASMAtomicXchgBool(&gIsXPCOMInitialized, false);
                Assert(wasInited == true);
                NOREF(wasInited);

# if defined (XPCOM_GLUE)
                XPCOMGlueShutdown();
# endif
            }
        }
    }

#endif /* !defined(VBOX_WITH_XPCOM) */

    AssertComRC(rc);

    return rc;
}
Ejemplo n.º 9
0
/**
 * Initializes the COM runtime.
 *
 * This method must be called on each thread of the client application that
 * wants to access COM facilities. The initialization must be performed before
 * calling any other COM method or attempting to instantiate COM objects.
 *
 * On platforms using XPCOM, this method uses the following scheme to search for
 * XPCOM runtime:
 *
 * 1. If the VBOX_APP_HOME environment variable is set, the path it specifies
 *    is used to search XPCOM libraries and components. If this method fails to
 *    initialize XPCOM runtime using this path, it will immediately return a
 *    failure and will NOT check for other paths as described below.
 *
 * 2. If VBOX_APP_HOME is not set, this methods tries the following paths in the
 *    given order:
 *
 *    a) Compiled-in application data directory (as returned by
 *       RTPathAppPrivateArch())
 *    b) "/usr/lib/virtualbox" (Linux only)
 *    c) "/opt/VirtualBox" (Linux only)
 *
 *    The first path for which the initialization succeeds will be used.
 *
 * On MS COM platforms, the COM runtime is provided by the system and does not
 * need to be searched for.
 *
 * Once the COM subsystem is no longer necessary on a given thread, Shutdown()
 * must be called to free resources allocated for it. Note that a thread may
 * call Initialize() several times but for each of tese calls there must be a
 * corresponding Shutdown() call.
 *
 * @return S_OK on success and a COM result code in case of failure.
 */
HRESULT Initialize(bool fGui)
{
    HRESULT rc = E_FAIL;

#if !defined(VBOX_WITH_XPCOM)

    /*
     * We initialize COM in GUI thread in STA, to be compliant with QT and
     * OLE requirments (for example to allow D&D), while other threads
     * initialized in regular MTA. To allow fast proxyless access from
     * GUI thread to COM objects, we explicitly provide our COM objects
     * with free threaded marshaller.
     * !!!!! Please think twice before touching this code !!!!!
     */
    DWORD flags = fGui ?
                  COINIT_APARTMENTTHREADED
                | COINIT_SPEED_OVER_MEMORY
                :
                  COINIT_MULTITHREADED
                | COINIT_DISABLE_OLE1DDE
                | COINIT_SPEED_OVER_MEMORY;

    rc = CoInitializeEx(NULL, flags);

    /* the overall result must be either S_OK or S_FALSE (S_FALSE means
     * "already initialized using the same apartment model") */
    AssertMsg(rc == S_OK || rc == S_FALSE, ("rc=%08X\n", rc));

    /* To be flow compatible with the XPCOM case, we return here if this isn't
     * the main thread or if it isn't its first initialization call.
     * Note! CoInitializeEx and CoUninitialize does it's own reference
     *       counting, so this exercise is entirely for the EventQueue init. */
    bool fRc;
    RTTHREAD hSelf = RTThreadSelf();
    if (hSelf != NIL_RTTHREAD)
        ASMAtomicCmpXchgHandle(&gCOMMainThread, hSelf, NIL_RTTHREAD, fRc);
    else
        fRc = false;

    if (fGui)
        Assert(RTThreadIsMain(hSelf));

    if (!fRc)
    {
        if (   gCOMMainThread == hSelf
            && SUCCEEDED(rc))
            gCOMMainInitCount++;

        AssertComRC(rc);
        return rc;
    }
    Assert(RTThreadIsMain(hSelf));

    /* this is the first main thread initialization */
    Assert(gCOMMainInitCount == 0);
    if (SUCCEEDED(rc))
        gCOMMainInitCount = 1;

#else /* !defined (VBOX_WITH_XPCOM) */

    /* Unused here */
    NOREF(fGui);

    if (ASMAtomicXchgBool(&gIsXPCOMInitialized, true) == true)
    {
        /* XPCOM is already initialized on the main thread, no special
         * initialization is necessary on additional threads. Just increase
         * the init counter if it's a main thread again (to correctly support
         * nested calls to Initialize()/Shutdown() for compatibility with
         * Win32). */

        nsCOMPtr<nsIEventQueue> eventQ;
        rc = NS_GetMainEventQ(getter_AddRefs(eventQ));

        if (NS_SUCCEEDED(rc))
        {
            PRBool isOnMainThread = PR_FALSE;
            rc = eventQ->IsOnCurrentThread(&isOnMainThread);
            if (NS_SUCCEEDED(rc) && isOnMainThread)
                ++gXPCOMInitCount;
        }

        AssertComRC(rc);
        return rc;
    }
    Assert(RTThreadIsMain(RTThreadSelf()));

    /* this is the first initialization */
    gXPCOMInitCount = 1;
    bool const fInitEventQueues = true;

    /* prepare paths for registry files */
    char szCompReg[RTPATH_MAX];
    char szXptiDat[RTPATH_MAX];

    int vrc = GetVBoxUserHomeDirectory(szCompReg, sizeof(szCompReg));
    AssertRCReturn(vrc, NS_ERROR_FAILURE);
    strcpy(szXptiDat, szCompReg);

    vrc = RTPathAppend(szCompReg, sizeof(szCompReg), "compreg.dat");
    AssertRCReturn(vrc, NS_ERROR_FAILURE);
    vrc = RTPathAppend(szXptiDat, sizeof(szXptiDat), "xpti.dat");
    AssertRCReturn(vrc, NS_ERROR_FAILURE);

    LogFlowFunc(("component registry  : \"%s\"\n", szCompReg));
    LogFlowFunc(("XPTI data file      : \"%s\"\n", szXptiDat));

#if defined (XPCOM_GLUE)
    XPCOMGlueStartup(nsnull);
#endif

    static const char *kAppPathsToProbe[] =
    {
        NULL, /* 0: will use VBOX_APP_HOME */
        NULL, /* 1: will try RTPathAppPrivateArch() */
#ifdef RT_OS_LINUX
        "/usr/lib/virtualbox",
        "/opt/VirtualBox",
#elif RT_OS_SOLARIS
        "/opt/VirtualBox/amd64",
        "/opt/VirtualBox/i386",
#elif RT_OS_DARWIN
        "/Application/VirtualBox.app/Contents/MacOS",
#endif
    };

    /* Find out the directory where VirtualBox binaries are located */
    for (size_t i = 0; i < RT_ELEMENTS(kAppPathsToProbe); ++ i)
    {
        char szAppHomeDir[RTPATH_MAX];

        if (i == 0)
        {
            /* Use VBOX_APP_HOME if present */
            vrc = RTEnvGetEx(RTENV_DEFAULT, "VBOX_APP_HOME", szAppHomeDir, sizeof(szAppHomeDir), NULL);
            if (vrc == VERR_ENV_VAR_NOT_FOUND)
                continue;
            AssertRC(vrc);
        }
        else if (i == 1)
        {
            /* Use RTPathAppPrivateArch() first */
            vrc = RTPathAppPrivateArch(szAppHomeDir, sizeof(szAppHomeDir));
            AssertRC(vrc);
        }
        else
        {
            /* Iterate over all other paths */
            szAppHomeDir[RTPATH_MAX - 1] = '\0';
            strncpy(szAppHomeDir, kAppPathsToProbe[i], RTPATH_MAX - 1);
            vrc = VINF_SUCCESS;
        }
        if (RT_FAILURE(vrc))
        {
            rc = NS_ERROR_FAILURE;
            continue;
        }

        char szCompDir[RTPATH_MAX];
        vrc = RTPathAppend(strcpy(szCompDir, szAppHomeDir), sizeof(szCompDir), "components");
        if (RT_FAILURE(vrc))
        {
            rc = NS_ERROR_FAILURE;
            continue;
        }
        LogFlowFunc(("component directory : \"%s\"\n", szCompDir));

        nsCOMPtr<DirectoryServiceProvider> dsProv;
        dsProv = new DirectoryServiceProvider();
        if (dsProv)
            rc = dsProv->init(szCompReg, szXptiDat, szCompDir, szAppHomeDir);
        else
            rc = NS_ERROR_OUT_OF_MEMORY;
        if (NS_FAILED(rc))
            break;

        /* Setup the application path for NS_InitXPCOM2. Note that we properly
         * answer the NS_XPCOM_CURRENT_PROCESS_DIR query in our directory
         * service provider but it seems to be activated after the directory
         * service is used for the first time (see the source NS_InitXPCOM2). So
         * use the same value here to be on the safe side. */
        nsCOMPtr <nsIFile> appDir;
        {
            char *appDirCP = NULL;
            vrc = RTStrUtf8ToCurrentCP(&appDirCP, szAppHomeDir);
            if (RT_SUCCESS(vrc))
            {
                nsCOMPtr<nsILocalFile> file;
                rc = NS_NewNativeLocalFile(nsEmbedCString(appDirCP),
                                           PR_FALSE, getter_AddRefs(file));
                if (NS_SUCCEEDED(rc))
                    appDir = do_QueryInterface(file, &rc);

                RTStrFree(appDirCP);
            }
            else
                rc = NS_ERROR_FAILURE;
        }
        if (NS_FAILED(rc))
            break;

        /* Set VBOX_XPCOM_HOME to the same app path to make XPCOM sources that
         * still use it instead of the directory service happy */
        vrc = RTEnvSetEx(RTENV_DEFAULT, "VBOX_XPCOM_HOME", szAppHomeDir);
        AssertRC(vrc);

        /* Finally, initialize XPCOM */
        {
            nsCOMPtr<nsIServiceManager> serviceManager;
            rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), appDir, dsProv);
            if (NS_SUCCEEDED(rc))
            {
                nsCOMPtr<nsIComponentRegistrar> registrar =
                    do_QueryInterface(serviceManager, &rc);
                if (NS_SUCCEEDED(rc))
                {
                    rc = registrar->AutoRegister(nsnull);
                    if (NS_SUCCEEDED(rc))
                    {
                        /* We succeeded, stop probing paths */
                        LogFlowFunc(("Succeeded.\n"));
                        break;
                    }
                }
            }
        }

        /* clean up before the new try */
        rc = NS_ShutdownXPCOM(nsnull);

        if (i == 0)
        {
            /* We failed with VBOX_APP_HOME, don't probe other paths */
            break;
        }
    }

#endif /* !defined (VBOX_WITH_XPCOM) */

    // for both COM and XPCOM, we only get here if this is the main thread;
    // only then initialize the autolock system (AutoLock.cpp)
    Assert(RTThreadIsMain(RTThreadSelf()));
    util::InitAutoLockSystem();

    AssertComRC(rc);

    /*
     * Init the main event queue (ASSUMES it cannot fail).
     */
    if (SUCCEEDED(rc))
        EventQueue::init();

    return rc;
}
Ejemplo n.º 10
0
/** entry point */
int main(int argc, char *argv[])
{
    const char *uuid = NULL;
    int c;
    int listHostModes = 0;
    int quit = 0;
    const struct option options[] =
    {
        { "help",          no_argument,       NULL, 'h' },
        { "startvm",       required_argument, NULL, 's' },
        { "fixedres",      required_argument, NULL, 'f' },
        { "listhostmodes", no_argument,       NULL, 'l' },
        { "scale",         no_argument,       NULL, 'c' }
    };

    printf("VirtualBox DirectFB GUI built %s %s\n"
           "(C) 2004-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
           "(C) 2004-2005 secunet Security Networks AG\n", __DATE__, __TIME__);

    for (;;)
    {
        c = getopt_long(argc, argv, "s:", options, NULL);
        if (c == -1)
            break;
        switch (c)
        {
            case 'h':
            {
                showusage();
                exit(0);
                break;
            }
            case 's':
            {
                // UUID as string, parse it
                RTUUID buuid;
                if (!RT_SUCCESS(RTUuidFromStr((PRTUUID)&buuid, optarg)))
                {
                    printf("Error, invalid UUID format given!\n");
                    showusage();
                    exit(-1);
                }
                uuid = optarg;
                break;
            }
            case 'f':
            {
                if (sscanf(optarg, "%ux%ux%u", &fixedVideoMode.width, &fixedVideoMode.height,
                           &fixedVideoMode.bpp) != 3)
                {
                    printf("Error, invalid resolution argument!\n");
                    showusage();
                    exit(-1);
                }
                useFixedVideoMode = 1;
                break;
            }
            case 'l':
            {
                listHostModes = 1;
                break;
            }
            case 'c':
            {
                scaleGuest = 1;
                break;
            }
            default:
                break;
        }
    }

    // check if we got a UUID
    if (!uuid)
    {
        printf("Error, no UUID given!\n");
        showusage();
        exit(-1);
    }


    /**
     * XPCOM setup
     */

    nsresult rc;
    /*
     * Note that we scope all nsCOMPtr variables in order to have all XPCOM
     * objects automatically released before we call NS_ShutdownXPCOM at the
     * end. This is an XPCOM requirement.
     */
    {
        nsCOMPtr<nsIServiceManager> serviceManager;
        rc = NS_InitXPCOM2(getter_AddRefs(serviceManager), nsnull, nsnull);
        if (NS_FAILED(rc))
        {
            printf("Error: XPCOM could not be initialized! rc=0x%x\n", rc);
            exit(-1);
        }

        // register our component
        nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(serviceManager);
        if (!registrar)
        {
            printf("Error: could not query nsIComponentRegistrar interface!\n");
            exit(-1);
        }
        registrar->AutoRegister(nsnull);

        /*
         * Make sure the main event queue is created. This event queue is
         * responsible for dispatching incoming XPCOM IPC messages. The main
         * thread should run this event queue's loop during lengthy non-XPCOM
         * operations to ensure messages from the VirtualBox server and other
         * XPCOM IPC clients are processed. This use case doesn't perform such
         * operations so it doesn't run the event loop.
         */
        nsCOMPtr<nsIEventQueue> eventQ;
        rc = NS_GetMainEventQ(getter_AddRefs (eventQ));
        if (NS_FAILED(rc))
        {
            printf("Error: could not get main event queue! rc=%08X\n", rc);
            return -1;
        }

        /*
         * Now XPCOM is ready and we can start to do real work.
         * IVirtualBox is the root interface of VirtualBox and will be
         * retrieved from the XPCOM component manager. We use the
         * XPCOM provided smart pointer nsCOMPtr for all objects because
         * that's very convenient and removes the need deal with reference
         * counting and freeing.
         */
        nsCOMPtr<nsIComponentManager> manager;
        rc = NS_GetComponentManager (getter_AddRefs (manager));
        if (NS_FAILED(rc))
        {
            printf("Error: could not get component manager! rc=%08X\n", rc);
            exit(-1);
        }

        nsCOMPtr<IVirtualBox> virtualBox;
        rc = manager->CreateInstanceByContractID(NS_VIRTUALBOX_CONTRACTID,
                                                 nsnull,
                                                 NS_GET_IID(IVirtualBox),
                                                 getter_AddRefs(virtualBox));
        if (NS_FAILED(rc))
        {
            printf("Error, could not instantiate object! rc=0x%x\n", rc);
            exit(-1);
        }

        nsCOMPtr<ISession> session;
        rc = manager->CreateInstance(CLSID_Session,
                                     nsnull,
                                     NS_GET_IID(ISession),
                                     getter_AddRefs(session));
        if (NS_FAILED(rc))
        {
            printf("Error: could not instantiate Session object! rc = %08X\n", rc);
            exit(-1);
        }

        // open session for this VM
        rc = virtualBox->OpenSession(session, NS_ConvertUTF8toUTF16(uuid).get());
        if (NS_FAILED(rc))
        {
            printf("Error: given machine not found!\n");
            exit(-1);
        }
        nsCOMPtr<IMachine> machine;
        session->GetMachine(getter_AddRefs(machine));
        if (!machine)
        {
            printf("Error: given machine not found!\n");
            exit(-1);
        }
        nsCOMPtr<IConsole> console;
        session->GetConsole(getter_AddRefs(console));
        if (!console)
        {
            printf("Error: cannot get console!\n");
            exit(-1);
        }

        nsCOMPtr<IDisplay> display;
        console->GetDisplay(getter_AddRefs(display));
        if (!display)
        {
            printf("Error: could not get display object!\n");
            exit(-1);
        }

        nsCOMPtr<IKeyboard> keyboard;
        nsCOMPtr<IMouse> mouse;
        VBoxDirectFB *frameBuffer = NULL;

        /**
         * Init DirectFB
         */
        IDirectFB *dfb = NULL;
        IDirectFBSurface *surface = NULL;
        IDirectFBInputDevice *dfbKeyboard = NULL;
        IDirectFBInputDevice *dfbMouse = NULL;
        IDirectFBEventBuffer *dfbEventBuffer = NULL;
        DFBSurfaceDescription dsc;
        int screen_width, screen_height;

        DFBCHECK(DirectFBInit(&argc, &argv));
        DFBCHECK(DirectFBCreate(&dfb));
        DFBCHECK(dfb->SetCooperativeLevel(dfb, DFSCL_FULLSCREEN));
        // populate our structure of supported video modes
        DFBCHECK(dfb->EnumVideoModes(dfb, enumVideoModesHandler, NULL));

        if (listHostModes)
        {
            printf("*****************************************************\n");
            printf("Number of available host video modes: %u\n", numVideoModes);
            for (uint32_t i = 0; i < numVideoModes; i++)
            {
                printf("Mode %u: xres = %u, yres = %u, bpp = %u\n", i,
                       videoModes[i].width, videoModes[i].height, videoModes[i].bpp);
            }
            printf("Note: display modes with bpp < have been filtered out\n");
            printf("*****************************************************\n");
            goto Leave;
        }

        if (useFixedVideoMode)
        {
            int32_t bestVideoMode = getBestVideoMode(fixedVideoMode.width,
                                                     fixedVideoMode.height,
                                                     fixedVideoMode.bpp);
            // validate the fixed mode
            if ((bestVideoMode == -1) ||
                ((fixedVideoMode.width  != videoModes[bestVideoMode].width) ||
                (fixedVideoMode.height != videoModes[bestVideoMode].height) ||
                (fixedVideoMode.bpp    != videoModes[bestVideoMode].bpp)))
            {
                printf("Error: the specified fixed video mode is not available!\n");
                exit(-1);
            }
        } else
        {
            initialVideoMode = getBestVideoMode(640, 480, 16);
            if (initialVideoMode == -1)
            {
                printf("Error: initial video mode 640x480x16 is not available!\n");
                exit(-1);
            }
        }

        dsc.flags = DSDESC_CAPS;
        dsc.caps = DSCAPS_PRIMARY;
        DFBCHECK(dfb->CreateSurface(dfb, &dsc, &surface));
        DFBCHECK(surface->Clear(surface, 0, 0, 0, 0));
        DFBCHECK(surface->GetSize(surface, &screen_width, &screen_height));
        DFBCHECK(dfb->GetInputDevice(dfb, DIDID_KEYBOARD, &dfbKeyboard));
        DFBCHECK(dfbKeyboard->CreateEventBuffer(dfbKeyboard, &dfbEventBuffer));
        DFBCHECK(dfb->GetInputDevice(dfb, DIDID_MOUSE, &dfbMouse));
        DFBCHECK(dfbMouse->AttachEventBuffer(dfbMouse, dfbEventBuffer));


        if (useFixedVideoMode)
        {
            printf("Information: setting video mode to %ux%ux%u\n", fixedVideoMode.width,
                   fixedVideoMode.height, fixedVideoMode.bpp);
            DFBCHECK(dfb->SetVideoMode(dfb, fixedVideoMode.width,
                                       fixedVideoMode.height, fixedVideoMode.bpp));
        } else
        {
            printf("Information: starting with default video mode %ux%ux%u\n",
                   videoModes[initialVideoMode].width, videoModes[initialVideoMode].height,
                   videoModes[initialVideoMode].bpp);
            DFBCHECK(dfb->SetVideoMode(dfb, videoModes[initialVideoMode].width,
                                            videoModes[initialVideoMode].height,
                                            videoModes[initialVideoMode].bpp));
        }

        // register our framebuffer
        frameBuffer = new VBoxDirectFB(dfb, surface);
        display->SetFramebuffer(0, frameBuffer);

        /**
         * Start the VM execution thread
         */
        console->PowerUp(NULL);

        console->GetKeyboard(getter_AddRefs(keyboard));
        console->GetMouse(getter_AddRefs(mouse));

        /**
         * Main event loop
         */
        #define MAX_KEYEVENTS 10
        PRInt32 keyEvents[MAX_KEYEVENTS];
        int numKeyEvents;

        while (!quit)
        {
            DFBInputEvent event;

            numKeyEvents = 0;
            DFBCHECK(dfbEventBuffer->WaitForEvent(dfbEventBuffer));
            while (dfbEventBuffer->GetEvent(dfbEventBuffer, DFB_EVENT(&event)) == DFB_OK)
            {
                int mouseXDelta = 0;
                int mouseYDelta = 0;
                int mouseZDelta = 0;
                switch (event.type)
                {
                    #define QUEUEEXT() keyEvents[numKeyEvents++] = 0xe0
                    #define QUEUEKEY(scan) keyEvents[numKeyEvents++] = scan | (event.type == DIET_KEYRELEASE ? 0x80 : 0x00)
                    #define QUEUEKEYRAW(scan) keyEvents[numKeyEvents++] = scan
                    case DIET_KEYPRESS:
                    case DIET_KEYRELEASE:
                    {
                        // @@@AH development hack to get out of it!
                        if ((event.key_id == DIKI_ESCAPE) && (event.modifiers & (DIMM_CONTROL | DIMM_ALT)))
                            quit = 1;

                        if (numKeyEvents < MAX_KEYEVENTS)
                        {
                            //printf("%s: key_code: 0x%x\n", event.type == DIET_KEYPRESS ? "DIET_KEYPRESS" : "DIET_KEYRELEASE", event.key_code);
                            switch ((uint32_t)event.key_id)
                            {
                                case DIKI_CONTROL_R:
                                    QUEUEEXT();
                                    QUEUEKEY(0x1d);
                                    break;
                                case DIKI_INSERT:
                                    QUEUEEXT();
                                    QUEUEKEY(0x52);
                                    break;
                                case DIKI_DELETE:
                                    QUEUEEXT();
                                    QUEUEKEY(0x53);
                                    break;
                                case DIKI_HOME:
                                    QUEUEEXT();
                                    QUEUEKEY(0x47);
                                    break;
                                case DIKI_END:
                                    QUEUEEXT();
                                    QUEUEKEY(0x4f);
                                    break;
                                case DIKI_PAGE_UP:
                                    QUEUEEXT();
                                    QUEUEKEY(0x49);
                                    break;
                                case DIKI_PAGE_DOWN:
                                    QUEUEEXT();
                                    QUEUEKEY(0x51);
                                    break;
                                case DIKI_LEFT:
                                    QUEUEEXT();
                                    QUEUEKEY(0x4b);
                                    break;
                                case DIKI_RIGHT:
                                    QUEUEEXT();
                                    QUEUEKEY(0x4d);
                                    break;
                                case DIKI_UP:
                                    QUEUEEXT();
                                    QUEUEKEY(0x48);
                                    break;
                                case DIKI_DOWN:
                                    QUEUEEXT();
                                    QUEUEKEY(0x50);
                                    break;
                                case DIKI_KP_DIV:
                                    QUEUEEXT();
                                    QUEUEKEY(0x35);
                                    break;
                                case DIKI_KP_ENTER:
                                    QUEUEEXT();
                                    QUEUEKEY(0x1c);
                                    break;
                                case DIKI_PRINT:
                                    // the break code is inverted!
                                    if (event.type == DIET_KEYPRESS)
                                    {
                                        QUEUEEXT();
                                        QUEUEKEY(0x2a);
                                        QUEUEEXT();
                                        QUEUEKEY(0x37);
                                    } else
                                    {
                                        QUEUEEXT();
                                        QUEUEKEY(0x37);
                                        QUEUEEXT();
                                        QUEUEKEY(0x2a);
                                    }
                                    break;
                                case DIKI_PAUSE:
                                    // This is a super weird key. No break code and a 6 byte
                                    // combination.
                                    if (event.type == DIET_KEYPRESS)
                                    {
                                        QUEUEKEY(0xe1);
                                        QUEUEKEY(0x1d);
                                        QUEUEKEY(0x45);
                                        QUEUEKEY(0xe1);
                                        QUEUEKEY(0x9d);
                                        QUEUEKEY(0xc5);
                                    }
                                    break;
                                case DIKI_META_L:
                                    // the left Windows logo is a bit different
                                    if (event.type == DIET_KEYPRESS)
                                    {
                                        QUEUEEXT();
                                        QUEUEKEYRAW(0x1f);
                                    } else
                                    {
                                        QUEUEEXT();
                                        QUEUEKEYRAW(0xf0);
                                        QUEUEKEYRAW(0x1f);
                                    }
                                    break;
                                case DIKI_META_R:
                                    // the right Windows logo is a bit different
                                    if (event.type == DIET_KEYPRESS)
                                    {
                                        QUEUEEXT();
                                        QUEUEKEYRAW(0x27);
                                    } else
                                    {
                                        QUEUEEXT();
                                        QUEUEKEYRAW(0xf0);
                                        QUEUEKEYRAW(0x27);
                                    }
                                    break;
                                case DIKI_SUPER_R:
                                    // the popup menu is a bit different
                                    if (event.type == DIET_KEYPRESS)
                                    {
                                        QUEUEEXT();
                                        QUEUEKEYRAW(0x2f);
                                    } else
                                    {
                                        QUEUEEXT();
                                        QUEUEKEYRAW(0xf0);
                                        QUEUEKEYRAW(0x2f);
                                    }
                                    break;

                                default:
                                    // check if we got a hardware scancode
                                    if (event.key_code != -1)
                                    {
                                        // take the scancode from DirectFB as is
                                        QUEUEKEY(event.key_code);
                                    } else
                                    {
                                        // XXX need extra handling!
                                    }
                            }
                        }
                        break;
                    }
                    #undef QUEUEEXT
                    #undef QUEUEKEY
                    #undef QUEUEKEYRAW

                    case DIET_AXISMOTION:
                    {
                        switch (event.axis)
                        {
                            case DIAI_X:
                                mouseXDelta += event.axisrel;
                                break;
                            case DIAI_Y:
                                mouseYDelta += event.axisrel;
                                break;
                            case DIAI_Z:
                                mouseZDelta += event.axisrel;
                                break;
                            default:
                                break;
                        }
                        // fall through
                    }
                    case DIET_BUTTONPRESS:
                        // fall through;
                    case DIET_BUTTONRELEASE:
                    {
                        int buttonState = 0;
                        if (event.buttons & DIBM_LEFT)
                            buttonState |= MouseButtonState::LeftButton;
                        if (event.buttons & DIBM_RIGHT)
                            buttonState |= MouseButtonState::RightButton;
                        if (event.buttons & DIBM_MIDDLE)
                            buttonState |= MouseButtonState::MiddleButton;
                        mouse->PutMouseEvent(mouseXDelta, mouseYDelta, mouseZDelta,
                                             buttonState);
                        break;
                    }
                    default:
                        break;
                }
            }
            // did we get any keyboard events?
            if (numKeyEvents > 0)
            {
                uint32_t codesStored;
                if (numKeyEvents > 1)
                {
                    keyboard->PutScancodes(numKeyEvents, keyEvents,
                                           &codesStored);
                } else
                {
                    keyboard->PutScancode(keyEvents[0]);
                }
            }
        }
        {
            nsCOMPtr<IProgress> progress;
            console->PowerDown(getter_AddRefs(progress));
            progress->WaitForCompletion(-1);
        }
    }

Leave:
    /*
     * Perform the standard XPCOM shutdown procedure.
     */
    NS_ShutdownXPCOM(nsnull);

    return 0;
}