set svn:eol-style to native
[reactos.git] / reactos / lib / ole32 / ole2.c
index 53e123b..339ccd2 100644 (file)
-/*\r
- *     OLE2 library\r
- *\r
- * Copyright 1995 Martin von Loewis\r
- * Copyright 1999 Francis Beaudet\r
- * Copyright 1999 Noel Borthwick\r
- * Copyright 1999, 2000 Marcus Meissner\r
- * Copyright 2005 Juan Lang\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
- */\r
-\r
-#include "config.h"\r
-\r
-#include <assert.h>\r
-#include <stdlib.h>\r
-#include <stdarg.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-\r
-#define COBJMACROS\r
-#define NONAMELESSUNION\r
-#define NONAMELESSSTRUCT\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "winerror.h"\r
-#include "wingdi.h"\r
-#include "winuser.h"\r
-#include "winnls.h"\r
-#include "winreg.h"\r
-#include "commctrl.h"\r
-#include "ole2.h"\r
-#include "ole2ver.h"\r
-#include "wownt32.h"\r
-\r
-#include "wine/winbase16.h"\r
-#include "wine/wingdi16.h"\r
-#include "wine/winuser16.h"\r
-#include "compobj_private.h"\r
-\r
-#include "wine/debug.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(ole);\r
-WINE_DECLARE_DEBUG_CHANNEL(accel);\r
-\r
-#define HICON_16(h32)          (LOWORD(h32))\r
-#define HICON_32(h16)          ((HICON)(ULONG_PTR)(h16))\r
-#define HINSTANCE_32(h16)      ((HINSTANCE)(ULONG_PTR)(h16))\r
-\r
-/******************************************************************************\r
- * These are static/global variables and internal data structures that the\r
- * OLE module uses to maintain it's state.\r
- */\r
-typedef struct tagDropTargetNode\r
-{\r
-  HWND          hwndTarget;\r
-  IDropTarget*    dropTarget;\r
-  struct tagDropTargetNode* prevDropTarget;\r
-  struct tagDropTargetNode* nextDropTarget;\r
-} DropTargetNode;\r
-\r
-typedef struct tagTrackerWindowInfo\r
-{\r
-  IDataObject* dataObject;\r
-  IDropSource* dropSource;\r
-  DWORD        dwOKEffect;\r
-  DWORD*       pdwEffect;\r
-  BOOL       trackingDone;\r
-  HRESULT      returnValue;\r
-\r
-  BOOL       escPressed;\r
-  HWND       curTargetHWND;    /* window the mouse is hovering over */\r
-  HWND       curDragTargetHWND; /* might be a ancestor of curTargetHWND */\r
-  IDropTarget* curDragTarget;\r
-} TrackerWindowInfo;\r
-\r
-typedef struct tagOleMenuDescriptor  /* OleMenuDescriptor */\r
-{\r
-  HWND               hwndFrame;         /* The containers frame window */\r
-  HWND               hwndActiveObject;  /* The active objects window */\r
-  OLEMENUGROUPWIDTHS mgw;               /* OLE menu group widths for the shared menu */\r
-  HMENU              hmenuCombined;     /* The combined menu */\r
-  BOOL               bIsServerItem;     /* True if the currently open popup belongs to the server */\r
-} OleMenuDescriptor;\r
-\r
-typedef struct tagOleMenuHookItem   /* OleMenu hook item in per thread hook list */\r
-{\r
-  DWORD tid;                /* Thread Id  */\r
-  HANDLE hHeap;             /* Heap this is allocated from */\r
-  HHOOK GetMsg_hHook;       /* message hook for WH_GETMESSAGE */\r
-  HHOOK CallWndProc_hHook;  /* message hook for WH_CALLWNDPROC */\r
-  struct tagOleMenuHookItem *next;\r
-} OleMenuHookItem;\r
-\r
-static OleMenuHookItem *hook_list;\r
-\r
-/*\r
- * This is the lock count on the OLE library. It is controlled by the\r
- * OLEInitialize/OLEUninitialize methods.\r
- */\r
-static ULONG OLE_moduleLockCount = 0;\r
-\r
-/*\r
- * Name of our registered window class.\r
- */\r
-static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";\r
-\r
-/*\r
- * This is the head of the Drop target container.\r
- */\r
-static DropTargetNode* targetListHead = NULL;\r
-\r
-/******************************************************************************\r
- * These are the prototypes of miscelaneous utility methods\r
- */\r
-static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);\r
-\r
-/******************************************************************************\r
- * These are the prototypes of the utility methods used to manage a shared menu\r
- */\r
-static void OLEMenu_Initialize(void);\r
-static void OLEMenu_UnInitialize(void);\r
-BOOL OLEMenu_InstallHooks( DWORD tid );\r
-BOOL OLEMenu_UnInstallHooks( DWORD tid );\r
-OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );\r
-static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );\r
-BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );\r
-LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);\r
-LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);\r
-\r
-/******************************************************************************\r
- * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)\r
- */\r
-extern void OLEClipbrd_UnInitialize(void);\r
-extern void OLEClipbrd_Initialize(void);\r
-\r
-/******************************************************************************\r
- * These are the prototypes of the utility methods used for OLE Drag n Drop\r
- */\r
-static void            OLEDD_Initialize(void);\r
-static void            OLEDD_UnInitialize(void);\r
-static void            OLEDD_InsertDropTarget(\r
-                        DropTargetNode* nodeToAdd);\r
-static DropTargetNode* OLEDD_ExtractDropTarget(\r
-                         HWND hwndOfTarget);\r
-static DropTargetNode* OLEDD_FindDropTarget(\r
-                         HWND hwndOfTarget);\r
-static LRESULT WINAPI  OLEDD_DragTrackerWindowProc(\r
-                        HWND   hwnd,\r
-                        UINT   uMsg,\r
-                        WPARAM wParam,\r
-                        LPARAM   lParam);\r
-static void OLEDD_TrackMouseMove(\r
-                         TrackerWindowInfo* trackerInfo,\r
-                        POINT            mousePos,\r
-                        DWORD              keyState);\r
-static void OLEDD_TrackStateChange(\r
-                         TrackerWindowInfo* trackerInfo,\r
-                        POINT            mousePos,\r
-                        DWORD              keyState);\r
-static DWORD OLEDD_GetButtonState(void);\r
-\r
-\r
-/******************************************************************************\r
- *             OleBuildVersion [OLE2.1]\r
- *             OleBuildVersion [OLE32.@]\r
- */\r
-DWORD WINAPI OleBuildVersion(void)\r
-{\r
-    TRACE("Returning version %d, build %d.\n", rmm, rup);\r
-    return (rmm<<16)+rup;\r
-}\r
-\r
-/***********************************************************************\r
- *           OleInitialize       (OLE2.2)\r
- *           OleInitialize       (OLE32.@)\r
- */\r
-HRESULT WINAPI OleInitialize(LPVOID reserved)\r
-{\r
-  HRESULT hr;\r
-\r
-  TRACE("(%p)\n", reserved);\r
-\r
-  /*\r
-   * The first duty of the OleInitialize is to initialize the COM libraries.\r
-   */\r
-  hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);\r
-\r
-  /*\r
-   * If the CoInitializeEx call failed, the OLE libraries can't be\r
-   * initialized.\r
-   */\r
-  if (FAILED(hr))\r
-    return hr;\r
-\r
-  /*\r
-   * Then, it has to initialize the OLE specific modules.\r
-   * This includes:\r
-   *     Clipboard\r
-   *     Drag and Drop\r
-   *     Object linking and Embedding\r
-   *     In-place activation\r
-   */\r
-  if (OLE_moduleLockCount==0)\r
-  {\r
-    /*\r
-     * Initialize the libraries.\r
-     */\r
-    TRACE("() - Initializing the OLE libraries\n");\r
-\r
-    /*\r
-     * OLE Clipboard\r
-     */\r
-    OLEClipbrd_Initialize();\r
-\r
-    /*\r
-     * Drag and Drop\r
-     */\r
-    OLEDD_Initialize();\r
-\r
-    /*\r
-     * OLE shared menu\r
-     */\r
-    OLEMenu_Initialize();\r
-  }\r
-\r
-  /*\r
-   * Then, we increase the lock count on the OLE module.\r
-   */\r
-  OLE_moduleLockCount++;\r
-\r
-  return hr;\r
-}\r
-\r
-/******************************************************************************\r
- *             OleUninitialize [OLE2.3]\r
- *             OleUninitialize [OLE32.@]\r
- */\r
-void WINAPI OleUninitialize(void)\r
-{\r
-  TRACE("()\n");\r
-\r
-  /*\r
-   * Decrease the lock count on the OLE module.\r
-   */\r
-  OLE_moduleLockCount--;\r
-\r
-  /*\r
-   * If we hit the bottom of the lock stack, free the libraries.\r
-   */\r
-  if (OLE_moduleLockCount==0)\r
-  {\r
-    /*\r
-     * Actually free the libraries.\r
-     */\r
-    TRACE("() - Freeing the last reference count\n");\r
-\r
-    /*\r
-     * OLE Clipboard\r
-     */\r
-    OLEClipbrd_UnInitialize();\r
-\r
-    /*\r
-     * Drag and Drop\r
-     */\r
-    OLEDD_UnInitialize();\r
-\r
-    /*\r
-     * OLE shared menu\r
-     */\r
-    OLEMenu_UnInitialize();\r
-  }\r
-\r
-  /*\r
-   * Then, uninitialize the COM libraries.\r
-   */\r
-  CoUninitialize();\r
-}\r
-\r
-/******************************************************************************\r
- *             OleInitializeWOW        [OLE32.@]\r
- */\r
-HRESULT WINAPI OleInitializeWOW(DWORD x) {\r
-        FIXME("(0x%08lx),stub!\n",x);\r
-        return 0;\r
-}\r
-\r
-/***********************************************************************\r
- *           RegisterDragDrop (OLE32.@)\r
- */\r
-HRESULT WINAPI RegisterDragDrop(\r
-       HWND hwnd,\r
-       LPDROPTARGET pDropTarget)\r
-{\r
-  DropTargetNode* dropTargetInfo;\r
-\r
-  TRACE("(%p,%p)\n", hwnd, pDropTarget);\r
-\r
-  if (!pDropTarget)\r
-    return E_INVALIDARG;\r
-  \r
-  /*\r
-   * First, check if the window is already registered.\r
-   */\r
-  dropTargetInfo = OLEDD_FindDropTarget(hwnd);\r
-\r
-  if (dropTargetInfo!=NULL)\r
-    return DRAGDROP_E_ALREADYREGISTERED;\r
-\r
-  /*\r
-   * If it's not there, we can add it. We first create a node for it.\r
-   */\r
-  dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));\r
-\r
-  if (dropTargetInfo==NULL)\r
-    return E_OUTOFMEMORY;\r
-\r
-  dropTargetInfo->hwndTarget     = hwnd;\r
-  dropTargetInfo->prevDropTarget = NULL;\r
-  dropTargetInfo->nextDropTarget = NULL;\r
-\r
-  /*\r
-   * Don't forget that this is an interface pointer, need to nail it down since\r
-   * we keep a copy of it.\r
-   */\r
-  dropTargetInfo->dropTarget  = pDropTarget;\r
-  IDropTarget_AddRef(dropTargetInfo->dropTarget);\r
-\r
-  OLEDD_InsertDropTarget(dropTargetInfo);\r
-\r
-       return S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- *           RevokeDragDrop (OLE32.@)\r
- */\r
-HRESULT WINAPI RevokeDragDrop(\r
-       HWND hwnd)\r
-{\r
-  DropTargetNode* dropTargetInfo;\r
-\r
-  TRACE("(%p)\n", hwnd);\r
-\r
-  /*\r
-   * First, check if the window is already registered.\r
-   */\r
-  dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);\r
-\r
-  /*\r
-   * If it ain't in there, it's an error.\r
-   */\r
-  if (dropTargetInfo==NULL)\r
-    return DRAGDROP_E_NOTREGISTERED;\r
-\r
-  /*\r
-   * If it's in there, clean-up it's used memory and\r
-   * references\r
-   */\r
-  IDropTarget_Release(dropTargetInfo->dropTarget);\r
-  HeapFree(GetProcessHeap(), 0, dropTargetInfo);\r
-\r
-       return S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- *           OleRegGetUserType (OLE32.@)\r
- *\r
- * This implementation of OleRegGetUserType ignores the dwFormOfType\r
- * parameter and always returns the full name of the object. This is\r
- * not too bad since this is the case for many objects because of the\r
- * way they are registered.\r
- */\r
-HRESULT WINAPI OleRegGetUserType(\r
-       REFCLSID clsid,\r
-       DWORD dwFormOfType,\r
-       LPOLESTR* pszUserType)\r
-{\r
-  char    keyName[60];\r
-  DWORD   dwKeyType;\r
-  DWORD   cbData;\r
-  HKEY    clsidKey;\r
-  LONG    hres;\r
-  LPBYTE  buffer;\r
-  HRESULT retVal;\r
-  /*\r
-   * Initialize the out parameter.\r
-   */\r
-  *pszUserType = NULL;\r
-\r
-  /*\r
-   * Build the key name we're looking for\r
-   */\r
-  sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",\r
-           clsid->Data1, clsid->Data2, clsid->Data3,\r
-           clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],\r
-           clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );\r
-\r
-  TRACE("(%s, %ld, %p)\n", keyName, dwFormOfType, pszUserType);\r
-\r
-  /*\r
-   * Open the class id Key\r
-   */\r
-  hres = RegOpenKeyA(HKEY_CLASSES_ROOT,\r
-                    keyName,\r
-                    &clsidKey);\r
-\r
-  if (hres != ERROR_SUCCESS)\r
-    return REGDB_E_CLASSNOTREG;\r
-\r
-  /*\r
-   * Retrieve the size of the name string.\r
-   */\r
-  cbData = 0;\r
-\r
-  hres = RegQueryValueExA(clsidKey,\r
-                         "",\r
-                         NULL,\r
-                         &dwKeyType,\r
-                         NULL,\r
-                         &cbData);\r
-\r
-  if (hres!=ERROR_SUCCESS)\r
-  {\r
-    RegCloseKey(clsidKey);\r
-    return REGDB_E_READREGDB;\r
-  }\r
-\r
-  /*\r
-   * Allocate a buffer for the registry value.\r
-   */\r
-  *pszUserType = CoTaskMemAlloc(cbData*2);\r
-\r
-  if (*pszUserType==NULL)\r
-  {\r
-    RegCloseKey(clsidKey);\r
-    return E_OUTOFMEMORY;\r
-  }\r
-\r
-  buffer = HeapAlloc(GetProcessHeap(), 0, cbData);\r
-\r
-  if (buffer == NULL)\r
-  {\r
-    RegCloseKey(clsidKey);\r
-    CoTaskMemFree(*pszUserType);\r
-    *pszUserType=NULL;\r
-    return E_OUTOFMEMORY;\r
-  }\r
-\r
-  hres = RegQueryValueExA(clsidKey,\r
-                         "",\r
-                         NULL,\r
-                         &dwKeyType,\r
-                         buffer,\r
-                         &cbData);\r
-\r
-  RegCloseKey(clsidKey);\r
-\r
-\r
-  if (hres!=ERROR_SUCCESS)\r
-  {\r
-    CoTaskMemFree(*pszUserType);\r
-    *pszUserType=NULL;\r
-\r
-    retVal = REGDB_E_READREGDB;\r
-  }\r
-  else\r
-  {\r
-    MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ );\r
-    retVal = S_OK;\r
-  }\r
-  HeapFree(GetProcessHeap(), 0, buffer);\r
-\r
-  return retVal;\r
-}\r
-\r
-/***********************************************************************\r
- * DoDragDrop [OLE32.@]\r
- */\r
-HRESULT WINAPI DoDragDrop (\r
-  IDataObject *pDataObject,  /* [in] ptr to the data obj           */\r
-  IDropSource* pDropSource,  /* [in] ptr to the source obj         */\r
-  DWORD       dwOKEffect,    /* [in] effects allowed by the source */\r
-  DWORD       *pdwEffect)    /* [out] ptr to effects of the source */\r
-{\r
-  TrackerWindowInfo trackerInfo;\r
-  HWND            hwndTrackWindow;\r
-  MSG             msg;\r
-\r
-  TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);\r
-\r
-  /*\r
-   * Setup the drag n drop tracking window.\r
-   */\r
-  if (!IsValidInterface((LPUNKNOWN)pDropSource))\r
-      return E_INVALIDARG;\r
-\r
-  trackerInfo.dataObject        = pDataObject;\r
-  trackerInfo.dropSource        = pDropSource;\r
-  trackerInfo.dwOKEffect        = dwOKEffect;\r
-  trackerInfo.pdwEffect         = pdwEffect;\r
-  trackerInfo.trackingDone      = FALSE;\r
-  trackerInfo.escPressed        = FALSE;\r
-  trackerInfo.curDragTargetHWND = 0;\r
-  trackerInfo.curTargetHWND     = 0;\r
-  trackerInfo.curDragTarget     = 0;\r
-\r
-  hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,\r
-                                   "TrackerWindow",\r
-                                   WS_POPUP,\r
-                                   CW_USEDEFAULT, CW_USEDEFAULT,\r
-                                   CW_USEDEFAULT, CW_USEDEFAULT,\r
-                                   0,\r
-                                   0,\r
-                                   0,\r
-                                   (LPVOID)&trackerInfo);\r
-\r
-  if (hwndTrackWindow!=0)\r
-  {\r
-    /*\r
-     * Capture the mouse input\r
-     */\r
-    SetCapture(hwndTrackWindow);\r
-\r
-    /*\r
-     * Pump messages. All mouse input should go the the capture window.\r
-     */\r
-    while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )\r
-    {\r
-      if ( (msg.message >= WM_KEYFIRST) &&\r
-          (msg.message <= WM_KEYLAST) )\r
-      {\r
-       /*\r
-        * When keyboard messages are sent to windows on this thread, we\r
-        * want to ignore notify the drop source that the state changed.\r
-        * in the case of the Escape key, we also notify the drop source\r
-        * we give it a special meaning.\r
-        */\r
-       if ( (msg.message==WM_KEYDOWN) &&\r
-            (msg.wParam==VK_ESCAPE) )\r
-       {\r
-         trackerInfo.escPressed = TRUE;\r
-       }\r
-\r
-       /*\r
-        * Notify the drop source.\r
-        */\r
-       OLEDD_TrackStateChange(&trackerInfo,\r
-                              msg.pt,\r
-                              OLEDD_GetButtonState());\r
-      }\r
-      else\r
-      {\r
-       /*\r
-        * Dispatch the messages only when it's not a keyboard message.\r
-        */\r
-       DispatchMessageA(&msg);\r
-      }\r
-    }\r
-\r
-    /*\r
-     * Destroy the temporary window.\r
-     */\r
-    DestroyWindow(hwndTrackWindow);\r
-\r
-    return trackerInfo.returnValue;\r
-  }\r
-\r
-  return E_FAIL;\r
-}\r
-\r
-/***********************************************************************\r
- * OleQueryLinkFromData [OLE32.@]\r
- */\r
-HRESULT WINAPI OleQueryLinkFromData(\r
-  IDataObject* pSrcDataObject)\r
-{\r
-  FIXME("(%p),stub!\n", pSrcDataObject);\r
-  return S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- * OleRegGetMiscStatus [OLE32.@]\r
- */\r
-HRESULT WINAPI OleRegGetMiscStatus(\r
-  REFCLSID clsid,\r
-  DWORD    dwAspect,\r
-  DWORD*   pdwStatus)\r
-{\r
-  char    keyName[60];\r
-  HKEY    clsidKey;\r
-  HKEY    miscStatusKey;\r
-  HKEY    aspectKey;\r
-  LONG    result;\r
-\r
-  /*\r
-   * Initialize the out parameter.\r
-   */\r
-  *pdwStatus = 0;\r
-\r
-  /*\r
-   * Build the key name we're looking for\r
-   */\r
-  sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",\r
-           clsid->Data1, clsid->Data2, clsid->Data3,\r
-           clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],\r
-           clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );\r
-\r
-  TRACE("(%s, %ld, %p)\n", keyName, dwAspect, pdwStatus);\r
-\r
-  /*\r
-   * Open the class id Key\r
-   */\r
-  result = RegOpenKeyA(HKEY_CLASSES_ROOT,\r
-                      keyName,\r
-                      &clsidKey);\r
-\r
-  if (result != ERROR_SUCCESS)\r
-    return REGDB_E_CLASSNOTREG;\r
-\r
-  /*\r
-   * Get the MiscStatus\r
-   */\r
-  result = RegOpenKeyA(clsidKey,\r
-                      "MiscStatus",\r
-                      &miscStatusKey);\r
-\r
-\r
-  if (result != ERROR_SUCCESS)\r
-  {\r
-    RegCloseKey(clsidKey);\r
-    return REGDB_E_READREGDB;\r
-  }\r
-\r
-  /*\r
-   * Read the default value\r
-   */\r
-  OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);\r
-\r
-  /*\r
-   * Open the key specific to the requested aspect.\r
-   */\r
-  sprintf(keyName, "%ld", dwAspect);\r
-\r
-  result = RegOpenKeyA(miscStatusKey,\r
-                      keyName,\r
-                      &aspectKey);\r
-\r
-  if (result == ERROR_SUCCESS)\r
-  {\r
-    OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);\r
-    RegCloseKey(aspectKey);\r
-  }\r
-\r
-  /*\r
-   * Cleanup\r
-   */\r
-  RegCloseKey(miscStatusKey);\r
-  RegCloseKey(clsidKey);\r
-\r
-  return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- *              OleSetContainedObject        [OLE32.@]\r
- */\r
-HRESULT WINAPI OleSetContainedObject(\r
-  LPUNKNOWN pUnknown,\r
-  BOOL      fContained)\r
-{\r
-  IRunnableObject* runnable = NULL;\r
-  HRESULT          hres;\r
-\r
-  TRACE("(%p,%x), stub!\n", pUnknown, fContained);\r
-\r
-  hres = IUnknown_QueryInterface(pUnknown,\r
-                                &IID_IRunnableObject,\r
-                                (void**)&runnable);\r
-\r
-  if (SUCCEEDED(hres))\r
-  {\r
-    hres = IRunnableObject_SetContainedObject(runnable, fContained);\r
-\r
-    IRunnableObject_Release(runnable);\r
-\r
-    return hres;\r
-  }\r
-\r
-  return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- *              OleLoad        [OLE32.@]\r
- */\r
-HRESULT WINAPI OleLoad(\r
-  LPSTORAGE       pStg,\r
-  REFIID          riid,\r
-  LPOLECLIENTSITE pClientSite,\r
-  LPVOID*         ppvObj)\r
-{\r
-  IPersistStorage* persistStorage = NULL;\r
-  IOleObject*      oleObject      = NULL;\r
-  STATSTG          storageInfo;\r
-  HRESULT          hres;\r
-\r
-  TRACE("(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj);\r
-\r
-  /*\r
-   * TODO, Conversion ... OleDoAutoConvert\r
-   */\r
-\r
-  /*\r
-   * Get the class ID for the object.\r
-   */\r
-  hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);\r
-\r
-  /*\r
-   * Now, try and create the handler for the object\r
-   */\r
-  hres = CoCreateInstance(&storageInfo.clsid,\r
-                         NULL,\r
-                         CLSCTX_INPROC_HANDLER,\r
-                         &IID_IOleObject,\r
-                         (void**)&oleObject);\r
-\r
-  /*\r
-   * If that fails, as it will most times, load the default\r
-   * OLE handler.\r
-   */\r
-  if (FAILED(hres))\r
-  {\r
-    hres = OleCreateDefaultHandler(&storageInfo.clsid,\r
-                                  NULL,\r
-                                  &IID_IOleObject,\r
-                                  (void**)&oleObject);\r
-  }\r
-\r
-  /*\r
-   * If we couldn't find a handler... this is bad. Abort the whole thing.\r
-   */\r
-  if (FAILED(hres))\r
-    return hres;\r
-\r
-  /*\r
-   * Inform the new object of it's client site.\r
-   */\r
-  hres = IOleObject_SetClientSite(oleObject, pClientSite);\r
-\r
-  /*\r
-   * Initialize the object with it's IPersistStorage interface.\r
-   */\r
-  hres = IOleObject_QueryInterface(oleObject,\r
-                                  &IID_IPersistStorage,\r
-                                  (void**)&persistStorage);\r
-\r
-  if (SUCCEEDED(hres))\r
-  {\r
-    IPersistStorage_Load(persistStorage, pStg);\r
-\r
-    IPersistStorage_Release(persistStorage);\r
-    persistStorage = NULL;\r
-  }\r
-\r
-  /*\r
-   * Return the requested interface to the caller.\r
-   */\r
-  hres = IOleObject_QueryInterface(oleObject, riid, ppvObj);\r
-\r
-  /*\r
-   * Cleanup interfaces used internally\r
-   */\r
-  IOleObject_Release(oleObject);\r
-\r
-  return hres;\r
-}\r
-\r
-/***********************************************************************\r
- *           OleSave     [OLE32.@]\r
- */\r
-HRESULT WINAPI OleSave(\r
-  LPPERSISTSTORAGE pPS,\r
-  LPSTORAGE        pStg,\r
-  BOOL             fSameAsLoad)\r
-{\r
-  HRESULT hres;\r
-  CLSID   objectClass;\r
-\r
-  TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);\r
-\r
-  /*\r
-   * First, we transfer the class ID (if available)\r
-   */\r
-  hres = IPersistStorage_GetClassID(pPS, &objectClass);\r
-\r
-  if (SUCCEEDED(hres))\r
-  {\r
-    WriteClassStg(pStg, &objectClass);\r
-  }\r
-\r
-  /*\r
-   * Then, we ask the object to save itself to the\r
-   * storage. If it is successful, we commit the storage.\r
-   */\r
-  hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);\r
-\r
-  if (SUCCEEDED(hres))\r
-  {\r
-    IStorage_Commit(pStg,\r
-                   STGC_DEFAULT);\r
-  }\r
-\r
-  return hres;\r
-}\r
-\r
-\r
-/******************************************************************************\r
- *              OleLockRunning        [OLE32.@]\r
- */\r
-HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)\r
-{\r
-  IRunnableObject* runnable = NULL;\r
-  HRESULT          hres;\r
-\r
-  TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);\r
-\r
-  hres = IUnknown_QueryInterface(pUnknown,\r
-                                &IID_IRunnableObject,\r
-                                (void**)&runnable);\r
-\r
-  if (SUCCEEDED(hres))\r
-  {\r
-    hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);\r
-\r
-    IRunnableObject_Release(runnable);\r
-\r
-    return hres;\r
-  }\r
-  else\r
-    return E_INVALIDARG;\r
-}\r
-\r
-\r
-/**************************************************************************\r
- * Internal methods to manage the shared OLE menu in response to the\r
- * OLE***MenuDescriptor API\r
- */\r
-\r
-/***\r
- * OLEMenu_Initialize()\r
- *\r
- * Initializes the OLEMENU data structures.\r
- */\r
-static void OLEMenu_Initialize()\r
-{\r
-}\r
-\r
-/***\r
- * OLEMenu_UnInitialize()\r
- *\r
- * Releases the OLEMENU data structures.\r
- */\r
-static void OLEMenu_UnInitialize()\r
-{\r
-}\r
-\r
-/*************************************************************************\r
- * OLEMenu_InstallHooks\r
- * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC\r
- *\r
- * RETURNS: TRUE if message hooks were successfully installed\r
- *          FALSE on failure\r
- */\r
-BOOL OLEMenu_InstallHooks( DWORD tid )\r
-{\r
-  OleMenuHookItem *pHookItem = NULL;\r
-\r
-  /* Create an entry for the hook table */\r
-  if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,\r
-                               sizeof(OleMenuHookItem)) ) )\r
-    return FALSE;\r
-\r
-  pHookItem->tid = tid;\r
-  pHookItem->hHeap = GetProcessHeap();\r
-\r
-  /* Install a thread scope message hook for WH_GETMESSAGE */\r
-  pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,\r
-                                               0, GetCurrentThreadId() );\r
-  if ( !pHookItem->GetMsg_hHook )\r
-    goto CLEANUP;\r
-\r
-  /* Install a thread scope message hook for WH_CALLWNDPROC */\r
-  pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,\r
-                                                    0, GetCurrentThreadId() );\r
-  if ( !pHookItem->CallWndProc_hHook )\r
-    goto CLEANUP;\r
-\r
-  /* Insert the hook table entry */\r
-  pHookItem->next = hook_list;\r
-  hook_list = pHookItem;\r
-\r
-  return TRUE;\r
-\r
-CLEANUP:\r
-  /* Unhook any hooks */\r
-  if ( pHookItem->GetMsg_hHook )\r
-    UnhookWindowsHookEx( pHookItem->GetMsg_hHook );\r
-  if ( pHookItem->CallWndProc_hHook )\r
-    UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );\r
-  /* Release the hook table entry */\r
-  HeapFree(pHookItem->hHeap, 0, pHookItem );\r
-\r
-  return FALSE;\r
-}\r
-\r
-/*************************************************************************\r
- * OLEMenu_UnInstallHooks\r
- * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC\r
- *\r
- * RETURNS: TRUE if message hooks were successfully installed\r
- *          FALSE on failure\r
- */\r
-BOOL OLEMenu_UnInstallHooks( DWORD tid )\r
-{\r
-  OleMenuHookItem *pHookItem = NULL;\r
-  OleMenuHookItem **ppHook = &hook_list;\r
-\r
-  while (*ppHook)\r
-  {\r
-      if ((*ppHook)->tid == tid)\r
-      {\r
-          pHookItem = *ppHook;\r
-          *ppHook = pHookItem->next;\r
-          break;\r
-      }\r
-      ppHook = &(*ppHook)->next;\r
-  }\r
-  if (!pHookItem) return FALSE;\r
-\r
-  /* Uninstall the hooks installed for this thread */\r
-  if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )\r
-    goto CLEANUP;\r
-  if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )\r
-    goto CLEANUP;\r
-\r
-  /* Release the hook table entry */\r
-  HeapFree(pHookItem->hHeap, 0, pHookItem );\r
-\r
-  return TRUE;\r
-\r
-CLEANUP:\r
-  /* Release the hook table entry */\r
-  HeapFree(pHookItem->hHeap, 0, pHookItem );\r
-\r
-  return FALSE;\r
-}\r
-\r
-/*************************************************************************\r
- * OLEMenu_IsHookInstalled\r
- * Tests if OLEMenu hooks have been installed for a thread\r
- *\r
- * RETURNS: The pointer and index of the hook table entry for the tid\r
- *          NULL and -1 for the index if no hooks were installed for this thread\r
- */\r
-OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )\r
-{\r
-  OleMenuHookItem *pHookItem = NULL;\r
-\r
-  /* Do a simple linear search for an entry whose tid matches ours.\r
-   * We really need a map but efficiency is not a concern here. */\r
-  for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)\r
-  {\r
-    if ( tid == pHookItem->tid )\r
-      return pHookItem;\r
-  }\r
-\r
-  return NULL;\r
-}\r
-\r
-/***********************************************************************\r
- *           OLEMenu_FindMainMenuIndex\r
- *\r
- * Used by OLEMenu API to find the top level group a menu item belongs to.\r
- * On success pnPos contains the index of the item in the top level menu group\r
- *\r
- * RETURNS: TRUE if the ID was found, FALSE on failure\r
- */\r
-static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )\r
-{\r
-  UINT i, nItems;\r
-\r
-  nItems = GetMenuItemCount( hMainMenu );\r
-\r
-  for (i = 0; i < nItems; i++)\r
-  {\r
-    HMENU hsubmenu;\r
-\r
-    /*  Is the current item a submenu? */\r
-    if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )\r
-    {\r
-      /* If the handle is the same we're done */\r
-      if ( hsubmenu == hPopupMenu )\r
-      {\r
-        if (pnPos)\r
-          *pnPos = i;\r
-        return TRUE;\r
-      }\r
-      /* Recursively search without updating pnPos */\r
-      else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )\r
-      {\r
-        if (pnPos)\r
-          *pnPos = i;\r
-        return TRUE;\r
-      }\r
-    }\r
-  }\r
-\r
-  return FALSE;\r
-}\r
-\r
-/***********************************************************************\r
- *           OLEMenu_SetIsServerMenu\r
- *\r
- * Checks whether a popup menu belongs to a shared menu group which is\r
- * owned by the server, and sets the menu descriptor state accordingly.\r
- * All menu messages from these groups should be routed to the server.\r
- *\r
- * RETURNS: TRUE if the popup menu is part of a server owned group\r
- *          FALSE if the popup menu is part of a container owned group\r
- */\r
-BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )\r
-{\r
-  UINT nPos = 0, nWidth, i;\r
-\r
-  pOleMenuDescriptor->bIsServerItem = FALSE;\r
-\r
-  /* Don't bother searching if the popup is the combined menu itself */\r
-  if ( hmenu == pOleMenuDescriptor->hmenuCombined )\r
-    return FALSE;\r
-\r
-  /* Find the menu item index in the shared OLE menu that this item belongs to */\r
-  if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu,  &nPos ) )\r
-    return FALSE;\r
-\r
-  /* The group widths array has counts for the number of elements\r
-   * in the groups File, Edit, Container, Object, Window, Help.\r
-   * The Edit, Object & Help groups belong to the server object\r
-   * and the other three belong to the container.\r
-   * Loop through the group widths and locate the group we are a member of.\r
-   */\r
-  for ( i = 0, nWidth = 0; i < 6; i++ )\r
-  {\r
-    nWidth += pOleMenuDescriptor->mgw.width[i];\r
-    if ( nPos < nWidth )\r
-    {\r
-      /* Odd elements are server menu widths */\r
-      pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;\r
-      break;\r
-    }\r
-  }\r
-\r
-  return pOleMenuDescriptor->bIsServerItem;\r
-}\r
-\r
-/*************************************************************************\r
- * OLEMenu_CallWndProc\r
- * Thread scope WH_CALLWNDPROC hook proc filter function (callback)\r
- * This is invoked from a message hook installed in OleSetMenuDescriptor.\r
- */\r
-LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)\r
-{\r
-  LPCWPSTRUCT pMsg = NULL;\r
-  HOLEMENU hOleMenu = 0;\r
-  OleMenuDescriptor *pOleMenuDescriptor = NULL;\r
-  OleMenuHookItem *pHookItem = NULL;\r
-  WORD fuFlags;\r
-\r
-  TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );\r
-\r
-  /* Check if we're being asked to process the message */\r
-  if ( HC_ACTION != code )\r
-    goto NEXTHOOK;\r
-\r
-  /* Retrieve the current message being dispatched from lParam */\r
-  pMsg = (LPCWPSTRUCT)lParam;\r
-\r
-  /* Check if the message is destined for a window we are interested in:\r
-   * If the window has an OLEMenu property we may need to dispatch\r
-   * the menu message to its active objects window instead. */\r
-\r
-  hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );\r
-  if ( !hOleMenu )\r
-    goto NEXTHOOK;\r
-\r
-  /* Get the menu descriptor */\r
-  pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );\r
-  if ( !pOleMenuDescriptor ) /* Bad descriptor! */\r
-    goto NEXTHOOK;\r
-\r
-  /* Process menu messages */\r
-  switch( pMsg->message )\r
-  {\r
-    case WM_INITMENU:\r
-    {\r
-      /* Reset the menu descriptor state */\r
-      pOleMenuDescriptor->bIsServerItem = FALSE;\r
-\r
-      /* Send this message to the server as well */\r
-      SendMessageA( pOleMenuDescriptor->hwndActiveObject,\r
-                  pMsg->message, pMsg->wParam, pMsg->lParam );\r
-      goto NEXTHOOK;\r
-    }\r
-\r
-    case WM_INITMENUPOPUP:\r
-    {\r
-      /* Save the state for whether this is a server owned menu */\r
-      OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );\r
-      break;\r
-    }\r
-\r
-    case WM_MENUSELECT:\r
-    {\r
-      fuFlags = HIWORD(pMsg->wParam);  /* Get flags */\r
-      if ( fuFlags & MF_SYSMENU )\r
-         goto NEXTHOOK;\r
-\r
-      /* Save the state for whether this is a server owned popup menu */\r
-      else if ( fuFlags & MF_POPUP )\r
-        OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );\r
-\r
-      break;\r
-    }\r
-\r
-    case WM_DRAWITEM:\r
-    {\r
-      LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;\r
-      if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )\r
-        goto NEXTHOOK;  /* Not a menu message */\r
-\r
-      break;\r
-    }\r
-\r
-    default:\r
-      goto NEXTHOOK;\r
-  }\r
-\r
-  /* If the message was for the server dispatch it accordingly */\r
-  if ( pOleMenuDescriptor->bIsServerItem )\r
-  {\r
-    SendMessageA( pOleMenuDescriptor->hwndActiveObject,\r
-                  pMsg->message, pMsg->wParam, pMsg->lParam );\r
-  }\r
-\r
-NEXTHOOK:\r
-  if ( pOleMenuDescriptor )\r
-    GlobalUnlock( hOleMenu );\r
-\r
-  /* Lookup the hook item for the current thread */\r
-  if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )\r
-  {\r
-    /* This should never fail!! */\r
-    WARN("could not retrieve hHook for current thread!\n" );\r
-    return 0;\r
-  }\r
-\r
-  /* Pass on the message to the next hooker */\r
-  return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );\r
-}\r
-\r
-/*************************************************************************\r
- * OLEMenu_GetMsgProc\r
- * Thread scope WH_GETMESSAGE hook proc filter function (callback)\r
- * This is invoked from a message hook installed in OleSetMenuDescriptor.\r
- */\r
-LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)\r
-{\r
-  LPMSG pMsg = NULL;\r
-  HOLEMENU hOleMenu = 0;\r
-  OleMenuDescriptor *pOleMenuDescriptor = NULL;\r
-  OleMenuHookItem *pHookItem = NULL;\r
-  WORD wCode;\r
-\r
-  TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );\r
-\r
-  /* Check if we're being asked to process a  messages */\r
-  if ( HC_ACTION != code )\r
-    goto NEXTHOOK;\r
-\r
-  /* Retrieve the current message being dispatched from lParam */\r
-  pMsg = (LPMSG)lParam;\r
-\r
-  /* Check if the message is destined for a window we are interested in:\r
-   * If the window has an OLEMenu property we may need to dispatch\r
-   * the menu message to its active objects window instead. */\r
-\r
-  hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );\r
-  if ( !hOleMenu )\r
-    goto NEXTHOOK;\r
-\r
-  /* Process menu messages */\r
-  switch( pMsg->message )\r
-  {\r
-    case WM_COMMAND:\r
-    {\r
-      wCode = HIWORD(pMsg->wParam);  /* Get notification code */\r
-      if ( wCode )\r
-        goto NEXTHOOK;  /* Not a menu message */\r
-      break;\r
-    }\r
-    default:\r
-      goto NEXTHOOK;\r
-  }\r
-\r
-  /* Get the menu descriptor */\r
-  pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );\r
-  if ( !pOleMenuDescriptor ) /* Bad descriptor! */\r
-    goto NEXTHOOK;\r
-\r
-  /* If the message was for the server dispatch it accordingly */\r
-  if ( pOleMenuDescriptor->bIsServerItem )\r
-  {\r
-    /* Change the hWnd in the message to the active objects hWnd.\r
-     * The message loop which reads this message will automatically\r
-     * dispatch it to the embedded objects window. */\r
-    pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;\r
-  }\r
-\r
-NEXTHOOK:\r
-  if ( pOleMenuDescriptor )\r
-    GlobalUnlock( hOleMenu );\r
-\r
-  /* Lookup the hook item for the current thread */\r
-  if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )\r
-  {\r
-    /* This should never fail!! */\r
-    WARN("could not retrieve hHook for current thread!\n" );\r
-    return FALSE;\r
-  }\r
-\r
-  /* Pass on the message to the next hooker */\r
-  return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );\r
-}\r
-\r
-/***********************************************************************\r
- * OleCreateMenuDescriptor [OLE32.@]\r
- * Creates an OLE menu descriptor for OLE to use when dispatching\r
- * menu messages and commands.\r
- *\r
- * PARAMS:\r
- *    hmenuCombined  -  Handle to the objects combined menu\r
- *    lpMenuWidths   -  Pointer to array of 6 LONG's indicating menus per group\r
- *\r
- */\r
-HOLEMENU WINAPI OleCreateMenuDescriptor(\r
-  HMENU                hmenuCombined,\r
-  LPOLEMENUGROUPWIDTHS lpMenuWidths)\r
-{\r
-  HOLEMENU hOleMenu;\r
-  OleMenuDescriptor *pOleMenuDescriptor;\r
-  int i;\r
-\r
-  if ( !hmenuCombined || !lpMenuWidths )\r
-    return 0;\r
-\r
-  /* Create an OLE menu descriptor */\r
-  if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,\r
-                                sizeof(OleMenuDescriptor) ) ) )\r
-  return 0;\r
-\r
-  pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );\r
-  if ( !pOleMenuDescriptor )\r
-    return 0;\r
-\r
-  /* Initialize menu group widths and hmenu */\r
-  for ( i = 0; i < 6; i++ )\r
-    pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];\r
-\r
-  pOleMenuDescriptor->hmenuCombined = hmenuCombined;\r
-  pOleMenuDescriptor->bIsServerItem = FALSE;\r
-  GlobalUnlock( hOleMenu );\r
-\r
-  return hOleMenu;\r
-}\r
-\r
-/***********************************************************************\r
- * OleDestroyMenuDescriptor [OLE32.@]\r
- * Destroy the shared menu descriptor\r
- */\r
-HRESULT WINAPI OleDestroyMenuDescriptor(\r
-  HOLEMENU hmenuDescriptor)\r
-{\r
-  if ( hmenuDescriptor )\r
-    GlobalFree( hmenuDescriptor );\r
-       return S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- * OleSetMenuDescriptor [OLE32.@]\r
- * Installs or removes OLE dispatching code for the containers frame window\r
- * FIXME: The lpFrame and lpActiveObject parameters are currently ignored\r
- * OLE should install context sensitive help F1 filtering for the app when\r
- * these are non null.\r
- *\r
- * PARAMS:\r
- *     hOleMenu         Handle to composite menu descriptor\r
- *     hwndFrame        Handle to containers frame window\r
- *     hwndActiveObject Handle to objects in-place activation window\r
- *     lpFrame          Pointer to IOleInPlaceFrame on containers window\r
- *     lpActiveObject   Pointer to IOleInPlaceActiveObject on active in-place object\r
- *\r
- * RETURNS:\r
- *      S_OK                               - menu installed correctly\r
- *      E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure\r
- */\r
-HRESULT WINAPI OleSetMenuDescriptor(\r
-  HOLEMENU               hOleMenu,\r
-  HWND                   hwndFrame,\r
-  HWND                   hwndActiveObject,\r
-  LPOLEINPLACEFRAME        lpFrame,\r
-  LPOLEINPLACEACTIVEOBJECT lpActiveObject)\r
-{\r
-  OleMenuDescriptor *pOleMenuDescriptor = NULL;\r
-\r
-  /* Check args */\r
-  if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )\r
-    return E_INVALIDARG;\r
-\r
-  if ( lpFrame || lpActiveObject )\r
-  {\r
-     FIXME("(%x, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",\r
-       (unsigned int)hOleMenu,\r
-       hwndFrame,\r
-       hwndActiveObject,\r
-       lpFrame,\r
-       lpActiveObject);\r
-  }\r
-\r
-  /* Set up a message hook to intercept the containers frame window messages.\r
-   * The message filter is responsible for dispatching menu messages from the\r
-   * shared menu which are intended for the object.\r
-   */\r
-\r
-  if ( hOleMenu )  /* Want to install dispatching code */\r
-  {\r
-    /* If OLEMenu hooks are already installed for this thread, fail\r
-     * Note: This effectively means that OleSetMenuDescriptor cannot\r
-     * be called twice in succession on the same frame window\r
-     * without first calling it with a null hOleMenu to uninstall */\r
-    if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )\r
-  return E_FAIL;\r
-\r
-    /* Get the menu descriptor */\r
-    pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );\r
-    if ( !pOleMenuDescriptor )\r
-      return E_UNEXPECTED;\r
-\r
-    /* Update the menu descriptor */\r
-    pOleMenuDescriptor->hwndFrame = hwndFrame;\r
-    pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;\r
-\r
-    GlobalUnlock( hOleMenu );\r
-    pOleMenuDescriptor = NULL;\r
-\r
-    /* Add a menu descriptor windows property to the frame window */\r
-    SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );\r
-\r
-    /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */\r
-    if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )\r
-      return E_FAIL;\r
-  }\r
-  else  /* Want to uninstall dispatching code */\r
-  {\r
-    /* Uninstall the hooks */\r
-    if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )\r
-      return E_FAIL;\r
-\r
-    /* Remove the menu descriptor property from the frame window */\r
-    RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );\r
-  }\r
-\r
-  return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- *              IsAccelerator        [OLE32.@]\r
- * Mostly copied from controls/menu.c TranslateAccelerator implementation\r
- */\r
-BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)\r
-{\r
-    LPACCEL lpAccelTbl;\r
-    int i;\r
-\r
-    if(!lpMsg) return FALSE;\r
-    if (!hAccel)\r
-    {\r
-       WARN_(accel)("NULL accel handle\n");\r
-       return FALSE;\r
-    }\r
-    if((lpMsg->message != WM_KEYDOWN &&\r
-       lpMsg->message != WM_KEYUP &&\r
-       lpMsg->message != WM_SYSKEYDOWN &&\r
-       lpMsg->message != WM_SYSKEYUP &&\r
-       lpMsg->message != WM_CHAR)) return FALSE;\r
-    lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL));\r
-    if (NULL == lpAccelTbl)\r
-    {\r
-       return FALSE;\r
-    }\r
-    if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries)\r
-    {\r
-       WARN_(accel)("CopyAcceleratorTableW failed\n");\r
-       HeapFree(GetProcessHeap(), 0, lpAccelTbl);\r
-       return FALSE;\r
-    }\r
-\r
-    TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"\r
-               "msg->hwnd=%p, msg->message=%04x, wParam=%08x, lParam=%08lx\n",\r
-               hAccel, cAccelEntries,\r
-               lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);\r
-    for(i = 0; i < cAccelEntries; i++)\r
-    {\r
-       if(lpAccelTbl[i].key != lpMsg->wParam)\r
-           continue;\r
-\r
-       if(lpMsg->message == WM_CHAR)\r
-       {\r
-           if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))\r
-           {\r
-               TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", lpMsg->wParam & 0xff);\r
-               goto found;\r
-           }\r
-       }\r
-       else\r
-       {\r
-           if(lpAccelTbl[i].fVirt & FVIRTKEY)\r
-           {\r
-               INT mask = 0;\r
-               TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",\r
-                               lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);\r
-               if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;\r
-               if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;\r
-               if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;\r
-               if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;\r
-               TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");\r
-           }\r
-           else\r
-           {\r
-               if(!(lpMsg->lParam & 0x01000000))  /* no special_key */\r
-               {\r
-                   if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))\r
-                   {                                                  /* ^^ ALT pressed */\r
-                       TRACE_(accel)("found accel for Alt-%c\n", lpMsg->wParam & 0xff);\r
-                       goto found;\r
-                   }\r
-               }\r
-           }\r
-       }\r
-    }\r
-\r
-    WARN_(accel)("couldn't translate accelerator key\n");\r
-    HeapFree(GetProcessHeap(), 0, lpAccelTbl);\r
-    return FALSE;\r
-\r
-found:\r
-    if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;\r
-    HeapFree(GetProcessHeap(), 0, lpAccelTbl);\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- * ReleaseStgMedium [OLE32.@]\r
- */\r
-void WINAPI ReleaseStgMedium(\r
-  STGMEDIUM* pmedium)\r
-{\r
-  switch (pmedium->tymed)\r
-  {\r
-    case TYMED_HGLOBAL:\r
-    {\r
-      if ( (pmedium->pUnkForRelease==0) &&\r
-          (pmedium->u.hGlobal!=0) )\r
-       GlobalFree(pmedium->u.hGlobal);\r
-      break;\r
-    }\r
-    case TYMED_FILE:\r
-    {\r
-      if (pmedium->u.lpszFileName!=0)\r
-      {\r
-       if (pmedium->pUnkForRelease==0)\r
-       {\r
-         DeleteFileW(pmedium->u.lpszFileName);\r
-       }\r
-\r
-       CoTaskMemFree(pmedium->u.lpszFileName);\r
-      }\r
-      break;\r
-    }\r
-    case TYMED_ISTREAM:\r
-    {\r
-      if (pmedium->u.pstm!=0)\r
-      {\r
-       IStream_Release(pmedium->u.pstm);\r
-      }\r
-      break;\r
-    }\r
-    case TYMED_ISTORAGE:\r
-    {\r
-      if (pmedium->u.pstg!=0)\r
-      {\r
-       IStorage_Release(pmedium->u.pstg);\r
-      }\r
-      break;\r
-    }\r
-    case TYMED_GDI:\r
-    {\r
-      if ( (pmedium->pUnkForRelease==0) &&\r
-          (pmedium->u.hBitmap!=0) )\r
-       DeleteObject(pmedium->u.hBitmap);\r
-      break;\r
-    }\r
-    case TYMED_MFPICT:\r
-    {\r
-      if ( (pmedium->pUnkForRelease==0) &&\r
-          (pmedium->u.hMetaFilePict!=0) )\r
-      {\r
-       LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);\r
-       DeleteMetaFile(pMP->hMF);\r
-       GlobalUnlock(pmedium->u.hMetaFilePict);\r
-       GlobalFree(pmedium->u.hMetaFilePict);\r
-      }\r
-      break;\r
-    }\r
-    case TYMED_ENHMF:\r
-    {\r
-      if ( (pmedium->pUnkForRelease==0) &&\r
-          (pmedium->u.hEnhMetaFile!=0) )\r
-      {\r
-       DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);\r
-      }\r
-      break;\r
-    }\r
-    case TYMED_NULL:\r
-    default:\r
-      break;\r
-  }\r
-  pmedium->tymed=TYMED_NULL;\r
-\r
-  /*\r
-   * After cleaning up, the unknown is released\r
-   */\r
-  if (pmedium->pUnkForRelease!=0)\r
-  {\r
-    IUnknown_Release(pmedium->pUnkForRelease);\r
-    pmedium->pUnkForRelease = 0;\r
-  }\r
-}\r
-\r
-/***\r
- * OLEDD_Initialize()\r
- *\r
- * Initializes the OLE drag and drop data structures.\r
- */\r
-static void OLEDD_Initialize()\r
-{\r
-    WNDCLASSA wndClass;\r
-\r
-    ZeroMemory (&wndClass, sizeof(WNDCLASSA));\r
-    wndClass.style         = CS_GLOBALCLASS;\r
-    wndClass.lpfnWndProc   = OLEDD_DragTrackerWindowProc;\r
-    wndClass.cbClsExtra    = 0;\r
-    wndClass.cbWndExtra    = sizeof(TrackerWindowInfo*);\r
-    wndClass.hCursor       = 0;\r
-    wndClass.hbrBackground = 0;\r
-    wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;\r
-\r
-    RegisterClassA (&wndClass);\r
-}\r
-\r
-/***\r
- * OLEDD_UnInitialize()\r
- *\r
- * Releases the OLE drag and drop data structures.\r
- */\r
-static void OLEDD_UnInitialize()\r
-{\r
-  /*\r
-   * Simply empty the list.\r
-   */\r
-  while (targetListHead!=NULL)\r
-  {\r
-    RevokeDragDrop(targetListHead->hwndTarget);\r
-  }\r
-}\r
-\r
-/***\r
- * OLEDD_InsertDropTarget()\r
- *\r
- * Insert the target node in the tree.\r
- */\r
-static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)\r
-{\r
-  DropTargetNode*  curNode;\r
-  DropTargetNode** parentNodeLink;\r
-\r
-  /*\r
-   * Iterate the tree to find the insertion point.\r
-   */\r
-  curNode        = targetListHead;\r
-  parentNodeLink = &targetListHead;\r
-\r
-  while (curNode!=NULL)\r
-  {\r
-    if (nodeToAdd->hwndTarget<curNode->hwndTarget)\r
-    {\r
-      /*\r
-       * If the node we want to add has a smaller HWND, go left\r
-       */\r
-      parentNodeLink = &curNode->prevDropTarget;\r
-      curNode        =  curNode->prevDropTarget;\r
-    }\r
-    else if (nodeToAdd->hwndTarget>curNode->hwndTarget)\r
-    {\r
-      /*\r
-       * If the node we want to add has a larger HWND, go right\r
-       */\r
-      parentNodeLink = &curNode->nextDropTarget;\r
-      curNode        =  curNode->nextDropTarget;\r
-    }\r
-    else\r
-    {\r
-      /*\r
-       * The item was found in the list. It shouldn't have been there\r
-       */\r
-      assert(FALSE);\r
-      return;\r
-    }\r
-  }\r
-\r
-  /*\r
-   * If we get here, we have found a spot for our item. The parentNodeLink\r
-   * pointer points to the pointer that we have to modify.\r
-   * The curNode should be NULL. We just have to establish the link and Voila!\r
-   */\r
-  assert(curNode==NULL);\r
-  assert(parentNodeLink!=NULL);\r
-  assert(*parentNodeLink==NULL);\r
-\r
-  *parentNodeLink=nodeToAdd;\r
-}\r
-\r
-/***\r
- * OLEDD_ExtractDropTarget()\r
- *\r
- * Removes the target node from the tree.\r
- */\r
-static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)\r
-{\r
-  DropTargetNode*  curNode;\r
-  DropTargetNode** parentNodeLink;\r
-\r
-  /*\r
-   * Iterate the tree to find the insertion point.\r
-   */\r
-  curNode        = targetListHead;\r
-  parentNodeLink = &targetListHead;\r
-\r
-  while (curNode!=NULL)\r
-  {\r
-    if (hwndOfTarget<curNode->hwndTarget)\r
-    {\r
-      /*\r
-       * If the node we want to add has a smaller HWND, go left\r
-       */\r
-      parentNodeLink = &curNode->prevDropTarget;\r
-      curNode        =  curNode->prevDropTarget;\r
-    }\r
-    else if (hwndOfTarget>curNode->hwndTarget)\r
-    {\r
-      /*\r
-       * If the node we want to add has a larger HWND, go right\r
-       */\r
-      parentNodeLink = &curNode->nextDropTarget;\r
-      curNode        =  curNode->nextDropTarget;\r
-    }\r
-    else\r
-    {\r
-      /*\r
-       * The item was found in the list. Detach it from it's parent and\r
-       * re-insert it's kids in the tree.\r
-       */\r
-      assert(parentNodeLink!=NULL);\r
-      assert(*parentNodeLink==curNode);\r
-\r
-      /*\r
-       * We arbitrately re-attach the left sub-tree to the parent.\r
-       */\r
-      *parentNodeLink = curNode->prevDropTarget;\r
-\r
-      /*\r
-       * And we re-insert the right subtree\r
-       */\r
-      if (curNode->nextDropTarget!=NULL)\r
-      {\r
-       OLEDD_InsertDropTarget(curNode->nextDropTarget);\r
-      }\r
-\r
-      /*\r
-       * The node we found is still a valid node once we complete\r
-       * the unlinking of the kids.\r
-       */\r
-      curNode->nextDropTarget=NULL;\r
-      curNode->prevDropTarget=NULL;\r
-\r
-      return curNode;\r
-    }\r
-  }\r
-\r
-  /*\r
-   * If we get here, the node is not in the tree\r
-   */\r
-  return NULL;\r
-}\r
-\r
-/***\r
- * OLEDD_FindDropTarget()\r
- *\r
- * Finds information about the drop target.\r
- */\r
-static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)\r
-{\r
-  DropTargetNode*  curNode;\r
-\r
-  /*\r
-   * Iterate the tree to find the HWND value.\r
-   */\r
-  curNode        = targetListHead;\r
-\r
-  while (curNode!=NULL)\r
-  {\r
-    if (hwndOfTarget<curNode->hwndTarget)\r
-    {\r
-      /*\r
-       * If the node we want to add has a smaller HWND, go left\r
-       */\r
-      curNode =  curNode->prevDropTarget;\r
-    }\r
-    else if (hwndOfTarget>curNode->hwndTarget)\r
-    {\r
-      /*\r
-       * If the node we want to add has a larger HWND, go right\r
-       */\r
-      curNode =  curNode->nextDropTarget;\r
-    }\r
-    else\r
-    {\r
-      /*\r
-       * The item was found in the list.\r
-       */\r
-      return curNode;\r
-    }\r
-  }\r
-\r
-  /*\r
-   * If we get here, the item is not in the list\r
-   */\r
-  return NULL;\r
-}\r
-\r
-/***\r
- * OLEDD_DragTrackerWindowProc()\r
- *\r
- * This method is the WindowProcedure of the drag n drop tracking\r
- * window. During a drag n Drop operation, an invisible window is created\r
- * to receive the user input and act upon it. This procedure is in charge\r
- * of this behavior.\r
- */\r
-static LRESULT WINAPI OLEDD_DragTrackerWindowProc(\r
-                        HWND   hwnd,\r
-                        UINT   uMsg,\r
-                        WPARAM wParam,\r
-                        LPARAM   lParam)\r
-{\r
-  switch (uMsg)\r
-  {\r
-    case WM_CREATE:\r
-    {\r
-      LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;\r
-\r
-      SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);\r
-\r
-\r
-      break;\r
-    }\r
-    case WM_MOUSEMOVE:\r
-    {\r
-      TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);\r
-      POINT            mousePos;\r
-\r
-      /*\r
-       * Get the current mouse position in screen coordinates.\r
-       */\r
-      mousePos.x = LOWORD(lParam);\r
-      mousePos.y = HIWORD(lParam);\r
-      ClientToScreen(hwnd, &mousePos);\r
-\r
-      /*\r
-       * Track the movement of the mouse.\r
-       */\r
-      OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);\r
-\r
-      break;\r
-    }\r
-    case WM_LBUTTONUP:\r
-    case WM_MBUTTONUP:\r
-    case WM_RBUTTONUP:\r
-    case WM_LBUTTONDOWN:\r
-    case WM_MBUTTONDOWN:\r
-    case WM_RBUTTONDOWN:\r
-    {\r
-      TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);\r
-      POINT            mousePos;\r
-\r
-      /*\r
-       * Get the current mouse position in screen coordinates.\r
-       */\r
-      mousePos.x = LOWORD(lParam);\r
-      mousePos.y = HIWORD(lParam);\r
-      ClientToScreen(hwnd, &mousePos);\r
-\r
-      /*\r
-       * Notify everyone that the button state changed\r
-       * TODO: Check if the "escape" key was pressed.\r
-       */\r
-      OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);\r
-\r
-      break;\r
-    }\r
-  }\r
-\r
-  /*\r
-   * This is a window proc after all. Let's call the default.\r
-   */\r
-  return DefWindowProcA (hwnd, uMsg, wParam, lParam);\r
-}\r
-\r
-/***\r
- * OLEDD_TrackMouseMove()\r
- *\r
- * This method is invoked while a drag and drop operation is in effect.\r
- * it will generate the appropriate callbacks in the drop source\r
- * and drop target. It will also provide the expected feedback to\r
- * the user.\r
- *\r
- * params:\r
- *    trackerInfo - Pointer to the structure identifying the\r
- *                  drag & drop operation that is currently\r
- *                  active.\r
- *    mousePos    - Current position of the mouse in screen\r
- *                  coordinates.\r
- *    keyState    - Contains the state of the shift keys and the\r
- *                  mouse buttons (MK_LBUTTON and the like)\r
- */\r
-static void OLEDD_TrackMouseMove(\r
-  TrackerWindowInfo* trackerInfo,\r
-  POINT            mousePos,\r
-  DWORD              keyState)\r
-{\r
-  HWND   hwndNewTarget = 0;\r
-  HRESULT  hr = S_OK;\r
-\r
-  /*\r
-   * Get the handle of the window under the mouse\r
-   */\r
-  hwndNewTarget = WindowFromPoint(mousePos);\r
-\r
-  /*\r
-   * Every time, we re-initialize the effects passed to the\r
-   * IDropTarget to the effects allowed by the source.\r
-   */\r
-  *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;\r
-\r
-  /*\r
-   * If we are hovering over the same target as before, send the\r
-   * DragOver notification\r
-   */\r
-  if ( (trackerInfo->curDragTarget != 0) &&\r
-       (trackerInfo->curTargetHWND == hwndNewTarget) )\r
-  {\r
-    POINTL  mousePosParam;\r
-\r
-    /*\r
-     * The documentation tells me that the coordinate should be in the target\r
-     * window's coordinate space. However, the tests I made tell me the\r
-     * coordinates should be in screen coordinates.\r
-     */\r
-    mousePosParam.x = mousePos.x;\r
-    mousePosParam.y = mousePos.y;\r
-\r
-    IDropTarget_DragOver(trackerInfo->curDragTarget,\r
-                        keyState,\r
-                        mousePosParam,\r
-                        trackerInfo->pdwEffect);\r
-  }\r
-  else\r
-  {\r
-    DropTargetNode* newDropTargetNode = 0;\r
-\r
-    /*\r
-     * If we changed window, we have to notify our old target and check for\r
-     * the new one.\r
-     */\r
-    if (trackerInfo->curDragTarget!=0)\r
-    {\r
-      IDropTarget_DragLeave(trackerInfo->curDragTarget);\r
-    }\r
-\r
-    /*\r
-     * Make sure we're hovering over a window.\r
-     */\r
-    if (hwndNewTarget!=0)\r
-    {\r
-      /*\r
-       * Find-out if there is a drag target under the mouse\r
-       */\r
-      HWND nexttar = hwndNewTarget;\r
-      trackerInfo->curTargetHWND = hwndNewTarget;\r
-\r
-      do {\r
-       newDropTargetNode = OLEDD_FindDropTarget(nexttar);\r
-      } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0);\r
-      if(nexttar) hwndNewTarget = nexttar;\r
-\r
-      trackerInfo->curDragTargetHWND = hwndNewTarget;\r
-      trackerInfo->curDragTarget     = newDropTargetNode ? newDropTargetNode->dropTarget : 0;\r
-\r
-      /*\r
-       * If there is, notify it that we just dragged-in\r
-       */\r
-      if (trackerInfo->curDragTarget!=0)\r
-      {\r
-       POINTL  mousePosParam;\r
-\r
-       /*\r
-        * The documentation tells me that the coordinate should be in the target\r
-        * window's coordinate space. However, the tests I made tell me the\r
-        * coordinates should be in screen coordinates.\r
-        */\r
-       mousePosParam.x = mousePos.x;\r
-       mousePosParam.y = mousePos.y;\r
-\r
-       IDropTarget_DragEnter(trackerInfo->curDragTarget,\r
-                             trackerInfo->dataObject,\r
-                             keyState,\r
-                             mousePosParam,\r
-                             trackerInfo->pdwEffect);\r
-      }\r
-    }\r
-    else\r
-    {\r
-      /*\r
-       * The mouse is not over a window so we don't track anything.\r
-       */\r
-      trackerInfo->curDragTargetHWND = 0;\r
-      trackerInfo->curTargetHWND     = 0;\r
-      trackerInfo->curDragTarget     = 0;\r
-    }\r
-  }\r
-\r
-  /*\r
-   * Now that we have done that, we have to tell the source to give\r
-   * us feedback on the work being done by the target.  If we don't\r
-   * have a target, simulate no effect.\r
-   */\r
-  if (trackerInfo->curDragTarget==0)\r
-  {\r
-    *trackerInfo->pdwEffect = DROPEFFECT_NONE;\r
-  }\r
-\r
-  hr = IDropSource_GiveFeedback(trackerInfo->dropSource,\r
-                               *trackerInfo->pdwEffect);\r
-\r
-  /*\r
-   * When we ask for feedback from the drop source, sometimes it will\r
-   * do all the necessary work and sometimes it will not handle it\r
-   * when that's the case, we must display the standard drag and drop\r
-   * cursors.\r
-   */\r
-  if (hr==DRAGDROP_S_USEDEFAULTCURSORS)\r
-  {\r
-    if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE)\r
-    {\r
-      SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(1)));\r
-    }\r
-    else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY)\r
-    {\r
-      SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(2)));\r
-    }\r
-    else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK)\r
-    {\r
-      SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(3)));\r
-    }\r
-    else\r
-    {\r
-      SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(0)));\r
-    }\r
-  }\r
-}\r
-\r
-/***\r
- * OLEDD_TrackStateChange()\r
- *\r
- * This method is invoked while a drag and drop operation is in effect.\r
- * It is used to notify the drop target/drop source callbacks when\r
- * the state of the keyboard or mouse button change.\r
- *\r
- * params:\r
- *    trackerInfo - Pointer to the structure identifying the\r
- *                  drag & drop operation that is currently\r
- *                  active.\r
- *    mousePos    - Current position of the mouse in screen\r
- *                  coordinates.\r
- *    keyState    - Contains the state of the shift keys and the\r
- *                  mouse buttons (MK_LBUTTON and the like)\r
- */\r
-static void OLEDD_TrackStateChange(\r
-  TrackerWindowInfo* trackerInfo,\r
-  POINT            mousePos,\r
-  DWORD              keyState)\r
-{\r
-  /*\r
-   * Ask the drop source what to do with the operation.\r
-   */\r
-  trackerInfo->returnValue = IDropSource_QueryContinueDrag(\r
-                              trackerInfo->dropSource,\r
-                              trackerInfo->escPressed,\r
-                              keyState);\r
-\r
-  /*\r
-   * All the return valued will stop the operation except the S_OK\r
-   * return value.\r
-   */\r
-  if (trackerInfo->returnValue!=S_OK)\r
-  {\r
-    /*\r
-     * Make sure the message loop in DoDragDrop stops\r
-     */\r
-    trackerInfo->trackingDone = TRUE;\r
-\r
-    /*\r
-     * Release the mouse in case the drop target decides to show a popup\r
-     * or a menu or something.\r
-     */\r
-    ReleaseCapture();\r
-\r
-    /*\r
-     * If we end-up over a target, drop the object in the target or\r
-     * inform the target that the operation was cancelled.\r
-     */\r
-    if (trackerInfo->curDragTarget!=0)\r
-    {\r
-      switch (trackerInfo->returnValue)\r
-      {\r
-       /*\r
-        * If the source wants us to complete the operation, we tell\r
-        * the drop target that we just dropped the object in it.\r
-        */\r
-        case DRAGDROP_S_DROP:\r
-       {\r
-         POINTL  mousePosParam;\r
-\r
-         /*\r
-          * The documentation tells me that the coordinate should be\r
-          * in the target window's coordinate space. However, the tests\r
-          * I made tell me the coordinates should be in screen coordinates.\r
-          */\r
-         mousePosParam.x = mousePos.x;\r
-         mousePosParam.y = mousePos.y;\r
-\r
-         IDropTarget_Drop(trackerInfo->curDragTarget,\r
-                          trackerInfo->dataObject,\r
-                          keyState,\r
-                          mousePosParam,\r
-                          trackerInfo->pdwEffect);\r
-         break;\r
-       }\r
-       /*\r
-        * If the source told us that we should cancel, fool the drop\r
-        * target by telling it that the mouse left it's window.\r
-        * Also set the drop effect to "NONE" in case the application\r
-        * ignores the result of DoDragDrop.\r
-        */\r
-        case DRAGDROP_S_CANCEL:\r
-         IDropTarget_DragLeave(trackerInfo->curDragTarget);\r
-         *trackerInfo->pdwEffect = DROPEFFECT_NONE;\r
-         break;\r
-      }\r
-    }\r
-  }\r
-}\r
-\r
-/***\r
- * OLEDD_GetButtonState()\r
- *\r
- * This method will use the current state of the keyboard to build\r
- * a button state mask equivalent to the one passed in the\r
- * WM_MOUSEMOVE wParam.\r
- */\r
-static DWORD OLEDD_GetButtonState()\r
-{\r
-  BYTE  keyboardState[256];\r
-  DWORD keyMask = 0;\r
-\r
-  GetKeyboardState(keyboardState);\r
-\r
-  if ( (keyboardState[VK_SHIFT] & 0x80) !=0)\r
-    keyMask |= MK_SHIFT;\r
-\r
-  if ( (keyboardState[VK_CONTROL] & 0x80) !=0)\r
-    keyMask |= MK_CONTROL;\r
-\r
-  if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)\r
-    keyMask |= MK_LBUTTON;\r
-\r
-  if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)\r
-    keyMask |= MK_RBUTTON;\r
-\r
-  if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)\r
-    keyMask |= MK_MBUTTON;\r
-\r
-  return keyMask;\r
-}\r
-\r
-/***\r
- * OLEDD_GetButtonState()\r
- *\r
- * This method will read the default value of the registry key in\r
- * parameter and extract a DWORD value from it. The registry key value\r
- * can be in a string key or a DWORD key.\r
- *\r
- * params:\r
- *     regKey   - Key to read the default value from\r
- *     pdwValue - Pointer to the location where the DWORD\r
- *                value is returned. This value is not modified\r
- *                if the value is not found.\r
- */\r
-\r
-static void OLEUTL_ReadRegistryDWORDValue(\r
-  HKEY   regKey,\r
-  DWORD* pdwValue)\r
-{\r
-  char  buffer[20];\r
-  DWORD dwKeyType;\r
-  DWORD cbData = 20;\r
-  LONG  lres;\r
-\r
-  lres = RegQueryValueExA(regKey,\r
-                         "",\r
-                         NULL,\r
-                         &dwKeyType,\r
-                         (LPBYTE)buffer,\r
-                         &cbData);\r
-\r
-  if (lres==ERROR_SUCCESS)\r
-  {\r
-    switch (dwKeyType)\r
-    {\r
-      case REG_DWORD:\r
-       *pdwValue = *(DWORD*)buffer;\r
-       break;\r
-      case REG_EXPAND_SZ:\r
-      case REG_MULTI_SZ:\r
-      case REG_SZ:\r
-       *pdwValue = (DWORD)strtoul(buffer, NULL, 10);\r
-       break;\r
-    }\r
-  }\r
-}\r
-\r
-/******************************************************************************\r
- * OleDraw (OLE32.@)\r
- *\r
- * The operation of this function is documented literally in the WinAPI\r
- * documentation to involve a QueryInterface for the IViewObject interface,\r
- * followed by a call to IViewObject::Draw.\r
- */\r
-HRESULT WINAPI OleDraw(\r
-       IUnknown *pUnk,\r
-       DWORD dwAspect,\r
-       HDC hdcDraw,\r
-       LPCRECT lprcBounds)\r
-{\r
-  HRESULT hres;\r
-  IViewObject *viewobject;\r
-\r
-  hres = IUnknown_QueryInterface(pUnk,\r
-                                &IID_IViewObject,\r
-                                (void**)&viewobject);\r
-\r
-  if (SUCCEEDED(hres))\r
-  {\r
-    RECTL rectl;\r
-\r
-    rectl.left = lprcBounds->left;\r
-    rectl.right = lprcBounds->right;\r
-    rectl.top = lprcBounds->top;\r
-    rectl.bottom = lprcBounds->bottom;\r
-    hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, &rectl, 0, 0, 0);\r
-\r
-    IViewObject_Release(viewobject);\r
-    return hres;\r
-  }\r
-  else\r
-  {\r
-    return DV_E_NOIVIEWOBJECT;\r
-  }\r
-}\r
-\r
-/***********************************************************************\r
- *             OleTranslateAccelerator [OLE32.@]\r
- */\r
-HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame,\r
-                   LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg)\r
-{\r
-    WORD wID;\r
-\r
-    TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg);\r
-\r
-    if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID))\r
-        return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID);\r
-\r
-    return S_FALSE;\r
-}\r
-\r
-/******************************************************************************\r
- *              OleCreate        [OLE32.@]\r
- *\r
- */\r
-HRESULT WINAPI OleCreate(\r
-       REFCLSID rclsid,\r
-       REFIID riid,\r
-       DWORD renderopt,\r
-       LPFORMATETC pFormatEtc,\r
-       LPOLECLIENTSITE pClientSite,\r
-       LPSTORAGE pStg,\r
-       LPVOID* ppvObj)\r
-{\r
-    HRESULT hres, hres1;\r
-    IUnknown * pUnk = NULL;\r
-\r
-    FIXME("\n\t%s\n\t%s semi-stub!\n", debugstr_guid(rclsid), debugstr_guid(riid));\r
-\r
-    if (SUCCEEDED((hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER|CLSCTX_LOCAL_SERVER , riid, (LPVOID*)&pUnk))))\r
-    {\r
-        if (pClientSite)\r
-        {\r
-            IOleObject * pOE;\r
-            IPersistStorage * pPS;\r
-            if (SUCCEEDED((hres = IUnknown_QueryInterface( pUnk, &IID_IOleObject, (LPVOID*)&pOE))))\r
-            {\r
-                TRACE("trying to set clientsite %p\n", pClientSite);\r
-                hres1 = IOleObject_SetClientSite(pOE, pClientSite);\r
-                TRACE("-- result 0x%08lx\n", hres1);\r
-                IOleObject_Release(pOE);\r
-            }\r
-            if (SUCCEEDED((hres = IUnknown_QueryInterface( pUnk, &IID_IPersistStorage, (LPVOID*)&pPS))))\r
-            {\r
-                TRACE("trying to set stg %p\n", pStg);\r
-                hres1 = IPersistStorage_InitNew(pPS, pStg);\r
-                TRACE("-- result 0x%08lx\n", hres1);\r
-                IPersistStorage_Release(pPS);\r
-            }\r
-        }\r
-    }\r
-\r
-    *ppvObj = pUnk;\r
-\r
-    TRACE("-- %p \n", pUnk);\r
-    return hres;\r
-}\r
-\r
-/******************************************************************************\r
- *              OleSetAutoConvert        [OLE32.@]\r
- */\r
-HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)\r
-{\r
-    HKEY hkey = 0;\r
-    char buf[200], szClsidNew[200];\r
-    HRESULT res = S_OK;\r
-\r
-    /* FIXME: convert to Unicode */\r
-    TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));\r
-    sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);\r
-    WINE_StringFromCLSID(clsidNew, szClsidNew);\r
-    if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))\r
-    {\r
-        res = REGDB_E_CLASSNOTREG;\r
-       goto done;\r
-    }\r
-    if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))\r
-    {\r
-        res = REGDB_E_WRITEREGDB;\r
-       goto done;\r
-    }\r
-\r
-done:\r
-    if (hkey) RegCloseKey(hkey);\r
-    return res;\r
-}\r
-\r
-/******************************************************************************\r
- *              OleDoAutoConvert        [OLE32.@]\r
- */\r
-HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew)\r
-{\r
-    FIXME("(%p,%p) : stub\n",pStg,pClsidNew);\r
-    return E_NOTIMPL;\r
-}\r
-\r
-/***********************************************************************\r
- *           OLE_FreeClipDataArray   [internal]\r
- *\r
- * NOTES:\r
- *  frees the data associated with an array of CLIPDATAs\r
- */\r
-static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray)\r
-{\r
-    ULONG i;\r
-    for (i = 0; i < count; i++)\r
-        if (pClipDataArray[i].pClipData)\r
-            CoTaskMemFree(pClipDataArray[i].pClipData);\r
-}\r
-\r
-/***********************************************************************\r
- *           PropSysAllocString                            [OLE32.@]\r
- * NOTES:\r
- *  Basically a copy of SysAllocStringLen.\r
- */\r
-BSTR WINAPI PropSysAllocString(LPCOLESTR str)\r
-{\r
-    DWORD  bufferSize;\r
-    DWORD* newBuffer;\r
-    WCHAR* stringBuffer;\r
-    int len;\r
-\r
-    if (!str) return 0;\r
-\r
-    len = lstrlenW(str);\r
-    /*\r
-     * Find the length of the buffer passed-in in bytes.\r
-     */\r
-    bufferSize = len * sizeof (WCHAR);\r
-\r
-    /*\r
-     * Allocate a new buffer to hold the string.\r
-     * don't forget to keep an empty spot at the beginning of the\r
-     * buffer for the character count and an extra character at the\r
-     * end for the NULL.\r
-     */\r
-    newBuffer = HeapAlloc(GetProcessHeap(), 0,\r
-                          bufferSize + sizeof(WCHAR) + sizeof(DWORD));\r
-\r
-    /*\r
-     * If the memory allocation failed, return a null pointer.\r
-     */\r
-    if (newBuffer==0)\r
-      return 0;\r
-\r
-    /*\r
-     * Copy the length of the string in the placeholder.\r
-     */\r
-    *newBuffer = bufferSize;\r
-\r
-    /*\r
-     * Skip the byte count.\r
-     */\r
-    newBuffer++;\r
-\r
-    /*\r
-     * Copy the information in the buffer.\r
-     * Since it is valid to pass a NULL pointer here, we'll initialize the\r
-     * buffer to nul if it is the case.\r
-     */\r
-    if (str != 0)\r
-      memcpy(newBuffer, str, bufferSize);\r
-    else\r
-      memset(newBuffer, 0, bufferSize);\r
-\r
-    /*\r
-     * Make sure that there is a nul character at the end of the\r
-     * string.\r
-     */\r
-    stringBuffer = (WCHAR*)newBuffer;\r
-    stringBuffer[len] = L'\0';\r
-\r
-    return (LPWSTR)stringBuffer;\r
-}\r
-\r
-/***********************************************************************\r
- *           PropSysFreeString                     [OLE32.@]\r
- * NOTES\r
- *  Copy of SysFreeString.\r
- */\r
-void WINAPI PropSysFreeString(LPOLESTR str)\r
-{\r
-    DWORD* bufferPointer;\r
-\r
-    /* NULL is a valid parameter */\r
-    if(!str) return;\r
-\r
-    /*\r
-     * We have to be careful when we free a BSTR pointer, it points to\r
-     * the beginning of the string but it skips the byte count contained\r
-     * before the string.\r
-     */\r
-    bufferPointer = (DWORD*)str;\r
-\r
-    bufferPointer--;\r
-\r
-    /*\r
-     * Free the memory from its "real" origin.\r
-     */\r
-    HeapFree(GetProcessHeap(), 0, bufferPointer);\r
-}\r
-\r
-/******************************************************************************\r
- * Check if a PROPVARIANT's type is valid.\r
- */\r
-static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt)\r
-{\r
-    switch (vt)\r
-    {\r
-    case VT_EMPTY:\r
-    case VT_NULL:\r
-    case VT_I2:\r
-    case VT_I4:\r
-    case VT_R4:\r
-    case VT_R8:\r
-    case VT_CY:\r
-    case VT_DATE:\r
-    case VT_BSTR:\r
-    case VT_ERROR:\r
-    case VT_BOOL:\r
-    case VT_UI1:\r
-    case VT_UI2:\r
-    case VT_UI4:\r
-    case VT_I8:\r
-    case VT_UI8:\r
-    case VT_LPSTR:\r
-    case VT_LPWSTR:\r
-    case VT_FILETIME:\r
-    case VT_BLOB:\r
-    case VT_STREAM:\r
-    case VT_STORAGE:\r
-    case VT_STREAMED_OBJECT:\r
-    case VT_STORED_OBJECT:\r
-    case VT_BLOB_OBJECT:\r
-    case VT_CF:\r
-    case VT_CLSID:\r
-    case VT_I2|VT_VECTOR:\r
-    case VT_I4|VT_VECTOR:\r
-    case VT_R4|VT_VECTOR:\r
-    case VT_R8|VT_VECTOR:\r
-    case VT_CY|VT_VECTOR:\r
-    case VT_DATE|VT_VECTOR:\r
-    case VT_BSTR|VT_VECTOR:\r
-    case VT_ERROR|VT_VECTOR:\r
-    case VT_BOOL|VT_VECTOR:\r
-    case VT_VARIANT|VT_VECTOR:\r
-    case VT_UI1|VT_VECTOR:\r
-    case VT_UI2|VT_VECTOR:\r
-    case VT_UI4|VT_VECTOR:\r
-    case VT_I8|VT_VECTOR:\r
-    case VT_UI8|VT_VECTOR:\r
-    case VT_LPSTR|VT_VECTOR:\r
-    case VT_LPWSTR|VT_VECTOR:\r
-    case VT_FILETIME|VT_VECTOR:\r
-    case VT_CF|VT_VECTOR:\r
-    case VT_CLSID|VT_VECTOR:\r
-        return S_OK;\r
-    }\r
-    WARN("Bad type %d\n", vt);\r
-    return STG_E_INVALIDPARAMETER;\r
-}\r
-\r
-/***********************************************************************\r
- *           PropVariantClear                      [OLE32.@]\r
- */\r
-HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */\r
-{\r
-    HRESULT hr;\r
-\r
-    TRACE("(%p)\n", pvar);\r
-\r
-    if (!pvar)\r
-        return S_OK;\r
-\r
-    hr = PROPVARIANT_ValidateType(pvar->vt);\r
-    if (FAILED(hr))\r
-        return hr;\r
-\r
-    switch(pvar->vt)\r
-    {\r
-    case VT_STREAM:\r
-    case VT_STREAMED_OBJECT:\r
-    case VT_STORAGE:\r
-    case VT_STORED_OBJECT:\r
-        if (pvar->u.pStream)\r
-            IUnknown_Release(pvar->u.pStream);\r
-        break;\r
-    case VT_CLSID:\r
-    case VT_LPSTR:\r
-    case VT_LPWSTR:\r
-        /* pick an arbitary typed pointer - we don't care about the type\r
-         * as we are just freeing it */\r
-        CoTaskMemFree(pvar->u.puuid);\r
-        break;\r
-    case VT_BLOB:\r
-    case VT_BLOB_OBJECT:\r
-        CoTaskMemFree(pvar->u.blob.pBlobData);\r
-        break;\r
-    case VT_BSTR:\r
-        if (pvar->u.bstrVal)\r
-            PropSysFreeString(pvar->u.bstrVal);\r
-        break;\r
-   case VT_CF:\r
-        if (pvar->u.pclipdata)\r
-        {\r
-            OLE_FreeClipDataArray(1, pvar->u.pclipdata);\r
-            CoTaskMemFree(pvar->u.pclipdata);\r
-        }\r
-        break;\r
-    default:\r
-        if (pvar->vt & VT_VECTOR)\r
-        {\r
-            ULONG i;\r
-\r
-            switch (pvar->vt & ~VT_VECTOR)\r
-            {\r
-            case VT_VARIANT:\r
-                FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems);\r
-                break;\r
-            case VT_CF:\r
-                OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems);\r
-                break;\r
-            case VT_BSTR:\r
-                for (i = 0; i < pvar->u.cabstr.cElems; i++)\r
-                    PropSysFreeString(pvar->u.cabstr.pElems[i]);\r
-                break;\r
-            case VT_LPSTR:\r
-                for (i = 0; i < pvar->u.calpstr.cElems; i++)\r
-                    CoTaskMemFree(pvar->u.calpstr.pElems[i]);\r
-                break;\r
-            case VT_LPWSTR:\r
-                for (i = 0; i < pvar->u.calpwstr.cElems; i++)\r
-                    CoTaskMemFree(pvar->u.calpwstr.pElems[i]);\r
-                break;\r
-            }\r
-            if (pvar->vt & ~VT_VECTOR)\r
-            {\r
-                /* pick an arbitary VT_VECTOR structure - they all have the same\r
-                 * memory layout */\r
-                CoTaskMemFree(pvar->u.capropvar.pElems);\r
-            }\r
-        }\r
-        else\r
-            WARN("Invalid/unsupported type %d\n", pvar->vt);\r
-    }\r
-\r
-    ZeroMemory(pvar, sizeof(*pvar));\r
-\r
-    return S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- *           PropVariantCopy                       [OLE32.@]\r
- */\r
-HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest,      /* [out] */\r
-                               const PROPVARIANT *pvarSrc) /* [in] */\r
-{\r
-    ULONG len;\r
-    HRESULT hr;\r
-\r
-    TRACE("(%p, %p)\n", pvarDest, pvarSrc);\r
-\r
-    hr = PROPVARIANT_ValidateType(pvarSrc->vt);\r
-    if (FAILED(hr))\r
-        return hr;\r
-\r
-    /* this will deal with most cases */\r
-    CopyMemory(pvarDest, pvarSrc, sizeof(*pvarDest));\r
-\r
-    switch(pvarSrc->vt)\r
-    {\r
-    case VT_STREAM:\r
-    case VT_STREAMED_OBJECT:\r
-    case VT_STORAGE:\r
-    case VT_STORED_OBJECT:\r
-        IUnknown_AddRef((LPUNKNOWN)pvarDest->u.pStream);\r
-        break;\r
-    case VT_CLSID:\r
-        pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));\r
-        CopyMemory(pvarDest->u.puuid, pvarSrc->u.puuid, sizeof(CLSID));\r
-        break;\r
-    case VT_LPSTR:\r
-        len = strlen(pvarSrc->u.pszVal);\r
-        pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));\r
-        CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR));\r
-        break;\r
-    case VT_LPWSTR:\r
-        len = lstrlenW(pvarSrc->u.pwszVal);\r
-        pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));\r
-        CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR));\r
-        break;\r
-    case VT_BLOB:\r
-    case VT_BLOB_OBJECT:\r
-        if (pvarSrc->u.blob.pBlobData)\r
-        {\r
-            len = pvarSrc->u.blob.cbSize;\r
-            pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len);\r
-            CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len);\r
-        }\r
-        break;\r
-    case VT_BSTR:\r
-        pvarDest->u.bstrVal = PropSysAllocString(pvarSrc->u.bstrVal);\r
-        break;\r
-    case VT_CF:\r
-        if (pvarSrc->u.pclipdata)\r
-        {\r
-            len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt);\r
-            CoTaskMemAlloc(len);\r
-            CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len);\r
-        }\r
-        break;\r
-    default:\r
-        if (pvarSrc->vt & VT_VECTOR)\r
-        {\r
-            int elemSize;\r
-            ULONG i;\r
-\r
-            switch(pvarSrc->vt & ~VT_VECTOR)\r
-            {\r
-            case VT_I1:       elemSize = sizeof(pvarSrc->u.cVal); break;\r
-            case VT_UI1:      elemSize = sizeof(pvarSrc->u.bVal); break;\r
-            case VT_I2:       elemSize = sizeof(pvarSrc->u.iVal); break;\r
-            case VT_UI2:      elemSize = sizeof(pvarSrc->u.uiVal); break;\r
-            case VT_BOOL:     elemSize = sizeof(pvarSrc->u.boolVal); break;\r
-            case VT_I4:       elemSize = sizeof(pvarSrc->u.lVal); break;\r
-            case VT_UI4:      elemSize = sizeof(pvarSrc->u.ulVal); break;\r
-            case VT_R4:       elemSize = sizeof(pvarSrc->u.fltVal); break;\r
-            case VT_R8:       elemSize = sizeof(pvarSrc->u.dblVal); break;\r
-            case VT_ERROR:    elemSize = sizeof(pvarSrc->u.scode); break;\r
-            case VT_I8:       elemSize = sizeof(pvarSrc->u.hVal); break;\r
-            case VT_UI8:      elemSize = sizeof(pvarSrc->u.uhVal); break;\r
-            case VT_CY:       elemSize = sizeof(pvarSrc->u.cyVal); break;\r
-            case VT_DATE:     elemSize = sizeof(pvarSrc->u.date); break;\r
-            case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break;\r
-            case VT_CLSID:    elemSize = sizeof(*pvarSrc->u.puuid); break;\r
-            case VT_CF:       elemSize = sizeof(*pvarSrc->u.pclipdata); break;\r
-            case VT_BSTR:     elemSize = sizeof(*pvarSrc->u.bstrVal); break;\r
-            case VT_LPSTR:    elemSize = sizeof(*pvarSrc->u.pszVal); break;\r
-            case VT_LPWSTR:   elemSize = sizeof(*pvarSrc->u.pwszVal); break;\r
-\r
-            case VT_VARIANT:\r
-            default:\r
-                FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);\r
-                return E_INVALIDARG;\r
-            }\r
-            len = pvarSrc->u.capropvar.cElems;\r
-            pvarDest->u.capropvar.pElems = CoTaskMemAlloc(len * elemSize);\r
-            if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))\r
-            {\r
-                for (i = 0; i < len; i++)\r
-                    PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]);\r
-            }\r
-            else if (pvarSrc->vt == (VT_VECTOR | VT_CF))\r
-            {\r
-                FIXME("Copy clipformats\n");\r
-            }\r
-            else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))\r
-            {\r
-                for (i = 0; i < len; i++)\r
-                    pvarDest->u.cabstr.pElems[i] = PropSysAllocString(pvarSrc->u.cabstr.pElems[i]);\r
-            }\r
-            else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))\r
-            {\r
-                size_t strLen;\r
-                for (i = 0; i < len; i++)\r
-                {\r
-                    strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1;\r
-                    pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);\r
-                    memcpy(pvarDest->u.calpstr.pElems[i],\r
-                     pvarSrc->u.calpstr.pElems[i], strLen);\r
-                }\r
-            }\r
-            else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))\r
-            {\r
-                size_t strLen;\r
-                for (i = 0; i < len; i++)\r
-                {\r
-                    strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) *\r
-                     sizeof(WCHAR);\r
-                    pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);\r
-                    memcpy(pvarDest->u.calpstr.pElems[i],\r
-                     pvarSrc->u.calpstr.pElems[i], strLen);\r
-                }\r
-            }\r
-            else\r
-                CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize);\r
-        }\r
-        else\r
-            WARN("Invalid/unsupported type %d\n", pvarSrc->vt);\r
-    }\r
-\r
-    return S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- *           FreePropVariantArray                          [OLE32.@]\r
- */\r
-HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */\r
-                                    PROPVARIANT *rgvars)    /* [in/out] */\r
-{\r
-    ULONG i;\r
-\r
-    TRACE("(%lu, %p)\n", cVariants, rgvars);\r
-\r
-    for(i = 0; i < cVariants; i++)\r
-        PropVariantClear(&rgvars[i]);\r
-\r
-    return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- * DllDebugObjectRPCHook (OLE32.@)\r
- * turns on and off internal debugging,  pointer is only used on macintosh\r
- */\r
-\r
-BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)\r
-{\r
-  FIXME("stub\n");\r
-  return TRUE;\r
-}\r
+/*
+ *     OLE2 library
+ *
+ * Copyright 1995 Martin von Loewis
+ * Copyright 1999 Francis Beaudet
+ * Copyright 1999 Noel Borthwick
+ * Copyright 1999, 2000 Marcus Meissner
+ * Copyright 2005 Juan Lang
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "commctrl.h"
+#include "ole2.h"
+#include "ole2ver.h"
+#include "wownt32.h"
+
+#include "wine/winbase16.h"
+#include "wine/wingdi16.h"
+#include "wine/winuser16.h"
+#include "compobj_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(ole);
+WINE_DECLARE_DEBUG_CHANNEL(accel);
+
+#define HICON_16(h32)          (LOWORD(h32))
+#define HICON_32(h16)          ((HICON)(ULONG_PTR)(h16))
+#define HINSTANCE_32(h16)      ((HINSTANCE)(ULONG_PTR)(h16))
+
+/******************************************************************************
+ * These are static/global variables and internal data structures that the
+ * OLE module uses to maintain it's state.
+ */
+typedef struct tagDropTargetNode
+{
+  HWND          hwndTarget;
+  IDropTarget*    dropTarget;
+  struct tagDropTargetNode* prevDropTarget;
+  struct tagDropTargetNode* nextDropTarget;
+} DropTargetNode;
+
+typedef struct tagTrackerWindowInfo
+{
+  IDataObject* dataObject;
+  IDropSource* dropSource;
+  DWORD        dwOKEffect;
+  DWORD*       pdwEffect;
+  BOOL       trackingDone;
+  HRESULT      returnValue;
+
+  BOOL       escPressed;
+  HWND       curTargetHWND;    /* window the mouse is hovering over */
+  HWND       curDragTargetHWND; /* might be a ancestor of curTargetHWND */
+  IDropTarget* curDragTarget;
+} TrackerWindowInfo;
+
+typedef struct tagOleMenuDescriptor  /* OleMenuDescriptor */
+{
+  HWND               hwndFrame;         /* The containers frame window */
+  HWND               hwndActiveObject;  /* The active objects window */
+  OLEMENUGROUPWIDTHS mgw;               /* OLE menu group widths for the shared menu */
+  HMENU              hmenuCombined;     /* The combined menu */
+  BOOL               bIsServerItem;     /* True if the currently open popup belongs to the server */
+} OleMenuDescriptor;
+
+typedef struct tagOleMenuHookItem   /* OleMenu hook item in per thread hook list */
+{
+  DWORD tid;                /* Thread Id  */
+  HANDLE hHeap;             /* Heap this is allocated from */
+  HHOOK GetMsg_hHook;       /* message hook for WH_GETMESSAGE */
+  HHOOK CallWndProc_hHook;  /* message hook for WH_CALLWNDPROC */
+  struct tagOleMenuHookItem *next;
+} OleMenuHookItem;
+
+static OleMenuHookItem *hook_list;
+
+/*
+ * This is the lock count on the OLE library. It is controlled by the
+ * OLEInitialize/OLEUninitialize methods.
+ */
+static ULONG OLE_moduleLockCount = 0;
+
+/*
+ * Name of our registered window class.
+ */
+static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
+
+/*
+ * This is the head of the Drop target container.
+ */
+static DropTargetNode* targetListHead = NULL;
+
+/******************************************************************************
+ * These are the prototypes of miscelaneous utility methods
+ */
+static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
+
+/******************************************************************************
+ * These are the prototypes of the utility methods used to manage a shared menu
+ */
+static void OLEMenu_Initialize(void);
+static void OLEMenu_UnInitialize(void);
+BOOL OLEMenu_InstallHooks( DWORD tid );
+BOOL OLEMenu_UnInstallHooks( DWORD tid );
+OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
+static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
+BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
+LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
+
+/******************************************************************************
+ * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
+ */
+extern void OLEClipbrd_UnInitialize(void);
+extern void OLEClipbrd_Initialize(void);
+
+/******************************************************************************
+ * These are the prototypes of the utility methods used for OLE Drag n Drop
+ */
+static void            OLEDD_Initialize(void);
+static void            OLEDD_UnInitialize(void);
+static void            OLEDD_InsertDropTarget(
+                        DropTargetNode* nodeToAdd);
+static DropTargetNode* OLEDD_ExtractDropTarget(
+                         HWND hwndOfTarget);
+static DropTargetNode* OLEDD_FindDropTarget(
+                         HWND hwndOfTarget);
+static LRESULT WINAPI  OLEDD_DragTrackerWindowProc(
+                        HWND   hwnd,
+                        UINT   uMsg,
+                        WPARAM wParam,
+                        LPARAM   lParam);
+static void OLEDD_TrackMouseMove(
+                         TrackerWindowInfo* trackerInfo,
+                        POINT            mousePos,
+                        DWORD              keyState);
+static void OLEDD_TrackStateChange(
+                         TrackerWindowInfo* trackerInfo,
+                        POINT            mousePos,
+                        DWORD              keyState);
+static DWORD OLEDD_GetButtonState(void);
+
+
+/******************************************************************************
+ *             OleBuildVersion [OLE2.1]
+ *             OleBuildVersion [OLE32.@]
+ */
+DWORD WINAPI OleBuildVersion(void)
+{
+    TRACE("Returning version %d, build %d.\n", rmm, rup);
+    return (rmm<<16)+rup;
+}
+
+/***********************************************************************
+ *           OleInitialize       (OLE2.2)
+ *           OleInitialize       (OLE32.@)
+ */
+HRESULT WINAPI OleInitialize(LPVOID reserved)
+{
+  HRESULT hr;
+
+  TRACE("(%p)\n", reserved);
+
+  /*
+   * The first duty of the OleInitialize is to initialize the COM libraries.
+   */
+  hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+  /*
+   * If the CoInitializeEx call failed, the OLE libraries can't be
+   * initialized.
+   */
+  if (FAILED(hr))
+    return hr;
+
+  /*
+   * Then, it has to initialize the OLE specific modules.
+   * This includes:
+   *     Clipboard
+   *     Drag and Drop
+   *     Object linking and Embedding
+   *     In-place activation
+   */
+  if (OLE_moduleLockCount==0)
+  {
+    /*
+     * Initialize the libraries.
+     */
+    TRACE("() - Initializing the OLE libraries\n");
+
+    /*
+     * OLE Clipboard
+     */
+    OLEClipbrd_Initialize();
+
+    /*
+     * Drag and Drop
+     */
+    OLEDD_Initialize();
+
+    /*
+     * OLE shared menu
+     */
+    OLEMenu_Initialize();
+  }
+
+  /*
+   * Then, we increase the lock count on the OLE module.
+   */
+  OLE_moduleLockCount++;
+
+  return hr;
+}
+
+/******************************************************************************
+ *             OleUninitialize [OLE2.3]
+ *             OleUninitialize [OLE32.@]
+ */
+void WINAPI OleUninitialize(void)
+{
+  TRACE("()\n");
+
+  /*
+   * Decrease the lock count on the OLE module.
+   */
+  OLE_moduleLockCount--;
+
+  /*
+   * If we hit the bottom of the lock stack, free the libraries.
+   */
+  if (OLE_moduleLockCount==0)
+  {
+    /*
+     * Actually free the libraries.
+     */
+    TRACE("() - Freeing the last reference count\n");
+
+    /*
+     * OLE Clipboard
+     */
+    OLEClipbrd_UnInitialize();
+
+    /*
+     * Drag and Drop
+     */
+    OLEDD_UnInitialize();
+
+    /*
+     * OLE shared menu
+     */
+    OLEMenu_UnInitialize();
+  }
+
+  /*
+   * Then, uninitialize the COM libraries.
+   */
+  CoUninitialize();
+}
+
+/******************************************************************************
+ *             OleInitializeWOW        [OLE32.@]
+ */
+HRESULT WINAPI OleInitializeWOW(DWORD x) {
+        FIXME("(0x%08lx),stub!\n",x);
+        return 0;
+}
+
+/***********************************************************************
+ *           RegisterDragDrop (OLE32.@)
+ */
+HRESULT WINAPI RegisterDragDrop(
+       HWND hwnd,
+       LPDROPTARGET pDropTarget)
+{
+  DropTargetNode* dropTargetInfo;
+
+  TRACE("(%p,%p)\n", hwnd, pDropTarget);
+
+  if (!pDropTarget)
+    return E_INVALIDARG;
+  
+  /*
+   * First, check if the window is already registered.
+   */
+  dropTargetInfo = OLEDD_FindDropTarget(hwnd);
+
+  if (dropTargetInfo!=NULL)
+    return DRAGDROP_E_ALREADYREGISTERED;
+
+  /*
+   * If it's not there, we can add it. We first create a node for it.
+   */
+  dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
+
+  if (dropTargetInfo==NULL)
+    return E_OUTOFMEMORY;
+
+  dropTargetInfo->hwndTarget     = hwnd;
+  dropTargetInfo->prevDropTarget = NULL;
+  dropTargetInfo->nextDropTarget = NULL;
+
+  /*
+   * Don't forget that this is an interface pointer, need to nail it down since
+   * we keep a copy of it.
+   */
+  dropTargetInfo->dropTarget  = pDropTarget;
+  IDropTarget_AddRef(dropTargetInfo->dropTarget);
+
+  OLEDD_InsertDropTarget(dropTargetInfo);
+
+       return S_OK;
+}
+
+/***********************************************************************
+ *           RevokeDragDrop (OLE32.@)
+ */
+HRESULT WINAPI RevokeDragDrop(
+       HWND hwnd)
+{
+  DropTargetNode* dropTargetInfo;
+
+  TRACE("(%p)\n", hwnd);
+
+  /*
+   * First, check if the window is already registered.
+   */
+  dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);
+
+  /*
+   * If it ain't in there, it's an error.
+   */
+  if (dropTargetInfo==NULL)
+    return DRAGDROP_E_NOTREGISTERED;
+
+  /*
+   * If it's in there, clean-up it's used memory and
+   * references
+   */
+  IDropTarget_Release(dropTargetInfo->dropTarget);
+  HeapFree(GetProcessHeap(), 0, dropTargetInfo);
+
+       return S_OK;
+}
+
+/***********************************************************************
+ *           OleRegGetUserType (OLE32.@)
+ *
+ * This implementation of OleRegGetUserType ignores the dwFormOfType
+ * parameter and always returns the full name of the object. This is
+ * not too bad since this is the case for many objects because of the
+ * way they are registered.
+ */
+HRESULT WINAPI OleRegGetUserType(
+       REFCLSID clsid,
+       DWORD dwFormOfType,
+       LPOLESTR* pszUserType)
+{
+  char    keyName[60];
+  DWORD   dwKeyType;
+  DWORD   cbData;
+  HKEY    clsidKey;
+  LONG    hres;
+  LPBYTE  buffer;
+  HRESULT retVal;
+  /*
+   * Initialize the out parameter.
+   */
+  *pszUserType = NULL;
+
+  /*
+   * Build the key name we're looking for
+   */
+  sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
+           clsid->Data1, clsid->Data2, clsid->Data3,
+           clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
+           clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
+
+  TRACE("(%s, %ld, %p)\n", keyName, dwFormOfType, pszUserType);
+
+  /*
+   * Open the class id Key
+   */
+  hres = RegOpenKeyA(HKEY_CLASSES_ROOT,
+                    keyName,
+                    &clsidKey);
+
+  if (hres != ERROR_SUCCESS)
+    return REGDB_E_CLASSNOTREG;
+
+  /*
+   * Retrieve the size of the name string.
+   */
+  cbData = 0;
+
+  hres = RegQueryValueExA(clsidKey,
+                         "",
+                         NULL,
+                         &dwKeyType,
+                         NULL,
+                         &cbData);
+
+  if (hres!=ERROR_SUCCESS)
+  {
+    RegCloseKey(clsidKey);
+    return REGDB_E_READREGDB;
+  }
+
+  /*
+   * Allocate a buffer for the registry value.
+   */
+  *pszUserType = CoTaskMemAlloc(cbData*2);
+
+  if (*pszUserType==NULL)
+  {
+    RegCloseKey(clsidKey);
+    return E_OUTOFMEMORY;
+  }
+
+  buffer = HeapAlloc(GetProcessHeap(), 0, cbData);
+
+  if (buffer == NULL)
+  {
+    RegCloseKey(clsidKey);
+    CoTaskMemFree(*pszUserType);
+    *pszUserType=NULL;
+    return E_OUTOFMEMORY;
+  }
+
+  hres = RegQueryValueExA(clsidKey,
+                         "",
+                         NULL,
+                         &dwKeyType,
+                         buffer,
+                         &cbData);
+
+  RegCloseKey(clsidKey);
+
+
+  if (hres!=ERROR_SUCCESS)
+  {
+    CoTaskMemFree(*pszUserType);
+    *pszUserType=NULL;
+
+    retVal = REGDB_E_READREGDB;
+  }
+  else
+  {
+    MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ );
+    retVal = S_OK;
+  }
+  HeapFree(GetProcessHeap(), 0, buffer);
+
+  return retVal;
+}
+
+/***********************************************************************
+ * DoDragDrop [OLE32.@]
+ */
+HRESULT WINAPI DoDragDrop (
+  IDataObject *pDataObject,  /* [in] ptr to the data obj           */
+  IDropSource* pDropSource,  /* [in] ptr to the source obj         */
+  DWORD       dwOKEffect,    /* [in] effects allowed by the source */
+  DWORD       *pdwEffect)    /* [out] ptr to effects of the source */
+{
+  TrackerWindowInfo trackerInfo;
+  HWND            hwndTrackWindow;
+  MSG             msg;
+
+  TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
+
+  /*
+   * Setup the drag n drop tracking window.
+   */
+  if (!IsValidInterface((LPUNKNOWN)pDropSource))
+      return E_INVALIDARG;
+
+  trackerInfo.dataObject        = pDataObject;
+  trackerInfo.dropSource        = pDropSource;
+  trackerInfo.dwOKEffect        = dwOKEffect;
+  trackerInfo.pdwEffect         = pdwEffect;
+  trackerInfo.trackingDone      = FALSE;
+  trackerInfo.escPressed        = FALSE;
+  trackerInfo.curDragTargetHWND = 0;
+  trackerInfo.curTargetHWND     = 0;
+  trackerInfo.curDragTarget     = 0;
+
+  hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
+                                   "TrackerWindow",
+                                   WS_POPUP,
+                                   CW_USEDEFAULT, CW_USEDEFAULT,
+                                   CW_USEDEFAULT, CW_USEDEFAULT,
+                                   0,
+                                   0,
+                                   0,
+                                   (LPVOID)&trackerInfo);
+
+  if (hwndTrackWindow!=0)
+  {
+    /*
+     * Capture the mouse input
+     */
+    SetCapture(hwndTrackWindow);
+
+    /*
+     * Pump messages. All mouse input should go the the capture window.
+     */
+    while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
+    {
+      if ( (msg.message >= WM_KEYFIRST) &&
+          (msg.message <= WM_KEYLAST) )
+      {
+       /*
+        * When keyboard messages are sent to windows on this thread, we
+        * want to ignore notify the drop source that the state changed.
+        * in the case of the Escape key, we also notify the drop source
+        * we give it a special meaning.
+        */
+       if ( (msg.message==WM_KEYDOWN) &&
+            (msg.wParam==VK_ESCAPE) )
+       {
+         trackerInfo.escPressed = TRUE;
+       }
+
+       /*
+        * Notify the drop source.
+        */
+       OLEDD_TrackStateChange(&trackerInfo,
+                              msg.pt,
+                              OLEDD_GetButtonState());
+      }
+      else
+      {
+       /*
+        * Dispatch the messages only when it's not a keyboard message.
+        */
+       DispatchMessageA(&msg);
+      }
+    }
+
+    /*
+     * Destroy the temporary window.
+     */
+    DestroyWindow(hwndTrackWindow);
+
+    return trackerInfo.returnValue;
+  }
+
+  return E_FAIL;
+}
+
+/***********************************************************************
+ * OleQueryLinkFromData [OLE32.@]
+ */
+HRESULT WINAPI OleQueryLinkFromData(
+  IDataObject* pSrcDataObject)
+{
+  FIXME("(%p),stub!\n", pSrcDataObject);
+  return S_OK;
+}
+
+/***********************************************************************
+ * OleRegGetMiscStatus [OLE32.@]
+ */
+HRESULT WINAPI OleRegGetMiscStatus(
+  REFCLSID clsid,
+  DWORD    dwAspect,
+  DWORD*   pdwStatus)
+{
+  char    keyName[60];
+  HKEY    clsidKey;
+  HKEY    miscStatusKey;
+  HKEY    aspectKey;
+  LONG    result;
+
+  /*
+   * Initialize the out parameter.
+   */
+  *pdwStatus = 0;
+
+  /*
+   * Build the key name we're looking for
+   */
+  sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
+           clsid->Data1, clsid->Data2, clsid->Data3,
+           clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
+           clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
+
+  TRACE("(%s, %ld, %p)\n", keyName, dwAspect, pdwStatus);
+
+  /*
+   * Open the class id Key
+   */
+  result = RegOpenKeyA(HKEY_CLASSES_ROOT,
+                      keyName,
+                      &clsidKey);
+
+  if (result != ERROR_SUCCESS)
+    return REGDB_E_CLASSNOTREG;
+
+  /*
+   * Get the MiscStatus
+   */
+  result = RegOpenKeyA(clsidKey,
+                      "MiscStatus",
+                      &miscStatusKey);
+
+
+  if (result != ERROR_SUCCESS)
+  {
+    RegCloseKey(clsidKey);
+    return REGDB_E_READREGDB;
+  }
+
+  /*
+   * Read the default value
+   */
+  OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
+
+  /*
+   * Open the key specific to the requested aspect.
+   */
+  sprintf(keyName, "%ld", dwAspect);
+
+  result = RegOpenKeyA(miscStatusKey,
+                      keyName,
+                      &aspectKey);
+
+  if (result == ERROR_SUCCESS)
+  {
+    OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
+    RegCloseKey(aspectKey);
+  }
+
+  /*
+   * Cleanup
+   */
+  RegCloseKey(miscStatusKey);
+  RegCloseKey(clsidKey);
+
+  return S_OK;
+}
+
+/******************************************************************************
+ *              OleSetContainedObject        [OLE32.@]
+ */
+HRESULT WINAPI OleSetContainedObject(
+  LPUNKNOWN pUnknown,
+  BOOL      fContained)
+{
+  IRunnableObject* runnable = NULL;
+  HRESULT          hres;
+
+  TRACE("(%p,%x), stub!\n", pUnknown, fContained);
+
+  hres = IUnknown_QueryInterface(pUnknown,
+                                &IID_IRunnableObject,
+                                (void**)&runnable);
+
+  if (SUCCEEDED(hres))
+  {
+    hres = IRunnableObject_SetContainedObject(runnable, fContained);
+
+    IRunnableObject_Release(runnable);
+
+    return hres;
+  }
+
+  return S_OK;
+}
+
+/******************************************************************************
+ *              OleLoad        [OLE32.@]
+ */
+HRESULT WINAPI OleLoad(
+  LPSTORAGE       pStg,
+  REFIID          riid,
+  LPOLECLIENTSITE pClientSite,
+  LPVOID*         ppvObj)
+{
+  IPersistStorage* persistStorage = NULL;
+  IOleObject*      oleObject      = NULL;
+  STATSTG          storageInfo;
+  HRESULT          hres;
+
+  TRACE("(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj);
+
+  /*
+   * TODO, Conversion ... OleDoAutoConvert
+   */
+
+  /*
+   * Get the class ID for the object.
+   */
+  hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
+
+  /*
+   * Now, try and create the handler for the object
+   */
+  hres = CoCreateInstance(&storageInfo.clsid,
+                         NULL,
+                         CLSCTX_INPROC_HANDLER,
+                         &IID_IOleObject,
+                         (void**)&oleObject);
+
+  /*
+   * If that fails, as it will most times, load the default
+   * OLE handler.
+   */
+  if (FAILED(hres))
+  {
+    hres = OleCreateDefaultHandler(&storageInfo.clsid,
+                                  NULL,
+                                  &IID_IOleObject,
+                                  (void**)&oleObject);
+  }
+
+  /*
+   * If we couldn't find a handler... this is bad. Abort the whole thing.
+   */
+  if (FAILED(hres))
+    return hres;
+
+  /*
+   * Inform the new object of it's client site.
+   */
+  hres = IOleObject_SetClientSite(oleObject, pClientSite);
+
+  /*
+   * Initialize the object with it's IPersistStorage interface.
+   */
+  hres = IOleObject_QueryInterface(oleObject,
+                                  &IID_IPersistStorage,
+                                  (void**)&persistStorage);
+
+  if (SUCCEEDED(hres))
+  {
+    IPersistStorage_Load(persistStorage, pStg);
+
+    IPersistStorage_Release(persistStorage);
+    persistStorage = NULL;
+  }
+
+  /*
+   * Return the requested interface to the caller.
+   */
+  hres = IOleObject_QueryInterface(oleObject, riid, ppvObj);
+
+  /*
+   * Cleanup interfaces used internally
+   */
+  IOleObject_Release(oleObject);
+
+  return hres;
+}
+
+/***********************************************************************
+ *           OleSave     [OLE32.@]
+ */
+HRESULT WINAPI OleSave(
+  LPPERSISTSTORAGE pPS,
+  LPSTORAGE        pStg,
+  BOOL             fSameAsLoad)
+{
+  HRESULT hres;
+  CLSID   objectClass;
+
+  TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
+
+  /*
+   * First, we transfer the class ID (if available)
+   */
+  hres = IPersistStorage_GetClassID(pPS, &objectClass);
+
+  if (SUCCEEDED(hres))
+  {
+    WriteClassStg(pStg, &objectClass);
+  }
+
+  /*
+   * Then, we ask the object to save itself to the
+   * storage. If it is successful, we commit the storage.
+   */
+  hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
+
+  if (SUCCEEDED(hres))
+  {
+    IStorage_Commit(pStg,
+                   STGC_DEFAULT);
+  }
+
+  return hres;
+}
+
+
+/******************************************************************************
+ *              OleLockRunning        [OLE32.@]
+ */
+HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)
+{
+  IRunnableObject* runnable = NULL;
+  HRESULT          hres;
+
+  TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);
+
+  hres = IUnknown_QueryInterface(pUnknown,
+                                &IID_IRunnableObject,
+                                (void**)&runnable);
+
+  if (SUCCEEDED(hres))
+  {
+    hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);
+
+    IRunnableObject_Release(runnable);
+
+    return hres;
+  }
+  else
+    return E_INVALIDARG;
+}
+
+
+/**************************************************************************
+ * Internal methods to manage the shared OLE menu in response to the
+ * OLE***MenuDescriptor API
+ */
+
+/***
+ * OLEMenu_Initialize()
+ *
+ * Initializes the OLEMENU data structures.
+ */
+static void OLEMenu_Initialize()
+{
+}
+
+/***
+ * OLEMenu_UnInitialize()
+ *
+ * Releases the OLEMENU data structures.
+ */
+static void OLEMenu_UnInitialize()
+{
+}
+
+/*************************************************************************
+ * OLEMenu_InstallHooks
+ * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
+ *
+ * RETURNS: TRUE if message hooks were successfully installed
+ *          FALSE on failure
+ */
+BOOL OLEMenu_InstallHooks( DWORD tid )
+{
+  OleMenuHookItem *pHookItem = NULL;
+
+  /* Create an entry for the hook table */
+  if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
+                               sizeof(OleMenuHookItem)) ) )
+    return FALSE;
+
+  pHookItem->tid = tid;
+  pHookItem->hHeap = GetProcessHeap();
+
+  /* Install a thread scope message hook for WH_GETMESSAGE */
+  pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
+                                               0, GetCurrentThreadId() );
+  if ( !pHookItem->GetMsg_hHook )
+    goto CLEANUP;
+
+  /* Install a thread scope message hook for WH_CALLWNDPROC */
+  pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
+                                                    0, GetCurrentThreadId() );
+  if ( !pHookItem->CallWndProc_hHook )
+    goto CLEANUP;
+
+  /* Insert the hook table entry */
+  pHookItem->next = hook_list;
+  hook_list = pHookItem;
+
+  return TRUE;
+
+CLEANUP:
+  /* Unhook any hooks */
+  if ( pHookItem->GetMsg_hHook )
+    UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
+  if ( pHookItem->CallWndProc_hHook )
+    UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
+  /* Release the hook table entry */
+  HeapFree(pHookItem->hHeap, 0, pHookItem );
+
+  return FALSE;
+}
+
+/*************************************************************************
+ * OLEMenu_UnInstallHooks
+ * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
+ *
+ * RETURNS: TRUE if message hooks were successfully installed
+ *          FALSE on failure
+ */
+BOOL OLEMenu_UnInstallHooks( DWORD tid )
+{
+  OleMenuHookItem *pHookItem = NULL;
+  OleMenuHookItem **ppHook = &hook_list;
+
+  while (*ppHook)
+  {
+      if ((*ppHook)->tid == tid)
+      {
+          pHookItem = *ppHook;
+          *ppHook = pHookItem->next;
+          break;
+      }
+      ppHook = &(*ppHook)->next;
+  }
+  if (!pHookItem) return FALSE;
+
+  /* Uninstall the hooks installed for this thread */
+  if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
+    goto CLEANUP;
+  if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
+    goto CLEANUP;
+
+  /* Release the hook table entry */
+  HeapFree(pHookItem->hHeap, 0, pHookItem );
+
+  return TRUE;
+
+CLEANUP:
+  /* Release the hook table entry */
+  HeapFree(pHookItem->hHeap, 0, pHookItem );
+
+  return FALSE;
+}
+
+/*************************************************************************
+ * OLEMenu_IsHookInstalled
+ * Tests if OLEMenu hooks have been installed for a thread
+ *
+ * RETURNS: The pointer and index of the hook table entry for the tid
+ *          NULL and -1 for the index if no hooks were installed for this thread
+ */
+OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
+{
+  OleMenuHookItem *pHookItem = NULL;
+
+  /* Do a simple linear search for an entry whose tid matches ours.
+   * We really need a map but efficiency is not a concern here. */
+  for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
+  {
+    if ( tid == pHookItem->tid )
+      return pHookItem;
+  }
+
+  return NULL;
+}
+
+/***********************************************************************
+ *           OLEMenu_FindMainMenuIndex
+ *
+ * Used by OLEMenu API to find the top level group a menu item belongs to.
+ * On success pnPos contains the index of the item in the top level menu group
+ *
+ * RETURNS: TRUE if the ID was found, FALSE on failure
+ */
+static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
+{
+  UINT i, nItems;
+
+  nItems = GetMenuItemCount( hMainMenu );
+
+  for (i = 0; i < nItems; i++)
+  {
+    HMENU hsubmenu;
+
+    /*  Is the current item a submenu? */
+    if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
+    {
+      /* If the handle is the same we're done */
+      if ( hsubmenu == hPopupMenu )
+      {
+        if (pnPos)
+          *pnPos = i;
+        return TRUE;
+      }
+      /* Recursively search without updating pnPos */
+      else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
+      {
+        if (pnPos)
+          *pnPos = i;
+        return TRUE;
+      }
+    }
+  }
+
+  return FALSE;
+}
+
+/***********************************************************************
+ *           OLEMenu_SetIsServerMenu
+ *
+ * Checks whether a popup menu belongs to a shared menu group which is
+ * owned by the server, and sets the menu descriptor state accordingly.
+ * All menu messages from these groups should be routed to the server.
+ *
+ * RETURNS: TRUE if the popup menu is part of a server owned group
+ *          FALSE if the popup menu is part of a container owned group
+ */
+BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
+{
+  UINT nPos = 0, nWidth, i;
+
+  pOleMenuDescriptor->bIsServerItem = FALSE;
+
+  /* Don't bother searching if the popup is the combined menu itself */
+  if ( hmenu == pOleMenuDescriptor->hmenuCombined )
+    return FALSE;
+
+  /* Find the menu item index in the shared OLE menu that this item belongs to */
+  if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu,  &nPos ) )
+    return FALSE;
+
+  /* The group widths array has counts for the number of elements
+   * in the groups File, Edit, Container, Object, Window, Help.
+   * The Edit, Object & Help groups belong to the server object
+   * and the other three belong to the container.
+   * Loop through the group widths and locate the group we are a member of.
+   */
+  for ( i = 0, nWidth = 0; i < 6; i++ )
+  {
+    nWidth += pOleMenuDescriptor->mgw.width[i];
+    if ( nPos < nWidth )
+    {
+      /* Odd elements are server menu widths */
+      pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
+      break;
+    }
+  }
+
+  return pOleMenuDescriptor->bIsServerItem;
+}
+
+/*************************************************************************
+ * OLEMenu_CallWndProc
+ * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
+ * This is invoked from a message hook installed in OleSetMenuDescriptor.
+ */
+LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
+{
+  LPCWPSTRUCT pMsg = NULL;
+  HOLEMENU hOleMenu = 0;
+  OleMenuDescriptor *pOleMenuDescriptor = NULL;
+  OleMenuHookItem *pHookItem = NULL;
+  WORD fuFlags;
+
+  TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
+
+  /* Check if we're being asked to process the message */
+  if ( HC_ACTION != code )
+    goto NEXTHOOK;
+
+  /* Retrieve the current message being dispatched from lParam */
+  pMsg = (LPCWPSTRUCT)lParam;
+
+  /* Check if the message is destined for a window we are interested in:
+   * If the window has an OLEMenu property we may need to dispatch
+   * the menu message to its active objects window instead. */
+
+  hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
+  if ( !hOleMenu )
+    goto NEXTHOOK;
+
+  /* Get the menu descriptor */
+  pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
+  if ( !pOleMenuDescriptor ) /* Bad descriptor! */
+    goto NEXTHOOK;
+
+  /* Process menu messages */
+  switch( pMsg->message )
+  {
+    case WM_INITMENU:
+    {
+      /* Reset the menu descriptor state */
+      pOleMenuDescriptor->bIsServerItem = FALSE;
+
+      /* Send this message to the server as well */
+      SendMessageA( pOleMenuDescriptor->hwndActiveObject,
+                  pMsg->message, pMsg->wParam, pMsg->lParam );
+      goto NEXTHOOK;
+    }
+
+    case WM_INITMENUPOPUP:
+    {
+      /* Save the state for whether this is a server owned menu */
+      OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
+      break;
+    }
+
+    case WM_MENUSELECT:
+    {
+      fuFlags = HIWORD(pMsg->wParam);  /* Get flags */
+      if ( fuFlags & MF_SYSMENU )
+         goto NEXTHOOK;
+
+      /* Save the state for whether this is a server owned popup menu */
+      else if ( fuFlags & MF_POPUP )
+        OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
+
+      break;
+    }
+
+    case WM_DRAWITEM:
+    {
+      LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
+      if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
+        goto NEXTHOOK;  /* Not a menu message */
+
+      break;
+    }
+
+    default:
+      goto NEXTHOOK;
+  }
+
+  /* If the message was for the server dispatch it accordingly */
+  if ( pOleMenuDescriptor->bIsServerItem )
+  {
+    SendMessageA( pOleMenuDescriptor->hwndActiveObject,
+                  pMsg->message, pMsg->wParam, pMsg->lParam );
+  }
+
+NEXTHOOK:
+  if ( pOleMenuDescriptor )
+    GlobalUnlock( hOleMenu );
+
+  /* Lookup the hook item for the current thread */
+  if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
+  {
+    /* This should never fail!! */
+    WARN("could not retrieve hHook for current thread!\n" );
+    return 0;
+  }
+
+  /* Pass on the message to the next hooker */
+  return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
+}
+
+/*************************************************************************
+ * OLEMenu_GetMsgProc
+ * Thread scope WH_GETMESSAGE hook proc filter function (callback)
+ * This is invoked from a message hook installed in OleSetMenuDescriptor.
+ */
+LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
+{
+  LPMSG pMsg = NULL;
+  HOLEMENU hOleMenu = 0;
+  OleMenuDescriptor *pOleMenuDescriptor = NULL;
+  OleMenuHookItem *pHookItem = NULL;
+  WORD wCode;
+
+  TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
+
+  /* Check if we're being asked to process a  messages */
+  if ( HC_ACTION != code )
+    goto NEXTHOOK;
+
+  /* Retrieve the current message being dispatched from lParam */
+  pMsg = (LPMSG)lParam;
+
+  /* Check if the message is destined for a window we are interested in:
+   * If the window has an OLEMenu property we may need to dispatch
+   * the menu message to its active objects window instead. */
+
+  hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
+  if ( !hOleMenu )
+    goto NEXTHOOK;
+
+  /* Process menu messages */
+  switch( pMsg->message )
+  {
+    case WM_COMMAND:
+    {
+      wCode = HIWORD(pMsg->wParam);  /* Get notification code */
+      if ( wCode )
+        goto NEXTHOOK;  /* Not a menu message */
+      break;
+    }
+    default:
+      goto NEXTHOOK;
+  }
+
+  /* Get the menu descriptor */
+  pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
+  if ( !pOleMenuDescriptor ) /* Bad descriptor! */
+    goto NEXTHOOK;
+
+  /* If the message was for the server dispatch it accordingly */
+  if ( pOleMenuDescriptor->bIsServerItem )
+  {
+    /* Change the hWnd in the message to the active objects hWnd.
+     * The message loop which reads this message will automatically
+     * dispatch it to the embedded objects window. */
+    pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
+  }
+
+NEXTHOOK:
+  if ( pOleMenuDescriptor )
+    GlobalUnlock( hOleMenu );
+
+  /* Lookup the hook item for the current thread */
+  if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
+  {
+    /* This should never fail!! */
+    WARN("could not retrieve hHook for current thread!\n" );
+    return FALSE;
+  }
+
+  /* Pass on the message to the next hooker */
+  return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
+}
+
+/***********************************************************************
+ * OleCreateMenuDescriptor [OLE32.@]
+ * Creates an OLE menu descriptor for OLE to use when dispatching
+ * menu messages and commands.
+ *
+ * PARAMS:
+ *    hmenuCombined  -  Handle to the objects combined menu
+ *    lpMenuWidths   -  Pointer to array of 6 LONG's indicating menus per group
+ *
+ */
+HOLEMENU WINAPI OleCreateMenuDescriptor(
+  HMENU                hmenuCombined,
+  LPOLEMENUGROUPWIDTHS lpMenuWidths)
+{
+  HOLEMENU hOleMenu;
+  OleMenuDescriptor *pOleMenuDescriptor;
+  int i;
+
+  if ( !hmenuCombined || !lpMenuWidths )
+    return 0;
+
+  /* Create an OLE menu descriptor */
+  if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
+                                sizeof(OleMenuDescriptor) ) ) )
+  return 0;
+
+  pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
+  if ( !pOleMenuDescriptor )
+    return 0;
+
+  /* Initialize menu group widths and hmenu */
+  for ( i = 0; i < 6; i++ )
+    pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
+
+  pOleMenuDescriptor->hmenuCombined = hmenuCombined;
+  pOleMenuDescriptor->bIsServerItem = FALSE;
+  GlobalUnlock( hOleMenu );
+
+  return hOleMenu;
+}
+
+/***********************************************************************
+ * OleDestroyMenuDescriptor [OLE32.@]
+ * Destroy the shared menu descriptor
+ */
+HRESULT WINAPI OleDestroyMenuDescriptor(
+  HOLEMENU hmenuDescriptor)
+{
+  if ( hmenuDescriptor )
+    GlobalFree( hmenuDescriptor );
+       return S_OK;
+}
+
+/***********************************************************************
+ * OleSetMenuDescriptor [OLE32.@]
+ * Installs or removes OLE dispatching code for the containers frame window
+ * FIXME: The lpFrame and lpActiveObject parameters are currently ignored
+ * OLE should install context sensitive help F1 filtering for the app when
+ * these are non null.
+ *
+ * PARAMS:
+ *     hOleMenu         Handle to composite menu descriptor
+ *     hwndFrame        Handle to containers frame window
+ *     hwndActiveObject Handle to objects in-place activation window
+ *     lpFrame          Pointer to IOleInPlaceFrame on containers window
+ *     lpActiveObject   Pointer to IOleInPlaceActiveObject on active in-place object
+ *
+ * RETURNS:
+ *      S_OK                               - menu installed correctly
+ *      E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
+ */
+HRESULT WINAPI OleSetMenuDescriptor(
+  HOLEMENU               hOleMenu,
+  HWND                   hwndFrame,
+  HWND                   hwndActiveObject,
+  LPOLEINPLACEFRAME        lpFrame,
+  LPOLEINPLACEACTIVEOBJECT lpActiveObject)
+{
+  OleMenuDescriptor *pOleMenuDescriptor = NULL;
+
+  /* Check args */
+  if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
+    return E_INVALIDARG;
+
+  if ( lpFrame || lpActiveObject )
+  {
+     FIXME("(%x, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",
+       (unsigned int)hOleMenu,
+       hwndFrame,
+       hwndActiveObject,
+       lpFrame,
+       lpActiveObject);
+  }
+
+  /* Set up a message hook to intercept the containers frame window messages.
+   * The message filter is responsible for dispatching menu messages from the
+   * shared menu which are intended for the object.
+   */
+
+  if ( hOleMenu )  /* Want to install dispatching code */
+  {
+    /* If OLEMenu hooks are already installed for this thread, fail
+     * Note: This effectively means that OleSetMenuDescriptor cannot
+     * be called twice in succession on the same frame window
+     * without first calling it with a null hOleMenu to uninstall */
+    if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
+  return E_FAIL;
+
+    /* Get the menu descriptor */
+    pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
+    if ( !pOleMenuDescriptor )
+      return E_UNEXPECTED;
+
+    /* Update the menu descriptor */
+    pOleMenuDescriptor->hwndFrame = hwndFrame;
+    pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
+
+    GlobalUnlock( hOleMenu );
+    pOleMenuDescriptor = NULL;
+
+    /* Add a menu descriptor windows property to the frame window */
+    SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
+
+    /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
+    if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
+      return E_FAIL;
+  }
+  else  /* Want to uninstall dispatching code */
+  {
+    /* Uninstall the hooks */
+    if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
+      return E_FAIL;
+
+    /* Remove the menu descriptor property from the frame window */
+    RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
+  }
+
+  return S_OK;
+}
+
+/******************************************************************************
+ *              IsAccelerator        [OLE32.@]
+ * Mostly copied from controls/menu.c TranslateAccelerator implementation
+ */
+BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
+{
+    LPACCEL lpAccelTbl;
+    int i;
+
+    if(!lpMsg) return FALSE;
+    if (!hAccel)
+    {
+       WARN_(accel)("NULL accel handle\n");
+       return FALSE;
+    }
+    if((lpMsg->message != WM_KEYDOWN &&
+       lpMsg->message != WM_KEYUP &&
+       lpMsg->message != WM_SYSKEYDOWN &&
+       lpMsg->message != WM_SYSKEYUP &&
+       lpMsg->message != WM_CHAR)) return FALSE;
+    lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL));
+    if (NULL == lpAccelTbl)
+    {
+       return FALSE;
+    }
+    if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries)
+    {
+       WARN_(accel)("CopyAcceleratorTableW failed\n");
+       HeapFree(GetProcessHeap(), 0, lpAccelTbl);
+       return FALSE;
+    }
+
+    TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"
+               "msg->hwnd=%p, msg->message=%04x, wParam=%08x, lParam=%08lx\n",
+               hAccel, cAccelEntries,
+               lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
+    for(i = 0; i < cAccelEntries; i++)
+    {
+       if(lpAccelTbl[i].key != lpMsg->wParam)
+           continue;
+
+       if(lpMsg->message == WM_CHAR)
+       {
+           if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
+           {
+               TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", lpMsg->wParam & 0xff);
+               goto found;
+           }
+       }
+       else
+       {
+           if(lpAccelTbl[i].fVirt & FVIRTKEY)
+           {
+               INT mask = 0;
+               TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
+                               lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
+               if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
+               if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
+               if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
+               if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
+               TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
+           }
+           else
+           {
+               if(!(lpMsg->lParam & 0x01000000))  /* no special_key */
+               {
+                   if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
+                   {                                                  /* ^^ ALT pressed */
+                       TRACE_(accel)("found accel for Alt-%c\n", lpMsg->wParam & 0xff);
+                       goto found;
+                   }
+               }
+           }
+       }
+    }
+
+    WARN_(accel)("couldn't translate accelerator key\n");
+    HeapFree(GetProcessHeap(), 0, lpAccelTbl);
+    return FALSE;
+
+found:
+    if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
+    HeapFree(GetProcessHeap(), 0, lpAccelTbl);
+    return TRUE;
+}
+
+/***********************************************************************
+ * ReleaseStgMedium [OLE32.@]
+ */
+void WINAPI ReleaseStgMedium(
+  STGMEDIUM* pmedium)
+{
+  switch (pmedium->tymed)
+  {
+    case TYMED_HGLOBAL:
+    {
+      if ( (pmedium->pUnkForRelease==0) &&
+          (pmedium->u.hGlobal!=0) )
+       GlobalFree(pmedium->u.hGlobal);
+      break;
+    }
+    case TYMED_FILE:
+    {
+      if (pmedium->u.lpszFileName!=0)
+      {
+       if (pmedium->pUnkForRelease==0)
+       {
+         DeleteFileW(pmedium->u.lpszFileName);
+       }
+
+       CoTaskMemFree(pmedium->u.lpszFileName);
+      }
+      break;
+    }
+    case TYMED_ISTREAM:
+    {
+      if (pmedium->u.pstm!=0)
+      {
+       IStream_Release(pmedium->u.pstm);
+      }
+      break;
+    }
+    case TYMED_ISTORAGE:
+    {
+      if (pmedium->u.pstg!=0)
+      {
+       IStorage_Release(pmedium->u.pstg);
+      }
+      break;
+    }
+    case TYMED_GDI:
+    {
+      if ( (pmedium->pUnkForRelease==0) &&
+          (pmedium->u.hBitmap!=0) )
+       DeleteObject(pmedium->u.hBitmap);
+      break;
+    }
+    case TYMED_MFPICT:
+    {
+      if ( (pmedium->pUnkForRelease==0) &&
+          (pmedium->u.hMetaFilePict!=0) )
+      {
+       LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);
+       DeleteMetaFile(pMP->hMF);
+       GlobalUnlock(pmedium->u.hMetaFilePict);
+       GlobalFree(pmedium->u.hMetaFilePict);
+      }
+      break;
+    }
+    case TYMED_ENHMF:
+    {
+      if ( (pmedium->pUnkForRelease==0) &&
+          (pmedium->u.hEnhMetaFile!=0) )
+      {
+       DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
+      }
+      break;
+    }
+    case TYMED_NULL:
+    default:
+      break;
+  }
+  pmedium->tymed=TYMED_NULL;
+
+  /*
+   * After cleaning up, the unknown is released
+   */
+  if (pmedium->pUnkForRelease!=0)
+  {
+    IUnknown_Release(pmedium->pUnkForRelease);
+    pmedium->pUnkForRelease = 0;
+  }
+}
+
+/***
+ * OLEDD_Initialize()
+ *
+ * Initializes the OLE drag and drop data structures.
+ */
+static void OLEDD_Initialize()
+{
+    WNDCLASSA wndClass;
+
+    ZeroMemory (&wndClass, sizeof(WNDCLASSA));
+    wndClass.style         = CS_GLOBALCLASS;
+    wndClass.lpfnWndProc   = OLEDD_DragTrackerWindowProc;
+    wndClass.cbClsExtra    = 0;
+    wndClass.cbWndExtra    = sizeof(TrackerWindowInfo*);
+    wndClass.hCursor       = 0;
+    wndClass.hbrBackground = 0;
+    wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
+
+    RegisterClassA (&wndClass);
+}
+
+/***
+ * OLEDD_UnInitialize()
+ *
+ * Releases the OLE drag and drop data structures.
+ */
+static void OLEDD_UnInitialize()
+{
+  /*
+   * Simply empty the list.
+   */
+  while (targetListHead!=NULL)
+  {
+    RevokeDragDrop(targetListHead->hwndTarget);
+  }
+}
+
+/***
+ * OLEDD_InsertDropTarget()
+ *
+ * Insert the target node in the tree.
+ */
+static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
+{
+  DropTargetNode*  curNode;
+  DropTargetNode** parentNodeLink;
+
+  /*
+   * Iterate the tree to find the insertion point.
+   */
+  curNode        = targetListHead;
+  parentNodeLink = &targetListHead;
+
+  while (curNode!=NULL)
+  {
+    if (nodeToAdd->hwndTarget<curNode->hwndTarget)
+    {
+      /*
+       * If the node we want to add has a smaller HWND, go left
+       */
+      parentNodeLink = &curNode->prevDropTarget;
+      curNode        =  curNode->prevDropTarget;
+    }
+    else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
+    {
+      /*
+       * If the node we want to add has a larger HWND, go right
+       */
+      parentNodeLink = &curNode->nextDropTarget;
+      curNode        =  curNode->nextDropTarget;
+    }
+    else
+    {
+      /*
+       * The item was found in the list. It shouldn't have been there
+       */
+      assert(FALSE);
+      return;
+    }
+  }
+
+  /*
+   * If we get here, we have found a spot for our item. The parentNodeLink
+   * pointer points to the pointer that we have to modify.
+   * The curNode should be NULL. We just have to establish the link and Voila!
+   */
+  assert(curNode==NULL);
+  assert(parentNodeLink!=NULL);
+  assert(*parentNodeLink==NULL);
+
+  *parentNodeLink=nodeToAdd;
+}
+
+/***
+ * OLEDD_ExtractDropTarget()
+ *
+ * Removes the target node from the tree.
+ */
+static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
+{
+  DropTargetNode*  curNode;
+  DropTargetNode** parentNodeLink;
+
+  /*
+   * Iterate the tree to find the insertion point.
+   */
+  curNode        = targetListHead;
+  parentNodeLink = &targetListHead;
+
+  while (curNode!=NULL)
+  {
+    if (hwndOfTarget<curNode->hwndTarget)
+    {
+      /*
+       * If the node we want to add has a smaller HWND, go left
+       */
+      parentNodeLink = &curNode->prevDropTarget;
+      curNode        =  curNode->prevDropTarget;
+    }
+    else if (hwndOfTarget>curNode->hwndTarget)
+    {
+      /*
+       * If the node we want to add has a larger HWND, go right
+       */
+      parentNodeLink = &curNode->nextDropTarget;
+      curNode        =  curNode->nextDropTarget;
+    }
+    else
+    {
+      /*
+       * The item was found in the list. Detach it from it's parent and
+       * re-insert it's kids in the tree.
+       */
+      assert(parentNodeLink!=NULL);
+      assert(*parentNodeLink==curNode);
+
+      /*
+       * We arbitrately re-attach the left sub-tree to the parent.
+       */
+      *parentNodeLink = curNode->prevDropTarget;
+
+      /*
+       * And we re-insert the right subtree
+       */
+      if (curNode->nextDropTarget!=NULL)
+      {
+       OLEDD_InsertDropTarget(curNode->nextDropTarget);
+      }
+
+      /*
+       * The node we found is still a valid node once we complete
+       * the unlinking of the kids.
+       */
+      curNode->nextDropTarget=NULL;
+      curNode->prevDropTarget=NULL;
+
+      return curNode;
+    }
+  }
+
+  /*
+   * If we get here, the node is not in the tree
+   */
+  return NULL;
+}
+
+/***
+ * OLEDD_FindDropTarget()
+ *
+ * Finds information about the drop target.
+ */
+static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
+{
+  DropTargetNode*  curNode;
+
+  /*
+   * Iterate the tree to find the HWND value.
+   */
+  curNode        = targetListHead;
+
+  while (curNode!=NULL)
+  {
+    if (hwndOfTarget<curNode->hwndTarget)
+    {
+      /*
+       * If the node we want to add has a smaller HWND, go left
+       */
+      curNode =  curNode->prevDropTarget;
+    }
+    else if (hwndOfTarget>curNode->hwndTarget)
+    {
+      /*
+       * If the node we want to add has a larger HWND, go right
+       */
+      curNode =  curNode->nextDropTarget;
+    }
+    else
+    {
+      /*
+       * The item was found in the list.
+       */
+      return curNode;
+    }
+  }
+
+  /*
+   * If we get here, the item is not in the list
+   */
+  return NULL;
+}
+
+/***
+ * OLEDD_DragTrackerWindowProc()
+ *
+ * This method is the WindowProcedure of the drag n drop tracking
+ * window. During a drag n Drop operation, an invisible window is created
+ * to receive the user input and act upon it. This procedure is in charge
+ * of this behavior.
+ */
+static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
+                        HWND   hwnd,
+                        UINT   uMsg,
+                        WPARAM wParam,
+                        LPARAM   lParam)
+{
+  switch (uMsg)
+  {
+    case WM_CREATE:
+    {
+      LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
+
+      SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
+
+
+      break;
+    }
+    case WM_MOUSEMOVE:
+    {
+      TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
+      POINT            mousePos;
+
+      /*
+       * Get the current mouse position in screen coordinates.
+       */
+      mousePos.x = LOWORD(lParam);
+      mousePos.y = HIWORD(lParam);
+      ClientToScreen(hwnd, &mousePos);
+
+      /*
+       * Track the movement of the mouse.
+       */
+      OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
+
+      break;
+    }
+    case WM_LBUTTONUP:
+    case WM_MBUTTONUP:
+    case WM_RBUTTONUP:
+    case WM_LBUTTONDOWN:
+    case WM_MBUTTONDOWN:
+    case WM_RBUTTONDOWN:
+    {
+      TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
+      POINT            mousePos;
+
+      /*
+       * Get the current mouse position in screen coordinates.
+       */
+      mousePos.x = LOWORD(lParam);
+      mousePos.y = HIWORD(lParam);
+      ClientToScreen(hwnd, &mousePos);
+
+      /*
+       * Notify everyone that the button state changed
+       * TODO: Check if the "escape" key was pressed.
+       */
+      OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
+
+      break;
+    }
+  }
+
+  /*
+   * This is a window proc after all. Let's call the default.
+   */
+  return DefWindowProcA (hwnd, uMsg, wParam, lParam);
+}
+
+/***
+ * OLEDD_TrackMouseMove()
+ *
+ * This method is invoked while a drag and drop operation is in effect.
+ * it will generate the appropriate callbacks in the drop source
+ * and drop target. It will also provide the expected feedback to
+ * the user.
+ *
+ * params:
+ *    trackerInfo - Pointer to the structure identifying the
+ *                  drag & drop operation that is currently
+ *                  active.
+ *    mousePos    - Current position of the mouse in screen
+ *                  coordinates.
+ *    keyState    - Contains the state of the shift keys and the
+ *                  mouse buttons (MK_LBUTTON and the like)
+ */
+static void OLEDD_TrackMouseMove(
+  TrackerWindowInfo* trackerInfo,
+  POINT            mousePos,
+  DWORD              keyState)
+{
+  HWND   hwndNewTarget = 0;
+  HRESULT  hr = S_OK;
+
+  /*
+   * Get the handle of the window under the mouse
+   */
+  hwndNewTarget = WindowFromPoint(mousePos);
+
+  /*
+   * Every time, we re-initialize the effects passed to the
+   * IDropTarget to the effects allowed by the source.
+   */
+  *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
+
+  /*
+   * If we are hovering over the same target as before, send the
+   * DragOver notification
+   */
+  if ( (trackerInfo->curDragTarget != 0) &&
+       (trackerInfo->curTargetHWND == hwndNewTarget) )
+  {
+    POINTL  mousePosParam;
+
+    /*
+     * The documentation tells me that the coordinate should be in the target
+     * window's coordinate space. However, the tests I made tell me the
+     * coordinates should be in screen coordinates.
+     */
+    mousePosParam.x = mousePos.x;
+    mousePosParam.y = mousePos.y;
+
+    IDropTarget_DragOver(trackerInfo->curDragTarget,
+                        keyState,
+                        mousePosParam,
+                        trackerInfo->pdwEffect);
+  }
+  else
+  {
+    DropTargetNode* newDropTargetNode = 0;
+
+    /*
+     * If we changed window, we have to notify our old target and check for
+     * the new one.
+     */
+    if (trackerInfo->curDragTarget!=0)
+    {
+      IDropTarget_DragLeave(trackerInfo->curDragTarget);
+    }
+
+    /*
+     * Make sure we're hovering over a window.
+     */
+    if (hwndNewTarget!=0)
+    {
+      /*
+       * Find-out if there is a drag target under the mouse
+       */
+      HWND nexttar = hwndNewTarget;
+      trackerInfo->curTargetHWND = hwndNewTarget;
+
+      do {
+       newDropTargetNode = OLEDD_FindDropTarget(nexttar);
+      } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0);
+      if(nexttar) hwndNewTarget = nexttar;
+
+      trackerInfo->curDragTargetHWND = hwndNewTarget;
+      trackerInfo->curDragTarget     = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
+
+      /*
+       * If there is, notify it that we just dragged-in
+       */
+      if (trackerInfo->curDragTarget!=0)
+      {
+       POINTL  mousePosParam;
+
+       /*
+        * The documentation tells me that the coordinate should be in the target
+        * window's coordinate space. However, the tests I made tell me the
+        * coordinates should be in screen coordinates.
+        */
+       mousePosParam.x = mousePos.x;
+       mousePosParam.y = mousePos.y;
+
+       IDropTarget_DragEnter(trackerInfo->curDragTarget,
+                             trackerInfo->dataObject,
+                             keyState,
+                             mousePosParam,
+                             trackerInfo->pdwEffect);
+      }
+    }
+    else
+    {
+      /*
+       * The mouse is not over a window so we don't track anything.
+       */
+      trackerInfo->curDragTargetHWND = 0;
+      trackerInfo->curTargetHWND     = 0;
+      trackerInfo->curDragTarget     = 0;
+    }
+  }
+
+  /*
+   * Now that we have done that, we have to tell the source to give
+   * us feedback on the work being done by the target.  If we don't
+   * have a target, simulate no effect.
+   */
+  if (trackerInfo->curDragTarget==0)
+  {
+    *trackerInfo->pdwEffect = DROPEFFECT_NONE;
+  }
+
+  hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
+                               *trackerInfo->pdwEffect);
+
+  /*
+   * When we ask for feedback from the drop source, sometimes it will
+   * do all the necessary work and sometimes it will not handle it
+   * when that's the case, we must display the standard drag and drop
+   * cursors.
+   */
+  if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
+  {
+    if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE)
+    {
+      SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(1)));
+    }
+    else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY)
+    {
+      SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(2)));
+    }
+    else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK)
+    {
+      SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(3)));
+    }
+    else
+    {
+      SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(0)));
+    }
+  }
+}
+
+/***
+ * OLEDD_TrackStateChange()
+ *
+ * This method is invoked while a drag and drop operation is in effect.
+ * It is used to notify the drop target/drop source callbacks when
+ * the state of the keyboard or mouse button change.
+ *
+ * params:
+ *    trackerInfo - Pointer to the structure identifying the
+ *                  drag & drop operation that is currently
+ *                  active.
+ *    mousePos    - Current position of the mouse in screen
+ *                  coordinates.
+ *    keyState    - Contains the state of the shift keys and the
+ *                  mouse buttons (MK_LBUTTON and the like)
+ */
+static void OLEDD_TrackStateChange(
+  TrackerWindowInfo* trackerInfo,
+  POINT            mousePos,
+  DWORD              keyState)
+{
+  /*
+   * Ask the drop source what to do with the operation.
+   */
+  trackerInfo->returnValue = IDropSource_QueryContinueDrag(
+                              trackerInfo->dropSource,
+                              trackerInfo->escPressed,
+                              keyState);
+
+  /*
+   * All the return valued will stop the operation except the S_OK
+   * return value.
+   */
+  if (trackerInfo->returnValue!=S_OK)
+  {
+    /*
+     * Make sure the message loop in DoDragDrop stops
+     */
+    trackerInfo->trackingDone = TRUE;
+
+    /*
+     * Release the mouse in case the drop target decides to show a popup
+     * or a menu or something.
+     */
+    ReleaseCapture();
+
+    /*
+     * If we end-up over a target, drop the object in the target or
+     * inform the target that the operation was cancelled.
+     */
+    if (trackerInfo->curDragTarget!=0)
+    {
+      switch (trackerInfo->returnValue)
+      {
+       /*
+        * If the source wants us to complete the operation, we tell
+        * the drop target that we just dropped the object in it.
+        */
+        case DRAGDROP_S_DROP:
+       {
+         POINTL  mousePosParam;
+
+         /*
+          * The documentation tells me that the coordinate should be
+          * in the target window's coordinate space. However, the tests
+          * I made tell me the coordinates should be in screen coordinates.
+          */
+         mousePosParam.x = mousePos.x;
+         mousePosParam.y = mousePos.y;
+
+         IDropTarget_Drop(trackerInfo->curDragTarget,
+                          trackerInfo->dataObject,
+                          keyState,
+                          mousePosParam,
+                          trackerInfo->pdwEffect);
+         break;
+       }
+       /*
+        * If the source told us that we should cancel, fool the drop
+        * target by telling it that the mouse left it's window.
+        * Also set the drop effect to "NONE" in case the application
+        * ignores the result of DoDragDrop.
+        */
+        case DRAGDROP_S_CANCEL:
+         IDropTarget_DragLeave(trackerInfo->curDragTarget);
+         *trackerInfo->pdwEffect = DROPEFFECT_NONE;
+         break;
+      }
+    }
+  }
+}
+
+/***
+ * OLEDD_GetButtonState()
+ *
+ * This method will use the current state of the keyboard to build
+ * a button state mask equivalent to the one passed in the
+ * WM_MOUSEMOVE wParam.
+ */
+static DWORD OLEDD_GetButtonState()
+{
+  BYTE  keyboardState[256];
+  DWORD keyMask = 0;
+
+  GetKeyboardState(keyboardState);
+
+  if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
+    keyMask |= MK_SHIFT;
+
+  if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
+    keyMask |= MK_CONTROL;
+
+  if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
+    keyMask |= MK_LBUTTON;
+
+  if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
+    keyMask |= MK_RBUTTON;
+
+  if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
+    keyMask |= MK_MBUTTON;
+
+  return keyMask;
+}
+
+/***
+ * OLEDD_GetButtonState()
+ *
+ * This method will read the default value of the registry key in
+ * parameter and extract a DWORD value from it. The registry key value
+ * can be in a string key or a DWORD key.
+ *
+ * params:
+ *     regKey   - Key to read the default value from
+ *     pdwValue - Pointer to the location where the DWORD
+ *                value is returned. This value is not modified
+ *                if the value is not found.
+ */
+
+static void OLEUTL_ReadRegistryDWORDValue(
+  HKEY   regKey,
+  DWORD* pdwValue)
+{
+  char  buffer[20];
+  DWORD dwKeyType;
+  DWORD cbData = 20;
+  LONG  lres;
+
+  lres = RegQueryValueExA(regKey,
+                         "",
+                         NULL,
+                         &dwKeyType,
+                         (LPBYTE)buffer,
+                         &cbData);
+
+  if (lres==ERROR_SUCCESS)
+  {
+    switch (dwKeyType)
+    {
+      case REG_DWORD:
+       *pdwValue = *(DWORD*)buffer;
+       break;
+      case REG_EXPAND_SZ:
+      case REG_MULTI_SZ:
+      case REG_SZ:
+       *pdwValue = (DWORD)strtoul(buffer, NULL, 10);
+       break;
+    }
+  }
+}
+
+/******************************************************************************
+ * OleDraw (OLE32.@)
+ *
+ * The operation of this function is documented literally in the WinAPI
+ * documentation to involve a QueryInterface for the IViewObject interface,
+ * followed by a call to IViewObject::Draw.
+ */
+HRESULT WINAPI OleDraw(
+       IUnknown *pUnk,
+       DWORD dwAspect,
+       HDC hdcDraw,
+       LPCRECT lprcBounds)
+{
+  HRESULT hres;
+  IViewObject *viewobject;
+
+  hres = IUnknown_QueryInterface(pUnk,
+                                &IID_IViewObject,
+                                (void**)&viewobject);
+
+  if (SUCCEEDED(hres))
+  {
+    RECTL rectl;
+
+    rectl.left = lprcBounds->left;
+    rectl.right = lprcBounds->right;
+    rectl.top = lprcBounds->top;
+    rectl.bottom = lprcBounds->bottom;
+    hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, &rectl, 0, 0, 0);
+
+    IViewObject_Release(viewobject);
+    return hres;
+  }
+  else
+  {
+    return DV_E_NOIVIEWOBJECT;
+  }
+}
+
+/***********************************************************************
+ *             OleTranslateAccelerator [OLE32.@]
+ */
+HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame,
+                   LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg)
+{
+    WORD wID;
+
+    TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg);
+
+    if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID))
+        return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID);
+
+    return S_FALSE;
+}
+
+/******************************************************************************
+ *              OleCreate        [OLE32.@]
+ *
+ */
+HRESULT WINAPI OleCreate(
+       REFCLSID rclsid,
+       REFIID riid,
+       DWORD renderopt,
+       LPFORMATETC pFormatEtc,
+       LPOLECLIENTSITE pClientSite,
+       LPSTORAGE pStg,
+       LPVOID* ppvObj)
+{
+    HRESULT hres, hres1;
+    IUnknown * pUnk = NULL;
+
+    FIXME("\n\t%s\n\t%s semi-stub!\n", debugstr_guid(rclsid), debugstr_guid(riid));
+
+    if (SUCCEEDED((hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER|CLSCTX_LOCAL_SERVER , riid, (LPVOID*)&pUnk))))
+    {
+        if (pClientSite)
+        {
+            IOleObject * pOE;
+            IPersistStorage * pPS;
+            if (SUCCEEDED((hres = IUnknown_QueryInterface( pUnk, &IID_IOleObject, (LPVOID*)&pOE))))
+            {
+                TRACE("trying to set clientsite %p\n", pClientSite);
+                hres1 = IOleObject_SetClientSite(pOE, pClientSite);
+                TRACE("-- result 0x%08lx\n", hres1);
+                IOleObject_Release(pOE);
+            }
+            if (SUCCEEDED((hres = IUnknown_QueryInterface( pUnk, &IID_IPersistStorage, (LPVOID*)&pPS))))
+            {
+                TRACE("trying to set stg %p\n", pStg);
+                hres1 = IPersistStorage_InitNew(pPS, pStg);
+                TRACE("-- result 0x%08lx\n", hres1);
+                IPersistStorage_Release(pPS);
+            }
+        }
+    }
+
+    *ppvObj = pUnk;
+
+    TRACE("-- %p \n", pUnk);
+    return hres;
+}
+
+/******************************************************************************
+ *              OleSetAutoConvert        [OLE32.@]
+ */
+HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
+{
+    HKEY hkey = 0;
+    char buf[200], szClsidNew[200];
+    HRESULT res = S_OK;
+
+    /* FIXME: convert to Unicode */
+    TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
+    sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]);
+    WINE_StringFromCLSID(clsidNew, szClsidNew);
+    if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey))
+    {
+        res = REGDB_E_CLASSNOTREG;
+       goto done;
+    }
+    if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1))
+    {
+        res = REGDB_E_WRITEREGDB;
+       goto done;
+    }
+
+done:
+    if (hkey) RegCloseKey(hkey);
+    return res;
+}
+
+/******************************************************************************
+ *              OleDoAutoConvert        [OLE32.@]
+ */
+HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew)
+{
+    FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
+    return E_NOTIMPL;
+}
+
+/***********************************************************************
+ *           OLE_FreeClipDataArray   [internal]
+ *
+ * NOTES:
+ *  frees the data associated with an array of CLIPDATAs
+ */
+static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray)
+{
+    ULONG i;
+    for (i = 0; i < count; i++)
+        if (pClipDataArray[i].pClipData)
+            CoTaskMemFree(pClipDataArray[i].pClipData);
+}
+
+/***********************************************************************
+ *           PropSysAllocString                            [OLE32.@]
+ * NOTES:
+ *  Basically a copy of SysAllocStringLen.
+ */
+BSTR WINAPI PropSysAllocString(LPCOLESTR str)
+{
+    DWORD  bufferSize;
+    DWORD* newBuffer;
+    WCHAR* stringBuffer;
+    int len;
+
+    if (!str) return 0;
+
+    len = lstrlenW(str);
+    /*
+     * Find the length of the buffer passed-in in bytes.
+     */
+    bufferSize = len * sizeof (WCHAR);
+
+    /*
+     * Allocate a new buffer to hold the string.
+     * don't forget to keep an empty spot at the beginning of the
+     * buffer for the character count and an extra character at the
+     * end for the NULL.
+     */
+    newBuffer = HeapAlloc(GetProcessHeap(), 0,
+                          bufferSize + sizeof(WCHAR) + sizeof(DWORD));
+
+    /*
+     * If the memory allocation failed, return a null pointer.
+     */
+    if (newBuffer==0)
+      return 0;
+
+    /*
+     * Copy the length of the string in the placeholder.
+     */
+    *newBuffer = bufferSize;
+
+    /*
+     * Skip the byte count.
+     */
+    newBuffer++;
+
+    /*
+     * Copy the information in the buffer.
+     * Since it is valid to pass a NULL pointer here, we'll initialize the
+     * buffer to nul if it is the case.
+     */
+    if (str != 0)
+      memcpy(newBuffer, str, bufferSize);
+    else
+      memset(newBuffer, 0, bufferSize);
+
+    /*
+     * Make sure that there is a nul character at the end of the
+     * string.
+     */
+    stringBuffer = (WCHAR*)newBuffer;
+    stringBuffer[len] = L'\0';
+
+    return (LPWSTR)stringBuffer;
+}
+
+/***********************************************************************
+ *           PropSysFreeString                     [OLE32.@]
+ * NOTES
+ *  Copy of SysFreeString.
+ */
+void WINAPI PropSysFreeString(LPOLESTR str)
+{
+    DWORD* bufferPointer;
+
+    /* NULL is a valid parameter */
+    if(!str) return;
+
+    /*
+     * We have to be careful when we free a BSTR pointer, it points to
+     * the beginning of the string but it skips the byte count contained
+     * before the string.
+     */
+    bufferPointer = (DWORD*)str;
+
+    bufferPointer--;
+
+    /*
+     * Free the memory from its "real" origin.
+     */
+    HeapFree(GetProcessHeap(), 0, bufferPointer);
+}
+
+/******************************************************************************
+ * Check if a PROPVARIANT's type is valid.
+ */
+static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt)
+{
+    switch (vt)
+    {
+    case VT_EMPTY:
+    case VT_NULL:
+    case VT_I2:
+    case VT_I4:
+    case VT_R4:
+    case VT_R8:
+    case VT_CY:
+    case VT_DATE:
+    case VT_BSTR:
+    case VT_ERROR:
+    case VT_BOOL:
+    case VT_UI1:
+    case VT_UI2:
+    case VT_UI4:
+    case VT_I8:
+    case VT_UI8:
+    case VT_LPSTR:
+    case VT_LPWSTR:
+    case VT_FILETIME:
+    case VT_BLOB:
+    case VT_STREAM:
+    case VT_STORAGE:
+    case VT_STREAMED_OBJECT:
+    case VT_STORED_OBJECT:
+    case VT_BLOB_OBJECT:
+    case VT_CF:
+    case VT_CLSID:
+    case VT_I2|VT_VECTOR:
+    case VT_I4|VT_VECTOR:
+    case VT_R4|VT_VECTOR:
+    case VT_R8|VT_VECTOR:
+    case VT_CY|VT_VECTOR:
+    case VT_DATE|VT_VECTOR:
+    case VT_BSTR|VT_VECTOR:
+    case VT_ERROR|VT_VECTOR:
+    case VT_BOOL|VT_VECTOR:
+    case VT_VARIANT|VT_VECTOR:
+    case VT_UI1|VT_VECTOR:
+    case VT_UI2|VT_VECTOR:
+    case VT_UI4|VT_VECTOR:
+    case VT_I8|VT_VECTOR:
+    case VT_UI8|VT_VECTOR:
+    case VT_LPSTR|VT_VECTOR:
+    case VT_LPWSTR|VT_VECTOR:
+    case VT_FILETIME|VT_VECTOR:
+    case VT_CF|VT_VECTOR:
+    case VT_CLSID|VT_VECTOR:
+        return S_OK;
+    }
+    WARN("Bad type %d\n", vt);
+    return STG_E_INVALIDPARAMETER;
+}
+
+/***********************************************************************
+ *           PropVariantClear                      [OLE32.@]
+ */
+HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */
+{
+    HRESULT hr;
+
+    TRACE("(%p)\n", pvar);
+
+    if (!pvar)
+        return S_OK;
+
+    hr = PROPVARIANT_ValidateType(pvar->vt);
+    if (FAILED(hr))
+        return hr;
+
+    switch(pvar->vt)
+    {
+    case VT_STREAM:
+    case VT_STREAMED_OBJECT:
+    case VT_STORAGE:
+    case VT_STORED_OBJECT:
+        if (pvar->u.pStream)
+            IUnknown_Release(pvar->u.pStream);
+        break;
+    case VT_CLSID:
+    case VT_LPSTR:
+    case VT_LPWSTR:
+        /* pick an arbitary typed pointer - we don't care about the type
+         * as we are just freeing it */
+        CoTaskMemFree(pvar->u.puuid);
+        break;
+    case VT_BLOB:
+    case VT_BLOB_OBJECT:
+        CoTaskMemFree(pvar->u.blob.pBlobData);
+        break;
+    case VT_BSTR:
+        if (pvar->u.bstrVal)
+            PropSysFreeString(pvar->u.bstrVal);
+        break;
+   case VT_CF:
+        if (pvar->u.pclipdata)
+        {
+            OLE_FreeClipDataArray(1, pvar->u.pclipdata);
+            CoTaskMemFree(pvar->u.pclipdata);
+        }
+        break;
+    default:
+        if (pvar->vt & VT_VECTOR)
+        {
+            ULONG i;
+
+            switch (pvar->vt & ~VT_VECTOR)
+            {
+            case VT_VARIANT:
+                FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems);
+                break;
+            case VT_CF:
+                OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems);
+                break;
+            case VT_BSTR:
+                for (i = 0; i < pvar->u.cabstr.cElems; i++)
+                    PropSysFreeString(pvar->u.cabstr.pElems[i]);
+                break;
+            case VT_LPSTR:
+                for (i = 0; i < pvar->u.calpstr.cElems; i++)
+                    CoTaskMemFree(pvar->u.calpstr.pElems[i]);
+                break;
+            case VT_LPWSTR:
+                for (i = 0; i < pvar->u.calpwstr.cElems; i++)
+                    CoTaskMemFree(pvar->u.calpwstr.pElems[i]);
+                break;
+            }
+            if (pvar->vt & ~VT_VECTOR)
+            {
+                /* pick an arbitary VT_VECTOR structure - they all have the same
+                 * memory layout */
+                CoTaskMemFree(pvar->u.capropvar.pElems);
+            }
+        }
+        else
+            WARN("Invalid/unsupported type %d\n", pvar->vt);
+    }
+
+    ZeroMemory(pvar, sizeof(*pvar));
+
+    return S_OK;
+}
+
+/***********************************************************************
+ *           PropVariantCopy                       [OLE32.@]
+ */
+HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest,      /* [out] */
+                               const PROPVARIANT *pvarSrc) /* [in] */
+{
+    ULONG len;
+    HRESULT hr;
+
+    TRACE("(%p, %p)\n", pvarDest, pvarSrc);
+
+    hr = PROPVARIANT_ValidateType(pvarSrc->vt);
+    if (FAILED(hr))
+        return hr;
+
+    /* this will deal with most cases */
+    CopyMemory(pvarDest, pvarSrc, sizeof(*pvarDest));
+
+    switch(pvarSrc->vt)
+    {
+    case VT_STREAM:
+    case VT_STREAMED_OBJECT:
+    case VT_STORAGE:
+    case VT_STORED_OBJECT:
+        IUnknown_AddRef((LPUNKNOWN)pvarDest->u.pStream);
+        break;
+    case VT_CLSID:
+        pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));
+        CopyMemory(pvarDest->u.puuid, pvarSrc->u.puuid, sizeof(CLSID));
+        break;
+    case VT_LPSTR:
+        len = strlen(pvarSrc->u.pszVal);
+        pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
+        CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR));
+        break;
+    case VT_LPWSTR:
+        len = lstrlenW(pvarSrc->u.pwszVal);
+        pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
+        CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR));
+        break;
+    case VT_BLOB:
+    case VT_BLOB_OBJECT:
+        if (pvarSrc->u.blob.pBlobData)
+        {
+            len = pvarSrc->u.blob.cbSize;
+            pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len);
+            CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len);
+        }
+        break;
+    case VT_BSTR:
+        pvarDest->u.bstrVal = PropSysAllocString(pvarSrc->u.bstrVal);
+        break;
+    case VT_CF:
+        if (pvarSrc->u.pclipdata)
+        {
+            len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt);
+            CoTaskMemAlloc(len);
+            CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len);
+        }
+        break;
+    default:
+        if (pvarSrc->vt & VT_VECTOR)
+        {
+            int elemSize;
+            ULONG i;
+
+            switch(pvarSrc->vt & ~VT_VECTOR)
+            {
+            case VT_I1:       elemSize = sizeof(pvarSrc->u.cVal); break;
+            case VT_UI1:      elemSize = sizeof(pvarSrc->u.bVal); break;
+            case VT_I2:       elemSize = sizeof(pvarSrc->u.iVal); break;
+            case VT_UI2:      elemSize = sizeof(pvarSrc->u.uiVal); break;
+            case VT_BOOL:     elemSize = sizeof(pvarSrc->u.boolVal); break;
+            case VT_I4:       elemSize = sizeof(pvarSrc->u.lVal); break;
+            case VT_UI4:      elemSize = sizeof(pvarSrc->u.ulVal); break;
+            case VT_R4:       elemSize = sizeof(pvarSrc->u.fltVal); break;
+            case VT_R8:       elemSize = sizeof(pvarSrc->u.dblVal); break;
+            case VT_ERROR:    elemSize = sizeof(pvarSrc->u.scode); break;
+            case VT_I8:       elemSize = sizeof(pvarSrc->u.hVal); break;
+            case VT_UI8:      elemSize = sizeof(pvarSrc->u.uhVal); break;
+            case VT_CY:       elemSize = sizeof(pvarSrc->u.cyVal); break;
+            case VT_DATE:     elemSize = sizeof(pvarSrc->u.date); break;
+            case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break;
+            case VT_CLSID:    elemSize = sizeof(*pvarSrc->u.puuid); break;
+            case VT_CF:       elemSize = sizeof(*pvarSrc->u.pclipdata); break;
+            case VT_BSTR:     elemSize = sizeof(*pvarSrc->u.bstrVal); break;
+            case VT_LPSTR:    elemSize = sizeof(*pvarSrc->u.pszVal); break;
+            case VT_LPWSTR:   elemSize = sizeof(*pvarSrc->u.pwszVal); break;
+
+            case VT_VARIANT:
+            default:
+                FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
+                return E_INVALIDARG;
+            }
+            len = pvarSrc->u.capropvar.cElems;
+            pvarDest->u.capropvar.pElems = CoTaskMemAlloc(len * elemSize);
+            if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
+            {
+                for (i = 0; i < len; i++)
+                    PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]);
+            }
+            else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
+            {
+                FIXME("Copy clipformats\n");
+            }
+            else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
+            {
+                for (i = 0; i < len; i++)
+                    pvarDest->u.cabstr.pElems[i] = PropSysAllocString(pvarSrc->u.cabstr.pElems[i]);
+            }
+            else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
+            {
+                size_t strLen;
+                for (i = 0; i < len; i++)
+                {
+                    strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1;
+                    pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
+                    memcpy(pvarDest->u.calpstr.pElems[i],
+                     pvarSrc->u.calpstr.pElems[i], strLen);
+                }
+            }
+            else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
+            {
+                size_t strLen;
+                for (i = 0; i < len; i++)
+                {
+                    strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) *
+                     sizeof(WCHAR);
+                    pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
+                    memcpy(pvarDest->u.calpstr.pElems[i],
+                     pvarSrc->u.calpstr.pElems[i], strLen);
+                }
+            }
+            else
+                CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize);
+        }
+        else
+            WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
+    }
+
+    return S_OK;
+}
+
+/***********************************************************************
+ *           FreePropVariantArray                          [OLE32.@]
+ */
+HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */
+                                    PROPVARIANT *rgvars)    /* [in/out] */
+{
+    ULONG i;
+
+    TRACE("(%lu, %p)\n", cVariants, rgvars);
+
+    for(i = 0; i < cVariants; i++)
+        PropVariantClear(&rgvars[i]);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ * DllDebugObjectRPCHook (OLE32.@)
+ * turns on and off internal debugging,  pointer is only used on macintosh
+ */
+
+BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)
+{
+  FIXME("stub\n");
+  return TRUE;
+}