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