| /* | |
| * OLE2 library | |
| * | |
| * Copyright 1995 Martin von Loewis | |
| * Copyright 1999 Francis Beaudet | |
| * Copyright 1999 Noel Borthwick | |
| * Copyright 1999, 2000 Marcus Meissner | |
| * Copyright 2005 Juan Lang | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #include "config.h" | |
| #include <assert.h> | |
| #include <stdlib.h> | |
| #include <stdarg.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #define COBJMACROS | |
| #define NONAMELESSUNION | |
| #define NONAMELESSSTRUCT | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winerror.h" | |
| #include "wingdi.h" | |
| #include "winuser.h" | |
| #include "winnls.h" | |
| #include "winreg.h" | |
| #include "ole2.h" | |
| #include "ole2ver.h" | |
| #include "wine/unicode.h" | |
| #include "compobj_private.h" | |
| #include "wine/list.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(ole); | |
| WINE_DECLARE_DEBUG_CHANNEL(accel); | |
| /****************************************************************************** | |
| * These are static/global variables and internal data structures that the | |
| * OLE module uses to maintain it's state. | |
| */ | |
| typedef struct tagDropTargetNode | |
| { | |
| HWND hwndTarget; | |
| IDropTarget* dropTarget; | |
| struct list entry; | |
| } DropTargetNode; | |
| typedef struct tagTrackerWindowInfo | |
| { | |
| IDataObject* dataObject; | |
| IDropSource* dropSource; | |
| DWORD dwOKEffect; | |
| DWORD* pdwEffect; | |
| BOOL trackingDone; | |
| HRESULT returnValue; | |
| BOOL escPressed; | |
| HWND curTargetHWND; /* window the mouse is hovering over */ | |
| HWND curDragTargetHWND; /* might be a ancestor of curTargetHWND */ | |
| IDropTarget* curDragTarget; | |
| POINTL curMousePos; /* current position of the mouse in screen coordinates */ | |
| DWORD dwKeyState; /* current state of the shift and ctrl keys and the mouse buttons */ | |
| } TrackerWindowInfo; | |
| typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */ | |
| { | |
| HWND hwndFrame; /* The containers frame window */ | |
| HWND hwndActiveObject; /* The active objects window */ | |
| OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */ | |
| HMENU hmenuCombined; /* The combined menu */ | |
| BOOL bIsServerItem; /* True if the currently open popup belongs to the server */ | |
| } OleMenuDescriptor; | |
| typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */ | |
| { | |
| DWORD tid; /* Thread Id */ | |
| HANDLE hHeap; /* Heap this is allocated from */ | |
| HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */ | |
| HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */ | |
| struct tagOleMenuHookItem *next; | |
| } OleMenuHookItem; | |
| static OleMenuHookItem *hook_list; | |
| /* | |
| * This is the lock count on the OLE library. It is controlled by the | |
| * OLEInitialize/OLEUninitialize methods. | |
| */ | |
| static LONG OLE_moduleLockCount = 0; | |
| /* | |
| * Name of our registered window class. | |
| */ | |
| static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32"; | |
| /* | |
| * This is the head of the Drop target container. | |
| */ | |
| static struct list targetListHead = LIST_INIT(targetListHead); | |
| /****************************************************************************** | |
| * These are the prototypes of miscellaneous utility methods | |
| */ | |
| static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue); | |
| /****************************************************************************** | |
| * These are the prototypes of the utility methods used to manage a shared menu | |
| */ | |
| static void OLEMenu_Initialize(void); | |
| static void OLEMenu_UnInitialize(void); | |
| static BOOL OLEMenu_InstallHooks( DWORD tid ); | |
| static BOOL OLEMenu_UnInstallHooks( DWORD tid ); | |
| static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid ); | |
| static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos ); | |
| static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor ); | |
| static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam); | |
| static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam); | |
| /****************************************************************************** | |
| * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c) | |
| */ | |
| extern void OLEClipbrd_UnInitialize(void); | |
| extern void OLEClipbrd_Initialize(void); | |
| /****************************************************************************** | |
| * These are the prototypes of the utility methods used for OLE Drag n Drop | |
| */ | |
| static void OLEDD_Initialize(void); | |
| static DropTargetNode* OLEDD_FindDropTarget( | |
| HWND hwndOfTarget); | |
| static void OLEDD_FreeDropTarget(DropTargetNode*, BOOL); | |
| static LRESULT WINAPI OLEDD_DragTrackerWindowProc( | |
| HWND hwnd, | |
| UINT uMsg, | |
| WPARAM wParam, | |
| LPARAM lParam); | |
| static void OLEDD_TrackMouseMove( | |
| TrackerWindowInfo* trackerInfo); | |
| static void OLEDD_TrackStateChange( | |
| TrackerWindowInfo* trackerInfo); | |
| static DWORD OLEDD_GetButtonState(void); | |
| /****************************************************************************** | |
| * OleBuildVersion [OLE32.@] | |
| */ | |
| DWORD WINAPI OleBuildVersion(void) | |
| { | |
| TRACE("Returning version %d, build %d.\n", rmm, rup); | |
| return (rmm<<16)+rup; | |
| } | |
| /*********************************************************************** | |
| * OleInitialize (OLE32.@) | |
| */ | |
| HRESULT WINAPI OleInitialize(LPVOID reserved) | |
| { | |
| HRESULT hr; | |
| TRACE("(%p)\n", reserved); | |
| /* | |
| * The first duty of the OleInitialize is to initialize the COM libraries. | |
| */ | |
| hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); | |
| /* | |
| * If the CoInitializeEx call failed, the OLE libraries can't be | |
| * initialized. | |
| */ | |
| if (FAILED(hr)) | |
| return hr; | |
| if (!COM_CurrentInfo()->ole_inits) | |
| hr = S_OK; | |
| /* | |
| * Then, it has to initialize the OLE specific modules. | |
| * This includes: | |
| * Clipboard | |
| * Drag and Drop | |
| * Object linking and Embedding | |
| * In-place activation | |
| */ | |
| if (!COM_CurrentInfo()->ole_inits++ && | |
| InterlockedIncrement(&OLE_moduleLockCount) == 1) | |
| { | |
| /* | |
| * Initialize the libraries. | |
| */ | |
| TRACE("() - Initializing the OLE libraries\n"); | |
| /* | |
| * OLE Clipboard | |
| */ | |
| OLEClipbrd_Initialize(); | |
| /* | |
| * Drag and Drop | |
| */ | |
| OLEDD_Initialize(); | |
| /* | |
| * OLE shared menu | |
| */ | |
| OLEMenu_Initialize(); | |
| } | |
| return hr; | |
| } | |
| /****************************************************************************** | |
| * OleUninitialize [OLE32.@] | |
| */ | |
| void WINAPI OleUninitialize(void) | |
| { | |
| TRACE("()\n"); | |
| /* | |
| * If we hit the bottom of the lock stack, free the libraries. | |
| */ | |
| if (!--COM_CurrentInfo()->ole_inits && !InterlockedDecrement(&OLE_moduleLockCount)) | |
| { | |
| /* | |
| * Actually free the libraries. | |
| */ | |
| TRACE("() - Freeing the last reference count\n"); | |
| /* | |
| * OLE Clipboard | |
| */ | |
| OLEClipbrd_UnInitialize(); | |
| /* | |
| * OLE shared menu | |
| */ | |
| OLEMenu_UnInitialize(); | |
| } | |
| /* | |
| * Then, uninitialize the COM libraries. | |
| */ | |
| CoUninitialize(); | |
| } | |
| /****************************************************************************** | |
| * OleInitializeWOW [OLE32.@] | |
| */ | |
| HRESULT WINAPI OleInitializeWOW(DWORD x, DWORD y) { | |
| FIXME("(0x%08x, 0x%08x),stub!\n",x, y); | |
| return 0; | |
| } | |
| /*********************************************************************** | |
| * RegisterDragDrop (OLE32.@) | |
| */ | |
| HRESULT WINAPI RegisterDragDrop( | |
| HWND hwnd, | |
| LPDROPTARGET pDropTarget) | |
| { | |
| DropTargetNode* dropTargetInfo; | |
| TRACE("(%p,%p)\n", hwnd, pDropTarget); | |
| if (!COM_CurrentApt()) | |
| { | |
| ERR("COM not initialized\n"); | |
| return E_OUTOFMEMORY; | |
| } | |
| if (!pDropTarget) | |
| return E_INVALIDARG; | |
| if (!IsWindow(hwnd)) | |
| { | |
| ERR("invalid hwnd %p\n", hwnd); | |
| return DRAGDROP_E_INVALIDHWND; | |
| } | |
| /* | |
| * First, check if the window is already registered. | |
| */ | |
| dropTargetInfo = OLEDD_FindDropTarget(hwnd); | |
| if (dropTargetInfo!=NULL) | |
| return DRAGDROP_E_ALREADYREGISTERED; | |
| /* | |
| * If it's not there, we can add it. We first create a node for it. | |
| */ | |
| dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode)); | |
| if (dropTargetInfo==NULL) | |
| return E_OUTOFMEMORY; | |
| dropTargetInfo->hwndTarget = hwnd; | |
| /* | |
| * Don't forget that this is an interface pointer, need to nail it down since | |
| * we keep a copy of it. | |
| */ | |
| IDropTarget_AddRef(pDropTarget); | |
| dropTargetInfo->dropTarget = pDropTarget; | |
| list_add_tail(&targetListHead, &dropTargetInfo->entry); | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * RevokeDragDrop (OLE32.@) | |
| */ | |
| HRESULT WINAPI RevokeDragDrop( | |
| HWND hwnd) | |
| { | |
| DropTargetNode* dropTargetInfo; | |
| TRACE("(%p)\n", hwnd); | |
| if (!IsWindow(hwnd)) | |
| { | |
| ERR("invalid hwnd %p\n", hwnd); | |
| return DRAGDROP_E_INVALIDHWND; | |
| } | |
| /* | |
| * First, check if the window is already registered. | |
| */ | |
| dropTargetInfo = OLEDD_FindDropTarget(hwnd); | |
| /* | |
| * If it ain't in there, it's an error. | |
| */ | |
| if (dropTargetInfo==NULL) | |
| return DRAGDROP_E_NOTREGISTERED; | |
| OLEDD_FreeDropTarget(dropTargetInfo, TRUE); | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * OleRegGetUserType (OLE32.@) | |
| * | |
| * This implementation of OleRegGetUserType ignores the dwFormOfType | |
| * parameter and always returns the full name of the object. This is | |
| * not too bad since this is the case for many objects because of the | |
| * way they are registered. | |
| */ | |
| HRESULT WINAPI OleRegGetUserType( | |
| REFCLSID clsid, | |
| DWORD dwFormOfType, | |
| LPOLESTR* pszUserType) | |
| { | |
| char keyName[60]; | |
| DWORD dwKeyType; | |
| DWORD cbData; | |
| HKEY clsidKey; | |
| LONG hres; | |
| LPSTR buffer; | |
| HRESULT retVal; | |
| /* | |
| * Initialize the out parameter. | |
| */ | |
| *pszUserType = NULL; | |
| /* | |
| * Build the key name we're looking for | |
| */ | |
| sprintf( keyName, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\", | |
| clsid->Data1, clsid->Data2, clsid->Data3, | |
| clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], | |
| clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); | |
| TRACE("(%s, %d, %p)\n", keyName, dwFormOfType, pszUserType); | |
| /* | |
| * Open the class id Key | |
| */ | |
| hres = RegOpenKeyA(HKEY_CLASSES_ROOT, | |
| keyName, | |
| &clsidKey); | |
| if (hres != ERROR_SUCCESS) | |
| return REGDB_E_CLASSNOTREG; | |
| /* | |
| * Retrieve the size of the name string. | |
| */ | |
| cbData = 0; | |
| hres = RegQueryValueExA(clsidKey, | |
| "", | |
| NULL, | |
| &dwKeyType, | |
| NULL, | |
| &cbData); | |
| if (hres!=ERROR_SUCCESS) | |
| { | |
| RegCloseKey(clsidKey); | |
| return REGDB_E_READREGDB; | |
| } | |
| /* | |
| * Allocate a buffer for the registry value. | |
| */ | |
| *pszUserType = CoTaskMemAlloc(cbData*2); | |
| if (*pszUserType==NULL) | |
| { | |
| RegCloseKey(clsidKey); | |
| return E_OUTOFMEMORY; | |
| } | |
| buffer = HeapAlloc(GetProcessHeap(), 0, cbData); | |
| if (buffer == NULL) | |
| { | |
| RegCloseKey(clsidKey); | |
| CoTaskMemFree(*pszUserType); | |
| *pszUserType=NULL; | |
| return E_OUTOFMEMORY; | |
| } | |
| hres = RegQueryValueExA(clsidKey, | |
| "", | |
| NULL, | |
| &dwKeyType, | |
| (LPBYTE) buffer, | |
| &cbData); | |
| RegCloseKey(clsidKey); | |
| if (hres!=ERROR_SUCCESS) | |
| { | |
| CoTaskMemFree(*pszUserType); | |
| *pszUserType=NULL; | |
| retVal = REGDB_E_READREGDB; | |
| } | |
| else | |
| { | |
| MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ ); | |
| retVal = S_OK; | |
| } | |
| HeapFree(GetProcessHeap(), 0, buffer); | |
| return retVal; | |
| } | |
| /*********************************************************************** | |
| * DoDragDrop [OLE32.@] | |
| */ | |
| HRESULT WINAPI DoDragDrop ( | |
| IDataObject *pDataObject, /* [in] ptr to the data obj */ | |
| IDropSource* pDropSource, /* [in] ptr to the source obj */ | |
| DWORD dwOKEffect, /* [in] effects allowed by the source */ | |
| DWORD *pdwEffect) /* [out] ptr to effects of the source */ | |
| { | |
| TrackerWindowInfo trackerInfo; | |
| HWND hwndTrackWindow; | |
| MSG msg; | |
| TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource); | |
| /* | |
| * Setup the drag n drop tracking window. | |
| */ | |
| if (!IsValidInterface((LPUNKNOWN)pDropSource)) | |
| return E_INVALIDARG; | |
| trackerInfo.dataObject = pDataObject; | |
| trackerInfo.dropSource = pDropSource; | |
| trackerInfo.dwOKEffect = dwOKEffect; | |
| trackerInfo.pdwEffect = pdwEffect; | |
| trackerInfo.trackingDone = FALSE; | |
| trackerInfo.escPressed = FALSE; | |
| trackerInfo.curDragTargetHWND = 0; | |
| trackerInfo.curTargetHWND = 0; | |
| trackerInfo.curDragTarget = 0; | |
| hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS, "TrackerWindow", | |
| WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, | |
| CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0, | |
| &trackerInfo); | |
| if (hwndTrackWindow!=0) | |
| { | |
| /* | |
| * Capture the mouse input | |
| */ | |
| SetCapture(hwndTrackWindow); | |
| msg.message = 0; | |
| /* | |
| * Pump messages. All mouse input should go to the capture window. | |
| */ | |
| while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) ) | |
| { | |
| trackerInfo.curMousePos.x = msg.pt.x; | |
| trackerInfo.curMousePos.y = msg.pt.y; | |
| trackerInfo.dwKeyState = OLEDD_GetButtonState(); | |
| if ( (msg.message >= WM_KEYFIRST) && | |
| (msg.message <= WM_KEYLAST) ) | |
| { | |
| /* | |
| * When keyboard messages are sent to windows on this thread, we | |
| * want to ignore notify the drop source that the state changed. | |
| * in the case of the Escape key, we also notify the drop source | |
| * we give it a special meaning. | |
| */ | |
| if ( (msg.message==WM_KEYDOWN) && | |
| (msg.wParam==VK_ESCAPE) ) | |
| { | |
| trackerInfo.escPressed = TRUE; | |
| } | |
| /* | |
| * Notify the drop source. | |
| */ | |
| OLEDD_TrackStateChange(&trackerInfo); | |
| } | |
| else | |
| { | |
| /* | |
| * Dispatch the messages only when it's not a keyboard message. | |
| */ | |
| DispatchMessageA(&msg); | |
| } | |
| } | |
| /* re-post the quit message to outer message loop */ | |
| if (msg.message == WM_QUIT) | |
| PostQuitMessage(msg.wParam); | |
| /* | |
| * Destroy the temporary window. | |
| */ | |
| DestroyWindow(hwndTrackWindow); | |
| return trackerInfo.returnValue; | |
| } | |
| return E_FAIL; | |
| } | |
| /*********************************************************************** | |
| * OleQueryLinkFromData [OLE32.@] | |
| */ | |
| HRESULT WINAPI OleQueryLinkFromData( | |
| IDataObject* pSrcDataObject) | |
| { | |
| FIXME("(%p),stub!\n", pSrcDataObject); | |
| return S_FALSE; | |
| } | |
| /*********************************************************************** | |
| * OleRegGetMiscStatus [OLE32.@] | |
| */ | |
| HRESULT WINAPI OleRegGetMiscStatus( | |
| REFCLSID clsid, | |
| DWORD dwAspect, | |
| DWORD* pdwStatus) | |
| { | |
| char keyName[60]; | |
| HKEY clsidKey; | |
| HKEY miscStatusKey; | |
| HKEY aspectKey; | |
| LONG result; | |
| /* | |
| * Initialize the out parameter. | |
| */ | |
| *pdwStatus = 0; | |
| /* | |
| * Build the key name we're looking for | |
| */ | |
| sprintf( keyName, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\", | |
| clsid->Data1, clsid->Data2, clsid->Data3, | |
| clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], | |
| clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); | |
| TRACE("(%s, %d, %p)\n", keyName, dwAspect, pdwStatus); | |
| /* | |
| * Open the class id Key | |
| */ | |
| result = RegOpenKeyA(HKEY_CLASSES_ROOT, | |
| keyName, | |
| &clsidKey); | |
| if (result != ERROR_SUCCESS) | |
| return REGDB_E_CLASSNOTREG; | |
| /* | |
| * Get the MiscStatus | |
| */ | |
| result = RegOpenKeyA(clsidKey, | |
| "MiscStatus", | |
| &miscStatusKey); | |
| if (result != ERROR_SUCCESS) | |
| { | |
| RegCloseKey(clsidKey); | |
| return REGDB_E_READREGDB; | |
| } | |
| /* | |
| * Read the default value | |
| */ | |
| OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus); | |
| /* | |
| * Open the key specific to the requested aspect. | |
| */ | |
| sprintf(keyName, "%d", dwAspect); | |
| result = RegOpenKeyA(miscStatusKey, | |
| keyName, | |
| &aspectKey); | |
| if (result == ERROR_SUCCESS) | |
| { | |
| OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus); | |
| RegCloseKey(aspectKey); | |
| } | |
| /* | |
| * Cleanup | |
| */ | |
| RegCloseKey(miscStatusKey); | |
| RegCloseKey(clsidKey); | |
| return S_OK; | |
| } | |
| static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum); | |
| typedef struct | |
| { | |
| const IEnumOLEVERBVtbl *lpvtbl; | |
| LONG ref; | |
| HKEY hkeyVerb; | |
| ULONG index; | |
| } EnumOLEVERB; | |
| static HRESULT WINAPI EnumOLEVERB_QueryInterface( | |
| IEnumOLEVERB *iface, REFIID riid, void **ppv) | |
| { | |
| TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); | |
| if (IsEqualIID(riid, &IID_IUnknown) || | |
| IsEqualIID(riid, &IID_IEnumOLEVERB)) | |
| { | |
| IUnknown_AddRef(iface); | |
| *ppv = iface; | |
| return S_OK; | |
| } | |
| return E_NOINTERFACE; | |
| } | |
| static ULONG WINAPI EnumOLEVERB_AddRef( | |
| IEnumOLEVERB *iface) | |
| { | |
| EnumOLEVERB *This = (EnumOLEVERB *)iface; | |
| TRACE("()\n"); | |
| return InterlockedIncrement(&This->ref); | |
| } | |
| static ULONG WINAPI EnumOLEVERB_Release( | |
| IEnumOLEVERB *iface) | |
| { | |
| EnumOLEVERB *This = (EnumOLEVERB *)iface; | |
| LONG refs = InterlockedDecrement(&This->ref); | |
| TRACE("()\n"); | |
| if (!refs) | |
| { | |
| RegCloseKey(This->hkeyVerb); | |
| HeapFree(GetProcessHeap(), 0, This); | |
| } | |
| return refs; | |
| } | |
| static HRESULT WINAPI EnumOLEVERB_Next( | |
| IEnumOLEVERB *iface, ULONG celt, LPOLEVERB rgelt, | |
| ULONG *pceltFetched) | |
| { | |
| EnumOLEVERB *This = (EnumOLEVERB *)iface; | |
| HRESULT hr = S_OK; | |
| TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched); | |
| if (pceltFetched) | |
| *pceltFetched = 0; | |
| for (; celt; celt--, rgelt++) | |
| { | |
| WCHAR wszSubKey[20]; | |
| LONG cbData; | |
| LPWSTR pwszOLEVERB; | |
| LPWSTR pwszMenuFlags; | |
| LPWSTR pwszAttribs; | |
| LONG res = RegEnumKeyW(This->hkeyVerb, This->index, wszSubKey, sizeof(wszSubKey)/sizeof(wszSubKey[0])); | |
| if (res == ERROR_NO_MORE_ITEMS) | |
| { | |
| hr = S_FALSE; | |
| break; | |
| } | |
| else if (res != ERROR_SUCCESS) | |
| { | |
| ERR("RegEnumKeyW failed with error %d\n", res); | |
| hr = REGDB_E_READREGDB; | |
| break; | |
| } | |
| res = RegQueryValueW(This->hkeyVerb, wszSubKey, NULL, &cbData); | |
| if (res != ERROR_SUCCESS) | |
| { | |
| ERR("RegQueryValueW failed with error %d\n", res); | |
| hr = REGDB_E_READREGDB; | |
| break; | |
| } | |
| pwszOLEVERB = CoTaskMemAlloc(cbData); | |
| if (!pwszOLEVERB) | |
| { | |
| hr = E_OUTOFMEMORY; | |
| break; | |
| } | |
| res = RegQueryValueW(This->hkeyVerb, wszSubKey, pwszOLEVERB, &cbData); | |
| if (res != ERROR_SUCCESS) | |
| { | |
| ERR("RegQueryValueW failed with error %d\n", res); | |
| hr = REGDB_E_READREGDB; | |
| CoTaskMemFree(pwszOLEVERB); | |
| break; | |
| } | |
| TRACE("verb string: %s\n", debugstr_w(pwszOLEVERB)); | |
| pwszMenuFlags = strchrW(pwszOLEVERB, ','); | |
| if (!pwszMenuFlags) | |
| { | |
| hr = OLEOBJ_E_INVALIDVERB; | |
| CoTaskMemFree(pwszOLEVERB); | |
| break; | |
| } | |
| /* nul terminate the name string and advance to first character */ | |
| *pwszMenuFlags = '\0'; | |
| pwszMenuFlags++; | |
| pwszAttribs = strchrW(pwszMenuFlags, ','); | |
| if (!pwszAttribs) | |
| { | |
| hr = OLEOBJ_E_INVALIDVERB; | |
| CoTaskMemFree(pwszOLEVERB); | |
| break; | |
| } | |
| /* nul terminate the menu string and advance to first character */ | |
| *pwszAttribs = '\0'; | |
| pwszAttribs++; | |
| /* fill out structure for this verb */ | |
| rgelt->lVerb = atolW(wszSubKey); | |
| rgelt->lpszVerbName = pwszOLEVERB; /* user should free */ | |
| rgelt->fuFlags = atolW(pwszMenuFlags); | |
| rgelt->grfAttribs = atolW(pwszAttribs); | |
| if (pceltFetched) | |
| (*pceltFetched)++; | |
| This->index++; | |
| } | |
| return hr; | |
| } | |
| static HRESULT WINAPI EnumOLEVERB_Skip( | |
| IEnumOLEVERB *iface, ULONG celt) | |
| { | |
| EnumOLEVERB *This = (EnumOLEVERB *)iface; | |
| TRACE("(%d)\n", celt); | |
| This->index += celt; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI EnumOLEVERB_Reset( | |
| IEnumOLEVERB *iface) | |
| { | |
| EnumOLEVERB *This = (EnumOLEVERB *)iface; | |
| TRACE("()\n"); | |
| This->index = 0; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI EnumOLEVERB_Clone( | |
| IEnumOLEVERB *iface, | |
| IEnumOLEVERB **ppenum) | |
| { | |
| EnumOLEVERB *This = (EnumOLEVERB *)iface; | |
| HKEY hkeyVerb; | |
| TRACE("(%p)\n", ppenum); | |
| if (!DuplicateHandle(GetCurrentProcess(), This->hkeyVerb, GetCurrentProcess(), (HANDLE *)&hkeyVerb, 0, FALSE, DUPLICATE_SAME_ACCESS)) | |
| return HRESULT_FROM_WIN32(GetLastError()); | |
| return EnumOLEVERB_Construct(hkeyVerb, This->index, ppenum); | |
| } | |
| static const IEnumOLEVERBVtbl EnumOLEVERB_VTable = | |
| { | |
| EnumOLEVERB_QueryInterface, | |
| EnumOLEVERB_AddRef, | |
| EnumOLEVERB_Release, | |
| EnumOLEVERB_Next, | |
| EnumOLEVERB_Skip, | |
| EnumOLEVERB_Reset, | |
| EnumOLEVERB_Clone | |
| }; | |
| static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum) | |
| { | |
| EnumOLEVERB *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); | |
| if (!This) | |
| { | |
| RegCloseKey(hkeyVerb); | |
| return E_OUTOFMEMORY; | |
| } | |
| This->lpvtbl = &EnumOLEVERB_VTable; | |
| This->ref = 1; | |
| This->index = index; | |
| This->hkeyVerb = hkeyVerb; | |
| *ppenum = (IEnumOLEVERB *)&This->lpvtbl; | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * OleRegEnumVerbs [OLE32.@] | |
| * | |
| * Enumerates verbs associated with a class stored in the registry. | |
| * | |
| * PARAMS | |
| * clsid [I] Class ID to enumerate the verbs for. | |
| * ppenum [O] Enumerator. | |
| * | |
| * RETURNS | |
| * S_OK: Success. | |
| * REGDB_E_CLASSNOTREG: The specified class does not have a key in the registry. | |
| * REGDB_E_READREGDB: The class key could not be opened for some other reason. | |
| * OLE_E_REGDB_KEY: The Verb subkey for the class is not present. | |
| * OLEOBJ_E_NOVERBS: The Verb subkey for the class is empty. | |
| */ | |
| HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum) | |
| { | |
| LONG res; | |
| HKEY hkeyVerb; | |
| DWORD dwSubKeys; | |
| static const WCHAR wszVerb[] = {'V','e','r','b',0}; | |
| TRACE("(%s, %p)\n", debugstr_guid(clsid), ppenum); | |
| res = COM_OpenKeyForCLSID(clsid, wszVerb, KEY_READ, &hkeyVerb); | |
| if (FAILED(res)) | |
| { | |
| if (res == REGDB_E_CLASSNOTREG) | |
| ERR("CLSID %s not registered\n", debugstr_guid(clsid)); | |
| else if (res == REGDB_E_KEYMISSING) | |
| ERR("no Verbs key for class %s\n", debugstr_guid(clsid)); | |
| else | |
| ERR("failed to open Verbs key for CLSID %s with error %d\n", | |
| debugstr_guid(clsid), res); | |
| return res; | |
| } | |
| res = RegQueryInfoKeyW(hkeyVerb, NULL, NULL, NULL, &dwSubKeys, NULL, | |
| NULL, NULL, NULL, NULL, NULL, NULL); | |
| if (res != ERROR_SUCCESS) | |
| { | |
| ERR("failed to get subkey count with error %d\n", GetLastError()); | |
| return REGDB_E_READREGDB; | |
| } | |
| if (!dwSubKeys) | |
| { | |
| WARN("class %s has no verbs\n", debugstr_guid(clsid)); | |
| RegCloseKey(hkeyVerb); | |
| return OLEOBJ_E_NOVERBS; | |
| } | |
| return EnumOLEVERB_Construct(hkeyVerb, 0, ppenum); | |
| } | |
| /****************************************************************************** | |
| * OleSetContainedObject [OLE32.@] | |
| */ | |
| HRESULT WINAPI OleSetContainedObject( | |
| LPUNKNOWN pUnknown, | |
| BOOL fContained) | |
| { | |
| IRunnableObject* runnable = NULL; | |
| HRESULT hres; | |
| TRACE("(%p,%x)\n", pUnknown, fContained); | |
| hres = IUnknown_QueryInterface(pUnknown, | |
| &IID_IRunnableObject, | |
| (void**)&runnable); | |
| if (SUCCEEDED(hres)) | |
| { | |
| hres = IRunnableObject_SetContainedObject(runnable, fContained); | |
| IRunnableObject_Release(runnable); | |
| return hres; | |
| } | |
| return S_OK; | |
| } | |
| /****************************************************************************** | |
| * OleRun [OLE32.@] | |
| * | |
| * Set the OLE object to the running state. | |
| * | |
| * PARAMS | |
| * pUnknown [I] OLE object to run. | |
| * | |
| * RETURNS | |
| * Success: S_OK. | |
| * Failure: Any HRESULT code. | |
| */ | |
| HRESULT WINAPI OleRun(LPUNKNOWN pUnknown) | |
| { | |
| IRunnableObject *runable; | |
| HRESULT hres; | |
| TRACE("(%p)\n", pUnknown); | |
| hres = IUnknown_QueryInterface(pUnknown, &IID_IRunnableObject, (void**)&runable); | |
| if (FAILED(hres)) | |
| return S_OK; /* Appears to return no error. */ | |
| hres = IRunnableObject_Run(runable, NULL); | |
| IRunnableObject_Release(runable); | |
| return hres; | |
| } | |
| /****************************************************************************** | |
| * OleLoad [OLE32.@] | |
| */ | |
| HRESULT WINAPI OleLoad( | |
| LPSTORAGE pStg, | |
| REFIID riid, | |
| LPOLECLIENTSITE pClientSite, | |
| LPVOID* ppvObj) | |
| { | |
| IPersistStorage* persistStorage = NULL; | |
| IUnknown* pUnk; | |
| IOleObject* pOleObject = NULL; | |
| STATSTG storageInfo; | |
| HRESULT hres; | |
| TRACE("(%p, %s, %p, %p)\n", pStg, debugstr_guid(riid), pClientSite, ppvObj); | |
| *ppvObj = NULL; | |
| /* | |
| * TODO, Conversion ... OleDoAutoConvert | |
| */ | |
| /* | |
| * Get the class ID for the object. | |
| */ | |
| hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME); | |
| /* | |
| * Now, try and create the handler for the object | |
| */ | |
| hres = CoCreateInstance(&storageInfo.clsid, | |
| NULL, | |
| CLSCTX_INPROC_HANDLER|CLSCTX_INPROC_SERVER, | |
| riid, | |
| (void**)&pUnk); | |
| /* | |
| * If that fails, as it will most times, load the default | |
| * OLE handler. | |
| */ | |
| if (FAILED(hres)) | |
| { | |
| hres = OleCreateDefaultHandler(&storageInfo.clsid, | |
| NULL, | |
| riid, | |
| (void**)&pUnk); | |
| } | |
| /* | |
| * If we couldn't find a handler... this is bad. Abort the whole thing. | |
| */ | |
| if (FAILED(hres)) | |
| return hres; | |
| if (pClientSite) | |
| { | |
| hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (void **)&pOleObject); | |
| if (SUCCEEDED(hres)) | |
| { | |
| DWORD dwStatus; | |
| hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus); | |
| } | |
| } | |
| if (SUCCEEDED(hres)) | |
| /* | |
| * Initialize the object with it's IPersistStorage interface. | |
| */ | |
| hres = IOleObject_QueryInterface(pUnk, | |
| &IID_IPersistStorage, | |
| (void**)&persistStorage); | |
| if (SUCCEEDED(hres)) | |
| { | |
| hres = IPersistStorage_Load(persistStorage, pStg); | |
| IPersistStorage_Release(persistStorage); | |
| persistStorage = NULL; | |
| } | |
| if (SUCCEEDED(hres) && pClientSite) | |
| /* | |
| * Inform the new object of it's client site. | |
| */ | |
| hres = IOleObject_SetClientSite(pOleObject, pClientSite); | |
| /* | |
| * Cleanup interfaces used internally | |
| */ | |
| if (pOleObject) | |
| IOleObject_Release(pOleObject); | |
| if (SUCCEEDED(hres)) | |
| { | |
| IOleLink *pOleLink; | |
| HRESULT hres1; | |
| hres1 = IUnknown_QueryInterface(pUnk, &IID_IOleLink, (void **)&pOleLink); | |
| if (SUCCEEDED(hres1)) | |
| { | |
| FIXME("handle OLE link\n"); | |
| IOleLink_Release(pOleLink); | |
| } | |
| } | |
| if (FAILED(hres)) | |
| { | |
| IUnknown_Release(pUnk); | |
| pUnk = NULL; | |
| } | |
| *ppvObj = pUnk; | |
| return hres; | |
| } | |
| /*********************************************************************** | |
| * OleSave [OLE32.@] | |
| */ | |
| HRESULT WINAPI OleSave( | |
| LPPERSISTSTORAGE pPS, | |
| LPSTORAGE pStg, | |
| BOOL fSameAsLoad) | |
| { | |
| HRESULT hres; | |
| CLSID objectClass; | |
| TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad); | |
| /* | |
| * First, we transfer the class ID (if available) | |
| */ | |
| hres = IPersistStorage_GetClassID(pPS, &objectClass); | |
| if (SUCCEEDED(hres)) | |
| { | |
| WriteClassStg(pStg, &objectClass); | |
| } | |
| /* | |
| * Then, we ask the object to save itself to the | |
| * storage. If it is successful, we commit the storage. | |
| */ | |
| hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad); | |
| if (SUCCEEDED(hres)) | |
| { | |
| IStorage_Commit(pStg, | |
| STGC_DEFAULT); | |
| } | |
| return hres; | |
| } | |
| /****************************************************************************** | |
| * OleLockRunning [OLE32.@] | |
| */ | |
| HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses) | |
| { | |
| IRunnableObject* runnable = NULL; | |
| HRESULT hres; | |
| TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses); | |
| hres = IUnknown_QueryInterface(pUnknown, | |
| &IID_IRunnableObject, | |
| (void**)&runnable); | |
| if (SUCCEEDED(hres)) | |
| { | |
| hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses); | |
| IRunnableObject_Release(runnable); | |
| return hres; | |
| } | |
| return S_OK; | |
| } | |
| /************************************************************************** | |
| * Internal methods to manage the shared OLE menu in response to the | |
| * OLE***MenuDescriptor API | |
| */ | |
| /*** | |
| * OLEMenu_Initialize() | |
| * | |
| * Initializes the OLEMENU data structures. | |
| */ | |
| static void OLEMenu_Initialize(void) | |
| { | |
| } | |
| /*** | |
| * OLEMenu_UnInitialize() | |
| * | |
| * Releases the OLEMENU data structures. | |
| */ | |
| static void OLEMenu_UnInitialize(void) | |
| { | |
| } | |
| /************************************************************************* | |
| * OLEMenu_InstallHooks | |
| * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC | |
| * | |
| * RETURNS: TRUE if message hooks were successfully installed | |
| * FALSE on failure | |
| */ | |
| static BOOL OLEMenu_InstallHooks( DWORD tid ) | |
| { | |
| OleMenuHookItem *pHookItem = NULL; | |
| /* Create an entry for the hook table */ | |
| if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0, | |
| sizeof(OleMenuHookItem)) ) ) | |
| return FALSE; | |
| pHookItem->tid = tid; | |
| pHookItem->hHeap = GetProcessHeap(); | |
| /* Install a thread scope message hook for WH_GETMESSAGE */ | |
| pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc, | |
| 0, GetCurrentThreadId() ); | |
| if ( !pHookItem->GetMsg_hHook ) | |
| goto CLEANUP; | |
| /* Install a thread scope message hook for WH_CALLWNDPROC */ | |
| pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc, | |
| 0, GetCurrentThreadId() ); | |
| if ( !pHookItem->CallWndProc_hHook ) | |
| goto CLEANUP; | |
| /* Insert the hook table entry */ | |
| pHookItem->next = hook_list; | |
| hook_list = pHookItem; | |
| return TRUE; | |
| CLEANUP: | |
| /* Unhook any hooks */ | |
| if ( pHookItem->GetMsg_hHook ) | |
| UnhookWindowsHookEx( pHookItem->GetMsg_hHook ); | |
| if ( pHookItem->CallWndProc_hHook ) | |
| UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ); | |
| /* Release the hook table entry */ | |
| HeapFree(pHookItem->hHeap, 0, pHookItem ); | |
| return FALSE; | |
| } | |
| /************************************************************************* | |
| * OLEMenu_UnInstallHooks | |
| * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC | |
| * | |
| * RETURNS: TRUE if message hooks were successfully installed | |
| * FALSE on failure | |
| */ | |
| static BOOL OLEMenu_UnInstallHooks( DWORD tid ) | |
| { | |
| OleMenuHookItem *pHookItem = NULL; | |
| OleMenuHookItem **ppHook = &hook_list; | |
| while (*ppHook) | |
| { | |
| if ((*ppHook)->tid == tid) | |
| { | |
| pHookItem = *ppHook; | |
| *ppHook = pHookItem->next; | |
| break; | |
| } | |
| ppHook = &(*ppHook)->next; | |
| } | |
| if (!pHookItem) return FALSE; | |
| /* Uninstall the hooks installed for this thread */ | |
| if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) ) | |
| goto CLEANUP; | |
| if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) ) | |
| goto CLEANUP; | |
| /* Release the hook table entry */ | |
| HeapFree(pHookItem->hHeap, 0, pHookItem ); | |
| return TRUE; | |
| CLEANUP: | |
| /* Release the hook table entry */ | |
| HeapFree(pHookItem->hHeap, 0, pHookItem ); | |
| return FALSE; | |
| } | |
| /************************************************************************* | |
| * OLEMenu_IsHookInstalled | |
| * Tests if OLEMenu hooks have been installed for a thread | |
| * | |
| * RETURNS: The pointer and index of the hook table entry for the tid | |
| * NULL and -1 for the index if no hooks were installed for this thread | |
| */ | |
| static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid ) | |
| { | |
| OleMenuHookItem *pHookItem = NULL; | |
| /* Do a simple linear search for an entry whose tid matches ours. | |
| * We really need a map but efficiency is not a concern here. */ | |
| for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next) | |
| { | |
| if ( tid == pHookItem->tid ) | |
| return pHookItem; | |
| } | |
| return NULL; | |
| } | |
| /*********************************************************************** | |
| * OLEMenu_FindMainMenuIndex | |
| * | |
| * Used by OLEMenu API to find the top level group a menu item belongs to. | |
| * On success pnPos contains the index of the item in the top level menu group | |
| * | |
| * RETURNS: TRUE if the ID was found, FALSE on failure | |
| */ | |
| static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos ) | |
| { | |
| INT i, nItems; | |
| nItems = GetMenuItemCount( hMainMenu ); | |
| for (i = 0; i < nItems; i++) | |
| { | |
| HMENU hsubmenu; | |
| /* Is the current item a submenu? */ | |
| if ( (hsubmenu = GetSubMenu(hMainMenu, i)) ) | |
| { | |
| /* If the handle is the same we're done */ | |
| if ( hsubmenu == hPopupMenu ) | |
| { | |
| if (pnPos) | |
| *pnPos = i; | |
| return TRUE; | |
| } | |
| /* Recursively search without updating pnPos */ | |
| else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) ) | |
| { | |
| if (pnPos) | |
| *pnPos = i; | |
| return TRUE; | |
| } | |
| } | |
| } | |
| return FALSE; | |
| } | |
| /*********************************************************************** | |
| * OLEMenu_SetIsServerMenu | |
| * | |
| * Checks whether a popup menu belongs to a shared menu group which is | |
| * owned by the server, and sets the menu descriptor state accordingly. | |
| * All menu messages from these groups should be routed to the server. | |
| * | |
| * RETURNS: TRUE if the popup menu is part of a server owned group | |
| * FALSE if the popup menu is part of a container owned group | |
| */ | |
| static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor ) | |
| { | |
| UINT nPos = 0, nWidth, i; | |
| pOleMenuDescriptor->bIsServerItem = FALSE; | |
| /* Don't bother searching if the popup is the combined menu itself */ | |
| if ( hmenu == pOleMenuDescriptor->hmenuCombined ) | |
| return FALSE; | |
| /* Find the menu item index in the shared OLE menu that this item belongs to */ | |
| if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) ) | |
| return FALSE; | |
| /* The group widths array has counts for the number of elements | |
| * in the groups File, Edit, Container, Object, Window, Help. | |
| * The Edit, Object & Help groups belong to the server object | |
| * and the other three belong to the container. | |
| * Loop through the group widths and locate the group we are a member of. | |
| */ | |
| for ( i = 0, nWidth = 0; i < 6; i++ ) | |
| { | |
| nWidth += pOleMenuDescriptor->mgw.width[i]; | |
| if ( nPos < nWidth ) | |
| { | |
| /* Odd elements are server menu widths */ | |
| pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE; | |
| break; | |
| } | |
| } | |
| return pOleMenuDescriptor->bIsServerItem; | |
| } | |
| /************************************************************************* | |
| * OLEMenu_CallWndProc | |
| * Thread scope WH_CALLWNDPROC hook proc filter function (callback) | |
| * This is invoked from a message hook installed in OleSetMenuDescriptor. | |
| */ | |
| static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam) | |
| { | |
| LPCWPSTRUCT pMsg = NULL; | |
| HOLEMENU hOleMenu = 0; | |
| OleMenuDescriptor *pOleMenuDescriptor = NULL; | |
| OleMenuHookItem *pHookItem = NULL; | |
| WORD fuFlags; | |
| TRACE("%i, %04lx, %08lx\n", code, wParam, lParam ); | |
| /* Check if we're being asked to process the message */ | |
| if ( HC_ACTION != code ) | |
| goto NEXTHOOK; | |
| /* Retrieve the current message being dispatched from lParam */ | |
| pMsg = (LPCWPSTRUCT)lParam; | |
| /* Check if the message is destined for a window we are interested in: | |
| * If the window has an OLEMenu property we may need to dispatch | |
| * the menu message to its active objects window instead. */ | |
| hOleMenu = GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" ); | |
| if ( !hOleMenu ) | |
| goto NEXTHOOK; | |
| /* Get the menu descriptor */ | |
| pOleMenuDescriptor = GlobalLock( hOleMenu ); | |
| if ( !pOleMenuDescriptor ) /* Bad descriptor! */ | |
| goto NEXTHOOK; | |
| /* Process menu messages */ | |
| switch( pMsg->message ) | |
| { | |
| case WM_INITMENU: | |
| { | |
| /* Reset the menu descriptor state */ | |
| pOleMenuDescriptor->bIsServerItem = FALSE; | |
| /* Send this message to the server as well */ | |
| SendMessageA( pOleMenuDescriptor->hwndActiveObject, | |
| pMsg->message, pMsg->wParam, pMsg->lParam ); | |
| goto NEXTHOOK; | |
| } | |
| case WM_INITMENUPOPUP: | |
| { | |
| /* Save the state for whether this is a server owned menu */ | |
| OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor ); | |
| break; | |
| } | |
| case WM_MENUSELECT: | |
| { | |
| fuFlags = HIWORD(pMsg->wParam); /* Get flags */ | |
| if ( fuFlags & MF_SYSMENU ) | |
| goto NEXTHOOK; | |
| /* Save the state for whether this is a server owned popup menu */ | |
| else if ( fuFlags & MF_POPUP ) | |
| OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor ); | |
| break; | |
| } | |
| case WM_DRAWITEM: | |
| { | |
| LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam; | |
| if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU ) | |
| goto NEXTHOOK; /* Not a menu message */ | |
| break; | |
| } | |
| default: | |
| goto NEXTHOOK; | |
| } | |
| /* If the message was for the server dispatch it accordingly */ | |
| if ( pOleMenuDescriptor->bIsServerItem ) | |
| { | |
| SendMessageA( pOleMenuDescriptor->hwndActiveObject, | |
| pMsg->message, pMsg->wParam, pMsg->lParam ); | |
| } | |
| NEXTHOOK: | |
| if ( pOleMenuDescriptor ) | |
| GlobalUnlock( hOleMenu ); | |
| /* Lookup the hook item for the current thread */ | |
| if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) ) | |
| { | |
| /* This should never fail!! */ | |
| WARN("could not retrieve hHook for current thread!\n" ); | |
| return 0; | |
| } | |
| /* Pass on the message to the next hooker */ | |
| return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam ); | |
| } | |
| /************************************************************************* | |
| * OLEMenu_GetMsgProc | |
| * Thread scope WH_GETMESSAGE hook proc filter function (callback) | |
| * This is invoked from a message hook installed in OleSetMenuDescriptor. | |
| */ | |
| static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam) | |
| { | |
| LPMSG pMsg = NULL; | |
| HOLEMENU hOleMenu = 0; | |
| OleMenuDescriptor *pOleMenuDescriptor = NULL; | |
| OleMenuHookItem *pHookItem = NULL; | |
| WORD wCode; | |
| TRACE("%i, %04lx, %08lx\n", code, wParam, lParam ); | |
| /* Check if we're being asked to process a messages */ | |
| if ( HC_ACTION != code ) | |
| goto NEXTHOOK; | |
| /* Retrieve the current message being dispatched from lParam */ | |
| pMsg = (LPMSG)lParam; | |
| /* Check if the message is destined for a window we are interested in: | |
| * If the window has an OLEMenu property we may need to dispatch | |
| * the menu message to its active objects window instead. */ | |
| hOleMenu = GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" ); | |
| if ( !hOleMenu ) | |
| goto NEXTHOOK; | |
| /* Process menu messages */ | |
| switch( pMsg->message ) | |
| { | |
| case WM_COMMAND: | |
| { | |
| wCode = HIWORD(pMsg->wParam); /* Get notification code */ | |
| if ( wCode ) | |
| goto NEXTHOOK; /* Not a menu message */ | |
| break; | |
| } | |
| default: | |
| goto NEXTHOOK; | |
| } | |
| /* Get the menu descriptor */ | |
| pOleMenuDescriptor = GlobalLock( hOleMenu ); | |
| if ( !pOleMenuDescriptor ) /* Bad descriptor! */ | |
| goto NEXTHOOK; | |
| /* If the message was for the server dispatch it accordingly */ | |
| if ( pOleMenuDescriptor->bIsServerItem ) | |
| { | |
| /* Change the hWnd in the message to the active objects hWnd. | |
| * The message loop which reads this message will automatically | |
| * dispatch it to the embedded objects window. */ | |
| pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject; | |
| } | |
| NEXTHOOK: | |
| if ( pOleMenuDescriptor ) | |
| GlobalUnlock( hOleMenu ); | |
| /* Lookup the hook item for the current thread */ | |
| if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) ) | |
| { | |
| /* This should never fail!! */ | |
| WARN("could not retrieve hHook for current thread!\n" ); | |
| return FALSE; | |
| } | |
| /* Pass on the message to the next hooker */ | |
| return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam ); | |
| } | |
| /*********************************************************************** | |
| * OleCreateMenuDescriptor [OLE32.@] | |
| * Creates an OLE menu descriptor for OLE to use when dispatching | |
| * menu messages and commands. | |
| * | |
| * PARAMS: | |
| * hmenuCombined - Handle to the objects combined menu | |
| * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group | |
| * | |
| */ | |
| HOLEMENU WINAPI OleCreateMenuDescriptor( | |
| HMENU hmenuCombined, | |
| LPOLEMENUGROUPWIDTHS lpMenuWidths) | |
| { | |
| HOLEMENU hOleMenu; | |
| OleMenuDescriptor *pOleMenuDescriptor; | |
| int i; | |
| if ( !hmenuCombined || !lpMenuWidths ) | |
| return 0; | |
| /* Create an OLE menu descriptor */ | |
| if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, | |
| sizeof(OleMenuDescriptor) ) ) ) | |
| return 0; | |
| pOleMenuDescriptor = GlobalLock( hOleMenu ); | |
| if ( !pOleMenuDescriptor ) | |
| return 0; | |
| /* Initialize menu group widths and hmenu */ | |
| for ( i = 0; i < 6; i++ ) | |
| pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i]; | |
| pOleMenuDescriptor->hmenuCombined = hmenuCombined; | |
| pOleMenuDescriptor->bIsServerItem = FALSE; | |
| GlobalUnlock( hOleMenu ); | |
| return hOleMenu; | |
| } | |
| /*********************************************************************** | |
| * OleDestroyMenuDescriptor [OLE32.@] | |
| * Destroy the shared menu descriptor | |
| */ | |
| HRESULT WINAPI OleDestroyMenuDescriptor( | |
| HOLEMENU hmenuDescriptor) | |
| { | |
| if ( hmenuDescriptor ) | |
| GlobalFree( hmenuDescriptor ); | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * OleSetMenuDescriptor [OLE32.@] | |
| * Installs or removes OLE dispatching code for the containers frame window. | |
| * | |
| * PARAMS | |
| * hOleMenu Handle to composite menu descriptor | |
| * hwndFrame Handle to containers frame window | |
| * hwndActiveObject Handle to objects in-place activation window | |
| * lpFrame Pointer to IOleInPlaceFrame on containers window | |
| * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object | |
| * | |
| * RETURNS | |
| * S_OK - menu installed correctly | |
| * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure | |
| * | |
| * FIXME | |
| * The lpFrame and lpActiveObject parameters are currently ignored | |
| * OLE should install context sensitive help F1 filtering for the app when | |
| * these are non null. | |
| */ | |
| HRESULT WINAPI OleSetMenuDescriptor( | |
| HOLEMENU hOleMenu, | |
| HWND hwndFrame, | |
| HWND hwndActiveObject, | |
| LPOLEINPLACEFRAME lpFrame, | |
| LPOLEINPLACEACTIVEOBJECT lpActiveObject) | |
| { | |
| OleMenuDescriptor *pOleMenuDescriptor = NULL; | |
| /* Check args */ | |
| if ( !hwndFrame || (hOleMenu && !hwndActiveObject) ) | |
| return E_INVALIDARG; | |
| if ( lpFrame || lpActiveObject ) | |
| { | |
| FIXME("(%p, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n", | |
| hOleMenu, | |
| hwndFrame, | |
| hwndActiveObject, | |
| lpFrame, | |
| lpActiveObject); | |
| } | |
| /* Set up a message hook to intercept the containers frame window messages. | |
| * The message filter is responsible for dispatching menu messages from the | |
| * shared menu which are intended for the object. | |
| */ | |
| if ( hOleMenu ) /* Want to install dispatching code */ | |
| { | |
| /* If OLEMenu hooks are already installed for this thread, fail | |
| * Note: This effectively means that OleSetMenuDescriptor cannot | |
| * be called twice in succession on the same frame window | |
| * without first calling it with a null hOleMenu to uninstall */ | |
| if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) | |
| return E_FAIL; | |
| /* Get the menu descriptor */ | |
| pOleMenuDescriptor = GlobalLock( hOleMenu ); | |
| if ( !pOleMenuDescriptor ) | |
| return E_UNEXPECTED; | |
| /* Update the menu descriptor */ | |
| pOleMenuDescriptor->hwndFrame = hwndFrame; | |
| pOleMenuDescriptor->hwndActiveObject = hwndActiveObject; | |
| GlobalUnlock( hOleMenu ); | |
| pOleMenuDescriptor = NULL; | |
| /* Add a menu descriptor windows property to the frame window */ | |
| SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu ); | |
| /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */ | |
| if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) ) | |
| return E_FAIL; | |
| } | |
| else /* Want to uninstall dispatching code */ | |
| { | |
| /* Uninstall the hooks */ | |
| if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) ) | |
| return E_FAIL; | |
| /* Remove the menu descriptor property from the frame window */ | |
| RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" ); | |
| } | |
| return S_OK; | |
| } | |
| /****************************************************************************** | |
| * IsAccelerator [OLE32.@] | |
| * Mostly copied from controls/menu.c TranslateAccelerator implementation | |
| */ | |
| BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd) | |
| { | |
| LPACCEL lpAccelTbl; | |
| int i; | |
| if(!lpMsg) return FALSE; | |
| if (!hAccel) | |
| { | |
| WARN_(accel)("NULL accel handle\n"); | |
| return FALSE; | |
| } | |
| if((lpMsg->message != WM_KEYDOWN && | |
| lpMsg->message != WM_SYSKEYDOWN && | |
| lpMsg->message != WM_SYSCHAR && | |
| lpMsg->message != WM_CHAR)) return FALSE; | |
| lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL)); | |
| if (NULL == lpAccelTbl) | |
| { | |
| return FALSE; | |
| } | |
| if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries) | |
| { | |
| WARN_(accel)("CopyAcceleratorTableW failed\n"); | |
| HeapFree(GetProcessHeap(), 0, lpAccelTbl); | |
| return FALSE; | |
| } | |
| TRACE_(accel)("hAccel=%p, cAccelEntries=%d," | |
| "msg->hwnd=%p, msg->message=%04x, wParam=%08lx, lParam=%08lx\n", | |
| hAccel, cAccelEntries, | |
| lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam); | |
| for(i = 0; i < cAccelEntries; i++) | |
| { | |
| if(lpAccelTbl[i].key != lpMsg->wParam) | |
| continue; | |
| if(lpMsg->message == WM_CHAR) | |
| { | |
| if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY)) | |
| { | |
| TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", LOWORD(lpMsg->wParam) & 0xff); | |
| goto found; | |
| } | |
| } | |
| else | |
| { | |
| if(lpAccelTbl[i].fVirt & FVIRTKEY) | |
| { | |
| INT mask = 0; | |
| TRACE_(accel)("found accel for virt_key %04lx (scan %04x)\n", | |
| lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff); | |
| if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT; | |
| if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL; | |
| if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT; | |
| if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found; | |
| TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n"); | |
| } | |
| else | |
| { | |
| if(!(lpMsg->lParam & 0x01000000)) /* no special_key */ | |
| { | |
| if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000)) | |
| { /* ^^ ALT pressed */ | |
| TRACE_(accel)("found accel for Alt-%c\n", LOWORD(lpMsg->wParam) & 0xff); | |
| goto found; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| WARN_(accel)("couldn't translate accelerator key\n"); | |
| HeapFree(GetProcessHeap(), 0, lpAccelTbl); | |
| return FALSE; | |
| found: | |
| if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd; | |
| HeapFree(GetProcessHeap(), 0, lpAccelTbl); | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * ReleaseStgMedium [OLE32.@] | |
| */ | |
| void WINAPI ReleaseStgMedium( | |
| STGMEDIUM* pmedium) | |
| { | |
| switch (pmedium->tymed) | |
| { | |
| case TYMED_HGLOBAL: | |
| { | |
| if ( (pmedium->pUnkForRelease==0) && | |
| (pmedium->u.hGlobal!=0) ) | |
| GlobalFree(pmedium->u.hGlobal); | |
| break; | |
| } | |
| case TYMED_FILE: | |
| { | |
| if (pmedium->u.lpszFileName!=0) | |
| { | |
| if (pmedium->pUnkForRelease==0) | |
| { | |
| DeleteFileW(pmedium->u.lpszFileName); | |
| } | |
| CoTaskMemFree(pmedium->u.lpszFileName); | |
| } | |
| break; | |
| } | |
| case TYMED_ISTREAM: | |
| { | |
| if (pmedium->u.pstm!=0) | |
| { | |
| IStream_Release(pmedium->u.pstm); | |
| } | |
| break; | |
| } | |
| case TYMED_ISTORAGE: | |
| { | |
| if (pmedium->u.pstg!=0) | |
| { | |
| IStorage_Release(pmedium->u.pstg); | |
| } | |
| break; | |
| } | |
| case TYMED_GDI: | |
| { | |
| if ( (pmedium->pUnkForRelease==0) && | |
| (pmedium->u.hBitmap!=0) ) | |
| DeleteObject(pmedium->u.hBitmap); | |
| break; | |
| } | |
| case TYMED_MFPICT: | |
| { | |
| if ( (pmedium->pUnkForRelease==0) && | |
| (pmedium->u.hMetaFilePict!=0) ) | |
| { | |
| LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict); | |
| DeleteMetaFile(pMP->hMF); | |
| GlobalUnlock(pmedium->u.hMetaFilePict); | |
| GlobalFree(pmedium->u.hMetaFilePict); | |
| } | |
| break; | |
| } | |
| case TYMED_ENHMF: | |
| { | |
| if ( (pmedium->pUnkForRelease==0) && | |
| (pmedium->u.hEnhMetaFile!=0) ) | |
| { | |
| DeleteEnhMetaFile(pmedium->u.hEnhMetaFile); | |
| } | |
| break; | |
| } | |
| case TYMED_NULL: | |
| default: | |
| break; | |
| } | |
| pmedium->tymed=TYMED_NULL; | |
| /* | |
| * After cleaning up, the unknown is released | |
| */ | |
| if (pmedium->pUnkForRelease!=0) | |
| { | |
| IUnknown_Release(pmedium->pUnkForRelease); | |
| pmedium->pUnkForRelease = 0; | |
| } | |
| } | |
| /*** | |
| * OLEDD_Initialize() | |
| * | |
| * Initializes the OLE drag and drop data structures. | |
| */ | |
| static void OLEDD_Initialize(void) | |
| { | |
| WNDCLASSA wndClass; | |
| ZeroMemory (&wndClass, sizeof(WNDCLASSA)); | |
| wndClass.style = CS_GLOBALCLASS; | |
| wndClass.lpfnWndProc = OLEDD_DragTrackerWindowProc; | |
| wndClass.cbClsExtra = 0; | |
| wndClass.cbWndExtra = sizeof(TrackerWindowInfo*); | |
| wndClass.hCursor = 0; | |
| wndClass.hbrBackground = 0; | |
| wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS; | |
| RegisterClassA (&wndClass); | |
| } | |
| /*** | |
| * OLEDD_FreeDropTarget() | |
| * | |
| * Frees the drag and drop data structure | |
| */ | |
| static void OLEDD_FreeDropTarget(DropTargetNode *dropTargetInfo, BOOL release_drop_target) | |
| { | |
| list_remove(&dropTargetInfo->entry); | |
| if (release_drop_target) IDropTarget_Release(dropTargetInfo->dropTarget); | |
| HeapFree(GetProcessHeap(), 0, dropTargetInfo); | |
| } | |
| /*** | |
| * OLEDD_UnInitialize() | |
| * | |
| * Releases the OLE drag and drop data structures. | |
| */ | |
| void OLEDD_UnInitialize(void) | |
| { | |
| /* | |
| * Simply empty the list. | |
| */ | |
| while (!list_empty(&targetListHead)) | |
| { | |
| DropTargetNode* curNode = LIST_ENTRY(list_head(&targetListHead), DropTargetNode, entry); | |
| OLEDD_FreeDropTarget(curNode, FALSE); | |
| } | |
| } | |
| /*** | |
| * OLEDD_FindDropTarget() | |
| * | |
| * Finds information about the drop target. | |
| */ | |
| static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget) | |
| { | |
| DropTargetNode* curNode; | |
| /* | |
| * Iterate the list to find the HWND value. | |
| */ | |
| LIST_FOR_EACH_ENTRY(curNode, &targetListHead, DropTargetNode, entry) | |
| if (hwndOfTarget==curNode->hwndTarget) | |
| return curNode; | |
| /* | |
| * If we get here, the item is not in the list | |
| */ | |
| return NULL; | |
| } | |
| /*** | |
| * OLEDD_DragTrackerWindowProc() | |
| * | |
| * This method is the WindowProcedure of the drag n drop tracking | |
| * window. During a drag n Drop operation, an invisible window is created | |
| * to receive the user input and act upon it. This procedure is in charge | |
| * of this behavior. | |
| */ | |
| #define DRAG_TIMER_ID 1 | |
| static LRESULT WINAPI OLEDD_DragTrackerWindowProc( | |
| HWND hwnd, | |
| UINT uMsg, | |
| WPARAM wParam, | |
| LPARAM lParam) | |
| { | |
| switch (uMsg) | |
| { | |
| case WM_CREATE: | |
| { | |
| LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam; | |
| SetWindowLongPtrA(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams); | |
| SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL); | |
| break; | |
| } | |
| case WM_TIMER: | |
| case WM_MOUSEMOVE: | |
| { | |
| OLEDD_TrackMouseMove((TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0)); | |
| break; | |
| } | |
| case WM_LBUTTONUP: | |
| case WM_MBUTTONUP: | |
| case WM_RBUTTONUP: | |
| case WM_LBUTTONDOWN: | |
| case WM_MBUTTONDOWN: | |
| case WM_RBUTTONDOWN: | |
| { | |
| OLEDD_TrackStateChange((TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0)); | |
| break; | |
| } | |
| case WM_DESTROY: | |
| { | |
| KillTimer(hwnd, DRAG_TIMER_ID); | |
| break; | |
| } | |
| } | |
| /* | |
| * This is a window proc after all. Let's call the default. | |
| */ | |
| return DefWindowProcA (hwnd, uMsg, wParam, lParam); | |
| } | |
| /*** | |
| * OLEDD_TrackMouseMove() | |
| * | |
| * This method is invoked while a drag and drop operation is in effect. | |
| * it will generate the appropriate callbacks in the drop source | |
| * and drop target. It will also provide the expected feedback to | |
| * the user. | |
| * | |
| * params: | |
| * trackerInfo - Pointer to the structure identifying the | |
| * drag & drop operation that is currently | |
| * active. | |
| */ | |
| static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo) | |
| { | |
| HWND hwndNewTarget = 0; | |
| HRESULT hr = S_OK; | |
| POINT pt; | |
| /* | |
| * Get the handle of the window under the mouse | |
| */ | |
| pt.x = trackerInfo->curMousePos.x; | |
| pt.y = trackerInfo->curMousePos.y; | |
| hwndNewTarget = WindowFromPoint(pt); | |
| /* | |
| * Every time, we re-initialize the effects passed to the | |
| * IDropTarget to the effects allowed by the source. | |
| */ | |
| *trackerInfo->pdwEffect = trackerInfo->dwOKEffect; | |
| /* | |
| * If we are hovering over the same target as before, send the | |
| * DragOver notification | |
| */ | |
| if ( (trackerInfo->curDragTarget != 0) && | |
| (trackerInfo->curTargetHWND == hwndNewTarget) ) | |
| { | |
| IDropTarget_DragOver(trackerInfo->curDragTarget, | |
| trackerInfo->dwKeyState, | |
| trackerInfo->curMousePos, | |
| trackerInfo->pdwEffect); | |
| } | |
| else | |
| { | |
| DropTargetNode* newDropTargetNode = 0; | |
| /* | |
| * If we changed window, we have to notify our old target and check for | |
| * the new one. | |
| */ | |
| if (trackerInfo->curDragTarget!=0) | |
| { | |
| IDropTarget_DragLeave(trackerInfo->curDragTarget); | |
| } | |
| /* | |
| * Make sure we're hovering over a window. | |
| */ | |
| if (hwndNewTarget!=0) | |
| { | |
| /* | |
| * Find-out if there is a drag target under the mouse | |
| */ | |
| HWND nexttar = hwndNewTarget; | |
| trackerInfo->curTargetHWND = hwndNewTarget; | |
| do { | |
| newDropTargetNode = OLEDD_FindDropTarget(nexttar); | |
| } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0); | |
| if(nexttar) hwndNewTarget = nexttar; | |
| trackerInfo->curDragTargetHWND = hwndNewTarget; | |
| trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0; | |
| /* | |
| * If there is, notify it that we just dragged-in | |
| */ | |
| if (trackerInfo->curDragTarget!=0) | |
| { | |
| IDropTarget_DragEnter(trackerInfo->curDragTarget, | |
| trackerInfo->dataObject, | |
| trackerInfo->dwKeyState, | |
| trackerInfo->curMousePos, | |
| trackerInfo->pdwEffect); | |
| } | |
| } | |
| else | |
| { | |
| /* | |
| * The mouse is not over a window so we don't track anything. | |
| */ | |
| trackerInfo->curDragTargetHWND = 0; | |
| trackerInfo->curTargetHWND = 0; | |
| trackerInfo->curDragTarget = 0; | |
| } | |
| } | |
| /* | |
| * Now that we have done that, we have to tell the source to give | |
| * us feedback on the work being done by the target. If we don't | |
| * have a target, simulate no effect. | |
| */ | |
| if (trackerInfo->curDragTarget==0) | |
| { | |
| *trackerInfo->pdwEffect = DROPEFFECT_NONE; | |
| } | |
| hr = IDropSource_GiveFeedback(trackerInfo->dropSource, | |
| *trackerInfo->pdwEffect); | |
| /* | |
| * When we ask for feedback from the drop source, sometimes it will | |
| * do all the necessary work and sometimes it will not handle it | |
| * when that's the case, we must display the standard drag and drop | |
| * cursors. | |
| */ | |
| if (hr==DRAGDROP_S_USEDEFAULTCURSORS) | |
| { | |
| if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) | |
| { | |
| SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(1))); | |
| } | |
| else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY) | |
| { | |
| SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(2))); | |
| } | |
| else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK) | |
| { | |
| SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(3))); | |
| } | |
| else | |
| { | |
| SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(0))); | |
| } | |
| } | |
| } | |
| /*** | |
| * OLEDD_TrackStateChange() | |
| * | |
| * This method is invoked while a drag and drop operation is in effect. | |
| * It is used to notify the drop target/drop source callbacks when | |
| * the state of the keyboard or mouse button change. | |
| * | |
| * params: | |
| * trackerInfo - Pointer to the structure identifying the | |
| * drag & drop operation that is currently | |
| * active. | |
| */ | |
| static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo) | |
| { | |
| /* | |
| * Ask the drop source what to do with the operation. | |
| */ | |
| trackerInfo->returnValue = IDropSource_QueryContinueDrag( | |
| trackerInfo->dropSource, | |
| trackerInfo->escPressed, | |
| trackerInfo->dwKeyState); | |
| /* | |
| * All the return valued will stop the operation except the S_OK | |
| * return value. | |
| */ | |
| if (trackerInfo->returnValue!=S_OK) | |
| { | |
| /* | |
| * Make sure the message loop in DoDragDrop stops | |
| */ | |
| trackerInfo->trackingDone = TRUE; | |
| /* | |
| * Release the mouse in case the drop target decides to show a popup | |
| * or a menu or something. | |
| */ | |
| ReleaseCapture(); | |
| /* | |
| * If we end-up over a target, drop the object in the target or | |
| * inform the target that the operation was cancelled. | |
| */ | |
| if (trackerInfo->curDragTarget!=0) | |
| { | |
| switch (trackerInfo->returnValue) | |
| { | |
| /* | |
| * If the source wants us to complete the operation, we tell | |
| * the drop target that we just dropped the object in it. | |
| */ | |
| case DRAGDROP_S_DROP: | |
| { | |
| IDropTarget_Drop(trackerInfo->curDragTarget, | |
| trackerInfo->dataObject, | |
| trackerInfo->dwKeyState, | |
| trackerInfo->curMousePos, | |
| trackerInfo->pdwEffect); | |
| break; | |
| } | |
| /* | |
| * If the source told us that we should cancel, fool the drop | |
| * target by telling it that the mouse left it's window. | |
| * Also set the drop effect to "NONE" in case the application | |
| * ignores the result of DoDragDrop. | |
| */ | |
| case DRAGDROP_S_CANCEL: | |
| IDropTarget_DragLeave(trackerInfo->curDragTarget); | |
| *trackerInfo->pdwEffect = DROPEFFECT_NONE; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| /*** | |
| * OLEDD_GetButtonState() | |
| * | |
| * This method will use the current state of the keyboard to build | |
| * a button state mask equivalent to the one passed in the | |
| * WM_MOUSEMOVE wParam. | |
| */ | |
| static DWORD OLEDD_GetButtonState(void) | |
| { | |
| BYTE keyboardState[256]; | |
| DWORD keyMask = 0; | |
| GetKeyboardState(keyboardState); | |
| if ( (keyboardState[VK_SHIFT] & 0x80) !=0) | |
| keyMask |= MK_SHIFT; | |
| if ( (keyboardState[VK_CONTROL] & 0x80) !=0) | |
| keyMask |= MK_CONTROL; | |
| if ( (keyboardState[VK_LBUTTON] & 0x80) !=0) | |
| keyMask |= MK_LBUTTON; | |
| if ( (keyboardState[VK_RBUTTON] & 0x80) !=0) | |
| keyMask |= MK_RBUTTON; | |
| if ( (keyboardState[VK_MBUTTON] & 0x80) !=0) | |
| keyMask |= MK_MBUTTON; | |
| return keyMask; | |
| } | |
| /*** | |
| * OLEDD_GetButtonState() | |
| * | |
| * This method will read the default value of the registry key in | |
| * parameter and extract a DWORD value from it. The registry key value | |
| * can be in a string key or a DWORD key. | |
| * | |
| * params: | |
| * regKey - Key to read the default value from | |
| * pdwValue - Pointer to the location where the DWORD | |
| * value is returned. This value is not modified | |
| * if the value is not found. | |
| */ | |
| static void OLEUTL_ReadRegistryDWORDValue( | |
| HKEY regKey, | |
| DWORD* pdwValue) | |
| { | |
| char buffer[20]; | |
| DWORD dwKeyType; | |
| DWORD cbData = 20; | |
| LONG lres; | |
| lres = RegQueryValueExA(regKey, | |
| "", | |
| NULL, | |
| &dwKeyType, | |
| (LPBYTE)buffer, | |
| &cbData); | |
| if (lres==ERROR_SUCCESS) | |
| { | |
| switch (dwKeyType) | |
| { | |
| case REG_DWORD: | |
| *pdwValue = *(DWORD*)buffer; | |
| break; | |
| case REG_EXPAND_SZ: | |
| case REG_MULTI_SZ: | |
| case REG_SZ: | |
| *pdwValue = (DWORD)strtoul(buffer, NULL, 10); | |
| break; | |
| } | |
| } | |
| } | |
| /****************************************************************************** | |
| * OleDraw (OLE32.@) | |
| * | |
| * The operation of this function is documented literally in the WinAPI | |
| * documentation to involve a QueryInterface for the IViewObject interface, | |
| * followed by a call to IViewObject::Draw. | |
| */ | |
| HRESULT WINAPI OleDraw( | |
| IUnknown *pUnk, | |
| DWORD dwAspect, | |
| HDC hdcDraw, | |
| LPCRECT lprcBounds) | |
| { | |
| HRESULT hres; | |
| IViewObject *viewobject; | |
| hres = IUnknown_QueryInterface(pUnk, | |
| &IID_IViewObject, | |
| (void**)&viewobject); | |
| if (SUCCEEDED(hres)) | |
| { | |
| RECTL rectl; | |
| rectl.left = lprcBounds->left; | |
| rectl.right = lprcBounds->right; | |
| rectl.top = lprcBounds->top; | |
| rectl.bottom = lprcBounds->bottom; | |
| hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, &rectl, 0, 0, 0); | |
| IViewObject_Release(viewobject); | |
| return hres; | |
| } | |
| else | |
| { | |
| return DV_E_NOIVIEWOBJECT; | |
| } | |
| } | |
| /*********************************************************************** | |
| * OleTranslateAccelerator [OLE32.@] | |
| */ | |
| HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame, | |
| LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg) | |
| { | |
| WORD wID; | |
| TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg); | |
| if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID)) | |
| return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID); | |
| return S_FALSE; | |
| } | |
| /****************************************************************************** | |
| * OleCreate [OLE32.@] | |
| * | |
| */ | |
| HRESULT WINAPI OleCreate( | |
| REFCLSID rclsid, | |
| REFIID riid, | |
| DWORD renderopt, | |
| LPFORMATETC pFormatEtc, | |
| LPOLECLIENTSITE pClientSite, | |
| LPSTORAGE pStg, | |
| LPVOID* ppvObj) | |
| { | |
| HRESULT hres; | |
| IUnknown * pUnk = NULL; | |
| IOleObject *pOleObject = NULL; | |
| TRACE("(%s, %s, %d, %p, %p, %p, %p)\n", debugstr_guid(rclsid), | |
| debugstr_guid(riid), renderopt, pFormatEtc, pClientSite, pStg, ppvObj); | |
| hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, riid, (LPVOID*)&pUnk); | |
| if (SUCCEEDED(hres)) | |
| hres = IStorage_SetClass(pStg, rclsid); | |
| if (pClientSite && SUCCEEDED(hres)) | |
| { | |
| hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (LPVOID*)&pOleObject); | |
| if (SUCCEEDED(hres)) | |
| { | |
| DWORD dwStatus; | |
| hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus); | |
| } | |
| } | |
| if (SUCCEEDED(hres)) | |
| { | |
| IPersistStorage * pPS; | |
| if (SUCCEEDED((hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (LPVOID*)&pPS)))) | |
| { | |
| TRACE("trying to set stg %p\n", pStg); | |
| hres = IPersistStorage_InitNew(pPS, pStg); | |
| TRACE("-- result 0x%08x\n", hres); | |
| IPersistStorage_Release(pPS); | |
| } | |
| } | |
| if (pClientSite && SUCCEEDED(hres)) | |
| { | |
| TRACE("trying to set clientsite %p\n", pClientSite); | |
| hres = IOleObject_SetClientSite(pOleObject, pClientSite); | |
| TRACE("-- result 0x%08x\n", hres); | |
| } | |
| if (pOleObject) | |
| IOleObject_Release(pOleObject); | |
| if (((renderopt == OLERENDER_DRAW) || (renderopt == OLERENDER_FORMAT)) && | |
| SUCCEEDED(hres)) | |
| { | |
| IRunnableObject *pRunnable; | |
| IOleCache *pOleCache; | |
| HRESULT hres2; | |
| hres2 = IUnknown_QueryInterface(pUnk, &IID_IRunnableObject, (void **)&pRunnable); | |
| if (SUCCEEDED(hres2)) | |
| { | |
| hres = IRunnableObject_Run(pRunnable, NULL); | |
| IRunnableObject_Release(pRunnable); | |
| } | |
| if (SUCCEEDED(hres)) | |
| { | |
| hres2 = IUnknown_QueryInterface(pUnk, &IID_IOleCache, (void **)&pOleCache); | |
| if (SUCCEEDED(hres2)) | |
| { | |
| DWORD dwConnection; | |
| hres = IOleCache_Cache(pOleCache, pFormatEtc, ADVF_PRIMEFIRST, &dwConnection); | |
| IOleCache_Release(pOleCache); | |
| } | |
| } | |
| } | |
| if (FAILED(hres) && pUnk) | |
| { | |
| IUnknown_Release(pUnk); | |
| pUnk = NULL; | |
| } | |
| *ppvObj = pUnk; | |
| TRACE("-- %p\n", pUnk); | |
| return hres; | |
| } | |
| /****************************************************************************** | |
| * OleGetAutoConvert [OLE32.@] | |
| */ | |
| HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew) | |
| { | |
| static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0}; | |
| HKEY hkey = NULL; | |
| WCHAR buf[CHARS_IN_GUID]; | |
| LONG len; | |
| HRESULT res = S_OK; | |
| res = COM_OpenKeyForCLSID(clsidOld, wszAutoConvertTo, KEY_READ, &hkey); | |
| if (FAILED(res)) | |
| goto done; | |
| len = sizeof(buf); | |
| if (RegQueryValueW(hkey, NULL, buf, &len)) | |
| { | |
| res = REGDB_E_KEYMISSING; | |
| goto done; | |
| } | |
| res = CLSIDFromString(buf, pClsidNew); | |
| done: | |
| if (hkey) RegCloseKey(hkey); | |
| return res; | |
| } | |
| /****************************************************************************** | |
| * OleSetAutoConvert [OLE32.@] | |
| */ | |
| HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew) | |
| { | |
| static const WCHAR wszAutoConvertTo[] = {'A','u','t','o','C','o','n','v','e','r','t','T','o',0}; | |
| HKEY hkey = NULL; | |
| WCHAR szClsidNew[CHARS_IN_GUID]; | |
| HRESULT res = S_OK; | |
| TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew)); | |
| res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey); | |
| if (FAILED(res)) | |
| goto done; | |
| StringFromGUID2(clsidNew, szClsidNew, CHARS_IN_GUID); | |
| if (RegSetValueW(hkey, wszAutoConvertTo, REG_SZ, szClsidNew, (strlenW(szClsidNew)+1) * sizeof(WCHAR))) | |
| { | |
| res = REGDB_E_WRITEREGDB; | |
| goto done; | |
| } | |
| done: | |
| if (hkey) RegCloseKey(hkey); | |
| return res; | |
| } | |
| /****************************************************************************** | |
| * OleDoAutoConvert [OLE32.@] | |
| */ | |
| HRESULT WINAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew) | |
| { | |
| FIXME("(%p,%p) : stub\n",pStg,pClsidNew); | |
| return E_NOTIMPL; | |
| } | |
| /****************************************************************************** | |
| * OleIsRunning [OLE32.@] | |
| */ | |
| BOOL WINAPI OleIsRunning(LPOLEOBJECT pObject) | |
| { | |
| IRunnableObject *pRunnable; | |
| HRESULT hr; | |
| BOOL running; | |
| TRACE("(%p)\n", pObject); | |
| hr = IOleObject_QueryInterface(pObject, &IID_IRunnableObject, (void **)&pRunnable); | |
| if (FAILED(hr)) | |
| return TRUE; | |
| running = IRunnableObject_IsRunning(pRunnable); | |
| IRunnableObject_Release(pRunnable); | |
| return running; | |
| } | |
| /*********************************************************************** | |
| * OleNoteObjectVisible [OLE32.@] | |
| */ | |
| HRESULT WINAPI OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL bVisible) | |
| { | |
| TRACE("(%p, %s)\n", pUnknown, bVisible ? "TRUE" : "FALSE"); | |
| return CoLockObjectExternal(pUnknown, bVisible, TRUE); | |
| } | |
| /*********************************************************************** | |
| * OLE_FreeClipDataArray [internal] | |
| * | |
| * NOTES: | |
| * frees the data associated with an array of CLIPDATAs | |
| */ | |
| static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray) | |
| { | |
| ULONG i; | |
| for (i = 0; i < count; i++) | |
| if (pClipDataArray[i].pClipData) | |
| CoTaskMemFree(pClipDataArray[i].pClipData); | |
| } | |
| /*********************************************************************** | |
| * PropSysAllocString [OLE32.@] | |
| * NOTES: | |
| * Basically a copy of SysAllocStringLen. | |
| */ | |
| BSTR WINAPI PropSysAllocString(LPCOLESTR str) | |
| { | |
| DWORD bufferSize; | |
| DWORD* newBuffer; | |
| WCHAR* stringBuffer; | |
| int len; | |
| if (!str) return 0; | |
| len = lstrlenW(str); | |
| /* | |
| * Find the length of the buffer passed-in, in bytes. | |
| */ | |
| bufferSize = len * sizeof (WCHAR); | |
| /* | |
| * Allocate a new buffer to hold the string. | |
| * Don't forget to keep an empty spot at the beginning of the | |
| * buffer for the character count and an extra character at the | |
| * end for the NULL. | |
| */ | |
| newBuffer = HeapAlloc(GetProcessHeap(), 0, | |
| bufferSize + sizeof(WCHAR) + sizeof(DWORD)); | |
| /* | |
| * If the memory allocation failed, return a null pointer. | |
| */ | |
| if (newBuffer==0) | |
| return 0; | |
| /* | |
| * Copy the length of the string in the placeholder. | |
| */ | |
| *newBuffer = bufferSize; | |
| /* | |
| * Skip the byte count. | |
| */ | |
| newBuffer++; | |
| memcpy(newBuffer, str, bufferSize); | |
| /* | |
| * Make sure that there is a nul character at the end of the | |
| * string. | |
| */ | |
| stringBuffer = (WCHAR*)newBuffer; | |
| stringBuffer[len] = '\0'; | |
| return stringBuffer; | |
| } | |
| /*********************************************************************** | |
| * PropSysFreeString [OLE32.@] | |
| * NOTES | |
| * Copy of SysFreeString. | |
| */ | |
| void WINAPI PropSysFreeString(LPOLESTR str) | |
| { | |
| DWORD* bufferPointer; | |
| /* NULL is a valid parameter */ | |
| if(!str) return; | |
| /* | |
| * We have to be careful when we free a BSTR pointer, it points to | |
| * the beginning of the string but it skips the byte count contained | |
| * before the string. | |
| */ | |
| bufferPointer = (DWORD*)str; | |
| bufferPointer--; | |
| /* | |
| * Free the memory from its "real" origin. | |
| */ | |
| HeapFree(GetProcessHeap(), 0, bufferPointer); | |
| } | |
| /****************************************************************************** | |
| * Check if a PROPVARIANT's type is valid. | |
| */ | |
| static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt) | |
| { | |
| switch (vt) | |
| { | |
| case VT_EMPTY: | |
| case VT_NULL: | |
| case VT_I2: | |
| case VT_I4: | |
| case VT_R4: | |
| case VT_R8: | |
| case VT_CY: | |
| case VT_DATE: | |
| case VT_BSTR: | |
| case VT_ERROR: | |
| case VT_BOOL: | |
| case VT_DECIMAL: | |
| case VT_UI1: | |
| case VT_UI2: | |
| case VT_UI4: | |
| case VT_I8: | |
| case VT_UI8: | |
| case VT_LPSTR: | |
| case VT_LPWSTR: | |
| case VT_FILETIME: | |
| case VT_BLOB: | |
| case VT_STREAM: | |
| case VT_STORAGE: | |
| case VT_STREAMED_OBJECT: | |
| case VT_STORED_OBJECT: | |
| case VT_BLOB_OBJECT: | |
| case VT_CF: | |
| case VT_CLSID: | |
| case VT_I2|VT_VECTOR: | |
| case VT_I4|VT_VECTOR: | |
| case VT_R4|VT_VECTOR: | |
| case VT_R8|VT_VECTOR: | |
| case VT_CY|VT_VECTOR: | |
| case VT_DATE|VT_VECTOR: | |
| case VT_BSTR|VT_VECTOR: | |
| case VT_ERROR|VT_VECTOR: | |
| case VT_BOOL|VT_VECTOR: | |
| case VT_VARIANT|VT_VECTOR: | |
| case VT_UI1|VT_VECTOR: | |
| case VT_UI2|VT_VECTOR: | |
| case VT_UI4|VT_VECTOR: | |
| case VT_I8|VT_VECTOR: | |
| case VT_UI8|VT_VECTOR: | |
| case VT_LPSTR|VT_VECTOR: | |
| case VT_LPWSTR|VT_VECTOR: | |
| case VT_FILETIME|VT_VECTOR: | |
| case VT_CF|VT_VECTOR: | |
| case VT_CLSID|VT_VECTOR: | |
| return S_OK; | |
| } | |
| WARN("Bad type %d\n", vt); | |
| return STG_E_INVALIDPARAMETER; | |
| } | |
| /*********************************************************************** | |
| * PropVariantClear [OLE32.@] | |
| */ | |
| HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */ | |
| { | |
| HRESULT hr; | |
| TRACE("(%p)\n", pvar); | |
| if (!pvar) | |
| return S_OK; | |
| hr = PROPVARIANT_ValidateType(pvar->vt); | |
| if (FAILED(hr)) | |
| return hr; | |
| switch(pvar->vt) | |
| { | |
| case VT_EMPTY: | |
| case VT_NULL: | |
| case VT_I2: | |
| case VT_I4: | |
| case VT_R4: | |
| case VT_R8: | |
| case VT_CY: | |
| case VT_DATE: | |
| case VT_ERROR: | |
| case VT_BOOL: | |
| case VT_DECIMAL: | |
| case VT_UI1: | |
| case VT_UI2: | |
| case VT_UI4: | |
| case VT_I8: | |
| case VT_UI8: | |
| case VT_FILETIME: | |
| break; | |
| case VT_STREAM: | |
| case VT_STREAMED_OBJECT: | |
| case VT_STORAGE: | |
| case VT_STORED_OBJECT: | |
| if (pvar->u.pStream) | |
| IUnknown_Release(pvar->u.pStream); | |
| break; | |
| case VT_CLSID: | |
| case VT_LPSTR: | |
| case VT_LPWSTR: | |
| /* pick an arbitrary typed pointer - we don't care about the type | |
| * as we are just freeing it */ | |
| CoTaskMemFree(pvar->u.puuid); | |
| break; | |
| case VT_BLOB: | |
| case VT_BLOB_OBJECT: | |
| CoTaskMemFree(pvar->u.blob.pBlobData); | |
| break; | |
| case VT_BSTR: | |
| if (pvar->u.bstrVal) | |
| PropSysFreeString(pvar->u.bstrVal); | |
| break; | |
| case VT_CF: | |
| if (pvar->u.pclipdata) | |
| { | |
| OLE_FreeClipDataArray(1, pvar->u.pclipdata); | |
| CoTaskMemFree(pvar->u.pclipdata); | |
| } | |
| break; | |
| default: | |
| if (pvar->vt & VT_VECTOR) | |
| { | |
| ULONG i; | |
| switch (pvar->vt & ~VT_VECTOR) | |
| { | |
| case VT_VARIANT: | |
| FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems); | |
| break; | |
| case VT_CF: | |
| OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems); | |
| break; | |
| case VT_BSTR: | |
| for (i = 0; i < pvar->u.cabstr.cElems; i++) | |
| PropSysFreeString(pvar->u.cabstr.pElems[i]); | |
| break; | |
| case VT_LPSTR: | |
| for (i = 0; i < pvar->u.calpstr.cElems; i++) | |
| CoTaskMemFree(pvar->u.calpstr.pElems[i]); | |
| break; | |
| case VT_LPWSTR: | |
| for (i = 0; i < pvar->u.calpwstr.cElems; i++) | |
| CoTaskMemFree(pvar->u.calpwstr.pElems[i]); | |
| break; | |
| } | |
| if (pvar->vt & ~VT_VECTOR) | |
| { | |
| /* pick an arbitrary VT_VECTOR structure - they all have the same | |
| * memory layout */ | |
| CoTaskMemFree(pvar->u.capropvar.pElems); | |
| } | |
| } | |
| else | |
| WARN("Invalid/unsupported type %d\n", pvar->vt); | |
| } | |
| ZeroMemory(pvar, sizeof(*pvar)); | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * PropVariantCopy [OLE32.@] | |
| */ | |
| HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, /* [out] */ | |
| const PROPVARIANT *pvarSrc) /* [in] */ | |
| { | |
| ULONG len; | |
| HRESULT hr; | |
| TRACE("(%p, %p vt %04x)\n", pvarDest, pvarSrc, pvarSrc->vt); | |
| hr = PROPVARIANT_ValidateType(pvarSrc->vt); | |
| if (FAILED(hr)) | |
| return hr; | |
| /* this will deal with most cases */ | |
| *pvarDest = *pvarSrc; | |
| switch(pvarSrc->vt) | |
| { | |
| case VT_EMPTY: | |
| case VT_NULL: | |
| case VT_I1: | |
| case VT_UI1: | |
| case VT_I2: | |
| case VT_UI2: | |
| case VT_BOOL: | |
| case VT_DECIMAL: | |
| case VT_I4: | |
| case VT_UI4: | |
| case VT_R4: | |
| case VT_ERROR: | |
| case VT_I8: | |
| case VT_UI8: | |
| case VT_R8: | |
| case VT_CY: | |
| case VT_DATE: | |
| case VT_FILETIME: | |
| break; | |
| case VT_STREAM: | |
| case VT_STREAMED_OBJECT: | |
| case VT_STORAGE: | |
| case VT_STORED_OBJECT: | |
| IUnknown_AddRef((LPUNKNOWN)pvarDest->u.pStream); | |
| break; | |
| case VT_CLSID: | |
| pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID)); | |
| *pvarDest->u.puuid = *pvarSrc->u.puuid; | |
| break; | |
| case VT_LPSTR: | |
| len = strlen(pvarSrc->u.pszVal); | |
| pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR)); | |
| CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR)); | |
| break; | |
| case VT_LPWSTR: | |
| len = lstrlenW(pvarSrc->u.pwszVal); | |
| pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR)); | |
| CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR)); | |
| break; | |
| case VT_BLOB: | |
| case VT_BLOB_OBJECT: | |
| if (pvarSrc->u.blob.pBlobData) | |
| { | |
| len = pvarSrc->u.blob.cbSize; | |
| pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len); | |
| CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len); | |
| } | |
| break; | |
| case VT_BSTR: | |
| pvarDest->u.bstrVal = PropSysAllocString(pvarSrc->u.bstrVal); | |
| break; | |
| case VT_CF: | |
| if (pvarSrc->u.pclipdata) | |
| { | |
| len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt); | |
| pvarDest->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA)); | |
| pvarDest->u.pclipdata->cbSize = pvarSrc->u.pclipdata->cbSize; | |
| pvarDest->u.pclipdata->ulClipFmt = pvarSrc->u.pclipdata->ulClipFmt; | |
| pvarDest->u.pclipdata->pClipData = CoTaskMemAlloc(len); | |
| CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len); | |
| } | |
| break; | |
| default: | |
| if (pvarSrc->vt & VT_VECTOR) | |
| { | |
| int elemSize; | |
| ULONG i; | |
| switch(pvarSrc->vt & ~VT_VECTOR) | |
| { | |
| case VT_I1: elemSize = sizeof(pvarSrc->u.cVal); break; | |
| case VT_UI1: elemSize = sizeof(pvarSrc->u.bVal); break; | |
| case VT_I2: elemSize = sizeof(pvarSrc->u.iVal); break; | |
| case VT_UI2: elemSize = sizeof(pvarSrc->u.uiVal); break; | |
| case VT_BOOL: elemSize = sizeof(pvarSrc->u.boolVal); break; | |
| case VT_I4: elemSize = sizeof(pvarSrc->u.lVal); break; | |
| case VT_UI4: elemSize = sizeof(pvarSrc->u.ulVal); break; | |
| case VT_R4: elemSize = sizeof(pvarSrc->u.fltVal); break; | |
| case VT_R8: elemSize = sizeof(pvarSrc->u.dblVal); break; | |
| case VT_ERROR: elemSize = sizeof(pvarSrc->u.scode); break; | |
| case VT_I8: elemSize = sizeof(pvarSrc->u.hVal); break; | |
| case VT_UI8: elemSize = sizeof(pvarSrc->u.uhVal); break; | |
| case VT_CY: elemSize = sizeof(pvarSrc->u.cyVal); break; | |
| case VT_DATE: elemSize = sizeof(pvarSrc->u.date); break; | |
| case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break; | |
| case VT_CLSID: elemSize = sizeof(*pvarSrc->u.puuid); break; | |
| case VT_CF: elemSize = sizeof(*pvarSrc->u.pclipdata); break; | |
| case VT_BSTR: elemSize = sizeof(pvarSrc->u.bstrVal); break; | |
| case VT_LPSTR: elemSize = sizeof(pvarSrc->u.pszVal); break; | |
| case VT_LPWSTR: elemSize = sizeof(pvarSrc->u.pwszVal); break; | |
| case VT_VARIANT: elemSize = sizeof(*pvarSrc->u.pvarVal); break; | |
| default: | |
| FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR); | |
| return E_INVALIDARG; | |
| } | |
| len = pvarSrc->u.capropvar.cElems; | |
| pvarDest->u.capropvar.pElems = CoTaskMemAlloc(len * elemSize); | |
| if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT)) | |
| { | |
| for (i = 0; i < len; i++) | |
| PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]); | |
| } | |
| else if (pvarSrc->vt == (VT_VECTOR | VT_CF)) | |
| { | |
| FIXME("Copy clipformats\n"); | |
| } | |
| else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR)) | |
| { | |
| for (i = 0; i < len; i++) | |
| pvarDest->u.cabstr.pElems[i] = PropSysAllocString(pvarSrc->u.cabstr.pElems[i]); | |
| } | |
| else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR)) | |
| { | |
| size_t strLen; | |
| for (i = 0; i < len; i++) | |
| { | |
| strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1; | |
| pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen); | |
| memcpy(pvarDest->u.calpstr.pElems[i], | |
| pvarSrc->u.calpstr.pElems[i], strLen); | |
| } | |
| } | |
| else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR)) | |
| { | |
| size_t strLen; | |
| for (i = 0; i < len; i++) | |
| { | |
| strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) * | |
| sizeof(WCHAR); | |
| pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen); | |
| memcpy(pvarDest->u.calpstr.pElems[i], | |
| pvarSrc->u.calpstr.pElems[i], strLen); | |
| } | |
| } | |
| else | |
| CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize); | |
| } | |
| else | |
| WARN("Invalid/unsupported type %d\n", pvarSrc->vt); | |
| } | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * FreePropVariantArray [OLE32.@] | |
| */ | |
| HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */ | |
| PROPVARIANT *rgvars) /* [in/out] */ | |
| { | |
| ULONG i; | |
| TRACE("(%u, %p)\n", cVariants, rgvars); | |
| if (!rgvars) | |
| return E_INVALIDARG; | |
| for(i = 0; i < cVariants; i++) | |
| PropVariantClear(&rgvars[i]); | |
| return S_OK; | |
| } | |
| /****************************************************************************** | |
| * DllDebugObjectRPCHook (OLE32.@) | |
| * turns on and off internal debugging, pointer is only used on macintosh | |
| */ | |
| BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy) | |
| { | |
| FIXME("stub\n"); | |
| return TRUE; | |
| } |