Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 49905)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 49906)
@@ -936,5 +936,5 @@
 $(VBOX_IDL_FILE.MSCOM): $(VBOX_PATH_MAIN_SRC)/idl/midl.xsl $(VBOX_XIDL_FILE) | $$(dir $$@)
 	$(call MSG_TOOL,xsltproc,VBoxSVC,$<,$@)
-	$(QUIET)$(VBOX_XSLTPROC) -o $@ $< $(VBOX_XIDL_FILE)
+	$(QUIET)$(VBOX_XSLTPROC) -o $@ $(if $(VBOX_WITH_MIDL_PROXY_STUB),-stringparam g_fGenProxy yes,) $< $(VBOX_XIDL_FILE)
 
 # Aliases for testing purposes.
Index: /trunk/src/VBox/Main/idl/midl.xsl
===================================================================
--- /trunk/src/VBox/Main/idl/midl.xsl	(revision 49905)
+++ /trunk/src/VBox/Main/idl/midl.xsl	(revision 49906)
@@ -21,4 +21,7 @@
 
 <xsl:strip-space elements="*"/>
+
+<!-- Whether to generate proxy code and type library ('yes'), or just the type-library. -->
+<xsl:param name="g_fGenProxy" select="'no'"/>
 
 
@@ -144,5 +147,21 @@
  *  libraries
 -->
