Index: /trunk/Config.kmk
===================================================================
--- /trunk/Config.kmk	(revision 47778)
+++ /trunk/Config.kmk	(revision 47779)
@@ -4167,8 +4167,9 @@
 # Template for building executables that use the VBox Main component.
 #
-TEMPLATE_VBOXMAINCLIENTEXE             = VBox Main Client (executable)
-TEMPLATE_VBOXMAINCLIENTEXE_EXTENDS     = VBOXMAINEXE
+TEMPLATE_VBOXMAINCLIENTEXE              = VBox Main Client (executable)
+TEMPLATE_VBOXMAINCLIENTEXE_EXTENDS      = VBOXMAINEXE
 ifeq ($(KBUILD_TARGET),win)
- TEMPLATE_VBOXMAINCLIENTEXE_LIBS.win   = $(TEMPLATE_VBOXMAINEXE_LIBS.win) \
+ TEMPLATE_VBOXMAINCLIENTEXE_DEPS		= $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h
+ TEMPLATE_VBOXMAINCLIENTEXE_LIBS.win	= $(TEMPLATE_VBOXMAINEXE_LIBS.win) \
    $(PATH_SDK_$(VBOX_WINPSDK)_LIB)/User32.Lib \
    $(PATH_SDK_$(VBOX_WINPSDK)_LIB)/Shell32.Lib \
@@ -4178,5 +4179,6 @@
    $(PATH_SDK_$(VBOX_WINPSDK)_LIB)/Uuid.Lib
 else
- TEMPLATE_VBOXMAINCLIENTEXE_DEFS = $(TEMPLATE_VBOXMAINEXE_DEFS) \
+ TEMPLATE_VBOXMAINCLIENTEXE_DEPS		= $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h
+ TEMPLATE_VBOXMAINCLIENTEXE_DEFS		= $(TEMPLATE_VBOXMAINEXE_DEFS) \
 	NDEBUG TRIMMED
  TEMPLATE_VBOXMAINCLIENTEXE_CXXFLAGS.linux = $(TEMPLATE_VBOXMAINEXE_CXXFLAGS.linux) \
@@ -4198,4 +4200,19 @@
 endif
 TEMPLATE_VBOXMAINCLIENTDLL_LDFLAGS.darwin = $(filter-out -bind_at_load,$(TEMPLATE_VBOXMAINCLIENTEXE_LDFLAGS.darwin))
+
+#
+# Template for building testcases which are API clients.
+#
+TEMPLATE_VBOXMAINCLIENTTSTEXE           = VBox Main Client Testcase (executable)
+TEMPLATE_VBOXMAINCLIENTTSTEXE_EXTENDS   = VBOXMAINCLIENTEXE
+TEMPLATE_VBOXMAINCLIENTTSTEXE_INST      = $(INST_TESTCASE)
+ifdef VBOX_WITH_RUNPATH
+ TEMPLATE_VBOXMAINCLIENTTSTEXE_LDFLAGS = '$(VBOX_GCC_RPATH_OPT)$(VBOX_WITH_RUNPATH)' $(TEMPLATE_VBOXMAINCLIENTEXE_LDFLAGS)
+else ifdef VBOX_WITH_RELATIVE_RUNPATH
+ TEMPLATE_VBOXMAINCLIENTTSTEXE_LDFLAGS = '$(VBOX_GCC_RPATH_OPT)$(VBOX_WITH_RELATIVE_RUNPATH)/..' $(TEMPLATE_VBOXMAINCLIENTEXE_LDFLAGS)
+endif
+if "$(KBUILD_TARGET)" == "win" && defined(VBOX_SIGNING_MODE)
+ TEMPLATE_VBOXMAINCLIENTTSTEXE_POST_CMDS =
+endif
 
 
Index: /trunk/src/VBox/Main/testcase/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/testcase/Makefile.kmk	(revision 47778)
+++ /trunk/src/VBox/Main/testcase/Makefile.kmk	(revision 47779)
@@ -32,5 +32,6 @@
 	$(if $(VBOX_WITH_GUEST_CONTROL),tstGuestCtrlParseBuffer,) \
 	$(if $(VBOX_WITH_GUEST_CONTROL),tstGuestCtrlContextID,) \
