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