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