Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenole2.c
Go to the documentation of this file.
00001 /* 00002 * OLE2 library 00003 * 00004 * Copyright 1995 Martin von Loewis 00005 * Copyright 1999 Francis Beaudet 00006 * Copyright 1999 Noel Borthwick 00007 * Copyright 1999, 2000 Marcus Meissner 00008 * Copyright 2005 Juan Lang 00009 * Copyright 2011 Adam Martinson for CodeWeavers 00010 * 00011 * This library is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU Lesser General Public 00013 * License as published by the Free Software Foundation; either 00014 * version 2.1 of the License, or (at your option) any later version. 00015 * 00016 * This library is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 * Lesser General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Lesser General Public 00022 * License along with this library; if not, write to the Free Software 00023 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00024 */ 00025 00026 #include "config.h" 00027 00028 #include <assert.h> 00029 #include <stdlib.h> 00030 #include <stdarg.h> 00031 #include <stdio.h> 00032 #include <string.h> 00033 00034 #define COBJMACROS 00035 #define NONAMELESSUNION 00036 #define NONAMELESSSTRUCT 00037 00038 #include "windef.h" 00039 #include "winbase.h" 00040 #include "winerror.h" 00041 #include "wingdi.h" 00042 #include "winuser.h" 00043 #include "winnls.h" 00044 #include "winreg.h" 00045 #include "ole2.h" 00046 #include "ole2ver.h" 00047 00048 #include "wine/unicode.h" 00049 #include "compobj_private.h" 00050 #include "wine/list.h" 00051 00052 #include "wine/debug.h" 00053 00054 WINE_DEFAULT_DEBUG_CHANNEL(ole); 00055 WINE_DECLARE_DEBUG_CHANNEL(accel); 00056 00057 /****************************************************************************** 00058 * These are static/global variables and internal data structures that the 00059 * OLE module uses to maintain it's state. 00060 */ 00061 typedef struct tagTrackerWindowInfo 00062 { 00063 IDataObject* dataObject; 00064 IDropSource* dropSource; 00065 DWORD dwOKEffect; 00066 DWORD* pdwEffect; 00067 BOOL trackingDone; 00068 HRESULT returnValue; 00069 00070 BOOL escPressed; 00071 HWND curTargetHWND; /* window the mouse is hovering over */ 00072 HWND curDragTargetHWND; /* might be a ancestor of curTargetHWND */ 00073 IDropTarget* curDragTarget; 00074 POINTL curMousePos; /* current position of the mouse in screen coordinates */ 00075 DWORD dwKeyState; /* current state of the shift and ctrl keys and the mouse buttons */ 00076 } TrackerWindowInfo; 00077 00078 typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */ 00079 { 00080 HWND hwndFrame; /* The containers frame window */ 00081 HWND hwndActiveObject; /* The active objects window */ 00082 OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */ 00083 HMENU hmenuCombined; /* The combined menu */ 00084 BOOL bIsServerItem; /* True if the currently open popup belongs to the server */ 00085 } OleMenuDescriptor; 00086 00087 typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */ 00088 { 00089 DWORD tid; /* Thread Id */ 00090 HANDLE hHeap; /* Heap this is allocated from */ 00091 HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */ 00092 HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */ 00093 struct tagOleMenuHookItem *next; 00094 } OleMenuHookItem; 00095 00096 static OleMenuHookItem *hook_list; 00097 00098 /* 00099 * This is the lock count on the OLE library. It is controlled by the 00100 * OLEInitialize/OLEUninitialize methods. 00101 */ 00102 static LONG OLE_moduleLockCount = 0; 00103 00104 /* 00105 * Name of our registered window class. 00106 */ 00107 static const WCHAR OLEDD_DRAGTRACKERCLASS[] = 00108 {'W','i','n','e','D','r','a','g','D','r','o','p','T','r','a','c','k','e','r','3','2',0}; 00109 00110 /* 00111 * Name of menu descriptor property. 00112 */ 00113 static const WCHAR prop_olemenuW[] = 00114 {'P','R','O','P','_','O','L','E','M','e','n','u','D','e','s','c','r','i','p','t','o','r',0}; 00115 00116 /* property to store IDropTarget pointer */ 00117 static const WCHAR prop_oledroptarget[] = 00118 {'O','l','e','D','r','o','p','T','a','r','g','e','t','I','n','t','e','r','f','a','c','e',0}; 00119 00120 /* property to store Marshalled IDropTarget pointer */ 00121 static const WCHAR prop_marshalleddroptarget[] = 00122 {'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}; 00123 00124 static const WCHAR clsidfmtW[] = 00125 {'C','L','S','I','D','\\','{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-', 00126 '%','0','2','x','%','0','2','x','-','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x', 00127 '%','0','2','x','%','0','2','x','}','\\',0}; 00128 00129 static const WCHAR emptyW[] = { 0 }; 00130 00131 /****************************************************************************** 00132 * These are the prototypes of miscellaneous utility methods 00133 */ 00134 static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue); 00135 00136 /****************************************************************************** 00137 * These are the prototypes of the utility methods used to manage a shared menu 00138 */ 00139 static void OLEMenu_Initialize(void); 00140 static void OLEMenu_UnInitialize(void); 00141 static BOOL OLEMenu_InstallHooks( DWORD tid ); 00142 static BOOL OLEMenu_UnInstallHooks( DWORD tid ); 00143 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid ); 00144 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos ); 00145 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor ); 00146 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam); 00147 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam); 00148 00149 /****************************************************************************** 00150 * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c) 00151 */ 00152 extern void OLEClipbrd_UnInitialize(void); 00153 extern void OLEClipbrd_Initialize(void); 00154 00155 /****************************************************************************** 00156 * These are the prototypes of the utility methods used for OLE Drag n Drop 00157 */ 00158 static void OLEDD_Initialize(void); 00159 static LRESULT WINAPI OLEDD_DragTrackerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 00160 static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo); 00161 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo); 00162 static DWORD OLEDD_GetButtonState(void); 00163 00164 /****************************************************************************** 00165 * OleBuildVersion [OLE32.@] 00166 */ 00167 DWORD WINAPI OleBuildVersion(void) 00168 { 00169 TRACE("Returning version %d, build %d.\n", rmm, rup); 00170 return (rmm<<16)+rup; 00171 } 00172 00173 /*********************************************************************** 00174 * OleInitialize (OLE32.@) 00175 */ 00176 HRESULT WINAPI OleInitialize(LPVOID reserved) 00177 { 00178 HRESULT hr; 00179 00180 TRACE("(%p)\n", reserved); 00181 00182 /* 00183 * The first duty of the OleInitialize is to initialize the COM libraries. 00184 */ 00185 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 00186 00187 /* 00188 * If the CoInitializeEx call failed, the OLE libraries can't be 00189 * initialized. 00190 */ 00191 if (FAILED(hr)) 00192 return hr; 00193 00194 if (!COM_CurrentInfo()->ole_inits) 00195 hr = S_OK; 00196 00197 /* 00198 * Then, it has to initialize the OLE specific modules. 00199 * This includes: 00200 * Clipboard 00201 * Drag and Drop 00202 * Object linking and Embedding 00203 * In-place activation 00204 */ 00205 if (!COM_CurrentInfo()->ole_inits++ && 00206 InterlockedIncrement(&OLE_moduleLockCount) == 1) 00207 { 00208 /* 00209 * Initialize the libraries. 00210 */ 00211 TRACE("() - Initializing the OLE libraries\n"); 00212 00213 /* 00214 * OLE Clipboard 00215 */ 00216 OLEClipbrd_Initialize(); 00217 00218 /* 00219 * Drag and Drop 00220 */ 00221 OLEDD_Initialize(); 00222 00223 /* 00224 * OLE shared menu 00225 */ 00226 OLEMenu_Initialize(); 00227 } 00228 00229 return hr; 00230 } 00231 00232 /****************************************************************************** 00233 * OleUninitialize [OLE32.@] 00234 */ 00235 void WINAPI OleUninitialize(void) 00236 { 00237 TRACE("()\n"); 00238 00239 /* 00240 * If we hit the bottom of the lock stack, free the libraries. 00241 */ 00242 if (!--COM_CurrentInfo()->ole_inits && !InterlockedDecrement(&OLE_moduleLockCount)) 00243 { 00244 /* 00245 * Actually free the libraries. 00246 */ 00247 TRACE("() - Freeing the last reference count\n"); 00248 00249 /* 00250 * OLE Clipboard 00251 */ 00252 OLEClipbrd_UnInitialize(); 00253 00254 /* 00255 * OLE shared menu 00256 */ 00257 OLEMenu_UnInitialize(); 00258 } 00259 00260 /* 00261 * Then, uninitialize the COM libraries. 00262 */ 00263 CoUninitialize(); 00264 } 00265 00266 /****************************************************************************** 00267 * OleInitializeWOW [OLE32.@] 00268 */ 00269 HRESULT WINAPI OleInitializeWOW(DWORD x, DWORD y) { 00270 FIXME("(0x%08x, 0x%08x),stub!\n",x, y); 00271 return 0; 00272 } 00273 00274 /************************************************************* 00275 * get_droptarget_handle 00276 * 00277 * Retrieve a handle to the map containing the marshalled IDropTarget. 00278 * This handle belongs to the process that called RegisterDragDrop. 00279 * See get_droptarget_local_handle(). 00280 */ 00281 static inline HANDLE get_droptarget_handle(HWND hwnd) 00282 { 00283 return GetPropW(hwnd, prop_marshalleddroptarget); 00284 } 00285 00286 /************************************************************* 00287 * is_droptarget 00288 * 00289 * Is the window a droptarget. 00290 */ 00291 static inline BOOL is_droptarget(HWND hwnd) 00292 { 00293 return get_droptarget_handle(hwnd) ? TRUE : FALSE; 00294 } 00295 00296 /************************************************************* 00297 * get_droptarget_local_handle 00298 * 00299 * Retrieve a handle to the map containing the marshalled IDropTarget. 00300 * The handle should be closed when finished with. 00301 */ 00302 static HANDLE get_droptarget_local_handle(HWND hwnd) 00303 { 00304 HANDLE handle, local_handle = 0; 00305 00306 handle = get_droptarget_handle(hwnd); 00307 00308 if(handle) 00309 { 00310 DWORD pid; 00311 HANDLE process; 00312 00313 GetWindowThreadProcessId(hwnd, &pid); 00314 process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid); 00315 if(process) 00316 { 00317 DuplicateHandle(process, handle, GetCurrentProcess(), &local_handle, 0, FALSE, DUPLICATE_SAME_ACCESS); 00318 CloseHandle(process); 00319 } 00320 } 00321 return local_handle; 00322 } 00323 00324 /*********************************************************************** 00325 * create_map_from_stream 00326 * 00327 * Helper for RegisterDragDrop. Creates a file mapping object 00328 * with the contents of the provided stream. The stream must 00329 * be a global memory backed stream. 00330 */ 00331 static HRESULT create_map_from_stream(IStream *stream, HANDLE *map) 00332 { 00333 HGLOBAL hmem; 00334 DWORD size; 00335 HRESULT hr; 00336 void *data; 00337 00338 hr = GetHGlobalFromStream(stream, &hmem); 00339 if(FAILED(hr)) return hr; 00340 00341 size = GlobalSize(hmem); 00342 *map = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL); 00343 if(!*map) return E_OUTOFMEMORY; 00344 00345 data = MapViewOfFile(*map, FILE_MAP_WRITE, 0, 0, size); 00346 memcpy(data, GlobalLock(hmem), size); 00347 GlobalUnlock(hmem); 00348 UnmapViewOfFile(data); 00349 return S_OK; 00350 } 00351 00352 /*********************************************************************** 00353 * create_stream_from_map 00354 * 00355 * Creates a stream from the provided map. 00356 */ 00357 static HRESULT create_stream_from_map(HANDLE map, IStream **stream) 00358 { 00359 HRESULT hr = E_OUTOFMEMORY; 00360 HGLOBAL hmem; 00361 void *data; 00362 MEMORY_BASIC_INFORMATION info; 00363 00364 data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0); 00365 if(!data) return hr; 00366 00367 VirtualQuery(data, &info, sizeof(info)); 00368 TRACE("size %d\n", (int)info.RegionSize); 00369 00370 hmem = GlobalAlloc(GMEM_MOVEABLE, info.RegionSize); 00371 if(hmem) 00372 { 00373 memcpy(GlobalLock(hmem), data, info.RegionSize); 00374 GlobalUnlock(hmem); 00375 hr = CreateStreamOnHGlobal(hmem, TRUE, stream); 00376 } 00377 UnmapViewOfFile(data); 00378 return hr; 00379 } 00380 00381 /* This is to work around apps which break COM rules by not implementing 00382 * IDropTarget::QueryInterface(). Windows doesn't expose this because it 00383 * doesn't call CoMarshallInterface() in RegisterDragDrop(). 00384 * The wrapper is only used internally, and only exists for the life of 00385 * the marshal. We don't want to hold a ref on the app provided target 00386 * as some apps destroy this prior to CoUninitialize without calling 00387 * RevokeDragDrop. The only (long-term) ref is held by the window prop. */ 00388 typedef struct { 00389 IDropTarget IDropTarget_iface; 00390 HWND hwnd; 00391 LONG refs; 00392 } DropTargetWrapper; 00393 00394 static inline DropTargetWrapper* impl_from_IDropTarget(IDropTarget* iface) 00395 { 00396 return CONTAINING_RECORD(iface, DropTargetWrapper, IDropTarget_iface); 00397 } 00398 00399 static HRESULT WINAPI DropTargetWrapper_QueryInterface(IDropTarget* iface, 00400 REFIID riid, 00401 void** ppvObject) 00402 { 00403 DropTargetWrapper* This = impl_from_IDropTarget(iface); 00404 if (IsEqualIID(riid, &IID_IUnknown) || 00405 IsEqualIID(riid, &IID_IDropTarget)) 00406 { 00407 IDropTarget_AddRef(&This->IDropTarget_iface); 00408 *ppvObject = &This->IDropTarget_iface; 00409 return S_OK; 00410 } 00411 *ppvObject = NULL; 00412 return E_NOINTERFACE; 00413 } 00414 00415 static ULONG WINAPI DropTargetWrapper_AddRef(IDropTarget* iface) 00416 { 00417 DropTargetWrapper* This = impl_from_IDropTarget(iface); 00418 return InterlockedIncrement(&This->refs); 00419 } 00420 00421 static ULONG WINAPI DropTargetWrapper_Release(IDropTarget* iface) 00422 { 00423 DropTargetWrapper* This = impl_from_IDropTarget(iface); 00424 ULONG refs = InterlockedDecrement(&This->refs); 00425 if (!refs) HeapFree(GetProcessHeap(), 0, This); 00426 return refs; 00427 } 00428 00429 static inline HRESULT get_target_from_wrapper( IDropTarget *wrapper, IDropTarget **target ) 00430 { 00431 DropTargetWrapper* This = impl_from_IDropTarget( wrapper ); 00432 *target = GetPropW( This->hwnd, prop_oledroptarget ); 00433 if (!*target) return DRAGDROP_E_NOTREGISTERED; 00434 IDropTarget_AddRef( *target ); 00435 return S_OK; 00436 } 00437 00438 static HRESULT WINAPI DropTargetWrapper_DragEnter(IDropTarget* iface, 00439 IDataObject* pDataObj, 00440 DWORD grfKeyState, 00441 POINTL pt, 00442 DWORD* pdwEffect) 00443 { 00444 IDropTarget *target; 00445 HRESULT r = get_target_from_wrapper( iface, &target ); 00446 00447 if (SUCCEEDED( r )) 00448 { 00449 r = IDropTarget_DragEnter( target, pDataObj, grfKeyState, pt, pdwEffect ); 00450 IDropTarget_Release( target ); 00451 } 00452 return r; 00453 } 00454 00455 static HRESULT WINAPI DropTargetWrapper_DragOver(IDropTarget* iface, 00456 DWORD grfKeyState, 00457 POINTL pt, 00458 DWORD* pdwEffect) 00459 { 00460 IDropTarget *target; 00461 HRESULT r = get_target_from_wrapper( iface, &target ); 00462 00463 if (SUCCEEDED( r )) 00464 { 00465 r = IDropTarget_DragOver( target, grfKeyState, pt, pdwEffect ); 00466 IDropTarget_Release( target ); 00467 } 00468 return r; 00469 } 00470 00471 static HRESULT WINAPI DropTargetWrapper_DragLeave(IDropTarget* iface) 00472 { 00473 IDropTarget *target; 00474 HRESULT r = get_target_from_wrapper( iface, &target ); 00475 00476 if (SUCCEEDED( r )) 00477 { 00478 r = IDropTarget_DragLeave( target ); 00479 IDropTarget_Release( target ); 00480 } 00481 return r; 00482 } 00483 00484 static HRESULT WINAPI DropTargetWrapper_Drop(IDropTarget* iface, 00485 IDataObject* pDataObj, 00486 DWORD grfKeyState, 00487 POINTL pt, 00488 DWORD* pdwEffect) 00489 { 00490 IDropTarget *target; 00491 HRESULT r = get_target_from_wrapper( iface, &target ); 00492 00493 if (SUCCEEDED( r )) 00494 { 00495 r = IDropTarget_Drop( target, pDataObj, grfKeyState, pt, pdwEffect ); 00496 IDropTarget_Release( target ); 00497 } 00498 return r; 00499 } 00500 00501 static const IDropTargetVtbl DropTargetWrapperVTbl = 00502 { 00503 DropTargetWrapper_QueryInterface, 00504 DropTargetWrapper_AddRef, 00505 DropTargetWrapper_Release, 00506 DropTargetWrapper_DragEnter, 00507 DropTargetWrapper_DragOver, 00508 DropTargetWrapper_DragLeave, 00509 DropTargetWrapper_Drop 00510 }; 00511 00512 static IDropTarget* WrapDropTarget( HWND hwnd ) 00513 { 00514 DropTargetWrapper* This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 00515 00516 if (This) 00517 { 00518 This->IDropTarget_iface.lpVtbl = &DropTargetWrapperVTbl; 00519 This->hwnd = hwnd; 00520 This->refs = 1; 00521 } 00522 return &This->IDropTarget_iface; 00523 } 00524 00525 /*********************************************************************** 00526 * get_droptarget_pointer 00527 * 00528 * Retrieves the marshalled IDropTarget from the window. 00529 */ 00530 static IDropTarget* get_droptarget_pointer(HWND hwnd) 00531 { 00532 IDropTarget *droptarget = NULL; 00533 HANDLE map; 00534 IStream *stream; 00535 00536 map = get_droptarget_local_handle(hwnd); 00537 if(!map) return NULL; 00538 00539 if(SUCCEEDED(create_stream_from_map(map, &stream))) 00540 { 00541 CoUnmarshalInterface(stream, &IID_IDropTarget, (void**)&droptarget); 00542 IStream_Release(stream); 00543 } 00544 CloseHandle(map); 00545 return droptarget; 00546 } 00547 00548 /*********************************************************************** 00549 * RegisterDragDrop (OLE32.@) 00550 */ 00551 HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget) 00552 { 00553 DWORD pid = 0; 00554 HRESULT hr; 00555 IStream *stream; 00556 HANDLE map; 00557 IDropTarget *wrapper; 00558 00559 TRACE("(%p,%p)\n", hwnd, pDropTarget); 00560 00561 if (!COM_CurrentApt()) 00562 { 00563 ERR("COM not initialized\n"); 00564 return E_OUTOFMEMORY; 00565 } 00566 00567 if (!pDropTarget) 00568 return E_INVALIDARG; 00569 00570 if (!IsWindow(hwnd)) 00571 { 00572 ERR("invalid hwnd %p\n", hwnd); 00573 return DRAGDROP_E_INVALIDHWND; 00574 } 00575 00576 /* block register for other processes windows */ 00577 GetWindowThreadProcessId(hwnd, &pid); 00578 if (pid != GetCurrentProcessId()) 00579 { 00580 FIXME("register for another process windows is disabled\n"); 00581 return DRAGDROP_E_INVALIDHWND; 00582 } 00583 00584 /* check if the window is already registered */ 00585 if (is_droptarget(hwnd)) 00586 return DRAGDROP_E_ALREADYREGISTERED; 00587 00588 /* 00589 * Marshal the drop target pointer into a shared memory map and 00590 * store the map's handle in a Wine specific window prop. We also 00591 * store the drop target pointer itself in the 00592 * "OleDropTargetInterface" prop for compatibility with Windows. 00593 */ 00594 00595 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 00596 if(FAILED(hr)) return hr; 00597 00598 /* IDropTarget::QueryInterface() shouldn't be called, some (broken) apps depend on this. */ 00599 wrapper = WrapDropTarget( hwnd ); 00600 if(!wrapper) 00601 { 00602 IStream_Release(stream); 00603 return E_OUTOFMEMORY; 00604 } 00605 hr = CoMarshalInterface(stream, &IID_IDropTarget, (IUnknown*)wrapper, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG); 00606 IDropTarget_Release(wrapper); 00607 00608 if(SUCCEEDED(hr)) 00609 { 00610 hr = create_map_from_stream(stream, &map); 00611 if(SUCCEEDED(hr)) 00612 { 00613 IDropTarget_AddRef(pDropTarget); 00614 SetPropW(hwnd, prop_oledroptarget, pDropTarget); 00615 SetPropW(hwnd, prop_marshalleddroptarget, map); 00616 } 00617 else 00618 { 00619 LARGE_INTEGER zero; 00620 zero.QuadPart = 0; 00621 IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL); 00622 CoReleaseMarshalData(stream); 00623 } 00624 } 00625 IStream_Release(stream); 00626 00627 return hr; 00628 } 00629 00630 /*********************************************************************** 00631 * RevokeDragDrop (OLE32.@) 00632 */ 00633 HRESULT WINAPI RevokeDragDrop(HWND hwnd) 00634 { 00635 HANDLE map; 00636 IStream *stream; 00637 IDropTarget *drop_target; 00638 HRESULT hr; 00639 00640 TRACE("(%p)\n", hwnd); 00641 00642 if (!IsWindow(hwnd)) 00643 { 00644 ERR("invalid hwnd %p\n", hwnd); 00645 return DRAGDROP_E_INVALIDHWND; 00646 } 00647 00648 /* no registration data */ 00649 if (!(map = get_droptarget_handle(hwnd))) 00650 return DRAGDROP_E_NOTREGISTERED; 00651 00652 drop_target = GetPropW(hwnd, prop_oledroptarget); 00653 if(drop_target) IDropTarget_Release(drop_target); 00654 00655 RemovePropW(hwnd, prop_oledroptarget); 00656 RemovePropW(hwnd, prop_marshalleddroptarget); 00657 00658 hr = create_stream_from_map(map, &stream); 00659 if(SUCCEEDED(hr)) 00660 { 00661 CoReleaseMarshalData(stream); 00662 IStream_Release(stream); 00663 } 00664 CloseHandle(map); 00665 00666 return hr; 00667 } 00668 00669 /*********************************************************************** 00670 * OleRegGetUserType (OLE32.@) 00671 * 00672 * This implementation of OleRegGetUserType ignores the dwFormOfType 00673 * parameter and always returns the full name of the object. This is 00674 * not too bad since this is the case for many objects because of the 00675 * way they are registered. 00676 */ 00677 HRESULT WINAPI OleRegGetUserType( 00678 REFCLSID clsid, 00679 DWORD dwFormOfType, 00680 LPOLESTR* pszUserType) 00681 { 00682 WCHAR keyName[60]; 00683 DWORD dwKeyType; 00684 DWORD cbData; 00685 HKEY clsidKey; 00686 LONG hres; 00687 00688 /* 00689 * Initialize the out parameter. 00690 */ 00691 *pszUserType = NULL; 00692 00693 /* 00694 * Build the key name we're looking for 00695 */ 00696 sprintfW( keyName, clsidfmtW, 00697 clsid->Data1, clsid->Data2, clsid->Data3, 00698 clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], 00699 clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); 00700 00701 TRACE("(%s, %d, %p)\n", debugstr_w(keyName), dwFormOfType, pszUserType); 00702 00703 /* 00704 * Open the class id Key 00705 */ 00706 hres = RegOpenKeyW(HKEY_CLASSES_ROOT, 00707 keyName, 00708 &clsidKey); 00709 00710 if (hres != ERROR_SUCCESS) 00711 return REGDB_E_CLASSNOTREG; 00712 00713 /* 00714 * Retrieve the size of the name string. 00715 */ 00716 cbData = 0; 00717 00718 hres = RegQueryValueExW(clsidKey, 00719 emptyW, 00720 NULL, 00721 &dwKeyType, 00722 NULL, 00723 &cbData); 00724 00725 if (hres!=ERROR_SUCCESS) 00726 { 00727 RegCloseKey(clsidKey); 00728 return REGDB_E_READREGDB; 00729 } 00730 00731 /* 00732 * Allocate a buffer for the registry value. 00733 */ 00734 *pszUserType = CoTaskMemAlloc(cbData); 00735 00736 if (*pszUserType==NULL) 00737 { 00738 RegCloseKey(clsidKey); 00739 return E_OUTOFMEMORY; 00740 } 00741 00742 hres = RegQueryValueExW(clsidKey, 00743 emptyW, 00744 NULL, 00745 &dwKeyType, 00746 (LPBYTE) *pszUserType, 00747 &cbData); 00748 00749 RegCloseKey(clsidKey); 00750 00751 if (hres != ERROR_SUCCESS) 00752 { 00753 CoTaskMemFree(*pszUserType); 00754 *pszUserType = NULL; 00755 00756 return REGDB_E_READREGDB; 00757 } 00758 00759 return S_OK; 00760 } 00761 00762 /*********************************************************************** 00763 * DoDragDrop [OLE32.@] 00764 */ 00765 HRESULT WINAPI DoDragDrop ( 00766 IDataObject *pDataObject, /* [in] ptr to the data obj */ 00767 IDropSource* pDropSource, /* [in] ptr to the source obj */ 00768 DWORD dwOKEffect, /* [in] effects allowed by the source */ 00769 DWORD *pdwEffect) /* [out] ptr to effects of the source */ 00770 { 00771 static const WCHAR trackerW[] = {'T','r','a','c','k','e','r','W','i','n','d','o','w',0}; 00772 TrackerWindowInfo trackerInfo; 00773 HWND hwndTrackWindow; 00774 MSG msg; 00775 00776 TRACE("(%p, %p, %08x, %p)\n", pDataObject, pDropSource, dwOKEffect, pdwEffect); 00777 00778 if (!pDataObject || !pDropSource || !pdwEffect) 00779 return E_INVALIDARG; 00780 00781 /* 00782 * Setup the drag n drop tracking window. 00783 */ 00784 00785 trackerInfo.dataObject = pDataObject; 00786 trackerInfo.dropSource = pDropSource; 00787 trackerInfo.dwOKEffect = dwOKEffect; 00788 trackerInfo.pdwEffect = pdwEffect; 00789 trackerInfo.trackingDone = FALSE; 00790 trackerInfo.escPressed = FALSE; 00791 trackerInfo.curDragTargetHWND = 0; 00792 trackerInfo.curTargetHWND = 0; 00793 trackerInfo.curDragTarget = 0; 00794 00795 hwndTrackWindow = CreateWindowW(OLEDD_DRAGTRACKERCLASS, trackerW, 00796 WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, 00797 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0, 00798 &trackerInfo); 00799 00800 if (hwndTrackWindow) 00801 { 00802 /* 00803 * Capture the mouse input 00804 */ 00805 SetCapture(hwndTrackWindow); 00806 00807 msg.message = 0; 00808 00809 /* 00810 * Pump messages. All mouse input should go to the capture window. 00811 */ 00812 while (!trackerInfo.trackingDone && GetMessageW(&msg, 0, 0, 0) ) 00813 { 00814 trackerInfo.curMousePos.x = msg.pt.x; 00815 trackerInfo.curMousePos.y = msg.pt.y; 00816 trackerInfo.dwKeyState = OLEDD_GetButtonState(); 00817 00818 if ( (msg.message >= WM_KEYFIRST) && 00819 (msg.message <= WM_KEYLAST) ) 00820 { 00821 /* 00822 * When keyboard messages are sent to windows on this thread, we 00823 * want to ignore notify the drop source that the state changed. 00824 * in the case of the Escape key, we also notify the drop source 00825 * we give it a special meaning. 00826 */ 00827 if ( (msg.message==WM_KEYDOWN) && 00828 (msg.wParam==VK_ESCAPE) ) 00829 { 00830 trackerInfo.escPressed = TRUE; 00831 } 00832 00833 /* 00834 * Notify the drop source. 00835 */ 00836 OLEDD_TrackStateChange(&trackerInfo); 00837 } 00838 else 00839 { 00840 /* 00841 * Dispatch the messages only when it's not a keyboard message. 00842 */ 00843 DispatchMessageW(&msg); 00844 } 00845 } 00846 00847 /* re-post the quit message to outer message loop */ 00848 if (msg.message == WM_QUIT) 00849 PostQuitMessage(msg.wParam); 00850 /* 00851 * Destroy the temporary window. 00852 */ 00853 DestroyWindow(hwndTrackWindow); 00854 00855 return trackerInfo.returnValue; 00856 } 00857 00858 return E_FAIL; 00859 } 00860 00861 /*********************************************************************** 00862 * OleQueryLinkFromData [OLE32.@] 00863 */ 00864 HRESULT WINAPI OleQueryLinkFromData( 00865 IDataObject* pSrcDataObject) 00866 { 00867 FIXME("(%p),stub!\n", pSrcDataObject); 00868 return S_FALSE; 00869 } 00870 00871 /*********************************************************************** 00872 * OleRegGetMiscStatus [OLE32.@] 00873 */ 00874 HRESULT WINAPI OleRegGetMiscStatus( 00875 REFCLSID clsid, 00876 DWORD dwAspect, 00877 DWORD* pdwStatus) 00878 { 00879 static const WCHAR miscstatusW[] = {'M','i','s','c','S','t','a','t','u','s',0}; 00880 static const WCHAR dfmtW[] = {'%','d',0}; 00881 WCHAR keyName[60]; 00882 HKEY clsidKey; 00883 HKEY miscStatusKey; 00884 HKEY aspectKey; 00885 LONG result; 00886 00887 /* 00888 * Initialize the out parameter. 00889 */ 00890 *pdwStatus = 0; 00891 00892 /* 00893 * Build the key name we're looking for 00894 */ 00895 sprintfW( keyName, clsidfmtW, 00896 clsid->Data1, clsid->Data2, clsid->Data3, 00897 clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], 00898 clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); 00899 00900 TRACE("(%s, %d, %p)\n", debugstr_w(keyName), dwAspect, pdwStatus); 00901 00902 /* 00903 * Open the class id Key 00904 */ 00905 result = RegOpenKeyW(HKEY_CLASSES_ROOT, 00906 keyName, 00907 &clsidKey); 00908 00909 if (result != ERROR_SUCCESS) 00910 return REGDB_E_CLASSNOTREG; 00911 00912 /* 00913 * Get the MiscStatus 00914 */ 00915 result = RegOpenKeyW(clsidKey, 00916 miscstatusW, 00917 &miscStatusKey); 00918 00919 00920 if (result != ERROR_SUCCESS) 00921 { 00922 RegCloseKey(clsidKey); 00923 return REGDB_E_READREGDB; 00924 } 00925 00926 /* 00927 * Read the default value 00928 */ 00929 OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus); 00930 00931 /* 00932 * Open the key specific to the requested aspect. 00933 */ 00934 sprintfW(keyName, dfmtW, dwAspect); 00935 00936 result = RegOpenKeyW(miscStatusKey, 00937 keyName, 00938 &aspectKey); 00939 00940 if (result == ERROR_SUCCESS) 00941 { 00942 OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus); 00943 RegCloseKey(aspectKey); 00944 } 00945 00946 /* 00947 * Cleanup 00948 */ 00949 RegCloseKey(miscStatusKey); 00950 RegCloseKey(clsidKey); 00951 00952 return S_OK; 00953 } 00954 00955 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum); 00956 00957 typedef struct 00958 { 00959 IEnumOLEVERB IEnumOLEVERB_iface; 00960 LONG ref; 00961 00962 HKEY hkeyVerb; 00963 ULONG index; 00964 } EnumOLEVERB; 00965 00966 static inline EnumOLEVERB *impl_from_IEnumOLEVERB(IEnumOLEVERB *iface) 00967 { 00968 return CONTAINING_RECORD(iface, EnumOLEVERB, IEnumOLEVERB_iface); 00969 } 00970 00971 static HRESULT WINAPI EnumOLEVERB_QueryInterface( 00972 IEnumOLEVERB *iface, REFIID riid, void **ppv) 00973 { 00974 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); 00975 if (IsEqualIID(riid, &IID_IUnknown) || 00976 IsEqualIID(riid, &IID_IEnumOLEVERB)) 00977 { 00978 IUnknown_AddRef(iface); 00979 *ppv = iface; 00980 return S_OK; 00981 } 00982 return E_NOINTERFACE; 00983 } 00984 00985 static ULONG WINAPI EnumOLEVERB_AddRef( 00986 IEnumOLEVERB *iface) 00987 { 00988 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface); 00989 TRACE("()\n"); 00990 return InterlockedIncrement(&This->ref); 00991 } 00992 00993 static ULONG WINAPI EnumOLEVERB_Release( 00994 IEnumOLEVERB *iface) 00995 { 00996 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface); 00997 LONG refs = InterlockedDecrement(&This->ref); 00998 TRACE("()\n"); 00999 if (!refs) 01000 { 01001 RegCloseKey(This->hkeyVerb); 01002 HeapFree(GetProcessHeap(), 0, This); 01003 } 01004 return refs; 01005 } 01006 01007 static HRESULT WINAPI EnumOLEVERB_Next( 01008 IEnumOLEVERB *iface, ULONG celt, LPOLEVERB rgelt, 01009 ULONG *pceltFetched) 01010 { 01011 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface); 01012 HRESULT hr = S_OK; 01013 01014 TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); 01015 01016 if (pceltFetched) 01017 *pceltFetched = 0; 01018 01019 for (; celt; celt--, rgelt++) 01020 { 01021 WCHAR wszSubKey[20]; 01022 LONG cbData; 01023 LPWSTR pwszOLEVERB; 01024 LPWSTR pwszMenuFlags; 01025 LPWSTR pwszAttribs; 01026 LONG res = RegEnumKeyW(This->hkeyVerb, This->index, wszSubKey, sizeof(wszSubKey)/sizeof(wszSubKey[0])); 01027 if (res == ERROR_NO_MORE_ITEMS) 01028 { 01029 hr = S_FALSE; 01030 break; 01031 } 01032 else if (res != ERROR_SUCCESS) 01033 { 01034 ERR("RegEnumKeyW failed with error %d\n", res); 01035 hr = REGDB_E_READREGDB; 01036 break; 01037 } 01038 res = RegQueryValueW(This->hkeyVerb, wszSubKey, NULL, &cbData); 01039 if (res != ERROR_SUCCESS) 01040 { 01041 ERR("RegQueryValueW failed with error %d\n", res); 01042 hr = REGDB_E_READREGDB; 01043 break; 01044 } 01045 pwszOLEVERB = CoTaskMemAlloc(cbData); 01046 if (!pwszOLEVERB) 01047 { 01048 hr = E_OUTOFMEMORY; 01049 break; 01050 } 01051 res = RegQueryValueW(This->hkeyVerb, wszSubKey, pwszOLEVERB, &cbData); 01052 if (res != ERROR_SUCCESS) 01053 { 01054 ERR("RegQueryValueW failed with error %d\n", res); 01055 hr = REGDB_E_READREGDB; 01056 CoTaskMemFree(pwszOLEVERB); 01057 break; 01058 } 01059 01060 TRACE("verb string: %s\n", debugstr_w(pwszOLEVERB)); 01061 pwszMenuFlags = strchrW(pwszOLEVERB, ','); 01062 if (!pwszMenuFlags) 01063 { 01064 hr = OLEOBJ_E_INVALIDVERB; 01065 CoTaskMemFree(pwszOLEVERB); 01066 break; 01067 } 01068 /* nul terminate the name string and advance to first character */ 01069 *pwszMenuFlags = '\0'; 01070 pwszMenuFlags++; 01071 pwszAttribs = strchrW(pwszMenuFlags, ','); 01072 if (!pwszAttribs) 01073 { 01074 hr = OLEOBJ_E_INVALIDVERB; 01075 CoTaskMemFree(pwszOLEVERB); 01076 break; 01077 } 01078 /* nul terminate the menu string and advance to first character */ 01079 *pwszAttribs = '\0'; 01080 pwszAttribs++; 01081 01082 /* fill out structure for this verb */ 01083 rgelt->lVerb = atolW(wszSubKey); 01084 rgelt->lpszVerbName = pwszOLEVERB; /* user should free */ 01085 rgelt->fuFlags = atolW(pwszMenuFlags); 01086 rgelt->grfAttribs = atolW(pwszAttribs); 01087 01088 if (pceltFetched) 01089 (*pceltFetched)++; 01090 This->index++; 01091 } 01092 return hr; 01093 } 01094 01095 static HRESULT WINAPI EnumOLEVERB_Skip( 01096 IEnumOLEVERB *iface, ULONG celt) 01097 { 01098 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface); 01099 01100 TRACE("(%d)\n", celt); 01101 01102 This->index += celt; 01103 return S_OK; 01104 } 01105 01106 static HRESULT WINAPI EnumOLEVERB_Reset( 01107 IEnumOLEVERB *iface) 01108 { 01109 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface); 01110 01111 TRACE("()\n"); 01112 01113 This->index = 0; 01114 return S_OK; 01115 } 01116 01117 static HRESULT WINAPI EnumOLEVERB_Clone( 01118 IEnumOLEVERB *iface, 01119 IEnumOLEVERB **ppenum) 01120 { 01121 EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface); 01122 HKEY hkeyVerb; 01123 TRACE("(%p)\n", ppenum); 01124 if (!DuplicateHandle(GetCurrentProcess(), This->hkeyVerb, GetCurrentProcess(), (HANDLE *)&hkeyVerb, 0, FALSE, DUPLICATE_SAME_ACCESS)) 01125 return HRESULT_FROM_WIN32(GetLastError()); 01126 return EnumOLEVERB_Construct(hkeyVerb, This->index, ppenum); 01127 } 01128 01129 static const IEnumOLEVERBVtbl EnumOLEVERB_VTable = 01130 { 01131 EnumOLEVERB_QueryInterface, 01132 EnumOLEVERB_AddRef, 01133 EnumOLEVERB_Release, 01134 EnumOLEVERB_Next, 01135 EnumOLEVERB_Skip, 01136 EnumOLEVERB_Reset, 01137 EnumOLEVERB_Clone 01138 }; 01139 01140 static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum) 01141 { 01142 EnumOLEVERB *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 01143 if (!This) 01144 { 01145 RegCloseKey(hkeyVerb); 01146 return E_OUTOFMEMORY; 01147 } 01148 This->IEnumOLEVERB_iface.lpVtbl = &EnumOLEVERB_VTable; 01149 This->ref = 1; 01150 This->index = index; 01151 This->hkeyVerb = hkeyVerb; 01152 *ppenum = &This->IEnumOLEVERB_iface; 01153 return S_OK; 01154 } 01155 01156 /*********************************************************************** 01157 * OleRegEnumVerbs [OLE32.@] 01158 * 01159 * Enumerates verbs associated with a class stored in the registry. 01160 * 01161 * PARAMS 01162 * clsid [I] Class ID to enumerate the verbs for. 01163 * ppenum [O] Enumerator. 01164 * 01165 * RETURNS 01166 * S_OK: Success. 01167 * REGDB_E_CLASSNOTREG: The specified class does not have a key in the registry. 01168 * REGDB_E_READREGDB: The class key could not be opened for some other reason. 01169 * OLE_E_REGDB_KEY: The Verb subkey for the class is not present. 01170 * OLEOBJ_E_NOVERBS: The Verb subkey for the class is empty. 01171 */ 01172 HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum) 01173 { 01174 LONG res; 01175 HKEY hkeyVerb; 01176 DWORD dwSubKeys; 01177 static const WCHAR wszVerb[] = {'V','e','r','b',0}; 01178 01179 TRACE("(%s, %p)\n", debugstr_guid(clsid), ppenum); 01180 01181 res = COM_OpenKeyForCLSID(clsid, wszVerb, KEY_READ, &hkeyVerb); 01182 if (FAILED(res)) 01183 { 01184 if (res == REGDB_E_CLASSNOTREG) 01185 ERR("CLSID %s not registered\n", debugstr_guid(clsid)); 01186 else if (res == REGDB_E_KEYMISSING) 01187 ERR("no Verbs key for class %s\n", debugstr_guid(clsid)); 01188 else 01189 ERR("failed to open Verbs key for CLSID %s with error %d\n", 01190 debugstr_guid(clsid), res); 01191 return res; 01192 } 01193 01194 res = RegQueryInfoKeyW(hkeyVerb, NULL, NULL, NULL, &dwSubKeys, NULL, 01195 NULL, NULL, NULL, NULL, NULL, NULL); 01196 if (res != ERROR_SUCCESS) 01197 { 01198 ERR("failed to get subkey count with error %d\n", GetLastError()); 01199 return REGDB_E_READREGDB; 01200 } 01201 01202 if (!dwSubKeys) 01203 { 01204 WARN("class %s has no verbs\n", debugstr_guid(clsid)); 01205 RegCloseKey(hkeyVerb); 01206 return OLEOBJ_E_NOVERBS; 01207 } 01208 01209 return EnumOLEVERB_Construct(hkeyVerb, 0, ppenum); 01210 } 01211 01212 /****************************************************************************** 01213 * OleSetContainedObject [OLE32.@] 01214 */ 01215 HRESULT WINAPI OleSetContainedObject( 01216 LPUNKNOWN pUnknown, 01217 BOOL fContained) 01218 { 01219 IRunnableObject* runnable = NULL; 01220 HRESULT hres; 01221 01222 TRACE("(%p,%x)\n", pUnknown, fContained); 01223 01224 hres = IUnknown_QueryInterface(pUnknown, 01225 &IID_IRunnableObject, 01226 (void**)&runnable); 01227 01228 if (SUCCEEDED(hres)) 01229 { 01230 hres = IRunnableObject_SetContainedObject(runnable, fContained); 01231 01232 IRunnableObject_Release(runnable); 01233 01234 return hres; 01235 } 01236 01237 return S_OK; 01238 } 01239 01240 /****************************************************************************** 01241 * OleRun [OLE32.@] 01242 * 01243 * Set the OLE object to the running state. 01244 * 01245 * PARAMS 01246 * pUnknown [I] OLE object to run. 01247 * 01248 * RETURNS 01249 * Success: S_OK. 01250 * Failure: Any HRESULT code. 01251 */ 01252 HRESULT WINAPI OleRun(LPUNKNOWN pUnknown) 01253 { 01254 IRunnableObject *runable; 01255 HRESULT hres; 01256 01257 TRACE("(%p)\n", pUnknown); 01258 01259 hres = IUnknown_QueryInterface(pUnknown, &IID_IRunnableObject, (void**)&runable); 01260 if (FAILED(hres)) 01261 return S_OK; /* Appears to return no error. */ 01262 01263 hres = IRunnableObject_Run(runable, NULL); 01264 IRunnableObject_Release(runable); 01265 return hres; 01266 } 01267 01268 /****************************************************************************** 01269 * OleLoad [OLE32.@] 01270 */ 01271 HRESULT WINAPI OleLoad( 01272 LPSTORAGE pStg, 01273 REFIID riid, 01274 LPOLECLIENTSITE pClientSite, 01275 LPVOID* ppvObj) 01276 { 01277 IPersistStorage* persistStorage = NULL; 01278 IUnknown* pUnk; 01279 IOleObject* pOleObject = NULL; 01280 STATSTG storageInfo; 01281 HRESULT hres; 01282 01283 TRACE("(%p, %s, %p, %p)\n", pStg, debugstr_guid(riid), pClientSite, ppvObj); 01284 01285 *ppvObj = NULL; 01286 01287 /* 01288 * TODO, Conversion ... OleDoAutoConvert 01289 */ 01290 01291 /* 01292 * Get the class ID for the object. 01293 */ 01294 hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME); 01295 01296 /* 01297 * Now, try and create the handler for the object 01298 */ 01299 hres = CoCreateInstance(&storageInfo.clsid, 01300 NULL, 01301 CLSCTX_INPROC_HANDLER|CLSCTX_INPROC_SERVER, 01302 riid, 01303 (void**)&pUnk); 01304 01305 /* 01306 * If that fails, as it will most times, load the default 01307 * OLE handler. 01308 */ 01309 if (FAILED(hres)) 01310 { 01311 hres = OleCreateDefaultHandler(&storageInfo.clsid, 01312 NULL, 01313 riid, 01314 (void**)&pUnk); 01315 } 01316 01317 /* 01318 * If we couldn't find a handler... this is bad. Abort the whole thing. 01319 */ 01320 if (FAILED(hres)) 01321 return hres; 01322 01323 if (pClientSite) 01324 { 01325 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (void **)&pOleObject); 01326 if (SUCCEEDED(hres)) 01327 { 01328 DWORD dwStatus; 01329 hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus); 01330 } 01331 } 01332 01333 /* 01334 * Initialize the object with its IPersistStorage interface. 01335 */ 01336 hres = IOleObject_QueryInterface(pUnk, 01337 &IID_IPersistStorage, 01338 (void**)&persistStorage); 01339 01340 if (SUCCEEDED(hres)) 01341 { 01342 hres = IPersistStorage_Load(persistStorage, pStg); 01343 01344 IPersistStorage_Release(persistStorage); 01345 persistStorage = NULL; 01346 } 01347 01348 if (SUCCEEDED(hres) && pClientSite) 01349 /* 01350 * Inform the new object of it's client site. 01351 */ 01352 hres = IOleObject_SetClientSite(pOleObject, pClientSite); 01353 01354 /* 01355 * Cleanup interfaces used internally 01356 */ 01357 if (pOleObject) 01358 IOleObject_Release(pOleObject); 01359 01360 if (SUCCEEDED(hres)) 01361 { 01362 IOleLink *pOleLink; 01363 HRESULT hres1; 01364 hres1 = IUnknown_QueryInterface(pUnk, &IID_IOleLink, (void **)&pOleLink); 01365 if (SUCCEEDED(hres1)) 01366 { 01367 FIXME("handle OLE link\n"); 01368 IOleLink_Release(pOleLink); 01369 } 01370 } 01371 01372 if (FAILED(hres)) 01373 { 01374 IUnknown_Release(pUnk); 01375 pUnk = NULL; 01376 } 01377 01378 *ppvObj = pUnk; 01379 01380 return hres; 01381 } 01382 01383 /*********************************************************************** 01384 * OleSave [OLE32.@] 01385 */ 01386 HRESULT WINAPI OleSave( 01387 LPPERSISTSTORAGE pPS, 01388 LPSTORAGE pStg, 01389 BOOL fSameAsLoad) 01390 { 01391 HRESULT hres; 01392 CLSID objectClass; 01393 01394 TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad); 01395 01396 /* 01397 * First, we transfer the class ID (if available) 01398 */ 01399 hres = IPersistStorage_GetClassID(pPS, &objectClass); 01400 01401 if (SUCCEEDED(hres)) 01402 { 01403 WriteClassStg(pStg, &objectClass); 01404 } 01405 01406 /* 01407 * Then, we ask the object to save itself to the 01408 * storage. If it is successful, we commit the storage. 01409 */ 01410 hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad); 01411 01412 if (SUCCEEDED(hres)) 01413 { 01414 IStorage_Commit(pStg, 01415 STGC_DEFAULT); 01416 } 01417 01418 return hres; 01419 } 01420 01421 01422 /****************************************************************************** 01423 * OleLockRunning [OLE32.@] 01424 */ 01425 HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses) 01426 { 01427 IRunnableObject* runnable = NULL; 01428 HRESULT hres; 01429 01430 TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses); 01431 01432 hres = IUnknown_QueryInterface(pUnknown, 01433 &IID_IRunnableObject, 01434 (void**)&runnable); 01435 01436 if (SUCCEEDED(hres)) 01437 { 01438 hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses); 01439 01440 IRunnableObject_Release(runnable); 01441 01442 return hres; 01443 } 01444 01445 return S_OK; 01446 } 01447 01448 01449 /************************************************************************** 01450 * Internal methods to manage the shared OLE menu in response to the 01451 * OLE***MenuDescriptor API 01452 */ 01453 01454 /*** 01455 * OLEMenu_Initialize() 01456 * 01457 * Initializes the OLEMENU data structures. 01458 */ 01459 static void OLEMenu_Initialize(void) 01460 { 01461 } 01462 01463 /*** 01464 * OLEMenu_UnInitialize() 01465 * 01466 * Releases the OLEMENU data structures. 01467 */ 01468 static void OLEMenu_UnInitialize(void) 01469 { 01470 } 01471 01472 /************************************************************************* 01473 * OLEMenu_InstallHooks 01474 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC 01475 * 01476 * RETURNS: TRUE if message hooks were successfully installed 01477 * FALSE on failure 01478 */ 01479 static BOOL OLEMenu_InstallHooks( DWORD tid ) 01480 { 01481 OleMenuHookItem *pHookItem; 01482 01483 /* Create an entry for the hook table */ 01484 if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0, 01485 sizeof(OleMenuHookItem)) ) ) 01486 return FALSE; 01487 01488 pHookItem->tid = tid; 01489 pHookItem->hHeap = GetProcessHeap(); 01490 pHookItem->CallWndProc_hHook = NULL; 01491 01492 /* Install a thread scope message hook for WH_GETMESSAGE */ 01493 pHookItem->GetMsg_hHook = SetWindowsHookExW( WH_GETMESSAGE, OLEMenu_GetMsgProc, 01494 0, GetCurrentThreadId() ); 01495 if ( !pHookItem->GetMsg_hHook ) 01496 goto CLEANUP; 01497 01498 /* Install a thread scope message hook for WH_CALLWNDPROC */ 01499 pHookItem->CallWndProc_hHook = SetWindowsHookExW( WH_CALLWNDPROC, OLEMenu_CallWndProc, 01500 0, GetCurrentThreadId() ); 01501 if ( !pHookItem->CallWndProc_hHook ) 01502 goto CLEANUP; 01503 01504 /* Insert the hook table entry */ 01505 pHookItem->next = hook_list; 01506 hook_list = pHookItem; 01507 01508 return TRUE; 01509 01510 CLEANUP: 01511 /* Unhook any hooks */ 01512 if ( pHookItem->GetMsg_hHook ) 01513 UnhookWindowsHookEx( pHookItem->GetMsg_hHook ); 01514 if ( pHookItem->CallWndProc_hHook ) 01515 UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ); 01516 /* Release the hook table entry */ 01517 HeapFree(pHookItem->hHeap, 0, pHookItem ); 01518 01519 return FALSE; 01520 } 01521 01522 /************************************************************************* 01523 * OLEMenu_UnInstallHooks 01524 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC 01525 * 01526 * RETURNS: TRUE if message hooks were successfully installed 01527 * FALSE on failure 01528 */ 01529 static BOOL OLEMenu_UnInstallHooks( DWORD tid ) 01530 { 01531 OleMenuHookItem *pHookItem = NULL; 01532 OleMenuHookItem **ppHook = &hook_list; 01533 01534 while (*ppHook) 01535 { 01536 if ((*ppHook)->tid == tid) 01537 { 01538 pHookItem = *ppHook; 01539 *ppHook = pHookItem->next; 01540 break; 01541 } 01542 ppHook = &(*ppHook)->next; 01543 } 01544 if (!pHookItem) return FALSE; 01545 01546 /* Uninstall the hooks installed for this thread */ 01547 if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) ) 01548 goto CLEANUP; 01549 if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) ) 01550 goto CLEANUP; 01551 01552 /* Release the hook table entry */ 01553 HeapFree(pHookItem->hHeap, 0, pHookItem ); 01554 01555 return TRUE; 01556 01557 CLEANUP: 01558 /* Release the hook table entry */ 01559 HeapFree(pHookItem->hHeap, 0, pHookItem ); 01560 01561 return FALSE; 01562 } 01563 01564 /************************************************************************* 01565 * OLEMenu_IsHookInstalled 01566 * Tests if OLEMenu hooks have been installed for a thread 01567 * 01568 * RETURNS: The pointer and index of the hook table entry for the tid 01569 * NULL and -1 for the index if no hooks were installed for this thread 01570 */ 01571 static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid ) 01572 { 01573 OleMenuHookItem *pHookItem; 01574 01575 /* Do a simple linear search for an entry whose tid matches ours. 01576 * We really need a map but efficiency is not a concern here. */ 01577 for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next) 01578 { 01579 if ( tid == pHookItem->tid ) 01580 return pHookItem; 01581 } 01582 01583 return NULL; 01584 } 01585 01586 /*********************************************************************** 01587 * OLEMenu_FindMainMenuIndex 01588 * 01589 * Used by OLEMenu API to find the top level group a menu item belongs to. 01590 * On success pnPos contains the index of the item in the top level menu group 01591 * 01592 * RETURNS: TRUE if the ID was found, FALSE on failure 01593 */ 01594 static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos ) 01595 { 01596 INT i, nItems; 01597 01598 nItems = GetMenuItemCount( hMainMenu ); 01599 01600 for (i = 0; i < nItems; i++) 01601 { 01602 HMENU hsubmenu; 01603 01604 /* Is the current item a submenu? */ 01605 if ( (hsubmenu = GetSubMenu(hMainMenu, i)) ) 01606 { 01607 /* If the handle is the same we're done */ 01608 if ( hsubmenu == hPopupMenu ) 01609 { 01610 if (pnPos) 01611 *pnPos = i; 01612 return TRUE; 01613 } 01614 /* Recursively search without updating pnPos */ 01615 else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) ) 01616 { 01617 if (pnPos) 01618 *pnPos = i; 01619 return TRUE; 01620 } 01621 } 01622 } 01623 01624 return FALSE; 01625 } 01626 01627 /*********************************************************************** 01628 * OLEMenu_SetIsServerMenu 01629 * 01630 * Checks whether a popup menu belongs to a shared menu group which is 01631 * owned by the server, and sets the menu descriptor state accordingly. 01632 * All menu messages from these groups should be routed to the server. 01633 * 01634 * RETURNS: TRUE if the popup menu is part of a server owned group 01635 * FALSE if the popup menu is part of a container owned group 01636 */ 01637 static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor ) 01638 { 01639 UINT nPos = 0, nWidth, i; 01640 01641 pOleMenuDescriptor->bIsServerItem = FALSE; 01642 01643 /* Don't bother searching if the popup is the combined menu itself */ 01644 if ( hmenu == pOleMenuDescriptor->hmenuCombined ) 01645 return FALSE; 01646 01647 /* Find the menu item index in the shared OLE menu that this item belongs to */ 01648 if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) ) 01649 return FALSE; 01650 01651 /* The group widths array has counts for the number of elements 01652 * in the groups File, Edit, Container, Object, Window, Help. 01653 * The Edit, Object & Help groups belong to the server object 01654 * and the other three belong to the container. 01655 * Loop through the group widths and locate the group we are a member of. 01656 */ 01657 for ( i = 0, nWidth = 0; i < 6; i++ ) 01658 { 01659 nWidth += pOleMenuDescriptor->mgw.width[i]; 01660 if ( nPos < nWidth ) 01661 { 01662 /* Odd elements are server menu widths */ 01663 pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE; 01664 break; 01665 } 01666 } 01667 01668 return pOleMenuDescriptor->bIsServerItem; 01669 } 01670 01671 /************************************************************************* 01672 * OLEMenu_CallWndProc 01673 * Thread scope WH_CALLWNDPROC hook proc filter function (callback) 01674 * This is invoked from a message hook installed in OleSetMenuDescriptor. 01675 */ 01676 static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam) 01677 { 01678 LPCWPSTRUCT pMsg; 01679 HOLEMENU hOleMenu = 0; 01680 OleMenuDescriptor *pOleMenuDescriptor = NULL; 01681 OleMenuHookItem *pHookItem = NULL; 01682 WORD fuFlags; 01683 01684 TRACE("%i, %04lx, %08lx\n", code, wParam, lParam ); 01685 01686 /* Check if we're being asked to process the message */ 01687 if ( HC_ACTION != code ) 01688 goto NEXTHOOK; 01689 01690 /* Retrieve the current message being dispatched from lParam */ 01691 pMsg = (LPCWPSTRUCT)lParam; 01692 01693 /* Check if the message is destined for a window we are interested in: 01694 * If the window has an OLEMenu property we may need to dispatch 01695 * the menu message to its active objects window instead. */ 01696 01697 hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW ); 01698 if ( !hOleMenu ) 01699 goto NEXTHOOK; 01700 01701 /* Get the menu descriptor */ 01702 pOleMenuDescriptor = GlobalLock( hOleMenu ); 01703 if ( !pOleMenuDescriptor ) /* Bad descriptor! */ 01704 goto NEXTHOOK; 01705 01706 /* Process menu messages */ 01707 switch( pMsg->message ) 01708 { 01709 case WM_INITMENU: 01710 { 01711 /* Reset the menu descriptor state */ 01712 pOleMenuDescriptor->bIsServerItem = FALSE; 01713 01714 /* Send this message to the server as well */ 01715 SendMessageW( pOleMenuDescriptor->hwndActiveObject, 01716 pMsg->message, pMsg->wParam, pMsg->lParam ); 01717 goto NEXTHOOK; 01718 } 01719 01720 case WM_INITMENUPOPUP: 01721 { 01722 /* Save the state for whether this is a server owned menu */ 01723 OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor ); 01724 break; 01725 } 01726 01727 case WM_MENUSELECT: 01728 { 01729 fuFlags = HIWORD(pMsg->wParam); /* Get flags */ 01730 if ( fuFlags & MF_SYSMENU ) 01731 goto NEXTHOOK; 01732 01733 /* Save the state for whether this is a server owned popup menu */ 01734 else if ( fuFlags & MF_POPUP ) 01735 OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor ); 01736 01737 break; 01738 } 01739 01740 case WM_DRAWITEM: 01741 { 01742 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam; 01743 if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU ) 01744 goto NEXTHOOK; /* Not a menu message */ 01745 01746 break; 01747 } 01748 01749 default: 01750 goto NEXTHOOK; 01751 } 01752 01753 /* If the message was for the server dispatch it accordingly */ 01754 if ( pOleMenuDescriptor->bIsServerItem ) 01755 { 01756 SendMessageW( pOleMenuDescriptor->hwndActiveObject, 01757 pMsg->message, pMsg->wParam, pMsg->lParam ); 01758 } 01759 01760 NEXTHOOK: 01761 if ( pOleMenuDescriptor ) 01762 GlobalUnlock( hOleMenu ); 01763 01764 /* Lookup the hook item for the current thread */ 01765 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) ) 01766 { 01767 /* This should never fail!! */ 01768 WARN("could not retrieve hHook for current thread!\n" ); 01769 return 0; 01770 } 01771 01772 /* Pass on the message to the next hooker */ 01773 return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam ); 01774 } 01775 01776 /************************************************************************* 01777 * OLEMenu_GetMsgProc 01778 * Thread scope WH_GETMESSAGE hook proc filter function (callback) 01779 * This is invoked from a message hook installed in OleSetMenuDescriptor. 01780 */ 01781 static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam) 01782 { 01783 LPMSG pMsg; 01784 HOLEMENU hOleMenu = 0; 01785 OleMenuDescriptor *pOleMenuDescriptor = NULL; 01786 OleMenuHookItem *pHookItem = NULL; 01787 WORD wCode; 01788 01789 TRACE("%i, %04lx, %08lx\n", code, wParam, lParam ); 01790 01791 /* Check if we're being asked to process a messages */ 01792 if ( HC_ACTION != code ) 01793 goto NEXTHOOK; 01794 01795 /* Retrieve the current message being dispatched from lParam */ 01796 pMsg = (LPMSG)lParam; 01797 01798 /* Check if the message is destined for a window we are interested in: 01799 * If the window has an OLEMenu property we may need to dispatch 01800 * the menu message to its active objects window instead. */ 01801 01802 hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW ); 01803 if ( !hOleMenu ) 01804 goto NEXTHOOK; 01805 01806 /* Process menu messages */ 01807 switch( pMsg->message ) 01808 { 01809 case WM_COMMAND: 01810 { 01811 wCode = HIWORD(pMsg->wParam); /* Get notification code */ 01812 if ( wCode ) 01813 goto NEXTHOOK; /* Not a menu message */ 01814 break; 01815 } 01816 default: 01817 goto NEXTHOOK; 01818 } 01819 01820 /* Get the menu descriptor */ 01821 pOleMenuDescriptor = GlobalLock( hOleMenu ); 01822 if ( !pOleMenuDescriptor ) /* Bad descriptor! */ 01823 goto NEXTHOOK; 01824 01825 /* If the message was for the server dispatch it accordingly */ 01826 if ( pOleMenuDescriptor->bIsServerItem ) 01827 { 01828 /* Change the hWnd in the message to the active objects hWnd. 01829 * The message loop which reads this message will automatically 01830 * dispatch it to the embedded objects window. */ 01831 pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject; 01832 } 01833 01834 NEXTHOOK: 01835 if ( pOleMenuDescriptor ) 01836 GlobalUnlock( hOleMenu ); 01837 01838 /* Lookup the hook item for the current thread */ 01839 if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) ) 01840 { 01841 /* This should never fail!! */ 01842 WARN("could not retrieve hHook for current thread!\n" ); 01843 return FALSE; 01844 } 01845 01846 /* Pass on the message to the next hooker */ 01847 return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam ); 01848 } 01849 01850 /*********************************************************************** 01851 * OleCreateMenuDescriptor [OLE32.@] 01852 * Creates an OLE menu descriptor for OLE to use when dispatching 01853 * menu messages and commands. 01854 * 01855 * PARAMS: 01856 * hmenuCombined - Handle to the objects combined menu 01857 * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group 01858 * 01859 */ 01860 HOLEMENU WINAPI OleCreateMenuDescriptor( 01861 HMENU hmenuCombined, 01862 LPOLEMENUGROUPWIDTHS lpMenuWidths) 01863 { 01864 HOLEMENU hOleMenu; 01865 OleMenuDescriptor *pOleMenuDescriptor; 01866 int i; 01867 01868 if ( !hmenuCombined || !lpMenuWidths ) 01869 return 0; 01870 01871 /* Create an OLE menu descriptor */ 01872 if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, 01873 sizeof(OleMenuDescriptor) ) ) ) 01874 return 0; 01875 01876 pOleMenuDescriptor = GlobalLock( hOleMenu ); 01877 if ( !pOleMenuDescriptor ) 01878 return 0; 01879 01880 /* Initialize menu group widths and hmenu */ 01881 for ( i = 0; i < 6; i++ ) 01882 pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i]; 01883 01884 pOleMenuDescriptor->hmenuCombined = hmenuCombined; 01885 pOleMenuDescriptor->bIsServerItem = FALSE; 01886 GlobalUnlock( hOleMenu ); 01887 01888 return hOleMenu; 01889 } 01890 01891 /*********************************************************************** 01892 * OleDestroyMenuDescriptor [OLE32.@] 01893 * Destroy the shared menu descriptor 01894 */ 01895 HRESULT WINAPI OleDestroyMenuDescriptor( 01896 HOLEMENU hmenuDescriptor) 01897 { 01898 if ( hmenuDescriptor ) 01899 GlobalFree( hmenuDescriptor ); 01900 return S_OK; 01901 } 01902 01903 /*********************************************************************** 01904 * OleSetMenuDescriptor [OLE32.@] 01905 * Installs or removes OLE dispatching code for the containers frame window. 01906 * 01907 * PARAMS 01908 * hOleMenu Handle to composite menu descriptor 01909 * hwndFrame Handle to containers frame window 01910 * hwndActiveObject Handle to objects in-place activation window 01911 * lpFrame Pointer to IOleInPlaceFrame on containers window 01912 * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object 01913 * 01914 * RETURNS 01915 * S_OK - menu installed correctly 01916 * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure 01917 * 01918 * FIXME 01919 * The lpFrame and lpActiveObject parameters are currently ignored 01920 * OLE should install context sensitive help F1 filtering for the app when 01921 * these are non null. 01922 */ 01923 HRESULT WINAPI OleSetMenuDescriptor( 01924 HOLEMENU hOleMenu, 01925 HWND hwndFrame, 01926 HWND hwndActiveObject, 01927 LPOLEINPLACEFRAME lpFrame, 01928 LPOLEINPLACEACTIVEOBJECT lpActiveObject) 01929 { 01930 OleMenuDescriptor *pOleMenuDescriptor = NULL; 01931 01932 /* Check args */ 01933 if ( !hwndFrame || (hOleMenu && !hwndActiveObject) ) 01934 return E_INVALIDARG; 01935 01936 if ( lpFrame || lpActiveObject ) 01937 { 01938 FIXME("(%p, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n", 01939 hOleMenu, 01940 hwndFrame, 01941 hwndActiveObject, 01942 lpFrame, 01943 lpActiveObject); 01944 } 01945 01946 /* Set up a message hook to intercept the containers frame window messages. 01947 * The message filter is responsible for dispatching menu messages from the 01948 * shared menu which are intended for the object. 01949 */ 01950 01951 if ( hOleMenu ) /* Want to install dispatching code */ 01952 { 01953 /* If OLEMenu hooks are already installed for this thread, fail 01954 * Note: This effectively means that OleSetMenuDescriptor cannot 01955 * be called twice in succession on the same frame window 01956 * without first calling it with a null hOleMenu to uninstall */ 01957 if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) 01958 return E_FAIL; 01959 01960 /* Get the menu descriptor */ 01961 pOleMenuDescriptor = GlobalLock( hOleMenu ); 01962 if ( !pOleMenuDescriptor ) 01963 return E_UNEXPECTED; 01964 01965 /* Update the menu descriptor */ 01966 pOleMenuDescriptor->hwndFrame = hwndFrame; 01967 pOleMenuDescriptor->hwndActiveObject = hwndActiveObject; 01968 01969 GlobalUnlock( hOleMenu ); 01970 pOleMenuDescriptor = NULL; 01971 01972 /* Add a menu descriptor windows property to the frame window */ 01973 SetPropW( hwndFrame, prop_olemenuW, hOleMenu ); 01974 01975 /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */ 01976 if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) ) 01977 return E_FAIL; 01978 } 01979 else /* Want to uninstall dispatching code */ 01980 { 01981 /* Uninstall the hooks */ 01982 if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) ) 01983 return E_FAIL; 01984 01985 /* Remove the menu descriptor property from the frame window */ 01986 RemovePropW( hwndFrame, prop_olemenuW ); 01987 } 01988 01989 return S_OK; 01990 } 01991 01992 /****************************************************************************** 01993 * IsAccelerator [OLE32.@] 01994 * Mostly copied from controls/menu.c TranslateAccelerator implementation 01995 */ 01996 BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd) 01997 { 01998 LPACCEL lpAccelTbl; 01999 int i; 02000 02001 if(!lpMsg) return FALSE; 02002 if (!hAccel) 02003 { 02004 WARN_(accel)("NULL accel handle\n"); 02005 return FALSE; 02006 } 02007 if((lpMsg->message != WM_KEYDOWN && 02008 lpMsg->message != WM_SYSKEYDOWN && 02009 lpMsg->message != WM_SYSCHAR && 02010 lpMsg->message != WM_CHAR)) return FALSE; 02011 lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL)); 02012 if (NULL == lpAccelTbl) 02013 { 02014 return FALSE; 02015 } 02016 if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries) 02017 { 02018 WARN_(accel)("CopyAcceleratorTableW failed\n"); 02019 HeapFree(GetProcessHeap(), 0, lpAccelTbl); 02020 return FALSE; 02021 } 02022 02023 TRACE_(accel)("hAccel=%p, cAccelEntries=%d," 02024 "msg->hwnd=%p, msg->message=%04x, wParam=%08lx, lParam=%08lx\n", 02025 hAccel, cAccelEntries, 02026 lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam); 02027 for(i = 0; i < cAccelEntries; i++) 02028 { 02029 if(lpAccelTbl[i].key != lpMsg->wParam) 02030 continue; 02031 02032 if(lpMsg->message == WM_CHAR) 02033 { 02034 if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY)) 02035 { 02036 TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", LOWORD(lpMsg->wParam) & 0xff); 02037 goto found; 02038 } 02039 } 02040 else 02041 { 02042 if(lpAccelTbl[i].fVirt & FVIRTKEY) 02043 { 02044 INT mask = 0; 02045 TRACE_(accel)("found accel for virt_key %04lx (scan %04x)\n", 02046 lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff); 02047 if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT; 02048 if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL; 02049 if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT; 02050 if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found; 02051 TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n"); 02052 } 02053 else 02054 { 02055 if(!(lpMsg->lParam & 0x01000000)) /* no special_key */ 02056 { 02057 if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000)) 02058 { /* ^^ ALT pressed */ 02059 TRACE_(accel)("found accel for Alt-%c\n", LOWORD(lpMsg->wParam) & 0xff); 02060 goto found; 02061 } 02062 } 02063 } 02064 } 02065 } 02066 02067 WARN_(accel)("couldn't translate accelerator key\n"); 02068 HeapFree(GetProcessHeap(), 0, lpAccelTbl); 02069 return FALSE; 02070 02071 found: 02072 if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd; 02073 HeapFree(GetProcessHeap(), 0, lpAccelTbl); 02074 return TRUE; 02075 } 02076 02077 /*********************************************************************** 02078 * ReleaseStgMedium [OLE32.@] 02079 */ 02080 void WINAPI ReleaseStgMedium( 02081 STGMEDIUM* pmedium) 02082 { 02083 switch (pmedium->tymed) 02084 { 02085 case TYMED_HGLOBAL: 02086 { 02087 if ( (pmedium->pUnkForRelease==0) && 02088 (pmedium->u.hGlobal!=0) ) 02089 GlobalFree(pmedium->u.hGlobal); 02090 break; 02091 } 02092 case TYMED_FILE: 02093 { 02094 if (pmedium->u.lpszFileName!=0) 02095 { 02096 if (pmedium->pUnkForRelease==0) 02097 { 02098 DeleteFileW(pmedium->u.lpszFileName); 02099 } 02100 02101 CoTaskMemFree(pmedium->u.lpszFileName); 02102 } 02103 break; 02104 } 02105 case TYMED_ISTREAM: 02106 { 02107 if (pmedium->u.pstm!=0) 02108 { 02109 IStream_Release(pmedium->u.pstm); 02110 } 02111 break; 02112 } 02113 case TYMED_ISTORAGE: 02114 { 02115 if (pmedium->u.pstg!=0) 02116 { 02117 IStorage_Release(pmedium->u.pstg); 02118 } 02119 break; 02120 } 02121 case TYMED_GDI: 02122 { 02123 if ( (pmedium->pUnkForRelease==0) && 02124 (pmedium->u.hBitmap!=0) ) 02125 DeleteObject(pmedium->u.hBitmap); 02126 break; 02127 } 02128 case TYMED_MFPICT: 02129 { 02130 if ( (pmedium->pUnkForRelease==0) && 02131 (pmedium->u.hMetaFilePict!=0) ) 02132 { 02133 LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict); 02134 DeleteMetaFile(pMP->hMF); 02135 GlobalUnlock(pmedium->u.hMetaFilePict); 02136 GlobalFree(pmedium->u.hMetaFilePict); 02137 } 02138 break; 02139 } 02140 case TYMED_ENHMF: 02141 { 02142 if ( (pmedium->pUnkForRelease==0) && 02143 (pmedium->u.hEnhMetaFile!=0) ) 02144 { 02145 DeleteEnhMetaFile(pmedium->u.hEnhMetaFile); 02146 } 02147 break; 02148 } 02149 case TYMED_NULL: 02150 default: 02151 break; 02152 } 02153 pmedium->tymed=TYMED_NULL; 02154 02155 /* 02156 * After cleaning up, the unknown is released 02157 */ 02158 if (pmedium->pUnkForRelease!=0) 02159 { 02160 IUnknown_Release(pmedium->pUnkForRelease); 02161 pmedium->pUnkForRelease = 0; 02162 } 02163 } 02164 02165 /*** 02166 * OLEDD_Initialize() 02167 * 02168 * Initializes the OLE drag and drop data structures. 02169 */ 02170 static void OLEDD_Initialize(void) 02171 { 02172 WNDCLASSW wndClass; 02173 02174 ZeroMemory (&wndClass, sizeof(WNDCLASSW)); 02175 wndClass.style = CS_GLOBALCLASS; 02176 wndClass.lpfnWndProc = OLEDD_DragTrackerWindowProc; 02177 wndClass.cbClsExtra = 0; 02178 wndClass.cbWndExtra = sizeof(TrackerWindowInfo*); 02179 wndClass.hCursor = 0; 02180 wndClass.hbrBackground = 0; 02181 wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS; 02182 02183 RegisterClassW (&wndClass); 02184 } 02185 02186 /*** 02187 * OLEDD_DragTrackerWindowProc() 02188 * 02189 * This method is the WindowProcedure of the drag n drop tracking 02190 * window. During a drag n Drop operation, an invisible window is created 02191 * to receive the user input and act upon it. This procedure is in charge 02192 * of this behavior. 02193 */ 02194 02195 #define DRAG_TIMER_ID 1 02196 02197 static LRESULT WINAPI OLEDD_DragTrackerWindowProc( 02198 HWND hwnd, 02199 UINT uMsg, 02200 WPARAM wParam, 02201 LPARAM lParam) 02202 { 02203 switch (uMsg) 02204 { 02205 case WM_CREATE: 02206 { 02207 LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam; 02208 02209 SetWindowLongPtrW(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams); 02210 SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL); 02211 02212 break; 02213 } 02214 case WM_TIMER: 02215 case WM_MOUSEMOVE: 02216 { 02217 OLEDD_TrackMouseMove((TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0)); 02218 break; 02219 } 02220 case WM_LBUTTONUP: 02221 case WM_MBUTTONUP: 02222 case WM_RBUTTONUP: 02223 case WM_LBUTTONDOWN: 02224 case WM_MBUTTONDOWN: 02225 case WM_RBUTTONDOWN: 02226 { 02227 OLEDD_TrackStateChange((TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0)); 02228 break; 02229 } 02230 case WM_DESTROY: 02231 { 02232 KillTimer(hwnd, DRAG_TIMER_ID); 02233 break; 02234 } 02235 } 02236 02237 /* 02238 * This is a window proc after all. Let's call the default. 02239 */ 02240 return DefWindowProcW (hwnd, uMsg, wParam, lParam); 02241 } 02242 02243 /*** 02244 * OLEDD_TrackMouseMove() 02245 * 02246 * This method is invoked while a drag and drop operation is in effect. 02247 * it will generate the appropriate callbacks in the drop source 02248 * and drop target. It will also provide the expected feedback to 02249 * the user. 02250 * 02251 * params: 02252 * trackerInfo - Pointer to the structure identifying the 02253 * drag & drop operation that is currently 02254 * active. 02255 */ 02256 static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo) 02257 { 02258 HWND hwndNewTarget = 0; 02259 HRESULT hr = S_OK; 02260 POINT pt; 02261 02262 /* 02263 * Get the handle of the window under the mouse 02264 */ 02265 pt.x = trackerInfo->curMousePos.x; 02266 pt.y = trackerInfo->curMousePos.y; 02267 hwndNewTarget = WindowFromPoint(pt); 02268 02269 /* 02270 * Every time, we re-initialize the effects passed to the 02271 * IDropTarget to the effects allowed by the source. 02272 */ 02273 *trackerInfo->pdwEffect = trackerInfo->dwOKEffect; 02274 02275 /* 02276 * If we are hovering over the same target as before, send the 02277 * DragOver notification 02278 */ 02279 if ( (trackerInfo->curDragTarget != 0) && 02280 (trackerInfo->curTargetHWND == hwndNewTarget) ) 02281 { 02282 IDropTarget_DragOver(trackerInfo->curDragTarget, 02283 trackerInfo->dwKeyState, 02284 trackerInfo->curMousePos, 02285 trackerInfo->pdwEffect); 02286 } 02287 else 02288 { 02289 /* 02290 * If we changed window, we have to notify our old target and check for 02291 * the new one. 02292 */ 02293 if (trackerInfo->curDragTarget) 02294 IDropTarget_DragLeave(trackerInfo->curDragTarget); 02295 02296 /* 02297 * Make sure we're hovering over a window. 02298 */ 02299 if (hwndNewTarget) 02300 { 02301 /* 02302 * Find-out if there is a drag target under the mouse 02303 */ 02304 HWND next_target_wnd = hwndNewTarget; 02305 02306 trackerInfo->curTargetHWND = hwndNewTarget; 02307 02308 while (next_target_wnd && !is_droptarget(next_target_wnd)) 02309 next_target_wnd = GetParent(next_target_wnd); 02310 02311 if (next_target_wnd) hwndNewTarget = next_target_wnd; 02312 02313 trackerInfo->curDragTargetHWND = hwndNewTarget; 02314 if(trackerInfo->curDragTarget) IDropTarget_Release(trackerInfo->curDragTarget); 02315 trackerInfo->curDragTarget = get_droptarget_pointer(hwndNewTarget); 02316 02317 /* 02318 * If there is, notify it that we just dragged-in 02319 */ 02320 if (trackerInfo->curDragTarget) 02321 { 02322 hr = IDropTarget_DragEnter(trackerInfo->curDragTarget, 02323 trackerInfo->dataObject, 02324 trackerInfo->dwKeyState, 02325 trackerInfo->curMousePos, 02326 trackerInfo->pdwEffect); 02327 02328 /* failed DragEnter() means invalid target */ 02329 if (hr != S_OK) 02330 { 02331 trackerInfo->curDragTargetHWND = 0; 02332 trackerInfo->curTargetHWND = 0; 02333 IDropTarget_Release(trackerInfo->curDragTarget); 02334 trackerInfo->curDragTarget = 0; 02335 } 02336 } 02337 } 02338 else 02339 { 02340 /* 02341 * The mouse is not over a window so we don't track anything. 02342 */ 02343 trackerInfo->curDragTargetHWND = 0; 02344 trackerInfo->curTargetHWND = 0; 02345 if(trackerInfo->curDragTarget) IDropTarget_Release(trackerInfo->curDragTarget); 02346 trackerInfo->curDragTarget = 0; 02347 } 02348 } 02349 02350 /* 02351 * Now that we have done that, we have to tell the source to give 02352 * us feedback on the work being done by the target. If we don't 02353 * have a target, simulate no effect. 02354 */ 02355 if (trackerInfo->curDragTarget==0) 02356 { 02357 *trackerInfo->pdwEffect = DROPEFFECT_NONE; 02358 } 02359 02360 hr = IDropSource_GiveFeedback(trackerInfo->dropSource, 02361 *trackerInfo->pdwEffect); 02362 02363 /* 02364 * When we ask for feedback from the drop source, sometimes it will 02365 * do all the necessary work and sometimes it will not handle it 02366 * when that's the case, we must display the standard drag and drop 02367 * cursors. 02368 */ 02369 if (hr == DRAGDROP_S_USEDEFAULTCURSORS) 02370 { 02371 HCURSOR hCur; 02372 02373 if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) 02374 { 02375 hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(2)); 02376 } 02377 else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY) 02378 { 02379 hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(3)); 02380 } 02381 else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK) 02382 { 02383 hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(4)); 02384 } 02385 else 02386 { 02387 hCur = LoadCursorW(hProxyDll, MAKEINTRESOURCEW(1)); 02388 } 02389 02390 SetCursor(hCur); 02391 } 02392 } 02393 02394 /*** 02395 * OLEDD_TrackStateChange() 02396 * 02397 * This method is invoked while a drag and drop operation is in effect. 02398 * It is used to notify the drop target/drop source callbacks when 02399 * the state of the keyboard or mouse button change. 02400 * 02401 * params: 02402 * trackerInfo - Pointer to the structure identifying the 02403 * drag & drop operation that is currently 02404 * active. 02405 */ 02406 static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo) 02407 { 02408 /* 02409 * Ask the drop source what to do with the operation. 02410 */ 02411 trackerInfo->returnValue = IDropSource_QueryContinueDrag( 02412 trackerInfo->dropSource, 02413 trackerInfo->escPressed, 02414 trackerInfo->dwKeyState); 02415 02416 /* 02417 * All the return valued will stop the operation except the S_OK 02418 * return value. 02419 */ 02420 if (trackerInfo->returnValue!=S_OK) 02421 { 02422 /* 02423 * Make sure the message loop in DoDragDrop stops 02424 */ 02425 trackerInfo->trackingDone = TRUE; 02426 02427 /* 02428 * Release the mouse in case the drop target decides to show a popup 02429 * or a menu or something. 02430 */ 02431 ReleaseCapture(); 02432 02433 /* 02434 * If we end-up over a target, drop the object in the target or 02435 * inform the target that the operation was cancelled. 02436 */ 02437 if (trackerInfo->curDragTarget) 02438 { 02439 switch (trackerInfo->returnValue) 02440 { 02441 /* 02442 * If the source wants us to complete the operation, we tell 02443 * the drop target that we just dropped the object in it. 02444 */ 02445 case DRAGDROP_S_DROP: 02446 if (*trackerInfo->pdwEffect != DROPEFFECT_NONE) 02447 IDropTarget_Drop(trackerInfo->curDragTarget, 02448 trackerInfo->dataObject, 02449 trackerInfo->dwKeyState, 02450 trackerInfo->curMousePos, 02451 trackerInfo->pdwEffect); 02452 else 02453 IDropTarget_DragLeave(trackerInfo->curDragTarget); 02454 break; 02455 02456 /* 02457 * If the source told us that we should cancel, fool the drop 02458 * target by telling it that the mouse left it's window. 02459 * Also set the drop effect to "NONE" in case the application 02460 * ignores the result of DoDragDrop. 02461 */ 02462 case DRAGDROP_S_CANCEL: 02463 IDropTarget_DragLeave(trackerInfo->curDragTarget); 02464 *trackerInfo->pdwEffect = DROPEFFECT_NONE; 02465 break; 02466 } 02467 } 02468 } 02469 } 02470 02471 /*** 02472 * OLEDD_GetButtonState() 02473 * 02474 * This method will use the current state of the keyboard to build 02475 * a button state mask equivalent to the one passed in the 02476 * WM_MOUSEMOVE wParam. 02477 */ 02478 static DWORD OLEDD_GetButtonState(void) 02479 { 02480 BYTE keyboardState[256]; 02481 DWORD keyMask = 0; 02482 02483 GetKeyboardState(keyboardState); 02484 02485 if ( (keyboardState[VK_SHIFT] & 0x80) !=0) 02486 keyMask |= MK_SHIFT; 02487 02488 if ( (keyboardState[VK_CONTROL] & 0x80) !=0) 02489 keyMask |= MK_CONTROL; 02490 02491 if ( (keyboardState[VK_LBUTTON] & 0x80) !=0) 02492 keyMask |= MK_LBUTTON; 02493 02494 if ( (keyboardState[VK_RBUTTON] & 0x80) !=0) 02495 keyMask |= MK_RBUTTON; 02496 02497 if ( (keyboardState[VK_MBUTTON] & 0x80) !=0) 02498 keyMask |= MK_MBUTTON; 02499 02500 return keyMask; 02501 } 02502 02503 /*** 02504 * OLEDD_GetButtonState() 02505 * 02506 * This method will read the default value of the registry key in 02507 * parameter and extract a DWORD value from it. The registry key value 02508 * can be in a string key or a DWORD key. 02509 * 02510 * params: 02511 * regKey - Key to read the default value from 02512 * pdwValue - Pointer to the location where the DWORD 02513 * value is returned. This value is not modified 02514 * if the value is not found. 02515 */ 02516 02517 static void OLEUTL_ReadRegistryDWORDValue( 02518 HKEY regKey, 02519 DWORD* pdwValue) 02520 { 02521 WCHAR buffer[20]; 02522 DWORD cbData = sizeof(buffer); 02523 DWORD dwKeyType; 02524 LONG lres; 02525 02526 lres = RegQueryValueExW(regKey, 02527 emptyW, 02528 NULL, 02529 &dwKeyType, 02530 (LPBYTE)buffer, 02531 &cbData); 02532 02533 if (lres==ERROR_SUCCESS) 02534 { 02535 switch (dwKeyType) 02536 { 02537 case REG_DWORD: 02538 *pdwValue = *(DWORD*)buffer; 02539 break; 02540 case REG_EXPAND_SZ: 02541 case REG_MULTI_SZ: 02542 case REG_SZ: 02543 *pdwValue = (DWORD)strtoulW(buffer, NULL, 10); 02544 break; 02545 } 02546 } 02547 } 02548 02549 /****************************************************************************** 02550 * OleDraw (OLE32.@) 02551 * 02552 * The operation of this function is documented literally in the WinAPI 02553 * documentation to involve a QueryInterface for the IViewObject interface, 02554 * followed by a call to IViewObject::Draw. 02555 */ 02556 HRESULT WINAPI OleDraw( 02557 IUnknown *pUnk, 02558 DWORD dwAspect, 02559 HDC hdcDraw, 02560 LPCRECT lprcBounds) 02561 { 02562 HRESULT hres; 02563 IViewObject *viewobject; 02564 02565 hres = IUnknown_QueryInterface(pUnk, 02566 &IID_IViewObject, 02567 (void**)&viewobject); 02568 02569 if (SUCCEEDED(hres)) 02570 { 02571 RECTL rectl; 02572 02573 rectl.left = lprcBounds->left; 02574 rectl.right = lprcBounds->right; 02575 rectl.top = lprcBounds->top; 02576 rectl.bottom = lprcBounds->bottom; 02577 hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, &rectl, 0, 0, 0); 02578 02579 IViewObject_Release(viewobject); 02580 return hres; 02581 } 02582 else 02583 { 02584 return DV_E_NOIVIEWOBJECT; 02585 } 02586 } 02587 02588 /*********************************************************************** 02589 * OleTranslateAccelerator [OLE32.@] 02590 */ 02591 HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame, 02592 LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg) 02593 { 02594 WORD wID; 02595 02596 TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg); 02597 02598 if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID)) 02599 return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID); 02600 02601 return S_FALSE; 02602 } 02603 02604 /****************************************************************************** 02605 * OleCreate [OLE32.@] 02606 * 02607 */ 02608 HRESULT WINAPI OleCreate( 02609 REFCLSID rclsid, 02610 REFIID riid, 02611 DWORD renderopt, 02612 LPFORMATETC pFormatEtc, 02613 LPOLECLIENTSITE pClientSite, 02614 LPSTORAGE pStg, 02615 LPVOID* ppvObj) 02616 { 02617 HRESULT hres; 02618 IUnknown * pUnk = NULL; 02619 IOleObject *pOleObject = NULL; 02620 02621 TRACE("(%s, %s, %d, %p, %p, %p, %p)\n", debugstr_guid(rclsid), 02622 debugstr_guid(riid), renderopt, pFormatEtc, pClientSite, pStg, ppvObj); 02623 02624 hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, riid, (LPVOID*)&pUnk); 02625 02626 if (SUCCEEDED(hres)) 02627 hres = IStorage_SetClass(pStg, rclsid); 02628 02629 if (pClientSite && SUCCEEDED(hres)) 02630 { 02631 hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (LPVOID*)&pOleObject); 02632 if (SUCCEEDED(hres)) 02633 { 02634 DWORD dwStatus; 02635 hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus); 02636 } 02637 } 02638 02639 if (SUCCEEDED(hres)) 02640 { 02641 IPersistStorage * pPS; 02642 if (SUCCEEDED((hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (LPVOID*)&pPS)))) 02643 { 02644 TRACE("trying to set stg %p\n", pStg); 02645 hres = IPersistStorage_InitNew(pPS, pStg); 02646 TRACE("-- result 0x%08x\n", hres); 02647 IPersistStorage_Release(pPS); 02648 } 02649 } 02650 02651 if (pClientSite && SUCCEEDED(hres)) 02652 { 02653 TRACE("trying to set clientsite %p\n", pClientSite); 02654 hres = IOleObject_SetClientSite(pOleObject, pClientSite); 02655 TRACE("-- result 0x%08x\n", hres); 02656 } 02657 02658 if (pOleObject) 02659 IOleObject_Release(pOleObject); 02660 02661 if (((renderopt == OLERENDER_DRAW) || (renderopt == OLERENDER_FORMAT)) && 02662 SUCCEEDED(hres)) 02663 { 02664 IRunnableObject *pRunnable; 02665 IOleCache *pOleCache; 02666 HRESULT hres2; 02667 02668 hres2 = IUnknown_QueryInterface(pUnk, &IID_IRunnableObject, (void **)&pRunnable); 02669 if (SUCCEEDED(hres2)) 02670 { 02671 hres = IRunnableObject_Run(pRunnable, NULL); 02672 IRunnableObject_Release(pRunnable); 02673 } 02674 02675 if (SUCCEEDED(hres)) 02676 { 02677 hres2 = IUnknown_QueryInterface(pUnk, &IID_IOleCache, (void **)&pOleCache); 02678 if (SUCCEEDED(hres2)) 02679 { 02680 DWORD dwConnection; 02681 if (renderopt == OLERENDER_DRAW && !pFormatEtc) { 02682 FORMATETC pfe; 02683 pfe.cfFormat = 0; 02684 pfe.ptd = NULL; 02685 pfe.dwAspect = DVASPECT_CONTENT; 02686 pfe.lindex = -1; 02687 pfe.tymed = TYMED_NULL; 02688 hres = IOleCache_Cache(pOleCache, &pfe, ADVF_PRIMEFIRST, &dwConnection); 02689 } 02690 else 02691 hres = IOleCache_Cache(pOleCache, pFormatEtc, ADVF_PRIMEFIRST, &dwConnection); 02692 IOleCache_Release(pOleCache); 02693 } 02694 } 02695 } 02696 02697 if (FAILED(hres) && pUnk) 02698 { 02699 IUnknown_Release(pUnk); 02700 pUnk = NULL; 02701 } 02702 02703 *ppvObj = pUnk; 02704 02705 TRACE("-- %p\n", pUnk); 02706 return hres; 02707 } 02708 02709 /****************************************************************************** 02710 * OleGetAutoConvert [OLE32.@] 02711 */ 02712 HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew) 02713 { 02714 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0}; 02715 HKEY hkey = NULL; 02716 WCHAR buf[CHARS_IN_GUID]; 02717 LONG len; 02718 HRESULT res = S_OK; 02719 02720 res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey); 02721 if (FAILED(res)) 02722 goto done; 02723 02724 len = sizeof(buf); 02725 if (RegQueryValueW(hkey, NULL, buf, &len)) 02726 { 02727 res = REGDB_E_KEYMISSING; 02728 goto done; 02729 } 02730 res = CLSIDFromString(buf, pClsidNew); 02731 done: 02732 if (hkey) RegCloseKey(hkey); 02733 return res; 02734 } 02735 02736 /****************************************************************************** 02737 * OleSetAutoConvert [OLE32.@] 02738 */ 02739 HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew) 02740 { 02741 static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0}; 02742 HKEY hkey = NULL; 02743 WCHAR szClsidNew[CHARS_IN_GUID]; 02744 HRESULT res = S_OK; 02745 02746 TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew)); 02747 02748 res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey); 02749 if (FAILED(res)) 02750 goto done; 02751 StringFromGUID2(clsidNew, szClsidNew, CHARS_IN_GUID); 02752 if (RegSetValueW(hkey, wszAutoConvertTo, REG_SZ, szClsidNew, (strlenW(szClsidNew)+1) * sizeof(WCHAR))) 02753 { 02754 res = REGDB_E_WRITEREGDB; 02755 goto done; 02756 } 02757 02758 done: 02759 if (hkey) RegCloseKey(hkey); 02760 return res; 02761 } 02762 02763 /****************************************************************************** 02764 * OleDoAutoConvert [OLE32.@] 02765 */ 02766 HRESULT WINAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew) 02767 { 02768 FIXME("(%p,%p) : stub\n",pStg,pClsidNew); 02769 return E_NOTIMPL; 02770 } 02771 02772 /****************************************************************************** 02773 * OleIsRunning [OLE32.@] 02774 */ 02775 BOOL WINAPI OleIsRunning(LPOLEOBJECT object) 02776 { 02777 IRunnableObject *pRunnable; 02778 HRESULT hr; 02779 BOOL running; 02780 02781 TRACE("(%p)\n", object); 02782 02783 if (!object) return FALSE; 02784 02785 hr = IOleObject_QueryInterface(object, &IID_IRunnableObject, (void **)&pRunnable); 02786 if (FAILED(hr)) 02787 return TRUE; 02788 running = IRunnableObject_IsRunning(pRunnable); 02789 IRunnableObject_Release(pRunnable); 02790 return running; 02791 } 02792 02793 /*********************************************************************** 02794 * OleNoteObjectVisible [OLE32.@] 02795 */ 02796 HRESULT WINAPI OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL bVisible) 02797 { 02798 TRACE("(%p, %s)\n", pUnknown, bVisible ? "TRUE" : "FALSE"); 02799 return CoLockObjectExternal(pUnknown, bVisible, TRUE); 02800 } 02801 02802 02803 /*********************************************************************** 02804 * OLE_FreeClipDataArray [internal] 02805 * 02806 * NOTES: 02807 * frees the data associated with an array of CLIPDATAs 02808 */ 02809 static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray) 02810 { 02811 ULONG i; 02812 for (i = 0; i < count; i++) 02813 if (pClipDataArray[i].pClipData) 02814 CoTaskMemFree(pClipDataArray[i].pClipData); 02815 } 02816 02817 /*********************************************************************** 02818 * PropSysAllocString [OLE32.@] 02819 * NOTES: 02820 * Basically a copy of SysAllocStringLen. 02821 */ 02822 BSTR WINAPI PropSysAllocString(LPCOLESTR str) 02823 { 02824 DWORD bufferSize; 02825 DWORD* newBuffer; 02826 WCHAR* stringBuffer; 02827 int len; 02828 02829 if (!str) return 0; 02830 02831 len = lstrlenW(str); 02832 /* 02833 * Find the length of the buffer passed-in, in bytes. 02834 */ 02835 bufferSize = len * sizeof (WCHAR); 02836 02837 /* 02838 * Allocate a new buffer to hold the string. 02839 * Don't forget to keep an empty spot at the beginning of the 02840 * buffer for the character count and an extra character at the 02841 * end for the NULL. 02842 */ 02843 newBuffer = HeapAlloc(GetProcessHeap(), 0, 02844 bufferSize + sizeof(WCHAR) + sizeof(DWORD)); 02845 02846 /* 02847 * If the memory allocation failed, return a null pointer. 02848 */ 02849 if (newBuffer==0) 02850 return 0; 02851 02852 /* 02853 * Copy the length of the string in the placeholder. 02854 */ 02855 *newBuffer = bufferSize; 02856 02857 /* 02858 * Skip the byte count. 02859 */ 02860 newBuffer++; 02861 02862 memcpy(newBuffer, str, bufferSize); 02863 02864 /* 02865 * Make sure that there is a nul character at the end of the 02866 * string. 02867 */ 02868 stringBuffer = (WCHAR*)newBuffer; 02869 stringBuffer[len] = '\0'; 02870 02871 return stringBuffer; 02872 } 02873 02874 /*********************************************************************** 02875 * PropSysFreeString [OLE32.@] 02876 * NOTES 02877 * Copy of SysFreeString. 02878 */ 02879 void WINAPI PropSysFreeString(LPOLESTR str) 02880 { 02881 DWORD* bufferPointer; 02882 02883 /* NULL is a valid parameter */ 02884 if(!str) return; 02885 02886 /* 02887 * We have to be careful when we free a BSTR pointer, it points to 02888 * the beginning of the string but it skips the byte count contained 02889 * before the string. 02890 */ 02891 bufferPointer = (DWORD*)str; 02892 02893 bufferPointer--; 02894 02895 /* 02896 * Free the memory from its "real" origin. 02897 */ 02898 HeapFree(GetProcessHeap(), 0, bufferPointer); 02899 } 02900 02901 /****************************************************************************** 02902 * Check if a PROPVARIANT's type is valid. 02903 */ 02904 static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt) 02905 { 02906 switch (vt) 02907 { 02908 case VT_EMPTY: 02909 case VT_NULL: 02910 case VT_I2: 02911 case VT_I4: 02912 case VT_R4: 02913 case VT_R8: 02914 case VT_CY: 02915 case VT_DATE: 02916 case VT_BSTR: 02917 case VT_ERROR: 02918 case VT_BOOL: 02919 case VT_DECIMAL: 02920 case VT_UI1: 02921 case VT_UI2: 02922 case VT_UI4: 02923 case VT_I8: 02924 case VT_UI8: 02925 case VT_LPSTR: 02926 case VT_LPWSTR: 02927 case VT_FILETIME: 02928 case VT_BLOB: 02929 case VT_STREAM: 02930 case VT_STORAGE: 02931 case VT_STREAMED_OBJECT: 02932 case VT_STORED_OBJECT: 02933 case VT_BLOB_OBJECT: 02934 case VT_CF: 02935 case VT_CLSID: 02936 case VT_I2|VT_VECTOR: 02937 case VT_I4|VT_VECTOR: 02938 case VT_R4|VT_VECTOR: 02939 case VT_R8|VT_VECTOR: 02940 case VT_CY|VT_VECTOR: 02941 case VT_DATE|VT_VECTOR: 02942 case VT_BSTR|VT_VECTOR: 02943 case VT_ERROR|VT_VECTOR: 02944 case VT_BOOL|VT_VECTOR: 02945 case VT_VARIANT|VT_VECTOR: 02946 case VT_UI1|VT_VECTOR: 02947 case VT_UI2|VT_VECTOR: 02948 case VT_UI4|VT_VECTOR: 02949 case VT_I8|VT_VECTOR: 02950 case VT_UI8|VT_VECTOR: 02951 case VT_LPSTR|VT_VECTOR: 02952 case VT_LPWSTR|VT_VECTOR: 02953 case VT_FILETIME|VT_VECTOR: 02954 case VT_CF|VT_VECTOR: 02955 case VT_CLSID|VT_VECTOR: 02956 return S_OK; 02957 } 02958 WARN("Bad type %d\n", vt); 02959 return STG_E_INVALIDPARAMETER; 02960 } 02961 02962 /*********************************************************************** 02963 * PropVariantClear [OLE32.@] 02964 */ 02965 HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */ 02966 { 02967 HRESULT hr; 02968 02969 TRACE("(%p)\n", pvar); 02970 02971 if (!pvar) 02972 return S_OK; 02973 02974 hr = PROPVARIANT_ValidateType(pvar->vt); 02975 if (FAILED(hr)) 02976 return hr; 02977 02978 switch(pvar->vt) 02979 { 02980 case VT_EMPTY: 02981 case VT_NULL: 02982 case VT_I2: 02983 case VT_I4: 02984 case VT_R4: 02985 case VT_R8: 02986 case VT_CY: 02987 case VT_DATE: 02988 case VT_ERROR: 02989 case VT_BOOL: 02990 case VT_DECIMAL: 02991 case VT_UI1: 02992 case VT_UI2: 02993 case VT_UI4: 02994 case VT_I8: 02995 case VT_UI8: 02996 case VT_FILETIME: 02997 break; 02998 case VT_STREAM: 02999 case VT_STREAMED_OBJECT: 03000 case VT_STORAGE: 03001 case VT_STORED_OBJECT: 03002 if (pvar->u.pStream) 03003 IUnknown_Release(pvar->u.pStream); 03004 break; 03005 case VT_CLSID: 03006 case VT_LPSTR: 03007 case VT_LPWSTR: 03008 /* pick an arbitrary typed pointer - we don't care about the type 03009 * as we are just freeing it */ 03010 CoTaskMemFree(pvar->u.puuid); 03011 break; 03012 case VT_BLOB: 03013 case VT_BLOB_OBJECT: 03014 CoTaskMemFree(pvar->u.blob.pBlobData); 03015 break; 03016 case VT_BSTR: 03017 if (pvar->u.bstrVal) 03018 PropSysFreeString(pvar->u.bstrVal); 03019 break; 03020 case VT_CF: 03021 if (pvar->u.pclipdata) 03022 { 03023 OLE_FreeClipDataArray(1, pvar->u.pclipdata); 03024 CoTaskMemFree(pvar->u.pclipdata); 03025 } 03026 break; 03027 default: 03028 if (pvar->vt & VT_VECTOR) 03029 { 03030 ULONG i; 03031 03032 switch (pvar->vt & ~VT_VECTOR) 03033 { 03034 case VT_VARIANT: 03035 FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems); 03036 break; 03037 case VT_CF: 03038 OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems); 03039 break; 03040 case VT_BSTR: 03041 for (i = 0; i < pvar->u.cabstr.cElems; i++) 03042 PropSysFreeString(pvar->u.cabstr.pElems[i]); 03043 break; 03044 case VT_LPSTR: 03045 for (i = 0; i < pvar->u.calpstr.cElems; i++) 03046 CoTaskMemFree(pvar->u.calpstr.pElems[i]); 03047 break; 03048 case VT_LPWSTR: 03049 for (i = 0; i < pvar->u.calpwstr.cElems; i++) 03050 CoTaskMemFree(pvar->u.calpwstr.pElems[i]); 03051 break; 03052 } 03053 if (pvar->vt & ~VT_VECTOR) 03054 { 03055 /* pick an arbitrary VT_VECTOR structure - they all have the same 03056 * memory layout */ 03057 CoTaskMemFree(pvar->u.capropvar.pElems); 03058 } 03059 } 03060 else 03061 WARN("Invalid/unsupported type %d\n", pvar->vt); 03062 } 03063 03064 ZeroMemory(pvar, sizeof(*pvar)); 03065 03066 return S_OK; 03067 } 03068 03069 /*********************************************************************** 03070 * PropVariantCopy [OLE32.@] 03071 */ 03072 HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, /* [out] */ 03073 const PROPVARIANT *pvarSrc) /* [in] */ 03074 { 03075 ULONG len; 03076 HRESULT hr; 03077 03078 TRACE("(%p, %p vt %04x)\n", pvarDest, pvarSrc, pvarSrc->vt); 03079 03080 hr = PROPVARIANT_ValidateType(pvarSrc->vt); 03081 if (FAILED(hr)) 03082 return hr; 03083 03084 /* this will deal with most cases */ 03085 *pvarDest = *pvarSrc; 03086 03087 switch(pvarSrc->vt) 03088 { 03089 case VT_EMPTY: 03090 case VT_NULL: 03091 case VT_I1: 03092 case VT_UI1: 03093 case VT_I2: 03094 case VT_UI2: 03095 case VT_BOOL: 03096 case VT_DECIMAL: 03097 case VT_I4: 03098 case VT_UI4: 03099 case VT_R4: 03100 case VT_ERROR: 03101 case VT_I8: 03102 case VT_UI8: 03103 case VT_R8: 03104 case VT_CY: 03105 case VT_DATE: 03106 case VT_FILETIME: 03107 break; 03108 case VT_STREAM: 03109 case VT_STREAMED_OBJECT: 03110 case VT_STORAGE: 03111 case VT_STORED_OBJECT: 03112 IUnknown_AddRef((LPUNKNOWN)pvarDest->u.pStream); 03113 break; 03114 case VT_CLSID: 03115 pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID)); 03116 *pvarDest->u.puuid = *pvarSrc->u.puuid; 03117 break; 03118 case VT_LPSTR: 03119 len = strlen(pvarSrc->u.pszVal); 03120 pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR)); 03121 CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR)); 03122 break; 03123 case VT_LPWSTR: 03124 len = lstrlenW(pvarSrc->u.pwszVal); 03125 pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR)); 03126 CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR)); 03127 break; 03128 case VT_BLOB: 03129 case VT_BLOB_OBJECT: 03130 if (pvarSrc->u.blob.pBlobData) 03131 { 03132 len = pvarSrc->u.blob.cbSize; 03133 pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len); 03134 CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len); 03135 } 03136 break; 03137 case VT_BSTR: 03138 pvarDest->u.bstrVal = PropSysAllocString(pvarSrc->u.bstrVal); 03139 break; 03140 case VT_CF: 03141 if (pvarSrc->u.pclipdata) 03142 { 03143 len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt); 03144 pvarDest->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA)); 03145 pvarDest->u.pclipdata->cbSize = pvarSrc->u.pclipdata->cbSize; 03146 pvarDest->u.pclipdata->ulClipFmt = pvarSrc->u.pclipdata->ulClipFmt; 03147 pvarDest->u.pclipdata->pClipData = CoTaskMemAlloc(len); 03148 CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len); 03149 } 03150 break; 03151 default: 03152 if (pvarSrc->vt & VT_VECTOR) 03153 { 03154 int elemSize; 03155 ULONG i; 03156 03157 switch(pvarSrc->vt & ~VT_VECTOR) 03158 { 03159 case VT_I1: elemSize = sizeof(pvarSrc->u.cVal); break; 03160 case VT_UI1: elemSize = sizeof(pvarSrc->u.bVal); break; 03161 case VT_I2: elemSize = sizeof(pvarSrc->u.iVal); break; 03162 case VT_UI2: elemSize = sizeof(pvarSrc->u.uiVal); break; 03163 case VT_BOOL: elemSize = sizeof(pvarSrc->u.boolVal); break; 03164 case VT_I4: elemSize = sizeof(pvarSrc->u.lVal); break; 03165 case VT_UI4: elemSize = sizeof(pvarSrc->u.ulVal); break; 03166 case VT_R4: elemSize = sizeof(pvarSrc->u.fltVal); break; 03167 case VT_R8: elemSize = sizeof(pvarSrc->u.dblVal); break; 03168 case VT_ERROR: elemSize = sizeof(pvarSrc->u.scode); break; 03169 case VT_I8: elemSize = sizeof(pvarSrc->u.hVal); break; 03170 case VT_UI8: elemSize = sizeof(pvarSrc->u.uhVal); break; 03171 case VT_CY: elemSize = sizeof(pvarSrc->u.cyVal); break; 03172 case VT_DATE: elemSize = sizeof(pvarSrc->u.date); break; 03173 case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break; 03174 case VT_CLSID: elemSize = sizeof(*pvarSrc->u.puuid); break; 03175 case VT_CF: elemSize = sizeof(*pvarSrc->u.pclipdata); break; 03176 case VT_BSTR: elemSize = sizeof(pvarSrc->u.bstrVal); break; 03177 case VT_LPSTR: elemSize = sizeof(pvarSrc->u.pszVal); break; 03178 case VT_LPWSTR: elemSize = sizeof(pvarSrc->u.pwszVal); break; 03179 case VT_VARIANT: elemSize = sizeof(*pvarSrc->u.pvarVal); break; 03180 03181 default: 03182 FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR); 03183 return E_INVALIDARG; 03184 } 03185 len = pvarSrc->u.capropvar.cElems; 03186 pvarDest->u.capropvar.pElems = CoTaskMemAlloc(len * elemSize); 03187 if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT)) 03188 { 03189 for (i = 0; i < len; i++) 03190 PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]); 03191 } 03192 else if (pvarSrc->vt == (VT_VECTOR | VT_CF)) 03193 { 03194 FIXME("Copy clipformats\n"); 03195 } 03196 else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR)) 03197 { 03198 for (i = 0; i < len; i++) 03199 pvarDest->u.cabstr.pElems[i] = PropSysAllocString(pvarSrc->u.cabstr.pElems[i]); 03200 } 03201 else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR)) 03202 { 03203 size_t strLen; 03204 for (i = 0; i < len; i++) 03205 { 03206 strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1; 03207 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen); 03208 memcpy(pvarDest->u.calpstr.pElems[i], 03209 pvarSrc->u.calpstr.pElems[i], strLen); 03210 } 03211 } 03212 else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR)) 03213 { 03214 size_t strLen; 03215 for (i = 0; i < len; i++) 03216 { 03217 strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) * 03218 sizeof(WCHAR); 03219 pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen); 03220 memcpy(pvarDest->u.calpstr.pElems[i], 03221 pvarSrc->u.calpstr.pElems[i], strLen); 03222 } 03223 } 03224 else 03225 CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize); 03226 } 03227 else 03228 WARN("Invalid/unsupported type %d\n", pvarSrc->vt); 03229 } 03230 03231 return S_OK; 03232 } 03233 03234 /*********************************************************************** 03235 * FreePropVariantArray [OLE32.@] 03236 */ 03237 HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */ 03238 PROPVARIANT *rgvars) /* [in/out] */ 03239 { 03240 ULONG i; 03241 03242 TRACE("(%u, %p)\n", cVariants, rgvars); 03243 03244 if (!rgvars) 03245 return E_INVALIDARG; 03246 03247 for(i = 0; i < cVariants; i++) 03248 PropVariantClear(&rgvars[i]); 03249 03250 return S_OK; 03251 } 03252 03253 /****************************************************************************** 03254 * DllDebugObjectRPCHook (OLE32.@) 03255 * turns on and off internal debugging, pointer is only used on macintosh 03256 */ 03257 03258 BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy) 03259 { 03260 FIXME("stub\n"); 03261 return TRUE; 03262 } Generated on Sun May 27 2012 04:25:39 for ReactOS by
1.7.6.1
|