4275b835b47ac496ca80ef551569ec63f8c095d4
[reactos.git] / dll / win32 / ole32 / ole2.c
1 /*
2 * OLE2 library
3 *
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1999 Francis Beaudet
6 * Copyright 1999 Noel Borthwick
7 * Copyright 1999, 2000 Marcus Meissner
8 * Copyright 2005 Juan Lang
9 * Copyright 2011 Adam Martinson for CodeWeavers
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26 #include "precomp.h"
27
28 #include "olestd.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(ole);
31 WINE_DECLARE_DEBUG_CHANNEL(accel);
32
33 /******************************************************************************
34 * These are static/global variables and internal data structures that the
35 * OLE module uses to maintain its state.
36 */
37 typedef struct tagTrackerWindowInfo
38 {
39 IDataObject* dataObject;
40 IDropSource* dropSource;
41 DWORD dwOKEffect;
42 DWORD* pdwEffect;
43 BOOL trackingDone;
44 HRESULT returnValue;
45
46 BOOL escPressed;
47 HWND curTargetHWND; /* window the mouse is hovering over */
48 IDropTarget* curDragTarget;
49 POINTL curMousePos; /* current position of the mouse in screen coordinates */
50 DWORD dwKeyState; /* current state of the shift and ctrl keys and the mouse buttons */
51 } TrackerWindowInfo;
52
53 typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */
54 {
55 HWND hwndFrame; /* The containers frame window */
56 HWND hwndActiveObject; /* The active objects window */
57 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */
58 HMENU hmenuCombined; /* The combined menu */
59 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */
60 } OleMenuDescriptor;
61
62 typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */
63 {
64 DWORD tid; /* Thread Id */
65 HANDLE hHeap; /* Heap this is allocated from */
66 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */
67 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */
68 struct tagOleMenuHookItem *next;
69 } OleMenuHookItem;
70
71 static OleMenuHookItem *hook_list;
72
73 /*
74 * This is the lock count on the OLE library. It is controlled by the
75 * OLEInitialize/OLEUninitialize methods.
76 */
77 static LONG OLE_moduleLockCount = 0;
78
79 /*
80 * Name of our registered window class.
81 */
82 static const WCHAR OLEDD_DRAGTRACKERCLASS[] =
83 {'W','i','n','e','D','r','a','g','D','r','o','p','T','r','a','c','k','e','r','3','2',0};
84
85 /*
86 * Name of menu descriptor property.
87 */
88 static const WCHAR prop_olemenuW[] =
89 {'P','R','O','P','_','O','L','E','M','e','n','u','D','e','s','c','r','i','p','t','o','r',0};
90
91 /* property to store IDropTarget pointer */
92 static const WCHAR prop_oledroptarget[] =
93 {'O','l','e','D','r','o','p','T','a','r','g','e','t','I','n','t','e','r','f','a','c','e',0};
94
95 /* property to store Marshalled IDropTarget pointer */
96 static const WCHAR prop_marshalleddroptarget[] =
97 {'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};
98
99 static const WCHAR emptyW[] = { 0 };
100
101 /******************************************************************************
102 * These are the prototypes of miscellaneous utility methods
103 */
104 static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
105
106 /******************************************************************************
107 * These are the prototypes of the utility methods used to manage a shared menu
108 */
109 static void OLEMenu_Initialize(void);
110 static void OLEMenu_UnInitialize(void);
111 static BOOL OLEMenu_InstallHooks( DWORD tid );
112 static BOOL OLEMenu_UnInstallHooks( DWORD tid );
113 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
114 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
115 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
116 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
117 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
118
119 /******************************************************************************
120 * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
121 */
122 extern void OLEClipbrd_UnInitialize(void);
123 extern void OLEClipbrd_Initialize(void);
124
125 /******************************************************************************
126 * These are the prototypes of the utility methods used for OLE Drag n Drop
127 */
128 static void OLEDD_Initialize(void);
129 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
130 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo);
131 static DWORD OLEDD_GetButtonState(void);
132
133 /******************************************************************************
134 * OleBuildVersion [OLE32.@]
135 */
136 DWORD WINAPI OleBuildVersion(void)
137 {
138 TRACE("Returning version %d, build %d.\n", rmm, rup);
139 return (rmm<<16)+rup;
140 }
141
142 /***********************************************************************
143 * OleInitialize (OLE32.@)
144 */
145 HRESULT WINAPI DECLSPEC_HOTPATCH OleInitialize(LPVOID reserved)
146 {
147 HRESULT hr;
148
149 TRACE("(%p)\n", reserved);
150
151 /*
152 * The first duty of the OleInitialize is to initialize the COM libraries.
153 */
154 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
155
156 /*
157 * If the CoInitializeEx call failed, the OLE libraries can't be
158 * initialized.
159 */
160 if (FAILED(hr))
161 return hr;
162
163 if (!COM_CurrentInfo()->ole_inits)
164 hr = S_OK;
165 else
166 hr = S_FALSE;
167
168 /*
169 * Then, it has to initialize the OLE specific modules.
170 * This includes:
171 * Clipboard
172 * Drag and Drop
173 * Object linking and Embedding
174 * In-place activation
175 */
176 if (!COM_CurrentInfo()->ole_inits++ &&
177 InterlockedIncrement(&OLE_moduleLockCount) == 1)
178 {
179 /*
180 * Initialize the libraries.
181 */
182 TRACE("() - Initializing the OLE libraries\n");
183
184 /*
185 * OLE Clipboard
186 */
187 OLEClipbrd_Initialize();
188
189 /*
190 * Drag and Drop
191 */
192 OLEDD_Initialize();
193
194 /*
195 * OLE shared menu
196 */
197 OLEMenu_Initialize();
198 }
199
200 return hr;
201 }
202
203 /******************************************************************************
204 * OleUninitialize [OLE32.@]
205 */
206 void WINAPI DECLSPEC_HOTPATCH OleUninitialize(void)
207 {
208 TRACE("()\n");
209
210 if (COM_CurrentInfo()->ole_inits == 0)
211 {
212 WARN("ole_inits is already 0\n");
213 return ;
214 }
215 /*
216 * If we hit the bottom of the lock stack, free the libraries.
217 */
218 if (!--COM_CurrentInfo()->ole_inits && !InterlockedDecrement(&OLE_moduleLockCount))
219 {
220 /*
221 * Actually free the libraries.
222 */
223 TRACE("() - Freeing the last reference count\n");
224
225 /*
226 * OLE Clipboard
227 */
228 OLEClipbrd_UnInitialize();
229
230 /*
231 * OLE shared menu
232 */
233 OLEMenu_UnInitialize();
234 }
235
236 /*
237 * Then, uninitialize the COM libraries.
238 */
239 CoUninitialize();
240 }
241
242 /******************************************************************************
243 * OleInitializeWOW [OLE32.@]
244 */
245 HRESULT WINAPI OleInitializeWOW(DWORD x, DWORD y) {
246 FIXME("(0x%08x, 0x%08x),stub!\n",x, y);
247 return 0;
248 }
249
250 /*************************************************************
251 * get_droptarget_handle
252 *
253 * Retrieve a handle to the map containing the marshalled IDropTarget.
254 * This handle belongs to the process that called RegisterDragDrop.
255 * See get_droptarget_local_handle().
256 */
257 static inline HANDLE get_droptarget_handle(HWND hwnd)
258 {
259 return GetPropW(hwnd, prop_marshalleddroptarget);
260 }
261
262 /*************************************************************
263 * is_droptarget
264 *
265 * Is the window a droptarget.
266 */
267 static inline BOOL is_droptarget(HWND hwnd)
268 {
269 return get_droptarget_handle(hwnd) != 0;
270 }
271
272 /*************************************************************
273 * get_droptarget_local_handle
274 *
275 * Retrieve a handle to the map containing the marshalled IDropTarget.
276 * The handle should be closed when finished with.
277 */
278 static HANDLE get_droptarget_local_handle(HWND hwnd)
279 {
280 HANDLE handle, local_handle = 0;
281
282 handle = get_droptarget_handle(hwnd);
283
284 if(handle)
285 {
286 DWORD pid;
287 HANDLE process;
288
289 GetWindowThreadProcessId(hwnd, &pid);
290 process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
291 if(process)
292 {
293 DuplicateHandle(process, handle, GetCurrentProcess(), &local_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
294 CloseHandle(process);
295 }
296 }
297 return local_handle;
298 }
299
300 /***********************************************************************
301 * create_map_from_stream
302 *
303 * Helper for RegisterDragDrop. Creates a file mapping object
304 * with the contents of the provided stream. The stream must
305 * be a global memory backed stream.
306 */
307 static HRESULT create_map_from_stream(IStream *stream, HANDLE *map)
308 {
309 HGLOBAL hmem;
310 DWORD size;
311 HRESULT hr;
312 void *data;
313
314 hr = GetHGlobalFromStream(stream, &hmem);
315 if(FAILED(hr)) return hr;
316
317 size = GlobalSize(hmem);
318 *map = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL);
319 if(!*map) return E_OUTOFMEMORY;
320
321 data = MapViewOfFile(*map, FILE_MAP_WRITE, 0, 0, size);
322 memcpy(data, GlobalLock(hmem), size);
323 GlobalUnlock(hmem);
324 UnmapViewOfFile(data);
325 return S_OK;
326 }
327
328 /***********************************************************************
329 * create_stream_from_map
330 *
331 * Creates a stream from the provided map.
332 */
333 static HRESULT create_stream_from_map(HANDLE map, IStream **stream)
334 {
335 HRESULT hr = E_OUTOFMEMORY;
336 HGLOBAL hmem;
337 void *data;
338 MEMORY_BASIC_INFORMATION info;
339
340 data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
341 if(!data) return hr;
342
343 VirtualQuery(data, &info, sizeof(info));
344 TRACE("size %d\n", (int)info.RegionSize);
345
346 hmem = GlobalAlloc(GMEM_MOVEABLE, info.RegionSize);
347 if(hmem)
348 {
349 memcpy(GlobalLock(hmem), data, info.RegionSize);
350 GlobalUnlock(hmem);
351 hr = CreateStreamOnHGlobal(hmem, TRUE, stream);
352 }
353 UnmapViewOfFile(data);
354 return hr;
355 }
356
357 /* This is to work around apps which break COM rules by not implementing
358 * IDropTarget::QueryInterface(). Windows doesn't expose this because it
359 * doesn't call CoMarshallInterface() in RegisterDragDrop().
360 * The wrapper is only used internally, and only exists for the life of
361 * the marshal. We don't want to hold a ref on the app provided target
362 * as some apps destroy this prior to CoUninitialize without calling
363 * RevokeDragDrop. The only (long-term) ref is held by the window prop. */
364 typedef struct {
365 IDropTarget IDropTarget_iface;
366 HWND hwnd;
367 LONG refs;
368 } DropTargetWrapper;
369
370 static inline DropTargetWrapper* impl_from_IDropTarget(IDropTarget* iface)
371 {
372 return CONTAINING_RECORD(iface, DropTargetWrapper, IDropTarget_iface);
373 }
374
375 static HRESULT WINAPI DropTargetWrapper_QueryInterface(IDropTarget* iface,
376 REFIID riid,
377 void** ppvObject)
378 {
379 DropTargetWrapper* This = impl_from_IDropTarget(iface);
380 if (IsEqualIID(riid, &IID_IUnknown) ||
381 IsEqualIID(riid, &IID_IDropTarget))
382 {
383 IDropTarget_AddRef(&This->IDropTarget_iface);
384 *ppvObject = &This->IDropTarget_iface;
385 return S_OK;
386 }
387 *ppvObject = NULL;
388 return E_NOINTERFACE;
389 }
390
391 static ULONG WINAPI DropTargetWrapper_AddRef(IDropTarget* iface)
392 {
393 DropTargetWrapper* This = impl_from_IDropTarget(iface);
394 return InterlockedIncrement(&This->refs);
395 }
396
397 static ULONG WINAPI DropTargetWrapper_Release(IDropTarget* iface)
398 {
399 DropTargetWrapper* This = impl_from_IDropTarget(iface);
400 ULONG refs = InterlockedDecrement(&This->refs);
401 if (!refs) HeapFree(GetProcessHeap(), 0, This);
402 return refs;
403 }
404
405 static inline HRESULT get_target_from_wrapper( IDropTarget *wrapper, IDropTarget **target )
406 {
407 DropTargetWrapper* This = impl_from_IDropTarget( wrapper );
408 *target = GetPropW( This->hwnd, prop_oledroptarget );
409 if (!*target) return DRAGDROP_E_NOTREGISTERED;
410 IDropTarget_AddRef( *target );
411 return S_OK;
412 }
413
414 static HRESULT WINAPI DropTargetWrapper_DragEnter(IDropTarget* iface,
415 IDataObject* pDataObj,
416 DWORD grfKeyState,
417 POINTL pt,
418 DWORD* pdwEffect)
419 {
420 IDropTarget *target;
421 HRESULT r = get_target_from_wrapper( iface, &target );
422
423 if (SUCCEEDED( r ))
424 {
425 r = IDropTarget_DragEnter( target, pDataObj, grfKeyState, pt, pdwEffect );
426 IDropTarget_Release( target );
427 }
428 return r;
429 }
430
431 static HRESULT WINAPI DropTargetWrapper_DragOver(IDropTarget* iface,
432 DWORD grfKeyState,
433 POINTL pt,
434 DWORD* pdwEffect)
435 {
436 IDropTarget *target;
437 HRESULT r = get_target_from_wrapper( iface, &target );
438
439 if (SUCCEEDED( r ))
440 {
441 r = IDropTarget_DragOver( target, grfKeyState, pt, pdwEffect );
442 IDropTarget_Release( target );
443 }
444 return r;
445 }
446
447 static HRESULT WINAPI DropTargetWrapper_DragLeave(IDropTarget* iface)
448 {
449 IDropTarget *target;
450 HRESULT r = get_target_from_wrapper( iface, &target );
451
452 if (SUCCEEDED( r ))
453 {
454 r = IDropTarget_DragLeave( target );
455 IDropTarget_Release( target );
456 }
457 return r;
458 }
459
460 static HRESULT WINAPI DropTargetWrapper_Drop(IDropTarget* iface,
461 IDataObject* pDataObj,
462 DWORD grfKeyState,
463 POINTL pt,
464 DWORD* pdwEffect)
465 {
466 IDropTarget *target;
467 HRESULT r = get_target_from_wrapper( iface, &target );
468
469 if (SUCCEEDED( r ))
470 {
471 r = IDropTarget_Drop( target, pDataObj, grfKeyState, pt, pdwEffect );
472 IDropTarget_Release( target );
473 }
474 return r;
475 }
476
477 static const IDropTargetVtbl DropTargetWrapperVTbl =
478 {
479 DropTargetWrapper_QueryInterface,
480 DropTargetWrapper_AddRef,
481 DropTargetWrapper_Release,
482 DropTargetWrapper_DragEnter,
483 DropTargetWrapper_DragOver,
484 DropTargetWrapper_DragLeave,
485 DropTargetWrapper_Drop
486 };
487
488 static IDropTarget* WrapDropTarget( HWND hwnd )
489 {
490 DropTargetWrapper* This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
491
492 if (This)
493 {
494 This->IDropTarget_iface.lpVtbl = &DropTargetWrapperVTbl;
495 This->hwnd = hwnd;
496 This->refs = 1;
497 }
498 return &This->IDropTarget_iface;
499 }
500
501 /***********************************************************************
502 * get_droptarget_pointer
503 *
504 * Retrieves the marshalled IDropTarget from the window.
505 */
506 static IDropTarget* get_droptarget_pointer(HWND hwnd)
507 {
508 IDropTarget *droptarget = NULL;
509 HANDLE map;
510 IStream *stream;
511
512 map = get_droptarget_local_handle(hwnd);
513 if(!map) return NULL;
514
515 if(SUCCEEDED(create_stream_from_map(map, &stream)))
516 {
517 CoUnmarshalInterface(stream, &IID_IDropTarget, (void**)&droptarget);
518 IStream_Release(stream);
519 }
520 CloseHandle(map);
521 return droptarget;
522 }
523
524 /***********************************************************************
525 * RegisterDragDrop (OLE32.@)
526 */
527 HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
528 {
529 DWORD pid = 0;
530 HRESULT hr;
531 IStream *stream;
532 HANDLE map;
533 IDropTarget *wrapper;
534
535 TRACE("(%p,%p)\n", hwnd, pDropTarget);
536
537 if (!COM_CurrentApt())
538 {
539 ERR("COM not initialized\n");
540 return E_OUTOFMEMORY;
541 }
542
543 if (!pDropTarget)
544 return E_INVALIDARG;
545
546 if (!IsWindow(hwnd))
547 {
548 ERR("invalid hwnd %p\n", hwnd);
549 return DRAGDROP_E_INVALIDHWND;
550 }
551
552 /* block register for other processes windows */
553 GetWindowThreadProcessId(hwnd, &pid);
554 if (pid != GetCurrentProcessId())
555 {
556 FIXME("register for another process windows is disabled\n");
557 return DRAGDROP_E_INVALIDHWND;
558 }
559
560 /* check if the window is already registered */
561 if (is_droptarget(hwnd))
562 return DRAGDROP_E_ALREADYREGISTERED;
563
564 /*
565 * Marshal the drop target pointer into a shared memory map and
566 * store the map's handle in a Wine specific window prop. We also
567 * store the drop target pointer itself in the
568 * "OleDropTargetInterface" prop for compatibility with Windows.
569 */
570
571 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
572 if(FAILED(hr)) return hr;
573
574 /* IDropTarget::QueryInterface() shouldn't be called, some (broken) apps depend on this. */
575 wrapper = WrapDropTarget( hwnd );
576 if(!wrapper)
577 {
578 IStream_Release(stream);
579 return E_OUTOFMEMORY;
580 }
581 hr = CoMarshalInterface(stream, &IID_IDropTarget, (IUnknown*)wrapper, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
582 IDropTarget_Release(wrapper);
583
584 if(SUCCEEDED(hr))
585 {
586 hr = create_map_from_stream(stream, &map);
587 if(SUCCEEDED(hr))
588 {
589 IDropTarget_AddRef(pDropTarget);
590 SetPropW(hwnd, prop_oledroptarget, pDropTarget);
591 SetPropW(hwnd, prop_marshalleddroptarget, map);
592 }
593 else
594 {
595 LARGE_INTEGER zero;
596 zero.QuadPart = 0;
597 IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
598 CoReleaseMarshalData(stream);
599 }
600 }
601 IStream_Release(stream);
602
603 return hr;
604 }
605
606 /***********************************************************************
607 * RevokeDragDrop (OLE32.@)
608 */
609 HRESULT WINAPI RevokeDragDrop(HWND hwnd)
610 {
611 HANDLE map;
612 IStream *stream;
613 IDropTarget *drop_target;
614 HRESULT hr;
615
616 TRACE("(%p)\n", hwnd);
617
618 if (!IsWindow(hwnd))
619 {
620 ERR("invalid hwnd %p\n", hwnd);
621 return DRAGDROP_E_INVALIDHWND;
622 }
623
624 /* no registration data */
625 if (!(map = get_droptarget_handle(hwnd)))
626 return DRAGDROP_E_NOTREGISTERED;
627
628 drop_target = GetPropW(hwnd, prop_oledroptarget);
629 if(drop_target) IDropTarget_Release(drop_target);
630
631 RemovePropW(hwnd, prop_oledroptarget);
632 RemovePropW(hwnd, prop_marshalleddroptarget);
633
634 hr = create_stream_from_map(map, &stream);
635 if(SUCCEEDED(hr))
636 {
637 CoReleaseMarshalData(stream);
638 IStream_Release(stream);
639 }
640 CloseHandle(map);
641
642 return hr;
643 }
644
645 /***********************************************************************
646 * OleRegGetUserType (OLE32.@)
647 */
648 HRESULT WINAPI OleRegGetUserType(REFCLSID clsid, DWORD form, LPOLESTR *usertype)
649 {
650 static const WCHAR auxusertypeW[] = {'A','u','x','U','s','e','r','T','y','p','e','\\','%','d',0};
651 DWORD valuetype, valuelen;
652 WCHAR auxkeynameW[16];
653 HKEY usertypekey;
654 HRESULT hres;
655 LONG ret;
656
657 TRACE("(%s, %u, %p)\n", debugstr_guid(clsid), form, usertype);
658
659 if (!usertype)
660 return E_INVALIDARG;
661
662 *usertype = NULL;
663
664 /* Return immediately if it's not registered. */
665 hres = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &usertypekey);
666 if (FAILED(hres))
667 return hres;
668
669 valuelen = 0;
670
671 /* Try additional types if requested. If they don't exist fall back to USERCLASSTYPE_FULL. */
672 if (form != USERCLASSTYPE_FULL)
673 {
674 HKEY auxkey;
675
676 sprintfW(auxkeynameW, auxusertypeW, form);
677 if (COM_OpenKeyForCLSID(clsid, auxkeynameW, KEY_READ, &auxkey) == S_OK)
678 {
679 if (!RegQueryValueExW(auxkey, emptyW, NULL, &valuetype, NULL, &valuelen) && valuelen)
680 {
681 RegCloseKey(usertypekey);
682 usertypekey = auxkey;
683 }
684 else
685 RegCloseKey(auxkey);
686 }
687 }
688
689 valuelen = 0;
690 if (RegQueryValueExW(usertypekey, emptyW, NULL, &valuetype, NULL, &valuelen))
691 {
692 RegCloseKey(usertypekey);
693 return REGDB_E_READREGDB;
694 }
695
696 *usertype = CoTaskMemAlloc(valuelen);
697 if (!*usertype)
698 {
699 RegCloseKey(usertypekey);
700 return E_OUTOFMEMORY;
701 }
702
703 ret = RegQueryValueExW(usertypekey,
704 emptyW,
705 NULL,
706 &valuetype,
707 (LPBYTE)*usertype,
708 &valuelen);
709 RegCloseKey(usertypekey);
710 if (ret != ERROR_SUCCESS)
711 {
712 CoTaskMemFree(*usertype);
713 *usertype = NULL;
714 return REGDB_E_READREGDB;
715 }
716
717 return S_OK;
718 }
719
720 /***********************************************************************
721 * DoDragDrop [OLE32.@]
722 */
723 HRESULT WINAPI DoDragDrop (
724 IDataObject *pDataObject, /* [in] ptr to the data obj */
725 IDropSource* pDropSource, /* [in] ptr to the source obj */
726 DWORD dwOKEffect, /* [in] effects allowed by the source */
727 DWORD *pdwEffect) /* [out] ptr to effects of the source */
728 {
729 static const WCHAR trackerW[] = {'T','r','a','c','k','e','r','W','i','n','d','o','w',0};
730 TrackerWindowInfo trackerInfo;
731 HWND hwndTrackWindow;
732 MSG msg;
733
734 TRACE("(%p, %p, %08x, %p)\n", pDataObject, pDropSource, dwOKEffect, pdwEffect);
735
736 if (!pDataObject || !pDropSource || !pdwEffect)
737 return E_INVALIDARG;
738
739 /*
740 * Setup the drag n drop tracking window.
741 */
742
743 trackerInfo.dataObject = pDataObject;
744 trackerInfo.dropSource = pDropSource;
745 trackerInfo.dwOKEffect = dwOKEffect;
746 trackerInfo.pdwEffect = pdwEffect;
747 trackerInfo.trackingDone = FALSE;
748 trackerInfo.escPressed = FALSE;
749 trackerInfo.curTargetHWND = 0;
750 trackerInfo.curDragTarget = 0;
751
752 hwndTrackWindow = CreateWindowW(OLEDD_DRAGTRACKERCLASS, trackerW,
753 WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
754 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0,
755 &trackerInfo);
756
757 if (hwndTrackWindow)
758 {
759 /*
760 * Capture the mouse input
761 */
762 SetCapture(hwndTrackWindow);
763
764 msg.message = 0;
765
766 /*
767 * Pump messages. All mouse input should go to the capture window.
768 */
769 while (!trackerInfo.trackingDone && GetMessageW(&msg, 0, 0, 0) )
770 {
771 trackerInfo.curMousePos.x = msg.pt.x;
772 trackerInfo.curMousePos.y = msg.pt.y;
773 trackerInfo.dwKeyState = OLEDD_GetButtonState();
774
775 if ( (msg.message >= WM_KEYFIRST) &&
776 (msg.message <= WM_KEYLAST) )
777 {
778 /*
779 * When keyboard messages are sent to windows on this thread, we
780 * want to ignore notify the drop source that the state changed.
781 * in the case of the Escape key, we also notify the drop source
782 * we give it a special meaning.
783 */
784 if ( (msg.message==WM_KEYDOWN) &&
785 (msg.wParam==VK_ESCAPE) )
786 {
787 trackerInfo.escPressed = TRUE;
788 }
789
790 /*
791 * Notify the drop source.
792 */
793 OLEDD_TrackStateChange(&trackerInfo);
794 }
795 else
796 {
797 /*
798 * Dispatch the messages only when it's not a keyboard message.
799 */
800 DispatchMessageW(&msg);
801 }
802 }
803
804 /* re-post the quit message to outer message loop */
805 if (msg.message == WM_QUIT)
806 PostQuitMessage(msg.wParam);
807 /*
808 * Destroy the temporary window.
809 */
810 DestroyWindow(hwndTrackWindow);
811
812 return trackerInfo.returnValue;
813 }
814
815 return E_FAIL;
816 }
817
818 /***********************************************************************
819 * OleQueryLinkFromData [OLE32.@]
820 */
821 HRESULT WINAPI OleQueryLinkFromData(
822 IDataObject* pSrcDataObject)
823 {
824 FIXME("(%p),stub!\n", pSrcDataObject);
825 return S_FALSE;
826 }
827
828 /***********************************************************************
829 * OleRegGetMiscStatus [OLE32.@]
830 */
831 HRESULT WINAPI OleRegGetMiscStatus(
832 REFCLSID clsid,
833 DWORD dwAspect,
834 DWORD* pdwStatus)
835 {
836 static const WCHAR miscstatusW[] = {'M','i','s','c','S','t','a','t','u','s',0};
837 static const WCHAR dfmtW[] = {'%','d',0};
838 WCHAR keyName[16];
839 HKEY miscStatusKey;
840 HKEY aspectKey;
841 LONG result;
842 HRESULT hr;
843
844 TRACE("(%s, %d, %p)\n", debugstr_guid(clsid), dwAspect, pdwStatus);
845
846 if (!pdwStatus) return E_INVALIDARG;
847
848 *pdwStatus = 0;
849
850 if (actctx_get_miscstatus(clsid, dwAspect, pdwStatus)) return S_OK;
851
852 hr = COM_OpenKeyForCLSID(clsid, miscstatusW, KEY_READ, &miscStatusKey);
853 if (FAILED(hr))
854 /* missing key is not a failure */
855 return hr == REGDB_E_KEYMISSING ? S_OK : hr;
856
857 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
858
859 /*
860 * Open the key specific to the requested aspect.
861 */
862 sprintfW(keyName, dfmtW, dwAspect);
863
864 result = open_classes_key(miscStatusKey, keyName, KEY_READ, &aspectKey);
865 if (result == ERROR_SUCCESS)
866 {
867 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
868 RegCloseKey(aspectKey);
869 }
870
871 RegCloseKey(miscStatusKey);
872 return S_OK;
873 }
874
875 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum);
876
877 typedef struct
878 {
879 IEnumOLEVERB IEnumOLEVERB_iface;
880 LONG ref;
881
882 HKEY hkeyVerb;
883 ULONG index;
884 } EnumOLEVERB;
885
886 static inline EnumOLEVERB *impl_from_IEnumOLEVERB(IEnumOLEVERB *iface)
887 {
888 return CONTAINING_RECORD(iface, EnumOLEVERB, IEnumOLEVERB_iface);
889 }
890
891 static HRESULT WINAPI EnumOLEVERB_QueryInterface(
892 IEnumOLEVERB *iface, REFIID riid, void **ppv)
893 {
894 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
895 if (IsEqualIID(riid, &IID_IUnknown) ||
896 IsEqualIID(riid, &IID_IEnumOLEVERB))
897 {
898 IEnumOLEVERB_AddRef(iface);
899 *ppv = iface;
900 return S_OK;
901 }
902 return E_NOINTERFACE;
903 }
904
905 static ULONG WINAPI EnumOLEVERB_AddRef(
906 IEnumOLEVERB *iface)
907 {
908 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
909 TRACE("()\n");
910 return InterlockedIncrement(&This->ref);
911 }
912
913 static ULONG WINAPI EnumOLEVERB_Release(
914 IEnumOLEVERB *iface)
915 {
916 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
917 LONG refs = InterlockedDecrement(&This->ref);
918 TRACE("()\n");
919 if (!refs)
920 {
921 RegCloseKey(This->hkeyVerb);
922 HeapFree(GetProcessHeap(), 0, This);
923 }
924 return refs;
925 }
926
927 static HRESULT WINAPI EnumOLEVERB_Next(
928 IEnumOLEVERB *iface, ULONG celt, LPOLEVERB rgelt,
929 ULONG *pceltFetched)
930 {
931 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
932 HRESULT hr = S_OK;
933
934 TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched);
935
936 if (pceltFetched)
937 *pceltFetched = 0;
938
939 for (; celt; celt--, rgelt++)
940 {
941 WCHAR wszSubKey[20];
942 LONG cbData;
943 LPWSTR pwszOLEVERB;
944 LPWSTR pwszMenuFlags;
945 LPWSTR pwszAttribs;
946 LONG res = RegEnumKeyW(This->hkeyVerb, This->index, wszSubKey, sizeof(wszSubKey)/sizeof(wszSubKey[0]));
947 if (res == ERROR_NO_MORE_ITEMS)
948 {
949 hr = S_FALSE;
950 break;
951 }
952 else if (res != ERROR_SUCCESS)
953 {
954 ERR("RegEnumKeyW failed with error %d\n", res);
955 hr = REGDB_E_READREGDB;
956 break;
957 }
958 res = RegQueryValueW(This->hkeyVerb, wszSubKey, NULL, &cbData);
959 if (res != ERROR_SUCCESS)
960 {
961 ERR("RegQueryValueW failed with error %d\n", res);
962 hr = REGDB_E_READREGDB;
963 break;
964 }
965 pwszOLEVERB = CoTaskMemAlloc(cbData);
966 if (!pwszOLEVERB)
967 {
968 hr = E_OUTOFMEMORY;
969 break;
970 }
971 res = RegQueryValueW(This->hkeyVerb, wszSubKey, pwszOLEVERB, &cbData);
972 if (res != ERROR_SUCCESS)
973 {
974 ERR("RegQueryValueW failed with error %d\n", res);
975 hr = REGDB_E_READREGDB;
976 CoTaskMemFree(pwszOLEVERB);
977 break;
978 }
979
980 TRACE("verb string: %s\n", debugstr_w(pwszOLEVERB));
981 pwszMenuFlags = strchrW(pwszOLEVERB, ',');
982 if (!pwszMenuFlags)
983 {
984 hr = OLEOBJ_E_INVALIDVERB;
985 CoTaskMemFree(pwszOLEVERB);
986 break;
987 }
988 /* nul terminate the name string and advance to first character */
989 *pwszMenuFlags = '\0';
990 pwszMenuFlags++;
991 pwszAttribs = strchrW(pwszMenuFlags, ',');
992 if (!pwszAttribs)
993 {
994 hr = OLEOBJ_E_INVALIDVERB;
995 CoTaskMemFree(pwszOLEVERB);
996 break;
997 }
998 /* nul terminate the menu string and advance to first character */
999 *pwszAttribs = '\0';
1000 pwszAttribs++;
1001
1002 /* fill out structure for this verb */
1003 rgelt->lVerb = atolW(wszSubKey);
1004 rgelt->lpszVerbName = pwszOLEVERB; /* user should free */
1005 rgelt->fuFlags = atolW(pwszMenuFlags);
1006 rgelt->grfAttribs = atolW(pwszAttribs);
1007
1008 if (pceltFetched)
1009 (*pceltFetched)++;
1010 This->index++;
1011 }
1012 return hr;
1013 }
1014
1015 static HRESULT WINAPI EnumOLEVERB_Skip(
1016 IEnumOLEVERB *iface, ULONG celt)
1017 {
1018 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1019
1020 TRACE("(%d)\n", celt);
1021
1022 This->index += celt;
1023 return S_OK;
1024 }
1025
1026 static HRESULT WINAPI EnumOLEVERB_Reset(
1027 IEnumOLEVERB *iface)
1028 {
1029 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1030
1031 TRACE("()\n");
1032
1033 This->index = 0;
1034 return S_OK;
1035 }
1036
1037 static HRESULT WINAPI EnumOLEVERB_Clone(
1038 IEnumOLEVERB *iface,
1039 IEnumOLEVERB **ppenum)
1040 {
1041 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
1042 HKEY hkeyVerb;
1043 TRACE("(%p)\n", ppenum);
1044 if (!DuplicateHandle(GetCurrentProcess(), This->hkeyVerb, GetCurrentProcess(), (HANDLE *)&hkeyVerb, 0, FALSE, DUPLICATE_SAME_ACCESS))
1045 return HRESULT_FROM_WIN32(GetLastError());
1046 return EnumOLEVERB_Construct(hkeyVerb, This->index, ppenum);
1047 }
1048
1049 static const IEnumOLEVERBVtbl EnumOLEVERB_VTable =
1050 {
1051 EnumOLEVERB_QueryInterface,
1052 EnumOLEVERB_AddRef,
1053 EnumOLEVERB_Release,
1054 EnumOLEVERB_Next,
1055 EnumOLEVERB_Skip,
1056 EnumOLEVERB_Reset,
1057 EnumOLEVERB_Clone
1058 };
1059
1060 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum)
1061 {
1062 EnumOLEVERB *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1063 if (!This)
1064 {
1065 RegCloseKey(hkeyVerb);
1066 return E_OUTOFMEMORY;
1067 }
1068 This->IEnumOLEVERB_iface.lpVtbl = &EnumOLEVERB_VTable;
1069 This->ref = 1;
1070 This->index = index;
1071 This->hkeyVerb = hkeyVerb;
1072 *ppenum = &This->IEnumOLEVERB_iface;
1073 return S_OK;
1074 }
1075
1076 /***********************************************************************
1077 * OleRegEnumVerbs [OLE32.@]
1078 *
1079 * Enumerates verbs associated with a class stored in the registry.
1080 *
1081 * PARAMS
1082 * clsid [I] Class ID to enumerate the verbs for.
1083 * ppenum [O] Enumerator.
1084 *
1085 * RETURNS
1086 * S_OK: Success.
1087 * REGDB_E_CLASSNOTREG: The specified class does not have a key in the registry.
1088 * REGDB_E_READREGDB: The class key could not be opened for some other reason.
1089 * OLE_E_REGDB_KEY: The Verb subkey for the class is not present.
1090 * OLEOBJ_E_NOVERBS: The Verb subkey for the class is empty.
1091 */
1092 HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum)
1093 {
1094 LONG res;
1095 HKEY hkeyVerb;
1096 DWORD dwSubKeys;
1097 static const WCHAR wszVerb[] = {'V','e','r','b',0};
1098
1099 TRACE("(%s, %p)\n", debugstr_guid(clsid), ppenum);
1100
1101 res = COM_OpenKeyForCLSID(clsid, wszVerb, KEY_READ, &hkeyVerb);
1102 if (FAILED(res))
1103 {
1104 if (res == REGDB_E_CLASSNOTREG)
1105 ERR("CLSID %s not registered\n", debugstr_guid(clsid));
1106 else if (res == REGDB_E_KEYMISSING)
1107 ERR("no Verbs key for class %s\n", debugstr_guid(clsid));
1108 else
1109 ERR("failed to open Verbs key for CLSID %s with error %d\n",
1110 debugstr_guid(clsid), res);
1111 return res;
1112 }
1113
1114 res = RegQueryInfoKeyW(hkeyVerb, NULL, NULL, NULL, &dwSubKeys, NULL,
1115 NULL, NULL, NULL, NULL, NULL, NULL);
1116 if (res != ERROR_SUCCESS)
1117 {
1118 ERR("failed to get subkey count with error %d\n", GetLastError());
1119 return REGDB_E_READREGDB;
1120 }
1121
1122 if (!dwSubKeys)
1123 {
1124 WARN("class %s has no verbs\n", debugstr_guid(clsid));
1125 RegCloseKey(hkeyVerb);
1126 return OLEOBJ_E_NOVERBS;
1127 }
1128
1129 return EnumOLEVERB_Construct(hkeyVerb, 0, ppenum);
1130 }
1131
1132 /******************************************************************************
1133 * OleSetContainedObject [OLE32.@]
1134 */
1135 HRESULT WINAPI OleSetContainedObject(
1136 LPUNKNOWN pUnknown,
1137 BOOL fContained)
1138 {
1139 IRunnableObject* runnable = NULL;
1140 HRESULT hres;
1141
1142 TRACE("(%p,%x)\n", pUnknown, fContained);
1143
1144 hres = IUnknown_QueryInterface(pUnknown,
1145 &IID_IRunnableObject,
1146 (void**)&runnable);
1147
1148 if (SUCCEEDED(hres))
1149 {
1150 hres = IRunnableObject_SetContainedObject(runnable, fContained);
1151
1152 IRunnableObject_Release(runnable);
1153
1154 return hres;
1155 }
1156
1157 return S_OK;
1158 }
1159
1160 /******************************************************************************
1161 * OleRun [OLE32.@]
1162 *
1163 * Set the OLE object to the running state.
1164 *
1165 * PARAMS
1166 * pUnknown [I] OLE object to run.
1167 *
1168 * RETURNS
1169 * Success: S_OK.
1170 * Failure: Any HRESULT code.
1171 */
1172 HRESULT WINAPI DECLSPEC_HOTPATCH OleRun(LPUNKNOWN pUnknown)
1173 {
1174 IRunnableObject *runable;
1175 HRESULT hres;
1176
1177 TRACE("(%p)\n", pUnknown);
1178
1179 hres = IUnknown_QueryInterface(pUnknown, &IID_IRunnableObject, (void**)&runable);
1180 if (FAILED(hres))
1181 return S_OK; /* Appears to return no error. */
1182
1183 hres = IRunnableObject_Run(runable, NULL);
1184 IRunnableObject_Release(runable);
1185 return hres;
1186 }
1187
1188 /******************************************************************************
1189 * OleLoad [OLE32.@]
1190 */
1191 HRESULT WINAPI OleLoad(
1192 LPSTORAGE pStg,
1193 REFIID riid,
1194 LPOLECLIENTSITE pClientSite,
1195 LPVOID* ppvObj)
1196 {
1197 IPersistStorage* persistStorage = NULL;
1198 IUnknown* pUnk;
1199 IOleObject* pOleObject = NULL;
1200 STATSTG storageInfo;
1201 HRESULT hres;
1202
1203 TRACE("(%p, %s, %p, %p)\n", pStg, debugstr_guid(riid), pClientSite, ppvObj);
1204
1205 *ppvObj = NULL;
1206
1207 /*
1208 * TODO, Conversion ... OleDoAutoConvert
1209 */
1210
1211 /*
1212 * Get the class ID for the object.
1213 */
1214 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
1215 if (FAILED(hres))
1216 return hres;
1217
1218 /*
1219 * Now, try and create the handler for the object
1220 */
1221 hres = CoCreateInstance(&storageInfo.clsid,
1222 NULL,
1223 CLSCTX_INPROC_HANDLER|CLSCTX_INPROC_SERVER,
1224 riid,
1225 (void**)&pUnk);
1226
1227 /*
1228 * If that fails, as it will most times, load the default
1229 * OLE handler.
1230 */
1231 if (FAILED(hres))
1232 {
1233 hres = OleCreateDefaultHandler(&storageInfo.clsid,
1234 NULL,
1235 riid,
1236 (void**)&pUnk);
1237 }
1238
1239 /*
1240 * If we couldn't find a handler... this is bad. Abort the whole thing.
1241 */
1242 if (FAILED(hres))
1243 return hres;
1244
1245 if (pClientSite)
1246 {
1247 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (void **)&pOleObject);
1248 if (SUCCEEDED(hres))
1249 {
1250 DWORD dwStatus;
1251 hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
1252 }
1253 }
1254
1255 /*
1256 * Initialize the object with its IPersistStorage interface.
1257 */
1258 hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (void**)&persistStorage);
1259 if (SUCCEEDED(hres))
1260 {
1261 hres = IPersistStorage_Load(persistStorage, pStg);
1262
1263 IPersistStorage_Release(persistStorage);
1264 persistStorage = NULL;
1265 }
1266
1267 if (SUCCEEDED(hres) && pClientSite)
1268 /*
1269 * Inform the new object of its client site.
1270 */
1271 hres = IOleObject_SetClientSite(pOleObject, pClientSite);
1272
1273 /*
1274 * Cleanup interfaces used internally
1275 */
1276 if (pOleObject)
1277 IOleObject_Release(pOleObject);
1278
1279 if (SUCCEEDED(hres))
1280 {
1281 IOleLink *pOleLink;
1282 HRESULT hres1;
1283 hres1 = IUnknown_QueryInterface(pUnk, &IID_IOleLink, (void **)&pOleLink);
1284 if (SUCCEEDED(hres1))
1285 {
1286 FIXME("handle OLE link\n");
1287 IOleLink_Release(pOleLink);
1288 }
1289 }
1290
1291 if (FAILED(hres))
1292 {
1293 IUnknown_Release(pUnk);
1294 pUnk = NULL;
1295 }
1296
1297 *ppvObj = pUnk;
1298
1299 return hres;
1300 }
1301
1302 /***********************************************************************
1303 * OleSave [OLE32.@]
1304 */
1305 HRESULT WINAPI OleSave(
1306 LPPERSISTSTORAGE pPS,
1307 LPSTORAGE pStg,
1308 BOOL fSameAsLoad)
1309 {
1310 HRESULT hres;
1311 CLSID objectClass;
1312
1313 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
1314
1315 /*
1316 * First, we transfer the class ID (if available)
1317 */
1318 hres = IPersistStorage_GetClassID(pPS, &objectClass);
1319
1320 if (SUCCEEDED(hres))
1321 {
1322 WriteClassStg(pStg, &objectClass);
1323 }
1324
1325 /*
1326 * Then, we ask the object to save itself to the
1327 * storage. If it is successful, we commit the storage.
1328 */
1329 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
1330
1331 if (SUCCEEDED(hres))
1332 {
1333 IStorage_Commit(pStg,
1334 STGC_DEFAULT);
1335 }
1336
1337 return hres;
1338 }
1339
1340
1341 /******************************************************************************
1342 * OleLockRunning [OLE32.@]
1343 */
1344 HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)
1345 {
1346 IRunnableObject* runnable = NULL;
1347 HRESULT hres;
1348
1349 TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);
1350
1351 hres = IUnknown_QueryInterface(pUnknown,
1352 &IID_IRunnableObject,
1353 (void**)&runnable);
1354
1355 if (SUCCEEDED(hres))
1356 {
1357 hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);
1358
1359 IRunnableObject_Release(runnable);
1360
1361 return hres;
1362 }
1363
1364 return S_OK;
1365 }
1366
1367
1368 /**************************************************************************
1369 * Internal methods to manage the shared OLE menu in response to the
1370 * OLE***MenuDescriptor API
1371 */
1372
1373 /***
1374 * OLEMenu_Initialize()
1375 *
1376 * Initializes the OLEMENU data structures.
1377 */
1378 static void OLEMenu_Initialize(void)
1379 {
1380 }
1381
1382 /***
1383 * OLEMenu_UnInitialize()
1384 *
1385 * Releases the OLEMENU data structures.
1386 */
1387 static void OLEMenu_UnInitialize(void)
1388 {
1389 }
1390
1391 /*************************************************************************
1392 * OLEMenu_InstallHooks
1393 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1394 *
1395 * RETURNS: TRUE if message hooks were successfully installed
1396 * FALSE on failure
1397 */
1398 static BOOL OLEMenu_InstallHooks( DWORD tid )
1399 {
1400 OleMenuHookItem *pHookItem;
1401
1402 /* Create an entry for the hook table */
1403 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
1404 sizeof(OleMenuHookItem)) ) )
1405 return FALSE;
1406
1407 pHookItem->tid = tid;
1408 pHookItem->hHeap = GetProcessHeap();
1409 pHookItem->CallWndProc_hHook = NULL;
1410
1411 /* Install a thread scope message hook for WH_GETMESSAGE */
1412 pHookItem->GetMsg_hHook = SetWindowsHookExW( WH_GETMESSAGE, OLEMenu_GetMsgProc,
1413 0, GetCurrentThreadId() );
1414 if ( !pHookItem->GetMsg_hHook )
1415 goto CLEANUP;
1416
1417 /* Install a thread scope message hook for WH_CALLWNDPROC */
1418 pHookItem->CallWndProc_hHook = SetWindowsHookExW( WH_CALLWNDPROC, OLEMenu_CallWndProc,
1419 0, GetCurrentThreadId() );
1420 if ( !pHookItem->CallWndProc_hHook )
1421 goto CLEANUP;
1422
1423 /* Insert the hook table entry */
1424 pHookItem->next = hook_list;
1425 hook_list = pHookItem;
1426
1427 return TRUE;
1428
1429 CLEANUP:
1430 /* Unhook any hooks */
1431 if ( pHookItem->GetMsg_hHook )
1432 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
1433 if ( pHookItem->CallWndProc_hHook )
1434 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
1435 /* Release the hook table entry */
1436 HeapFree(pHookItem->hHeap, 0, pHookItem );
1437
1438 return FALSE;
1439 }
1440
1441 /*************************************************************************
1442 * OLEMenu_UnInstallHooks
1443 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
1444 *
1445 * RETURNS: TRUE if message hooks were successfully installed
1446 * FALSE on failure
1447 */
1448 static BOOL OLEMenu_UnInstallHooks( DWORD tid )
1449 {
1450 OleMenuHookItem *pHookItem = NULL;
1451 OleMenuHookItem **ppHook = &hook_list;
1452
1453 while (*ppHook)
1454 {
1455 if ((*ppHook)->tid == tid)
1456 {
1457 pHookItem = *ppHook;
1458 *ppHook = pHookItem->next;
1459 break;
1460 }
1461 ppHook = &(*ppHook)->next;
1462 }
1463 if (!pHookItem) return FALSE;
1464
1465 /* Uninstall the hooks installed for this thread */
1466 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
1467 goto CLEANUP;
1468 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
1469 goto CLEANUP;
1470
1471 /* Release the hook table entry */
1472 HeapFree(pHookItem->hHeap, 0, pHookItem );
1473
1474 return TRUE;
1475
1476 CLEANUP:
1477 /* Release the hook table entry */
1478 HeapFree(pHookItem->hHeap, 0, pHookItem );
1479
1480 return FALSE;
1481 }
1482
1483 /*************************************************************************
1484 * OLEMenu_IsHookInstalled
1485 * Tests if OLEMenu hooks have been installed for a thread
1486 *
1487 * RETURNS: The pointer and index of the hook table entry for the tid
1488 * NULL and -1 for the index if no hooks were installed for this thread
1489 */
1490 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
1491 {
1492 OleMenuHookItem *pHookItem;
1493
1494 /* Do a simple linear search for an entry whose tid matches ours.
1495 * We really need a map but efficiency is not a concern here. */
1496 for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
1497 {
1498 if ( tid == pHookItem->tid )
1499 return pHookItem;
1500 }
1501
1502 return NULL;
1503 }
1504
1505 /***********************************************************************
1506 * OLEMenu_FindMainMenuIndex
1507 *
1508 * Used by OLEMenu API to find the top level group a menu item belongs to.
1509 * On success pnPos contains the index of the item in the top level menu group
1510 *
1511 * RETURNS: TRUE if the ID was found, FALSE on failure
1512 */
1513 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
1514 {
1515 INT i, nItems;
1516
1517 nItems = GetMenuItemCount( hMainMenu );
1518
1519 for (i = 0; i < nItems; i++)
1520 {
1521 HMENU hsubmenu;
1522
1523 /* Is the current item a submenu? */
1524 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
1525 {
1526 /* If the handle is the same we're done */
1527 if ( hsubmenu == hPopupMenu )
1528 {
1529 if (pnPos)
1530 *pnPos = i;
1531 return TRUE;
1532 }
1533 /* Recursively search without updating pnPos */
1534 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1535 {
1536 if (pnPos)
1537 *pnPos = i;
1538 return TRUE;
1539 }
1540 }
1541 }
1542
1543 return FALSE;
1544 }
1545
1546 /***********************************************************************
1547 * OLEMenu_SetIsServerMenu
1548 *
1549 * Checks whether a popup menu belongs to a shared menu group which is
1550 * owned by the server, and sets the menu descriptor state accordingly.
1551 * All menu messages from these groups should be routed to the server.
1552 *
1553 * RETURNS: TRUE if the popup menu is part of a server owned group
1554 * FALSE if the popup menu is part of a container owned group
1555 */
1556 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1557 {
1558 UINT nPos = 0, nWidth, i;
1559
1560 pOleMenuDescriptor->bIsServerItem = FALSE;
1561
1562 /* Don't bother searching if the popup is the combined menu itself */
1563 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1564 return FALSE;
1565
1566 /* Find the menu item index in the shared OLE menu that this item belongs to */
1567 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1568 return FALSE;
1569
1570 /* The group widths array has counts for the number of elements
1571 * in the groups File, Edit, Container, Object, Window, Help.
1572 * The Edit, Object & Help groups belong to the server object
1573 * and the other three belong to the container.
1574 * Loop through the group widths and locate the group we are a member of.
1575 */
1576 for ( i = 0, nWidth = 0; i < 6; i++ )
1577 {
1578 nWidth += pOleMenuDescriptor->mgw.width[i];
1579 if ( nPos < nWidth )
1580 {
1581 /* Odd elements are server menu widths */
1582 pOleMenuDescriptor->bIsServerItem = i%2;
1583 break;
1584 }
1585 }
1586
1587 return pOleMenuDescriptor->bIsServerItem;
1588 }
1589
1590 /*************************************************************************
1591 * OLEMenu_CallWndProc
1592 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1593 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1594 */
1595 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1596 {
1597 LPCWPSTRUCT pMsg;
1598 HOLEMENU hOleMenu = 0;
1599 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1600 OleMenuHookItem *pHookItem = NULL;
1601 WORD fuFlags;
1602
1603 TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
1604
1605 /* Check if we're being asked to process the message */
1606 if ( HC_ACTION != code )
1607 goto NEXTHOOK;
1608
1609 /* Retrieve the current message being dispatched from lParam */
1610 pMsg = (LPCWPSTRUCT)lParam;
1611
1612 /* Check if the message is destined for a window we are interested in:
1613 * If the window has an OLEMenu property we may need to dispatch
1614 * the menu message to its active objects window instead. */
1615
1616 hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
1617 if ( !hOleMenu )
1618 goto NEXTHOOK;
1619
1620 /* Get the menu descriptor */
1621 pOleMenuDescriptor = GlobalLock( hOleMenu );
1622 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1623 goto NEXTHOOK;
1624
1625 /* Process menu messages */
1626 switch( pMsg->message )
1627 {
1628 case WM_INITMENU:
1629 {
1630 /* Reset the menu descriptor state */
1631 pOleMenuDescriptor->bIsServerItem = FALSE;
1632
1633 /* Send this message to the server as well */
1634 SendMessageW( pOleMenuDescriptor->hwndActiveObject,
1635 pMsg->message, pMsg->wParam, pMsg->lParam );
1636 goto NEXTHOOK;
1637 }
1638
1639 case WM_INITMENUPOPUP:
1640 {
1641 /* Save the state for whether this is a server owned menu */
1642 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1643 break;
1644 }
1645
1646 case WM_MENUSELECT:
1647 {
1648 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1649 if ( fuFlags & MF_SYSMENU )
1650 goto NEXTHOOK;
1651
1652 /* Save the state for whether this is a server owned popup menu */
1653 else if ( fuFlags & MF_POPUP )
1654 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1655
1656 break;
1657 }
1658
1659 case WM_DRAWITEM:
1660 {
1661 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1662 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1663 goto NEXTHOOK; /* Not a menu message */
1664
1665 break;
1666 }
1667
1668 default:
1669 goto NEXTHOOK;
1670 }
1671
1672 /* If the message was for the server dispatch it accordingly */
1673 if ( pOleMenuDescriptor->bIsServerItem )
1674 {
1675 SendMessageW( pOleMenuDescriptor->hwndActiveObject,
1676 pMsg->message, pMsg->wParam, pMsg->lParam );
1677 }
1678
1679 NEXTHOOK:
1680 if ( pOleMenuDescriptor )
1681 GlobalUnlock( hOleMenu );
1682
1683 /* Lookup the hook item for the current thread */
1684 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1685 {
1686 /* This should never fail!! */
1687 WARN("could not retrieve hHook for current thread!\n" );
1688 return 0;
1689 }
1690
1691 /* Pass on the message to the next hooker */
1692 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1693 }
1694
1695 /*************************************************************************
1696 * OLEMenu_GetMsgProc
1697 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1698 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1699 */
1700 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1701 {
1702 LPMSG pMsg;
1703 HOLEMENU hOleMenu = 0;
1704 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1705 OleMenuHookItem *pHookItem = NULL;
1706 WORD wCode;
1707
1708 TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
1709
1710 /* Check if we're being asked to process a messages */
1711 if ( HC_ACTION != code )
1712 goto NEXTHOOK;
1713
1714 /* Retrieve the current message being dispatched from lParam */
1715 pMsg = (LPMSG)lParam;
1716
1717 /* Check if the message is destined for a window we are interested in:
1718 * If the window has an OLEMenu property we may need to dispatch
1719 * the menu message to its active objects window instead. */
1720
1721 hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
1722 if ( !hOleMenu )
1723 goto NEXTHOOK;
1724
1725 /* Process menu messages */
1726 switch( pMsg->message )
1727 {
1728 case WM_COMMAND:
1729 {
1730 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1731 if ( wCode )
1732 goto NEXTHOOK; /* Not a menu message */
1733 break;
1734 }
1735 default:
1736 goto NEXTHOOK;
1737 }
1738
1739 /* Get the menu descriptor */
1740 pOleMenuDescriptor = GlobalLock( hOleMenu );
1741 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1742 goto NEXTHOOK;
1743
1744 /* If the message was for the server dispatch it accordingly */
1745 if ( pOleMenuDescriptor->bIsServerItem )
1746 {
1747 /* Change the hWnd in the message to the active objects hWnd.
1748 * The message loop which reads this message will automatically
1749 * dispatch it to the embedded objects window. */
1750 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1751 }
1752
1753 NEXTHOOK:
1754 if ( pOleMenuDescriptor )
1755 GlobalUnlock( hOleMenu );
1756
1757 /* Lookup the hook item for the current thread */
1758 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1759 {
1760 /* This should never fail!! */
1761 WARN("could not retrieve hHook for current thread!\n" );
1762 return FALSE;
1763 }
1764
1765 /* Pass on the message to the next hooker */
1766 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1767 }
1768
1769 /***********************************************************************
1770 * OleCreateMenuDescriptor [OLE32.@]
1771 * Creates an OLE menu descriptor for OLE to use when dispatching
1772 * menu messages and commands.
1773 *
1774 * PARAMS:
1775 * hmenuCombined - Handle to the objects combined menu
1776 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1777 *
1778 */
1779 HOLEMENU WINAPI OleCreateMenuDescriptor(
1780 HMENU hmenuCombined,
1781 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1782 {
1783 HOLEMENU hOleMenu;
1784 OleMenuDescriptor *pOleMenuDescriptor;
1785 int i;
1786
1787 if ( !hmenuCombined || !lpMenuWidths )
1788 return 0;
1789
1790 /* Create an OLE menu descriptor */
1791 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1792 sizeof(OleMenuDescriptor) ) ) )
1793 return 0;
1794
1795 pOleMenuDescriptor = GlobalLock( hOleMenu );
1796 if ( !pOleMenuDescriptor )
1797 return 0;
1798
1799 /* Initialize menu group widths and hmenu */
1800 for ( i = 0; i < 6; i++ )
1801 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1802
1803 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1804 pOleMenuDescriptor->bIsServerItem = FALSE;
1805 GlobalUnlock( hOleMenu );
1806
1807 return hOleMenu;
1808 }
1809
1810 /***********************************************************************
1811 * OleDestroyMenuDescriptor [OLE32.@]
1812 * Destroy the shared menu descriptor
1813 */
1814 HRESULT WINAPI OleDestroyMenuDescriptor(
1815 HOLEMENU hmenuDescriptor)
1816 {
1817 if ( hmenuDescriptor )
1818 GlobalFree( hmenuDescriptor );
1819 return S_OK;
1820 }
1821
1822 /***********************************************************************
1823 * OleSetMenuDescriptor [OLE32.@]
1824 * Installs or removes OLE dispatching code for the containers frame window.
1825 *
1826 * PARAMS
1827 * hOleMenu Handle to composite menu descriptor
1828 * hwndFrame Handle to containers frame window
1829 * hwndActiveObject Handle to objects in-place activation window
1830 * lpFrame Pointer to IOleInPlaceFrame on containers window
1831 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1832 *
1833 * RETURNS
1834 * S_OK - menu installed correctly
1835 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1836 *
1837 * FIXME
1838 * The lpFrame and lpActiveObject parameters are currently ignored
1839 * OLE should install context sensitive help F1 filtering for the app when
1840 * these are non null.
1841 */
1842 HRESULT WINAPI OleSetMenuDescriptor(
1843 HOLEMENU hOleMenu,
1844 HWND hwndFrame,
1845 HWND hwndActiveObject,
1846 LPOLEINPLACEFRAME lpFrame,
1847 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1848 {
1849 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1850
1851 /* Check args */
1852 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1853 return E_INVALIDARG;
1854
1855 if ( lpFrame || lpActiveObject )
1856 {
1857 FIXME("(%p, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",
1858 hOleMenu,
1859 hwndFrame,
1860 hwndActiveObject,
1861 lpFrame,
1862 lpActiveObject);
1863 }
1864
1865 /* Set up a message hook to intercept the containers frame window messages.
1866 * The message filter is responsible for dispatching menu messages from the
1867 * shared menu which are intended for the object.
1868 */
1869
1870 if ( hOleMenu ) /* Want to install dispatching code */
1871 {
1872 /* If OLEMenu hooks are already installed for this thread, fail
1873 * Note: This effectively means that OleSetMenuDescriptor cannot
1874 * be called twice in succession on the same frame window
1875 * without first calling it with a null hOleMenu to uninstall
1876 */
1877 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1878 return E_FAIL;
1879
1880 /* Get the menu descriptor */
1881 pOleMenuDescriptor = GlobalLock( hOleMenu );
1882 if ( !pOleMenuDescriptor )
1883 return E_UNEXPECTED;
1884
1885 /* Update the menu descriptor */
1886 pOleMenuDescriptor->hwndFrame = hwndFrame;
1887 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1888
1889 GlobalUnlock( hOleMenu );
1890 pOleMenuDescriptor = NULL;
1891
1892 /* Add a menu descriptor windows property to the frame window */
1893 SetPropW( hwndFrame, prop_olemenuW, hOleMenu );
1894
1895 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1896 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1897 return E_FAIL;
1898 }
1899 else /* Want to uninstall dispatching code */
1900 {
1901 /* Uninstall the hooks */
1902 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1903 return E_FAIL;
1904
1905 /* Remove the menu descriptor property from the frame window */
1906 RemovePropW( hwndFrame, prop_olemenuW );
1907 }
1908
1909 return S_OK;
1910 }
1911
1912 /******************************************************************************
1913 * IsAccelerator [OLE32.@]
1914 * Mostly copied from controls/menu.c TranslateAccelerator implementation
1915 */
1916 BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
1917 {
1918 LPACCEL lpAccelTbl;
1919 int i;
1920
1921 if(!lpMsg) return FALSE;
1922 if (!hAccel)
1923 {
1924 WARN_(accel)("NULL accel handle\n");
1925 return FALSE;
1926 }
1927 if((lpMsg->message != WM_KEYDOWN &&
1928 lpMsg->message != WM_SYSKEYDOWN &&
1929 lpMsg->message != WM_SYSCHAR &&
1930 lpMsg->message != WM_CHAR)) return FALSE;
1931 lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL));
1932 if (NULL == lpAccelTbl)
1933 {
1934 return FALSE;
1935 }
1936 if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries)
1937 {
1938 WARN_(accel)("CopyAcceleratorTableW failed\n");
1939 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1940 return FALSE;
1941 }
1942
1943 TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"
1944 "msg->hwnd=%p, msg->message=%04x, wParam=%08lx, lParam=%08lx\n",
1945 hAccel, cAccelEntries,
1946 lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
1947 for(i = 0; i < cAccelEntries; i++)
1948 {
1949 if(lpAccelTbl[i].key != lpMsg->wParam)
1950 continue;
1951
1952 if(lpMsg->message == WM_CHAR)
1953 {
1954 if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
1955 {
1956 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", LOWORD(lpMsg->wParam) & 0xff);
1957 goto found;
1958 }
1959 }
1960 else
1961 {
1962 if(lpAccelTbl[i].fVirt & FVIRTKEY)
1963 {
1964 INT mask = 0;
1965 TRACE_(accel)("found accel for virt_key %04lx (scan %04x)\n",
1966 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
1967 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
1968 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
1969 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
1970 if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
1971 TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
1972 }
1973 else
1974 {
1975 if(!(lpMsg->lParam & 0x01000000)) /* no special_key */
1976 {
1977 if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
1978 { /* ^^ ALT pressed */
1979 TRACE_(accel)("found accel for Alt-%c\n", LOWORD(lpMsg->wParam) & 0xff);
1980 goto found;
1981 }
1982 }
1983 }
1984 }
1985 }
1986
1987 WARN_(accel)("couldn't translate accelerator key\n");
1988 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1989 return FALSE;
1990
1991 found:
1992 if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
1993 HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1994 return TRUE;
1995 }
1996
1997 /***********************************************************************
1998 * ReleaseStgMedium [OLE32.@]
1999 */
2000 void WINAPI ReleaseStgMedium(
2001 STGMEDIUM* pmedium)
2002 {
2003 switch (pmedium->tymed)
2004 {
2005 case TYMED_HGLOBAL:
2006 {
2007 if ( (pmedium->pUnkForRelease==0) &&
2008 (pmedium->u.hGlobal!=0) )
2009 GlobalFree(pmedium->u.hGlobal);
2010 break;
2011 }
2012 case TYMED_FILE:
2013 {
2014 if (pmedium->u.lpszFileName!=0)
2015 {
2016 if (pmedium->pUnkForRelease==0)
2017 {
2018 DeleteFileW(pmedium->u.lpszFileName);
2019 }
2020
2021 CoTaskMemFree(pmedium->u.lpszFileName);
2022 }
2023 break;
2024 }
2025 case TYMED_ISTREAM:
2026 {
2027 if (pmedium->u.pstm!=0)
2028 {
2029 IStream_Release(pmedium->u.pstm);
2030 }
2031 break;
2032 }
2033 case TYMED_ISTORAGE:
2034 {
2035 if (pmedium->u.pstg!=0)
2036 {
2037 IStorage_Release(pmedium->u.pstg);
2038 }
2039 break;
2040 }
2041 case TYMED_GDI:
2042 {
2043 if ( (pmedium->pUnkForRelease==0) &&
2044 (pmedium->u.hBitmap!=0) )
2045 DeleteObject(pmedium->u.hBitmap);
2046 break;
2047 }
2048 case TYMED_MFPICT:
2049 {
2050 if ( (pmedium->pUnkForRelease==0) &&
2051 (pmedium->u.hMetaFilePict!=0) )
2052 {
2053 LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);
2054 DeleteMetaFile(pMP->hMF);
2055 GlobalUnlock(pmedium->u.hMetaFilePict);
2056 GlobalFree(pmedium->u.hMetaFilePict);
2057 }
2058 break;
2059 }
2060 case TYMED_ENHMF:
2061 {
2062 if ( (pmedium->pUnkForRelease==0) &&
2063 (pmedium->u.hEnhMetaFile!=0) )
2064 {
2065 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
2066 }
2067 break;
2068 }
2069 case TYMED_NULL:
2070 default:
2071 break;
2072 }
2073 pmedium->tymed=TYMED_NULL;
2074
2075 /*
2076 * After cleaning up, the unknown is released
2077 */
2078 if (pmedium->pUnkForRelease!=0)
2079 {
2080 IUnknown_Release(pmedium->pUnkForRelease);
2081 pmedium->pUnkForRelease = 0;
2082 }
2083 }
2084
2085 /***
2086 * OLEDD_Initialize()
2087 *
2088 * Initializes the OLE drag and drop data structures.
2089 */
2090 static void OLEDD_Initialize(void)
2091 {
2092 WNDCLASSW wndClass;
2093
2094 ZeroMemory (&wndClass, sizeof(WNDCLASSW));
2095 wndClass.style = CS_GLOBALCLASS;
2096 wndClass.lpfnWndProc = OLEDD_DragTrackerWindowProc;
2097 wndClass.cbClsExtra = 0;
2098 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
2099 wndClass.hCursor = 0;
2100 wndClass.hbrBackground = 0;
2101 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
2102
2103 RegisterClassW (&wndClass);
2104 }
2105
2106 /***
2107 * OLEDD_DragTrackerWindowProc()
2108 *
2109 * This method is the WindowProcedure of the drag n drop tracking
2110 * window. During a drag n Drop operation, an invisible window is created
2111 * to receive the user input and act upon it. This procedure is in charge
2112 * of this behavior.
2113 */
2114
2115 #define DRAG_TIMER_ID 1
2116
2117 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
2118 HWND hwnd,
2119 UINT uMsg,
2120 WPARAM wParam,
2121 LPARAM lParam)
2122 {
2123 switch (uMsg)
2124 {
2125 case WM_CREATE:
2126 {
2127 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
2128
2129 SetWindowLongPtrW(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams);
2130 SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL);
2131
2132 break;
2133 }
2134 case WM_TIMER:
2135 case WM_MOUSEMOVE:
2136 case WM_LBUTTONUP:
2137 case WM_MBUTTONUP:
2138 case WM_RBUTTONUP:
2139 case WM_LBUTTONDOWN:
2140 case WM_MBUTTONDOWN:
2141 case WM_RBUTTONDOWN:
2142 {
2143 TrackerWindowInfo *trackerInfo = (TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0);
2144 if (trackerInfo->trackingDone) break;
2145 OLEDD_TrackStateChange(trackerInfo);
2146 break;
2147 }
2148 case WM_DESTROY:
2149 {
2150 KillTimer(hwnd, DRAG_TIMER_ID);
2151 break;
2152 }
2153 }
2154
2155 /*
2156 * This is a window proc after all. Let's call the default.
2157 */
2158 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
2159 }
2160
2161 static void drag_enter( TrackerWindowInfo *info, HWND new_target )
2162 {
2163 HRESULT hr;
2164
2165 info->curTargetHWND = new_target;
2166
2167 while (new_target && !is_droptarget( new_target ))
2168 new_target = GetParent( new_target );
2169
2170 info->curDragTarget = get_droptarget_pointer( new_target );
2171
2172 if (info->curDragTarget)
2173 {
2174 *info->pdwEffect = info->dwOKEffect;
2175 hr = IDropTarget_DragEnter( info->curDragTarget, info->dataObject,
2176 info->dwKeyState, info->curMousePos,
2177 info->pdwEffect );
2178 *info->pdwEffect &= info->dwOKEffect;
2179
2180 /* failed DragEnter() means invalid target */
2181 if (hr != S_OK)
2182 {
2183 IDropTarget_Release( info->curDragTarget );
2184 info->curDragTarget = NULL;
2185 info->curTargetHWND = NULL;
2186 }
2187 }
2188 }
2189
2190 static void drag_end( TrackerWindowInfo *info )
2191 {
2192 HRESULT hr;
2193
2194 info->trackingDone = TRUE;
2195 ReleaseCapture();
2196
2197 if (info->curDragTarget)
2198 {
2199 if (info->returnValue == DRAGDROP_S_DROP &&
2200 *info->pdwEffect != DROPEFFECT_NONE)
2201 {
2202 *info->pdwEffect = info->dwOKEffect;
2203 hr = IDropTarget_Drop( info->curDragTarget, info->dataObject, info->dwKeyState,
2204 info->curMousePos, info->pdwEffect );
2205 *info->pdwEffect &= info->dwOKEffect;
2206
2207 if (FAILED( hr ))
2208 info->returnValue = hr;
2209 }
2210 else
2211 {
2212 IDropTarget_DragLeave( info->curDragTarget );
2213 *info->pdwEffect = DROPEFFECT_NONE;
2214 }
2215 IDropTarget_Release( info->curDragTarget );
2216 info->curDragTarget = NULL;
2217 }
2218 else
2219 *info->pdwEffect = DROPEFFECT_NONE;
2220 }
2221
2222 static HRESULT give_feedback( TrackerWindowInfo *info )
2223 {
2224 HRESULT hr;
2225 int res;
2226 HCURSOR cur;
2227
2228 if (info->curDragTarget == NULL)
2229 *info->pdwEffect = DROPEFFECT_NONE;
2230
2231 hr = IDropSource_GiveFeedback( info->dropSource, *info->pdwEffect );
2232
2233 if (hr == DRAGDROP_S_USEDEFAULTCURSORS)
2234 {
2235 if (*info->pdwEffect & DROPEFFECT_MOVE)
2236 res = CURSOR_MOVE;
2237 else if (*info->pdwEffect & DROPEFFECT_COPY)
2238 res = CURSOR_COPY;
2239 else if (*info->pdwEffect & DROPEFFECT_LINK)
2240 res = CURSOR_LINK;
2241 else
2242 res = CURSOR_NODROP;
2243
2244 cur = LoadCursorW( hProxyDll, MAKEINTRESOURCEW( res ) );
2245 SetCursor( cur );
2246 }
2247
2248 return hr;
2249 }
2250
2251 /***
2252 * OLEDD_TrackStateChange()
2253 *
2254 * This method is invoked while a drag and drop operation is in effect.
2255 *
2256 * params:
2257 * trackerInfo - Pointer to the structure identifying the
2258 * drag & drop operation that is currently
2259 * active.
2260 */
2261 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo)
2262 {
2263 HWND hwndNewTarget = 0;
2264 POINT pt;
2265
2266 /*
2267 * Get the handle of the window under the mouse
2268 */
2269 pt.x = trackerInfo->curMousePos.x;
2270 pt.y = trackerInfo->curMousePos.y;
2271 hwndNewTarget = WindowFromPoint(pt);
2272
2273 trackerInfo->returnValue = IDropSource_QueryContinueDrag(trackerInfo->dropSource,
2274 trackerInfo->escPressed,
2275 trackerInfo->dwKeyState);
2276
2277 if (trackerInfo->curTargetHWND != hwndNewTarget &&
2278 (trackerInfo->returnValue == S_OK ||
2279 trackerInfo->returnValue == DRAGDROP_S_DROP))
2280 {
2281 if (trackerInfo->curDragTarget)
2282 {
2283 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2284 IDropTarget_Release(trackerInfo->curDragTarget);
2285 trackerInfo->curDragTarget = NULL;
2286 trackerInfo->curTargetHWND = NULL;
2287 }
2288
2289 if (hwndNewTarget)
2290 drag_enter( trackerInfo, hwndNewTarget );
2291
2292 give_feedback( trackerInfo );
2293
2294 }
2295
2296 if (trackerInfo->returnValue == S_OK)
2297 {
2298 if (trackerInfo->curDragTarget)
2299 {
2300 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
2301 IDropTarget_DragOver(trackerInfo->curDragTarget,
2302 trackerInfo->dwKeyState,
2303 trackerInfo->curMousePos,
2304 trackerInfo->pdwEffect);
2305 *trackerInfo->pdwEffect &= trackerInfo->dwOKEffect;
2306 }
2307 give_feedback( trackerInfo );
2308 }
2309 else
2310 drag_end( trackerInfo );
2311 }
2312
2313 /***
2314 * OLEDD_GetButtonState()
2315 *
2316 * This method will use the current state of the keyboard to build
2317 * a button state mask equivalent to the one passed in the
2318 * WM_MOUSEMOVE wParam.
2319 */
2320 static DWORD OLEDD_GetButtonState(void)
2321 {
2322 BYTE keyboardState[256];
2323 DWORD keyMask = 0;
2324
2325 GetKeyboardState(keyboardState);
2326
2327 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2328 keyMask |= MK_SHIFT;
2329
2330 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2331 keyMask |= MK_CONTROL;
2332
2333 if ( (keyboardState[VK_MENU] & 0x80) !=0)
2334 keyMask |= MK_ALT;
2335
2336 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2337 keyMask |= MK_LBUTTON;
2338
2339 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2340 keyMask |= MK_RBUTTON;
2341
2342 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2343 keyMask |= MK_MBUTTON;
2344
2345 return keyMask;
2346 }
2347
2348 /***
2349 * OLEDD_GetButtonState()
2350 *
2351 * This method will read the default value of the registry key in
2352 * parameter and extract a DWORD value from it. The registry key value
2353 * can be in a string key or a DWORD key.
2354 *
2355 * params:
2356 * regKey - Key to read the default value from
2357 * pdwValue - Pointer to the location where the DWORD
2358 * value is returned. This value is not modified
2359 * if the value is not found.
2360 */
2361
2362 static void OLEUTL_ReadRegistryDWORDValue(
2363 HKEY regKey,
2364 DWORD* pdwValue)
2365 {
2366 WCHAR buffer[20];
2367 DWORD cbData = sizeof(buffer);
2368 DWORD dwKeyType;
2369 LONG lres;
2370
2371 lres = RegQueryValueExW(regKey,
2372 emptyW,
2373 NULL,
2374 &dwKeyType,
2375 (LPBYTE)buffer,
2376 &cbData);
2377
2378 if (lres==ERROR_SUCCESS)
2379 {
2380 switch (dwKeyType)
2381 {
2382 case REG_DWORD:
2383 *pdwValue = *(DWORD*)buffer;
2384 break;
2385 case REG_EXPAND_SZ:
2386 case REG_MULTI_SZ:
2387 case REG_SZ:
2388 *pdwValue = (DWORD)strtoulW(buffer, NULL, 10);
2389 break;
2390 }
2391 }
2392 }
2393
2394 /******************************************************************************
2395 * OleDraw (OLE32.@)
2396 *
2397 * The operation of this function is documented literally in the WinAPI
2398 * documentation to involve a QueryInterface for the IViewObject interface,
2399 * followed by a call to IViewObject::Draw.
2400 */
2401 HRESULT WINAPI OleDraw(
2402 IUnknown *pUnk,
2403 DWORD dwAspect,
2404 HDC hdcDraw,
2405 LPCRECT rect)
2406 {
2407 HRESULT hres;
2408 IViewObject *viewobject;
2409
2410 if (!pUnk) return E_INVALIDARG;
2411
2412 hres = IUnknown_QueryInterface(pUnk,
2413 &IID_IViewObject,
2414 (void**)&viewobject);
2415 if (SUCCEEDED(hres))
2416 {
2417 hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, (RECTL*)rect, 0, 0, 0);
2418 IViewObject_Release(viewobject);
2419 return hres;
2420 }
2421 else
2422 return DV_E_NOIVIEWOBJECT;
2423 }
2424
2425 /***********************************************************************
2426 * OleTranslateAccelerator [OLE32.@]
2427 */
2428 HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame,
2429 LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg)
2430 {
2431 WORD wID;
2432
2433 TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg);
2434
2435 if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID))
2436 return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID);
2437
2438 return S_FALSE;
2439 }
2440
2441 /******************************************************************************
2442 * OleCreate [OLE32.@]
2443 *
2444 */
2445 HRESULT WINAPI OleCreate(
2446 REFCLSID rclsid,
2447 REFIID riid,
2448 DWORD renderopt,
2449 LPFORMATETC pFormatEtc,
2450 LPOLECLIENTSITE pClientSite,
2451 LPSTORAGE pStg,
2452 LPVOID* ppvObj)
2453 {
2454 HRESULT hres;
2455 IUnknown * pUnk = NULL;
2456 IOleObject *pOleObject = NULL;
2457
2458 TRACE("(%s, %s, %d, %p, %p, %p, %p)\n", debugstr_guid(rclsid),
2459 debugstr_guid(riid), renderopt, pFormatEtc, pClientSite, pStg, ppvObj);
2460
2461 hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, riid, (LPVOID*)&pUnk);
2462
2463 if (SUCCEEDED(hres))
2464 hres = IStorage_SetClass(pStg, rclsid);
2465
2466 if (pClientSite && SUCCEEDED(hres))
2467 {
2468 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (LPVOID*)&pOleObject);
2469 if (SUCCEEDED(hres))
2470 {
2471 DWORD dwStatus;
2472 IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
2473 }
2474 }
2475
2476 if (SUCCEEDED(hres))
2477 {
2478 IPersistStorage * pPS;
2479 if (SUCCEEDED((hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (LPVOID*)&pPS))))
2480 {
2481 TRACE("trying to set stg %p\n", pStg);
2482 hres = IPersistStorage_InitNew(pPS, pStg);
2483 TRACE("-- result 0x%08x\n", hres);
2484 IPersistStorage_Release(pPS);
2485 }
2486 }
2487
2488 if (pClientSite && SUCCEEDED(hres))
2489 {
2490 TRACE("trying to set clientsite %p\n", pClientSite);
2491 hres = IOleObject_SetClientSite(pOleObject, pClientSite);
2492 TRACE("-- result 0x%08x\n", hres);
2493 }
2494
2495 if (pOleObject)
2496 IOleObject_Release(pOleObject);
2497
2498 if (((renderopt == OLERENDER_DRAW) || (renderopt == OLERENDER_FORMAT)) &&
2499 SUCCEEDED(hres))
2500 {
2501 hres = OleRun(pUnk);
2502 if (SUCCEEDED(hres))
2503 {
2504 IOleCache *pOleCache;
2505
2506 if (SUCCEEDED(IUnknown_QueryInterface(pUnk, &IID_IOleCache, (void **)&pOleCache)))
2507 {
2508 DWORD dwConnection;
2509 if (renderopt == OLERENDER_DRAW && !pFormatEtc) {
2510 FORMATETC pfe;
2511 pfe.cfFormat = 0;
2512 pfe.ptd = NULL;
2513 pfe.dwAspect = DVASPECT_CONTENT;
2514 pfe.lindex = -1;
2515 pfe.tymed = TYMED_NULL;
2516 hres = IOleCache_Cache(pOleCache, &pfe, ADVF_PRIMEFIRST, &dwConnection);
2517 }
2518 else
2519 hres = IOleCache_Cache(pOleCache, pFormatEtc, ADVF_PRIMEFIRST, &dwConnection);
2520 IOleCache_Release(pOleCache);
2521 }
2522 }
2523 }
2524
2525 if (FAILED(hres) && pUnk)
2526 {
2527 IUnknown_Release(pUnk);
2528 pUnk = NULL;
2529 }
2530
2531 *ppvObj = pUnk;
2532
2533 TRACE("-- %p\n", pUnk);
2534 return hres;
2535 }
2536
2537 /******************************************************************************
2538 * OleGetAutoConvert [OLE32.@]
2539 */
2540 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
2541 {
2542 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2543 HKEY hkey = NULL;
2544 WCHAR buf[CHARS_IN_GUID];
2545 LONG len;
2546 HRESULT res = S_OK;
2547
2548 res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey);
2549 if (FAILED(res))
2550 goto done;
2551
2552 len = sizeof(buf);
2553 if (RegQueryValueW(hkey, NULL, buf, &len))
2554 {
2555 res = REGDB_E_KEYMISSING;
2556 goto done;
2557 }
2558 res = CLSIDFromString(buf, pClsidNew);
2559 done:
2560 if (hkey) RegCloseKey(hkey);
2561 return res;
2562 }
2563
2564 /******************************************************************************
2565 * OleSetAutoConvert [OLE32.@]
2566 */
2567 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
2568 {
2569 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0};
2570 HKEY hkey = NULL;
2571 WCHAR szClsidNew[CHARS_IN_GUID];
2572 HRESULT res = S_OK;
2573
2574 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2575
2576 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
2577 if (FAILED(res))
2578 goto done;
2579 StringFromGUID2(clsidNew, szClsidNew, CHARS_IN_GUID);
2580 if (RegSetValueW(hkey, wszAutoConvertTo, REG_SZ, szClsidNew, (strlenW(szClsidNew)+1) * sizeof(WCHAR)))
2581 {
2582 res = REGDB_E_WRITEREGDB;
2583 goto done;
2584 }
2585
2586 done:
2587 if (hkey) RegCloseKey(hkey);
2588 return res;
2589 }
2590
2591 /******************************************************************************
2592 * OleDoAutoConvert [OLE32.@]
2593 */
2594 HRESULT WINAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew)
2595 {
2596 WCHAR *user_type_old, *user_type_new;
2597 CLIPFORMAT cf;
2598 STATSTG stat;
2599 CLSID clsid;
2600 HRESULT hr;
2601
2602 TRACE("(%p, %p)\n", pStg, pClsidNew);
2603
2604 *pClsidNew = CLSID_NULL;
2605 if(!pStg)
2606 return E_INVALIDARG;
2607 hr = IStorage_Stat(pStg, &stat, STATFLAG_NONAME);
2608 if(FAILED(hr))
2609 return hr;
2610
2611 *pClsidNew = stat.clsid;
2612 hr = OleGetAutoConvert(&stat.clsid, &clsid);
2613 if(FAILED(hr))
2614 return hr;
2615
2616 hr = IStorage_SetClass(pStg, &clsid);
2617 if(FAILED(hr))
2618 return hr;
2619
2620 hr = ReadFmtUserTypeStg(pStg, &cf, &user_type_old);
2621 if(FAILED(hr)) {
2622 cf = 0;
2623 user_type_new = NULL;
2624 }
2625
2626 hr = OleRegGetUserType(&clsid, USERCLASSTYPE_FULL, &user_type_new);
2627 if(FAILED(hr))
2628 user_type_new = NULL;
2629
2630 hr = WriteFmtUserTypeStg(pStg, cf, user_type_new);
2631 CoTaskMemFree(user_type_new);
2632 if(FAILED(hr))
2633 {
2634 CoTaskMemFree(user_type_old);
2635 IStorage_SetClass(pStg, &stat.clsid);
2636 return hr;
2637 }
2638
2639 hr = SetConvertStg(pStg, TRUE);
2640 if(FAILED(hr))
2641 {
2642 WriteFmtUserTypeStg(pStg, cf, user_type_old);
2643 IStorage_SetClass(pStg, &stat.clsid);
2644 }
2645 else
2646 *pClsidNew = clsid;
2647 CoTaskMemFree(user_type_old);
2648 return hr;
2649 }
2650
2651 /******************************************************************************
2652 * OleIsRunning [OLE32.@]
2653 */
2654 BOOL WINAPI OleIsRunning(LPOLEOBJECT object)
2655 {
2656 IRunnableObject *pRunnable;
2657 HRESULT hr;
2658 BOOL running;
2659
2660 TRACE("(%p)\n", object);
2661
2662 if (!object) return FALSE;
2663
2664 hr = IOleObject_QueryInterface(object, &IID_IRunnableObject, (void **)&pRunnable);
2665 if (FAILED(hr))
2666 return TRUE;
2667 running = IRunnableObject_IsRunning(pRunnable);
2668 IRunnableObject_Release(pRunnable);
2669 return running;
2670 }
2671
2672 /***********************************************************************
2673 * OleNoteObjectVisible [OLE32.@]
2674 */
2675 HRESULT WINAPI OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL bVisible)
2676 {
2677 TRACE("(%p, %s)\n", pUnknown, bVisible ? "TRUE" : "FALSE");
2678 return CoLockObjectExternal(pUnknown, bVisible, TRUE);
2679 }
2680
2681
2682 /***********************************************************************
2683 * OLE_FreeClipDataArray [internal]
2684 *
2685 * NOTES:
2686 * frees the data associated with an array of CLIPDATAs
2687 */
2688 static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray)
2689 {
2690 ULONG i;
2691 for (i = 0; i < count; i++)
2692 CoTaskMemFree(pClipDataArray[i].pClipData);
2693 }
2694
2695 /***********************************************************************
2696 * PropSysAllocString [OLE32.@]
2697 * NOTES
2698 * Forward to oleaut32.
2699 */
2700 BSTR WINAPI PropSysAllocString(LPCOLESTR str)
2701 {
2702 return SysAllocString(str);
2703 }
2704
2705 /***********************************************************************
2706 * PropSysFreeString [OLE32.@]
2707 * NOTES
2708 * Forward to oleaut32.
2709 */
2710 void WINAPI PropSysFreeString(LPOLESTR str)
2711 {
2712 SysFreeString(str);
2713 }
2714
2715 /******************************************************************************
2716 * Check if a PROPVARIANT's type is valid.
2717 */
2718 static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt)
2719 {
2720 switch (vt)
2721 {
2722 case VT_EMPTY:
2723 case VT_NULL:
2724 case VT_I1:
2725 case VT_I2:
2726 case VT_I4:
2727 case VT_I8:
2728 case VT_R4:
2729 case VT_R8:
2730 case VT_CY:
2731 case VT_DATE:
2732 case VT_BSTR:
2733 case VT_ERROR:
2734 case VT_BOOL:
2735 case VT_DECIMAL:
2736 case VT_UI1:
2737 case VT_UI2:
2738 case VT_UI4:
2739 case VT_UI8:
2740 case VT_INT:
2741 case VT_UINT:
2742 case VT_LPSTR:
2743 case VT_LPWSTR:
2744 case VT_FILETIME:
2745 case VT_BLOB:
2746 case VT_DISPATCH:
2747 case VT_UNKNOWN:
2748 case VT_STREAM:
2749 case VT_STORAGE:
2750 case VT_STREAMED_OBJECT:
2751 case VT_STORED_OBJECT:
2752 case VT_BLOB_OBJECT:
2753 case VT_CF:
2754 case VT_CLSID:
2755 case VT_I1|VT_VECTOR:
2756 case VT_I2|VT_VECTOR:
2757 case VT_I4|VT_VECTOR:
2758 case VT_I8|VT_VECTOR:
2759 case VT_R4|VT_VECTOR:
2760 case VT_R8|VT_VECTOR:
2761 case VT_CY|VT_VECTOR:
2762 case VT_DATE|VT_VECTOR:
2763 case VT_BSTR|VT_VECTOR:
2764 case VT_ERROR|VT_VECTOR:
2765 case VT_BOOL|VT_VECTOR:
2766 case VT_VARIANT|VT_VECTOR:
2767 case VT_UI1|VT_VECTOR:
2768 case VT_UI2|VT_VECTOR:
2769 case VT_UI4|VT_VECTOR:
2770 case VT_UI8|VT_VECTOR:
2771 case VT_LPSTR|VT_VECTOR:
2772 case VT_LPWSTR|VT_VECTOR:
2773 case VT_FILETIME|VT_VECTOR:
2774 case VT_CF|VT_VECTOR:
2775 case VT_CLSID|VT_VECTOR:
2776 return S_OK;
2777 }
2778 WARN("Bad type %d\n", vt);
2779 return STG_E_INVALIDPARAMETER;
2780 }
2781
2782 /***********************************************************************
2783 * PropVariantClear [OLE32.@]
2784 */
2785 HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */
2786 {
2787 HRESULT hr;
2788
2789 TRACE("(%p)\n", pvar);
2790
2791 if (!pvar)
2792 return S_OK;
2793
2794 hr = PROPVARIANT_ValidateType(pvar->vt);
2795 if (FAILED(hr))
2796 {
2797 memset(pvar, 0, sizeof(*pvar));
2798 return hr;
2799 }
2800
2801 switch(pvar->vt)
2802 {
2803 case VT_EMPTY:
2804 case VT_NULL:
2805 case VT_I1:
2806 case VT_I2:
2807 case VT_I4:
2808 case VT_I8:
2809 case VT_R4:
2810 case VT_R8:
2811 case VT_CY:
2812 case VT_DATE:
2813 case VT_ERROR:
2814 case VT_BOOL:
2815 case VT_DECIMAL:
2816 case VT_UI1:
2817 case VT_UI2:
2818 case VT_UI4:
2819 case VT_UI8:
2820 case VT_INT:
2821 case VT_UINT:
2822 case VT_FILETIME:
2823 break;
2824 case VT_DISPATCH:
2825 case VT_UNKNOWN:
2826 case VT_STREAM:
2827 case VT_STREAMED_OBJECT:
2828 case VT_STORAGE:
2829 case VT_STORED_OBJECT:
2830 if (pvar->u.pStream)
2831 IStream_Release(pvar->u.pStream);
2832 break;
2833 case VT_CLSID:
2834 case VT_LPSTR:
2835 case VT_LPWSTR:
2836 /* pick an arbitrary typed pointer - we don't care about the type
2837 * as we are just freeing it */
2838 CoTaskMemFree(pvar->u.puuid);
2839 break;
2840 case VT_BLOB:
2841 case VT_BLOB_OBJECT:
2842 CoTaskMemFree(pvar->u.blob.pBlobData);
2843 break;
2844 case VT_BSTR:
2845 PropSysFreeString(pvar->u.bstrVal);
2846 break;
2847 case VT_CF:
2848 if (pvar->u.pclipdata)
2849 {
2850 OLE_FreeClipDataArray(1, pvar->u.pclipdata);
2851 CoTaskMemFree(pvar->u.pclipdata);
2852 }
2853 break;
2854 default:
2855 if (pvar->vt & VT_VECTOR)
2856 {
2857 ULONG i;
2858
2859 switch (pvar->vt & ~VT_VECTOR)
2860 {
2861 case VT_VARIANT:
2862 FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems);
2863 break;
2864 case VT_CF:
2865 OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems);
2866 break;
2867 case VT_BSTR:
2868 for (i = 0; i < pvar->u.cabstr.cElems; i++)
2869 PropSysFreeString(pvar->u.cabstr.pElems[i]);
2870 break;
2871 case VT_LPSTR:
2872 for (i = 0; i < pvar->u.calpstr.cElems; i++)
2873 CoTaskMemFree(pvar->u.calpstr.pElems[i]);
2874 break;
2875 case VT_LPWSTR:
2876 for (i = 0; i < pvar->u.calpwstr.cElems; i++)
2877 CoTaskMemFree(pvar->u.calpwstr.pElems[i]);
2878 break;
2879 }
2880 if (pvar->vt & ~VT_VECTOR)
2881 {
2882 /* pick an arbitrary VT_VECTOR structure - they all have the same
2883 * memory layout */
2884 CoTaskMemFree(pvar->u.capropvar.pElems);
2885 }
2886 }
2887 else
2888 {
2889 WARN("Invalid/unsupported type %d\n", pvar->vt);
2890 hr = STG_E_INVALIDPARAMETER;
2891 }
2892 }
2893
2894 memset(pvar, 0, sizeof(*pvar));
2895 return hr;
2896 }
2897
2898 /***********************************************************************
2899 * PropVariantCopy [OLE32.@]
2900 */
2901 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, /* [out] */
2902 const PROPVARIANT *pvarSrc) /* [in] */
2903 {
2904 ULONG len;
2905 HRESULT hr;
2906
2907 TRACE("(%p, %p vt %04x)\n", pvarDest, pvarSrc, pvarSrc->vt);
2908
2909 hr = PROPVARIANT_ValidateType(pvarSrc->vt);
2910 if (FAILED(hr))
2911 return DISP_E_BADVARTYPE;
2912
2913 /* this will deal with most cases */
2914 *pvarDest = *pvarSrc;
2915
2916 switch(pvarSrc->vt)
2917 {
2918 case VT_EMPTY:
2919 case VT_NULL:
2920 case VT_I1:
2921 case VT_UI1:
2922 case VT_I2:
2923 case VT_UI2:
2924 case VT_BOOL:
2925 case VT_DECIMAL:
2926 case VT_I4:
2927 case VT_UI4:
2928 case VT_R4:
2929 case VT_ERROR:
2930 case VT_I8:
2931 case VT_UI8:
2932 case VT_INT:
2933 case VT_UINT:
2934 case VT_R8:
2935 case VT_CY:
2936 case VT_DATE:
2937 case VT_FILETIME:
2938 break;
2939 case VT_DISPATCH:
2940 case VT_UNKNOWN:
2941 case VT_STREAM:
2942 case VT_STREAMED_OBJECT:
2943 case VT_STORAGE:
2944 case VT_STORED_OBJECT:
2945 if (pvarDest->u.pStream)
2946 IStream_AddRef(pvarDest->u.pStream);
2947 break;
2948 case VT_CLSID:
2949 pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));
2950 *pvarDest->u.puuid = *pvarSrc->u.puuid;
2951 break;
2952 case VT_LPSTR:
2953 if (pvarSrc->u.pszVal)
2954 {
2955 len = strlen(pvarSrc->u.pszVal);
2956 pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
2957 CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR));
2958 }
2959 break;
2960 case VT_LPWSTR:
2961 if (pvarSrc->u.pwszVal)
2962 {
2963 len = lstrlenW(pvarSrc->u.pwszVal);
2964 pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
2965 CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR));
2966 }
2967 break;
2968 case VT_BLOB:
2969 case VT_BLOB_OBJECT:
2970 if (pvarSrc->u.blob.pBlobData)
2971 {
2972 len = pvarSrc->u.blob.cbSize;
2973 pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len);
2974 CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len);
2975 }
2976 break;
2977 case VT_BSTR:
2978 pvarDest->u.bstrVal = PropSysAllocString(pvarSrc->u.bstrVal);
2979 break;
2980 case VT_CF:
2981 if (pvarSrc->u.pclipdata)
2982 {
2983 len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt);
2984 pvarDest->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
2985 pvarDest->u.pclipdata->cbSize = pvarSrc->u.pclipdata->cbSize;
2986 pvarDest->u.pclipdata->ulClipFmt = pvarSrc->u.pclipdata->ulClipFmt;
2987 pvarDest->u.pclipdata->pClipData = CoTaskMemAlloc(len);
2988 CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len);
2989 }
2990 break;
2991 default:
2992 if (pvarSrc->vt & VT_VECTOR)
2993 {
2994 int elemSize;
2995 ULONG i;
2996
2997 switch(pvarSrc->vt & ~VT_VECTOR)
2998 {
2999 case VT_I1: elemSize = sizeof(pvarSrc->u.cVal); break;
3000 case VT_UI1: elemSize = sizeof(pvarSrc->u.bVal); break;
3001 case VT_I2: elemSize = sizeof(pvarSrc->u.iVal); break;
3002 case VT_UI2: elemSize = sizeof(pvarSrc->u.uiVal); break;
3003 case VT_BOOL: elemSize = sizeof(pvarSrc->u.boolVal); break;
3004 case VT_I4: elemSize = sizeof(pvarSrc->u.lVal); break;
3005 case VT_UI4: elemSize = sizeof(pvarSrc->u.ulVal); break;
3006 case VT_R4: elemSize = sizeof(pvarSrc->u.fltVal); break;
3007 case VT_R8: elemSize = sizeof(pvarSrc->u.dblVal); break;
3008 case VT_ERROR: elemSize = sizeof(pvarSrc->u.scode); break;
3009 case VT_I8: elemSize = sizeof(pvarSrc->u.hVal); break;
3010 case VT_UI8: elemSize = sizeof(pvarSrc->u.uhVal); break;
3011 case VT_CY: elemSize = sizeof(pvarSrc->u.cyVal); break;
3012 case VT_DATE: elemSize = sizeof(pvarSrc->u.date); break;
3013 case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break;
3014 case VT_CLSID: elemSize = sizeof(*pvarSrc->u.puuid); break;
3015 case VT_CF: elemSize = sizeof(*pvarSrc->u.pclipdata); break;
3016 case VT_BSTR: elemSize = sizeof(pvarSrc->u.bstrVal); break;
3017 case VT_LPSTR: elemSize = sizeof(pvarSrc->u.pszVal); break;
3018 case VT_LPWSTR: elemSize = sizeof(pvarSrc->u.pwszVal); break;
3019 case VT_VARIANT: elemSize = sizeof(*pvarSrc->u.pvarVal); break;
3020
3021 default:
3022 FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
3023 return E_INVALIDARG;
3024 }
3025 len = pvarSrc->u.capropvar.cElems;
3026 pvarDest->u.capropvar.pElems = len ? CoTaskMemAlloc(len * elemSize) : NULL;
3027 if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
3028 {
3029 for (i = 0; i < len; i++)
3030 PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]);
3031 }
3032 else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
3033 {
3034 FIXME("Copy clipformats\n");
3035 }
3036 else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
3037 {
3038 for (i = 0; i < len; i++)
3039 pvarDest->u.cabstr.pElems[i] = PropSysAllocString(pvarSrc->u.cabstr.pElems[i]);
3040 }
3041 else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
3042 {
3043 size_t strLen;
3044 for (i = 0; i < len; i++)
3045 {
3046 strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1;
3047 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
3048 memcpy(pvarDest->u.calpstr.pElems[i],
3049 pvarSrc->u.calpstr.pElems[i], strLen);
3050 }
3051 }
3052 else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
3053 {
3054 size_t strLen;
3055 for (i = 0; i < len; i++)
3056 {
3057 strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) *
3058 sizeof(WCHAR);
3059 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen);
3060 memcpy(pvarDest->u.calpstr.pElems[i],
3061 pvarSrc->u.calpstr.pElems[i], strLen);
3062 }
3063 }
3064 else
3065 CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize);
3066 }
3067 else
3068 WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
3069 }
3070
3071 return S_OK;
3072 }
3073
3074 /***********************************************************************
3075 * FreePropVariantArray [OLE32.@]
3076 */
3077 HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */
3078 PROPVARIANT *rgvars) /* [in/out] */
3079 {
3080 ULONG i;
3081
3082 TRACE("(%u, %p)\n", cVariants, rgvars);
3083
3084 if (!rgvars)
3085 return E_INVALIDARG;
3086
3087 for(i = 0; i < cVariants; i++)
3088 PropVariantClear(&rgvars[i]);
3089
3090 return S_OK;
3091 }
3092
3093 /******************************************************************************
3094 * DllDebugObjectRPCHook (OLE32.@)
3095 * turns on and off internal debugging, pointer is only used on macintosh
3096 */
3097
3098 BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)
3099 {
3100 FIXME("stub\n");
3101 return TRUE;
3102 }