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

Last change on this file since 6648 was 6648, checked in by bird, 24 years ago

Added $Id:$ keyword.

File size: 58.2 KB
Line 
1/* $Id: ole2.c,v 1.2 2001-09-05 13:17:11 bird Exp $ */
2/*
3 * OLE2 library
4 *
5 * Copyright 1995 Martin von Loewis
6 * Copyright 1999 Francis Beaudet
7 * Copyright 1999 Noel Borthwick
8 */
9
10#include <assert.h>
11#include <stdlib.h>
12#include <stdio.h>
13#include <string.h>
14
15#include "windef.h"
16#include "winbase.h"
17#include "wingdi.h"
18#include "winuser.h"
19#include "winerror.h"
20#include "ole2.h"
21#include "commctrl.h"
22#include "wine/obj_clientserver.h"
23#include "wine/winbase16.h"
24#include "wine/wingdi16.h"
25#include "wine/winuser16.h"
26#include "debugtools.h"
27#include "ole2ver.h"
28#include "winreg.h"
29#include "ole32_main.h"
30
31DEFAULT_DEBUG_CHANNEL(ole);
32DECLARE_DEBUG_CHANNEL(accel);
33
34/******************************************************************************
35 * These are static/global variables and internal data structures that the
36 * OLE module uses to maintain it's state.
37 */
38typedef struct tagDropTargetNode
39{
40 HWND hwndTarget;
41 IDropTarget* dropTarget;
42 struct tagDropTargetNode* prevDropTarget;
43 struct tagDropTargetNode* nextDropTarget;
44} DropTargetNode;
45
46typedef struct tagTrackerWindowInfo
47{
48 IDataObject* dataObject;
49 IDropSource* dropSource;
50 DWORD dwOKEffect;
51 DWORD* pdwEffect;
52 BOOL trackingDone;
53 HRESULT returnValue;
54
55 BOOL escPressed;
56 HWND curDragTargetHWND;
57 IDropTarget* curDragTarget;
58} TrackerWindowInfo;
59
60typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */
61{
62 HWND hwndFrame; /* The containers frame window */
63 HWND hwndActiveObject; /* The active objects window */
64 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */
65 HMENU hmenuCombined; /* The combined menu */
66 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */
67} OleMenuDescriptor;
68
69typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */
70{
71 DWORD tid; /* Thread Id */
72 HANDLE hHeap; /* Heap this is allocated from */
73 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */
74 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */
75 struct tagOleMenuHookItem *next;
76} OleMenuHookItem;
77
78static OleMenuHookItem *hook_list;
79
80/*
81 * This is the lock count on the OLE library. It is controlled by the
82 * OLEInitialize/OLEUninitialize methods.
83 */
84static ULONG OLE_moduleLockCount = 0;
85
86/*
87 * Name of our registered window class.
88 */
89static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
90
91/*
92 * This is the head of the Drop target container.
93 */
94static DropTargetNode* targetListHead = NULL;
95
96/******************************************************************************
97 * These are the prototypes of miscelaneous utility methods
98 */
99static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
100
101/******************************************************************************
102 * These are the prototypes of the utility methods used to manage a shared menu
103 */
104static void OLEMenu_Initialize();
105static void OLEMenu_UnInitialize();
106BOOL OLEMenu_InstallHooks( DWORD tid );
107BOOL OLEMenu_UnInstallHooks( DWORD tid );
108OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
109static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
110BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
111LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
112LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
113
114/******************************************************************************
115 * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
116 */
117void OLEClipbrd_UnInitialize();
118void OLEClipbrd_Initialize();
119
120/******************************************************************************
121 * These are the prototypes of the utility methods used for OLE Drag n Drop
122 */
123static void OLEDD_Initialize();
124static void OLEDD_UnInitialize();
125static void OLEDD_InsertDropTarget(
126 DropTargetNode* nodeToAdd);
127static DropTargetNode* OLEDD_ExtractDropTarget(
128 HWND hwndOfTarget);
129static DropTargetNode* OLEDD_FindDropTarget(
130 HWND hwndOfTarget);
131static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
132 HWND hwnd,
133 UINT uMsg,
134 WPARAM wParam,
135 LPARAM lParam);
136static void OLEDD_TrackMouseMove(
137 TrackerWindowInfo* trackerInfo,
138 POINT mousePos,
139 DWORD keyState);
140static void OLEDD_TrackStateChange(
141 TrackerWindowInfo* trackerInfo,
142 POINT mousePos,
143 DWORD keyState);
144static DWORD OLEDD_GetButtonState();
145
146
147/******************************************************************************
148 * OleBuildVersion [OLE2.1]
149 */
150DWORD WINAPI OleBuildVersion(void)
151{
152 TRACE("Returning version %d, build %d.\n", rmm, rup);
153 return (rmm<<16)+rup;
154}
155
156/***********************************************************************
157 * OleInitialize (OLE2.2) (OLE32.108)
158 */
159HRESULT WINAPI OleInitialize(LPVOID reserved)
160{
161 HRESULT hr;
162
163 TRACE("(%p)\n", reserved);
164
165 /*
166 * The first duty of the OleInitialize is to initialize the COM libraries.
167 */
168 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
169
170 /*
171 * If the CoInitializeEx call failed, the OLE libraries can't be
172 * initialized.
173 */
174 if (FAILED(hr))
175 return hr;
176
177 /*
178 * Then, it has to initialize the OLE specific modules.
179 * This includes:
180 * Clipboard
181 * Drag and Drop
182 * Object linking and Embedding
183 * In-place activation
184 */
185 if (OLE_moduleLockCount==0)
186{
187 /*
188 * Initialize the libraries.
189 */
190 TRACE("() - Initializing the OLE libraries\n");
191
192 /*
193 * OLE Clipboard
194 */
195 OLEClipbrd_Initialize();
196
197 /*
198 * Drag and Drop
199 */
200 OLEDD_Initialize();
201
202 /*
203 * OLE shared menu
204 */
205 OLEMenu_Initialize();
206}
207
208 /*
209 * Then, we increase the lock count on the OLE module.
210 */
211 OLE_moduleLockCount++;
212
213 return hr;
214}
215
216/******************************************************************************
217 * CoGetCurrentProcess [COMPOBJ.34] [OLE2.2][OLE32.108]
218 *
219 * NOTES
220 * Is DWORD really the correct return type for this function?
221 */
222DWORD WINAPI CoGetCurrentProcess(void)
223{
224 return GetCurrentProcessId();
225}
226
227/******************************************************************************
228 * OleUninitialize [OLE2.3] [OLE32.131]
229 */
230void WINAPI OleUninitialize(void)
231{
232 TRACE("()\n");
233
234 /*
235 * Decrease the lock count on the OLE module.
236 */
237 OLE_moduleLockCount--;
238
239 /*
240 * If we hit the bottom of the lock stack, free the libraries.
241 */
242 if (OLE_moduleLockCount==0)
243 {
244 /*
245 * Actually free the libraries.
246 */
247 TRACE("() - Freeing the last reference count\n");
248
249 /*
250 * OLE Clipboard
251 */
252 OLEClipbrd_UnInitialize();
253
254 /*
255 * Drag and Drop
256 */
257 OLEDD_UnInitialize();
258
259 /*
260 * OLE shared menu
261 */
262 OLEMenu_UnInitialize();
263 }
264
265 /*
266 * Then, uninitialize the COM libraries.
267 */
268 CoUninitialize();
269}
270
271#ifndef __WIN32OS2__
272//imessagefilter.cpp
273/******************************************************************************
274 * CoRegisterMessageFilter [OLE32.38]
275 */
276HRESULT WINAPI CoRegisterMessageFilter(
277 LPMESSAGEFILTER lpMessageFilter, /* [in] Pointer to interface */
278 LPMESSAGEFILTER *lplpMessageFilter /* [out] Indirect pointer to prior instance if non-NULL */
279) {
280 FIXME("stub\n");
281 if (lplpMessageFilter) {
282 *lplpMessageFilter = NULL;
283 }
284 return S_OK;
285}
286#endif
287
288/******************************************************************************
289 * OleInitializeWOW [OLE32.109]
290 */
291HRESULT WINAPI OleInitializeWOW(DWORD x) {
292 FIXME("(0x%08lx),stub!\n",x);
293 return 0;
294}
295
296/***********************************************************************
297 * RegisterDragDrop16 (OLE2.35)
298 */
299HRESULT WINAPI RegisterDragDrop16(
300 HWND16 hwnd,
301 LPDROPTARGET pDropTarget
302) {
303 FIXME("(0x%04x,%p),stub!\n",hwnd,pDropTarget);
304 return S_OK;
305}
306
307/***********************************************************************
308 * RegisterDragDrop (OLE32.139)
309 */
310HRESULT WINAPI RegisterDragDrop(
311 HWND hwnd,
312 LPDROPTARGET pDropTarget)
313{
314 DropTargetNode* dropTargetInfo;
315
316 TRACE("(0x%x,%p)\n", hwnd, pDropTarget);
317
318 /*
319 * First, check if the window is already registered.
320 */
321 dropTargetInfo = OLEDD_FindDropTarget(hwnd);
322
323 if (dropTargetInfo!=NULL)
324 return DRAGDROP_E_ALREADYREGISTERED;
325
326 /*
327 * If it's not there, we can add it. We first create a node for it.
328 */
329 dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
330
331 if (dropTargetInfo==NULL)
332 return E_OUTOFMEMORY;
333
334 dropTargetInfo->hwndTarget = hwnd;
335 dropTargetInfo->prevDropTarget = NULL;
336 dropTargetInfo->nextDropTarget = NULL;
337
338 /*
339 * Don't forget that this is an interface pointer, need to nail it down since
340 * we keep a copy of it.
341 */
342 dropTargetInfo->dropTarget = pDropTarget;
343 IDropTarget_AddRef(dropTargetInfo->dropTarget);
344
345 OLEDD_InsertDropTarget(dropTargetInfo);
346
347 return S_OK;
348}
349
350/***********************************************************************
351 * RevokeDragDrop16 (OLE2.36)
352 */
353HRESULT WINAPI RevokeDragDrop16(
354 HWND16 hwnd
355) {
356 FIXME("(0x%04x),stub!\n",hwnd);
357 return S_OK;
358}
359
360/***********************************************************************
361 * RevokeDragDrop (OLE32.141)
362 */
363HRESULT WINAPI RevokeDragDrop(
364 HWND hwnd)
365{
366 DropTargetNode* dropTargetInfo;
367
368 TRACE("(0x%x)\n", hwnd);
369
370 /*
371 * First, check if the window is already registered.
372 */
373 dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);
374
375 /*
376 * If it ain't in there, it's an error.
377 */
378 if (dropTargetInfo==NULL)
379 return DRAGDROP_E_NOTREGISTERED;
380
381 /*
382 * If it's in there, clean-up it's used memory and
383 * references
384 */
385 IDropTarget_Release(dropTargetInfo->dropTarget);
386 HeapFree(GetProcessHeap(), 0, dropTargetInfo);
387
388 return S_OK;
389}
390
391/***********************************************************************
392 * OleRegGetUserType (OLE32.122)
393 *
394 * This implementation of OleRegGetUserType ignores the dwFormOfType
395 * parameter and always returns the full name of the object. This is
396 * not too bad since this is the case for many objects because of the
397 * way they are registered.
398 */
399HRESULT WINAPI OleRegGetUserType(
400 REFCLSID clsid,
401 DWORD dwFormOfType,
402 LPOLESTR* pszUserType)
403{
404 char keyName[60];
405 DWORD dwKeyType;
406 DWORD cbData;
407 HKEY clsidKey;
408 LONG hres;
409 LPBYTE buffer;
410 HRESULT retVal;
411 /*
412 * Initialize the out parameter.
413 */
414 *pszUserType = NULL;
415
416 /*
417 * Build the key name we're looking for
418 */
419 sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
420 clsid->Data1, clsid->Data2, clsid->Data3,
421 clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
422 clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
423
424 TRACE("(%s, %ld, %p)\n", keyName, dwFormOfType, pszUserType);
425
426 /*
427 * Open the class id Key
428 */
429 hres = RegOpenKeyA(HKEY_CLASSES_ROOT,
430 keyName,
431 &clsidKey);
432
433 if (hres != ERROR_SUCCESS)
434 return REGDB_E_CLASSNOTREG;
435
436 /*
437 * Retrieve the size of the name string.
438 */
439 cbData = 0;
440
441 hres = RegQueryValueExA(clsidKey,
442 "",
443 NULL,
444 &dwKeyType,
445 NULL,
446 &cbData);
447
448 if (hres!=ERROR_SUCCESS)
449 {
450 RegCloseKey(clsidKey);
451 return REGDB_E_READREGDB;
452 }
453
454 /*
455 * Allocate a buffer for the registry value.
456 */
457 *pszUserType = CoTaskMemAlloc(cbData*2);
458
459 if (*pszUserType==NULL)
460 {
461 RegCloseKey(clsidKey);
462 return E_OUTOFMEMORY;
463 }
464
465 buffer = HeapAlloc(GetProcessHeap(), 0, cbData);
466
467 if (buffer == NULL)
468 {
469 RegCloseKey(clsidKey);
470 CoTaskMemFree(*pszUserType);
471 *pszUserType=NULL;
472 return E_OUTOFMEMORY;
473 }
474
475 hres = RegQueryValueExA(clsidKey,
476 "",
477 NULL,
478 &dwKeyType,
479 buffer,
480 &cbData);
481
482 RegCloseKey(clsidKey);
483
484
485 if (hres!=ERROR_SUCCESS)
486 {
487 CoTaskMemFree(*pszUserType);
488 *pszUserType=NULL;
489
490 retVal = REGDB_E_READREGDB;
491 }
492 else
493 {
494 MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ );
495 retVal = S_OK;
496 }
497 HeapFree(GetProcessHeap(), 0, buffer);
498
499 return retVal;
500}
501
502/***********************************************************************
503 * DoDragDrop [OLE32.65]
504 */
505HRESULT WINAPI DoDragDrop (
506 IDataObject *pDataObject, /* [in] ptr to the data obj */
507 IDropSource* pDropSource, /* [in] ptr to the source obj */
508 DWORD dwOKEffect, /* [in] effects allowed by the source */
509 DWORD *pdwEffect) /* [out] ptr to effects of the source */
510{
511 TrackerWindowInfo trackerInfo;
512 HWND hwndTrackWindow;
513 MSG msg;
514
515 TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
516
517 /*
518 * Setup the drag n drop tracking window.
519 */
520 trackerInfo.dataObject = pDataObject;
521 trackerInfo.dropSource = pDropSource;
522 trackerInfo.dwOKEffect = dwOKEffect;
523 trackerInfo.pdwEffect = pdwEffect;
524 trackerInfo.trackingDone = FALSE;
525 trackerInfo.escPressed = FALSE;
526 trackerInfo.curDragTargetHWND = 0;
527 trackerInfo.curDragTarget = 0;
528
529 hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
530 "TrackerWindow",
531 WS_POPUP,
532 CW_USEDEFAULT, CW_USEDEFAULT,
533 CW_USEDEFAULT, CW_USEDEFAULT,
534 0,
535 0,
536 0,
537 (LPVOID)&trackerInfo);
538
539 if (hwndTrackWindow!=0)
540 {
541 /*
542 * Capture the mouse input
543 */
544 SetCapture(hwndTrackWindow);
545
546 /*
547 * Pump messages. All mouse input should go the the capture window.
548 */
549 while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
550 {
551 if ( (msg.message >= WM_KEYFIRST) &&
552 (msg.message <= WM_KEYLAST) )
553 {
554 /*
555 * When keyboard messages are sent to windows on this thread, we
556 * want to ignore notify the drop source that the state changed.
557 * in the case of the Escape key, we also notify the drop source
558 * we give it a special meaning.
559 */
560 if ( (msg.message==WM_KEYDOWN) &&
561 (msg.wParam==VK_ESCAPE) )
562 {
563 trackerInfo.escPressed = TRUE;
564 }
565
566 /*
567 * Notify the drop source.
568 */
569 OLEDD_TrackStateChange(&trackerInfo,
570 msg.pt,
571 OLEDD_GetButtonState());
572 }
573 else
574 {
575 /*
576 * Dispatch the messages only when it's not a keyboard message.
577 */
578 DispatchMessageA(&msg);
579 }
580 }
581
582 /*
583 * Destroy the temporary window.
584 */
585 DestroyWindow(hwndTrackWindow);
586
587 return trackerInfo.returnValue;
588 }
589
590 return E_FAIL;
591}
592
593/***********************************************************************
594 * OleQueryLinkFromData [OLE32.118]
595 */
596HRESULT WINAPI OleQueryLinkFromData(
597 IDataObject* pSrcDataObject)
598{
599 FIXME("(%p),stub!\n", pSrcDataObject);
600 return S_OK;
601}
602
603/***********************************************************************
604 * OleRegGetMiscStatus [OLE32.121]
605 */
606HRESULT WINAPI OleRegGetMiscStatus(
607 REFCLSID clsid,
608 DWORD dwAspect,
609 DWORD* pdwStatus)
610{
611 char keyName[60];
612 HKEY clsidKey;
613 HKEY miscStatusKey;
614 HKEY aspectKey;
615 LONG result;
616
617 /*
618 * Initialize the out parameter.
619 */
620 *pdwStatus = 0;
621
622 /*
623 * Build the key name we're looking for
624 */
625 sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
626 clsid->Data1, clsid->Data2, clsid->Data3,
627 clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
628 clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
629
630 TRACE("(%s, %ld, %p)\n", keyName, dwAspect, pdwStatus);
631
632 /*
633 * Open the class id Key
634 */
635 result = RegOpenKeyA(HKEY_CLASSES_ROOT,
636 keyName,
637 &clsidKey);
638
639 if (result != ERROR_SUCCESS)
640 return REGDB_E_CLASSNOTREG;
641
642 /*
643 * Get the MiscStatus
644 */
645 result = RegOpenKeyA(clsidKey,
646 "MiscStatus",
647 &miscStatusKey);
648
649
650 if (result != ERROR_SUCCESS)
651 {
652 RegCloseKey(clsidKey);
653 return REGDB_E_READREGDB;
654 }
655
656 /*
657 * Read the default value
658 */
659 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
660
661 /*
662 * Open the key specific to the requested aspect.
663 */
664 sprintf(keyName, "%ld", dwAspect);
665
666 result = RegOpenKeyA(miscStatusKey,
667 keyName,
668 &aspectKey);
669
670 if (result == ERROR_SUCCESS)
671 {
672 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
673 RegCloseKey(aspectKey);
674 }
675
676 /*
677 * Cleanup
678 */
679 RegCloseKey(miscStatusKey);
680 RegCloseKey(clsidKey);
681
682 return S_OK;
683}
684
685/******************************************************************************
686 * OleSetContainedObject [OLE32.128]
687 */
688HRESULT WINAPI OleSetContainedObject(
689 LPUNKNOWN pUnknown,
690 BOOL fContained)
691{
692 IRunnableObject* runnable = NULL;
693 HRESULT hres;
694
695 TRACE("(%p,%x), stub!\n", pUnknown, fContained);
696
697 hres = IUnknown_QueryInterface(pUnknown,
698 &IID_IRunnableObject,
699 (void**)&runnable);
700
701 if (SUCCEEDED(hres))
702 {
703 hres = IRunnableObject_SetContainedObject(runnable, fContained);
704
705 IRunnableObject_Release(runnable);
706
707 return hres;
708 }
709
710 return S_OK;
711}
712
713/******************************************************************************
714 * OleLoad [OLE32.112]
715 */
716HRESULT WINAPI OleLoad(
717 LPSTORAGE pStg,
718 REFIID riid,
719 LPOLECLIENTSITE pClientSite,
720 LPVOID* ppvObj)
721{
722 IPersistStorage* persistStorage = NULL;
723 IOleObject* oleObject = NULL;
724 STATSTG storageInfo;
725 HRESULT hres;
726
727 TRACE("(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj);
728
729 /*
730 * TODO, Conversion ... OleDoAutoConvert
731 */
732
733 /*
734 * Get the class ID for the object.
735 */
736 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
737
738 /*
739 * Now, try and create the handler for the object
740 */
741 hres = CoCreateInstance(&storageInfo.clsid,
742 NULL,
743 CLSCTX_INPROC_HANDLER,
744 &IID_IOleObject,
745 (void**)&oleObject);
746
747 /*
748 * If that fails, as it will most times, load the default
749 * OLE handler.
750 */
751 if (FAILED(hres))
752 {
753 hres = OleCreateDefaultHandler(&storageInfo.clsid,
754 NULL,
755 &IID_IOleObject,
756 (void**)&oleObject);
757 }
758
759 /*
760 * If we couldn't find a handler... this is bad. Abort the whole thing.
761 */
762 if (FAILED(hres))
763 return hres;
764
765 /*
766 * Inform the new object of it's client site.
767 */
768 hres = IOleObject_SetClientSite(oleObject, pClientSite);
769
770 /*
771 * Initialize the object with it's IPersistStorage interface.
772 */
773 hres = IOleObject_QueryInterface(oleObject,
774 &IID_IPersistStorage,
775 (void**)&persistStorage);
776
777 if (SUCCEEDED(hres))
778 {
779 IPersistStorage_Load(persistStorage, pStg);
780
781 IPersistStorage_Release(persistStorage);
782 persistStorage = NULL;
783 }
784
785 /*
786 * Return the requested interface to the caller.
787 */
788 hres = IOleObject_QueryInterface(oleObject, riid, ppvObj);
789
790 /*
791 * Cleanup interfaces used internally
792 */
793 IOleObject_Release(oleObject);
794
795 return hres;
796}
797
798/***********************************************************************
799 * OleSave [OLE32.124]
800 */
801HRESULT WINAPI OleSave(
802 LPPERSISTSTORAGE pPS,
803 LPSTORAGE pStg,
804 BOOL fSameAsLoad)
805{
806 HRESULT hres;
807 CLSID objectClass;
808
809 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
810
811 /*
812 * First, we transfer the class ID (if available)
813 */
814 hres = IPersistStorage_GetClassID(pPS, &objectClass);
815
816 if (SUCCEEDED(hres))
817 {
818 WriteClassStg(pStg, &objectClass);
819 }
820
821 /*
822 * Then, we ask the object to save itself to the
823 * storage. If it is successful, we commit the storage.
824 */
825 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
826
827 if (SUCCEEDED(hres))
828 {
829 IStorage_Commit(pStg,
830 STGC_DEFAULT);
831 }
832
833 return hres;
834}
835
836
837/******************************************************************************
838 * OleLockRunning [OLE32.114]
839 */
840HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)
841{
842 IRunnableObject* runnable = NULL;
843 HRESULT hres;
844
845 TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);
846
847 hres = IUnknown_QueryInterface(pUnknown,
848 &IID_IRunnableObject,
849 (void**)&runnable);
850
851 if (SUCCEEDED(hres))
852 {
853 hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);
854
855 IRunnableObject_Release(runnable);
856
857 return hres;
858 }
859 else
860 return E_INVALIDARG;
861}
862
863
864/**************************************************************************
865 * Internal methods to manage the shared OLE menu in response to the
866 * OLE***MenuDescriptor API
867 */
868
869/***
870 * OLEMenu_Initialize()
871 *
872 * Initializes the OLEMENU data structures.
873 */
874static void OLEMenu_Initialize()
875{
876}
877
878/***
879 * OLEMenu_UnInitialize()
880 *
881 * Releases the OLEMENU data structures.
882 */
883static void OLEMenu_UnInitialize()
884{
885}
886
887/*************************************************************************
888 * OLEMenu_InstallHooks
889 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
890 *
891 * RETURNS: TRUE if message hooks were succesfully installed
892 * FALSE on failure
893 */
894BOOL OLEMenu_InstallHooks( DWORD tid )
895{
896 OleMenuHookItem *pHookItem = NULL;
897
898 /* Create an entry for the hook table */
899 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
900 sizeof(OleMenuHookItem)) ) )
901 return FALSE;
902
903 pHookItem->tid = tid;
904 pHookItem->hHeap = GetProcessHeap();
905
906 /* Install a thread scope message hook for WH_GETMESSAGE */
907 pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
908 0, GetCurrentThreadId() );
909 if ( !pHookItem->GetMsg_hHook )
910 goto CLEANUP;
911
912 /* Install a thread scope message hook for WH_CALLWNDPROC */
913 pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
914 0, GetCurrentThreadId() );
915 if ( !pHookItem->CallWndProc_hHook )
916 goto CLEANUP;
917
918 /* Insert the hook table entry */
919 pHookItem->next = hook_list;
920 hook_list = pHookItem;
921
922 return TRUE;
923
924CLEANUP:
925 /* Unhook any hooks */
926 if ( pHookItem->GetMsg_hHook )
927 UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
928 if ( pHookItem->CallWndProc_hHook )
929 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
930 /* Release the hook table entry */
931 HeapFree(pHookItem->hHeap, 0, pHookItem );
932
933 return FALSE;
934}
935
936/*************************************************************************
937 * OLEMenu_UnInstallHooks
938 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
939 *
940 * RETURNS: TRUE if message hooks were succesfully installed
941 * FALSE on failure
942 */
943BOOL OLEMenu_UnInstallHooks( DWORD tid )
944{
945 OleMenuHookItem *pHookItem = NULL;
946 OleMenuHookItem **ppHook = &hook_list;
947
948 while (*ppHook)
949 {
950 if ((*ppHook)->tid == tid)
951 {
952 pHookItem = *ppHook;
953 *ppHook = pHookItem->next;
954 break;
955 }
956 ppHook = &(*ppHook)->next;
957 }
958 if (!pHookItem) return FALSE;
959
960 /* Uninstall the hooks installed for this thread */
961 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
962 goto CLEANUP;
963 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
964 goto CLEANUP;
965
966 /* Release the hook table entry */
967 HeapFree(pHookItem->hHeap, 0, pHookItem );
968
969 return TRUE;
970
971CLEANUP:
972 /* Release the hook table entry */
973 if (pHookItem)
974 HeapFree(pHookItem->hHeap, 0, pHookItem );
975
976 return FALSE;
977}
978
979/*************************************************************************
980 * OLEMenu_IsHookInstalled
981 * Tests if OLEMenu hooks have been installed for a thread
982 *
983 * RETURNS: The pointer and index of the hook table entry for the tid
984 * NULL and -1 for the index if no hooks were installed for this thread
985 */
986OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
987{
988 OleMenuHookItem *pHookItem = NULL;
989
990 /* Do a simple linear search for an entry whose tid matches ours.
991 * We really need a map but efficiency is not a concern here. */
992 for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
993 {
994 if ( tid == pHookItem->tid )
995 return pHookItem;
996 }
997
998 return NULL;
999}
1000
1001/***********************************************************************
1002 * OLEMenu_FindMainMenuIndex
1003 *
1004 * Used by OLEMenu API to find the top level group a menu item belongs to.
1005 * On success pnPos contains the index of the item in the top level menu group
1006 *
1007 * RETURNS: TRUE if the ID was found, FALSE on failure
1008 */
1009static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
1010{
1011 UINT i, nItems;
1012
1013 nItems = GetMenuItemCount( hMainMenu );
1014
1015 for (i = 0; i < nItems; i++)
1016 {
1017 HMENU hsubmenu;
1018
1019 /* Is the current item a submenu? */
1020 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) )
1021 {
1022 /* If the handle is the same we're done */
1023 if ( hsubmenu == hPopupMenu )
1024 {
1025 if (pnPos)
1026 *pnPos = i;
1027 return TRUE;
1028 }
1029 /* Recursively search without updating pnPos */
1030 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
1031 {
1032 if (pnPos)
1033 *pnPos = i;
1034 return TRUE;
1035 }
1036 }
1037 }
1038
1039 return FALSE;
1040}
1041
1042/***********************************************************************
1043 * OLEMenu_SetIsServerMenu
1044 *
1045 * Checks whether a popup menu belongs to a shared menu group which is
1046 * owned by the server, and sets the menu descriptor state accordingly.
1047 * All menu messages from these groups should be routed to the server.
1048 *
1049 * RETURNS: TRUE if the popup menu is part of a server owned group
1050 * FASE if the popup menu is part of a container owned group
1051 */
1052BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1053{
1054 UINT nPos = 0, nWidth, i;
1055
1056 pOleMenuDescriptor->bIsServerItem = FALSE;
1057
1058 /* Don't bother searching if the popup is the combined menu itself */
1059 if ( hmenu == pOleMenuDescriptor->hmenuCombined )
1060 return FALSE;
1061
1062 /* Find the menu item index in the shared OLE menu that this item belongs to */
1063 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) )
1064 return FALSE;
1065
1066 /* The group widths array has counts for the number of elements
1067 * in the groups File, Edit, Container, Object, Window, Help.
1068 * The Edit, Object & Help groups belong to the server object
1069 * and the other three belong to the container.
1070 * Loop thru the group widths and locate the group we are a member of.
1071 */
1072 for ( i = 0, nWidth = 0; i < 6; i++ )
1073 {
1074 nWidth += pOleMenuDescriptor->mgw.width[i];
1075 if ( nPos < nWidth )
1076 {
1077 /* Odd elements are server menu widths */
1078 pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
1079 break;
1080 }
1081 }
1082
1083 return pOleMenuDescriptor->bIsServerItem;
1084}
1085
1086/*************************************************************************
1087 * OLEMenu_CallWndProc
1088 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
1089 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1090 */
1091LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1092{
1093 LPCWPSTRUCT pMsg = NULL;
1094 HOLEMENU hOleMenu = 0;
1095 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1096 OleMenuHookItem *pHookItem = NULL;
1097 WORD fuFlags;
1098
1099 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1100
1101 /* Check if we're being asked to process the message */
1102 if ( HC_ACTION != code )
1103 goto NEXTHOOK;
1104
1105 /* Retrieve the current message being dispatched from lParam */
1106 pMsg = (LPCWPSTRUCT)lParam;
1107
1108 /* Check if the message is destined for a window we are interested in:
1109 * If the window has an OLEMenu property we may need to dispatch
1110 * the menu message to its active objects window instead. */
1111
1112 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1113 if ( !hOleMenu )
1114 goto NEXTHOOK;
1115
1116 /* Get the menu descriptor */
1117 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1118 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1119 goto NEXTHOOK;
1120
1121 /* Process menu messages */
1122 switch( pMsg->message )
1123 {
1124 case WM_INITMENU:
1125 {
1126 /* Reset the menu descriptor state */
1127 pOleMenuDescriptor->bIsServerItem = FALSE;
1128
1129 /* Send this message to the server as well */
1130 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1131 pMsg->message, pMsg->wParam, pMsg->lParam );
1132 goto NEXTHOOK;
1133 }
1134
1135 case WM_INITMENUPOPUP:
1136 {
1137 /* Save the state for whether this is a server owned menu */
1138 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
1139 break;
1140 }
1141
1142 case WM_MENUSELECT:
1143 {
1144 fuFlags = HIWORD(pMsg->wParam); /* Get flags */
1145 if ( fuFlags & MF_SYSMENU )
1146 goto NEXTHOOK;
1147
1148 /* Save the state for whether this is a server owned popup menu */
1149 else if ( fuFlags & MF_POPUP )
1150 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
1151
1152 break;
1153 }
1154
1155 case WM_DRAWITEM:
1156 {
1157 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
1158 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
1159 goto NEXTHOOK; /* Not a menu message */
1160
1161 break;
1162 }
1163
1164 default:
1165 goto NEXTHOOK;
1166 }
1167
1168 /* If the message was for the server dispatch it accordingly */
1169 if ( pOleMenuDescriptor->bIsServerItem )
1170 {
1171 SendMessageA( pOleMenuDescriptor->hwndActiveObject,
1172 pMsg->message, pMsg->wParam, pMsg->lParam );
1173 }
1174
1175NEXTHOOK:
1176 if ( pOleMenuDescriptor )
1177 GlobalUnlock( hOleMenu );
1178
1179 /* Lookup the hook item for the current thread */
1180 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1181 {
1182 /* This should never fail!! */
1183 WARN("could not retrieve hHook for current thread!\n" );
1184 return 0;
1185 }
1186
1187 /* Pass on the message to the next hooker */
1188 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
1189}
1190
1191/*************************************************************************
1192 * OLEMenu_GetMsgProc
1193 * Thread scope WH_GETMESSAGE hook proc filter function (callback)
1194 * This is invoked from a message hook installed in OleSetMenuDescriptor.
1195 */
1196LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1197{
1198 LPMSG pMsg = NULL;
1199 HOLEMENU hOleMenu = 0;
1200 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1201 OleMenuHookItem *pHookItem = NULL;
1202 WORD wCode;
1203
1204 TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam );
1205
1206 /* Check if we're being asked to process a messages */
1207 if ( HC_ACTION != code )
1208 goto NEXTHOOK;
1209
1210 /* Retrieve the current message being dispatched from lParam */
1211 pMsg = (LPMSG)lParam;
1212
1213 /* Check if the message is destined for a window we are interested in:
1214 * If the window has an OLEMenu property we may need to dispatch
1215 * the menu message to its active objects window instead. */
1216
1217 hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1218 if ( !hOleMenu )
1219 goto NEXTHOOK;
1220
1221 /* Process menu messages */
1222 switch( pMsg->message )
1223 {
1224 case WM_COMMAND:
1225 {
1226 wCode = HIWORD(pMsg->wParam); /* Get notification code */
1227 if ( wCode )
1228 goto NEXTHOOK; /* Not a menu message */
1229 break;
1230 }
1231 default:
1232 goto NEXTHOOK;
1233 }
1234
1235 /* Get the menu descriptor */
1236 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1237 if ( !pOleMenuDescriptor ) /* Bad descriptor! */
1238 goto NEXTHOOK;
1239
1240 /* If the message was for the server dispatch it accordingly */
1241 if ( pOleMenuDescriptor->bIsServerItem )
1242 {
1243 /* Change the hWnd in the message to the active objects hWnd.
1244 * The message loop which reads this message will automatically
1245 * dispatch it to the embedded objects window. */
1246 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
1247 }
1248
1249NEXTHOOK:
1250 if ( pOleMenuDescriptor )
1251 GlobalUnlock( hOleMenu );
1252
1253 /* Lookup the hook item for the current thread */
1254 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1255 {
1256 /* This should never fail!! */
1257 WARN("could not retrieve hHook for current thread!\n" );
1258 return FALSE;
1259 }
1260
1261 /* Pass on the message to the next hooker */
1262 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
1263}
1264
1265/***********************************************************************
1266 * OleCreateMenuDescriptor [OLE32.97]
1267 * Creates an OLE menu descriptor for OLE to use when dispatching
1268 * menu messages and commands.
1269 *
1270 * PARAMS:
1271 * hmenuCombined - Handle to the objects combined menu
1272 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group
1273 *
1274 */
1275HOLEMENU WINAPI OleCreateMenuDescriptor(
1276 HMENU hmenuCombined,
1277 LPOLEMENUGROUPWIDTHS lpMenuWidths)
1278{
1279 HOLEMENU hOleMenu;
1280 OleMenuDescriptor *pOleMenuDescriptor;
1281 int i;
1282
1283 if ( !hmenuCombined || !lpMenuWidths )
1284 return 0;
1285
1286 /* Create an OLE menu descriptor */
1287 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
1288 sizeof(OleMenuDescriptor) ) ) )
1289 return 0;
1290
1291 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1292 if ( !pOleMenuDescriptor )
1293 return 0;
1294
1295 /* Initialize menu group widths and hmenu */
1296 for ( i = 0; i < 6; i++ )
1297 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1298
1299 pOleMenuDescriptor->hmenuCombined = hmenuCombined;
1300 pOleMenuDescriptor->bIsServerItem = FALSE;
1301 GlobalUnlock( hOleMenu );
1302
1303 return hOleMenu;
1304}
1305
1306/***********************************************************************
1307 * OleDestroyMenuDescriptor [OLE32.99]
1308 * Destroy the shared menu descriptor
1309 */
1310HRESULT WINAPI OleDestroyMenuDescriptor(
1311 HOLEMENU hmenuDescriptor)
1312{
1313 if ( hmenuDescriptor )
1314 GlobalFree( hmenuDescriptor );
1315 return S_OK;
1316}
1317
1318/***********************************************************************
1319 * OleSetMenuDescriptor [OLE32.129]
1320 * Installs or removes OLE dispatching code for the containers frame window
1321 * FIXME: The lpFrame and lpActiveObject parameters are currently ignored
1322 * OLE should install context sensitive help F1 filtering for the app when
1323 * these are non null.
1324 *
1325 * PARAMS:
1326 * hOleMenu Handle to composite menu descriptor
1327 * hwndFrame Handle to containers frame window
1328 * hwndActiveObject Handle to objects in-place activation window
1329 * lpFrame Pointer to IOleInPlaceFrame on containers window
1330 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object
1331 *
1332 * RETURNS:
1333 * S_OK - menu installed correctly
1334 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1335 */
1336HRESULT WINAPI OleSetMenuDescriptor(
1337 HOLEMENU hOleMenu,
1338 HWND hwndFrame,
1339 HWND hwndActiveObject,
1340 LPOLEINPLACEFRAME lpFrame,
1341 LPOLEINPLACEACTIVEOBJECT lpActiveObject)
1342{
1343 OleMenuDescriptor *pOleMenuDescriptor = NULL;
1344
1345 /* Check args */
1346 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
1347 return E_INVALIDARG;
1348
1349 if ( lpFrame || lpActiveObject )
1350 {
1351 FIXME("(%x, %x, %x, %p, %p), Context sensitive help filtering not implemented!\n",
1352 (unsigned int)hOleMenu,
1353 hwndFrame,
1354 hwndActiveObject,
1355 lpFrame,
1356 lpActiveObject);
1357 }
1358
1359 /* Set up a message hook to intercept the containers frame window messages.
1360 * The message filter is responsible for dispatching menu messages from the
1361 * shared menu which are intended for the object.
1362 */
1363
1364 if ( hOleMenu ) /* Want to install dispatching code */
1365 {
1366 /* If OLEMenu hooks are already installed for this thread, fail
1367 * Note: This effectively means that OleSetMenuDescriptor cannot
1368 * be called twice in succession on the same frame window
1369 * without first calling it with a null hOleMenu to uninstall */
1370 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1371 return E_FAIL;
1372
1373 /* Get the menu descriptor */
1374 pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
1375 if ( !pOleMenuDescriptor )
1376 return E_UNEXPECTED;
1377
1378 /* Update the menu descriptor */
1379 pOleMenuDescriptor->hwndFrame = hwndFrame;
1380 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
1381
1382 GlobalUnlock( hOleMenu );
1383 pOleMenuDescriptor = NULL;
1384
1385 /* Add a menu descriptor windows property to the frame window */
1386 SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
1387
1388 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
1389 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
1390 return E_FAIL;
1391 }
1392 else /* Want to uninstall dispatching code */
1393 {
1394 /* Uninstall the hooks */
1395 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
1396 return E_FAIL;
1397
1398 /* Remove the menu descriptor property from the frame window */
1399 RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
1400 }
1401
1402 return S_OK;
1403}
1404
1405/******************************************************************************
1406 * IsAccelerator [OLE32.75]
1407 * Mostly copied from controls/menu.c TranslateAccelerator implementation
1408 */
1409BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
1410{
1411 /* YES, Accel16! */
1412 LPACCEL16 lpAccelTbl;
1413 int i;
1414
1415 if(!lpMsg) return FALSE;
1416#ifdef __WIN32OS2__
1417 if (!hAccel || !(lpAccelTbl = (LPACCEL16)LockResource(hAccel)))
1418#else
1419 if (!hAccel || !(lpAccelTbl = (LPACCEL16)LockResource16(hAccel)))
1420#endif
1421 {
1422 WARN_(accel)("invalid accel handle=%04x\n", hAccel);
1423 return FALSE;
1424 }
1425 if((lpMsg->message != WM_KEYDOWN &&
1426 lpMsg->message != WM_KEYUP &&
1427 lpMsg->message != WM_SYSKEYDOWN &&
1428 lpMsg->message != WM_SYSKEYUP &&
1429 lpMsg->message != WM_CHAR)) return FALSE;
1430
1431 TRACE_(accel)("hAccel=%04x, cAccelEntries=%d,"
1432 "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%08lx\n",
1433 hAccel, cAccelEntries,
1434 lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
1435 for(i = 0; i < cAccelEntries; i++)
1436 {
1437 if(lpAccelTbl[i].key != lpMsg->wParam)
1438 continue;
1439
1440 if(lpMsg->message == WM_CHAR)
1441 {
1442 if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY))
1443 {
1444 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", lpMsg->wParam & 0xff);
1445 goto found;
1446 }
1447 }
1448 else
1449 {
1450 if(lpAccelTbl[i].fVirt & FVIRTKEY)
1451 {
1452 INT mask = 0;
1453 TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n",
1454 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff);
1455 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
1456 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
1457 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
1458 if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found;
1459 TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n");
1460 }
1461 else
1462 {
1463 if(!(lpMsg->lParam & 0x01000000)) /* no special_key */
1464 {
1465 if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000))
1466 { /* ^^ ALT pressed */
1467 TRACE_(accel)("found accel for Alt-%c\n", lpMsg->wParam & 0xff);
1468 goto found;
1469 }
1470 }
1471 }
1472 }
1473 }
1474
1475 WARN_(accel)("couldn't translate accelerator key\n");
1476 return FALSE;
1477
1478found:
1479 if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
1480 return TRUE;
1481}
1482
1483/***********************************************************************
1484 * ReleaseStgMedium [OLE32.140]
1485 */
1486void WINAPI ReleaseStgMedium(
1487 STGMEDIUM* pmedium)
1488{
1489 switch (pmedium->tymed)
1490 {
1491 case TYMED_HGLOBAL:
1492 {
1493 if ( (pmedium->pUnkForRelease==0) &&
1494 (pmedium->u.hGlobal!=0) )
1495 GlobalFree(pmedium->u.hGlobal);
1496
1497 pmedium->u.hGlobal = 0;
1498 break;
1499 }
1500 case TYMED_FILE:
1501 {
1502 if (pmedium->u.lpszFileName!=0)
1503 {
1504 if (pmedium->pUnkForRelease==0)
1505 {
1506 DeleteFileW(pmedium->u.lpszFileName);
1507 }
1508
1509 CoTaskMemFree(pmedium->u.lpszFileName);
1510 }
1511
1512 pmedium->u.lpszFileName = 0;
1513 break;
1514 }
1515 case TYMED_ISTREAM:
1516 {
1517 if (pmedium->u.pstm!=0)
1518 {
1519 IStream_Release(pmedium->u.pstm);
1520 }
1521
1522 pmedium->u.pstm = 0;
1523 break;
1524 }
1525 case TYMED_ISTORAGE:
1526 {
1527 if (pmedium->u.pstg!=0)
1528 {
1529 IStorage_Release(pmedium->u.pstg);
1530 }
1531
1532 pmedium->u.pstg = 0;
1533 break;
1534 }
1535 case TYMED_GDI:
1536 {
1537 if ( (pmedium->pUnkForRelease==0) &&
1538 (pmedium->u.hGlobal!=0) )
1539 DeleteObject(pmedium->u.hGlobal);
1540
1541 pmedium->u.hGlobal = 0;
1542 break;
1543 }
1544 case TYMED_MFPICT:
1545 {
1546 if ( (pmedium->pUnkForRelease==0) &&
1547 (pmedium->u.hMetaFilePict!=0) )
1548 {
1549 LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);
1550 DeleteMetaFile(pMP->hMF);
1551 GlobalUnlock(pmedium->u.hMetaFilePict);
1552 GlobalFree(pmedium->u.hMetaFilePict);
1553 }
1554
1555 pmedium->u.hMetaFilePict = 0;
1556 break;
1557 }
1558 case TYMED_ENHMF:
1559 {
1560 if ( (pmedium->pUnkForRelease==0) &&
1561 (pmedium->u.hEnhMetaFile!=0) )
1562 {
1563 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
1564 }
1565
1566 pmedium->u.hEnhMetaFile = 0;
1567 break;
1568 }
1569 case TYMED_NULL:
1570 default:
1571 break;
1572 }
1573
1574 /*
1575 * After cleaning up, the unknown is released
1576 */
1577 if (pmedium->pUnkForRelease!=0)
1578 {
1579 IUnknown_Release(pmedium->pUnkForRelease);
1580 pmedium->pUnkForRelease = 0;
1581 }
1582}
1583
1584/***
1585 * OLEDD_Initialize()
1586 *
1587 * Initializes the OLE drag and drop data structures.
1588 */
1589static void OLEDD_Initialize()
1590{
1591 WNDCLASSA wndClass;
1592
1593 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1594 wndClass.style = CS_GLOBALCLASS;
1595 wndClass.lpfnWndProc = (WNDPROC)OLEDD_DragTrackerWindowProc;
1596 wndClass.cbClsExtra = 0;
1597 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*);
1598 wndClass.hCursor = 0;
1599 wndClass.hbrBackground = 0;
1600 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1601
1602 RegisterClassA (&wndClass);
1603}
1604
1605/***
1606 * OLEDD_UnInitialize()
1607 *
1608 * Releases the OLE drag and drop data structures.
1609 */
1610static void OLEDD_UnInitialize()
1611{
1612 /*
1613 * Simply empty the list.
1614 */
1615 while (targetListHead!=NULL)
1616 {
1617 RevokeDragDrop(targetListHead->hwndTarget);
1618 }
1619}
1620
1621/***
1622 * OLEDD_InsertDropTarget()
1623 *
1624 * Insert the target node in the tree.
1625 */
1626static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
1627{
1628 DropTargetNode* curNode;
1629 DropTargetNode** parentNodeLink;
1630
1631 /*
1632 * Iterate the tree to find the insertion point.
1633 */
1634 curNode = targetListHead;
1635 parentNodeLink = &targetListHead;
1636
1637 while (curNode!=NULL)
1638 {
1639 if (nodeToAdd->hwndTarget<curNode->hwndTarget)
1640 {
1641 /*
1642 * If the node we want to add has a smaller HWND, go left
1643 */
1644 parentNodeLink = &curNode->prevDropTarget;
1645 curNode = curNode->prevDropTarget;
1646 }
1647 else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
1648 {
1649 /*
1650 * If the node we want to add has a larger HWND, go right
1651 */
1652 parentNodeLink = &curNode->nextDropTarget;
1653 curNode = curNode->nextDropTarget;
1654 }
1655 else
1656 {
1657 /*
1658 * The item was found in the list. It shouldn't have been there
1659 */
1660 assert(FALSE);
1661 return;
1662 }
1663 }
1664
1665 /*
1666 * If we get here, we have found a spot for our item. The parentNodeLink
1667 * pointer points to the pointer that we have to modify.
1668 * The curNode should be NULL. We just have to establish the link and Voila!
1669 */
1670 assert(curNode==NULL);
1671 assert(parentNodeLink!=NULL);
1672 assert(*parentNodeLink==NULL);
1673
1674 *parentNodeLink=nodeToAdd;
1675}
1676
1677/***
1678 * OLEDD_ExtractDropTarget()
1679 *
1680 * Removes the target node from the tree.
1681 */
1682static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
1683{
1684 DropTargetNode* curNode;
1685 DropTargetNode** parentNodeLink;
1686
1687 /*
1688 * Iterate the tree to find the insertion point.
1689 */
1690 curNode = targetListHead;
1691 parentNodeLink = &targetListHead;
1692
1693 while (curNode!=NULL)
1694 {
1695 if (hwndOfTarget<curNode->hwndTarget)
1696 {
1697 /*
1698 * If the node we want to add has a smaller HWND, go left
1699 */
1700 parentNodeLink = &curNode->prevDropTarget;
1701 curNode = curNode->prevDropTarget;
1702 }
1703 else if (hwndOfTarget>curNode->hwndTarget)
1704 {
1705 /*
1706 * If the node we want to add has a larger HWND, go right
1707 */
1708 parentNodeLink = &curNode->nextDropTarget;
1709 curNode = curNode->nextDropTarget;
1710 }
1711 else
1712 {
1713 /*
1714 * The item was found in the list. Detach it from it's parent and
1715 * re-insert it's kids in the tree.
1716 */
1717 assert(parentNodeLink!=NULL);
1718 assert(*parentNodeLink==curNode);
1719
1720 /*
1721 * We arbitrately re-attach the left sub-tree to the parent.
1722 */
1723 *parentNodeLink = curNode->prevDropTarget;
1724
1725 /*
1726 * And we re-insert the right subtree
1727 */
1728 if (curNode->nextDropTarget!=NULL)
1729 {
1730 OLEDD_InsertDropTarget(curNode->nextDropTarget);
1731 }
1732
1733 /*
1734 * The node we found is still a valid node once we complete
1735 * the unlinking of the kids.
1736 */
1737 curNode->nextDropTarget=NULL;
1738 curNode->prevDropTarget=NULL;
1739
1740 return curNode;
1741 }
1742 }
1743
1744 /*
1745 * If we get here, the node is not in the tree
1746 */
1747 return NULL;
1748}
1749
1750/***
1751 * OLEDD_FindDropTarget()
1752 *
1753 * Finds information about the drop target.
1754 */
1755static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1756{
1757 DropTargetNode* curNode;
1758
1759 /*
1760 * Iterate the tree to find the HWND value.
1761 */
1762 curNode = targetListHead;
1763
1764 while (curNode!=NULL)
1765 {
1766 if (hwndOfTarget<curNode->hwndTarget)
1767 {
1768 /*
1769 * If the node we want to add has a smaller HWND, go left
1770 */
1771 curNode = curNode->prevDropTarget;
1772 }
1773 else if (hwndOfTarget>curNode->hwndTarget)
1774 {
1775 /*
1776 * If the node we want to add has a larger HWND, go right
1777 */
1778 curNode = curNode->nextDropTarget;
1779 }
1780 else
1781 {
1782 /*
1783 * The item was found in the list.
1784 */
1785 return curNode;
1786 }
1787 }
1788
1789 /*
1790 * If we get here, the item is not in the list
1791 */
1792 return NULL;
1793}
1794
1795/***
1796 * OLEDD_DragTrackerWindowProc()
1797 *
1798 * This method is the WindowProcedure of the drag n drop tracking
1799 * window. During a drag n Drop operation, an invisible window is created
1800 * to receive the user input and act upon it. This procedure is in charge
1801 * of this behavior.
1802 */
1803static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1804 HWND hwnd,
1805 UINT uMsg,
1806 WPARAM wParam,
1807 LPARAM lParam)
1808{
1809 switch (uMsg)
1810 {
1811 case WM_CREATE:
1812 {
1813 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1814
1815 SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams);
1816
1817
1818 break;
1819 }
1820 case WM_MOUSEMOVE:
1821 {
1822 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1823 POINT mousePos;
1824
1825 /*
1826 * Get the current mouse position in screen coordinates.
1827 */
1828 mousePos.x = LOWORD(lParam);
1829 mousePos.y = HIWORD(lParam);
1830 ClientToScreen(hwnd, &mousePos);
1831
1832 /*
1833 * Track the movement of the mouse.
1834 */
1835 OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
1836
1837 break;
1838 }
1839 case WM_LBUTTONUP:
1840 case WM_MBUTTONUP:
1841 case WM_RBUTTONUP:
1842 case WM_LBUTTONDOWN:
1843 case WM_MBUTTONDOWN:
1844 case WM_RBUTTONDOWN:
1845 {
1846 TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
1847 POINT mousePos;
1848
1849 /*
1850 * Get the current mouse position in screen coordinates.
1851 */
1852 mousePos.x = LOWORD(lParam);
1853 mousePos.y = HIWORD(lParam);
1854 ClientToScreen(hwnd, &mousePos);
1855
1856 /*
1857 * Notify everyone that the button state changed
1858 * TODO: Check if the "escape" key was pressed.
1859 */
1860 OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
1861
1862 break;
1863 }
1864 }
1865
1866 /*
1867 * This is a window proc after all. Let's call the default.
1868 */
1869 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1870}
1871
1872/***
1873 * OLEDD_TrackMouseMove()
1874 *
1875 * This method is invoked while a drag and drop operation is in effect.
1876 * it will generate the appropriate callbacks in the drop source
1877 * and drop target. It will also provide the expected feedback to
1878 * the user.
1879 *
1880 * params:
1881 * trackerInfo - Pointer to the structure identifying the
1882 * drag & drop operation that is currently
1883 * active.
1884 * mousePos - Current position of the mouse in screen
1885 * coordinates.
1886 * keyState - Contains the state of the shift keys and the
1887 * mouse buttons (MK_LBUTTON and the like)
1888 */
1889static void OLEDD_TrackMouseMove(
1890 TrackerWindowInfo* trackerInfo,
1891 POINT mousePos,
1892 DWORD keyState)
1893{
1894 HWND hwndNewTarget = 0;
1895 HRESULT hr = S_OK;
1896
1897 /*
1898 * Get the handle of the window under the mouse
1899 */
1900 hwndNewTarget = WindowFromPoint(mousePos);
1901
1902 /*
1903 * Every time, we re-initialize the effects passed to the
1904 * IDropTarget to the effects allowed by the source.
1905 */
1906 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
1907
1908 /*
1909 * If we are hovering over the same target as before, send the
1910 * DragOver notification
1911 */
1912 if ( (trackerInfo->curDragTarget != 0) &&
1913 (trackerInfo->curDragTargetHWND==hwndNewTarget) )
1914 {
1915 POINTL mousePosParam;
1916
1917 /*
1918 * The documentation tells me that the coordinate should be in the target
1919 * window's coordinate space. However, the tests I made tell me the
1920 * coordinates should be in screen coordinates.
1921 */
1922 mousePosParam.x = mousePos.x;
1923 mousePosParam.y = mousePos.y;
1924
1925 IDropTarget_DragOver(trackerInfo->curDragTarget,
1926 keyState,
1927 mousePosParam,
1928 trackerInfo->pdwEffect);
1929 }
1930 else
1931 {
1932 DropTargetNode* newDropTargetNode = 0;
1933
1934 /*
1935 * If we changed window, we have to notify our old target and check for
1936 * the new one.
1937 */
1938 if (trackerInfo->curDragTarget!=0)
1939 {
1940 IDropTarget_DragLeave(trackerInfo->curDragTarget);
1941 }
1942
1943 /*
1944 * Make sure we're hovering over a window.
1945 */
1946 if (hwndNewTarget!=0)
1947 {
1948 /*
1949 * Find-out if there is a drag target under the mouse
1950 */
1951 HWND nexttar = hwndNewTarget;
1952 do {
1953 newDropTargetNode = OLEDD_FindDropTarget(nexttar);
1954 } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0);
1955 if(nexttar) hwndNewTarget = nexttar;
1956
1957 trackerInfo->curDragTargetHWND = hwndNewTarget;
1958 trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
1959
1960 /*
1961 * If there is, notify it that we just dragged-in
1962 */
1963 if (trackerInfo->curDragTarget!=0)
1964 {
1965 POINTL mousePosParam;
1966
1967 /*
1968 * The documentation tells me that the coordinate should be in the target
1969 * window's coordinate space. However, the tests I made tell me the
1970 * coordinates should be in screen coordinates.
1971 */
1972 mousePosParam.x = mousePos.x;
1973 mousePosParam.y = mousePos.y;
1974
1975 IDropTarget_DragEnter(trackerInfo->curDragTarget,
1976 trackerInfo->dataObject,
1977 keyState,
1978 mousePosParam,
1979 trackerInfo->pdwEffect);
1980 }
1981 }
1982 else
1983 {
1984 /*
1985 * The mouse is not over a window so we don't track anything.
1986 */
1987 trackerInfo->curDragTargetHWND = 0;
1988 trackerInfo->curDragTarget = 0;
1989 }
1990 }
1991
1992 /*
1993 * Now that we have done that, we have to tell the source to give
1994 * us feedback on the work being done by the target. If we don't
1995 * have a target, simulate no effect.
1996 */
1997 if (trackerInfo->curDragTarget==0)
1998 {
1999 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2000 }
2001
2002 hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
2003 *trackerInfo->pdwEffect);
2004
2005 /*
2006 * When we ask for feedback from the drop source, sometimes it will
2007 * do all the necessary work and sometimes it will not handle it
2008 * when that's the case, we must display the standard drag and drop
2009 * cursors.
2010 */
2011 if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
2012 {
2013 if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE)
2014 {
2015 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(1)));
2016 }
2017 else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY)
2018 {
2019 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(2)));
2020 }
2021 else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK)
2022 {
2023 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(3)));
2024 }
2025 else
2026 {
2027 SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(0)));
2028 }
2029 }
2030}
2031
2032/***
2033 * OLEDD_TrackStateChange()
2034 *
2035 * This method is invoked while a drag and drop operation is in effect.
2036 * It is used to notify the drop target/drop source callbacks when
2037 * the state of the keyboard or mouse button change.
2038 *
2039 * params:
2040 * trackerInfo - Pointer to the structure identifying the
2041 * drag & drop operation that is currently
2042 * active.
2043 * mousePos - Current position of the mouse in screen
2044 * coordinates.
2045 * keyState - Contains the state of the shift keys and the
2046 * mouse buttons (MK_LBUTTON and the like)
2047 */
2048static void OLEDD_TrackStateChange(
2049 TrackerWindowInfo* trackerInfo,
2050 POINT mousePos,
2051 DWORD keyState)
2052{
2053 /*
2054 * Ask the drop source what to do with the operation.
2055 */
2056 trackerInfo->returnValue = IDropSource_QueryContinueDrag(
2057 trackerInfo->dropSource,
2058 trackerInfo->escPressed,
2059 keyState);
2060
2061 /*
2062 * All the return valued will stop the operation except the S_OK
2063 * return value.
2064 */
2065 if (trackerInfo->returnValue!=S_OK)
2066 {
2067 /*
2068 * Make sure the message loop in DoDragDrop stops
2069 */
2070 trackerInfo->trackingDone = TRUE;
2071
2072 /*
2073 * Release the mouse in case the drop target decides to show a popup
2074 * or a menu or something.
2075 */
2076 ReleaseCapture();
2077
2078 /*
2079 * If we end-up over a target, drop the object in the target or
2080 * inform the target that the operation was cancelled.
2081 */
2082 if (trackerInfo->curDragTarget!=0)
2083 {
2084 switch (trackerInfo->returnValue)
2085 {
2086 /*
2087 * If the source wants us to complete the operation, we tell
2088 * the drop target that we just dropped the object in it.
2089 */
2090 case DRAGDROP_S_DROP:
2091 {
2092 POINTL mousePosParam;
2093
2094 /*
2095 * The documentation tells me that the coordinate should be
2096 * in the target window's coordinate space. However, the tests
2097 * I made tell me the coordinates should be in screen coordinates.
2098 */
2099 mousePosParam.x = mousePos.x;
2100 mousePosParam.y = mousePos.y;
2101
2102 IDropTarget_Drop(trackerInfo->curDragTarget,
2103 trackerInfo->dataObject,
2104 keyState,
2105 mousePosParam,
2106 trackerInfo->pdwEffect);
2107 break;
2108 }
2109 /*
2110 * If the source told us that we should cancel, fool the drop
2111 * target by telling it that the mouse left it's window.
2112 * Also set the drop effect to "NONE" in case the application
2113 * ignores the result of DoDragDrop.
2114 */
2115 case DRAGDROP_S_CANCEL:
2116 IDropTarget_DragLeave(trackerInfo->curDragTarget);
2117 *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2118 break;
2119 }
2120 }
2121 }
2122}
2123
2124/***
2125 * OLEDD_GetButtonState()
2126 *
2127 * This method will use the current state of the keyboard to build
2128 * a button state mask equivalent to the one passed in the
2129 * WM_MOUSEMOVE wParam.
2130 */
2131static DWORD OLEDD_GetButtonState()
2132{
2133 BYTE keyboardState[256];
2134 DWORD keyMask = 0;
2135
2136 GetKeyboardState(keyboardState);
2137
2138 if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
2139 keyMask |= MK_SHIFT;
2140
2141 if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
2142 keyMask |= MK_CONTROL;
2143
2144 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
2145 keyMask |= MK_LBUTTON;
2146
2147 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
2148 keyMask |= MK_RBUTTON;
2149
2150 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
2151 keyMask |= MK_MBUTTON;
2152
2153 return keyMask;
2154}
2155
2156/***
2157 * OLEDD_GetButtonState()
2158 *
2159 * This method will read the default value of the registry key in
2160 * parameter and extract a DWORD value from it. The registry key value
2161 * can be in a string key or a DWORD key.
2162 *
2163 * params:
2164 * regKey - Key to read the default value from
2165 * pdwValue - Pointer to the location where the DWORD
2166 * value is returned. This value is not modified
2167 * if the value is not found.
2168 */
2169
2170static void OLEUTL_ReadRegistryDWORDValue(
2171 HKEY regKey,
2172 DWORD* pdwValue)
2173{
2174 char buffer[20];
2175 DWORD dwKeyType;
2176 DWORD cbData = 20;
2177 LONG lres;
2178
2179 lres = RegQueryValueExA(regKey,
2180 "",
2181 NULL,
2182 &dwKeyType,
2183 (LPBYTE)buffer,
2184 &cbData);
2185
2186 if (lres==ERROR_SUCCESS)
2187 {
2188 switch (dwKeyType)
2189 {
2190 case REG_DWORD:
2191 *pdwValue = *(DWORD*)buffer;
2192 break;
2193 case REG_EXPAND_SZ:
2194 case REG_MULTI_SZ:
2195 case REG_SZ:
2196 *pdwValue = (DWORD)strtoul(buffer, NULL, 10);
2197 break;
2198 }
2199 }
2200}
2201#ifndef __WIN32OS2__
2202/******************************************************************************
2203 * OleMetaFilePictFromIconAndLabel
2204 *
2205 * Returns a global memory handle to a metafile which contains the icon and
2206 * label given.
2207 * I guess the result of that should look somehow like desktop icons.
2208 * If no hIcon is given, we load the icon via lpszSourceFile and iIconIndex.
2209 * This code might be wrong at some places.
2210 */
2211HGLOBAL16 WINAPI OleMetaFilePictFromIconAndLabel16(
2212 HICON16 hIcon,
2213 LPCOLESTR16 lpszLabel,
2214 LPCOLESTR16 lpszSourceFile,
2215 UINT16 iIconIndex
2216) {
2217 METAFILEPICT16 *mf;
2218 HGLOBAL16 hmf;
2219 HDC16 hdc;
2220
2221 FIXME("(%04x, '%s', '%s', %d): incorrect metrics, please try to correct them !\n\n\n", hIcon, lpszLabel, lpszSourceFile, iIconIndex);
2222
2223 if (!hIcon) {
2224 if (lpszSourceFile) {
2225 HINSTANCE16 hInstance = LoadLibrary16(lpszSourceFile);
2226
2227 /* load the icon at index from lpszSourceFile */
2228 hIcon = (HICON16)LoadIconA(hInstance, (LPCSTR)(DWORD)iIconIndex);
2229 FreeLibrary16(hInstance);
2230 } else
2231 return (HGLOBAL)NULL;
2232 }
2233
2234 hdc = CreateMetaFile16(NULL);
2235 DrawIcon(hdc, 0, 0, hIcon); /* FIXME */
2236 TextOutA(hdc, 0, 0, lpszLabel, 1); /* FIXME */
2237 hmf = GlobalAlloc16(0, sizeof(METAFILEPICT16));
2238 mf = (METAFILEPICT16 *)GlobalLock16(hmf);
2239 mf->mm = MM_ANISOTROPIC;
2240 mf->xExt = 20; /* FIXME: bogus */
2241 mf->yExt = 20; /* dito */
2242 mf->hMF = CloseMetaFile16(hdc);
2243 return hmf;
2244}
2245#endif
2246/******************************************************************************
2247 * DllDebugObjectRPCHook
2248 * turns on and off internal debugging, pointer is only used on macintosh
2249 */
2250
2251BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)
2252{
2253 FIXME("stub\n");
2254 return TRUE;
2255}
2256
Note: See TracBrowser for help on using the repository browser.