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

Last change on this file since 6502 was 5602, checked in by sandervl, 24 years ago

resync with Wine 20010418

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