-<xsl:template match="library">[
+<xsl:template match="library">
+  <xsl:if test="$g_fGenProxy = 'yes'">
+    <!-- Declare everything outside the library and then reference these
+         from inside the library statement.  See:
+         http://msdn.microsoft.com/en-us/library/windows/desktop/aa366841(v=vs.85).aspx -->
+    <xsl:text>&#x0A;</xsl:text>
+    <!-- forward declarations -->
+    <xsl:apply-templates select="if | interface" mode="forward"/>
+    <xsl:text>&#x0A;</xsl:text>
+    <!-- all enums go first -->
+    <xsl:apply-templates select="enum | if/enum"/>
+    <!-- everything else but result codes and enums -->
+    <xsl:apply-templates select="*[not(self::result or self::enum) and
+                                   not(self::if[result] or self::if[enum])]"/>
+  </xsl:if>
+
+[
     uuid(<xsl:value-of select="@uuid"/>),
     version(<xsl:value-of select="@version"/>),
@@ -161,9 +180,17 @@
   <xsl:apply-templates select="if | interface" mode="forward"/>
   <xsl:text>&#x0A;</xsl:text>
-  <!-- all enums go first -->
-  <xsl:apply-templates select="enum | if/enum"/>
-  <!-- everything else but result codes and enums -->
-  <xsl:apply-templates select="*[not(self::result or self::enum) and
-                                 not(self::if[result] or self::if[enum])]"/>
+  <xsl:choose>
+    <xsl:when test="$g_fGenProxy = 'yes'">
+      <!-- all enums go first -->
+      <xsl:apply-templates select="enum | if/enum" mode="forward"/>
+    </xsl:when>
+    <xsl:otherwise>
+      <!-- all enums go first -->
+      <xsl:apply-templates select="enum | if/enum"/>
+      <!-- everything else but result codes and enums -->
+      <xsl:apply-templates select="*[not(self::result or self::enum) and
+                                     not(self::if[result] or self::if[enum])]"/>
+    </xsl:otherwise>
+  </xsl:choose>
   <!-- -->
   <xsl:text>}; /* library </xsl:text>
@@ -190,4 +217,11 @@
   <xsl:value-of select="@name"/>
   <xsl:text>;&#x0A;</xsl:text>
+</xsl:template>
+
+
+<xsl:template match="enum" mode="forward">
+  <xsl:text>enum </xsl:text>
+  <xsl:value-of select="@name"/>
+  <xsl:text>;&#x0A;&#x0A;</xsl:text>
 </xsl:template>
 
Index: /trunk/src/VBox/Main/testcase/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/testcase/Makefile.kmk	(revision 49905)
+++ /trunk/src/VBox/Main/testcase/Makefile.kmk	(revision 49906)
@@ -26,14 +26,15 @@
  if defined(VBOX_WITH_TESTCASES)
   PROGRAMS       += \
-	tstAPI \
-	$(if $(VBOX_OSE),,tstOVF) \
-	$(if $(VBOX_WITH_XPCOM),tstVBoxAPIXPCOM,tstVBoxAPIWin) \
-	$(if $(VBOX_WITH_RESOURCE_USAGE_API),tstCollector,) \
-	$(if $(VBOX_WITH_GUEST_CONTROL),tstGuestCtrlParseBuffer,) \
-	$(if $(VBOX_WITH_GUEST_CONTROL),tstGuestCtrlContextID,) \
-	tstMediumLock \
-	tstMouseImpl
+  	tstAPI \
+  	tstVBoxAPIPerf \
+  	$(if $(VBOX_OSE),,tstOVF) \
+  	$(if $(VBOX_WITH_XPCOM),tstVBoxAPIXPCOM,tstVBoxAPIWin) \
+  	$(if $(VBOX_WITH_RESOURCE_USAGE_API),tstCollector,) \
+  	$(if $(VBOX_WITH_GUEST_CONTROL),tstGuestCtrlParseBuffer,) \
+  	$(if $(VBOX_WITH_GUEST_CONTROL),tstGuestCtrlContextID,) \
+  	tstMediumLock \
+  	tstMouseImpl
   PROGRAMS.linux += \
-	$(if $(VBOX_WITH_USB),tstUSBProxyLinux,)
+  	$(if $(VBOX_WITH_USB),tstUSBProxyLinux,)
  endif # !VBOX_WITH_TESTCASES
 endif # !VBOX_ONLY_SDK
@@ -65,4 +66,11 @@
 tstAPI_SOURCES  = tstAPI.cpp
 
+
+#
+# tstVBoxAPIPerf
+#
+tstVBoxAPIPerf_TEMPLATE = VBOXMAINCLIENTTSTEXE
+tstVBoxAPIPerf_SOURCES  = \
+	tstVBoxAPIPerf.cpp
 
 #
Index: /trunk/src/VBox/Main/testcase/tstVBoxAPIPerf.cpp
===================================================================
--- /trunk/src/VBox/Main/testcase/tstVBoxAPIPerf.cpp	(revision 49906)
+++ /trunk/src/VBox/Main/testcase/tstVBoxAPIPerf.cpp	(revision 49906)
@@ -0,0 +1,206 @@
+/* $Id$ */
+/** @file
+ * tstVBoxAPIPerf - Checks the performance of the COM / XPOM API.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <VBox/com/com.h>
+#include <VBox/com/string.h>
+#include <VBox/com/array.h>
+#include <VBox/com/Guid.h>
+#include <VBox/com/ErrorInfo.h>
+#include <VBox/com/VirtualBox.h>
+
+#include <iprt/test.h>
+#include <iprt/time.h>
+
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+static RTTEST g_hTest;
+
+
+/** Worker fro TST_COM_EXPR(). */
+static HRESULT tstComExpr(HRESULT hrc, const char *pszOperation, int iLine)
+{
+    if (FAILED(hrc))
+        RTTestFailed(g_hTest, "%s failed on line %u with hrc=%Rhrc", pszOperation, iLine, hrc);
+    return hrc;
+}
+
+/** Macro that executes the given expression and report any failure.
+ *  The expression must return a HRESULT. */
+#define TST_COM_EXPR(expr) tstComExpr(expr, #expr, __LINE__)
+
+
+
+static void tstApiPrf1(IVirtualBox *pVBox)
+{
+    RTTestSub(g_hTest, "IVirtualBox::Revision performance");
+
+    uint32_t const cCalls   = 65536;
+    uint32_t       cLeft    = cCalls;
+    uint64_t       uStartTS = RTTimeNanoTS();
+    while (cLeft-- > 0)
+    {
+        ULONG uRev;
+        HRESULT hrc = pVBox->COMGETTER(Revision)(&uRev);
+        if (FAILED(hrc))
+        {
+            tstComExpr(hrc, "IVirtualBox::Revision", __LINE__);
+            return;
+        }
+    }
+    uint64_t uElapsed = RTTimeNanoTS() - uStartTS;
+    RTTestValue(g_hTest, "IVirtualBox::Revision average", uElapsed / cCalls, RTTESTUNIT_NS_PER_CALL);
+    RTTestSubDone(g_hTest);
+}
+
+
+static void tstApiPrf2(IVirtualBox *pVBox)
+{
+    RTTestSub(g_hTest, "IVirtualBox::Version performance");
+
+    uint32_t const cCalls   = 65536;
+    uint32_t       cLeft    = cCalls;
+    uint64_t       uStartTS = RTTimeNanoTS();
+    while (cLeft-- > 0)
+    {
+        com::Bstr bstrVersion;
+        HRESULT hrc = pVBox->COMGETTER(Version)(bstrVersion.asOutParam());
+        if (FAILED(hrc))
+        {
+            tstComExpr(hrc, "IVirtualBox::Version", __LINE__);
+            return;
+        }
+    }
+    uint64_t uElapsed = RTTimeNanoTS() - uStartTS;
+    RTTestValue(g_hTest, "IVirtualBox::Version average", uElapsed / cCalls, RTTESTUNIT_NS_PER_CALL);
+    RTTestSubDone(g_hTest);
+}
+
+
+static void tstApiPrf3(IVirtualBox *pVBox)
+{
+    RTTestSub(g_hTest, "IVirtualBox::Host performance");
+
+    /* The first call. */
+    uint64_t    uStartTS = RTTimeNanoTS();
+    IHost      *pHost = NULL;
+    HRESULT     hrc = pVBox->COMGETTER(Host)(&pHost);
+    if (FAILED(hrc))
+    {
+        tstComExpr(hrc, "IVirtualBox::Host", __LINE__);
+        return;
+    }
+    pHost->Release();
+    uint64_t uElapsed = RTTimeNanoTS() - uStartTS;
+    RTTestValue(g_hTest, "IVirtualBox::Host first", uElapsed, RTTESTUNIT_NS);
+
+    /* Subsequent calls. */
+    uint32_t const cCalls1  = 4096;
+    uint32_t       cLeft    = cCalls1;
+    uStartTS = RTTimeNanoTS();
+    while (cLeft-- > 0)
+    {
+        IHost *pHost2 = NULL;
+        hrc = pVBox->COMGETTER(Host)(&pHost2);
+        if (FAILED(hrc))
+        {
+            tstComExpr(hrc, "IVirtualBox::Host", __LINE__);
+            return;
+        }
+        pHost2->Release();
+    }
+    uElapsed = RTTimeNanoTS() - uStartTS;
+    RTTestValue(g_hTest, "IVirtualBox::Host average", uElapsed / cCalls1, RTTESTUNIT_NS_PER_CALL);
+
+    /* Keep a reference around and see how that changes things.
+       Note! VBoxSVC is not creating and destroying Host().  */
+    pHost = NULL;
+    hrc = pVBox->COMGETTER(Host)(&pHost);
+
+    uint32_t const cCalls2  = 16384;
+    cLeft    = cCalls2;
+    uStartTS = RTTimeNanoTS();
+    while (cLeft-- > 0)
+    {
+        IHost *pHost2 = NULL;
+        hrc = pVBox->COMGETTER(Host)(&pHost2);
+        if (FAILED(hrc))
+        {
+            tstComExpr(hrc, "IVirtualBox::Host", __LINE__);
+            pHost->Release();
+            return;
+        }
+        pHost2->Release();
+    }
+    uElapsed = RTTimeNanoTS() - uStartTS;
+    RTTestValue(g_hTest, "IVirtualBox::Host 2nd ref", uElapsed / cCalls2, RTTESTUNIT_NS_PER_CALL);
+    pHost->Release();
+
+    RTTestSubDone(g_hTest);
+}
+
+
+
+int main(int argc, char **argv)
+{
+    /*
+     * Initialization.
+     */
+    RTEXITCODE rcExit = RTTestInitAndCreate("tstVBoxAPIPerf", &g_hTest);
+    if (rcExit != RTEXITCODE_SUCCESS)
+        return rcExit;
+    RTTestBanner(g_hTest);
+
+    RTTestSub(g_hTest, "Initializing COM and singletons");
+    HRESULT hrc = com::Initialize();
+    if (SUCCEEDED(hrc))
+    {
+        ComPtr<IVirtualBox> ptrVBox;
+        hrc = TST_COM_EXPR(ptrVBox.createLocalObject(CLSID_VirtualBox));
+        if (SUCCEEDED(hrc))
+        {
+            ComPtr<ISession> ptrSession;
+            hrc = TST_COM_EXPR(ptrSession.createInprocObject(CLSID_Session));
+            if (SUCCEEDED(hrc))
+            {
+                RTTestSubDone(g_hTest);
+
+                /*
+                 * Call test functions.
+                 */
+                tstApiPrf1(ptrVBox);
+                tstApiPrf2(ptrVBox);
+                tstApiPrf3(ptrVBox);
+
+                /** @todo Find something that returns a 2nd instance of an interface and see
+                 *        how if wrapper stuff is reused in any way. */
+            }
+        }
+
+        com::Shutdown();
+    }
+    else
+        RTTestIFailed("com::Initialize failed with hrc=%Rhrc", hrc);
+    return RTTestSummaryAndDestroy(g_hTest);
+}
+
