source: trunk/src/ole32/ole2.c@ 10432

Last change on this file since 10432 was 10432, checked in by bird, 22 years ago

#682: Drag & Drop fixes. Some Wine resync.

File size: 99.0 KB
Line 
1
2/*
3 * OLE2 library
4 *
5 * Copyright 1995 Martin von Loewis
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Noel Borthwick
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24#include "config.h"
25
26#include <assert.h>
27#include <stdlib.h>
28#include <stdio.h>
29#include <string.h>
30
31#include "commctrl.h"
32#include "ole2.h"
33#include "ole2ver.h"
34#include "windef.h"
35#include "winbase.h"
36#include "winerror.h"
37#include "winuser.h"
38#include "winreg.h"
39
40#include "wine/obj_clientserver.h"
41#ifdef __WIN32OS2__ /* we've got older headers! */
42#include "wine/obj_propertystorage.h"
43#include "wine/obj_oleaut.h"
44#endif
45#include "wine/winbase16.h"
46#include "wine/wingdi16.h"
47#include "wine/winuser16.h"
48#include "ole32_main.h"
49
50#include "wine/debug.h"
51
52WINE_DEFAULT_DEBUG_CHANNEL(ole);
53WINE_DECLARE_DEBUG_CHANNEL(accel);
54
55/******************************************************************************
56 * These are static/global variables and internal data structures that the
57 * OLE module uses to maintain it's state.
58 */
59typedef struct tagDropTargetNode
60{
61 HWND hwndTarget;
62 IDropTarget* dropTarget;
63#ifdef __WIN32OS2__
64 BOOL fDragEnter;
65 DWORD dwEffect;
66 IDataObject * pDataObject;
67#endif
68 struct tagDropTargetNode* prevDropTarget;
69 struct tagDropTargetNode* nextDropTarget;
70} DropTargetNode;
71
72typedef struct tagTrackerWindowInfo
73{
74 IDataObject* dataObject;
75 IDropSource* dropSource;
76 DWORD dwOKEffect;
77 DWORD* pdwEffect;
78 BOOL trackingDone;
79 HRESULT returnValue;
80
81 BOOL escPressed;
82 HWND curTargetHWND; /* window the mouse is hovering over */
83 HWND curDragTargetHWND; /* might be a ancestor of curTargetHWND */
84 IDropTarget* curDragTarget;
85} TrackerWindowInfo;
86
87typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */
88{
89 HWND hwndFrame; /* The containers frame window */
90 HWND hwndActiveObject; /* The active objects window */
91 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */
92 HMENU hmenuCombined; /* The combined menu */
93 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */
94} OleMenuDescriptor;
95
96typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */
97{
98 DWORD tid; /* Thread Id */
99 HANDLE hHeap; /* Heap this is allocated from */
100 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */
101 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */
102 struct tagOleMenuHookItem *next;
103} OleMenuHookItem;
104
105static OleMenuHookItem *hook_list;
106
107/*
108 * This is the lock count on the OLE library. It is controlled by the
109 * OLEInitialize/OLEUninitialize methods.
110 */
111static ULONG OLE_moduleLockCount = 0;
112
113/*
114 * Name of our registered window class.
115 */
116static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
117
118/*
119 * This is the head of the Drop target container.
120 */
121static DropTargetNode* targetListHead = NULL;
122
123/******************************************************************************
124 * These are the prototypes of miscelaneous utility methods
125 */
126static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
127
128/******************************************************************************
129 * These are the prototypes of the utility methods used to manage a shared menu
130 */
131#ifdef __WIN32OS2__
132/* Changed () -> (void) as () isn't a prototype good enought for VAC. */
133#endif
134static void OLEMenu_Initialize(void);
135static void OLEMenu_UnInitialize(void);
136BOOL OLEMenu_InstallHooks( DWORD tid );
137BOOL OLEMenu_UnInstallHooks( DWORD tid );
138OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
139static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
140BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
141LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
142LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
143
144/******************************************************************************
145 * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
146 */
147void OLEClipbrd_UnInitialize(void);
148void OLEClipbrd_Initialize(void);
149
150/******************************************************************************
151 * These are the prototypes of the utility methods used for OLE Drag n Drop
152 */
153static void OLEDD_Initialize(void);
154static void OLEDD_UnInitialize(void);
155static void OLEDD_InsertDropTarget(
156 DropTargetNode* nodeToAdd);
157static DropTargetNode* OLEDD_ExtractDropTarget(
158 HWND hwndOfTarget);
159static DropTargetNode* OLEDD_FindDropTarget(
160 HWND hwndOfTarget);
161static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
162 HWND hwnd,
163 UINT uMsg,
164 WPARAM wParam,
165 LPARAM lParam);
166static void OLEDD_TrackMouseMove(
167 TrackerWindowInfo* trackerInfo,
168 POINT mousePos,
169 DWORD keyState);
170static void OLEDD_TrackStateChange(
171 TrackerWindowInfo* trackerInfo,
172 POINT mousePos,
173 DWORD keyState);
174static DWORD OLEDD_GetButtonState(void);
175
176#ifdef __WIN32OS2__
177static IDropTarget *IDropTarget_Constructor(void);
178
179HWND hwndTracker = 0;
180#endif
181
182/******************************************************************************
183 * OleBuildVersion [OLE2.1]
184 * OleBuildVersion [OLE32.@]
185 */
186DWORD WINAPI OleBuildVersion(void)
187{
188 TRACE("Returning version %d, build %d.\n", rmm, rup);
189 return (rmm<<16)+rup;
190}
191
192/***********************************************************************
193 * OleInitialize (OLE2.2)
194 * OleInitialize (OLE32.@)
195 */
196HRESULT WINAPI OleInitialize(LPVOID reserved)
197{
198 HRESULT hr;
199
200 TRACE("(%p)\n", reserved);
201
202 /*
203 * The first duty of the OleInitialize is to initialize the COM libraries.
204 */
205 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
206
207 /*
208 * If the CoInitializeEx call failed, the OLE libraries can't be
209 * initialized.
210 */
211 if (FAILED(hr))
212 return hr;
213
214 /*
215 * Then, it has to initialize the OLE specific modules.
216 * This includes:
217 * Clipboard
218 * Drag and Drop
219 * Object linking and Embedding
220 * In-place activation
221 */
222 if (OLE_moduleLockCount==0)
223 {
224 /*
225 * Initialize the libraries.
226 */
227 TRACE("() - Initializing the OLE libraries\n");
228
229 /*
230 * OLE Clipboard
231 */
232 OLEClipbrd_Initialize();
233
234 /*
235 * Drag and Drop
236 */
237 OLEDD_Initialize();
238
239 /*
240 * OLE shared menu
241 */
242 OLEMenu_Initialize();
243 }
244
245 /*
246 * Then, we increase the lock count on the OLE module.
247 */
248 OLE_moduleLockCount++;
249
250 return hr;
251}
252
253/******************************************************************************
254 * CoGetCurrentProcess [COMPOBJ.34]
255 * CoGetCurrentProcess [OLE32.@]
256 *
257 * NOTES
258 * Is DWORD really the correct return type for this function?
259 */
260DWORD WINAPI CoGetCurrentProcess(void)
261{
262 return GetCurrentProcessId();
263}
264
265/******************************************************************************
266 * OleUninitialize [OLE2.3]
267 * OleUninitialize [OLE32.@]
268 */
269void WINAPI OleUninitialize(void)
270{
271 TRACE("()\n");
272
273 /*
274 * Decrease the lock count on the OLE module.
275 */
276 OLE_moduleLockCount--;
277
278 /*
279 * If we hit the bottom of the lock stack, free the libraries.
280 */
281 if (OLE_moduleLockCount==0)
282 {
283 /*
284 * Actually free the libraries.
285 */
286 TRACE("() - Freeing the last reference count\n");
287
288 /*
289 * OLE Clipboard
290 */
291 OLEClipbrd_UnInitialize();
292
293 /*
294 * Drag and Drop
295 */
296 OLEDD_UnInitialize();
297
298 /*
299 * OLE shared menu
300 */
301 OLEMenu_UnInitialize();
302 }
303
304 /*
305 * Then, uninitialize the COM libraries.
306 */
307 CoUninitialize();
308}
309
310/******************************************************************************
311 * CoRegisterMessageFilter [OLE32.@]
312 */
313HRESULT WINAPI CoRegisterMessageFilter(
314 LPMESSAGEFILTER lpMessageFilter, /* [in] Pointer to interface */
315 LPMESSAGEFILTER *lplpMessageFilter /* [out] Indirect pointer to prior instance if non-NULL */
316) {
317 FIXME("stub\n");
318 if (lplpMessageFilter) {
319 *lplpMessageFilter = NULL;
320 }
321 return S_OK;
322}
323
324/******************************************************************************
325 * OleInitializeWOW [OLE32.@]
326 */
327HRESULT WINAPI OleInitializeWOW(DWORD x) {
328 FIXME("(0x%08lx),stub!\n",x);
329 return 0;
330}
331
332/***********************************************************************
333 * RegisterDragDrop (OLE32.@)
334 */
335HRESULT WINAPI RegisterDragDrop(
336 HWND hwnd,
337 LPDROPTARGET pDropTarget)
338{
339 DropTargetNode* dropTargetInfo;
340
341 TRACE("(%p,%p)\n", hwnd, pDropTarget);
342
343 /*
344 * First, check if the window is already registered.
345 */
346 dropTargetInfo = OLEDD_FindDropTarget(hwnd);
347
348 if (dropTargetInfo!=NULL)
349 return DRAGDROP_E_ALREADYREGISTERED;
350
351 /*
352 * If it's not there, we can add it. We first create a node for it.
353 */
354 dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
355
356 if (dropTargetInfo==NULL)
357 return E_OUTOFMEMORY;
358
359 dropTargetInfo->hwndTarget = hwnd;
360 dropTargetInfo->prevDropTarget = NULL;
361 dropTargetInfo->nextDropTarget = NULL;
362
363#ifdef __WIN32OS2__
364 dropTargetInfo->pDataObject = NULL;
365 dropTargetInfo->fDragEnter = FALSE;
366 dropTargetInfo->dwEffect = 0;
367#endif
368 /*
369 * Don't forget that this is an interface pointer, need to nail it down since
370 * we keep a copy of it.
371 */
372 dropTargetInfo->dropTarget = pDropTarget;
373 IDropTarget_AddRef(dropTargetInfo->dropTarget);
374
375 OLEDD_InsertDropTarget(dropTargetInfo);
376
377 return S_OK;
378}
379
380/***********************************************************************
381 * RevokeDragDrop (OLE32.@)
382 */
383HRESULT WINAPI RevokeDragDrop(
384 HWND hwnd)
385{
386 DropTargetNode* dropTargetInfo;
387
388 TRACE("(%p)\n", hwnd);
389
390 /*
391 * First, check if the window is already registered.
392 */
393 dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);
394
395 /*
396 * If it ain't in there, it's an error.
397 */
398 if (dropTargetInfo==NULL)
399 return DRAGDROP_E_NOTREGISTERED;
400
401#ifdef __WIN32OS2__
402 if(dropTargetInfo->pDataObject) {
403 IDataObject_Release(dropTargetInfo->pDataObject);
404 }
405#endif
406
407 /*
408 * If it's in there, clean-up it's used memory and
409 * references
410 */
411 IDropTarget_Release(dropTargetInfo->dropTarget);
412 HeapFree(GetProcessHeap(), 0, dropTargetInfo);
413
414 return S_OK;
415}
416
417/***********************************************************************
418 * OleRegGetUserType (OLE32.@)
419 *
420 * This implementation of OleRegGetUserType ignores the dwFormOfType
421 * parameter and always returns the full name of the object. This is
422 * not too bad since this is the case for many objects because of the
423 * way they are registered.
424 */
425HRESULT WINAPI OleRegGetUserType(
426 REFCLSID clsid,
427 DWORD dwFormOfType,
428 LPOLESTR* pszUserType)
429{
430 char keyName[60];
431 DWORD dwKeyType;
432 DWORD cbData;
433 HKEY clsidKey;
434 LONG hres;
435 LPBYTE buffer;
436 HRESULT retVal;
437 /*
438 * Initialize the out parameter.
439 */
440 *pszUserType = NULL;
441
442 /*
443 * Build the key name we're looking for
444 */
445 sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
446 clsid->Data1, clsid->Data2, clsid->Data3,
447 clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
448 clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
449
450 TRACE("(%s, %ld, %p)\n", keyName, dwFormOfType, pszUserType);
451
452 /*
453 * Open the class id Key
454 */
455 hres = RegOpenKeyA(HKEY_CLASSES_ROOT,
456 keyName,
457 &clsidKey);
458
459 if (hres != ERROR_SUCCESS)
460 return REGDB_E_CLASSNOTREG;
461
462 /*
463 * Retrieve the size of the name string.
464 */
465 cbData = 0;
466
467 hres = RegQueryValueExA(clsidKey,
468 "",
469 NULL,
470 &dwKeyType,
471 NULL,
472 &cbData);
473
474 if (hres!=ERROR_SUCCESS)
475 {
476 RegCloseKey(clsidKey);
477 return REGDB_E_READREGDB;
478 }
479
480 /*
481 * Allocate a buffer for the registry value.
482 */
483 *pszUserType = CoTaskMemAlloc(cbData*2);
484
485 if (*pszUserType==NULL)
486 {
487 RegCloseKey(clsidKey);
488 return E_OUTOFMEMORY;
489 }
490
491 buffer = HeapAlloc(GetProcessHeap(), 0, cbData);
492
493 if (buffer == NULL)
494 {
495 RegCloseKey(clsidKey);
496 CoTaskMemFree(*pszUserType);
497 *pszUserType=NULL;
498 return E_OUTOFMEMORY;
499 }
500
501 hres = RegQueryValueExA(clsidKey,
502 "",
503 NULL,
504 &dwKeyType,
505 buffer,
506 &cbData);
507
508 RegCloseKey(clsidKey);
509
510
511 if (hres!=ERROR_SUCCESS)
512 {
513 CoTaskMemFree(*pszUserType);
514 *pszUserType=NULL;
515
516 retVal = REGDB_E_READREGDB;
517 }
518 else
519 {
520 MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ );
521 retVal = S_OK;
522 }
523 HeapFree(GetProcessHeap(), 0, buffer);
524
525 return retVal;
526}
527
528/***********************************************************************
529 * DoDragDrop [OLE32.@]
530 */
531HRESULT WINAPI DoDragDrop (
532 IDataObject *pDataObject, /* [in] ptr to the data obj */
533 IDropSource* pDropSource, /* [in] ptr to the source obj */
534 DWORD dwOKEffect, /* [in] effects allowed by the source */
535 DWORD *pdwEffect) /* [out] ptr to effects of the source */
536{
537 TrackerWindowInfo trackerInfo;
538 HWND hwndTrackWindow;
539 MSG msg;
540
541 TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
542
543 /*
544 * Setup the drag n drop tracking window.
545 */
546 if (!IsValidInterface((LPUNKNOWN)pDropSource))
547 return E_INVALIDARG;
548
549 trackerInfo.dataObject = pDataObject;
550 trackerInfo.dropSource = pDropSource;
551 trackerInfo.dwOKEffect = dwOKEffect;
552 trackerInfo.pdwEffect = pdwEffect;
553 trackerInfo.trackingDone = FALSE;
554 trackerInfo.escPressed = FALSE;
555 trackerInfo.curDragTargetHWND = 0;
556 trackerInfo.curTargetHWND = 0;
557 trackerInfo.curDragTarget = 0;
558
559#ifdef __WIN32OS2__
560 IDataObject_AddRef(trackerInfo.dataObject);
561#endif
562
563 hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
564 "TrackerWindow",
565 WS_POPUP,
566 CW_USEDEFAULT, CW_USEDEFAULT,
567 CW_USEDEFAULT, CW_USEDEFAULT,
568 0,
569 0,
570 0,
571 (LPVOID)&trackerInfo);
572
573 if (hwndTrackWindow!=0)
574 {
575#ifdef __WIN32OS2__
576 hwndTracker = hwndTrackWindow;
577#endif
578
579 /*
580 * Capture the mouse input
581 */
582 SetCapture(hwndTrackWindow);
583
584 /*
585 * Pump messages. All mouse input should go the the capture window.
586 */
587 while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
588 {
589 if ( (msg.message >= WM_KEYFIRST) &&
590 (msg.message <= WM_KEYLAST) )
591 {
592#ifdef __WIN32OS2__
593 dprintf(("dragloop: key msg %x\n", msg.message));
594#endif
595 /*
596 * When keyboard messages are sent to windows on this thread, we
597 * want to ignore notify the drop source that the state changed.
598 * in the case of the Escape key, we also notify the drop source
599 * we give it a special meaning.
600 */
601 if ( (msg.message==WM_KEYDOWN) &&
602 (msg.wParam==VK_ESCAPE) )
603 {
604 trackerInfo.escPressed = TRUE;
605 }
606
607 /*
608 * Notify the drop source.
609 */
610 OLEDD_TrackStateChange(&trackerInfo,
611 msg.pt,
612 OLEDD_GetButtonState());
613 }
614 else
615 {
616#ifdef __WIN32OS2__
617 dprintf(("dragloop: dispmsg %x\n", msg.message));
618#endif
619 /*
620 * Dispatch the messages only when it's not a keyboard message.
621 */
622 DispatchMessageA(&msg);
623 }
624 }
625
626 /*
627 * Destroy the temporary window.
628 */
629 DestroyWindow(hwndTrackWindow);
630
631#ifdef __WIN32OS2__
632 IDataObject_Release(trackerInfo.dataObject);
633#endif
634
635 return trackerInfo.returnValue;
636 }
637
638#ifdef __WIN32OS2__
639 IDataObject_Release(trackerInfo.dataObject);
640#endif
641
642 return E_FAIL;
643}
644
645/***********************************************************************
646 * OleQueryLinkFromData [OLE32.@]
647 */
648HRESULT WINAPI OleQueryLinkFromData(
649 IDataObject* pSrcDataObject)
650{
651 FIXME("(%p),stub!\n", pSrcDataObject);
652 return S_OK;
653}
654
655/***********************************************************************
656 * OleRegGetMiscStatus [OLE32.@]
657 */
658HRESULT WINAPI OleRegGetMiscStatus(
659 REFCLSID clsid,
660 DWORD dwAspect,
661 DWORD* pdwStatus)
662{
663 char keyName[60];
664 HKEY clsidKey;
665 HKEY miscStatusKey;
666 HKEY aspectKey;
667 LONG result;
668
669 /*
670 * Initialize the out parameter.
671 */
672 *pdwStatus = 0;
673
674 /*
675 * Build the key name we're looking for
676 */
677 sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
678 clsid->Data1, clsid->Data2, clsid->Data3,
679 clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
680 clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
681
682 TRACE("(%s, %ld, %p)\n", keyName, dwAspect, pdwStatus);
683
684 /*
685 * Open the class id Key
686 */
687 result = RegOpenKeyA(HKEY_CLASSES_ROOT,
688 keyName,
689 &clsidKey);
690
691 if (result != ERROR_SUCCESS)
692 return REGDB_E_CLASSNOTREG;
693
694 /*
695 * Get the MiscStatus
696 */
697 result = RegOpenKeyA(clsidKey,
698 "MiscStatus",
699 &miscStatusKey);
700
701
702 if (result != ERROR_SUCCESS)
703 {
704 RegCloseKey(clsidKey);
705 return REGDB_E_READREGDB;
706 }
707
708 /*
709 * Read the default value
710 */
711 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
712
713 /*
714 * Open the key specific to the requested aspect.
715 */
716 sprintf(keyName, "%ld", dwAspect);
717
718 result = RegOpenKeyA(miscStatusKey,
719 keyName,
720 &aspectKey);
721
722 if (result == ERROR_SUCCESS)
723 {
724 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
725 RegCloseKey(aspectKey);
726 }
727
728 /*
729 * Cleanup
730 */
731 RegCloseKey(miscStatusKey);
732 RegCloseKey(clsidKey);
733
734 return S_OK;
735}
736
737/******************************************************************************
738 * OleSetContainedObject [OLE32.@]
739 */
740HRESULT WINAPI OleSetContainedObject(
741 LPUNKNOWN pUnknown,
742 BOOL fContained)
743{
744 IRunnableObject* runnable = NULL;
745 HRESULT hres;
746
747 TRACE("(%p,%x), stub!\n", pUnknown, fContained);
748
749 hres = IUnknown_QueryInterface(pUnknown,
750 &IID_IRunnableObject,
751 (void**)&runnable);
752
753 if (SUCCEEDED(hres))
754 {
755 hres = IRunnableObject_SetContainedObject(runnable, fContained);
756
757 IRunnableObject_Release(runnable);
758
759 return hres;
760 }
761
762 return S_OK;
763}
764
765/******************************************************************************
766 * OleLoad [OLE32.@]
767 */
768HRESULT WINAPI OleLoad(
769 LPSTORAGE pStg,
770 REFIID riid,
771 LPOLECLIENTSITE pClientSite,
772 LPVOID* ppvObj)
773{
774 IPersistStorage* persistStorage = NULL;
775 IOleObject* oleObject = NULL;
776 STATSTG storageInfo;
777 HRESULT hres;
778
779 TRACE("(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj);
780
781 /*
782 * TODO, Conversion ... OleDoAutoConvert
783 */
784
785 /*
786 * Get the class ID for the object.
787 */
788 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
789
790 /*
791 * Now, try and create the handler for the object
792 */
793 hres = CoCreateInstance(&storageInfo.clsid,
794 NULL,
795 CLSCTX_INPROC_HANDLER,
796 &IID_IOleObject,
797 (void**)&oleObject);
798
799 /*
800 * If that fails, as it will most times, load the default
801 * OLE handler.
802 */
803 if (FAILED(hres))
804 {
805 hres = OleCreateDefaultHandler(&storageInfo.clsid,
806 NULL,
807 &IID_IOleObject,
808 (void**)&oleObject);
809 }
810
811 /*
812 * If we couldn't find a handler... this is bad. Abort the whole thing.
813 */
814 if (FAILED(hres))
815 return hres;
816
817 /*
818 * Inform the new object of it's client site.
819 */
820 hres = IOleObject_SetClientSite(oleObject, pClientSite);
821
822 /*
823 * Initialize the object with it's IPersistStorage interface.
824 */
825 hres = IOleObject_QueryInterface(oleObject,
826 &IID_IPersistStorage,
827 (void**)&persistStorage);
828
829 if (SUCCEEDED(hres))
830 {
831 IPersistStorage_Load(persistStorage, pStg);
832
833 IPersistStorage_Release(persistStorage);
834 persistStorage = NULL;
835 }
836
837 /*
838 * Return the requested interface to the caller.
839 */
840 hres = IOleObject_QueryInterface(oleObject, riid, ppvObj);
841
842 /*
843 * Cleanup interfaces used internally
844 */
845 IOleObject_Release(oleObject);
846
847 return hres;
848}
849
850/***********************************************************************
851 * OleSave [OLE32.@]
852 */
853HRESULT WINAPI OleSave(
854 LPPERSISTSTORAGE pPS,
855 LPSTORAGE pStg,
856 BOOL fSameAsLoad)
857{
858 HRESULT hres;
859 CLSID objectClass;
860
861 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
862
863 /*
864 * First, we transfer the class ID (if available)
865 */
866 hres = IPersistStorage_GetClassID(pPS, &objectClass);
867
868 if (SUCCEEDED(hres))
869 {
870 WriteClassStg(pStg, &objectClass);
871 }
872
873 /*
874 * Then, we ask the object to save itself to the
875 * storage. If it is successful, we commit the storage.
876 */
877 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
878
879 if (SUCCEEDED(hres))
880 {
881 IStorage_Commit(pStg,
882 STGC_DEFAULT);
883 }
884
885 return hres;
886}
887
888
889/******************************************************************************
890 * OleLockRunning [OLE32.@]
891 */
892HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)
893{
894 IRunnableObject* runnable = NULL;
895 HRESULT hres;
896
897 TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);
898
899 hres = IUnknown_QueryInterface(pUnknown,
900 &IID_IRunnableObject,
901 (void**)&runnable);
902
903 if (SUCCEEDED(hres))
904 {
905 hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);
906
907 IRunnableObject_Release(runnable);
908
909 return hres;
910 }
911 else
912 return E_INVALIDARG;
913}
914
915
916/**************************************************************************
917 * Internal methods to manage the shared OLE menu in response to the
918 * OLE***MenuDescriptor API
919 */
920
921/***
922 * OLEMenu_Initialize()
923 *
924 * Initializes the OLEMENU data structures.
925 */
926static void OLEMenu_Initialize()
927{
928}
929
930/***
931 * OLEMenu_UnInitialize()
932 *
933 * Releases the OLEMENU data structures.
934 */
935static void OLEMenu_UnInitialize()
936{
937}
938
939/*************************************************************************
940 * OLEMenu_InstallHooks
941 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
942 *
943 * RETURNS: TRUE if message hooks were successfully installed
944 * FALSE on failure
945 */
946BOOL OLEMenu_InstallHooks( DWORD tid )
947{
948 OleMenuHookItem *pHookItem = NULL;
949
950 /* Create an entry for the hook table */
951 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
952 sizeof(OleMenuHookItem)) ) )
953 return FALSE;
954
955 pHookItem->tid = tid;
956 pHookItem->hHeap = GetProcessHeap();
957
958 /* Install a thread scope message hook for WH_GETMESSAGE */
959 pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
960 0, GetCurrentThreadId() );
961 if ( !pHookItem->GetMsg_hHook )
962 goto CLEANUP;
963
964 /* Install a thread scope message hook for WH_CALLWNDPROC */
965 pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
966 0, GetCurrentThreadId() );
967 if ( !pHookItem->CallWndProc_hHook )
968 goto CLEANUP;
969
970 /* Insert the hook table entry */
971 pHookItem->next = hook_list;
972 hook_list = pHookItem;
973
974 return TRUE;
975
976CLEANUP:
977 /* Unhook any hooks */
978 if ( pHookItem->GetMsg_hHook )
979 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
980 if ( pHookItem->CallWndProc_hHook )
981 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
982 /* Release the hook table entry */
983 HeapFree(pHookItem->hHeap, 0, pHookItem );
984
985 return FALSE;
986}
987
988/*************************************************************************
989 * OLEMenu_UnInstallHooks
990 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
991 *
992 * RETURNS: TRUE if message hooks were successfully installed
993 * FALSE on failure
994 */
995BOOL OLEMenu_UnInstallHooks( DWORD tid )
996{
997 OleMenuHookItem *pHookItem = NULL;
998 OleMenuHookItem **ppHook = &hook_list;
999
1000 while (*ppHook)
1001 {
1002 if ((*ppHook)->tid == tid)
1003 {
1004 pHookItem = *ppHook;
1005 *ppHook = pHookItem->next;
1006 break;
1007 }
1008 ppHook = &(*ppHook)->next;
1009 }
1010 if (!pHookItem) return FALSE;
1011
1012 /* Uninstall the hooks installed for this thread */
1013 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
1014 goto CLEANUP;
1015 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
1016 goto CLEANUP;
1017
1018 /* Release the hook table entry */
1019 HeapFree(pHookItem->hHeap, 0, pHookItem );
1020
1021 return TRUE;
1022
1023CLEANUP:
1024 /* Release the hook table entry */
1025 if (pHookItem)
1026 HeapFree(pHookItem->hHeap, 0, pHookItem );
1027
1028 return FALSE;
1029}
1030
1031/*************************************************************************
1032 * OLEMenu_IsHookInstalled
1033 * Tests if OLEMenu hooks have been installed for a thread
1034 *
1035 * RETURNS: The pointer and index of the hook table entry for the tid
1036 * NULL and -1 for the index if no hooks were installed for this thread
1037 */
1038OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
1039{
1040 OleMenuHookItem *pHookItem = NULL;
1041
1042 /* Do a simple linear search for an entry whose tid matches ours.
1043 * We really need a map but efficiency is not a concern here. */
1044 for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
1045 {
1046 if ( tid == pHookItem->tid )
1047 return pHookItem;
1048 }
1049
1050 return NULL;
1051}
1052
1053/***********************************************************************
1054 * OLEMenu_FindMainMenuIndex
1055 *
1056 * Used by OLEMenu API to find the top level group a menu item belongs to.
1057 * On success pnPos contains the index of the item in the top level menu group
1058 *
1059 * RETURNS: TRUE if the ID was found, FALSE on failure
1060 */
1061static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
1062{
1063 UINT i, nItems;
1064
1065 nItems = GetMenuItemCount( hMainMenu );
1066
1067 for (i = 0; i < nItems; i++)
1068 {
1069 HMENU hsubmenu;
1070
1071 /* Is the current item a submenu? */
1072 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
1073 {
1074 /* If the handle is the same we're done */
1075 if ( hsubmenu == hPopupMenu )
1076 {
1077 if (pnPos)
1078 *pnPos = i;
1079 return TRUE;
1080 }
1081 /* Recursively search without updating pnPos */
1082 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1083 {
1084 if (pnPos)
1085 *pnPos = i;
1086 return TRUE;
1087 }
1088 }
1089 }
1090
1091 return FALSE;
1092}
1093
1094/***********************************************************************
1095 * OLEMenu_SetIsServerMenu
1096 *
1097 * Checks whether a popup menu belongs to a shared menu group which is
1098 * owned by the server, and sets the menu descriptor state accordingly.
1099 * All menu messages from these groups should be routed to the server.
1100 *
1101 * RETURNS: TRUE if the popup menu is part of a server owned group
1102 * FASE if the popup menu is part of a container owned group
1103 */
1104BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1105{
1106 UINT nPos = 0, nWidth, i;
1107
1108 pOleMenuDescriptor->bIsServerItem = FALSE;
1109
1110 /* Don't bother searching if the popup is the combined menu itself */
1111 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1112 return FALSE;
1113
1114 /* Find the menu item index in the shared OLE menu that this item belongs to */
1115 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1116 return FALSE;
1117
1118 /* The group widths array has counts for the number of elements
1119 * in the groups File, Edit, Container, Object, Window, Help.
1120 * The Edit, Object & Help groups belong to the server object
1121 * and the other three belong to the container.
1122 * Loop through the group widths and locate the group we are a member of.
1123 */
1124 for ( i = 0, nWidth = 0; i < 6; i++ )
1125 {
1126 nWidth += pOleMenuDescriptor->mgw.width[i];
1127 if ( nPos < nWidth )
1128 {
1129 /* Odd elements are server menu widths */
1130 pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
1131 break;
1132 }
1133 }
1134
1135 return pOleMenuDescriptor->bIsServerItem;
1136}
1137
1138/*************************************************************************
1139 * OLEMenu_CallWndProc
1140 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1141 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1142 */
1143LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1144{
1145 LPCWPSTRUCT pMsg = NULL;
1146 HOLEMENU hOleMenu = 0;
1147 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1148 OleMenuHookItem *pHookItem = NULL;
1149 WORD fuFlags;
1150
1151 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1152
1153 /* Check if we're being asked to process the message */
1154 if ( HC_ACTION != code )
1155 goto NEXTHOOK;
1156
1157 /* Retrieve the current message being dispatched from lParam */
1158 pMsg = (LPCWPSTRUCT)lParam;
1159
1160 /* Check if the message is destined for a window we are interested in:
1161 * If the window has an OLEMenu property we may need to dispatch
1162 * the menu message to its active objects window instead. */
1163
1164 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1165 if ( !hOleMenu )
1166 goto NEXTHOOK;
1167
1168 /* Get the menu descriptor */
1169 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1170 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1171 goto NEXTHOOK;
1172
1173 /* Process menu messages */
1174 switch( pMsg->message )
1175 {
1176 case WM_INITMENU:
1177 {
1178 /* Reset the menu descriptor state */
1179 pOleMenuDescriptor->bIsServerItem = FALSE;
1180
1181 /* Send this message to the server as well */
1182 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1183 pMsg->message, pMsg->wParam, pMsg->lParam );
1184 goto NEXTHOOK;
1185 }
1186
1187 case WM_INITMENUPOPUP:
1188 {
1189 /* Save the state for whether this is a server owned menu */
1190 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1191 break;
1192 }
1193
1194 case WM_MENUSELECT:
1195 {
1196 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1197 if ( fuFlags & MF_SYSMENU )
1198 goto NEXTHOOK;
1199
1200 /* Save the state for whether this is a server owned popup menu */
1201 else if ( fuFlags & MF_POPUP )
1202 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1203
1204 break;
1205 }
1206
1207 case WM_DRAWITEM:
1208 {
1209 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1210 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1211 goto NEXTHOOK; /* Not a menu message */
1212
1213 break;
1214 }
1215
1216 default:
1217 goto NEXTHOOK;
1218 }
1219
1220 /* If the message was for the server dispatch it accordingly */
1221 if ( pOleMenuDescriptor->bIsServerItem )
1222 {
1223 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1224 pMsg->message, pMsg->wParam, pMsg->lParam );
1225 }
1226
1227NEXTHOOK:
1228 if ( pOleMenuDescriptor )
1229 GlobalUnlock( hOleMenu );
1230
1231 /* Lookup the hook item for the current thread */
1232 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1233 {
1234 /* This should never fail!! */
1235 WARN("could not retrieve hHook for current thread!\n" );
1236 return 0;
1237 }
1238
1239 /* Pass on the message to the next hooker */
1240 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1241}
1242
1243/*************************************************************************
1244 * OLEMenu_GetMsgProc
1245 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1246 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1247 */
1248LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1249{
1250 LPMSG pMsg = NULL;
1251 HOLEMENU hOleMenu = 0;
1252 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1253 OleMenuHookItem *pHookItem = NULL;
1254 WORD wCode;
1255
1256 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1257
1258 /* Check if we're being asked to process a messages */
1259 if ( HC_ACTION != code )
1260 goto NEXTHOOK;
1261
1262 /* Retrieve the current message being dispatched from lParam */
1263 pMsg = (LPMSG)lParam;
1264
1265 /* Check if the message is destined for a window we are interested in:
1266 * If the window has an OLEMenu property we may need to dispatch
1267 * the menu message to its active objects window instead. */
1268
1269 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1270 if ( !hOleMenu )
1271 goto NEXTHOOK;
1272
1273 /* Process menu messages */
1274 switch( pMsg->message )
1275 {
1276 case WM_COMMAND:
1277 {
1278 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1279 if ( wCode )
1280 goto NEXTHOOK; /* Not a menu message */
1281 break;
1282 }
1283 default:
1284 goto NEXTHOOK;
1285 }
1286
1287 /* Get the menu descriptor */
1288 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1289 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1290 goto NEXTHOOK;
1291
1292 /* If the message was for the server dispatch it accordingly */
1293 if ( pOleMenuDescriptor->bIsServerItem )
1294 {
1295 /* Change the hWnd in the message to the active objects hWnd.
1296 * The message loop which reads this message will automatically
1297 * dispatch it to the embedded objects window. */
1298 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1299 }
1300
1301NEXTHOOK:
1302 if ( pOleMenuDescriptor )
1303 GlobalUnlock( hOleMenu );
1304
1305 /* Lookup the hook item for the current thread */
1306 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1307 {
1308 /* This should never fail!! */
1309 WARN("could not retrieve hHook for current thread!\n" );
1310 return FALSE;
1311 }
1312
1313 /* Pass on the message to the next hooker */
1314 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1315}
1316
1317/***********************************************************************
1318 * OleCreateMenuDescriptor [OLE32.@]
1319 * Creates an OLE menu descriptor for OLE to use when dispatching
1320 * menu messages and commands.
1321 *
1322 * PARAMS:
1323 * hmenuCombined - Handle to the objects combined menu
1324 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1325 *
1326 */
1327HOLEMENU WINAPI OleCreateMenuDescriptor(
1328 HMENU hmenuCombined,
1329 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1330{
1331 HOLEMENU hOleMenu;
1332 OleMenuDescriptor *pOleMenuDescriptor;
1333 int i;
1334
1335 if ( !hmenuCombined || !lpMenuWidths )
1336 return 0;
1337
1338 /* Create an OLE menu descriptor */
1339 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1340 sizeof(OleMenuDescriptor) ) ) )
1341 return 0;
1342
1343 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1344 if ( !pOleMenuDescriptor )
1345 return 0;
1346
1347 /* Initialize menu group widths and hmenu */
1348 for ( i = 0; i < 6; i++ )
1349 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1350
1351 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1352 pOleMenuDescriptor->bIsServerItem = FALSE;
1353 GlobalUnlock( hOleMenu );
1354
1355 return hOleMenu;
1356}
1357
1358/***********************************************************************
1359 * OleDestroyMenuDescriptor [OLE32.@]
1360 * Destroy the shared menu descriptor
1361 */
1362HRESULT WINAPI OleDestroyMenuDescriptor(
1363 HOLEMENU hmenuDescriptor)
1364{
1365 if ( hmenuDescriptor )
1366 GlobalFree( hmenuDescriptor );
1367 return S_OK;
1368}
1369
1370/***********************************************************************
1371 * OleSetMenuDescriptor [OLE32.@]
1372 * Installs or removes OLE dispatching code for the containers frame window
1373 * FIXME: The lpFrame and lpActiveObject parameters are currently ignored
1374 * OLE should install context sensitive help F1 filtering for the app when
1375 * these are non null.
1376 *
1377 * PARAMS:
1378 * hOleMenu Handle to composite menu descriptor
1379 * hwndFrame Handle to containers frame window
1380 * hwndActiveObject Handle to objects in-place activation window
1381 * lpFrame Pointer to IOleInPlaceFrame on containers window
1382 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1383 *
1384 * RETURNS:
1385 * S_OK - menu installed correctly
1386 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1387 */
1388HRESULT WINAPI OleSetMenuDescriptor(
1389 HOLEMENU hOleMenu,
1390 HWND hwndFrame,
1391 HWND hwndActiveObject,
1392 LPOLEINPLACEFRAME lpFrame,
1393 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1394{
1395 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1396
1397 /* Check args */
1398 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1399 return E_INVALIDARG;
1400
1401 if ( lpFrame || lpActiveObject )
1402 {
1403 FIXME("(%x, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",
1404 (unsigned int)hOleMenu,
1405 hwndFrame,
1406 hwndActiveObject,
1407 lpFrame,
1408 lpActiveObject);
1409 }
1410
1411 /* Set up a message hook to intercept the containers frame window messages.
1412 * The message filter is responsible for dispatching menu messages from the
1413 * shared menu which are intended for the object.
1414 */
1415
1416 if ( hOleMenu ) /* Want to install dispatching code */
1417 {
1418 /* If OLEMenu hooks are already installed for this thread, fail
1419 * Note: This effectively means that OleSetMenuDescriptor cannot
1420 * be called twice in succession on the same frame window
1421 * without first calling it with a null hOleMenu to uninstall */
1422 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1423 return E_FAIL;
1424
1425 /* Get the menu descriptor */
1426 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1427 if ( !pOleMenuDescriptor )
1428 return E_UNEXPECTED;
1429
1430 /* Update the menu descriptor */
1431 pOleMenuDescriptor->hwndFrame = hwndFrame;
1432 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1433
1434 GlobalUnlock( hOleMenu );
1435 pOleMenuDescriptor = NULL;
1436
1437 /* Add a menu descriptor windows property to the frame window */
1438 SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
1439
1440 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1441 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1442 return E_FAIL;
1443 }
1444 else /* Want to uninstall dispatching code */
1445 {
1446 /* Uninstall the hooks */
1447 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1448 return E_FAIL;
1449
1450 /* Remove the menu descriptor property from the frame window */
1451 RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
1452 }
1453
1454 return S_OK;
1455}
1456
1457/******************************************************************************
1458 * IsAccelerator [OLE32.@]
1459 * Mostly copied from controls/menu.c TranslateAccelerator implementation
1460 */
1461BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
1462{
1463 /* YES, Accel16! */
1464 LPACCEL16 lpAccelTbl;
1465 int i;
1466
1467 if(!lpMsg) return FALSE;
1468
1469#ifdef __WIN32OS2__
1470 if (!hAccel || !(lpAccelTbl = (LPACCEL16)LockResource(hAccel)))
1471#else
1472 if (!hAccel || !(lpAccelTbl = (LPACCEL16)LockResource16(hAccel)))
1473#endif
1474 {
1475 WARN_(accel)("invalid accel handle=%p\n", hAccel);
1476 return FALSE;
1477 }
1478 if((lpMsg->message != WM_KEYDOWN &&
1479 lpMsg->message != WM_KEYUP &&
1480 lpMsg->message != WM_SYSKEYDOWN &&
1481 lpMsg->message != WM_SYSKEYUP &&
1482 lpMsg->message != WM_CHAR)) return FALSE;
1483
1484 TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"
1485 "msg->hwnd=%p, msg->message=%04x, wParam=%08x, lParam=%08lx\n",
1486 hAccel, cAccelEntries,
1487 lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
1488 for(i = 0; i < cAccelEntries; i++)
1489 {
1490 if(lpAccelTbl[i].key != lpMsg->wParam)
1491 continue;
1492
1493 if(lpMsg->message == WM_CHAR)
1494 {
1495 if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
1496 {
1497 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", lpMsg->wParam & 0xff);
1498 goto found;
1499 }
1500 }
1501 else
1502 {
1503 if(lpAccelTbl[i].fVirt & FVIRTKEY)
1504 {
1505 INT mask = 0;
1506 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
1507 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
1508 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
1509 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
1510 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
1511 if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
1512 TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
1513 }
1514 else
1515 {
1516 if(!(lpMsg->lParam & 0x01000000)) /* no special_key */
1517 {
1518 if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
1519 { /* ^^ ALT pressed */
1520 TRACE_(accel)("found accel for Alt-%c\n", lpMsg->wParam & 0xff);
1521 goto found;
1522 }
1523 }
1524 }
1525 }
1526 }
1527
1528 WARN_(accel)("couldn't translate accelerator key\n");
1529 return FALSE;
1530
1531found:
1532 if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
1533 return TRUE;
1534}
1535
1536/***********************************************************************
1537 * ReleaseStgMedium [OLE32.@]
1538 */
1539void WINAPI ReleaseStgMedium(
1540 STGMEDIUM* pmedium)
1541{
1542 switch (pmedium->tymed)
1543 {
1544 case TYMED_HGLOBAL:
1545 {
1546 if ( (pmedium->pUnkForRelease==0) &&
1547 (pmedium->u.hGlobal!=0) )
1548 GlobalFree(pmedium->u.hGlobal);
1549
1550 pmedium->u.hGlobal = 0;
1551 break;
1552 }
1553 case TYMED_FILE:
1554 {
1555 if (pmedium->u.lpszFileName!=0)
1556 {
1557 if (pmedium->pUnkForRelease==0)
1558 {
1559 DeleteFileW(pmedium->u.lpszFileName);
1560 }
1561
1562 CoTaskMemFree(pmedium->u.lpszFileName);
1563 }
1564
1565 pmedium->u.lpszFileName = 0;
1566 break;
1567 }
1568 case TYMED_ISTREAM:
1569 {
1570 if (pmedium->u.pstm!=0)
1571 {
1572 IStream_Release(pmedium->u.pstm);
1573 }
1574
1575 pmedium->u.pstm = 0;
1576 break;
1577 }
1578 case TYMED_ISTORAGE:
1579 {
1580 if (pmedium->u.pstg!=0)
1581 {
1582 IStorage_Release(pmedium->u.pstg);
1583 }
1584
1585 pmedium->u.pstg = 0;
1586 break;
1587 }
1588 case TYMED_GDI:
1589 {
1590 if ( (pmedium->pUnkForRelease==0) &&
1591 (pmedium->u.hGlobal!=0) )
1592 DeleteObject(pmedium->u.hGlobal);
1593
1594 pmedium->u.hGlobal = 0;
1595 break;
1596 }
1597 case TYMED_MFPICT:
1598 {
1599 if ( (pmedium->pUnkForRelease==0) &&
1600 (pmedium->u.hMetaFilePict!=0) )
1601 {
1602 LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hGlobal);
1603 DeleteMetaFile(pMP->hMF);
1604 GlobalUnlock(pmedium->u.hGlobal);
1605 GlobalFree(pmedium->u.hGlobal);
1606 }
1607
1608 pmedium->u.hMetaFilePict = 0;
1609 break;
1610 }
1611 case TYMED_ENHMF:
1612 {
1613 if ( (pmedium->pUnkForRelease==0) &&
1614 (pmedium->u.hEnhMetaFile!=0) )
1615 {
1616 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1617 }
1618
1619 pmedium->u.hEnhMetaFile = 0;
1620 break;
1621 }
1622 case TYMED_NULL:
1623 default:
1624 break;
1625 }
1626 pmedium->tymed=TYMED_NULL;
1627
1628 /*
1629 * After cleaning up, the unknown is released
1630 */
1631 if (pmedium->pUnkForRelease!=0)
1632 {
1633 IUnknown_Release(pmedium->pUnkForRelease);
1634 pmedium->pUnkForRelease = 0;
1635 }
1636}
1637
1638/***
1639 * OLEDD_Initialize()
1640 *
1641 * Initializes the OLE drag and drop data structures.
1642 */
1643static void OLEDD_Initialize()
1644{
1645 WNDCLASSA wndClass;
1646
1647 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1648 wndClass.style = CS_GLOBALCLASS;
1649 wndClass.lpfnWndProc = (WNDPROC)OLEDD_DragTrackerWindowProc;
1650 wndClass.cbClsExtra = 0;
1651 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
1652 wndClass.hCursor = 0;
1653 wndClass.hbrBackground = 0;
1654 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1655
1656 RegisterClassA (&wndClass);
1657
1658#ifdef __WIN32OS2__
1659 {
1660 IDropTarget *desktopdnd;
1661
1662 desktopdnd = IDropTarget_Constructor();
1663 RegisterDragDrop(GetDesktopWindow(), desktopdnd);
1664 }
1665#endif
1666}
1667
1668/***
1669 * OLEDD_UnInitialize()
1670 *
1671 * Releases the OLE drag and drop data structures.
1672 */
1673static void OLEDD_UnInitialize()
1674{
1675 /*
1676 * Simply empty the list.
1677 */
1678 while (targetListHead!=NULL)
1679 {
1680 RevokeDragDrop(targetListHead->hwndTarget);
1681 }
1682}
1683
1684/***
1685 * OLEDD_InsertDropTarget()
1686 *
1687 * Insert the target node in the tree.
1688 */
1689static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
1690{
1691 DropTargetNode* curNode;
1692 DropTargetNode** parentNodeLink;
1693
1694 /*
1695 * Iterate the tree to find the insertion point.
1696 */
1697 curNode = targetListHead;
1698 parentNodeLink = &targetListHead;
1699
1700 while (curNode!=NULL)
1701 {
1702 if (nodeToAdd->hwndTarget<curNode->hwndTarget)
1703 {
1704 /*
1705 * If the node we want to add has a smaller HWND, go left
1706 */
1707 parentNodeLink = &curNode->prevDropTarget;
1708 curNode = curNode->prevDropTarget;
1709 }
1710 else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
1711 {
1712 /*
1713 * If the node we want to add has a larger HWND, go right
1714 */
1715 parentNodeLink = &curNode->nextDropTarget;
1716 curNode = curNode->nextDropTarget;
1717 }
1718 else
1719 {
1720 /*
1721 * The item was found in the list. It shouldn't have been there
1722 */
1723 assert(FALSE);
1724 return;
1725 }
1726 }
1727
1728 /*
1729 * If we get here, we have found a spot for our item. The parentNodeLink
1730 * pointer points to the pointer that we have to modify.
1731 * The curNode should be NULL. We just have to establish the link and Voila!
1732 */
1733 assert(curNode==NULL);
1734 assert(parentNodeLink!=NULL);
1735 assert(*parentNodeLink==NULL);
1736
1737 *parentNodeLink=nodeToAdd;
1738}
1739
1740/***
1741 * OLEDD_ExtractDropTarget()
1742 *
1743 * Removes the target node from the tree.
1744 */
1745static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
1746{
1747 DropTargetNode* curNode;
1748 DropTargetNode** parentNodeLink;
1749
1750 /*
1751 * Iterate the tree to find the insertion point.
1752 */
1753 curNode = targetListHead;
1754 parentNodeLink = &targetListHead;
1755
1756 while (curNode!=NULL)
1757 {
1758 if (hwndOfTarget<curNode->hwndTarget)
1759 {
1760 /*
1761 * If the node we want to add has a smaller HWND, go left
1762 */
1763 parentNodeLink = &curNode->prevDropTarget;
1764 curNode = curNode->prevDropTarget;
1765 }
1766 else if (hwndOfTarget>curNode->hwndTarget)
1767 {
1768 /*
1769 * If the node we want to add has a larger HWND, go right
1770 */
1771 parentNodeLink = &curNode->nextDropTarget;
1772 curNode = curNode->nextDropTarget;
1773 }
1774 else
1775 {
1776 /*
1777 * The item was found in the list. Detach it from it's parent and
1778 * re-insert it's kids in the tree.
1779 */
1780 assert(parentNodeLink!=NULL);
1781 assert(*parentNodeLink==curNode);
1782
1783 /*
1784 * We arbitrately re-attach the left sub-tree to the parent.
1785 */
1786 *parentNodeLink = curNode->prevDropTarget;
1787
1788 /*
1789 * And we re-insert the right subtree
1790 */
1791 if (curNode->nextDropTarget!=NULL)
1792 {
1793 OLEDD_InsertDropTarget(curNode->nextDropTarget);
1794 }
1795
1796 /*
1797 * The node we found is still a valid node once we complete
1798 * the unlinking of the kids.
1799 */
1800 curNode->nextDropTarget=NULL;
1801 curNode->prevDropTarget=NULL;
1802
1803 return curNode;
1804 }
1805 }
1806
1807 /*
1808 * If we get here, the node is not in the tree
1809 */
1810 return NULL;
1811}
1812
1813/***
1814 * OLEDD_FindDropTarget()
1815 *
1816 * Finds information about the drop target.
1817 */
1818static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1819{
1820 DropTargetNode* curNode;
1821
1822 /*
1823 * Iterate the tree to find the HWND value.
1824 */
1825 curNode = targetListHead;
1826
1827 while (curNode!=NULL)
1828 {
1829 if (hwndOfTarget<curNode->hwndTarget)
1830 {
1831 /*
1832 * If the node we want to add has a smaller HWND, go left
1833 */
1834 curNode = curNode->prevDropTarget;
1835 }
1836 else if (hwndOfTarget>curNode->hwndTarget)
1837 {
1838 /*
1839 * If the node we want to add has a larger HWND, go right
1840 */
1841 curNode = curNode->nextDropTarget;
1842 }
1843 else
1844 {
1845 /*
1846 * The item was found in the list.
1847 */
1848 return curNode;
1849 }
1850 }
1851
1852 /*
1853 * If we get here, the item is not in the list
1854 */
1855 return NULL;
1856}
1857
1858/***
1859 * OLEDD_DragTrackerWindowProc()
1860 *
1861 * This method is the WindowProcedure of the drag n drop tracking
1862 * window. During a drag n Drop operation, an invisible window is created
1863 * to receive the user input and act upon it. This procedure is in charge
1864 * of this behavior.
1865 */
1866static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1867 HWND hwnd,
1868 UINT uMsg,
1869 WPARAM wParam,
1870 LPARAM lParam)
1871{
1872 dprintf(("OLEDD_DragTrackerWindowProc(%x, %x, %x, %x)\n", hwnd, uMsg, wParam, lParam));
1873 switch (uMsg)
1874 {
1875 case WM_CREATE:
1876 {
1877 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1878
1879 SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
1880
1881 break;
1882 }
1883 case WM_MOUSEMOVE:
1884 {
1885 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1886 POINT mousePos;
1887
1888 /*
1889 * Get the current mouse position in screen coordinates.
1890 */
1891 mousePos.x = LOWORD(lParam);
1892 mousePos.y = HIWORD(lParam);
1893 ClientToScreen(hwnd, &mousePos);
1894
1895 /*
1896 * Track the movement of the mouse.
1897 */
1898 #ifdef __WIN32OS2__
1899 wParam = OLEDD_GetButtonState();
1900 #endif
1901 OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
1902
1903 break;
1904 }
1905 case WM_LBUTTONUP:
1906 case WM_MBUTTONUP:
1907 case WM_RBUTTONUP:
1908 case WM_LBUTTONDOWN:
1909 case WM_MBUTTONDOWN:
1910 case WM_RBUTTONDOWN:
1911 {
1912 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1913 POINT mousePos;
1914
1915 /*
1916 * Get the current mouse position in screen coordinates.
1917 */
1918 mousePos.x = LOWORD(lParam);
1919 mousePos.y = HIWORD(lParam);
1920 ClientToScreen(hwnd, &mousePos);
1921
1922 /*
1923 * Notify everyone that the button state changed
1924 * TODO: Check if the "escape" key was pressed.
1925 */
1926 OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
1927
1928 break;
1929 }
1930 }
1931
1932 /*
1933 * This is a window proc after all. Let's call the default.
1934 */
1935 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1936}
1937
1938/***
1939 * OLEDD_TrackMouseMove()
1940 *
1941 * This method is invoked while a drag and drop operation is in effect.
1942 * it will generate the appropriate callbacks in the drop source
1943 * and drop target. It will also provide the expected feedback to
1944 * the user.
1945 *
1946 * params:
1947 * trackerInfo - Pointer to the structure identifying the
1948 * drag & drop operation that is currently
1949 * active.
1950 * mousePos - Current position of the mouse in screen
1951 * coordinates.
1952 * keyState - Contains the state of the shift keys and the
1953 * mouse buttons (MK_LBUTTON and the like)
1954 */
1955static void OLEDD_TrackMouseMove(
1956 TrackerWindowInfo* trackerInfo,
1957 POINT mousePos,
1958 DWORD keyState)
1959{
1960 HWND hwndNewTarget;
1961 HRESULT hr;
1962
1963#ifdef __WIN32OS2__
1964 TRACE("OLEDD_TrackMouseMove: %p, (%d,%d), %x\n", trackerInfo, mousePos.x, mousePos.y, keyState);
1965#endif
1966
1967 /*
1968 * Get the handle of the window under the mouse
1969 */
1970 hwndNewTarget = WindowFromPoint(mousePos);
1971
1972#ifdef __WIN32OS2__
1973 dprintf(("OLEDD_TrackMouseMove: hwndNewTarget %x current %x", hwndNewTarget, trackerInfo->curDragTargetHWND));
1974#endif
1975
1976 /*
1977 * Every time, we re-initialize the effects passed to the
1978 * IDropTarget to the effects allowed by the source.
1979 */
1980 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
1981
1982 /*
1983 * If we are hovering over the same target as before, send the
1984 * DragOver notification
1985 */
1986 if ( (trackerInfo->curDragTarget != 0) &&
1987 (trackerInfo->curTargetHWND == hwndNewTarget) )
1988 {
1989 POINTL mousePosParam;
1990
1991 /*
1992 * The documentation tells me that the coordinate should be in the target
1993 * window's coordinate space. However, the tests I made tell me the
1994 * coordinates should be in screen coordinates.
1995 */
1996 mousePosParam.x = mousePos.x;
1997 mousePosParam.y = mousePos.y;
1998
1999#ifdef __WIN32OS2__
2000 hr =
2001#endif
2002 IDropTarget_DragOver(trackerInfo->curDragTarget,
2003 keyState,
2004 mousePosParam,
2005 trackerInfo->pdwEffect);
2006#ifdef __WIN32OS2__
2007 TRACE("OLEDD_TrackMouseMove: IDropTarget_DragEnter -> %x, *pdwEffect=%x\n", hr, *trackerInfo->pdwEffect);
2008#endif
2009 }
2010 else
2011 {
2012 DropTargetNode* newDropTargetNode = 0;
2013
2014 /*
2015 * If we changed window, we have to notify our old target and check for
2016 * the new one.
2017 */
2018 if (trackerInfo->curDragTarget!=0)
2019 {
2020#ifdef __WIN32OS2__
2021 hr =
2022#endif
2023 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2024#ifdef __WIN32OS2__
2025 TRACE("OLEDD_TrackMouseMove: IDropTarget_DragLeave -> %x\n", hr);
2026#endif
2027 }
2028
2029 /*
2030 * Make sure we're hovering over a window.
2031 */
2032 if (hwndNewTarget!=0)
2033 {
2034 /*
2035 * Find-out if there is a drag target under the mouse
2036 */
2037 HWND nexttar = hwndNewTarget;
2038 trackerInfo->curTargetHWND = hwndNewTarget;
2039
2040 do {
2041 newDropTargetNode = OLEDD_FindDropTarget(nexttar);
2042 } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0);
2043 if(nexttar) hwndNewTarget = nexttar;
2044
2045 trackerInfo->curDragTargetHWND = hwndNewTarget;
2046 trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
2047
2048 /*
2049 * If there is, notify it that we just dragged-in
2050 */
2051 if (trackerInfo->curDragTarget!=0)
2052 {
2053 POINTL mousePosParam;
2054
2055 /*
2056 * The documentation tells me that the coordinate should be in the target
2057 * window's coordinate space. However, the tests I made tell me the
2058 * coordinates should be in screen coordinates.
2059 */
2060 mousePosParam.x = mousePos.x;
2061 mousePosParam.y = mousePos.y;
2062
2063#ifdef __WIN32OS2__
2064 hr =
2065#endif
2066 IDropTarget_DragEnter(trackerInfo->curDragTarget,
2067 trackerInfo->dataObject,
2068 keyState,
2069 mousePosParam,
2070 trackerInfo->pdwEffect);
2071#ifdef __WIN32OS2__
2072 TRACE("OLEDD_TrackMouseMove: IDropTarget_DragEnter -> %x, *pdwEffect=%x\n", hr, *trackerInfo->pdwEffect);
2073#endif
2074 }
2075 }
2076 else
2077 {
2078 /*
2079 * The mouse is not over a window so we don't track anything.
2080 */
2081 trackerInfo->curDragTargetHWND = 0;
2082 trackerInfo->curTargetHWND = 0;
2083 trackerInfo->curDragTarget = 0;
2084 }
2085 }
2086
2087 /*
2088 * Now that we have done that, we have to tell the source to give
2089 * us feedback on the work being done by the target. If we don't
2090 * have a target, simulate no effect.
2091 */
2092 if (trackerInfo->curDragTarget==0)
2093 {
2094 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2095 }
2096
2097 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
2098 *trackerInfo->pdwEffect);
2099#ifdef __WIN32OS2__
2100 TRACE("OLEDD_TrackMouseMove: IDropSource_GiveFeedback *pdwEffect=%x -> %x\n", *trackerInfo->pdwEffect, hr);
2101#endif
2102
2103 /*
2104 * When we ask for feedback from the drop source, sometimes it will
2105 * do all the necessary work and sometimes it will not handle it
2106 * when that's the case, we must display the standard drag and drop
2107 * cursors.
2108 */
2109 if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
2110 {
2111 if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE)
2112 {
2113 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(1)));
2114 }
2115 else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY)
2116 {
2117 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(2)));
2118 }
2119 else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK)
2120 {
2121 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(3)));
2122 }
2123 else
2124 {
2125 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(0)));
2126 }
2127 }
2128}
2129
2130/***
2131 * OLEDD_TrackStateChange()
2132 *
2133 * This method is invoked while a drag and drop operation is in effect.
2134 * It is used to notify the drop target/drop source callbacks when
2135 * the state of the keyboard or mouse button change.
2136 *
2137 * params:
2138 * trackerInfo - Pointer to the structure identifying the
2139 * drag & drop operation that is currently
2140 * active.
2141 * mousePos - Current position of the mouse in screen
2142 * coordinates.
2143 * keyState - Contains the state of the shift keys and the
2144 * mouse buttons (MK_LBUTTON and the like)
2145 */
2146static void OLEDD_TrackStateChange(
2147 TrackerWindowInfo* trackerInfo,
2148 POINT mousePos,
2149 DWORD keyState)
2150{
2151#ifdef __WIN32OS2__
2152 TRACE("OLEDD_TrackStateChange: %p (%d,%d) %x\n", trackerInfo, mousePos.x, mousePos.y, keyState);
2153#endif
2154
2155 /*
2156 * Ask the drop source what to do with the operation.
2157 */
2158 trackerInfo->returnValue = IDropSource_QueryContinueDrag(
2159 trackerInfo->dropSource,
2160 trackerInfo->escPressed,
2161 keyState);
2162#ifdef __WIN32OS2__
2163 TRACE("OLEDD_TrackStateChange: IDropSource_QueryContinueDrag -> %x\n", trackerInfo->returnValue);
2164#endif
2165
2166 /*
2167 * All the return valued will stop the operation except the S_OK
2168 * return value.
2169 */
2170 if (trackerInfo->returnValue!=S_OK)
2171 {
2172 /*
2173 * Make sure the message loop in DoDragDrop stops
2174 */
2175 trackerInfo->trackingDone = TRUE;
2176
2177 /*
2178 * Release the mouse in case the drop target decides to show a popup
2179 * or a menu or something.
2180 */
2181 ReleaseCapture();
2182
2183 /*
2184 * If we end-up over a target, drop the object in the target or
2185 * inform the target that the operation was cancelled.
2186 */
2187 if (trackerInfo->curDragTarget!=0)
2188 {
2189 switch (trackerInfo->returnValue)
2190 {
2191 /*
2192 * If the source wants us to complete the operation, we tell
2193 * the drop target that we just dropped the object in it.
2194 */
2195 case DRAGDROP_S_DROP:
2196 {
2197 POINTL mousePosParam;
2198
2199 /*
2200 * The documentation tells me that the coordinate should be
2201 * in the target window's coordinate space. However, the tests
2202 * I made tell me the coordinates should be in screen coordinates.
2203 */
2204 mousePosParam.x = mousePos.x;
2205 mousePosParam.y = mousePos.y;
2206
2207 IDropTarget_Drop(trackerInfo->curDragTarget,
2208 trackerInfo->dataObject,
2209 keyState,
2210 mousePosParam,
2211 trackerInfo->pdwEffect);
2212 break;
2213 }
2214 /*
2215 * If the source told us that we should cancel, fool the drop
2216 * target by telling it that the mouse left it's window.
2217 * Also set the drop effect to "NONE" in case the application
2218 * ignores the result of DoDragDrop.
2219 */
2220 case DRAGDROP_S_CANCEL:
2221 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2222 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2223 break;
2224
2225#ifdef __WIN32OS2__
2226#ifdef DEBUG
2227 default:
2228 TRACE("OLEDD_TrackStateChange: unknown return value %x\n", trackerInfo->returnValue);
2229 assert(FALSE);
2230 break;
2231#endif
2232#endif
2233 }
2234 }
2235 }
2236#ifdef __WIN32OS2__
2237 else /* Read DoDragDrop() docs. This is point 5 in the remark section. */
2238 OLEDD_TrackMouseMove(trackerInfo, mousePos, keyState);
2239 TRACE("OLEDD_TrackStateChange: IDropSource_QueryContinueDrag -> %x\n", trackerInfo->returnValue);
2240#endif
2241}
2242
2243/***
2244 * OLEDD_GetButtonState()
2245 *
2246 * This method will use the current state of the keyboard to build
2247 * a button state mask equivalent to the one passed in the
2248 * WM_MOUSEMOVE wParam.
2249 */
2250static DWORD OLEDD_GetButtonState(void)
2251{
2252 BYTE keyboardState[256];
2253 DWORD keyMask = 0;
2254
2255 GetKeyboardState(keyboardState);
2256
2257 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2258 keyMask |= MK_SHIFT;
2259
2260 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2261 keyMask |= MK_CONTROL;
2262
2263#ifdef __WIN32OS2__
2264 if ( (keyboardState[VK_MENU] & 0x80) != 0)
2265 keyMask |= MK_ALT;
2266#endif
2267
2268 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2269 keyMask |= MK_LBUTTON;
2270
2271 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2272 keyMask |= MK_RBUTTON;
2273
2274 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2275 keyMask |= MK_MBUTTON;
2276
2277
2278 return keyMask;
2279}
2280
2281/***
2282 * OLEDD_GetButtonState()
2283 *
2284 * This method will read the default value of the registry key in
2285 * parameter and extract a DWORD value from it. The registry key value
2286 * can be in a string key or a DWORD key.
2287 *
2288 * params:
2289 * regKey - Key to read the default value from
2290 * pdwValue - Pointer to the location where the DWORD
2291 * value is returned. This value is not modified
2292 * if the value is not found.
2293 */
2294
2295static void OLEUTL_ReadRegistryDWORDValue(
2296 HKEY regKey,
2297 DWORD* pdwValue)
2298{
2299 char buffer[20];
2300 DWORD dwKeyType;
2301 DWORD cbData = 20;
2302 LONG lres;
2303
2304 lres = RegQueryValueExA(regKey,
2305 "",
2306 NULL,
2307 &dwKeyType,
2308 (LPBYTE)buffer,
2309 &cbData);
2310
2311 if (lres==ERROR_SUCCESS)
2312 {
2313 switch (dwKeyType)
2314 {
2315 case REG_DWORD:
2316 *pdwValue = *(DWORD*)buffer;
2317 break;
2318 case REG_EXPAND_SZ:
2319 case REG_MULTI_SZ:
2320 case REG_SZ:
2321 *pdwValue = (DWORD)strtoul(buffer, NULL, 10);
2322 break;
2323 }
2324 }
2325}
2326
2327
2328/******************************************************************************
2329 * OleDraw (OLE32.@)
2330 *
2331 * The operation of this function is documented literally in the WinAPI
2332 * documentation to involve a QueryInterface for the IViewObject interface,
2333 * followed by a call to IViewObject::Draw.
2334 */
2335HRESULT WINAPI OleDraw(
2336 IUnknown *pUnk,
2337 DWORD dwAspect,
2338 HDC hdcDraw,
2339 LPCRECT lprcBounds)
2340{
2341 HRESULT hres;
2342 IViewObject *viewobject;
2343
2344 hres = IUnknown_QueryInterface(pUnk,
2345 &IID_IViewObject,
2346 (void**)&viewobject);
2347
2348 if (SUCCEEDED(hres))
2349 {
2350 RECTL rectl;
2351
2352 rectl.left = lprcBounds->left;
2353 rectl.right = lprcBounds->right;
2354 rectl.top = lprcBounds->top;
2355 rectl.bottom = lprcBounds->bottom;
2356 hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, &rectl, 0, 0, 0);
2357
2358 IViewObject_Release(viewobject);
2359 return hres;
2360 }
2361 else
2362 {
2363 return DV_E_NOIVIEWOBJECT;
2364 }
2365}
2366
2367/***********************************************************************
2368 * OleTranslateAccelerator [OLE32.@]
2369 */
2370HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame,
2371 LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg)
2372{
2373 WORD wID;
2374
2375 TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg);
2376
2377 if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID))
2378 return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID);
2379
2380 return S_FALSE;
2381}
2382
2383/******************************************************************************
2384 * OleCreate [OLE32.@]
2385 *
2386 */
2387HRESULT WINAPI OleCreate(
2388 REFCLSID rclsid,
2389 REFIID riid,
2390 DWORD renderopt,
2391 LPFORMATETC pFormatEtc,
2392 LPOLECLIENTSITE pClientSite,
2393 LPSTORAGE pStg,
2394 LPVOID* ppvObj)
2395{
2396 HRESULT hres, hres1;
2397 IUnknown * pUnk = NULL;
2398
2399 FIXME("\n\t%s\n\t%s semi-stub!\n", debugstr_guid(rclsid), debugstr_guid(riid));
2400
2401 if (SUCCEEDED((hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER|CLSCTX_LOCAL_SERVER , riid, (LPVOID*)&pUnk))))
2402 {
2403 if (pClientSite)
2404 {
2405 IOleObject * pOE;
2406 IPersistStorage * pPS;
2407 if (SUCCEEDED((hres = IUnknown_QueryInterface( pUnk, &IID_IOleObject, (LPVOID*)&pOE))))
2408 {
2409 TRACE("trying to set clientsite %p\n", pClientSite);
2410 hres1 = IOleObject_SetClientSite(pOE, pClientSite);
2411 TRACE("-- result 0x%08lx\n", hres1);
2412 IOleObject_Release(pOE);
2413 }
2414 if (SUCCEEDED((hres = IUnknown_QueryInterface( pUnk, &IID_IPersistStorage, (LPVOID*)&pPS))))
2415 {
2416 TRACE("trying to set stg %p\n", pStg);
2417 hres1 = IPersistStorage_InitNew(pPS, pStg);
2418 TRACE("-- result 0x%08lx\n", hres1);
2419 IPersistStorage_Release(pPS);
2420 }
2421 }
2422 }
2423
2424 *ppvObj = pUnk;
2425
2426 TRACE("-- %p \n", pUnk);
2427 return hres;
2428}
2429
2430/***********************************************************************
2431 * OLE_FreeClipDataArray [internal]
2432 *
2433 * NOTES:
2434 * frees the data associated with an array of CLIPDATAs
2435 */
2436static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray)
2437{
2438 ULONG i;
2439 for (i = 0; i < count; i++)
2440 if (pClipDataArray[i].pClipData)
2441 CoTaskMemFree(pClipDataArray[i].pClipData);
2442}
2443
2444HRESULT WINAPI FreePropVariantArray(ULONG,PROPVARIANT*);
2445
2446/***********************************************************************
2447 * PropVariantClear [OLE32.@]
2448 */
2449HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */
2450{
2451 TRACE("(%p)\n", pvar);
2452
2453 if (!pvar)
2454 return S_OK;
2455
2456 switch(pvar->vt)
2457 {
2458 case VT_STREAM:
2459 case VT_STREAMED_OBJECT:
2460 case VT_STORAGE:
2461 case VT_STORED_OBJECT:
2462 IUnknown_Release((LPUNKNOWN)pvar->u.pStream);
2463 break;
2464 case VT_CLSID:
2465 case VT_LPSTR:
2466 case VT_LPWSTR:
2467 /* pick an arbitary typed pointer - we don't care about the type
2468 * as we are just freeing it */
2469 CoTaskMemFree(pvar->u.puuid);
2470 break;
2471 case VT_BLOB:
2472 case VT_BLOB_OBJECT:
2473 CoTaskMemFree(pvar->u.blob.pBlobData);
2474 break;
2475 case VT_BSTR:
2476 FIXME("Need to load OLEAUT32 for SysFreeString\n");
2477 /* SysFreeString(pvar->u.bstrVal); */
2478 break;
2479 case VT_CF:
2480 if (pvar->u.pclipdata)
2481 {
2482 OLE_FreeClipDataArray(1, pvar->u.pclipdata);
2483 CoTaskMemFree(pvar->u.pclipdata);
2484 }
2485 break;
2486 default:
2487 if (pvar->vt & VT_ARRAY)
2488 {
2489 FIXME("Need to call SafeArrayDestroy\n");
2490 /* SafeArrayDestroy(pvar->u.caub); */
2491 }
2492 switch (pvar->vt & VT_VECTOR)
2493 {
2494 case VT_VARIANT:
2495 FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems);
2496 break;
2497 case VT_CF:
2498 OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems);
2499 break;
2500 case VT_BSTR:
2501 case VT_LPSTR:
2502 case VT_LPWSTR:
2503 FIXME("Freeing of vector sub-type not supported yet\n");
2504 }
2505 if (pvar->vt & VT_VECTOR)
2506 {
2507 /* pick an arbitary VT_VECTOR structure - they all have the same
2508 * memory layout */
2509 CoTaskMemFree(pvar->u.capropvar.pElems);
2510 }
2511 }
2512
2513 ZeroMemory(pvar, sizeof(*pvar));
2514
2515 return S_OK;
2516}
2517
2518/***********************************************************************
2519 * PropVariantCopy [OLE32.@]
2520 */
2521HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, /* [out] */
2522 const PROPVARIANT *pvarSrc) /* [in] */
2523{
2524 ULONG len;
2525 TRACE("(%p, %p): stub:\n", pvarDest, pvarSrc);
2526
2527 /* this will deal with most cases */
2528 CopyMemory(pvarDest, pvarSrc, sizeof(*pvarDest));
2529
2530 switch(pvarSrc->vt)
2531 {
2532 case VT_STREAM:
2533 case VT_STREAMED_OBJECT:
2534 case VT_STORAGE:
2535 case VT_STORED_OBJECT:
2536 IUnknown_AddRef((LPUNKNOWN)pvarDest->u.pStream);
2537 break;
2538 case VT_CLSID:
2539 pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));
2540 CopyMemory(pvarDest->u.puuid, pvarSrc->u.puuid, sizeof(CLSID));
2541 break;
2542 case VT_LPSTR:
2543 len = strlen(pvarSrc->u.pszVal);
2544 pvarDest->u.pszVal = CoTaskMemAlloc(len);
2545 CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, len);
2546 break;
2547 case VT_LPWSTR:
2548 len = lstrlenW(pvarSrc->u.pwszVal);
2549 pvarDest->u.pwszVal = CoTaskMemAlloc(len);
2550 CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, len);
2551 break;
2552 case VT_BLOB:
2553 case VT_BLOB_OBJECT:
2554 if (pvarSrc->u.blob.pBlobData)
2555 {
2556 len = pvarSrc->u.blob.cbSize;
2557 pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len);
2558 CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len);
2559 }
2560 break;
2561 case VT_BSTR:
2562 FIXME("Need to copy BSTR\n");
2563 break;
2564 case VT_CF:
2565 if (pvarSrc->u.pclipdata)
2566 {
2567 len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt);
2568 CoTaskMemAlloc(len);
2569 CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len);
2570 }
2571 break;
2572 default:
2573 if (pvarSrc->vt & VT_ARRAY)
2574 {
2575 FIXME("Need to call SafeArrayCopy\n");
2576 /* SafeArrayCopy(...); */
2577 }
2578 if (pvarSrc->vt & VT_VECTOR)
2579 {
2580 int elemSize;
2581 switch(pvarSrc->vt & VT_VECTOR)
2582 {
2583 case VT_I1: elemSize = sizeof(pvarSrc->u.cVal); break;
2584 case VT_UI1: elemSize = sizeof(pvarSrc->u.bVal); break;
2585 case VT_I2: elemSize = sizeof(pvarSrc->u.iVal); break;
2586 case VT_UI2: elemSize = sizeof(pvarSrc->u.uiVal); break;
2587 case VT_BOOL: elemSize = sizeof(pvarSrc->u.boolVal); break;
2588 case VT_I4: elemSize = sizeof(pvarSrc->u.lVal); break;
2589 case VT_UI4: elemSize = sizeof(pvarSrc->u.ulVal); break;
2590 case VT_R4: elemSize = sizeof(pvarSrc->u.fltVal); break;
2591 case VT_R8: elemSize = sizeof(pvarSrc->u.dblVal); break;
2592 case VT_ERROR: elemSize = sizeof(pvarSrc->u.scode); break;
2593 case VT_I8: elemSize = sizeof(pvarSrc->u.hVal); break;
2594 case VT_UI8: elemSize = sizeof(pvarSrc->u.uhVal); break;
2595 case VT_CY: elemSize = sizeof(pvarSrc->u.cyVal); break;
2596 case VT_DATE: elemSize = sizeof(pvarSrc->u.date); break;
2597 case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break;
2598 case VT_CLSID: elemSize = sizeof(*pvarSrc->u.puuid); break;
2599 case VT_CF: elemSize = sizeof(*pvarSrc->u.pclipdata); break;
2600
2601 case VT_BSTR:
2602 case VT_LPSTR:
2603 case VT_LPWSTR:
2604 case VT_VARIANT:
2605 default:
2606 FIXME("Invalid element type: %ul\n", pvarSrc->vt & VT_VECTOR);
2607 return E_INVALIDARG;
2608 }
2609 len = pvarSrc->u.capropvar.cElems;
2610 pvarDest->u.capropvar.pElems = CoTaskMemAlloc(len * elemSize);
2611 if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
2612 {
2613 ULONG i;
2614 for (i = 0; i < len; i++)
2615 PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]);
2616 }
2617 else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
2618 {
2619 FIXME("Copy clipformats\n");
2620 }
2621 else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
2622 {
2623 FIXME("Copy BSTRs\n");
2624 }
2625 else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
2626 {
2627 FIXME("Copy LPSTRs\n");
2628 }
2629 else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
2630 {
2631 FIXME("Copy LPWSTRs\n");
2632 }
2633 else
2634 CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize);
2635 }
2636 }
2637
2638 return S_OK;
2639}
2640
2641/***********************************************************************
2642 * FreePropVariantArray [OLE32.@]
2643 */
2644HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */
2645 PROPVARIANT *rgvars) /* [in/out] */
2646{
2647 ULONG i;
2648
2649 TRACE("(%lu, %p)\n", cVariants, rgvars);
2650
2651 for(i = 0; i < cVariants; i++)
2652 PropVariantClear(&rgvars[i]);
2653
2654 return S_OK;
2655}
2656
2657
2658
2659#ifdef __WIN32OS2__
2660#include <dbglog.h>
2661
2662/***********************************************************************
2663* IEnumFORMATETC implementation
2664*/
2665
2666typedef struct
2667{
2668 /* IUnknown fields */
2669 ICOM_VFIELD(IEnumFORMATETC);
2670 DWORD ref;
2671 /* IEnumFORMATETC fields */
2672 UINT posFmt;
2673 UINT countFmt;
2674 LPFORMATETC pFmt;
2675} IEnumFORMATETCImpl;
2676
2677static HRESULT WINAPI IEnumFORMATETC_fnQueryInterface(LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj);
2678static ULONG WINAPI IEnumFORMATETC_fnAddRef(LPENUMFORMATETC iface);
2679static ULONG WINAPI IEnumFORMATETC_fnRelease(LPENUMFORMATETC iface);
2680static HRESULT WINAPI IEnumFORMATETC_fnNext(LPENUMFORMATETC iface, ULONG celt, FORMATETC* rgelt, ULONG* pceltFethed);
2681static HRESULT WINAPI IEnumFORMATETC_fnSkip(LPENUMFORMATETC iface, ULONG celt);
2682static HRESULT WINAPI IEnumFORMATETC_fnReset(LPENUMFORMATETC iface);
2683static HRESULT WINAPI IEnumFORMATETC_fnClone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum);
2684
2685static struct ICOM_VTABLE(IEnumFORMATETC) efvt =
2686{
2687 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2688 IEnumFORMATETC_fnQueryInterface,
2689 IEnumFORMATETC_fnAddRef,
2690 IEnumFORMATETC_fnRelease,
2691 IEnumFORMATETC_fnNext,
2692 IEnumFORMATETC_fnSkip,
2693 IEnumFORMATETC_fnReset,
2694 IEnumFORMATETC_fnClone
2695};
2696
2697static LPENUMFORMATETC IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[])
2698{
2699 IEnumFORMATETCImpl* ef;
2700 DWORD size=cfmt * sizeof(FORMATETC);
2701
2702 ef=(IEnumFORMATETCImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumFORMATETCImpl));
2703
2704 if(ef)
2705 {
2706 ef->ref=1;
2707 ICOM_VTBL(ef)=&efvt;
2708
2709 ef->countFmt = cfmt;
2710 ef->pFmt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2711
2712 if (ef->pFmt)
2713 {
2714 memcpy(ef->pFmt, afmt, size);
2715 }
2716 }
2717
2718 TRACE("(%p)->(%u,%p)\n",ef, cfmt, afmt);
2719 return (LPENUMFORMATETC)ef;
2720}
2721
2722static HRESULT WINAPI IEnumFORMATETC_fnQueryInterface(LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
2723{
2724 ICOM_THIS(IEnumFORMATETCImpl,iface);
2725 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
2726
2727 *ppvObj = NULL;
2728
2729 if(IsEqualIID(riid, &IID_IUnknown))
2730 {
2731 *ppvObj = This;
2732 }
2733 else if(IsEqualIID(riid, &IID_IEnumFORMATETC))
2734 {
2735 *ppvObj = (IEnumFORMATETC*)This;
2736 }
2737
2738 if(*ppvObj)
2739 {
2740 IUnknown_AddRef((IUnknown*)(*ppvObj));
2741 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
2742 return S_OK;
2743 }
2744 TRACE("-- Interface: E_NOINTERFACE\n");
2745 return E_NOINTERFACE;
2746
2747}
2748
2749static ULONG WINAPI IEnumFORMATETC_fnAddRef(LPENUMFORMATETC iface)
2750{
2751 ICOM_THIS(IEnumFORMATETCImpl,iface);
2752 TRACE("(%p)->(count=%lu)\n",This, This->ref);
2753 return ++(This->ref);
2754}
2755
2756static ULONG WINAPI IEnumFORMATETC_fnRelease(LPENUMFORMATETC iface)
2757{
2758 ICOM_THIS(IEnumFORMATETCImpl,iface);
2759 TRACE("(%p)->()\n",This);
2760
2761 if (!--(This->ref))
2762 {
2763 TRACE(" destroying IEnumFORMATETC(%p)\n",This);
2764 if (This->pFmt)
2765 {
2766 HeapFree(GetProcessHeap(),0, This->pFmt);
2767 }
2768 HeapFree(GetProcessHeap(),0,This);
2769 return 0;
2770 }
2771 return This->ref;
2772}
2773
2774static HRESULT WINAPI IEnumFORMATETC_fnNext(LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
2775{
2776 ICOM_THIS(IEnumFORMATETCImpl,iface);
2777 int i;
2778
2779 TRACE("(%p)->(%lu,%p)\n", This, celt, rgelt);
2780
2781 if(!This->pFmt)return S_FALSE;
2782 if(!rgelt) return E_INVALIDARG;
2783 if (pceltFethed) *pceltFethed = 0;
2784
2785 for(i = 0; This->posFmt < This->countFmt && celt > i; i++)
2786 {
2787 *rgelt++ = This->pFmt[This->posFmt++];
2788 }
2789
2790 if (pceltFethed) *pceltFethed = i;
2791
2792 return ((i == celt) ? S_OK : S_FALSE);
2793}
2794
2795static HRESULT WINAPI IEnumFORMATETC_fnSkip(LPENUMFORMATETC iface, ULONG celt)
2796{
2797 ICOM_THIS(IEnumFORMATETCImpl,iface);
2798 TRACE("(%p)->(num=%lu)\n", This, celt);
2799
2800 if((This->posFmt + celt) >= This->countFmt) return S_FALSE;
2801 This->posFmt += celt;
2802 return S_OK;
2803}
2804
2805static HRESULT WINAPI IEnumFORMATETC_fnReset(LPENUMFORMATETC iface)
2806{
2807 ICOM_THIS(IEnumFORMATETCImpl,iface);
2808 TRACE("(%p)->()\n", This);
2809
2810 This->posFmt = 0;
2811 return S_OK;
2812}
2813
2814static HRESULT WINAPI IEnumFORMATETC_fnClone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum)
2815{
2816 ICOM_THIS(IEnumFORMATETCImpl,iface);
2817 TRACE("(%p)->(ppenum=%p)\n", This, ppenum);
2818
2819 if (!ppenum) return E_INVALIDARG;
2820 *ppenum = IEnumFORMATETC_Constructor(This->countFmt, This->pFmt);
2821 return S_OK;
2822}
2823
2824/***********************************************************************
2825* IDataObject implementation
2826*/
2827
2828
2829typedef struct
2830{
2831 /* IUnknown fields */
2832 ICOM_VFIELD(IDataObject);
2833 DWORD ref;
2834
2835 /* IDataObject fields */
2836 LPFORMATETC pFormatEtc;
2837 LPSTGMEDIUM pStgMedium;
2838 DWORD cDataCount;
2839} IDataObjectImpl;
2840
2841static struct ICOM_VTABLE(IDataObject) dtovt;
2842
2843/**************************************************************************
2844* IDataObject_Constructor
2845*/
2846static LPDATAOBJECT IDataObject_Constructor(void)
2847{
2848 IDataObjectImpl* dto;
2849
2850 dto = (IDataObjectImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDataObjectImpl));
2851
2852 if (dto)
2853 {
2854 dto->ref = 1;
2855 ICOM_VTBL(dto) = &dtovt;
2856 }
2857
2858 return (LPDATAOBJECT)dto;
2859}
2860
2861/***************************************************************************
2862* IDataObject_QueryInterface
2863*/
2864static HRESULT WINAPI IDataObject_fnQueryInterface(LPDATAOBJECT iface, REFIID riid, LPVOID * ppvObj)
2865{
2866 ICOM_THIS(IDataObjectImpl,iface);
2867 dprintf(("IDataObject_fnQueryInterface (%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj));
2868
2869 *ppvObj = NULL;
2870
2871 if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/
2872 {
2873 *ppvObj = This;
2874 }
2875 else if(IsEqualIID(riid, &IID_IDataObject)) /*IDataObject*/
2876 {
2877 *ppvObj = (IDataObject*)This;
2878 }
2879
2880 if(*ppvObj)
2881 {
2882 IUnknown_AddRef((IUnknown*)*ppvObj);
2883 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
2884 return S_OK;
2885 }
2886 TRACE("-- Interface: E_NOINTERFACE\n");
2887 return E_NOINTERFACE;
2888}
2889
2890/**************************************************************************
2891* IDataObject_AddRef
2892*/
2893static ULONG WINAPI IDataObject_fnAddRef(LPDATAOBJECT iface)
2894{
2895 ICOM_THIS(IDataObjectImpl,iface);
2896
2897 dprintf(("IDataObject_fnAddRef (%p)->(count=%lu)\n",This, This->ref));
2898
2899 return ++(This->ref);
2900}
2901
2902/**************************************************************************
2903* IDataObject_Release
2904*/
2905static ULONG WINAPI IDataObject_fnRelease(LPDATAOBJECT iface)
2906{
2907 ICOM_THIS(IDataObjectImpl,iface);
2908 dprintf(("IDataObject_fnRelease (%p)->()\n",This));
2909
2910 if (!--(This->ref))
2911 {
2912 TRACE(" destroying IDataObject(%p)\n",This);
2913 HeapFree(GetProcessHeap(),0,This);
2914 return 0;
2915 }
2916 return This->ref;
2917}
2918
2919/**************************************************************************
2920* IDataObject_fnGetData
2921*/
2922static HRESULT WINAPI IDataObject_fnGetData(LPDATAOBJECT iface, LPFORMATETC pformatetcIn, STGMEDIUM *pmedium)
2923{
2924 int i;
2925
2926 ICOM_THIS(IDataObjectImpl,iface);
2927
2928 if(pformatetcIn == NULL || pmedium == NULL)
2929 return E_INVALIDARG;
2930
2931 dprintf(("IDataObject_fnGetData %x %x", pformatetcIn, pmedium));
2932
2933 if(pformatetcIn->cfFormat != CF_HDROP && pformatetcIn->cfFormat != CF_TEXT && pformatetcIn->cfFormat != CF_UNICODETEXT)
2934 {
2935 FIXME("-- expected clipformat not implemented\n");
2936 return (E_INVALIDARG);
2937 }
2938
2939 /* check our formats table what we have */
2940 for (i=0; i<This->cDataCount; i++)
2941 {
2942 if ((This->pFormatEtc[i].cfFormat == pformatetcIn->cfFormat)
2943 && (This->pFormatEtc[i].tymed == pformatetcIn->tymed))
2944 {
2945 pmedium->u.hGlobal = This->pStgMedium[i].u.hGlobal;
2946 break;
2947 }
2948 }
2949 if (pmedium->u.hGlobal)
2950 {
2951 pmedium->tymed = TYMED_HGLOBAL;
2952 pmedium->pUnkForRelease = NULL;
2953 return S_OK;
2954 }
2955 return E_OUTOFMEMORY;
2956}
2957
2958static HRESULT WINAPI IDataObject_fnGetDataHere(LPDATAOBJECT iface, LPFORMATETC pformatetc, STGMEDIUM *pmedium)
2959{
2960 ICOM_THIS(IDataObjectImpl,iface);
2961
2962 dprintf(("IDataObject_fnGetDataHere %x %x STUB", pformatetc, pmedium));
2963 return E_NOTIMPL;
2964}
2965
2966static HRESULT WINAPI IDataObject_fnQueryGetData(LPDATAOBJECT iface, LPFORMATETC pformatetc)
2967{
2968 ICOM_THIS(IDataObjectImpl,iface);
2969 UINT i;
2970
2971 dprintf(("IDataObject_fnQueryGetData (%p)->(fmt=0x%08x tym=0x%08lx)\n", This, pformatetc->cfFormat, pformatetc->tymed));
2972
2973 if(!(DVASPECT_CONTENT & pformatetc->dwAspect))
2974 return DV_E_DVASPECT;
2975
2976 if(This->pFormatEtc == NULL) {
2977 return DV_E_TYMED;
2978 }
2979 /* check our formats table what we have */
2980 for (i=0; i<This->cDataCount; i++)
2981 {
2982 if ((This->pFormatEtc[i].cfFormat == pformatetc->cfFormat)
2983 && (This->pFormatEtc[i].tymed == pformatetc->tymed))
2984 {
2985 return S_OK;
2986 }
2987 }
2988
2989 return DV_E_TYMED;
2990}
2991
2992static HRESULT WINAPI IDataObject_fnGetCanonicalFormatEtc(LPDATAOBJECT iface, LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut)
2993{
2994 ICOM_THIS(IDataObjectImpl,iface);
2995
2996 dprintf(("IDataObject_fnGetCanonicalFormatEtc STUB"));
2997 return DATA_S_SAMEFORMATETC;
2998}
2999
3000static HRESULT WINAPI IDataObject_fnSetData(LPDATAOBJECT iface, LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
3001{
3002 LPFORMATETC pfeNew, pfeTemp;
3003 LPSTGMEDIUM psmNew, psmTemp;
3004 ICOM_THIS(IDataObjectImpl,iface);
3005
3006 //no need for more than one item
3007 if(This->cDataCount != 0) {
3008 DebugInt3();
3009 return E_OUTOFMEMORY;
3010 }
3011 This->cDataCount++;
3012
3013 pfeNew = malloc(sizeof(FORMATETC) * This->cDataCount);
3014 psmNew = malloc(sizeof(STGMEDIUM) * This->cDataCount);
3015
3016 if(pfeNew && psmNew)
3017 {
3018 memset(pfeNew, 0, sizeof(FORMATETC) * This->cDataCount);
3019 memset(psmNew, 0, sizeof(STGMEDIUM) * This->cDataCount);
3020
3021 /* copy the existing data */
3022 if(This->pFormatEtc)
3023 {
3024 memcpy(pfeNew, This->pFormatEtc, sizeof(FORMATETC) * (This->cDataCount - 1));
3025 }
3026 if(This->pStgMedium)
3027 {
3028 memcpy(psmNew, This->pStgMedium, sizeof(STGMEDIUM) * (This->cDataCount - 1));
3029 }
3030
3031 /* add the new data */
3032 pfeNew[This->cDataCount - 1] = *pformatetc;
3033 if(fRelease)
3034 {
3035 psmNew[This->cDataCount - 1] = *pmedium;
3036 }
3037 else
3038 {
3039 DebugInt3();
3040// CopyStgMedium(pmedium, &psmNew[This->cDataCount - 1]);
3041 }
3042
3043 pfeTemp = This->pFormatEtc;
3044 This->pFormatEtc = pfeNew;
3045 pfeNew = pfeTemp;
3046
3047 psmTemp = This->pStgMedium;
3048 This->pStgMedium = psmNew;
3049 psmNew = psmTemp;
3050 }
3051
3052 if(pfeNew)
3053 free(pfeNew);
3054
3055 if(psmNew)
3056 free(psmNew);
3057
3058 if(This->pFormatEtc && This->pStgMedium)
3059 return S_OK;
3060
3061 return E_OUTOFMEMORY;
3062}
3063
3064static HRESULT WINAPI IDataObject_fnEnumFormatEtc(LPDATAOBJECT iface, DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
3065{
3066 ICOM_THIS(IDataObjectImpl,iface);
3067
3068 TRACE("(%p)->()\n", This);
3069 *ppenumFormatEtc=NULL;
3070
3071 /* only get data */
3072 if (DATADIR_GET == dwDirection)
3073 {
3074 *ppenumFormatEtc = IEnumFORMATETC_Constructor(This->cDataCount, This->pFormatEtc);
3075 return (*ppenumFormatEtc) ? S_OK : E_FAIL;
3076 }
3077
3078 return E_NOTIMPL;
3079}
3080
3081static HRESULT WINAPI IDataObject_fnDAdvise(LPDATAOBJECT iface, FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
3082{
3083 ICOM_THIS(IDataObjectImpl,iface);
3084
3085 dprintf(("IDataObject_fnDAdvise STUB"));
3086 return E_NOTIMPL;
3087}
3088static HRESULT WINAPI IDataObject_fnDUnadvise(LPDATAOBJECT iface, DWORD dwConnection)
3089{
3090 ICOM_THIS(IDataObjectImpl,iface);
3091
3092 dprintf(("IDataObject_fnDUnadvise STUB"));
3093 return E_NOTIMPL;
3094}
3095static HRESULT WINAPI IDataObject_fnEnumDAdvise(LPDATAOBJECT iface, IEnumSTATDATA **ppenumAdvise)
3096{
3097 ICOM_THIS(IDataObjectImpl,iface);
3098
3099 dprintf(("IDataObject_fnEnumDAdvise STUB"));
3100 return OLE_E_ADVISENOTSUPPORTED;
3101}
3102
3103static struct ICOM_VTABLE(IDataObject) dtovt =
3104{
3105 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3106 IDataObject_fnQueryInterface,
3107 IDataObject_fnAddRef,
3108 IDataObject_fnRelease,
3109 IDataObject_fnGetData,
3110 IDataObject_fnGetDataHere,
3111 IDataObject_fnQueryGetData,
3112 IDataObject_fnGetCanonicalFormatEtc,
3113 IDataObject_fnSetData,
3114 IDataObject_fnEnumFormatEtc,
3115 IDataObject_fnDAdvise,
3116 IDataObject_fnDUnadvise,
3117 IDataObject_fnEnumDAdvise
3118};
3119
3120//******************************************************************************
3121//******************************************************************************
3122BOOL WINAPI OLEDD_AcceptsDragDrop(HWND hwnd)
3123{
3124 DropTargetNode *pTarget;
3125
3126 /*
3127 * Find-out if there is a drag target under the mouse
3128 */
3129 HWND nexttar = hwnd;
3130 do {
3131 pTarget = OLEDD_FindDropTarget(nexttar);
3132 }
3133 while(!pTarget && (nexttar = GetParent(nexttar)) != 0);
3134
3135 if(pTarget != NULL) {
3136 dprintf(("OLEDD_AcceptsDragDrop %x accepted", hwnd));
3137 return TRUE;
3138 }
3139 dprintf(("OLEDD_AcceptsDragDrop %x refused", hwnd));
3140 return FALSE;
3141}
3142//******************************************************************************
3143//******************************************************************************
3144BOOL WINAPI OLEDD_DropFiles(HWND hwnd)
3145{
3146 DropTargetNode *pTarget;
3147 DWORD keyState = 0;
3148 POINTL mousePosParam;
3149 POINT mousePos;
3150 HWND nexttar = hwnd;
3151
3152 dprintf(("OLEDD_DropFiles %x", hwnd));
3153
3154 do {
3155 pTarget = OLEDD_FindDropTarget(nexttar);
3156 }
3157 while(!pTarget && (nexttar = GetParent(nexttar)) != 0);
3158 if(pTarget == NULL) {
3159 return FALSE;
3160 }
3161
3162 /*
3163 * The documentation tells me that the coordinate should be in the target
3164 * window's coordinate space. However, the tests I made tell me the
3165 * coordinates should be in screen coordinates.
3166 */
3167 GetCursorPos(&mousePos);
3168 mousePosParam.x = mousePos.x;
3169 mousePosParam.y = mousePos.y;
3170
3171 if(GetKeyState(VK_SHIFT) & 0x8000) keyState |= MK_SHIFT;
3172 if(GetKeyState(VK_CONTROL) & 0x8000) keyState |= MK_CONTROL;
3173 if(GetKeyState(VK_MENU) & 0x8000) keyState |= MK_ALT;
3174 if(GetKeyState(VK_LBUTTON) & 0x8000) keyState |= MK_LBUTTON;
3175 if(GetKeyState(VK_RBUTTON) & 0x8000) keyState |= MK_RBUTTON;
3176 if(GetKeyState(VK_MBUTTON) & 0x8000) keyState |= MK_MBUTTON;
3177
3178 return IDropTarget_Drop(pTarget->dropTarget, pTarget->pDataObject,
3179 keyState, mousePosParam, &pTarget->dwEffect) == S_OK;
3180}
3181//******************************************************************************
3182//******************************************************************************
3183BOOL WIN32API OLEDD_DragOver(HWND hwnd, DWORD dwEffect)
3184{
3185 DropTargetNode *pTarget;
3186 DWORD keyState = 0;
3187 POINTL mousePosParam;
3188 POINT mousePos;
3189 HWND nexttar = hwnd;
3190
3191 dprintf(("OLEDD_DragOver %x %d", hwnd, dwEffect));
3192
3193 do {
3194 pTarget = OLEDD_FindDropTarget(nexttar);
3195 }
3196 while(!pTarget && (nexttar = GetParent(nexttar)) != 0);
3197 if(pTarget == NULL) {
3198 return FALSE;
3199 }
3200
3201 /*
3202 * The documentation tells me that the coordinate should be in the target
3203 * window's coordinate space. However, the tests I made tell me the
3204 * coordinates should be in screen coordinates.
3205 */
3206 GetCursorPos(&mousePos);
3207 mousePosParam.x = mousePos.x;
3208 mousePosParam.y = mousePos.y;
3209
3210 if(GetKeyState(VK_SHIFT) & 0x8000) keyState |= MK_SHIFT;
3211 if(GetKeyState(VK_CONTROL) & 0x8000) keyState |= MK_CONTROL;
3212 if(GetKeyState(VK_MENU) & 0x8000) keyState |= MK_ALT;
3213 if(GetKeyState(VK_LBUTTON) & 0x8000) keyState |= MK_LBUTTON;
3214 if(GetKeyState(VK_RBUTTON) & 0x8000) keyState |= MK_RBUTTON;
3215 if(GetKeyState(VK_MBUTTON) & 0x8000) keyState |= MK_MBUTTON;
3216 return IDropTarget_DragOver(pTarget->dropTarget, keyState, mousePosParam, &dwEffect) == S_OK;
3217}
3218//******************************************************************************
3219//******************************************************************************
3220BOOL WIN32API OLEDD_DragEnter(HWND hwnd, HDROP hDrop, DWORD dwEffect)
3221{
3222 FORMATETC fe;
3223 STGMEDIUM medium;
3224 DropTargetNode *pTarget;
3225 DWORD keyState = 0;
3226 POINTL mousePosParam;
3227 POINT mousePos;
3228 HWND nexttar = hwnd;
3229
3230 dprintf(("OLEDD_DragEnter %x %x %d", hwnd, hDrop, dwEffect));
3231
3232 do {
3233 pTarget = OLEDD_FindDropTarget(nexttar);
3234 }
3235 while(!pTarget && (nexttar = GetParent(nexttar)) != 0);
3236 if(pTarget == NULL) {
3237 return FALSE;
3238 }
3239
3240 /*
3241 * The documentation tells me that the coordinate should be in the target
3242 * window's coordinate space. However, the tests I made tell me the
3243 * coordinates should be in screen coordinates.
3244 */
3245 GetCursorPos(&mousePos);
3246 mousePosParam.x = mousePos.x;
3247 mousePosParam.y = mousePos.y;
3248
3249 if(GetKeyState(VK_SHIFT) & 0x8000) keyState |= MK_SHIFT;
3250 if(GetKeyState(VK_CONTROL) & 0x8000) keyState |= MK_CONTROL;
3251 if(GetKeyState(VK_MENU) & 0x8000) keyState |= MK_ALT;
3252 if(GetKeyState(VK_LBUTTON) & 0x8000) keyState |= MK_LBUTTON;
3253 if(GetKeyState(VK_RBUTTON) & 0x8000) keyState |= MK_RBUTTON;
3254 if(GetKeyState(VK_MBUTTON) & 0x8000) keyState |= MK_MBUTTON;
3255
3256 /* Note: It's the application's responsibility to free hDrop */
3257 /* TODO: Possible memory leak if app never calls GetData */
3258 fe.cfFormat = CF_HDROP;
3259 fe.ptd = NULL;
3260 fe.dwAspect = DVASPECT_CONTENT;
3261 fe.lindex = -1;
3262 fe.tymed = TYMED_HGLOBAL;
3263
3264 medium.u.hGlobal = hDrop;
3265 medium.tymed = TYMED_HGLOBAL;
3266 medium.pUnkForRelease = NULL;
3267
3268 pTarget->fDragEnter = TRUE;
3269 pTarget->dwEffect = dwEffect;
3270
3271 if(pTarget->pDataObject) {
3272 IDataObject_Release(pTarget->pDataObject);
3273 }
3274
3275 pTarget->pDataObject = IDataObject_Constructor();
3276 IDataObject_SetData(pTarget->pDataObject, &fe, &medium, TRUE);
3277 return IDropTarget_DragEnter(pTarget->dropTarget, pTarget->pDataObject, keyState, mousePosParam, &dwEffect) == S_OK;
3278}
3279//******************************************************************************
3280//******************************************************************************
3281BOOL WIN32API OLEDD_DragLeave(HWND hwnd)
3282{
3283 DropTargetNode *pTarget;
3284 HWND nexttar = hwnd;
3285
3286 dprintf(("OLEDD_DragLeave %x", hwnd));
3287
3288 do {
3289 pTarget = OLEDD_FindDropTarget(nexttar);
3290 }
3291 while(!pTarget && (nexttar = GetParent(nexttar)) != 0);
3292 if(pTarget == NULL) {
3293 return FALSE;
3294 }
3295 pTarget->fDragEnter = FALSE;
3296 if(pTarget->pDataObject) {
3297 IDataObject_Release(pTarget->pDataObject);
3298 pTarget->pDataObject = NULL;
3299 }
3300 return IDropTarget_DragLeave(pTarget->dropTarget) == S_OK;
3301}
3302//******************************************************************************
3303//******************************************************************************
3304
3305#include <oslibdnd.h>
3306
3307typedef struct
3308{
3309 /* IUnknown fields */
3310 ICOM_VFIELD(IDropTarget);
3311 DWORD ref;
3312
3313 LPVOID lpDnDData;
3314 LPSTR lpOS2StringData;
3315 LPVOID lpDragStruct;
3316 POINTL pt;
3317 HGLOBAL hDndData;
3318 FORMATETC format;
3319 STGMEDIUM medium;
3320 LPDATAOBJECT pDataObject;
3321} IDropTargetImpl;
3322
3323
3324/***************************************************************************
3325* IDropTarget_QueryInterface
3326*/
3327static HRESULT WINAPI IDropTarget_fnQueryInterface(IDropTarget *iface, REFIID riid, LPVOID * ppvObj)
3328{
3329 ICOM_THIS(IDropTargetImpl,iface);
3330
3331 dprintf(("IDropTarget_fnQueryInterface (%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj));
3332
3333 *ppvObj = NULL;
3334
3335 if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/
3336 {
3337 *ppvObj = This;
3338 }
3339 else if(IsEqualIID(riid, &IID_IDropTarget)) /*IDropTarget*/
3340 {
3341 *ppvObj = (IDropTarget*)This;
3342 }
3343
3344 if(*ppvObj)
3345 {
3346 IUnknown_AddRef((IUnknown*)*ppvObj);
3347 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
3348 return S_OK;
3349 }
3350 TRACE("-- Interface: E_NOINTERFACE\n");
3351 return E_NOINTERFACE;
3352}
3353
3354/**************************************************************************
3355* IDropTarget_AddRef
3356*/
3357static ULONG WINAPI IDropTarget_fnAddRef(IDropTarget *iface)
3358{
3359 ICOM_THIS(IDropTargetImpl,iface);
3360
3361 dprintf(("IDropTarget_fnAddRef (%p)->(count=%lu)\n",This, This->ref));
3362
3363 return ++(This->ref);
3364}
3365
3366/**************************************************************************
3367* IDropTarget_fnCleanup
3368*/
3369static ULONG WINAPI IDropTarget_fnCleanup(IDropTarget *iface)
3370{
3371 ICOM_THIS(IDropTargetImpl,iface);
3372
3373 if(This->pDataObject) {
3374 IDataObject_Release(This->pDataObject);
3375 This->pDataObject = 0;
3376 if(This->lpDnDData) {
3377 HeapFree(GetProcessHeap(), 0, This->lpDnDData);
3378 This->lpDnDData = NULL;
3379 }
3380 if(This->lpOS2StringData) {
3381 HeapFree(GetProcessHeap(), 0, This->lpOS2StringData);
3382 This->lpOS2StringData = NULL;
3383 }
3384 if(This->lpDragStruct) {
3385 OSLibFreeDragStruct(This->lpDragStruct);
3386 This->lpDragStruct = NULL;
3387 }
3388 }
3389 return S_OK;
3390}
3391/**************************************************************************
3392* IDropTarget_Release
3393*/
3394static ULONG WINAPI IDropTarget_fnRelease(IDropTarget *iface)
3395{
3396 ICOM_THIS(IDropTargetImpl,iface);
3397
3398 dprintf(("IDropTarget_fnRelease (%p)->(count=%lu)\n",This, This->ref));
3399
3400 IDropTarget_fnCleanup(iface);
3401 if(This->ref == 1) {
3402 if(This->hDndData) {
3403 GlobalFree(This->hDndData);
3404 This->hDndData = 0;
3405 }
3406 }
3407 return --(This->ref);
3408}
3409//******************************************************************************
3410//******************************************************************************
3411static HRESULT WINAPI IDropTarget_fnDragEnter(IDropTarget *iface, IDataObject* pDataObject,
3412 DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
3413{
3414 HRESULT ret;
3415 DWORD size, dwEffect;
3416 LPVOID lpData;
3417 DROPFILES *lpDrop;
3418 LPSTR *lpStringData;
3419 ICOM_THIS(IDropTargetImpl,iface);
3420 DWORD supportedformats[] = {CF_HDROP, CF_TEXT};
3421 int i;
3422
3423 dprintf(("IDropTarget_fnDragEnter %x (%d,%d)", grfKeyState, pt.x, pt.y));
3424 IDropTarget_fnCleanup(iface);
3425
3426 IDataObject_AddRef(pDataObject);
3427 This->pDataObject = pDataObject;
3428
3429#ifdef DEBUG
3430 {
3431 IEnumFORMATETC *enumfmt = NULL;
3432
3433 if(IDataObject_EnumFormatEtc(pDataObject, DATADIR_GET, &enumfmt) == S_OK) {
3434 for (;;) {
3435
3436 FORMATETC tmp;
3437 ULONG actual = 1, res;
3438
3439 res = IEnumFORMATETC_Next(enumfmt, 1, &tmp, &actual);
3440
3441 if(res != S_OK) break;
3442
3443 dprintf(("format %x typed %x", tmp.cfFormat, tmp.tymed));
3444 }
3445 IEnumFORMATETC_Release(enumfmt);
3446 }
3447 }
3448#endif
3449
3450 for(i=0;i<sizeof(supportedformats)/sizeof(supportedformats[0]);i++)
3451 {
3452 This->format.cfFormat = supportedformats[i];
3453 This->format.ptd = NULL;
3454 This->format.dwAspect = DVASPECT_CONTENT;
3455 This->format.lindex = -1;
3456 This->format.tymed = TYMED_HGLOBAL;
3457 ret = IDataObject_GetData(pDataObject, &This->format, &This->medium);
3458 if(ret != S_OK) {
3459 dprintf(("IDataObject_GetData failed with %x", ret));
3460 continue;
3461 }
3462 size = GlobalSize(This->medium.u.hGlobal);
3463 if(size == 0) {
3464 dprintf(("GlobalSize failed for %x", This->medium.u.hGlobal));
3465 ReleaseStgMedium(&This->medium);
3466 return E_OUTOFMEMORY;
3467 }
3468 dprintf(("handle %x size %d, format %x tymed %x", This->medium.u.hGlobal, size, This->format.cfFormat, This->format.tymed));
3469
3470 if(size == 1) {//empty string; use previous data
3471 if(This->hDndData == 0) {
3472 DebugInt3();
3473 ReleaseStgMedium(&This->medium);
3474 return E_OUTOFMEMORY;
3475 }
3476 This->medium.u.hGlobal = This->hDndData;
3477
3478 dprintf(("Reuse old global handle %x", This->hDndData));
3479 size = GlobalSize(This->medium.u.hGlobal);
3480 if(size == 0) {
3481 dprintf(("GlobalSize failed for %x", This->medium.u.hGlobal));
3482 ReleaseStgMedium(&This->medium);
3483 return E_OUTOFMEMORY;
3484 }
3485 dprintf(("handle %x size %d, format %x tymed %x", This->medium.u.hGlobal, size, This->format.cfFormat, This->format.tymed));
3486 }
3487 else This->hDndData = This->medium.u.hGlobal;
3488
3489 This->lpDnDData = (LPVOID)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
3490 if(This->lpDnDData == NULL) {
3491 dprintf(("HeapAlloc failed for %d bytes", size));
3492 return E_OUTOFMEMORY;
3493 }
3494 This->lpOS2StringData = (LPVOID)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size*2);
3495 if(This->lpOS2StringData == NULL) {
3496 dprintf(("HeapAlloc failed for %d bytes", size));
3497 return E_OUTOFMEMORY;
3498 }
3499 lpData = GlobalLock(This->medium.u.hGlobal);
3500
3501 if(This->format.cfFormat == CF_HDROP) {
3502 memcpy(This->lpDnDData, lpData, size);
3503 lpDrop = (DROPFILES *)This->lpDnDData;
3504 lpStringData = (LPSTR)(lpDrop) + lpDrop->pFiles;
3505 if(lpDrop->fWide == FALSE) {
3506 OemToCharA((LPSTR)lpStringData, (LPSTR)This->lpOS2StringData);
3507 }
3508 else {
3509 int len;
3510 len = lstrlenW((LPWSTR)lpStringData);
3511 WideCharToMultiByte( CP_OEMCP, 0, (LPWSTR)lpStringData, len, (LPSTR)This->lpOS2StringData, len, NULL, NULL );
3512 }
3513 }
3514 else
3515 if(This->format.cfFormat == CF_TEXT) {
3516 strcpy(This->lpDnDData, lpData);
3517 OemToCharA( This->lpDnDData, This->lpOS2StringData );
3518 }
3519 dprintf(("Drop string %s", This->lpOS2StringData));
3520 GlobalUnlock(This->medium.u.hGlobal);
3521
3522 This->pt = pt;
3523
3524 This->lpDragStruct = OSLibCreateDragStruct(hwndTracker, This->pt.x, This->pt.y, This->lpOS2StringData);
3525 if(This->lpDragStruct == NULL) {
3526 dprintf(("OSLibCreateDragStruct"));
3527 ReleaseStgMedium(&This->medium);
3528 return E_OUTOFMEMORY;
3529 }
3530
3531 dwEffect = OSLibDragOver(This->lpDragStruct, pt.x, pt.y);
3532 break;
3533 }
3534 if(ret != S_OK) {
3535 dprintf(("IDataObject_GetData failed (fatal) with %x", ret));
3536 return ret;
3537 }
3538 if(pdwEffect) {
3539 *pdwEffect = dwEffect;
3540 }
3541
3542 return S_OK;
3543}
3544//******************************************************************************
3545//******************************************************************************
3546static HRESULT WINAPI IDropTarget_fnDragOver(IDropTarget *iface, DWORD grfKeyState, POINTL pt,
3547 DWORD* pdwEffect)
3548{
3549 DWORD dwEffect;
3550 ICOM_THIS(IDropTargetImpl,iface);
3551
3552 dprintf(("IDropTarget_fnDragOver %x (%d,%d)", grfKeyState, pt.x, pt.y));
3553
3554 dwEffect = OSLibDragOver(This->lpDragStruct, pt.x, pt.y);
3555 if(pdwEffect) {
3556 *pdwEffect = dwEffect;
3557 }
3558 return S_OK;
3559}
3560//******************************************************************************
3561//******************************************************************************
3562static HRESULT WINAPI IDropTarget_fnDragLeave(IDropTarget *iface)
3563{
3564 ICOM_THIS(IDropTargetImpl,iface);
3565
3566 dprintf(("IDropTarget_fnDragLeave"));
3567
3568 OSLibDragLeave(This->lpDragStruct);
3569
3570 IDropTarget_fnCleanup(iface);
3571 return S_OK;
3572}
3573//******************************************************************************
3574//******************************************************************************
3575static HRESULT WINAPI IDropTarget_fnDrop(IDropTarget *iface, IDataObject* pDataObject, DWORD grfKeyState,
3576 POINTL pt, DWORD* pdwEffect)
3577{
3578 DWORD dwEffect;
3579 ICOM_THIS(IDropTargetImpl,iface);
3580
3581 dprintf(("IDropTarget_fnDrop %x (%d,%d) %s", grfKeyState, pt.x, pt.y, This->lpOS2StringData));
3582
3583 dwEffect = OSLibDragDrop(This->lpDragStruct, pt.x, pt.y, This->lpOS2StringData);
3584 if(pdwEffect) {
3585 *pdwEffect = dwEffect;
3586 }
3587 return S_OK;
3588}
3589//******************************************************************************
3590//******************************************************************************
3591
3592static struct ICOM_VTABLE(IDropTarget) droptarget =
3593{
3594 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
3595 IDropTarget_fnQueryInterface,
3596 IDropTarget_fnAddRef,
3597 IDropTarget_fnRelease,
3598 IDropTarget_fnDragEnter,
3599 IDropTarget_fnDragOver,
3600 IDropTarget_fnDragLeave,
3601 IDropTarget_fnDrop,
3602};
3603
3604
3605/**************************************************************************
3606* IDropTarget_Constructor
3607*/
3608static IDropTarget *IDropTarget_Constructor()
3609{
3610 IDropTargetImpl* dto;
3611
3612 dto = (IDropTargetImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDropTargetImpl));
3613
3614 if (dto)
3615 {
3616 dto->ref = 1;
3617 dto->pDataObject = NULL;
3618 dto->lpDnDData = NULL;
3619 dto->lpOS2StringData = NULL;
3620 dto->hDndData = 0;
3621 ICOM_VTBL(dto) = &droptarget;
3622 }
3623
3624 return (IDropTarget *)dto;
3625}
3626
3627#endif
3628
3629#ifndef __WIN32OS2__
3630/******************************************************************************
3631 * OleMetaFilePictFromIconAndLabel (OLE2.56)
3632 *
3633 * Returns a global memory handle to a metafile which contains the icon and
3634 * label given.
3635 * I guess the result of that should look somehow like desktop icons.
3636 * If no hIcon is given, we load the icon via lpszSourceFile and iIconIndex.
3637 * This code might be wrong at some places.
3638 */
3639HGLOBAL16 WINAPI OleMetaFilePictFromIconAndLabel16(
3640 HICON16 hIcon,
3641 LPCOLESTR16 lpszLabel,
3642 LPCOLESTR16 lpszSourceFile,
3643 UINT16 iIconIndex
3644) {
3645 METAFILEPICT16 *mf;
3646 HGLOBAL16 hmf;
3647 HDC16 hdc;
3648
3649 FIXME("(%04x, '%s', '%s', %d): incorrect metrics, please try to correct them !\n\n\n", hIcon, lpszLabel, lpszSourceFile, iIconIndex);
3650
3651 if (!hIcon) {
3652 if (lpszSourceFile) {
3653 HINSTANCE16 hInstance = LoadLibrary16(lpszSourceFile);
3654
3655 /* load the icon at index from lpszSourceFile */
3656 hIcon = (HICON16)LoadIconA(hInstance, (LPCSTR)(DWORD)iIconIndex);
3657 FreeLibrary16(hInstance);
3658 } else
3659 return (HGLOBAL)NULL;
3660 }
3661
3662 hdc = CreateMetaFile16(NULL);
3663 DrawIcon(hdc, 0, 0, hIcon); /* FIXME */
3664 TextOutA(hdc, 0, 0, lpszLabel, 1); /* FIXME */
3665 hmf = GlobalAlloc16(0, sizeof(METAFILEPICT16));
3666 mf = (METAFILEPICT16 *)GlobalLock16(hmf);
3667 mf->mm = MM_ANISOTROPIC;
3668 mf->xExt = 20; /* FIXME: bogus */
3669 mf->yExt = 20; /* dito */
3670 mf->hMF = CloseMetaFile16(hdc);
3671 return hmf;
3672}
3673#endif
3674
3675/******************************************************************************
3676 * DllDebugObjectRPCHook (OLE32.@)
3677 * turns on and off internal debugging, pointer is only used on macintosh
3678 */
3679
3680BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)
3681{
3682 FIXME("stub\n");
3683 return TRUE;
3684}
Note: See TracBrowser for help on using the repository browser.