Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp	(revision 51674)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp	(revision 51675)
@@ -64,5 +64,7 @@
 
 VBoxDnDWnd::VBoxDnDWnd(void)
-    : hWnd(NULL),
+    : hThread(NIL_RTTHREAD),
+      mEventSem(NIL_RTSEMEVENT),
+      hWnd(NULL),
       uAllActions(DND_IGNORE_ACTION),
       mfMouseButtonDown(false),
@@ -83,9 +85,13 @@
 VBoxDnDWnd::~VBoxDnDWnd(void)
 {
-    /** @todo Shutdown crit sect / event etc! */
-
-    reset();
-}
-
+    Destroy();
+}
+
+/**
+ * Initializes the proxy window with a given DnD context.
+ *
+ * @return  IPRT status code.
+ * @param   pContext                Pointer to context to use.
+ */
 int VBoxDnDWnd::Initialize(PVBOXDNDCONTEXT pContext)
 {
@@ -102,11 +108,13 @@
     {
         /* Message pump thread for our proxy window. */
-        rc = RTThreadCreate(&gCtx.hEvtQueue, VBoxDnDWnd::Thread, this,
+        rc = RTThreadCreate(&hThread, VBoxDnDWnd::Thread, this,
                             0, RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
                             "VBoxTrayDnDWnd");
-        if (RT_FAILURE(rc))
-            LogRel(("DnD: Failed to start proxy window thread, rc=%Rrc\n", rc));
-        /** @todo Wait for thread to be started! */
-    }
+        if (RT_SUCCESS(rc))
+            rc = RTThreadUserWait(hThread, 30 * 1000 /* Timeout in ms */);
+    }
+
+    if (RT_FAILURE(rc))
+        LogRel(("DnD: Failed to initialize proxy window, rc=%Rrc\n", rc));
 
     LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
@@ -115,9 +123,34 @@
 
 /**
+ * Destroys the proxy window and releases all remaining
+ * resources again.
+ *
+ */
+void VBoxDnDWnd::Destroy(void)
+{
+    if (hThread != NIL_RTTHREAD)
+    {
+        int rcThread = VERR_WRONG_ORDER;
+        int rc = RTThreadWait(hThread, 60 * 1000 /* Timeout in ms */, &rcThread);
+        LogFlowFunc(("Waiting for thread resulted in %Rrc (thread exited with %Rrc)\n",
+                     rc, rcThread));
+    }
+
+    reset();
+
+    RTCritSectDelete(&mCritSect);
+    if (mEventSem != NIL_RTSEMEVENT)
+        RTSemEventDestroy(mEventSem);
+
+    LogFlowFuncLeave();
+}
+
+/**
  * Thread for handling the window's message pump.
  *
  * @return  IPRT status code.
- * @param   hThread
- * @param   pvUser
+ * @param   hThread                 Handle to this thread.
+ * @param   pvUser                  Pointer to VBoxDnDWnd instance which
+ *                                  is using the thread.
  */
 /* static */
@@ -152,4 +185,6 @@
 #endif
 
+    bool fSignalled = false; /* Thread signalled? */
+
     int rc = VINF_SUCCESS;
     if (!RegisterClassEx(&wndClass))
@@ -223,6 +258,9 @@
     if (RT_SUCCESS(rc))
     {
+        rc = RTThreadUserSignal(hThread);
+        fSignalled = RT_SUCCESS(rc);
+
         bool fShutdown = false;
-        do
+        while (RT_SUCCESS(rc))
         {
             MSG uMsg;
@@ -243,6 +281,5 @@
 
             /** @todo Immediately drop on failure? */
-
-        } while (RT_SUCCESS(rc));
+        }
 
 #ifdef VBOX_WITH_DRAG_AND_DROP_GH
@@ -254,8 +291,26 @@
     }
 
+    if (!fSignalled)
+    {
+        int rc2 = RTThreadUserSignal(hThread);
+        AssertRC(rc2);
+    }
+
     LogFlowFuncLeaveRC(rc);
     return rc;
 }
 