-	$(if true,tstMouseImpl,)
+	tstMediumLock \
+	tstMouseImpl
   PROGRAMS.linux += \
 	$(if $(VBOX_WITH_USB),tstUSBProxyLinux,)
@@ -60,15 +61,7 @@
 # tstAPI
 #
-tstAPI_TEMPLATE = VBOXMAINCLIENTEXE
+tstAPI_TEMPLATE = VBOXMAINCLIENTTSTEXE
 #tstAPI_INST = $(INST_SDK)bindings/gluecom/samples/
 tstAPI_SOURCES  = tstAPI.cpp
-ifeq ($(KBUILD_TARGET),win) ## @todo just add this to the template.
-tstAPI_DEPS = $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h
-else
-tstAPI_DEPS = $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h
-endif
-ifdef VBOX_WITH_RESOURCE_USAGE_API
-tstAPI_DEFS += VBOX_WITH_RESOURCE_USAGE_API
-endif
 
 
@@ -76,15 +69,7 @@
 # tstOVF
 #
-tstOVF_TEMPLATE = VBOXMAINCLIENTEXE
+tstOVF_TEMPLATE = VBOXMAINCLIENTTSTEXE
 #tstOVF_INST = $(INST_SDK)bindings/gluecom/samples/
 tstOVF_SOURCES  = tstOVF.cpp
-ifeq ($(KBUILD_TARGET),win) ## @todo just add this to the template.
-tstOVF_DEPS = $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h
-else
-tstOVF_DEPS = $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h
-endif
-ifdef VBOX_WITH_RESOURCE_USAGE_API
-tstOVF_DEFS += VBOX_WITH_RESOURCE_USAGE_API
-endif
 
 ifndef VBOX_OSE
@@ -109,19 +94,6 @@
 # It comes with a custom makefile which should be tested as well!
 #
-tstVBoxAPILinux_TEMPLATE = VBOXR3EXE
+tstVBoxAPILinux_TEMPLATE = VBOXMAINCLIENTTSTEXE
 tstVBoxAPILinux_SOURCES  = tstVBoxAPILinux.cpp
