ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

ole2.c
Go to the documentation of this file.
00001 /*
00002  *  OLE2 library
00003  *
00004  * Copyright 1995 Martin von Loewis
00005  * Copyright 1999 Francis Beaudet
00006  * Copyright 1999 Noel Borthwick
00007  * Copyright 1999, 2000 Marcus Meissner
00008  * Copyright 2005 Juan Lang
00009  * Copyright 2011 Adam Martinson for CodeWeavers
00010  *
00011  * This library is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU Lesser General Public
00013  * License as published by the Free Software Foundation; either
00014  * version 2.1 of the License, or (at your option) any later version.
00015  *
00016  * This library is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * Lesser General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Lesser General Public
00022  * License along with this library; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00024  */
00025 
00026 #include "config.h"
00027 
00028 #include <assert.h>
00029 #include <stdlib.h>
00030 #include <stdarg.h>
00031 #include <stdio.h>
00032 #include <string.h>
00033 
00034 #define COBJMACROS
00035 #define NONAMELESSUNION
00036 #define NONAMELESSSTRUCT
00037 
00038 #include "windef.h"
00039 #include "winbase.h"
00040 #include "winerror.h"
00041 #include "wingdi.h"
00042 #include "winuser.h"
00043 #include "winnls.h"
00044 #include "winreg.h"
00045 #include "ole2.h"
00046 #include "ole2ver.h"
00047 
00048 #include "wine/unicode.h"
00049 #include "compobj_private.h"
00050 #include "wine/list.h"
00051 
00052 #include "wine/debug.h"
00053 
00054 WINE_DEFAULT_DEBUG_CHANNEL(ole);
00055 WINE_DECLARE_DEBUG_CHANNEL(accel);
00056 
00057 /******************************************************************************
00058  * These are static/global variables and internal data structures that the
00059  * OLE module uses to maintain it's state.
00060  */
00061 typedef struct tagTrackerWindowInfo
00062 {
00063   IDataObject* dataObject;
00064   IDropSource* dropSource;
00065   DWORD        dwOKEffect;
00066   DWORD*       pdwEffect;
00067   BOOL       trackingDone;
00068   HRESULT      returnValue;
00069 
00070   BOOL       escPressed;
00071   HWND       curTargetHWND; /* window the mouse is hovering over */
00072   HWND       curDragTargetHWND; /* might be a ancestor of curTargetHWND */
00073   IDropTarget* curDragTarget;
00074   POINTL     curMousePos;       /* current position of the mouse in screen coordinates */
00075   DWORD      dwKeyState;        /* current state of the shift and ctrl keys and the mouse buttons */
00076 } TrackerWindowInfo;
00077 
00078 typedef struct tagOleMenuDescriptor  /* OleMenuDescriptor */
00079 {
00080   HWND               hwndFrame;         /* The containers frame window */
00081   HWND               hwndActiveObject;  /* The active objects window */
00082   OLEMENUGROUPWIDTHS mgw;               /* OLE menu group widths for the shared menu */
00083   HMENU              hmenuCombined;     /* The combined menu */
00084   BOOL               bIsServerItem;     /* True if the currently open popup belongs to the server */
00085 } OleMenuDescriptor;
00086 
00087 typedef struct tagOleMenuHookItem   /* OleMenu hook item in per thread hook list */
00088 {
00089   DWORD tid;                /* Thread Id  */
00090   HANDLE hHeap;             /* Heap this is allocated from */
00091   HHOOK GetMsg_hHook;       /* message hook for WH_GETMESSAGE */
00092   HHOOK CallWndProc_hHook;  /* message hook for WH_CALLWNDPROC */
00093   struct tagOleMenuHookItem *next;
00094 } OleMenuHookItem;
00095 
00096 static OleMenuHookItem *hook_list;
00097 
00098 /*
00099  * This is the lock count on the OLE library. It is controlled by the
00100  * OLEInitialize/OLEUninitialize methods.
00101  */
00102 static LONG OLE_moduleLockCount = 0;
00103 
00104 /*
00105  * Name of our registered window class.
00106  */
00107 static const WCHAR OLEDD_DRAGTRACKERCLASS[] =
00108   {'W','i','n','e','D','r','a','g','D','r','o','p','T','r','a','c','k','e','r','3','2',0};
00109 
00110 /*
00111  * Name of menu descriptor property.
00112  */
00113 static const WCHAR prop_olemenuW[] =
00114   {'P','R','O','P','_','O','L','E','M','e','n','u','D','e','s','c','r','i','p','t','o','r',0};
00115 
00116 /* property to store IDropTarget pointer */
00117 static const WCHAR prop_oledroptarget[] =
00118   {'O','l','e','D','r','o','p','T','a','r','g','e','t','I','n','t','e','r','f','a','c','e',0};
00119 
00120 /* property to store Marshalled IDropTarget pointer */
00121 static const WCHAR prop_marshalleddroptarget[] =
00122   {'W','i','n','e','M','a','r','s','h','a','l','l','e','d','D','r','o','p','T','a','r','g','e','t',0};
00123 
00124 static const WCHAR clsidfmtW[] =
00125   {'C','L','S','I','D','\\','{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-',
00126    '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x',
00127     '%','0','2','x','%','0','2','x','}','\\',0};
00128 
00129 static const WCHAR emptyW[] = { 0 };
00130 
00131 /******************************************************************************
00132  * These are the prototypes of miscellaneous utility methods
00133  */
00134 static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
00135 
00136 /******************************************************************************
00137  * These are the prototypes of the utility methods used to manage a shared menu
00138  */
00139 static void OLEMenu_Initialize(void);
00140 static void OLEMenu_UnInitialize(void);
00141 static BOOL OLEMenu_InstallHooks( DWORD tid );
00142 static BOOL OLEMenu_UnInstallHooks( DWORD tid );
00143 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
00144 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
00145 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
00146 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
00147 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
00148 
00149 /******************************************************************************
00150  * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
00151  */
00152 extern void OLEClipbrd_UnInitialize(void);
00153 extern void OLEClipbrd_Initialize(void);
00154 
00155 /******************************************************************************
00156  * These are the prototypes of the utility methods used for OLE Drag n Drop
00157  */
00158 static void OLEDD_Initialize(void);
00159 static LRESULT WINAPI  OLEDD_DragTrackerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
00160 static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo);
00161 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo);
00162 static DWORD OLEDD_GetButtonState(void);
00163 
00164 /******************************************************************************
00165  *      OleBuildVersion [OLE32.@]
00166  */
00167 DWORD WINAPI OleBuildVersion(void)
00168 {
00169     TRACE("Returning version %d, build %d.\n", rmm, rup);
00170     return (rmm<<16)+rup;
00171 }
00172 
00173 /***********************************************************************
00174  *           OleInitialize       (OLE32.@)
00175  */
00176 HRESULT WINAPI OleInitialize(LPVOID reserved)
00177 {
00178   HRESULT hr;
00179 
00180   TRACE("(%p)\n", reserved);
00181 
00182   /*
00183    * The first duty of the OleInitialize is to initialize the COM libraries.
00184    */
00185   hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
00186 
00187   /*
00188    * If the CoInitializeEx call failed, the OLE libraries can't be
00189    * initialized.
00190    */
00191   if (FAILED(hr))
00192     return hr;
00193 
00194   if (!COM_CurrentInfo()->ole_inits)
00195     hr = S_OK;
00196 
00197   /*
00198    * Then, it has to initialize the OLE specific modules.
00199    * This includes:
00200    *     Clipboard
00201    *     Drag and Drop
00202    *     Object linking and Embedding
00203    *     In-place activation
00204    */
00205   if (!COM_CurrentInfo()->ole_inits++ &&
00206       InterlockedIncrement(&OLE_moduleLockCount) == 1)
00207   {
00208     /*
00209      * Initialize the libraries.
00210      */
00211     TRACE("() - Initializing the OLE libraries\n");
00212 
00213     /*
00214      * OLE Clipboard
00215      */
00216     OLEClipbrd_Initialize();
00217 
00218     /*
00219      * Drag and Drop
00220      */
00221     OLEDD_Initialize();
00222 
00223     /*
00224      * OLE shared menu
00225      */
00226     OLEMenu_Initialize();
00227   }
00228 
00229   return hr;
00230 }
00231 
00232 /******************************************************************************
00233  *      OleUninitialize [OLE32.@]
00234  */
00235 void WINAPI OleUninitialize(void)
00236 {
00237   TRACE("()\n");
00238 
00239   /*
00240    * If we hit the bottom of the lock stack, free the libraries.
00241    */
00242   if (!--COM_CurrentInfo()->ole_inits && !InterlockedDecrement(&OLE_moduleLockCount))
00243   {
00244     /*
00245      * Actually free the libraries.
00246      */
00247     TRACE("() - Freeing the last reference count\n");
00248 
00249     /*
00250      * OLE Clipboard
00251      */
00252     OLEClipbrd_UnInitialize();
00253 
00254     /*
00255      * OLE shared menu
00256      */
00257     OLEMenu_UnInitialize();
00258   }
00259 
00260   /*
00261    * Then, uninitialize the COM libraries.
00262    */
00263   CoUninitialize();
00264 }
00265 
00266 /******************************************************************************
00267  *      OleInitializeWOW    [OLE32.@]
00268  */
00269 HRESULT WINAPI OleInitializeWOW(DWORD x, DWORD y) {
00270         FIXME("(0x%08x, 0x%08x),stub!\n",x, y);
00271         return 0;
00272 }
00273 
00274 /*************************************************************
00275  *           get_droptarget_handle
00276  *
00277  * Retrieve a handle to the map containing the marshalled IDropTarget.
00278  * This handle belongs to the process that called RegisterDragDrop.
00279  * See get_droptarget_local_handle().
00280  */
00281 static inline HANDLE get_droptarget_handle(HWND hwnd)
00282 {
00283     return GetPropW(hwnd, prop_marshalleddroptarget);
00284 }
00285 
00286 /*************************************************************
00287  *           is_droptarget
00288  *
00289  * Is the window a droptarget.
00290  */
00291 static inline BOOL is_droptarget(HWND hwnd)
00292 {
00293     return get_droptarget_handle(hwnd) ? TRUE : FALSE;
00294 }
00295 
00296 /*************************************************************
00297  *           get_droptarget_local_handle
00298  *
00299  * Retrieve a handle to the map containing the marshalled IDropTarget.
00300  * The handle should be closed when finished with.
00301  */
00302 static HANDLE get_droptarget_local_handle(HWND hwnd)
00303 {
00304     HANDLE handle, local_handle = 0;
00305 
00306     handle = get_droptarget_handle(hwnd);
00307 
00308     if(handle)
00309     {
00310         DWORD pid;
00311         HANDLE process;
00312 
00313         GetWindowThreadProcessId(hwnd, &pid);
00314         process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
00315         if(process)
00316         {
00317             DuplicateHandle(process, handle, GetCurrentProcess(), &local_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
00318             CloseHandle(process);
00319         }
00320     }
00321     return local_handle;
00322 }
00323 
00324 /***********************************************************************
00325  *     create_map_from_stream
00326  *
00327  * Helper for RegisterDragDrop.  Creates a file mapping object
00328  * with the contents of the provided stream.  The stream must
00329  * be a global memory backed stream.
00330  */
00331 static HRESULT create_map_from_stream(IStream *stream, HANDLE *map)
00332 {
00333     HGLOBAL hmem;
00334     DWORD size;
00335     HRESULT hr;
00336     void *data;
00337 
00338     hr = GetHGlobalFromStream(stream, &hmem);
00339     if(FAILED(hr)) return hr;
00340 
00341     size = GlobalSize(hmem);
00342     *map = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL);
00343     if(!*map) return E_OUTOFMEMORY;
00344 
00345     data = MapViewOfFile(*map, FILE_MAP_WRITE, 0, 0, size);
00346     memcpy(data, GlobalLock(hmem), size);
00347     GlobalUnlock(hmem);
00348     UnmapViewOfFile(data);
00349     return S_OK;
00350 }
00351 
00352 /***********************************************************************
00353  *     create_stream_from_map
00354  *
00355  * Creates a stream from the provided map.
00356  */
00357 static HRESULT create_stream_from_map(HANDLE map, IStream **stream)
00358 {
00359     HRESULT hr = E_OUTOFMEMORY;
00360     HGLOBAL hmem;
00361     void *data;
00362     MEMORY_BASIC_INFORMATION info;
00363 
00364     data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
00365     if(!data) return hr;
00366 
00367     VirtualQuery(data, &info, sizeof(info));
00368     TRACE("size %d\n", (int)info.RegionSize);
00369 
00370     hmem = GlobalAlloc(GMEM_MOVEABLE, info.RegionSize);
00371     if(hmem)
00372     {
00373         memcpy(GlobalLock(hmem), data, info.RegionSize);
00374         GlobalUnlock(hmem);
00375         hr = CreateStreamOnHGlobal(hmem, TRUE, stream);
00376     }
00377     UnmapViewOfFile(data);
00378     return hr;
00379 }
00380 
00381 /* This is to work around apps which break COM rules by not implementing
00382  * IDropTarget::QueryInterface().  Windows doesn't expose this because it
00383  * doesn't call CoMarshallInterface() in RegisterDragDrop().
00384  * The wrapper is only used internally, and only exists for the life of
00385  * the marshal.  We don't want to hold a ref on the app provided target
00386  * as some apps destroy this prior to CoUninitialize without calling
00387  * RevokeDragDrop.  The only (long-term) ref is held by the window prop. */
00388 typedef struct {
00389     IDropTarget IDropTarget_iface;
00390     HWND hwnd;
00391     LONG refs;
00392 } DropTargetWrapper;
00393 
00394 static inline DropTargetWrapper* impl_from_IDropTarget(IDropTarget* iface)
00395 {
00396     return CONTAINING_RECORD(iface, DropTargetWrapper, IDropTarget_iface);
00397 }
00398 
00399 static HRESULT WINAPI DropTargetWrapper_QueryInterface(IDropTarget* iface,
00400                                                        REFIID riid,
00401                                                        void** ppvObject)
00402 {
00403     DropTargetWrapper* This = impl_from_IDropTarget(iface);
00404     if (IsEqualIID(riid, &IID_IUnknown) ||
00405         IsEqualIID(riid, &IID_IDropTarget))
00406     {
00407         IDropTarget_AddRef(&This->IDropTarget_iface);
00408         *ppvObject = &This->IDropTarget_iface;
00409         return S_OK;
00410     }
00411     *ppvObject = NULL;
00412     return E_NOINTERFACE;
00413 }
00414 
00415 static ULONG WINAPI DropTargetWrapper_AddRef(IDropTarget* iface)
00416 {
00417     DropTargetWrapper* This = impl_from_IDropTarget(iface);
00418     return InterlockedIncrement(&This->refs);
00419 }
00420 
00421 static ULONG WINAPI DropTargetWrapper_Release(IDropTarget* iface)
00422 {
00423     DropTargetWrapper* This = impl_from_IDropTarget(iface);
00424     ULONG refs = InterlockedDecrement(&This->refs);
00425     if (!refs) HeapFree(GetProcessHeap(), 0, This);
00426     return refs;
00427 }
00428 
00429 static inline HRESULT get_target_from_wrapper( IDropTarget *wrapper, IDropTarget **target )
00430 {
00431     DropTargetWrapper* This = impl_from_IDropTarget( wrapper );
00432     *target = GetPropW( This->hwnd, prop_oledroptarget );
00433     if (!*target) return DRAGDROP_E_NOTREGISTERED;
00434     IDropTarget_AddRef( *target );
00435     return S_OK;
00436 }
00437 
00438 static HRESULT WINAPI DropTargetWrapper_DragEnter(IDropTarget* iface,
00439                                                   IDataObject* pDataObj,
00440                                                   DWORD grfKeyState,
00441                                                   POINTL pt,
00442                                                   DWORD* pdwEffect)
00443 {
00444     IDropTarget *target;
00445     HRESULT r = get_target_from_wrapper( iface, &target );
00446 
00447     if (SUCCEEDED( r ))
00448     {
00449         r = IDropTarget_DragEnter( target, pDataObj, grfKeyState, pt, pdwEffect );
00450         IDropTarget_Release( target );
00451     }
00452     return r;
00453 }
00454 
00455 static HRESULT WINAPI DropTargetWrapper_DragOver(IDropTarget* iface,
00456                                                  DWORD grfKeyState,
00457                                                  POINTL pt,
00458                                                  DWORD* pdwEffect)
00459 {
00460     IDropTarget *target;
00461     HRESULT r = get_target_from_wrapper( iface, &target );
00462 
00463     if (SUCCEEDED( r ))
00464     {
00465         r = IDropTarget_DragOver( target, grfKeyState, pt, pdwEffect );
00466         IDropTarget_Release( target );
00467     }
00468     return r;
00469 }
00470 
00471 static HRESULT WINAPI DropTargetWrapper_DragLeave(IDropTarget* iface)
00472 {
00473     IDropTarget *target;
00474     HRESULT r = get_target_from_wrapper( iface, &target );
00475 
00476     if (SUCCEEDED( r ))
00477     {
00478         r = IDropTarget_DragLeave( target );
00479         IDropTarget_Release( target );
00480     }
00481     return r;
00482 }
00483 
00484 static HRESULT WINAPI DropTargetWrapper_Drop(IDropTarget* iface,
00485                                              IDataObject* pDataObj,
00486                                              DWORD grfKeyState,
00487                                              POINTL pt,
00488                                              DWORD* pdwEffect)
00489 {
00490     IDropTarget *target;
00491     HRESULT r = get_target_from_wrapper( iface, &target );
00492 
00493     if (SUCCEEDED( r ))
00494     {
00495         r = IDropTarget_Drop( target, pDataObj, grfKeyState, pt, pdwEffect );
00496         IDropTarget_Release( target );
00497     }
00498     return r;
00499 }
00500 
00501 static const IDropTargetVtbl DropTargetWrapperVTbl =
00502 {
00503     DropTargetWrapper_QueryInterface,
00504     DropTargetWrapper_AddRef,
00505     DropTargetWrapper_Release,
00506     DropTargetWrapper_DragEnter,
00507     DropTargetWrapper_DragOver,
00508     DropTargetWrapper_DragLeave,
00509     DropTargetWrapper_Drop
00510 };
00511 
00512 static IDropTarget* WrapDropTarget( HWND hwnd )
00513 {
00514     DropTargetWrapper* This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
00515 
00516     if (This)
00517     {
00518         This->IDropTarget_iface.lpVtbl = &DropTargetWrapperVTbl;
00519         This->hwnd = hwnd;
00520         This->refs = 1;
00521     }
00522     return &This->IDropTarget_iface;
00523 }
00524 
00525 /***********************************************************************
00526  *     get_droptarget_pointer
00527  *
00528  * Retrieves the marshalled IDropTarget from the window.
00529  */
00530 static IDropTarget* get_droptarget_pointer(HWND hwnd)
00531 {
00532     IDropTarget *droptarget = NULL;
00533     HANDLE map;
00534     IStream *stream;
00535 
00536     map = get_droptarget_local_handle(hwnd);
00537     if(!map) return NULL;
00538 
00539     if(SUCCEEDED(create_stream_from_map(map, &stream)))
00540     {
00541         CoUnmarshalInterface(stream, &IID_IDropTarget, (void**)&droptarget);
00542         IStream_Release(stream);
00543     }
00544     CloseHandle(map);
00545     return droptarget;
00546 }
00547 
00548 /***********************************************************************
00549  *           RegisterDragDrop (OLE32.@)
00550  */
00551 HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
00552 {
00553   DWORD pid = 0;
00554   HRESULT hr;
00555   IStream *stream;
00556   HANDLE map;
00557   IDropTarget *wrapper;
00558 
00559   TRACE("(%p,%p)\n", hwnd, pDropTarget);
00560 
00561   if (!COM_CurrentApt())
00562   {
00563     ERR("COM not initialized\n");
00564     return E_OUTOFMEMORY;
00565   }
00566 
00567   if (!pDropTarget)
00568     return E_INVALIDARG;
00569 
00570   if (!IsWindow(hwnd))
00571   {
00572     ERR("invalid hwnd %p\n", hwnd);
00573     return DRAGDROP_E_INVALIDHWND;
00574   }
00575 
00576   /* block register for other processes windows */
00577   GetWindowThreadProcessId(hwnd, &pid);
00578   if (pid != GetCurrentProcessId())
00579   {
00580     FIXME("register for another process windows is disabled\n");
00581     return DRAGDROP_E_INVALIDHWND;
00582   }
00583 
00584   /* check if the window is already registered */
00585   if (is_droptarget(hwnd))
00586     return DRAGDROP_E_ALREADYREGISTERED;
00587 
00588   /*
00589    * Marshal the drop target pointer into a shared memory map and
00590    * store the map's handle in a Wine specific window prop.  We also
00591    * store the drop target pointer itself in the
00592    * "OleDropTargetInterface" prop for compatibility with Windows.
00593    */
00594 
00595   hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
00596   if(FAILED(hr)) return hr;
00597 
00598   /* IDropTarget::QueryInterface() shouldn't be called, some (broken) apps depend on this. */
00599   wrapper = WrapDropTarget( hwnd );
00600   if(!wrapper)
00601   {
00602     IStream_Release(stream);
00603     return E_OUTOFMEMORY;
00604   }
00605   hr = CoMarshalInterface(stream, &IID_IDropTarget, (IUnknown*)wrapper, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
00606   IDropTarget_Release(wrapper);
00607 
00608   if(SUCCEEDED(hr))
00609   {
00610     hr = create_map_from_stream(stream, &map);
00611     if(SUCCEEDED(hr))
00612     {
00613       IDropTarget_AddRef(pDropTarget);
00614       SetPropW(hwnd, prop_oledroptarget, pDropTarget);
00615       SetPropW(hwnd, prop_marshalleddroptarget, map);
00616     }
00617     else
00618     {
00619       LARGE_INTEGER zero;
00620       zero.QuadPart = 0;
00621       IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
00622       CoReleaseMarshalData(stream);
00623     }
00624   }
00625   IStream_Release(stream);
00626 
00627   return hr;
00628 }
00629 
00630 /***********************************************************************
00631  *           RevokeDragDrop (OLE32.@)
00632  */
00633 HRESULT WINAPI RevokeDragDrop(HWND hwnd)
00634 {
00635   HANDLE map;
00636   IStream *stream;
00637   IDropTarget *drop_target;
00638   HRESULT hr;
00639 
00640   TRACE("(%p)\n", hwnd);
00641 
00642   if (!IsWindow(hwnd))
00643   {
00644     ERR("invalid hwnd %p\n", hwnd);
00645     return DRAGDROP_E_INVALIDHWND;
00646   }
00647 
00648   /* no registration data */
00649   if (!(map = get_droptarget_handle(hwnd)))
00650     return DRAGDROP_E_NOTREGISTERED;
00651 
00652   drop_target = GetPropW(hwnd, prop_oledroptarget);
00653   if(drop_target) IDropTarget_Release(drop_target);
00654 
00655   RemovePropW(hwnd, prop_oledroptarget);
00656   RemovePropW(hwnd, prop_marshalleddroptarget);
00657 
00658   hr = create_stream_from_map(map, &stream);
00659   if(SUCCEEDED(hr))
00660   {
00661       CoReleaseMarshalData(stream);
00662       IStream_Release(stream);
00663   }
00664   CloseHandle(map);
00665 
00666   return hr;
00667 }
00668 
00669 /***********************************************************************
00670  *           OleRegGetUserType (OLE32.@)
00671  *
00672  * This implementation of OleRegGetUserType ignores the dwFormOfType
00673  * parameter and always returns the full name of the object. This is
00674  * not too bad since this is the case for many objects because of the
00675  * way they are registered.
00676  */
00677 HRESULT WINAPI OleRegGetUserType(
00678     REFCLSID clsid,
00679     DWORD dwFormOfType,
00680     LPOLESTR* pszUserType)
00681 {
00682   WCHAR   keyName[60];
00683   DWORD   dwKeyType;
00684   DWORD   cbData;
00685   HKEY    clsidKey;
00686   LONG    hres;
00687 
00688   /*
00689    * Initialize the out parameter.
00690    */
00691   *pszUserType = NULL;
00692 
00693   /*
00694    * Build the key name we're looking for
00695    */
00696   sprintfW( keyName, clsidfmtW,
00697             clsid->Data1, clsid->Data2, clsid->Data3,
00698             clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
00699             clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
00700 
00701   TRACE("(%s, %d, %p)\n", debugstr_w(keyName), dwFormOfType, pszUserType);
00702 
00703   /*
00704    * Open the class id Key
00705    */
00706   hres = RegOpenKeyW(HKEY_CLASSES_ROOT,
00707              keyName,
00708              &clsidKey);
00709 
00710   if (hres != ERROR_SUCCESS)
00711     return REGDB_E_CLASSNOTREG;
00712 
00713   /*
00714    * Retrieve the size of the name string.
00715    */
00716   cbData = 0;
00717 
00718   hres = RegQueryValueExW(clsidKey,
00719               emptyW,
00720               NULL,
00721               &dwKeyType,
00722               NULL,
00723               &cbData);
00724 
00725   if (hres!=ERROR_SUCCESS)
00726   {
00727     RegCloseKey(clsidKey);
00728     return REGDB_E_READREGDB;
00729   }
00730 
00731   /*
00732    * Allocate a buffer for the registry value.
00733    */
00734   *pszUserType = CoTaskMemAlloc(cbData);
00735 
00736   if (*pszUserType==NULL)
00737   {
00738     RegCloseKey(clsidKey);
00739     return E_OUTOFMEMORY;
00740   }
00741 
00742   hres = RegQueryValueExW(clsidKey,
00743               emptyW,
00744               NULL,
00745               &dwKeyType,
00746               (LPBYTE) *pszUserType,
00747               &cbData);
00748 
00749   RegCloseKey(clsidKey);
00750 
00751   if (hres != ERROR_SUCCESS)
00752   {
00753     CoTaskMemFree(*pszUserType);
00754     *pszUserType = NULL;
00755 
00756     return REGDB_E_READREGDB;
00757   }
00758 
00759   return S_OK;
00760 }
00761 
00762 /***********************************************************************
00763  * DoDragDrop [OLE32.@]
00764  */
00765 HRESULT WINAPI DoDragDrop (
00766   IDataObject *pDataObject,  /* [in] ptr to the data obj           */
00767   IDropSource* pDropSource,  /* [in] ptr to the source obj         */
00768   DWORD       dwOKEffect,    /* [in] effects allowed by the source */
00769   DWORD       *pdwEffect)    /* [out] ptr to effects of the source */
00770 {
00771   static const WCHAR trackerW[] = {'T','r','a','c','k','e','r','W','i','n','d','o','w',0};
00772   TrackerWindowInfo trackerInfo;
00773   HWND            hwndTrackWindow;
00774   MSG             msg;
00775 
00776   TRACE("(%p, %p, %08x, %p)\n", pDataObject, pDropSource, dwOKEffect, pdwEffect);
00777 
00778   if (!pDataObject || !pDropSource || !pdwEffect)
00779       return E_INVALIDARG;
00780 
00781   /*
00782    * Setup the drag n drop tracking window.
00783    */
00784 
00785   trackerInfo.dataObject        = pDataObject;
00786   trackerInfo.dropSource        = pDropSource;
00787   trackerInfo.dwOKEffect        = dwOKEffect;
00788   trackerInfo.pdwEffect         = pdwEffect;
00789   trackerInfo.trackingDone      = FALSE;
00790   trackerInfo.escPressed        = FALSE;
00791   trackerInfo.curDragTargetHWND = 0;
00792   trackerInfo.curTargetHWND     = 0;
00793   trackerInfo.curDragTarget     = 0;
00794 
00795   hwndTrackWindow = CreateWindowW(OLEDD_DRAGTRACKERCLASS, trackerW,
00796                                   WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
00797                                   CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0,
00798                                   &trackerInfo);
00799 
00800   if (hwndTrackWindow)
00801   {
00802     /*
00803      * Capture the mouse input
00804      */
00805     SetCapture(hwndTrackWindow);
00806 
00807     msg.message = 0;
00808 
00809     /*
00810      * Pump messages. All mouse input should go to the capture window.
00811      */
00812     while (!trackerInfo.trackingDone && GetMessageW(&msg, 0, 0, 0) )
00813     {
00814       trackerInfo.curMousePos.x = msg.pt.x;
00815       trackerInfo.curMousePos.y = msg.pt.y;
00816       trackerInfo.dwKeyState = OLEDD_GetButtonState();
00817         
00818       if ( (msg.message >= WM_KEYFIRST) &&
00819        (msg.message <= WM_KEYLAST) )
00820       {
00821     /*
00822      * When keyboard messages are sent to windows on this thread, we
00823      * want to ignore notify the drop source that the state changed.
00824      * in the case of the Escape key, we also notify the drop source
00825      * we give it a special meaning.
00826      */
00827     if ( (msg.message==WM_KEYDOWN) &&
00828          (msg.wParam==VK_ESCAPE) )
00829     {
00830       trackerInfo.escPressed = TRUE;
00831     }
00832 
00833     /*
00834      * Notify the drop source.
00835      */
00836         OLEDD_TrackStateChange(&trackerInfo);
00837       }
00838       else
00839       {
00840     /*
00841      * Dispatch the messages only when it's not a keyboard message.
00842      */
00843     DispatchMessageW(&msg);
00844       }
00845     }
00846 
00847     /* re-post the quit message to outer message loop */
00848     if (msg.message == WM_QUIT)
00849         PostQuitMessage(msg.wParam);
00850     /*
00851      * Destroy the temporary window.
00852      */
00853     DestroyWindow(hwndTrackWindow);
00854 
00855     return trackerInfo.returnValue;
00856   }
00857 
00858   return E_FAIL;
00859 }
00860 
00861 /***********************************************************************
00862  * OleQueryLinkFromData [OLE32.@]
00863  */
00864 HRESULT WINAPI OleQueryLinkFromData(
00865   IDataObject* pSrcDataObject)
00866 {
00867   FIXME("(%p),stub!\n", pSrcDataObject);
00868   return S_FALSE;
00869 }
00870 
00871 /***********************************************************************
00872  * OleRegGetMiscStatus [OLE32.@]
00873  */
00874 HRESULT WINAPI OleRegGetMiscStatus(
00875   REFCLSID clsid,
00876   DWORD    dwAspect,
00877   DWORD*   pdwStatus)
00878 {
00879   static const WCHAR miscstatusW[] = {'M','i','s','c','S','t','a','t','u','s',0};
00880   static const WCHAR dfmtW[] = {'%','d',0};
00881   WCHAR   keyName[60];
00882   HKEY    clsidKey;
00883   HKEY    miscStatusKey;
00884   HKEY    aspectKey;
00885   LONG    result;
00886 
00887   /*
00888    * Initialize the out parameter.
00889    */
00890   *pdwStatus = 0;
00891 
00892   /*
00893    * Build the key name we're looking for
00894    */
00895   sprintfW( keyName, clsidfmtW,
00896             clsid->Data1, clsid->Data2, clsid->Data3,
00897             clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
00898             clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
00899 
00900   TRACE("(%s, %d, %p)\n", debugstr_w(keyName), dwAspect, pdwStatus);
00901 
00902   /*
00903    * Open the class id Key
00904    */
00905   result = RegOpenKeyW(HKEY_CLASSES_ROOT,
00906                keyName,
00907                &clsidKey);
00908 
00909   if (result != ERROR_SUCCESS)
00910     return REGDB_E_CLASSNOTREG;
00911 
00912   /*
00913    * Get the MiscStatus
00914    */
00915   result = RegOpenKeyW(clsidKey,
00916                miscstatusW,
00917                &miscStatusKey);
00918 
00919 
00920   if (result != ERROR_SUCCESS)
00921   {
00922     RegCloseKey(clsidKey);
00923     return REGDB_E_READREGDB;
00924   }
00925 
00926   /*
00927    * Read the default value
00928    */
00929   OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
00930 
00931   /*
00932    * Open the key specific to the requested aspect.
00933    */
00934   sprintfW(keyName, dfmtW, dwAspect);
00935 
00936   result = RegOpenKeyW(miscStatusKey,
00937                keyName,
00938                &aspectKey);
00939 
00940   if (result == ERROR_SUCCESS)
00941   {
00942     OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
00943     RegCloseKey(aspectKey);
00944   }
00945 
00946   /*
00947    * Cleanup
00948    */
00949   RegCloseKey(miscStatusKey);
00950   RegCloseKey(clsidKey);
00951 
00952   return S_OK;
00953 }
00954 
00955 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum);
00956 
00957 typedef struct
00958 {
00959     IEnumOLEVERB IEnumOLEVERB_iface;
00960     LONG ref;
00961 
00962     HKEY hkeyVerb;
00963     ULONG index;
00964 } EnumOLEVERB;
00965 
00966 static inline EnumOLEVERB *impl_from_IEnumOLEVERB(IEnumOLEVERB *iface)
00967 {
00968     return CONTAINING_RECORD(iface, EnumOLEVERB, IEnumOLEVERB_iface);
00969 }
00970 
00971 static HRESULT WINAPI EnumOLEVERB_QueryInterface(
00972     IEnumOLEVERB *iface, REFIID riid, void **ppv)
00973 {
00974     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
00975     if (IsEqualIID(riid, &IID_IUnknown) ||
00976         IsEqualIID(riid, &IID_IEnumOLEVERB))
00977     {
00978         IUnknown_AddRef(iface);
00979         *ppv = iface;
00980         return S_OK;
00981     }
00982     return E_NOINTERFACE;
00983 }
00984 
00985 static ULONG WINAPI EnumOLEVERB_AddRef(
00986     IEnumOLEVERB *iface)
00987 {
00988     EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
00989     TRACE("()\n");
00990     return InterlockedIncrement(&This->ref);
00991 }
00992 
00993 static ULONG WINAPI EnumOLEVERB_Release(
00994     IEnumOLEVERB *iface)
00995 {
00996     EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
00997     LONG refs = InterlockedDecrement(&This->ref);
00998     TRACE("()\n");
00999     if (!refs)
01000     {
01001         RegCloseKey(This->hkeyVerb);
01002         HeapFree(GetProcessHeap(), 0, This);
01003     }
01004     return refs;
01005 }
01006 
01007 static HRESULT WINAPI EnumOLEVERB_Next(
01008     IEnumOLEVERB *iface, ULONG celt, LPOLEVERB rgelt,
01009     ULONG *pceltFetched)
01010 {
01011     EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
01012     HRESULT hr = S_OK;
01013 
01014     TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched);
01015 
01016     if (pceltFetched)
01017         *pceltFetched = 0;
01018 
01019     for (; celt; celt--, rgelt++)
01020     {
01021         WCHAR wszSubKey[20];
01022         LONG cbData;
01023         LPWSTR pwszOLEVERB;
01024         LPWSTR pwszMenuFlags;
01025         LPWSTR pwszAttribs;
01026         LONG res = RegEnumKeyW(This->hkeyVerb, This->index, wszSubKey, sizeof(wszSubKey)/sizeof(wszSubKey[0]));
01027         if (res == ERROR_NO_MORE_ITEMS)
01028         {
01029             hr = S_FALSE;
01030             break;
01031         }
01032         else if (res != ERROR_SUCCESS)
01033         {
01034             ERR("RegEnumKeyW failed with error %d\n", res);
01035             hr = REGDB_E_READREGDB;
01036             break;
01037         }
01038         res = RegQueryValueW(This->hkeyVerb, wszSubKey, NULL, &cbData);
01039         if (res != ERROR_SUCCESS)
01040         {
01041             ERR("RegQueryValueW failed with error %d\n", res);
01042             hr = REGDB_E_READREGDB;
01043             break;
01044         }
01045         pwszOLEVERB = CoTaskMemAlloc(cbData);
01046         if (!pwszOLEVERB)
01047         {
01048             hr = E_OUTOFMEMORY;
01049             break;
01050         }
01051         res = RegQueryValueW(This->hkeyVerb, wszSubKey, pwszOLEVERB, &cbData);
01052         if (res != ERROR_SUCCESS)
01053         {
01054             ERR("RegQueryValueW failed with error %d\n", res);
01055             hr = REGDB_E_READREGDB;
01056             CoTaskMemFree(pwszOLEVERB);
01057             break;
01058         }
01059 
01060         TRACE("verb string: %s\n", debugstr_w(pwszOLEVERB));
01061         pwszMenuFlags = strchrW(pwszOLEVERB, ',');
01062         if (!pwszMenuFlags)
01063         {
01064             hr = OLEOBJ_E_INVALIDVERB;
01065             CoTaskMemFree(pwszOLEVERB);
01066             break;
01067         }
01068         /* nul terminate the name string and advance to first character */
01069         *pwszMenuFlags = '\0';
01070         pwszMenuFlags++;
01071         pwszAttribs = strchrW(pwszMenuFlags, ',');
01072         if (!pwszAttribs)
01073         {
01074             hr = OLEOBJ_E_INVALIDVERB;
01075             CoTaskMemFree(pwszOLEVERB);
01076             break;
01077         }
01078         /* nul terminate the menu string and advance to first character */
01079         *pwszAttribs = '\0';
01080         pwszAttribs++;
01081 
01082         /* fill out structure for this verb */
01083         rgelt->lVerb = atolW(wszSubKey);
01084         rgelt->lpszVerbName = pwszOLEVERB; /* user should free */
01085         rgelt->fuFlags = atolW(pwszMenuFlags);
01086         rgelt->grfAttribs = atolW(pwszAttribs);
01087 
01088         if (pceltFetched)
01089             (*pceltFetched)++;
01090         This->index++;
01091     }
01092     return hr;
01093 }
01094 
01095 static HRESULT WINAPI EnumOLEVERB_Skip(
01096     IEnumOLEVERB *iface, ULONG celt)
01097 {
01098     EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
01099 
01100     TRACE("(%d)\n", celt);
01101 
01102     This->index += celt;
01103     return S_OK;
01104 }
01105 
01106 static HRESULT WINAPI EnumOLEVERB_Reset(
01107     IEnumOLEVERB *iface)
01108 {
01109     EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
01110 
01111     TRACE("()\n");
01112 
01113     This->index = 0;
01114     return S_OK;
01115 }
01116 
01117 static HRESULT WINAPI EnumOLEVERB_Clone(
01118     IEnumOLEVERB *iface,
01119     IEnumOLEVERB **ppenum)
01120 {
01121     EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
01122     HKEY hkeyVerb;
01123     TRACE("(%p)\n", ppenum);
01124     if (!DuplicateHandle(GetCurrentProcess(), This->hkeyVerb, GetCurrentProcess(), (HANDLE *)&hkeyVerb, 0, FALSE, DUPLICATE_SAME_ACCESS))
01125         return HRESULT_FROM_WIN32(GetLastError());
01126     return EnumOLEVERB_Construct(hkeyVerb, This->index, ppenum);
01127 }
01128 
01129 static const IEnumOLEVERBVtbl EnumOLEVERB_VTable =
01130 {
01131     EnumOLEVERB_QueryInterface,
01132     EnumOLEVERB_AddRef,
01133     EnumOLEVERB_Release,
01134     EnumOLEVERB_Next,
01135     EnumOLEVERB_Skip,
01136     EnumOLEVERB_Reset,
01137     EnumOLEVERB_Clone
01138 };
01139 
01140 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum)
01141 {
01142     EnumOLEVERB *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
01143     if (!This)
01144     {
01145         RegCloseKey(hkeyVerb);
01146         return E_OUTOFMEMORY;
01147     }
01148     This->IEnumOLEVERB_iface.lpVtbl = &EnumOLEVERB_VTable;
01149     This->ref = 1;
01150     This->index = index;
01151     This->hkeyVerb = hkeyVerb;
01152     *ppenum = &This->IEnumOLEVERB_iface;
01153     return S_OK;
01154 }
01155 
01156 /***********************************************************************
01157  *           OleRegEnumVerbs    [OLE32.@]
01158  *
01159  * Enumerates verbs associated with a class stored in the registry.
01160  *
01161  * PARAMS
01162  *  clsid  [I] Class ID to enumerate the verbs for.
01163  *  ppenum [O] Enumerator.
01164  *
01165  * RETURNS
01166  *  S_OK: Success.
01167  *  REGDB_E_CLASSNOTREG: The specified class does not have a key in the registry.
01168  *  REGDB_E_READREGDB: The class key could not be opened for some other reason.
01169  *  OLE_E_REGDB_KEY: The Verb subkey for the class is not present.
01170  *  OLEOBJ_E_NOVERBS: The Verb subkey for the class is empty.
01171  */
01172 HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum)
01173 {
01174     LONG res;
01175     HKEY hkeyVerb;
01176     DWORD dwSubKeys;
01177     static const WCHAR wszVerb[] = {'V','e','r','b',0};
01178 
01179     TRACE("(%s, %p)\n", debugstr_guid(clsid), ppenum);
01180 
01181     res = COM_OpenKeyForCLSID(clsid, wszVerb, KEY_READ, &hkeyVerb);
01182     if (FAILED(res))
01183     {
01184         if (res == REGDB_E_CLASSNOTREG)
01185             ERR("CLSID %s not registered\n", debugstr_guid(clsid));
01186         else if (res == REGDB_E_KEYMISSING)
01187             ERR("no Verbs key for class %s\n", debugstr_guid(clsid));
01188         else
01189             ERR("failed to open Verbs key for CLSID %s with error %d\n",
01190                 debugstr_guid(clsid), res);
01191         return res;
01192     }
01193 
01194     res = RegQueryInfoKeyW(hkeyVerb, NULL, NULL, NULL, &dwSubKeys, NULL,
01195                           NULL, NULL, NULL, NULL, NULL, NULL);
01196     if (res != ERROR_SUCCESS)
01197     {
01198         ERR("failed to get subkey count with error %d\n", GetLastError());
01199         return REGDB_E_READREGDB;
01200     }
01201 
01202     if (!dwSubKeys)
01203     {
01204         WARN("class %s has no verbs\n", debugstr_guid(clsid));
01205         RegCloseKey(hkeyVerb);
01206         return OLEOBJ_E_NOVERBS;
01207     }
01208 
01209     return EnumOLEVERB_Construct(hkeyVerb, 0, ppenum);
01210 }
01211 
01212 /******************************************************************************
01213  *              OleSetContainedObject        [OLE32.@]
01214  */
01215 HRESULT WINAPI OleSetContainedObject(
01216   LPUNKNOWN pUnknown,
01217   BOOL      fContained)
01218 {
01219   IRunnableObject* runnable = NULL;
01220   HRESULT          hres;
01221 
01222   TRACE("(%p,%x)\n", pUnknown, fContained);
01223 
01224   hres = IUnknown_QueryInterface(pUnknown,
01225                  &IID_IRunnableObject,
01226                  (void**)&runnable);
01227 
01228   if (SUCCEEDED(hres))
01229   {
01230     hres = IRunnableObject_SetContainedObject(runnable, fContained);
01231 
01232     IRunnableObject_Release(runnable);
01233 
01234     return hres;
01235   }
01236 
01237   return S_OK;
01238 }
01239 
01240 /******************************************************************************
01241  *              OleRun        [OLE32.@]
01242  *
01243  * Set the OLE object to the running state.
01244  *
01245  * PARAMS
01246  *  pUnknown [I] OLE object to run.
01247  *
01248  * RETURNS
01249  *  Success: S_OK.
01250  *  Failure: Any HRESULT code.
01251  */
01252 HRESULT WINAPI OleRun(LPUNKNOWN pUnknown)
01253 {
01254     IRunnableObject *runable;
01255     HRESULT hres;
01256 
01257     TRACE("(%p)\n", pUnknown);
01258 
01259     hres = IUnknown_QueryInterface(pUnknown, &IID_IRunnableObject, (void**)&runable);
01260     if (FAILED(hres))
01261         return S_OK; /* Appears to return no error. */
01262 
01263     hres = IRunnableObject_Run(runable, NULL);
01264     IRunnableObject_Release(runable);
01265     return hres;
01266 }
01267 
01268 /******************************************************************************
01269  *              OleLoad        [OLE32.@]
01270  */
01271 HRESULT WINAPI OleLoad(
01272   LPSTORAGE       pStg,
01273   REFIID          riid,
01274   LPOLECLIENTSITE pClientSite,
01275   LPVOID*         ppvObj)
01276 {
01277   IPersistStorage* persistStorage = NULL;
01278   IUnknown*        pUnk;
01279   IOleObject*      pOleObject      = NULL;
01280   STATSTG          storageInfo;
01281   HRESULT          hres;
01282 
01283   TRACE("(%p, %s, %p, %p)\n", pStg, debugstr_guid(riid), pClientSite, ppvObj);
01284 
01285   *ppvObj = NULL;
01286 
01287   /*
01288    * TODO, Conversion ... OleDoAutoConvert
01289    */
01290 
01291   /*
01292    * Get the class ID for the object.
01293    */
01294   hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
01295 
01296   /*
01297    * Now, try and create the handler for the object
01298    */
01299   hres = CoCreateInstance(&storageInfo.clsid,
01300               NULL,
01301               CLSCTX_INPROC_HANDLER|CLSCTX_INPROC_SERVER,
01302               riid,
01303               (void**)&pUnk);
01304 
01305   /*
01306    * If that fails, as it will most times, load the default
01307    * OLE handler.
01308    */
01309   if (FAILED(hres))
01310   {
01311     hres = OleCreateDefaultHandler(&storageInfo.clsid,
01312                    NULL,
01313                    riid,
01314                    (void**)&pUnk);
01315   }
01316 
01317   /*
01318    * If we couldn't find a handler... this is bad. Abort the whole thing.
01319    */
01320   if (FAILED(hres))
01321     return hres;
01322 
01323   if (pClientSite)
01324   {
01325     hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (void **)&pOleObject);
01326     if (SUCCEEDED(hres))
01327     {
01328         DWORD dwStatus;
01329         hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
01330     }
01331   }
01332 
01333   /*
01334    * Initialize the object with its IPersistStorage interface.
01335    */
01336   hres = IOleObject_QueryInterface(pUnk,
01337                                    &IID_IPersistStorage,
01338                                    (void**)&persistStorage);
01339 
01340   if (SUCCEEDED(hres))
01341   {
01342     hres = IPersistStorage_Load(persistStorage, pStg);
01343 
01344     IPersistStorage_Release(persistStorage);
01345     persistStorage = NULL;
01346   }
01347 
01348   if (SUCCEEDED(hres) && pClientSite)
01349     /*
01350      * Inform the new object of it's client site.
01351      */
01352     hres = IOleObject_SetClientSite(pOleObject, pClientSite);
01353 
01354   /*
01355    * Cleanup interfaces used internally
01356    */
01357   if (pOleObject)
01358     IOleObject_Release(pOleObject);
01359 
01360   if (SUCCEEDED(hres))
01361   {
01362     IOleLink *pOleLink;
01363     HRESULT hres1;
01364     hres1 = IUnknown_QueryInterface(pUnk, &IID_IOleLink, (void **)&pOleLink);
01365     if (SUCCEEDED(hres1))
01366     {
01367       FIXME("handle OLE link\n");
01368       IOleLink_Release(pOleLink);
01369     }
01370   }
01371 
01372   if (FAILED(hres))
01373   {
01374     IUnknown_Release(pUnk);
01375     pUnk = NULL;
01376   }
01377 
01378   *ppvObj = pUnk;
01379 
01380   return hres;
01381 }
01382 
01383 /***********************************************************************
01384  *           OleSave     [OLE32.@]
01385  */
01386 HRESULT WINAPI OleSave(
01387   LPPERSISTSTORAGE pPS,
01388   LPSTORAGE        pStg,
01389   BOOL             fSameAsLoad)
01390 {
01391   HRESULT hres;
01392   CLSID   objectClass;
01393 
01394   TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
01395 
01396   /*
01397    * First, we transfer the class ID (if available)
01398    */
01399   hres = IPersistStorage_GetClassID(pPS, &objectClass);
01400 
01401   if (SUCCEEDED(hres))
01402   {
01403     WriteClassStg(pStg, &objectClass);
01404   }
01405 
01406   /*
01407    * Then, we ask the object to save itself to the
01408    * storage. If it is successful, we commit the storage.
01409    */
01410   hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
01411 
01412   if (SUCCEEDED(hres))
01413   {
01414     IStorage_Commit(pStg,
01415             STGC_DEFAULT);
01416   }
01417 
01418   return hres;
01419 }
01420 
01421 
01422 /******************************************************************************
01423  *              OleLockRunning        [OLE32.@]
01424  */
01425 HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)
01426 {
01427   IRunnableObject* runnable = NULL;
01428   HRESULT          hres;
01429 
01430   TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);
01431 
01432   hres = IUnknown_QueryInterface(pUnknown,
01433                  &IID_IRunnableObject,
01434                  (void**)&runnable);
01435 
01436   if (SUCCEEDED(hres))
01437   {
01438     hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);
01439 
01440     IRunnableObject_Release(runnable);
01441 
01442     return hres;
01443   }
01444 
01445   return S_OK;
01446 }
01447 
01448 
01449 /**************************************************************************
01450  * Internal methods to manage the shared OLE menu in response to the
01451  * OLE***MenuDescriptor API
01452  */
01453 
01454 /***
01455  * OLEMenu_Initialize()
01456  *
01457  * Initializes the OLEMENU data structures.
01458  */
01459 static void OLEMenu_Initialize(void)
01460 {
01461 }
01462 
01463 /***
01464  * OLEMenu_UnInitialize()
01465  *
01466  * Releases the OLEMENU data structures.
01467  */
01468 static void OLEMenu_UnInitialize(void)
01469 {
01470 }
01471 
01472 /*************************************************************************
01473  * OLEMenu_InstallHooks
01474  * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
01475  *
01476  * RETURNS: TRUE if message hooks were successfully installed
01477  *          FALSE on failure
01478  */
01479 static BOOL OLEMenu_InstallHooks( DWORD tid )
01480 {
01481   OleMenuHookItem *pHookItem;
01482 
01483   /* Create an entry for the hook table */
01484   if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
01485                                sizeof(OleMenuHookItem)) ) )
01486     return FALSE;
01487 
01488   pHookItem->tid = tid;
01489   pHookItem->hHeap = GetProcessHeap();
01490   pHookItem->CallWndProc_hHook = NULL;
01491 
01492   /* Install a thread scope message hook for WH_GETMESSAGE */
01493   pHookItem->GetMsg_hHook = SetWindowsHookExW( WH_GETMESSAGE, OLEMenu_GetMsgProc,
01494                                                0, GetCurrentThreadId() );
01495   if ( !pHookItem->GetMsg_hHook )
01496     goto CLEANUP;
01497 
01498   /* Install a thread scope message hook for WH_CALLWNDPROC */
01499   pHookItem->CallWndProc_hHook = SetWindowsHookExW( WH_CALLWNDPROC, OLEMenu_CallWndProc,
01500                                                     0, GetCurrentThreadId() );
01501   if ( !pHookItem->CallWndProc_hHook )
01502     goto CLEANUP;
01503 
01504   /* Insert the hook table entry */
01505   pHookItem->next = hook_list;
01506   hook_list = pHookItem;
01507 
01508   return TRUE;
01509 
01510 CLEANUP:
01511   /* Unhook any hooks */
01512   if ( pHookItem->GetMsg_hHook )
01513     UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
01514   if ( pHookItem->CallWndProc_hHook )
01515     UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
01516   /* Release the hook table entry */
01517   HeapFree(pHookItem->hHeap, 0, pHookItem );
01518 
01519   return FALSE;
01520 }
01521 
01522 /*************************************************************************
01523  * OLEMenu_UnInstallHooks
01524  * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
01525  *
01526  * RETURNS: TRUE if message hooks were successfully installed
01527  *          FALSE on failure
01528  */
01529 static BOOL OLEMenu_UnInstallHooks( DWORD tid )
01530 {
01531   OleMenuHookItem *pHookItem = NULL;
01532   OleMenuHookItem **ppHook = &hook_list;
01533 
01534   while (*ppHook)
01535   {
01536       if ((*ppHook)->tid == tid)
01537       {
01538           pHookItem = *ppHook;
01539           *ppHook = pHookItem->next;
01540           break;
01541       }
01542       ppHook = &(*ppHook)->next;
01543   }
01544   if (!pHookItem) return FALSE;
01545 
01546   /* Uninstall the hooks installed for this thread */
01547   if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
01548     goto CLEANUP;
01549   if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
01550     goto CLEANUP;
01551 
01552   /* Release the hook table entry */
01553   HeapFree(pHookItem->hHeap, 0, pHookItem );
01554 
01555   return TRUE;
01556 
01557 CLEANUP:
01558   /* Release the hook table entry */
01559   HeapFree(pHookItem->hHeap, 0, pHookItem );
01560 
01561   return FALSE;
01562 }
01563 
01564 /*************************************************************************
01565  * OLEMenu_IsHookInstalled
01566  * Tests if OLEMenu hooks have been installed for a thread
01567  *
01568  * RETURNS: The pointer and index of the hook table entry for the tid
01569  *          NULL and -1 for the index if no hooks were installed for this thread
01570  */
01571 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
01572 {
01573   OleMenuHookItem *pHookItem;
01574 
01575   /* Do a simple linear search for an entry whose tid matches ours.
01576    * We really need a map but efficiency is not a concern here. */
01577   for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
01578   {
01579     if ( tid == pHookItem->tid )
01580       return pHookItem;
01581   }
01582 
01583   return NULL;
01584 }
01585 
01586 /***********************************************************************
01587  *           OLEMenu_FindMainMenuIndex
01588  *
01589  * Used by OLEMenu API to find the top level group a menu item belongs to.
01590  * On success pnPos contains the index of the item in the top level menu group
01591  *
01592  * RETURNS: TRUE if the ID was found, FALSE on failure
01593  */
01594 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
01595 {
01596   INT i, nItems;
01597 
01598   nItems = GetMenuItemCount( hMainMenu );
01599 
01600   for (i = 0; i < nItems; i++)
01601   {
01602     HMENU hsubmenu;
01603 
01604     /*  Is the current item a submenu? */
01605     if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
01606     {
01607       /* If the handle is the same we're done */
01608       if ( hsubmenu == hPopupMenu )
01609       {
01610         if (pnPos)
01611           *pnPos = i;
01612         return TRUE;
01613       }
01614       /* Recursively search without updating pnPos */
01615       else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
01616       {
01617         if (pnPos)
01618           *pnPos = i;
01619         return TRUE;
01620       }
01621     }
01622   }
01623 
01624   return FALSE;
01625 }
01626 
01627 /***********************************************************************
01628  *           OLEMenu_SetIsServerMenu
01629  *
01630  * Checks whether a popup menu belongs to a shared menu group which is
01631  * owned by the server, and sets the menu descriptor state accordingly.
01632  * All menu messages from these groups should be routed to the server.
01633  *
01634  * RETURNS: TRUE if the popup menu is part of a server owned group
01635  *          FALSE if the popup menu is part of a container owned group
01636  */
01637 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
01638 {
01639   UINT nPos = 0, nWidth, i;
01640 
01641   pOleMenuDescriptor->bIsServerItem = FALSE;
01642 
01643   /* Don't bother searching if the popup is the combined menu itself */
01644   if ( hmenu == pOleMenuDescriptor->hmenuCombined )
01645     return FALSE;
01646 
01647   /* Find the menu item index in the shared OLE menu that this item belongs to */
01648   if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu,  &nPos ) )
01649     return FALSE;
01650 
01651   /* The group widths array has counts for the number of elements
01652    * in the groups File, Edit, Container, Object, Window, Help.
01653    * The Edit, Object & Help groups belong to the server object
01654    * and the other three belong to the container.
01655    * Loop through the group widths and locate the group we are a member of.
01656    */
01657   for ( i = 0, nWidth = 0; i < 6; i++ )
01658   {
01659     nWidth += pOleMenuDescriptor->mgw.width[i];
01660     if ( nPos < nWidth )
01661     {
01662       /* Odd elements are server menu widths */
01663       pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
01664       break;
01665     }
01666   }
01667 
01668   return pOleMenuDescriptor->bIsServerItem;
01669 }
01670 
01671 /*************************************************************************
01672  * OLEMenu_CallWndProc
01673  * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
01674  * This is invoked from a message hook installed in OleSetMenuDescriptor.
01675  */
01676 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
01677 {
01678   LPCWPSTRUCT pMsg;
01679   HOLEMENU hOleMenu = 0;
01680   OleMenuDescriptor *pOleMenuDescriptor = NULL;
01681   OleMenuHookItem *pHookItem = NULL;
01682   WORD fuFlags;
01683 
01684   TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
01685 
01686   /* Check if we're being asked to process the message */
01687   if ( HC_ACTION != code )
01688     goto NEXTHOOK;
01689 
01690   /* Retrieve the current message being dispatched from lParam */
01691   pMsg = (LPCWPSTRUCT)lParam;
01692 
01693   /* Check if the message is destined for a window we are interested in:
01694    * If the window has an OLEMenu property we may need to dispatch
01695    * the menu message to its active objects window instead. */
01696 
01697   hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
01698   if ( !hOleMenu )
01699     goto NEXTHOOK;
01700 
01701   /* Get the menu descriptor */
01702   pOleMenuDescriptor = GlobalLock( hOleMenu );
01703   if ( !pOleMenuDescriptor ) /* Bad descriptor! */
01704     goto NEXTHOOK;
01705 
01706   /* Process menu messages */
01707   switch( pMsg->message )
01708   {
01709     case WM_INITMENU:
01710     {
01711       /* Reset the menu descriptor state */
01712       pOleMenuDescriptor->bIsServerItem = FALSE;
01713 
01714       /* Send this message to the server as well */
01715       SendMessageW( pOleMenuDescriptor->hwndActiveObject,
01716                   pMsg->message, pMsg->wParam, pMsg->lParam );
01717       goto NEXTHOOK;
01718     }
01719 
01720     case WM_INITMENUPOPUP:
01721     {
01722       /* Save the state for whether this is a server owned menu */
01723       OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
01724       break;
01725     }
01726 
01727     case WM_MENUSELECT:
01728     {
01729       fuFlags = HIWORD(pMsg->wParam);  /* Get flags */
01730       if ( fuFlags & MF_SYSMENU )
01731          goto NEXTHOOK;
01732 
01733       /* Save the state for whether this is a server owned popup menu */
01734       else if ( fuFlags & MF_POPUP )
01735         OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
01736 
01737       break;
01738     }
01739 
01740     case WM_DRAWITEM:
01741     {
01742       LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
01743       if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
01744         goto NEXTHOOK;  /* Not a menu message */
01745 
01746       break;
01747     }
01748 
01749     default:
01750       goto NEXTHOOK;
01751   }
01752 
01753   /* If the message was for the server dispatch it accordingly */
01754   if ( pOleMenuDescriptor->bIsServerItem )
01755   {
01756     SendMessageW( pOleMenuDescriptor->hwndActiveObject,
01757                   pMsg->message, pMsg->wParam, pMsg->lParam );
01758   }
01759 
01760 NEXTHOOK:
01761   if ( pOleMenuDescriptor )
01762     GlobalUnlock( hOleMenu );
01763 
01764   /* Lookup the hook item for the current thread */
01765   if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
01766   {
01767     /* This should never fail!! */
01768     WARN("could not retrieve hHook for current thread!\n" );
01769     return 0;
01770   }
01771 
01772   /* Pass on the message to the next hooker */
01773   return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
01774 }
01775 
01776 /*************************************************************************
01777  * OLEMenu_GetMsgProc
01778  * Thread scope WH_GETMESSAGE hook proc filter function (callback)
01779  * This is invoked from a message hook installed in OleSetMenuDescriptor.
01780  */
01781 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
01782 {
01783   LPMSG pMsg;
01784   HOLEMENU hOleMenu = 0;
01785   OleMenuDescriptor *pOleMenuDescriptor = NULL;
01786   OleMenuHookItem *pHookItem = NULL;
01787   WORD wCode;
01788 
01789   TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
01790 
01791   /* Check if we're being asked to process a  messages */
01792   if ( HC_ACTION != code )
01793     goto NEXTHOOK;
01794 
01795   /* Retrieve the current message being dispatched from lParam */
01796   pMsg = (LPMSG)lParam;
01797 
01798   /* Check if the message is destined for a window we are interested in:
01799    * If the window has an OLEMenu property we may need to dispatch
01800    * the menu message to its active objects window instead. */
01801 
01802   hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
01803   if ( !hOleMenu )
01804     goto NEXTHOOK;
01805 
01806   /* Process menu messages */
01807   switch( pMsg->message )
01808   {
01809     case WM_COMMAND:
01810     {
01811       wCode = HIWORD(pMsg->wParam);  /* Get notification code */
01812       if ( wCode )
01813         goto NEXTHOOK;  /* Not a menu message */
01814       break;
01815     }
01816     default:
01817       goto NEXTHOOK;
01818   }
01819 
01820   /* Get the menu descriptor */
01821   pOleMenuDescriptor = GlobalLock( hOleMenu );
01822   if ( !pOleMenuDescriptor ) /* Bad descriptor! */
01823     goto NEXTHOOK;
01824 
01825   /* If the message was for the server dispatch it accordingly */
01826   if ( pOleMenuDescriptor->bIsServerItem )
01827   {
01828     /* Change the hWnd in the message to the active objects hWnd.
01829      * The message loop which reads this message will automatically
01830      * dispatch it to the embedded objects window. */
01831     pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
01832   }
01833 
01834 NEXTHOOK:
01835   if ( pOleMenuDescriptor )
01836     GlobalUnlock( hOleMenu );
01837 
01838   /* Lookup the hook item for the current thread */
01839   if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
01840   {
01841     /* This should never fail!! */
01842     WARN("could not retrieve hHook for current thread!\n" );
01843     return FALSE;
01844   }
01845 
01846   /* Pass on the message to the next hooker */
01847   return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
01848 }
01849 
01850 /***********************************************************************
01851  * OleCreateMenuDescriptor [OLE32.@]
01852  * Creates an OLE menu descriptor for OLE to use when dispatching
01853  * menu messages and commands.
01854  *
01855  * PARAMS:
01856  *    hmenuCombined  -  Handle to the objects combined menu
01857  *    lpMenuWidths   -  Pointer to array of 6 LONG's indicating menus per group
01858  *
01859  */
01860 HOLEMENU WINAPI OleCreateMenuDescriptor(
01861   HMENU                hmenuCombined,
01862   LPOLEMENUGROUPWIDTHS lpMenuWidths)
01863 {
01864   HOLEMENU hOleMenu;
01865   OleMenuDescriptor *pOleMenuDescriptor;
01866   int i;
01867 
01868   if ( !hmenuCombined || !lpMenuWidths )
01869     return 0;
01870 
01871   /* Create an OLE menu descriptor */
01872   if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
01873                                 sizeof(OleMenuDescriptor) ) ) )
01874   return 0;
01875 
01876   pOleMenuDescriptor = GlobalLock( hOleMenu );
01877   if ( !pOleMenuDescriptor )
01878     return 0;
01879 
01880   /* Initialize menu group widths and hmenu */
01881   for ( i = 0; i < 6; i++ )
01882     pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
01883 
01884   pOleMenuDescriptor->hmenuCombined = hmenuCombined;
01885   pOleMenuDescriptor->bIsServerItem = FALSE;
01886   GlobalUnlock( hOleMenu );
01887 
01888   return hOleMenu;
01889 }
01890 
01891 /***********************************************************************
01892  * OleDestroyMenuDescriptor [OLE32.@]
01893  * Destroy the shared menu descriptor
01894  */
01895 HRESULT WINAPI OleDestroyMenuDescriptor(
01896   HOLEMENU hmenuDescriptor)
01897 {
01898   if ( hmenuDescriptor )
01899     GlobalFree( hmenuDescriptor );
01900     return S_OK;
01901 }
01902 
01903 /***********************************************************************
01904  * OleSetMenuDescriptor [OLE32.@]
01905  * Installs or removes OLE dispatching code for the containers frame window.
01906  *
01907  * PARAMS
01908  *     hOleMenu         Handle to composite menu descriptor
01909  *     hwndFrame        Handle to containers frame window
01910  *     hwndActiveObject Handle to objects in-place activation window
01911  *     lpFrame          Pointer to IOleInPlaceFrame on containers window
01912  *     lpActiveObject   Pointer to IOleInPlaceActiveObject on active in-place object
01913  *
01914  * RETURNS
01915  *      S_OK                               - menu installed correctly
01916  *      E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
01917  *
01918  * FIXME
01919  *      The lpFrame and lpActiveObject parameters are currently ignored
01920  *      OLE should install context sensitive help F1 filtering for the app when
01921  *      these are non null.
01922  */
01923 HRESULT WINAPI OleSetMenuDescriptor(
01924   HOLEMENU               hOleMenu,
01925   HWND                   hwndFrame,
01926   HWND                   hwndActiveObject,
01927   LPOLEINPLACEFRAME        lpFrame,
01928   LPOLEINPLACEACTIVEOBJECT lpActiveObject)
01929 {
01930   OleMenuDescriptor *pOleMenuDescriptor = NULL;
01931 
01932   /* Check args */
01933   if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
01934     return E_INVALIDARG;
01935 
01936   if ( lpFrame || lpActiveObject )
01937   {
01938      FIXME("(%p, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",
01939     hOleMenu,
01940     hwndFrame,
01941     hwndActiveObject,
01942     lpFrame,
01943     lpActiveObject);
01944   }
01945 
01946   /* Set up a message hook to intercept the containers frame window messages.
01947    * The message filter is responsible for dispatching menu messages from the
01948    * shared menu which are intended for the object.
01949    */
01950 
01951   if ( hOleMenu )  /* Want to install dispatching code */
01952   {
01953     /* If OLEMenu hooks are already installed for this thread, fail
01954      * Note: This effectively means that OleSetMenuDescriptor cannot
01955      * be called twice in succession on the same frame window
01956      * without first calling it with a null hOleMenu to uninstall */
01957     if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
01958   return E_FAIL;
01959 
01960     /* Get the menu descriptor */
01961     pOleMenuDescriptor = GlobalLock( hOleMenu );
01962     if ( !pOleMenuDescriptor )
01963       return E_UNEXPECTED;
01964 
01965     /* Update the menu descriptor */
01966     pOleMenuDescriptor->hwndFrame = hwndFrame;
01967     pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
01968 
01969     GlobalUnlock( hOleMenu );
01970     pOleMenuDescriptor = NULL;
01971 
01972     /* Add a menu descriptor windows property to the frame window */
01973     SetPropW( hwndFrame, prop_olemenuW, hOleMenu );
01974 
01975     /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
01976     if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
01977       return E_FAIL;
01978   }
01979   else  /* Want to uninstall dispatching code */
01980   {
01981     /* Uninstall the hooks */
01982     if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
01983       return E_FAIL;
01984 
01985     /* Remove the menu descriptor property from the frame window */
01986     RemovePropW( hwndFrame, prop_olemenuW );
01987   }
01988 
01989   return S_OK;
01990 }
01991 
01992 /******************************************************************************
01993  *              IsAccelerator        [OLE32.@]
01994  * Mostly copied from controls/menu.c TranslateAccelerator implementation
01995  */
01996 BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
01997 {
01998     LPACCEL lpAccelTbl;
01999     int i;
02000 
02001     if(!lpMsg) return FALSE;
02002     if (!hAccel)
02003     {
02004     WARN_(accel)("NULL accel handle\n");
02005     return FALSE;
02006     }
02007     if((lpMsg->message != WM_KEYDOWN &&
02008     lpMsg->message != WM_SYSKEYDOWN &&
02009     lpMsg->message != WM_SYSCHAR &&
02010     lpMsg->message != WM_CHAR)) return FALSE;
02011     lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL));
02012     if (NULL == lpAccelTbl)
02013     {
02014     return FALSE;
02015     }
02016     if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries)
02017     {
02018     WARN_(accel)("CopyAcceleratorTableW failed\n");
02019     HeapFree(GetProcessHeap(), 0, lpAccelTbl);
02020     return FALSE;
02021     }
02022 
02023     TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"
02024         "msg->hwnd=%p, msg->message=%04x, wParam=%08lx, lParam=%08lx\n",
02025         hAccel, cAccelEntries,
02026         lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
02027     for(i = 0; i < cAccelEntries; i++)
02028     {
02029     if(lpAccelTbl[i].key != lpMsg->wParam)
02030         continue;
02031 
02032     if(lpMsg->message == WM_CHAR)
02033     {
02034         if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
02035         {
02036         TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", LOWORD(lpMsg->wParam) & 0xff);
02037         goto found;
02038         }
02039     }
02040     else
02041     {
02042         if(lpAccelTbl[i].fVirt & FVIRTKEY)
02043         {
02044         INT mask = 0;
02045         TRACE_(accel)("found accel for virt_key %04lx (scan %04x)\n",
02046                 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
02047         if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
02048         if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
02049         if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
02050         if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
02051         TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
02052         }
02053         else
02054         {
02055         if(!(lpMsg->lParam & 0x01000000))  /* no special_key */
02056         {
02057             if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
02058             {                              /* ^^ ALT pressed */
02059             TRACE_(accel)("found accel for Alt-%c\n", LOWORD(lpMsg->wParam) & 0xff);
02060             goto found;
02061             }
02062         }
02063         }
02064     }
02065     }
02066 
02067     WARN_(accel)("couldn't translate accelerator key\n");
02068     HeapFree(GetProcessHeap(), 0, lpAccelTbl);
02069     return FALSE;
02070 
02071 found:
02072     if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
02073     HeapFree(GetProcessHeap(), 0, lpAccelTbl);
02074     return TRUE;
02075 }
02076 
02077 /***********************************************************************
02078  * ReleaseStgMedium [OLE32.@]
02079  */
02080 void WINAPI ReleaseStgMedium(
02081   STGMEDIUM* pmedium)
02082 {
02083   switch (pmedium->tymed)
02084   {
02085     case TYMED_HGLOBAL:
02086     {
02087       if ( (pmedium->pUnkForRelease==0) &&
02088        (pmedium->u.hGlobal!=0) )
02089     GlobalFree(pmedium->u.hGlobal);
02090       break;
02091     }
02092     case TYMED_FILE:
02093     {
02094       if (pmedium->u.lpszFileName!=0)
02095       {
02096     if (pmedium->pUnkForRelease==0)
02097     {
02098       DeleteFileW(pmedium->u.lpszFileName);
02099     }
02100 
02101     CoTaskMemFree(pmedium->u.lpszFileName);
02102       }
02103       break;
02104     }
02105     case TYMED_ISTREAM:
02106     {
02107       if (pmedium->u.pstm!=0)
02108       {
02109     IStream_Release(pmedium->u.pstm);
02110       }
02111       break;
02112     }
02113     case TYMED_ISTORAGE:
02114     {
02115       if (pmedium->u.pstg!=0)
02116       {
02117     IStorage_Release(pmedium->u.pstg);
02118       }
02119       break;
02120     }
02121     case TYMED_GDI:
02122     {
02123       if ( (pmedium->pUnkForRelease==0) &&
02124        (pmedium->u.hBitmap!=0) )
02125     DeleteObject(pmedium->u.hBitmap);
02126       break;
02127     }
02128     case TYMED_MFPICT:
02129     {
02130       if ( (pmedium->pUnkForRelease==0) &&
02131        (pmedium->u.hMetaFilePict!=0) )
02132       {
02133     LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);
02134     DeleteMetaFile(pMP->hMF);
02135     GlobalUnlock(pmedium->u.hMetaFilePict);
02136     GlobalFree(pmedium->u.hMetaFilePict);
02137       }
02138       break;
02139     }
02140     case TYMED_ENHMF:
02141     {
02142       if ( (pmedium->pUnkForRelease==0) &&
02143        (pmedium->u.hEnhMetaFile!=0) )
02144       {
02145     DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
02146       }
02147       break;
02148     }
02149     case TYMED_NULL:
02150     default:
02151       break;
02152   }
02153   pmedium->tymed=TYMED_NULL;
02154 
02155   /*
02156    * After cleaning up, the unknown is released
02157    */
02158   if (pmedium->pUnkForRelease!=0)
02159   {
02160     IUnknown_Release(pmedium->pUnkForRelease);
02161     pmedium->pUnkForRelease = 0;
02162   }
02163 }
02164 
02165 /***
02166  * OLEDD_Initialize()
02167  *
02168  * Initializes the OLE drag and drop data structures.
02169  */
02170 static void OLEDD_Initialize(void)
02171 {
02172     WNDCLASSW wndClass;
02173 
02174     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
02175     wndClass.style         = CS_GLOBALCLASS;
02176     wndClass.lpfnWndProc   = OLEDD_DragTrackerWindowProc;
02177     wndClass.cbClsExtra    = 0;
02178     wndClass.cbWndExtra    = sizeof(TrackerWindowInfo*);
02179     wndClass.hCursor       = 0;
02180     wndClass.hbrBackground = 0;
02181     wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
02182 
02183     RegisterClassW (&wndClass);
02184 }
02185 
02186 /***
02187  * OLEDD_DragTrackerWindowProc()
02188  *
02189  * This method is the WindowProcedure of the drag n drop tracking
02190  * window. During a drag n Drop operation, an invisible window is created
02191  * to receive the user input and act upon it. This procedure is in charge
02192  * of this behavior.
02193  */
02194 
02195 #define DRAG_TIMER_ID 1
02196 
02197 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
02198              HWND   hwnd,
02199              UINT   uMsg,
02200              WPARAM wParam,
02201              LPARAM   lParam)
02202 {
02203   switch (uMsg)
02204   {
02205     case WM_CREATE:
02206     {
02207       LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
02208 
02209       SetWindowLongPtrW(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams);
02210       SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL);
02211 
02212       break;
02213     }
02214     case WM_TIMER:
02215     case WM_MOUSEMOVE:
02216     {
02217       OLEDD_TrackMouseMove((TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0));
02218       break;
02219     }
02220     case WM_LBUTTONUP:
02221     case WM_MBUTTONUP:
02222     case WM_RBUTTONUP:
02223     case WM_LBUTTONDOWN:
02224     case WM_MBUTTONDOWN:
02225     case WM_RBUTTONDOWN:
02226     {
02227       OLEDD_TrackStateChange((TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0));
02228       break;
02229     }
02230     case WM_DESTROY:
02231     {
02232       KillTimer(hwnd, DRAG_TIMER_ID);
02233       break;
02234     }
02235   }
02236 
02237   /*
02238    * This is a window proc after all. Let's call the default.
02239    */
02240   return DefWindowProcW (hwnd, uMsg, wParam, lParam);
02241 }
02242 
02243 /***
02244  * OLEDD_TrackMouseMove()
02245  *
02246  * This method is invoked while a drag and drop operation is in effect.
02247  * it will generate the appropriate callbacks in the drop source
02248  * and drop target. It will also provide the expected feedback to
02249  * the user.
02250  *
02251  * params:
02252  *    trackerInfo - Pointer to the structure identifying the
02253  *                  drag & drop operation that is currently
02254  *                  active.
02255  */
02256 static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo)
02257 {
02258   HWND   hwndNewTarget = 0;
02259   HRESULT  hr = S_OK;
02260   POINT pt;
02261 
02262   /*
02263    * Get the handle of the window under the mouse
02264    */
02265   pt.x = trackerInfo->curMousePos.x;
02266   pt.y = trackerInfo->curMousePos.y;
02267   hwndNewTarget = WindowFromPoint(pt);
02268 
02269   /*
02270    * Every time, we re-initialize the effects passed to the
02271    * IDropTarget to the effects allowed by the source.
02272    */
02273   *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
02274 
02275   /*
02276    * If we are hovering over the same target as before, send the
02277    * DragOver notification
02278    */
02279   if ( (trackerInfo->curDragTarget != 0) &&
02280        (trackerInfo->curTargetHWND == hwndNewTarget) )
02281   {
02282     IDropTarget_DragOver(trackerInfo->curDragTarget,
02283                          trackerInfo->dwKeyState,
02284                          trackerInfo->curMousePos,
02285              trackerInfo->pdwEffect);
02286   }
02287   else
02288   {
02289     /*
02290      * If we changed window, we have to notify our old target and check for
02291      * the new one.
02292      */
02293     if (trackerInfo->curDragTarget)
02294       IDropTarget_DragLeave(trackerInfo->curDragTarget);
02295 
02296     /*
02297      * Make sure we're hovering over a window.
02298      */
02299     if (hwndNewTarget)
02300     {
02301       /*
02302        * Find-out if there is a drag target under the mouse
02303        */
02304       HWND next_target_wnd = hwndNewTarget;
02305 
02306       trackerInfo->curTargetHWND = hwndNewTarget;
02307 
02308       while (next_target_wnd && !is_droptarget(next_target_wnd))
02309           next_target_wnd = GetParent(next_target_wnd);
02310 
02311       if (next_target_wnd) hwndNewTarget = next_target_wnd;
02312 
02313       trackerInfo->curDragTargetHWND = hwndNewTarget;
02314       if(trackerInfo->curDragTarget) IDropTarget_Release(trackerInfo->curDragTarget);
02315       trackerInfo->curDragTarget     = get_droptarget_pointer(hwndNewTarget);
02316 
02317       /*
02318        * If there is, notify it that we just dragged-in
02319        */
02320       if (trackerInfo->curDragTarget)
02321       {
02322         hr = IDropTarget_DragEnter(trackerInfo->curDragTarget,
02323                                    trackerInfo->dataObject,
02324                                    trackerInfo->dwKeyState,
02325                                    trackerInfo->curMousePos,
02326                                    trackerInfo->pdwEffect);
02327 
02328         /* failed DragEnter() means invalid target */
02329         if (hr != S_OK)
02330         {
02331           trackerInfo->curDragTargetHWND = 0;
02332           trackerInfo->curTargetHWND     = 0;
02333           IDropTarget_Release(trackerInfo->curDragTarget);
02334           trackerInfo->curDragTarget     = 0;
02335         }
02336       }
02337     }
02338     else
02339     {
02340       /*
02341        * The mouse is not over a window so we don't track anything.
02342        */
02343       trackerInfo->curDragTargetHWND = 0;
02344       trackerInfo->curTargetHWND     = 0;
02345       if(trackerInfo->curDragTarget) IDropTarget_Release(trackerInfo->curDragTarget);
02346       trackerInfo->curDragTarget     = 0;
02347     }
02348   }
02349 
02350   /*
02351    * Now that we have done that, we have to tell the source to give
02352    * us feedback on the work being done by the target.  If we don't
02353    * have a target, simulate no effect.
02354    */
02355   if (trackerInfo->curDragTarget==0)
02356   {
02357     *trackerInfo->pdwEffect = DROPEFFECT_NONE;
02358   }
02359 
02360   hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
02361                 *trackerInfo->pdwEffect);
02362 
02363   /*
02364    * When we ask for feedback from the drop source, sometimes it will
02365    * do all the necessary work and sometimes it will not handle it
02366    * when that's the case, we must display the standard drag and drop
02367    * cursors.
02368    */
02369   if (hr == DRAGDROP_S_USEDEFAULTCURSORS)
02370   {
02371     HCURSOR hCur;
02372 
02373     if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE)
02374     {
02375       hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(2));
02376     }
02377     else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY)
02378     {
02379       hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(3));
02380     }
02381     else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK)
02382     {
02383       hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(4));
02384     }
02385     else
02386     {
02387       hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(1));
02388     }
02389 
02390     SetCursor(hCur);
02391   }
02392 }
02393 
02394 /***
02395  * OLEDD_TrackStateChange()
02396  *
02397  * This method is invoked while a drag and drop operation is in effect.
02398  * It is used to notify the drop target/drop source callbacks when
02399  * the state of the keyboard or mouse button change.
02400  *
02401  * params:
02402  *    trackerInfo - Pointer to the structure identifying the
02403  *                  drag & drop operation that is currently
02404  *                  active.
02405  */
02406 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo)
02407 {
02408   /*
02409    * Ask the drop source what to do with the operation.
02410    */
02411   trackerInfo->returnValue = IDropSource_QueryContinueDrag(
02412                    trackerInfo->dropSource,
02413                    trackerInfo->escPressed,
02414                                trackerInfo->dwKeyState);
02415 
02416   /*
02417    * All the return valued will stop the operation except the S_OK
02418    * return value.
02419    */
02420   if (trackerInfo->returnValue!=S_OK)
02421   {
02422     /*
02423      * Make sure the message loop in DoDragDrop stops
02424      */
02425     trackerInfo->trackingDone = TRUE;
02426 
02427     /*
02428      * Release the mouse in case the drop target decides to show a popup
02429      * or a menu or something.
02430      */
02431     ReleaseCapture();
02432 
02433     /*
02434      * If we end-up over a target, drop the object in the target or
02435      * inform the target that the operation was cancelled.
02436      */
02437     if (trackerInfo->curDragTarget)
02438     {
02439       switch (trackerInfo->returnValue)
02440       {
02441     /*
02442      * If the source wants us to complete the operation, we tell
02443      * the drop target that we just dropped the object in it.
02444      */
02445         case DRAGDROP_S_DROP:
02446           if (*trackerInfo->pdwEffect != DROPEFFECT_NONE)
02447             IDropTarget_Drop(trackerInfo->curDragTarget,
02448                              trackerInfo->dataObject,
02449                              trackerInfo->dwKeyState,
02450                              trackerInfo->curMousePos,
02451                              trackerInfo->pdwEffect);
02452           else
02453             IDropTarget_DragLeave(trackerInfo->curDragTarget);
02454           break;
02455 
02456     /*
02457      * If the source told us that we should cancel, fool the drop
02458      * target by telling it that the mouse left it's window.
02459      * Also set the drop effect to "NONE" in case the application
02460      * ignores the result of DoDragDrop.
02461      */
02462         case DRAGDROP_S_CANCEL:
02463       IDropTarget_DragLeave(trackerInfo->curDragTarget);
02464       *trackerInfo->pdwEffect = DROPEFFECT_NONE;
02465       break;
02466       }
02467     }
02468   }
02469 }
02470 
02471 /***
02472  * OLEDD_GetButtonState()
02473  *
02474  * This method will use the current state of the keyboard to build
02475  * a button state mask equivalent to the one passed in the
02476  * WM_MOUSEMOVE wParam.
02477  */
02478 static DWORD OLEDD_GetButtonState(void)
02479 {
02480   BYTE  keyboardState[256];
02481   DWORD keyMask = 0;
02482 
02483   GetKeyboardState(keyboardState);
02484 
02485   if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
02486     keyMask |= MK_SHIFT;
02487 
02488   if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
02489     keyMask |= MK_CONTROL;
02490 
02491   if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
02492     keyMask |= MK_LBUTTON;
02493 
02494   if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
02495     keyMask |= MK_RBUTTON;
02496 
02497   if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
02498     keyMask |= MK_MBUTTON;
02499 
02500   return keyMask;
02501 }
02502 
02503 /***
02504  * OLEDD_GetButtonState()
02505  *
02506  * This method will read the default value of the registry key in
02507  * parameter and extract a DWORD value from it. The registry key value
02508  * can be in a string key or a DWORD key.
02509  *
02510  * params:
02511  *     regKey   - Key to read the default value from
02512  *     pdwValue - Pointer to the location where the DWORD
02513  *                value is returned. This value is not modified
02514  *                if the value is not found.
02515  */
02516 
02517 static void OLEUTL_ReadRegistryDWORDValue(
02518   HKEY   regKey,
02519   DWORD* pdwValue)
02520 {
02521   WCHAR buffer[20];
02522   DWORD cbData = sizeof(buffer);
02523   DWORD dwKeyType;
02524   LONG  lres;
02525 
02526   lres = RegQueryValueExW(regKey,
02527               emptyW,
02528               NULL,
02529               &dwKeyType,
02530               (LPBYTE)buffer,
02531               &cbData);
02532 
02533   if (lres==ERROR_SUCCESS)
02534   {
02535     switch (dwKeyType)
02536     {
02537       case REG_DWORD:
02538     *pdwValue = *(DWORD*)buffer;
02539     break;
02540       case REG_EXPAND_SZ:
02541       case REG_MULTI_SZ:
02542       case REG_SZ:
02543     *pdwValue = (DWORD)strtoulW(buffer, NULL, 10);
02544     break;
02545     }
02546   }
02547 }
02548 
02549 /******************************************************************************
02550  * OleDraw (OLE32.@)
02551  *
02552  * The operation of this function is documented literally in the WinAPI
02553  * documentation to involve a QueryInterface for the IViewObject interface,
02554  * followed by a call to IViewObject::Draw.
02555  */
02556 HRESULT WINAPI OleDraw(
02557     IUnknown *pUnk,
02558     DWORD dwAspect,
02559     HDC hdcDraw,
02560     LPCRECT lprcBounds)
02561 {
02562   HRESULT hres;
02563   IViewObject *viewobject;
02564 
02565   hres = IUnknown_QueryInterface(pUnk,
02566                  &IID_IViewObject,
02567                  (void**)&viewobject);
02568 
02569   if (SUCCEEDED(hres))
02570   {
02571     RECTL rectl;
02572 
02573     rectl.left = lprcBounds->left;
02574     rectl.right = lprcBounds->right;
02575     rectl.top = lprcBounds->top;
02576     rectl.bottom = lprcBounds->bottom;
02577     hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, &rectl, 0, 0, 0);
02578 
02579     IViewObject_Release(viewobject);
02580     return hres;
02581   }
02582   else
02583   {
02584     return DV_E_NOIVIEWOBJECT;
02585   }
02586 }
02587 
02588 /***********************************************************************
02589  *             OleTranslateAccelerator [OLE32.@]
02590  */
02591 HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame,
02592                    LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg)
02593 {
02594     WORD wID;
02595 
02596     TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg);
02597 
02598     if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID))
02599         return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID);
02600 
02601     return S_FALSE;
02602 }
02603 
02604 /******************************************************************************
02605  *              OleCreate        [OLE32.@]
02606  *
02607  */
02608 HRESULT WINAPI OleCreate(
02609     REFCLSID rclsid,
02610     REFIID riid,
02611     DWORD renderopt,
02612     LPFORMATETC pFormatEtc,
02613     LPOLECLIENTSITE pClientSite,
02614     LPSTORAGE pStg,
02615     LPVOID* ppvObj)
02616 {
02617     HRESULT hres;
02618     IUnknown * pUnk = NULL;
02619     IOleObject *pOleObject = NULL;
02620 
02621     TRACE("(%s, %s, %d, %p, %p, %p, %p)\n", debugstr_guid(rclsid),
02622         debugstr_guid(riid), renderopt, pFormatEtc, pClientSite, pStg, ppvObj);
02623 
02624     hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, riid, (LPVOID*)&pUnk);
02625 
02626     if (SUCCEEDED(hres))
02627         hres = IStorage_SetClass(pStg, rclsid);
02628 
02629     if (pClientSite && SUCCEEDED(hres))
02630     {
02631         hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (LPVOID*)&pOleObject);
02632         if (SUCCEEDED(hres))
02633         {
02634             DWORD dwStatus;
02635             hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
02636         }
02637     }
02638 
02639     if (SUCCEEDED(hres))
02640     {
02641         IPersistStorage * pPS;
02642         if (SUCCEEDED((hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (LPVOID*)&pPS))))
02643         {
02644             TRACE("trying to set stg %p\n", pStg);
02645             hres = IPersistStorage_InitNew(pPS, pStg);
02646             TRACE("-- result 0x%08x\n", hres);
02647             IPersistStorage_Release(pPS);
02648         }
02649     }
02650 
02651     if (pClientSite && SUCCEEDED(hres))
02652     {
02653         TRACE("trying to set clientsite %p\n", pClientSite);
02654         hres = IOleObject_SetClientSite(pOleObject, pClientSite);
02655         TRACE("-- result 0x%08x\n", hres);
02656     }
02657 
02658     if (pOleObject)
02659         IOleObject_Release(pOleObject);
02660 
02661     if (((renderopt == OLERENDER_DRAW) || (renderopt == OLERENDER_FORMAT)) &&
02662         SUCCEEDED(hres))
02663     {
02664         IRunnableObject *pRunnable;
02665         IOleCache *pOleCache;
02666         HRESULT hres2;
02667 
02668         hres2 = IUnknown_QueryInterface(pUnk, &IID_IRunnableObject, (void **)&pRunnable);
02669         if (SUCCEEDED(hres2))
02670         {
02671             hres = IRunnableObject_Run(pRunnable, NULL);
02672             IRunnableObject_Release(pRunnable);
02673         }
02674 
02675         if (SUCCEEDED(hres))
02676         {
02677             hres2 = IUnknown_QueryInterface(pUnk, &IID_IOleCache, (void **)&pOleCache);
02678             if (SUCCEEDED(hres2))
02679             {
02680                 DWORD dwConnection;
02681                 if (renderopt == OLERENDER_DRAW && !pFormatEtc) {
02682                     FORMATETC pfe;
02683                     pfe.cfFormat = 0;
02684                     pfe.ptd = NULL;
02685                     pfe.dwAspect = DVASPECT_CONTENT;
02686                     pfe.lindex = -1;
02687                     pfe.tymed = TYMED_NULL;
02688                     hres = IOleCache_Cache(pOleCache, &pfe, ADVF_PRIMEFIRST, &dwConnection);
02689                 }
02690                 else
02691                     hres = IOleCache_Cache(pOleCache, pFormatEtc, ADVF_PRIMEFIRST, &dwConnection);
02692                 IOleCache_Release(pOleCache);
02693             }
02694         }
02695     }
02696 
02697     if (FAILED(hres) && pUnk)
02698     {
02699         IUnknown_Release(pUnk);
02700         pUnk = NULL;
02701     }
02702 
02703     *ppvObj = pUnk;
02704 
02705     TRACE("-- %p\n", pUnk);
02706     return hres;
02707 }
02708 
02709 /******************************************************************************
02710  *              OleGetAutoConvert        [OLE32.@]
02711  */
02712 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
02713 {
02714     static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
02715     HKEY hkey = NULL;
02716     WCHAR buf[CHARS_IN_GUID];
02717     LONG len;
02718     HRESULT res = S_OK;
02719 
02720     res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
02721     if (FAILED(res))
02722         goto done;
02723 
02724     len = sizeof(buf);
02725     if (RegQueryValueW(hkey, NULL, buf, &len))
02726     {
02727         res = REGDB_E_KEYMISSING;
02728         goto done;
02729     }
02730     res = CLSIDFromString(buf, pClsidNew);
02731 done:
02732     if (hkey) RegCloseKey(hkey);
02733     return res;
02734 }
02735 
02736 /******************************************************************************
02737  *              OleSetAutoConvert        [OLE32.@]
02738  */
02739 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
02740 {
02741     static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
02742     HKEY hkey = NULL;
02743     WCHAR szClsidNew[CHARS_IN_GUID];
02744     HRESULT res = S_OK;
02745 
02746     TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
02747     
02748     res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
02749     if (FAILED(res))
02750         goto done;
02751     StringFromGUID2(clsidNew, szClsidNew, CHARS_IN_GUID);
02752     if (RegSetValueW(hkey, wszAutoConvertTo, REG_SZ, szClsidNew, (strlenW(szClsidNew)+1) * sizeof(WCHAR)))
02753     {
02754         res = REGDB_E_WRITEREGDB;
02755     goto done;
02756     }
02757 
02758 done:
02759     if (hkey) RegCloseKey(hkey);
02760     return res;
02761 }
02762 
02763 /******************************************************************************
02764  *              OleDoAutoConvert        [OLE32.@]
02765  */
02766 HRESULT WINAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew)
02767 {
02768     FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
02769     return E_NOTIMPL;
02770 }
02771 
02772 /******************************************************************************
02773  *              OleIsRunning        [OLE32.@]
02774  */
02775 BOOL WINAPI OleIsRunning(LPOLEOBJECT object)
02776 {
02777     IRunnableObject *pRunnable;
02778     HRESULT hr;
02779     BOOL running;
02780 
02781     TRACE("(%p)\n", object);
02782 
02783     if (!object) return FALSE;
02784 
02785     hr = IOleObject_QueryInterface(object, &IID_IRunnableObject, (void **)&pRunnable);
02786     if (FAILED(hr))
02787         return TRUE;
02788     running = IRunnableObject_IsRunning(pRunnable);
02789     IRunnableObject_Release(pRunnable);
02790     return running;
02791 }
02792 
02793 /***********************************************************************
02794  *           OleNoteObjectVisible               [OLE32.@]
02795  */
02796 HRESULT WINAPI OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL bVisible)
02797 {
02798     TRACE("(%p, %s)\n", pUnknown, bVisible ? "TRUE" : "FALSE");
02799     return CoLockObjectExternal(pUnknown, bVisible, TRUE);
02800 }
02801 
02802 
02803 /***********************************************************************
02804  *           OLE_FreeClipDataArray   [internal]
02805  *
02806  * NOTES:
02807  *  frees the data associated with an array of CLIPDATAs
02808  */
02809 static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray)
02810 {
02811     ULONG i;
02812     for (i = 0; i < count; i++)
02813         if (pClipDataArray[i].pClipData)
02814             CoTaskMemFree(pClipDataArray[i].pClipData);
02815 }
02816 
02817 /***********************************************************************
02818  *           PropSysAllocString             [OLE32.@]
02819  * NOTES:
02820  *  Basically a copy of SysAllocStringLen.
02821  */
02822 BSTR WINAPI PropSysAllocString(LPCOLESTR str)
02823 {
02824     DWORD  bufferSize;
02825     DWORD* newBuffer;
02826     WCHAR* stringBuffer;
02827     int len;
02828 
02829     if (!str) return 0;
02830 
02831     len = lstrlenW(str);
02832     /*
02833      * Find the length of the buffer passed-in, in bytes.
02834      */
02835     bufferSize = len * sizeof (WCHAR);
02836 
02837     /*
02838      * Allocate a new buffer to hold the string.
02839      * Don't forget to keep an empty spot at the beginning of the
02840      * buffer for the character count and an extra character at the
02841      * end for the NULL.
02842      */
02843     newBuffer = HeapAlloc(GetProcessHeap(), 0,
02844                           bufferSize + sizeof(WCHAR) + sizeof(DWORD));
02845 
02846     /*
02847      * If the memory allocation failed, return a null pointer.
02848      */
02849     if (newBuffer==0)
02850       return 0;
02851 
02852     /*
02853      * Copy the length of the string in the placeholder.
02854      */
02855     *newBuffer = bufferSize;
02856 
02857     /*
02858      * Skip the byte count.
02859      */
02860     newBuffer++;
02861 
02862     memcpy(newBuffer, str, bufferSize);
02863 
02864     /*
02865      * Make sure that there is a nul character at the end of the
02866      * string.
02867      */
02868     stringBuffer = (WCHAR*)newBuffer;
02869     stringBuffer[len] = '\0';
02870 
02871     return stringBuffer;
02872 }
02873 
02874 /***********************************************************************
02875  *           PropSysFreeString              [OLE32.@]
02876  * NOTES
02877  *  Copy of SysFreeString.
02878  */
02879 void WINAPI PropSysFreeString(LPOLESTR str)
02880 {
02881     DWORD* bufferPointer;
02882 
02883     /* NULL is a valid parameter */
02884     if(!str) return;
02885 
02886     /*
02887      * We have to be careful when we free a BSTR pointer, it points to
02888      * the beginning of the string but it skips the byte count contained
02889      * before the string.
02890      */
02891     bufferPointer = (DWORD*)str;
02892 
02893     bufferPointer--;
02894 
02895     /*
02896      * Free the memory from its "real" origin.
02897      */
02898     HeapFree(GetProcessHeap(), 0, bufferPointer);
02899 }
02900 
02901 /******************************************************************************
02902  * Check if a PROPVARIANT's type is valid.
02903  */
02904 static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt)
02905 {
02906     switch (vt)
02907     {
02908     case VT_EMPTY:
02909     case VT_NULL:
02910     case VT_I2:
02911     case VT_I4:
02912     case VT_R4:
02913     case VT_R8:
02914     case VT_CY:
02915     case VT_DATE:
02916     case VT_BSTR:
02917     case VT_ERROR:
02918     case VT_BOOL:
02919     case VT_DECIMAL:
02920     case VT_UI1:
02921     case VT_UI2:
02922     case VT_UI4:
02923     case VT_I8:
02924     case VT_UI8:
02925     case VT_LPSTR:
02926     case VT_LPWSTR:
02927     case VT_FILETIME:
02928     case VT_BLOB:
02929     case VT_STREAM:
02930     case VT_STORAGE:
02931     case VT_STREAMED_OBJECT:
02932     case VT_STORED_OBJECT:
02933     case VT_BLOB_OBJECT:
02934     case VT_CF:
02935     case VT_CLSID:
02936     case VT_I2|VT_VECTOR:
02937     case VT_I4|VT_VECTOR:
02938     case VT_R4|VT_VECTOR:
02939     case VT_R8|VT_VECTOR:
02940     case VT_CY|VT_VECTOR:
02941     case VT_DATE|VT_VECTOR:
02942     case VT_BSTR|VT_VECTOR:
02943     case VT_ERROR|VT_VECTOR:
02944     case VT_BOOL|VT_VECTOR:
02945     case VT_VARIANT|VT_VECTOR:
02946     case VT_UI1|VT_VECTOR:
02947     case VT_UI2|VT_VECTOR:
02948     case VT_UI4|VT_VECTOR:
02949     case VT_I8|VT_VECTOR:
02950     case VT_UI8|VT_VECTOR:
02951     case VT_LPSTR|VT_VECTOR:
02952     case VT_LPWSTR|VT_VECTOR:
02953     case VT_FILETIME|VT_VECTOR:
02954     case VT_CF|VT_VECTOR:
02955     case VT_CLSID|VT_VECTOR:
02956         return S_OK;
02957     }
02958     WARN("Bad type %d\n", vt);
02959     return STG_E_INVALIDPARAMETER;
02960 }
02961 
02962 /***********************************************************************
02963  *           PropVariantClear               [OLE32.@]
02964  */
02965 HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */
02966 {
02967     HRESULT hr;
02968 
02969     TRACE("(%p)\n", pvar);
02970 
02971     if (!pvar)
02972         return S_OK;
02973 
02974     hr = PROPVARIANT_ValidateType(pvar->vt);
02975     if (FAILED(hr))
02976         return hr;
02977 
02978     switch(pvar->vt)
02979     {
02980     case VT_EMPTY:
02981     case VT_NULL:
02982     case VT_I2:
02983     case VT_I4:
02984     case VT_R4:
02985     case VT_R8:
02986     case VT_CY:
02987     case VT_DATE:
02988     case VT_ERROR:
02989     case VT_BOOL:
02990     case VT_DECIMAL:
02991     case VT_UI1:
02992     case VT_UI2:
02993     case VT_UI4:
02994     case VT_I8:
02995     case VT_UI8:
02996     case VT_FILETIME:
02997         break;
02998     case VT_STREAM:
02999     case VT_STREAMED_OBJECT:
03000     case VT_STORAGE:
03001     case VT_STORED_OBJECT:
03002         if (pvar->u.pStream)
03003             IUnknown_Release(pvar->u.pStream);
03004         break;
03005     case VT_CLSID:
03006     case VT_LPSTR:
03007     case VT_LPWSTR:
03008         /* pick an arbitrary typed pointer - we don't care about the type
03009          * as we are just freeing it */
03010         CoTaskMemFree(pvar->u.puuid);
03011         break;
03012     case VT_BLOB:
03013     case VT_BLOB_OBJECT:
03014         CoTaskMemFree(pvar->u.blob.pBlobData);
03015         break;
03016     case VT_BSTR:
03017         if (pvar->u.bstrVal)
03018             PropSysFreeString(pvar->u.bstrVal);
03019         break;
03020     case VT_CF:
03021         if (pvar->u.pclipdata)
03022         {
03023             OLE_FreeClipDataArray(1, pvar->u.pclipdata);
03024             CoTaskMemFree(pvar->u.pclipdata);
03025         }
03026         break;
03027     default:
03028         if (pvar->vt & VT_VECTOR)
03029         {
03030             ULONG i;
03031 
03032             switch (pvar->vt & ~VT_VECTOR)
03033             {
03034             case VT_VARIANT:
03035                 FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems);
03036                 break;
03037             case VT_CF:
03038                 OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems);
03039                 break;
03040             case VT_BSTR:
03041                 for (i = 0; i < pvar->u.cabstr.cElems; i++)
03042                     PropSysFreeString(pvar->u.cabstr.pElems[i]);
03043                 break;
03044             case VT_LPSTR:
03045                 for (i = 0; i < pvar->u.calpstr.cElems; i++)
03046                     CoTaskMemFree(pvar->u.calpstr.pElems[i]);
03047                 break;
03048             case VT_LPWSTR:
03049                 for (i = 0; i < pvar->u.calpwstr.cElems; i++)
03050                     CoTaskMemFree(pvar->u.calpwstr.pElems[i]);
03051                 break;
03052             }
03053             if (pvar->vt & ~VT_VECTOR)
03054             {
03055                 /* pick an arbitrary VT_VECTOR structure - they all have the same
03056                  * memory layout */
03057                 CoTaskMemFree(pvar->u.capropvar.pElems);
03058             }
03059         }
03060         else
03061             WARN("Invalid/unsupported type %d\n", pvar->vt);
03062     }
03063 
03064     ZeroMemory(pvar, sizeof(*pvar));
03065 
03066     return S_OK;
03067 }
03068 
03069 /***********************************************************************
03070  *           PropVariantCopy                [OLE32.@]
03071  */
03072 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest,      /* [out] */
03073                                const PROPVARIANT *pvarSrc) /* [in] */
03074 {
03075     ULONG len;
03076     HRESULT hr;
03077 
03078     TRACE("(%p, %p vt %04x)\n", pvarDest, pvarSrc, pvarSrc->vt);
03079 
03080     hr = PROPVARIANT_ValidateType(pvarSrc->vt);
03081     if (FAILED(hr))
03082         return hr;
03083 
03084     /* this will deal with most cases */
03085     *pvarDest = *pvarSrc;
03086 
03087     switch(pvarSrc->vt)
03088     {
03089     case VT_EMPTY:
03090     case VT_NULL:
03091     case VT_I1:
03092     case VT_UI1:
03093     case VT_I2:
03094     case VT_UI2:
03095     case VT_BOOL:
03096     case VT_DECIMAL:
03097     case VT_I4:
03098     case VT_UI4:
03099     case VT_R4:
03100     case VT_ERROR:
03101     case VT_I8:
03102     case VT_UI8:
03103     case VT_R8:
03104     case VT_CY:
03105     case VT_DATE:
03106     case VT_FILETIME:
03107         break;
03108     case VT_STREAM:
03109     case VT_STREAMED_OBJECT:
03110     case VT_STORAGE:
03111     case VT_STORED_OBJECT:
03112         IUnknown_AddRef((LPUNKNOWN)pvarDest->u.pStream);
03113         break;
03114     case VT_CLSID:
03115         pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));
03116         *pvarDest->u.puuid = *pvarSrc->u.puuid;
03117         break;
03118     case VT_LPSTR:
03119         len = strlen(pvarSrc->u.pszVal);
03120         pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
03121         CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR));
03122         break;
03123     case VT_LPWSTR:
03124         len = lstrlenW(pvarSrc->u.pwszVal);
03125         pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
03126         CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR));
03127         break;
03128     case VT_BLOB:
03129     case VT_BLOB_OBJECT:
03130         if (pvarSrc->u.blob.pBlobData)
03131         {
03132             len = pvarSrc->u.blob.cbSize;
03133             pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len);
03134             CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len);
03135         }
03136         break;
03137     case VT_BSTR:
03138         pvarDest->u.bstrVal = PropSysAllocString(pvarSrc->u.bstrVal);
03139         break;
03140     case VT_CF:
03141         if (pvarSrc->u.pclipdata)
03142         {
03143             len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt);
03144             pvarDest->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
03145             pvarDest->u.pclipdata->cbSize = pvarSrc->u.pclipdata->cbSize;
03146             pvarDest->u.pclipdata->ulClipFmt = pvarSrc->u.pclipdata->ulClipFmt;
03147             pvarDest->u.pclipdata->pClipData = CoTaskMemAlloc(len);
03148             CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len);
03149         }
03150         break;
03151     default:
03152         if (pvarSrc->vt & VT_VECTOR)
03153         {
03154             int elemSize;
03155             ULONG i;
03156 
03157             switch(pvarSrc->vt & ~VT_VECTOR)
03158             {
03159             case VT_I1:       elemSize = sizeof(pvarSrc->u.cVal); break;
03160             case VT_UI1:      elemSize = sizeof(pvarSrc->u.bVal); break;
03161             case VT_I2:       elemSize = sizeof(pvarSrc->u.iVal); break;
03162             case VT_UI2:      elemSize = sizeof(pvarSrc->u.uiVal); break;
03163             case VT_BOOL:     elemSize = sizeof(pvarSrc->u.boolVal); break;
03164             case VT_I4:       elemSize = sizeof(pvarSrc->u.lVal); break;
03165             case VT_UI4:      elemSize = sizeof(pvarSrc->u.ulVal); break;
03166             case VT_R4:       elemSize = sizeof(pvarSrc->u.fltVal); break;
03167             case VT_R8:       elemSize = sizeof(pvarSrc->u.dblVal); break;
03168             case VT_ERROR:    elemSize = sizeof(pvarSrc->u.scode); break;
03169             case VT_I8:       elemSize = sizeof(pvarSrc->u.hVal); break;
03170             case VT_UI8:      elemSize = sizeof(pvarSrc->u.uhVal); break;
03171             case VT_CY:       elemSize = sizeof(pvarSrc->u.cyVal); break;
03172             case VT_DATE:     elemSize = sizeof(pvarSrc->u.date); break;
03173             case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break;
03174             case VT_CLSID:    elemSize = sizeof(*pvarSrc->u.puuid); break;
03175             case VT_CF:       elemSize = sizeof(*pvarSrc->u.pclipdata); break;
03176             case VT_BSTR:     elemSize = sizeof(pvarSrc->u.bstrVal); break;
03177             case VT_LPSTR:    elemSize = sizeof(pvarSrc->u.pszVal); break;
03178             case VT_LPWSTR:   elemSize = sizeof(pvarSrc->u.pwszVal); break;
03179             case VT_VARIANT:  elemSize = sizeof(*pvarSrc->u.pvarVal); break;
03180 
03181             default:
03182                 FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
03183                 return E_INVALIDARG;
03184             }
03185             len = pvarSrc->u.capropvar.cElems;
03186             pvarDest->u.capropvar.pElems = CoTaskMemAlloc(len * elemSize);
03187             if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
03188             {
03189                 for (i = 0; i < len; i++)
03190                     PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]);
03191             }
03192             else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
03193             {
03194                 FIXME("Copy clipformats\n");
03195             }
03196             else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
03197             {
03198                 for (i = 0; i < len; i++)
03199                     pvarDest->u.cabstr.pElems[i] = PropSysAllocString(pvarSrc->u.cabstr.pElems[i]);
03200             }
03201             else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
03202             {
03203                 size_t strLen;
03204                 for (i = 0; i < len; i++)
03205                 {
03206                     strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1;
03207                     pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
03208                     memcpy(pvarDest->u.calpstr.pElems[i],
03209                      pvarSrc->u.calpstr.pElems[i], strLen);
03210                 }
03211             }
03212             else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
03213             {
03214                 size_t strLen;
03215                 for (i = 0; i < len; i++)
03216                 {
03217                     strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) *
03218                      sizeof(WCHAR);
03219                     pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
03220                     memcpy(pvarDest->u.calpstr.pElems[i],
03221                      pvarSrc->u.calpstr.pElems[i], strLen);
03222                 }
03223             }
03224             else
03225                 CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize);
03226         }
03227         else
03228             WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
03229     }
03230 
03231     return S_OK;
03232 }
03233 
03234 /***********************************************************************
03235  *           FreePropVariantArray               [OLE32.@]
03236  */
03237 HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */
03238                                     PROPVARIANT *rgvars)    /* [in/out] */
03239 {
03240     ULONG i;
03241 
03242     TRACE("(%u, %p)\n", cVariants, rgvars);
03243 
03244     if (!rgvars)
03245         return E_INVALIDARG;
03246 
03247     for(i = 0; i < cVariants; i++)
03248         PropVariantClear(&rgvars[i]);
03249 
03250     return S_OK;
03251 }
03252 
03253 /******************************************************************************
03254  * DllDebugObjectRPCHook (OLE32.@)
03255  * turns on and off internal debugging,  pointer is only used on macintosh
03256  */
03257 
03258 BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)
03259 {
03260   FIXME("stub\n");
03261   return TRUE;
03262 }

Generated on Sun May 27 2012 04:25:39 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.