+/**
+ * Monitor enumeration callback for building up a simple bounding
+ * box, capable of holding all enumerated monitors.
+ *
+ * @return  BOOL                    TRUE if enumeration should continue,
+ *                                  FALSE if not.
+ * @param   hMonitor                Handle to current monitor being enumerated.
+ * @param   hdcMonitor              The current monitor's DC (device context).
+ * @param   lprcMonitor             The current monitor's RECT.
+ * @param   lParam                  Pointer to a RECT structure holding the
+ *                                  bounding box to build.
+ */
 /* static */
 BOOL CALLBACK VBoxDnDWnd::MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor,
@@ -283,4 +338,7 @@
 }
 
+/**
+ * The proxy window's WndProc.
+ */
 LRESULT CALLBACK VBoxDnDWnd::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
@@ -606,4 +664,9 @@
 }
 
+/**
+ * Unregisters this proxy as a drop target.
+ *
+ * @return  IPRT status code.
+ */
 int VBoxDnDWnd::UnregisterAsDropTarget(void)
 {
@@ -633,4 +696,9 @@
 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */
 
+/**
+ * Handles the creation of a proxy window.
+ *
+ * @return  IPRT status code.
+ */
 int VBoxDnDWnd::OnCreate(void)
 {
@@ -646,4 +714,7 @@
 }
 
+/**
+ * Handles the destruction of a proxy window.
+ */
 void VBoxDnDWnd::OnDestroy(void)
 {
@@ -652,4 +723,12 @@
 }
 
+/**
+ * Handles actions required when the host cursor enters
+ * the guest's screen to initiate a host -> guest DnD operation.
+ *
+ * @return  IPRT status code.
+ * @param   lstFormats              Supported formats offered by the host.
+ * @param   uAllActions             Supported actions offered by the host.
+ */
 int VBoxDnDWnd::OnHgEnter(const RTCList<RTCString> &lstFormats, uint32_t uAllActions)
 {
@@ -716,4 +795,16 @@
 }
 
+/**
+ * Handles actions required when the host cursor moves inside
+ * the guest's screen.
+ *
+ * @return  IPRT status code.
+ * @param   u32xPos                 Absolute X position (in pixels) of the host cursor
+ *                                  inside the guest.
+ * @param   u32yPos                 Absolute Y position (in pixels) of the host cursor
+ *                                  inside the guest.
+ * @param   uAction                 Action the host wants to perform while moving.
+ *                                  Currently ignored.
+ */
 int VBoxDnDWnd::OnHgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t uAction)
 {
@@ -753,4 +844,10 @@
 }
 
+/**
+ * Handles actions required when the host cursor leaves
+ * the guest's screen again.
+ *
+ * @return  IPRT status code.
+ */
 int VBoxDnDWnd::OnHgLeave(void)
 {
@@ -773,4 +870,10 @@
 }
 
+/**
+ * Handles actions required when the host cursor wants to drop
+ * and therefore start a "drop" action in the guest.
+ *
+ * @return  IPRT status code.
+ */
 int VBoxDnDWnd::OnHgDrop(void)
 {
@@ -812,4 +915,12 @@
 }
 
+/**
+ * Handles actions required when the host has sent over DnD data
+ * to the guest after a "drop" event.
+ *
+ * @return  IPRT status code.
+ * @param   pvData                  Pointer to raw data received.
+ * @param   cbData                  Size of data (in bytes) received.
+ */
 int VBoxDnDWnd::OnHgDataReceived(const void *pvData, uint32_t cbData)
 {
@@ -843,4 +954,10 @@
 }
 