-tstVBoxAPILinux_CXXFLAGS = -Wno-non-virtual-dtor -fshort-wchar
-tstVBoxAPILinux_LDFLAGS.solaris += '$(VBOX_GCC_RPATH_OPT)$$(VBOX_ORIGIN)/../../..'
-ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP
- tstVBoxAPILinux_DEFS += VBOX_WITH_XPCOM_NAMESPACE_CLEANUP
-endif
-tstVBoxAPILinux_DEFS += VBOX_WITH_XPCOM
-tstVBoxAPILinux_INCS     = \
-	$(VBOX_XPCOM_INCS) \
-	$(VBOX_PATH_SDK)/bindings/xpcom/include
-tstVBoxAPILinux_LIBPATH  = $(LIBPATH_XPCOM)
-tstVBoxAPILinux_LIBS     = $(LIB_XPCOM) $(LIB_RUNTIME)
-tstVBoxAPILinux_DEPS     = \
-	$(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h
 
 
@@ -129,10 +101,8 @@
 # tstVBoxAPIWin
 #
-tstVBoxAPIWin_TEMPLATE = VBOXMAINCLIENTEXE
+tstVBoxAPIWin_TEMPLATE = VBOXMAINCLIENTTSTEXE
 tstVBoxAPIWin_SOURCES  = \
 	tstVBoxAPIWin.cpp \
 	$(VBOX_PATH_SDK)/bindings/mscom/lib/VirtualBox_i.c
-tstVBoxAPIWin_DEPS     = \
-	$(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h
 
 
@@ -140,5 +110,5 @@
 # tstCollector
 #
-tstCollector_TEMPLATE = VBOXMAINCLIENTEXE
+tstCollector_TEMPLATE = VBOXMAINCLIENTTSTEXE
 tstCollector_SOURCES  = \
 	tstCollector.cpp \
@@ -154,5 +124,5 @@
 # tstGuestCtrlParseBuffer
 #
-tstGuestCtrlParseBuffer_TEMPLATE = VBOXMAINCLIENTEXE
+tstGuestCtrlParseBuffer_TEMPLATE = VBOXMAINCLIENTTSTEXE
 tstGuestCtrlParseBuffer_DEFS    += VBOX_WITH_HGCM VBOX_WITH_GUEST_CONTROL VBOX_GUESTCTRL_TEST_CASE
 tstGuestCtrlParseBuffer_SOURCES  = \
@@ -160,9 +130,4 @@
 	../src-client/GuestCtrlPrivate.cpp
 tstGuestCtrlParseBuffer_INCS     = ../include
-ifeq ($(KBUILD_TARGET),win) ## @todo just add this to the template.
- tstGuestCtrlParseBuffer_DEPS    = $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h
-else
- tstGuestCtrlParseBuffer_DEPS    = $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h
-endif
 
 
@@ -170,5 +135,5 @@
 # tstGuestCtrlContextID
 #
-tstGuestCtrlContextID_TEMPLATE = VBOXMAINCLIENTEXE
+tstGuestCtrlContextID_TEMPLATE = VBOXMAINCLIENTTSTEXE
 tstGuestCtrlContextID_DEFS    += VBOX_WITH_HGCM VBOX_WITH_GUEST_CONTROL VBOX_GUESTCTRL_TEST_CASE
 tstGuestCtrlContextID_SOURCES  = \
@@ -176,9 +141,4 @@
 	../src-client/GuestCtrlPrivate.cpp
 tstGuestCtrlContextID_INCS     = ../include
-ifeq ($(KBUILD_TARGET),win) ## @todo just add this to the template.
- tstGuestCtrlContextID_DEPS    = $(VBOX_PATH_SDK)/bindings/mscom/include/VirtualBox.h
-else
- tstGuestCtrlContextID_DEPS    = $(VBOX_PATH_SDK)/bindings/xpcom/include/VirtualBox_XPCOM.h
-endif
 
 
@@ -210,4 +170,11 @@
 
 #
+# tstMediumLock
+#
+tstMediumLock_TEMPLATE = VBOXMAINCLIENTTSTEXE
+tstMediumLock_SOURCES  = tstMediumLock.cpp
+
+
+#
 # tstMouseImpl
 #
Index: /trunk/src/VBox/Main/testcase/tstMediumLock.cpp
===================================================================
--- /trunk/src/VBox/Main/testcase/tstMediumLock.cpp	(revision 47779)
+++ /trunk/src/VBox/Main/testcase/tstMediumLock.cpp	(revision 47779)
@@ -0,0 +1,330 @@
+/* $Id$ */
+
+/** @file
+ *
+ * Medium lock test cases.
+ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_ENABLED
+#define LOG_GROUP LOG_GROUP_MAIN
+#define LOG_INSTANCE NULL
+#include <VBox/log.h>
+
+#include <VBox/com/com.h>
+#include <VBox/com/ptr.h>
+#include <VBox/com/defs.h>
+#include <VBox/com/array.h>
+#include <VBox/com/string.h>
+#include <VBox/com/VirtualBox.h>
+
+#include <iprt/assert.h>
+#include <iprt/uuid.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/initterm.h>
+#include <iprt/test.h>
+
+using namespace com;
+
+
+#define TEST_RT_SUCCESS(x,y,z) \
+    do \
+    { \
+        int rc = (y); \
+        if (RT_FAILURE(rc)) \
+            RTTestFailed((x), "%s %Rrc", (z), rc); \
+    } while (0)
+
+#define TEST_COM_SUCCESS(x,y,z) \
+    do \
+    { \
+        HRESULT hrc = (y); \
+        if (FAILED(hrc)) \
+            RTTestFailed((x), "%s %Rhrc", (z), hrc); \
+    } while (0)
+
+#define TEST_COM_FAILURE(x,y,z) \
+    do \
+    { \
+        HRESULT hrc = (y); \
+        if (SUCCEEDED(hrc)) \
+            RTTestFailed((x), "%s", (z)); \
+    } while (0)
+
+int main(int argc, char *argv[])
+{
+    /* Init the runtime without loading the support driver. */
+    RTR3InitExe(argc, &argv, 0);
+
+    RTTEST hTest;
+    RTEXITCODE rcExit = RTTestInitAndCreate("tstMediumLock", &hTest);
+    if (rcExit)
+        return rcExit;
+    RTTestBanner(hTest);
+
+    bool fComInit = false;
+    ComPtr<IVirtualBox> pVirtualBox;
+    char szPathTemp[RTPATH_MAX] = "";
+    ComPtr<IMedium> pMedium;
+
+    if (!RTTestSubErrorCount(hTest))
+    {
+        RTTestSub(hTest, "Constructing temp image name");
+        TEST_RT_SUCCESS(hTest, RTPathTemp(szPathTemp, sizeof(szPathTemp)), "temp directory");
+        RTUUID uuid;
+        RTUuidCreate(&uuid);
+        char szFile[50];
+        RTStrPrintf(szFile, sizeof(szFile), "%RTuuid.vdi", &uuid);
+        TEST_RT_SUCCESS(hTest, RTPathAppend(szPathTemp, sizeof(szPathTemp), szFile), "concatenate image name");
+    }
+
+    if (!RTTestSubErrorCount(hTest))
+    {
+        RTTestSub(hTest, "Initializing COM");
+        TEST_COM_SUCCESS(hTest, Initialize(), "init");
+    }
+
+    if (!RTTestSubErrorCount(hTest))
+    {
+        fComInit = true;
+
+        RTTestSub(hTest, "Getting VirtualBox reference");
+        TEST_COM_SUCCESS(hTest, pVirtualBox.createLocalObject(CLSID_VirtualBox), "vbox reference");
+    }
+
+    if (!RTTestSubErrorCount(hTest))
+    {
+        RTTestSub(hTest, "Creating temp hard disk medium");
+        TEST_COM_SUCCESS(hTest, pVirtualBox->CreateHardDisk(Bstr("VDI").raw(), Bstr(szPathTemp).raw(), pMedium.asOutParam()), "create medium");
+        if (!pMedium.isNull())
+        {
+            ComPtr<IProgress> pProgress;
+            SafeArray<MediumVariant_T> variant;
+            variant.push_back(MediumVariant_Standard);
+            TEST_COM_SUCCESS(hTest, pMedium->CreateBaseStorage(_1M, ComSafeArrayAsInParam(variant), pProgress.asOutParam()), "create base storage");
+            if (!pProgress.isNull())
+                TEST_COM_SUCCESS(hTest, pProgress->WaitForCompletion(30000), "waiting for completion of create");
+        }
+    }
+
+    if (!RTTestSubErrorCount(hTest))
+    {
+        RTTestSub(hTest, "Write locks");
+
+        MediumState_T mediumState = MediumState_NotCreated;
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state");
+        if (mediumState != MediumState_Created)
+            RTTestFailed(hTest, "wrong medium state %d", mediumState);
+
+        TEST_COM_SUCCESS(hTest, pMedium->LockWrite(&mediumState), "write lock");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting lock write state");
+        if (mediumState != MediumState_LockedWrite)
+            RTTestFailed(hTest, "wrong lock write medium state %d", mediumState);
+
+        TEST_COM_FAILURE(hTest, pMedium->LockWrite(&mediumState), "nested write lock succeeded");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock write state");
+        if (mediumState != MediumState_LockedWrite)
+            RTTestFailed(hTest, "wrong after nested lock write medium state %d", mediumState);
+
+        TEST_COM_SUCCESS(hTest, pMedium->UnlockWrite(&mediumState), "write unlock");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting unlock write state");
+        if (mediumState != MediumState_Created)
+            RTTestFailed(hTest, "wrong unlock write medium state %d", mediumState);
+    }
+
+    if (!RTTestSubErrorCount(hTest))
+    {
+        RTTestSub(hTest, "Read locks");
+
+        MediumState_T mediumState = MediumState_NotCreated;
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state");
+        if (mediumState != MediumState_Created)
+            RTTestFailed(hTest, "wrong medium state %d", mediumState);
+
+        TEST_COM_SUCCESS(hTest, pMedium->LockRead(&mediumState), "read lock");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting lock read state");
+        if (mediumState != MediumState_LockedRead)
+            RTTestFailed(hTest, "wrong lock read medium state %d", mediumState);
+
+        TEST_COM_SUCCESS(hTest, pMedium->LockRead(&mediumState), "nested read lock failed");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock read state");
+        if (mediumState != MediumState_LockedRead)
+            RTTestFailed(hTest, "wrong after nested lock read medium state %d", mediumState);
+
+        TEST_COM_SUCCESS(hTest, pMedium->UnlockRead(&mediumState), "read nested unlock");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock read state");
+        if (mediumState != MediumState_LockedRead)
+            RTTestFailed(hTest, "wrong after nested lock read medium state %d", mediumState);
+
+        TEST_COM_SUCCESS(hTest, pMedium->UnlockRead(&mediumState), "read unlock");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting unlock read state");
+        if (mediumState != MediumState_Created)
+            RTTestFailed(hTest, "wrong unlock read medium state %d", mediumState);
+    }
+
+    if (!RTTestSubErrorCount(hTest))
+    {
+        RTTestSub(hTest, "Mixing write and read locks");
+
+        MediumState_T mediumState = MediumState_NotCreated;
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state");
+        if (mediumState != MediumState_Created)
+            RTTestFailed(hTest, "wrong medium state %d", mediumState);
+
+        TEST_COM_SUCCESS(hTest, pMedium->LockWrite(&mediumState), "write lock");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting lock write state");
+        if (mediumState != MediumState_LockedWrite)
+            RTTestFailed(hTest, "wrong lock write medium state %d", mediumState);
+
+        TEST_COM_FAILURE(hTest, pMedium->LockRead(&mediumState), "write+read lock succeeded");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock write state");
+        if (mediumState != MediumState_LockedWrite)
+            RTTestFailed(hTest, "wrong after nested lock write medium state %d", mediumState);
+
+        TEST_COM_SUCCESS(hTest, pMedium->UnlockWrite(&mediumState), "write unlock");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting unlock write state");
+        if (mediumState != MediumState_Created)
+            RTTestFailed(hTest, "wrong unlock write medium state %d", mediumState);
+    }
+
+    if (!RTTestSubErrorCount(hTest))
+    {
+        RTTestSub(hTest, "Mixing read and write locks");
+
+        MediumState_T mediumState = MediumState_NotCreated;
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state");
+        if (mediumState != MediumState_Created)
+            RTTestFailed(hTest, "wrong medium state %d", mediumState);
+
+        TEST_COM_SUCCESS(hTest, pMedium->LockRead(&mediumState), "read lock");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting lock read state");
+        if (mediumState != MediumState_LockedRead)
+            RTTestFailed(hTest, "wrong lock read medium state %d", mediumState);
+
+        TEST_COM_FAILURE(hTest, pMedium->LockWrite(&mediumState), "read+write lock succeeded");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after nested lock read state");
+        if (mediumState != MediumState_LockedRead)
+            RTTestFailed(hTest, "wrong after nested lock read medium state %d", mediumState);
+
+        TEST_COM_SUCCESS(hTest, pMedium->UnlockRead(&mediumState), "read unlock");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting unlock read state");
+        if (mediumState != MediumState_Created)
+            RTTestFailed(hTest, "wrong unlock read medium state %d", mediumState);
+    }
+
+    if (!RTTestSubErrorCount(hTest))
+    {
+        RTTestSub(hTest, "Write locks, read unlocks");
+
+        MediumState_T mediumState = MediumState_NotCreated;
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state");
+        if (mediumState != MediumState_Created)
+            RTTestFailed(hTest, "wrong medium state %d", mediumState);
+
+        TEST_COM_SUCCESS(hTest, pMedium->LockWrite(&mediumState), "write lock");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting lock write state");
+        if (mediumState != MediumState_LockedWrite)
+            RTTestFailed(hTest, "wrong lock write medium state %d", mediumState);
+
+        TEST_COM_FAILURE(hTest, pMedium->UnlockRead(&mediumState), "read unlocking a write lock succeeded");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after read unlock write state");
+        if (mediumState != MediumState_LockedWrite)
+            RTTestFailed(hTest, "wrong after read lock write medium state %d", mediumState);
+
+        TEST_COM_SUCCESS(hTest, pMedium->UnlockWrite(&mediumState), "write unlock");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting unlock write state");
+        if (mediumState != MediumState_Created)
+            RTTestFailed(hTest, "wrong unlock write medium state %d", mediumState);
+    }
+
+    if (!RTTestSubErrorCount(hTest))
+    {
+        RTTestSub(hTest, "Read locks, write unlocks");
+
+        MediumState_T mediumState = MediumState_NotCreated;
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state");
+        if (mediumState != MediumState_Created)
+            RTTestFailed(hTest, "wrong medium state %d", mediumState);
+
+        TEST_COM_SUCCESS(hTest, pMedium->LockRead(&mediumState), "read lock");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting lock read state");
+        if (mediumState != MediumState_LockedRead)
+            RTTestFailed(hTest, "wrong lock write medium state %d", mediumState);
+
+        TEST_COM_FAILURE(hTest, pMedium->UnlockWrite(&mediumState), "write unlocking a read lock succeeded");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting after write unlock read state");
+        if (mediumState != MediumState_LockedRead)
+            RTTestFailed(hTest, "wrong after write lock read medium state %d", mediumState);
+
+        TEST_COM_SUCCESS(hTest, pMedium->UnlockRead(&mediumState), "read unlock");
+
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting unlock read state");
+        if (mediumState != MediumState_Created)
+            RTTestFailed(hTest, "wrong unlock read medium state %d", mediumState);
+    }
+
+    /* Cleanup, also part of the testcase */
+
+    if (!pMedium.isNull())
+    {
+        RTTestSub(hTest, "Closing medium");
+        MediumState_T mediumState = MediumState_NotCreated;
+        TEST_COM_SUCCESS(hTest, pMedium->COMGETTER(State)(&mediumState), "getting state");
+        if (mediumState == MediumState_Created)
+        {
+            ComPtr<IProgress> pProgress;
+            TEST_COM_SUCCESS(hTest, pMedium->DeleteStorage(pProgress.asOutParam()), "deleting storage");
+            if (!pProgress.isNull())
+                TEST_COM_SUCCESS(hTest, pProgress->WaitForCompletion(30000), "waiting for completion of delete");
+        }
+        TEST_COM_SUCCESS(hTest, pMedium->Close(), "closing");
+        pMedium.setNull();
+    }
+
+    pVirtualBox.setNull();
+
+    /* Make sure that there are no object references alive here, XPCOM does
+     * a very bad job at cleaning up such leftovers, spitting out warning
+     * messages in a debug build. */
+
+    if (fComInit)
+    {
+        RTTestIPrintf(RTTESTLVL_DEBUG, "Shutting down COM...\n");
+        Shutdown();
+    }
+
+    /*
+     * Summary.
+     */
+    return RTTestSummaryAndDestroy(hTest);
+}