+/**
+ * Handles actions required when the host wants to cancel an action
+ * host -> guest operation.
+ *
+ * @return  IPRT status code.
+ */
 int VBoxDnDWnd::OnHgCancel(void)
 {
@@ -864,4 +981,27 @@
 
 #ifdef VBOX_WITH_DRAG_AND_DROP_GH
+/**
+ * Handles actions required to start a guest -> host DnD operation.
+ * This works by letting the host ask whether a DnD operation is pending
+ * on the guest. The guest must not know anything about the host's DnD state
+ * and/or operations due to security reasons.
+ *
+ * To capture a pending DnD operation on the guest which then can be communicated
+ * to the host the proxy window needs to be registered as a drop target. This drop
+ * target then will act as a proxy target between the guest OS and the host. In other
+ * words, the guest OS will use this proxy target as a regular (invisible) window
+ * which can be used by the regular guest OS' DnD mechanisms, independently of the
+ * host OS. To make sure this proxy target is able receive an in-progress DnD operation
+ * on the guest, it will be shown invisibly across all active guest OS screens. Just
+ * think of an opened umbrella across all screens here.
+ *
+ * As soon as the proxy target and its underlying data object receive appropriate
+ * DnD messages they'll be hidden again, and the control will be transferred back
+ * this class again.
+ *
+ * @return  IPRT status code.
+ * @param   uScreenID               Screen ID the host wants to query a pending operation
+ *                                  for. Currently not used/needed here.
+ */
 int VBoxDnDWnd::OnGhIsDnDPending(uint32_t uScreenID)
 {
@@ -995,9 +1135,19 @@
 }
 
-int VBoxDnDWnd::OnGhDropped(const char *pszFormat, uint32_t cbFormats,
+/**
+ * Handles actions required to let the guest know that the host
+ * started a "drop" action on the host. This will tell the guest
+ * to send data in a specific format the host requested.
+ *
+ * @return  IPRT status code.
+ * @param   pszFormat               Format the host requests the data in.
+ * @param   cbFormat                Size (in bytes) of format string.
+ * @param   uDefAction              Default action on the host.
+ */
+int VBoxDnDWnd::OnGhDropped(const char *pszFormat, uint32_t cbFormat,
                             uint32_t uDefAction)
 {
     AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
-    AssertReturn(cbFormats, VERR_INVALID_PARAMETER);
+    AssertReturn(cbFormat, VERR_INVALID_PARAMETER);
 
     LogFlowThisFunc(("mMode=%ld, mState=%ld, pDropTarget=0x%p, pszFormat=%s, uDefAction=0x%x\n",
@@ -1043,14 +1193,42 @@
 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */
 
+/**
+ * Injects a DnD event in this proxy window's Windows
+ * event queue. The (allocated) event will be deleted by
+ * this class after processing.
+ *
+ * @return  IPRT status code.
+ * @param   pEvent                  Event to inject.
+ */
 int VBoxDnDWnd::ProcessEvent(PVBOXDNDEVENT pEvent)
 {
     AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
 
-    PostMessage(hWnd, WM_VBOXTRAY_DND_MESSAGE,
-                0 /* wParm */, (LPARAM)pEvent /* lParm */);
+    BOOL fRc = PostMessage(hWnd, WM_VBOXTRAY_DND_MESSAGE,
+                           0 /* wParm */, (LPARAM)pEvent /* lParm */);
+    if (!fRc)
+    {
+        static int s_iBitchedAboutFailedDnDMessages = 0;
+        if (s_iBitchedAboutFailedDnDMessages++ < 10)
+        {
+            DWORD dwErr = GetLastError();
+            LogRel(("DnD: Processing event %p failed with %ld (%Rrc), skpping\n",
+                    pEvent, dwErr, RTErrConvertFromWin32(dwErr)));
+        }
+
+        RTMemFree(pEvent);
+        pEvent = NULL;
+
+        return VERR_NO_MEMORY;
+    }
 
     return VINF_SUCCESS;
 }
 
+/**
+ * Hides the proxy window again.
+ *
+ * @return  IPRT status code.
+ */
 int VBoxDnDWnd::hide(void)
 {
@@ -1063,4 +1241,10 @@
 }
 
+/**
+ * Shows the (invisible) proxy window in fullscreen,
+ * spawned across all active guest monitors.
+ *
+ * @return  IPRT status code.
+ */
 int VBoxDnDWnd::makeFullscreen(void)
 {
@@ -1137,4 +1321,12 @@
 }
 
+/**
+ * Moves the guest mouse cursor to a specific position.
+ *
+ * @return  IPRT status code.
+ * @param   x                       X position (in pixels) to move cursor to.
+ * @param   y                       Y position (in pixels) to move cursor to.
+ * @param   dwMouseInputFlags       Additional movement flags. @sa MOUSEEVENTF_ flags.
+ */
 int VBoxDnDWnd::mouseMove(int x, int y, DWORD dwMouseInputFlags)
 {
@@ -1175,4 +1367,9 @@
 }
 
+/**
+ * Releases a previously pressed left guest mouse button.
+ *
+ * @return  IPRT status code.
+ */
 int VBoxDnDWnd::mouseRelease(void)
 {
@@ -1199,4 +1396,7 @@
 }
 
+/**
+ * Resets the proxy window.
+ */
 void VBoxDnDWnd::reset(void)
 {
@@ -1214,4 +1414,10 @@
 }
 
+/**
+ * Sets the current operation mode of this proxy window.
+ *
+ * @return  IPRT status code.
+ * @param   enmMode                 New mode to set.
+ */
 int VBoxDnDWnd::setMode(Mode enmMode)
 {
@@ -1225,5 +1431,10 @@
 }
 
-static LRESULT CALLBACK vboxDnDWndProcInstance(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+/**
+ * Static helper function for having an own WndProc for proxy
+ * window instances.
+ */
+static LRESULT CALLBACK vboxDnDWndProcInstance(HWND hWnd, UINT uMsg,
+                                               WPARAM wParam, LPARAM lParam)
 {
     LONG_PTR pUserData = GetWindowLongPtr(hWnd, GWLP_USERDATA);
@@ -1237,5 +1448,10 @@
 }
 
-static LRESULT CALLBACK vboxDnDWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+/**
+ * Static helper function for routing Windows messages to a specific
+ * proxy window instance.
+ */
+static LRESULT CALLBACK vboxDnDWndProc(HWND hWnd, UINT uMsg,
+                                       WPARAM wParam, LPARAM lParam)
 {
     /* Note: WM_NCCREATE is not the first ever message which arrives, but
@@ -1346,6 +1562,4 @@
     /* Set shutdown indicator. */
     ASMAtomicWriteBool(&pCtx->fShutdown, true);
-
-    /** @todo Notify / wait for HGCM thread! */
 }
 
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h	(revision 51674)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h	(revision 51675)
@@ -230,7 +230,4 @@
     /** Shutdown indicator. */
     bool                       fShutdown;
-    /** Thread handle for main event queue
-     *  processing. */
-    RTTHREAD                   hEvtQueue;
     /** The DnD main event queue. */
     RTCMTList<VBOXDNDEVENT>    lstEvtQueue;
@@ -238,6 +235,6 @@
      *  events. */
     RTSEMEVENT                 hEvtQueueSem;
-    /** List of drag'n drop windows. At
-     *  the moment only one source is supported. */
+    /** List of drag'n drop proxy windows.
+     *  Note: At the moment only one window is supported. */
     RTCMTList<VBoxDnDWnd*>     lstWnd;
 
@@ -303,4 +300,5 @@
 
     int Initialize(PVBOXDNDCONTEXT pContext);
+    void Destroy(void);
 
 public:
@@ -360,4 +358,7 @@
     /** Pointer to DnD context. */
     PVBOXDNDCONTEXT            pContext;
+    /** The proxy window's main thread for processing
+     *  window messages. */
+    RTTHREAD                   hThread;
     RTCRITSECT                 mCritSect;
     RTSEMEVENT                 mEventSem;
@@ -383,4 +384,6 @@
     bool                       mfMouseButtonDown;
 # ifdef VBOX_WITH_DRAG_AND_DROP_GH
+    /** IDropTarget implementation for guest -> host
+     *  support. */
     VBoxDnDDropTarget         *pDropTarget;
 # endif /* VBOX_WITH_DRAG_AND_DROP_GH */
@@ -395,8 +398,6 @@
     /** The current state. */
     State                      mState;
-    bool                       mInFlight;
+    /** Format being requested. */
     RTCString                  mFormatRequested;
-    RTCList<RTCString>         mLstFormats;
-    RTCList<RTCString>         mLstActions;
 };
 #endif /* __VBOXTRAYDND__H */
