2005-07-31 12:11:56 +00:00
|
|
|
/*
|
|
|
|
* OLE2 library
|
|
|
|
*
|
|
|
|
* Copyright 1995 Martin von Loewis
|
|
|
|
* Copyright 1999 Francis Beaudet
|
|
|
|
* Copyright 1999 Noel Borthwick
|
|
|
|
* Copyright 1999, 2000 Marcus Meissner
|
|
|
|
* Copyright 2005 Juan Lang
|
2011-11-16 17:01:04 +00:00
|
|
|
* Copyright 2011 Adam Martinson for CodeWeavers
|
2005-07-31 12:11:56 +00:00
|
|
|
*
|
|
|
|
* 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
|
2007-04-20 12:23:52 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
|
|
|
|
2018-03-20 11:38:17 +00:00
|
|
|
#include <assert.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#define COBJMACROS
|
|
|
|
#define NONAMELESSUNION
|
|
|
|
|
|
|
|
#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 "compobj_private.h"
|
2016-06-07 10:47:21 +00:00
|
|
|
#include "olestd.h"
|
2018-03-20 11:38:17 +00:00
|
|
|
#include "wine/list.h"
|
|
|
|
|
|
|
|
#include "wine/debug.h"
|
2016-06-07 10:47:21 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
|
|
|
WINE_DECLARE_DEBUG_CHANNEL(accel);
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* These are static/global variables and internal data structures that the
|
2014-04-24 12:14:13 +00:00
|
|
|
* OLE module uses to maintain its state.
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
|
|
|
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 */
|
|
|
|
IDropTarget* curDragTarget;
|
2019-03-15 13:31:13 +00:00
|
|
|
#ifdef __REACTOS__
|
|
|
|
HWND accepterHWND;
|
|
|
|
#endif
|
2005-12-26 23:16:41 +00:00
|
|
|
POINTL curMousePos; /* current position of the mouse in screen coordinates */
|
|
|
|
DWORD dwKeyState; /* current state of the shift and ctrl keys and the mouse buttons */
|
2005-07-31 12:11:56 +00:00
|
|
|
} 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.
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
static LONG OLE_moduleLockCount = 0;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Name of our registered window class.
|
|
|
|
*/
|
2010-05-29 11:34:57 +00:00
|
|
|
static const WCHAR OLEDD_DRAGTRACKERCLASS[] =
|
|
|
|
{'W','i','n','e','D','r','a','g','D','r','o','p','T','r','a','c','k','e','r','3','2',0};
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
2010-05-29 11:34:57 +00:00
|
|
|
* Name of menu descriptor property.
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
2010-05-29 11:34:57 +00:00
|
|
|
static const WCHAR prop_olemenuW[] =
|
|
|
|
{'P','R','O','P','_','O','L','E','M','e','n','u','D','e','s','c','r','i','p','t','o','r',0};
|
|
|
|
|
|
|
|
/* property to store IDropTarget pointer */
|
|
|
|
static const WCHAR prop_oledroptarget[] =
|
|
|
|
{'O','l','e','D','r','o','p','T','a','r','g','e','t','I','n','t','e','r','f','a','c','e',0};
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
/* property to store Marshalled IDropTarget pointer */
|
|
|
|
static const WCHAR prop_marshalleddroptarget[] =
|
|
|
|
{'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};
|
|
|
|
|
2010-05-29 11:34:57 +00:00
|
|
|
static const WCHAR emptyW[] = { 0 };
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/******************************************************************************
|
2008-07-10 09:14:19 +00:00
|
|
|
* These are the prototypes of miscellaneous utility methods
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
|
|
|
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);
|
2007-04-20 12:23:52 +00:00
|
|
|
static BOOL OLEMenu_InstallHooks( DWORD tid );
|
|
|
|
static BOOL OLEMenu_UnInstallHooks( DWORD tid );
|
|
|
|
static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
|
2005-07-31 12:11:56 +00:00
|
|
|
static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
|
2007-04-20 12:23:52 +00:00
|
|
|
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);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* 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
|
|
|
|
*/
|
2010-05-29 11:34:57 +00:00
|
|
|
static void OLEDD_Initialize(void);
|
|
|
|
static LRESULT WINAPI OLEDD_DragTrackerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo);
|
2005-07-31 12:11:56 +00:00
|
|
|
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.@)
|
|
|
|
*/
|
2015-11-17 10:30:40 +00:00
|
|
|
HRESULT WINAPI DECLSPEC_HOTPATCH OleInitialize(LPVOID reserved)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2010-03-10 14:28:56 +00:00
|
|
|
if (!COM_CurrentInfo()->ole_inits)
|
|
|
|
hr = S_OK;
|
2016-03-04 09:25:52 +00:00
|
|
|
else
|
|
|
|
hr = S_FALSE;
|
2010-03-10 14:28:56 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/*
|
|
|
|
* Then, it has to initialize the OLE specific modules.
|
|
|
|
* This includes:
|
|
|
|
* Clipboard
|
|
|
|
* Drag and Drop
|
|
|
|
* Object linking and Embedding
|
|
|
|
* In-place activation
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
if (!COM_CurrentInfo()->ole_inits++ &&
|
|
|
|
InterlockedIncrement(&OLE_moduleLockCount) == 1)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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.@]
|
|
|
|
*/
|
2015-03-09 19:57:38 +00:00
|
|
|
void WINAPI DECLSPEC_HOTPATCH OleUninitialize(void)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
TRACE("()\n");
|
|
|
|
|
2016-03-04 09:25:52 +00:00
|
|
|
if (COM_CurrentInfo()->ole_inits == 0)
|
|
|
|
{
|
|
|
|
WARN("ole_inits is already 0\n");
|
|
|
|
return ;
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
/*
|
|
|
|
* If we hit the bottom of the lock stack, free the libraries.
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
if (!--COM_CurrentInfo()->ole_inits && !InterlockedDecrement(&OLE_moduleLockCount))
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* 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.@]
|
|
|
|
*/
|
2005-08-12 17:19:46 +00:00
|
|
|
HRESULT WINAPI OleInitializeWOW(DWORD x, DWORD y) {
|
2007-04-20 12:23:52 +00:00
|
|
|
FIXME("(0x%08x, 0x%08x),stub!\n",x, y);
|
2005-07-31 12:11:56 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
/*************************************************************
|
|
|
|
* get_droptarget_handle
|
|
|
|
*
|
|
|
|
* Retrieve a handle to the map containing the marshalled IDropTarget.
|
|
|
|
* This handle belongs to the process that called RegisterDragDrop.
|
|
|
|
* See get_droptarget_local_handle().
|
|
|
|
*/
|
|
|
|
static inline HANDLE get_droptarget_handle(HWND hwnd)
|
|
|
|
{
|
|
|
|
return GetPropW(hwnd, prop_marshalleddroptarget);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************
|
|
|
|
* is_droptarget
|
|
|
|
*
|
|
|
|
* Is the window a droptarget.
|
|
|
|
*/
|
|
|
|
static inline BOOL is_droptarget(HWND hwnd)
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
return get_droptarget_handle(hwnd) != 0;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
}
|
|
|
|
|
2019-03-15 13:31:13 +00:00
|
|
|
#ifdef __REACTOS__
|
|
|
|
static inline BOOL is_acceptfiles(HWND hwnd)
|
|
|
|
{
|
|
|
|
return !!(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_ACCEPTFILES);
|
|
|
|
}
|
|
|
|
#endif
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
/*************************************************************
|
|
|
|
* get_droptarget_local_handle
|
|
|
|
*
|
|
|
|
* Retrieve a handle to the map containing the marshalled IDropTarget.
|
|
|
|
* The handle should be closed when finished with.
|
|
|
|
*/
|
|
|
|
static HANDLE get_droptarget_local_handle(HWND hwnd)
|
|
|
|
{
|
|
|
|
HANDLE handle, local_handle = 0;
|
|
|
|
|
|
|
|
handle = get_droptarget_handle(hwnd);
|
|
|
|
|
|
|
|
if(handle)
|
|
|
|
{
|
|
|
|
DWORD pid;
|
|
|
|
HANDLE process;
|
|
|
|
|
|
|
|
GetWindowThreadProcessId(hwnd, &pid);
|
|
|
|
process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
|
|
|
|
if(process)
|
|
|
|
{
|
|
|
|
DuplicateHandle(process, handle, GetCurrentProcess(), &local_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
|
|
CloseHandle(process);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return local_handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* create_map_from_stream
|
|
|
|
*
|
|
|
|
* Helper for RegisterDragDrop. Creates a file mapping object
|
|
|
|
* with the contents of the provided stream. The stream must
|
|
|
|
* be a global memory backed stream.
|
|
|
|
*/
|
|
|
|
static HRESULT create_map_from_stream(IStream *stream, HANDLE *map)
|
|
|
|
{
|
|
|
|
HGLOBAL hmem;
|
|
|
|
DWORD size;
|
|
|
|
HRESULT hr;
|
|
|
|
void *data;
|
|
|
|
|
|
|
|
hr = GetHGlobalFromStream(stream, &hmem);
|
|
|
|
if(FAILED(hr)) return hr;
|
|
|
|
|
|
|
|
size = GlobalSize(hmem);
|
|
|
|
*map = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL);
|
|
|
|
if(!*map) return E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
data = MapViewOfFile(*map, FILE_MAP_WRITE, 0, 0, size);
|
|
|
|
memcpy(data, GlobalLock(hmem), size);
|
|
|
|
GlobalUnlock(hmem);
|
|
|
|
UnmapViewOfFile(data);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* create_stream_from_map
|
|
|
|
*
|
|
|
|
* Creates a stream from the provided map.
|
|
|
|
*/
|
|
|
|
static HRESULT create_stream_from_map(HANDLE map, IStream **stream)
|
|
|
|
{
|
|
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
HGLOBAL hmem;
|
|
|
|
void *data;
|
|
|
|
MEMORY_BASIC_INFORMATION info;
|
|
|
|
|
|
|
|
data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
|
|
|
|
if(!data) return hr;
|
|
|
|
|
|
|
|
VirtualQuery(data, &info, sizeof(info));
|
|
|
|
TRACE("size %d\n", (int)info.RegionSize);
|
|
|
|
|
|
|
|
hmem = GlobalAlloc(GMEM_MOVEABLE, info.RegionSize);
|
|
|
|
if(hmem)
|
|
|
|
{
|
|
|
|
memcpy(GlobalLock(hmem), data, info.RegionSize);
|
|
|
|
GlobalUnlock(hmem);
|
|
|
|
hr = CreateStreamOnHGlobal(hmem, TRUE, stream);
|
|
|
|
}
|
|
|
|
UnmapViewOfFile(data);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
2011-11-16 17:01:04 +00:00
|
|
|
/* This is to work around apps which break COM rules by not implementing
|
|
|
|
* IDropTarget::QueryInterface(). Windows doesn't expose this because it
|
|
|
|
* doesn't call CoMarshallInterface() in RegisterDragDrop().
|
|
|
|
* The wrapper is only used internally, and only exists for the life of
|
2012-05-17 15:16:51 +00:00
|
|
|
* the marshal. We don't want to hold a ref on the app provided target
|
|
|
|
* as some apps destroy this prior to CoUninitialize without calling
|
|
|
|
* RevokeDragDrop. The only (long-term) ref is held by the window prop. */
|
2011-11-16 17:01:04 +00:00
|
|
|
typedef struct {
|
|
|
|
IDropTarget IDropTarget_iface;
|
2012-05-17 15:16:51 +00:00
|
|
|
HWND hwnd;
|
2011-11-16 17:01:04 +00:00
|
|
|
LONG refs;
|
|
|
|
} DropTargetWrapper;
|
|
|
|
|
|
|
|
static inline DropTargetWrapper* impl_from_IDropTarget(IDropTarget* iface)
|
|
|
|
{
|
|
|
|
return CONTAINING_RECORD(iface, DropTargetWrapper, IDropTarget_iface);
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI DropTargetWrapper_QueryInterface(IDropTarget* iface,
|
|
|
|
REFIID riid,
|
|
|
|
void** ppvObject)
|
|
|
|
{
|
|
|
|
DropTargetWrapper* This = impl_from_IDropTarget(iface);
|
|
|
|
if (IsEqualIID(riid, &IID_IUnknown) ||
|
|
|
|
IsEqualIID(riid, &IID_IDropTarget))
|
|
|
|
{
|
|
|
|
IDropTarget_AddRef(&This->IDropTarget_iface);
|
|
|
|
*ppvObject = &This->IDropTarget_iface;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
*ppvObject = NULL;
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI DropTargetWrapper_AddRef(IDropTarget* iface)
|
|
|
|
{
|
|
|
|
DropTargetWrapper* This = impl_from_IDropTarget(iface);
|
|
|
|
return InterlockedIncrement(&This->refs);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI DropTargetWrapper_Release(IDropTarget* iface)
|
|
|
|
{
|
|
|
|
DropTargetWrapper* This = impl_from_IDropTarget(iface);
|
|
|
|
ULONG refs = InterlockedDecrement(&This->refs);
|
2012-05-17 15:16:51 +00:00
|
|
|
if (!refs) HeapFree(GetProcessHeap(), 0, This);
|
2011-11-16 17:01:04 +00:00
|
|
|
return refs;
|
|
|
|
}
|
|
|
|
|
2012-05-17 15:16:51 +00:00
|
|
|
static inline HRESULT get_target_from_wrapper( IDropTarget *wrapper, IDropTarget **target )
|
|
|
|
{
|
|
|
|
DropTargetWrapper* This = impl_from_IDropTarget( wrapper );
|
|
|
|
*target = GetPropW( This->hwnd, prop_oledroptarget );
|
|
|
|
if (!*target) return DRAGDROP_E_NOTREGISTERED;
|
|
|
|
IDropTarget_AddRef( *target );
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2011-11-16 17:01:04 +00:00
|
|
|
static HRESULT WINAPI DropTargetWrapper_DragEnter(IDropTarget* iface,
|
|
|
|
IDataObject* pDataObj,
|
|
|
|
DWORD grfKeyState,
|
|
|
|
POINTL pt,
|
|
|
|
DWORD* pdwEffect)
|
|
|
|
{
|
2012-05-17 15:16:51 +00:00
|
|
|
IDropTarget *target;
|
|
|
|
HRESULT r = get_target_from_wrapper( iface, &target );
|
|
|
|
|
|
|
|
if (SUCCEEDED( r ))
|
|
|
|
{
|
|
|
|
r = IDropTarget_DragEnter( target, pDataObj, grfKeyState, pt, pdwEffect );
|
|
|
|
IDropTarget_Release( target );
|
|
|
|
}
|
|
|
|
return r;
|
2011-11-16 17:01:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI DropTargetWrapper_DragOver(IDropTarget* iface,
|
|
|
|
DWORD grfKeyState,
|
|
|
|
POINTL pt,
|
|
|
|
DWORD* pdwEffect)
|
|
|
|
{
|
2012-05-17 15:16:51 +00:00
|
|
|
IDropTarget *target;
|
|
|
|
HRESULT r = get_target_from_wrapper( iface, &target );
|
|
|
|
|
|
|
|
if (SUCCEEDED( r ))
|
|
|
|
{
|
|
|
|
r = IDropTarget_DragOver( target, grfKeyState, pt, pdwEffect );
|
|
|
|
IDropTarget_Release( target );
|
|
|
|
}
|
|
|
|
return r;
|
2011-11-16 17:01:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI DropTargetWrapper_DragLeave(IDropTarget* iface)
|
|
|
|
{
|
2012-05-17 15:16:51 +00:00
|
|
|
IDropTarget *target;
|
|
|
|
HRESULT r = get_target_from_wrapper( iface, &target );
|
|
|
|
|
|
|
|
if (SUCCEEDED( r ))
|
|
|
|
{
|
|
|
|
r = IDropTarget_DragLeave( target );
|
|
|
|
IDropTarget_Release( target );
|
|
|
|
}
|
|
|
|
return r;
|
2011-11-16 17:01:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI DropTargetWrapper_Drop(IDropTarget* iface,
|
|
|
|
IDataObject* pDataObj,
|
|
|
|
DWORD grfKeyState,
|
|
|
|
POINTL pt,
|
|
|
|
DWORD* pdwEffect)
|
|
|
|
{
|
2012-05-17 15:16:51 +00:00
|
|
|
IDropTarget *target;
|
|
|
|
HRESULT r = get_target_from_wrapper( iface, &target );
|
|
|
|
|
|
|
|
if (SUCCEEDED( r ))
|
|
|
|
{
|
|
|
|
r = IDropTarget_Drop( target, pDataObj, grfKeyState, pt, pdwEffect );
|
|
|
|
IDropTarget_Release( target );
|
|
|
|
}
|
|
|
|
return r;
|
2011-11-16 17:01:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const IDropTargetVtbl DropTargetWrapperVTbl =
|
|
|
|
{
|
|
|
|
DropTargetWrapper_QueryInterface,
|
|
|
|
DropTargetWrapper_AddRef,
|
|
|
|
DropTargetWrapper_Release,
|
|
|
|
DropTargetWrapper_DragEnter,
|
|
|
|
DropTargetWrapper_DragOver,
|
|
|
|
DropTargetWrapper_DragLeave,
|
|
|
|
DropTargetWrapper_Drop
|
|
|
|
};
|
|
|
|
|
2012-05-17 15:16:51 +00:00
|
|
|
static IDropTarget* WrapDropTarget( HWND hwnd )
|
2011-11-16 17:01:04 +00:00
|
|
|
{
|
|
|
|
DropTargetWrapper* This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
|
|
|
|
|
|
|
|
if (This)
|
|
|
|
{
|
|
|
|
This->IDropTarget_iface.lpVtbl = &DropTargetWrapperVTbl;
|
2012-05-17 15:16:51 +00:00
|
|
|
This->hwnd = hwnd;
|
2011-11-16 17:01:04 +00:00
|
|
|
This->refs = 1;
|
|
|
|
}
|
|
|
|
return &This->IDropTarget_iface;
|
|
|
|
}
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
/***********************************************************************
|
|
|
|
* get_droptarget_pointer
|
2010-05-29 11:34:57 +00:00
|
|
|
*
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
* Retrieves the marshalled IDropTarget from the window.
|
2010-05-29 11:34:57 +00:00
|
|
|
*/
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
static IDropTarget* get_droptarget_pointer(HWND hwnd)
|
2010-05-29 11:34:57 +00:00
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
IDropTarget *droptarget = NULL;
|
|
|
|
HANDLE map;
|
|
|
|
IStream *stream;
|
|
|
|
|
|
|
|
map = get_droptarget_local_handle(hwnd);
|
|
|
|
if(!map) return NULL;
|
|
|
|
|
|
|
|
if(SUCCEEDED(create_stream_from_map(map, &stream)))
|
|
|
|
{
|
|
|
|
CoUnmarshalInterface(stream, &IID_IDropTarget, (void**)&droptarget);
|
|
|
|
IStream_Release(stream);
|
|
|
|
}
|
|
|
|
CloseHandle(map);
|
|
|
|
return droptarget;
|
2010-05-29 11:34:57 +00:00
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/***********************************************************************
|
|
|
|
* RegisterDragDrop (OLE32.@)
|
|
|
|
*/
|
2010-05-29 11:34:57 +00:00
|
|
|
HRESULT WINAPI RegisterDragDrop(HWND hwnd, LPDROPTARGET pDropTarget)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2010-05-29 11:34:57 +00:00
|
|
|
DWORD pid = 0;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
HRESULT hr;
|
|
|
|
IStream *stream;
|
|
|
|
HANDLE map;
|
2011-11-16 17:01:04 +00:00
|
|
|
IDropTarget *wrapper;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
TRACE("(%p,%p)\n", hwnd, pDropTarget);
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
if (!COM_CurrentApt())
|
|
|
|
{
|
|
|
|
ERR("COM not initialized\n");
|
2008-01-14 15:45:45 +00:00
|
|
|
return E_OUTOFMEMORY;
|
2007-04-20 12:23:52 +00:00
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
if (!pDropTarget)
|
|
|
|
return E_INVALIDARG;
|
2007-04-20 12:23:52 +00:00
|
|
|
|
|
|
|
if (!IsWindow(hwnd))
|
|
|
|
{
|
|
|
|
ERR("invalid hwnd %p\n", hwnd);
|
|
|
|
return DRAGDROP_E_INVALIDHWND;
|
|
|
|
}
|
|
|
|
|
2010-05-29 11:34:57 +00:00
|
|
|
/* block register for other processes windows */
|
|
|
|
GetWindowThreadProcessId(hwnd, &pid);
|
|
|
|
if (pid != GetCurrentProcessId())
|
|
|
|
{
|
|
|
|
FIXME("register for another process windows is disabled\n");
|
|
|
|
return DRAGDROP_E_INVALIDHWND;
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2010-05-29 11:34:57 +00:00
|
|
|
/* check if the window is already registered */
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (is_droptarget(hwnd))
|
2005-07-31 12:11:56 +00:00
|
|
|
return DRAGDROP_E_ALREADYREGISTERED;
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
/*
|
|
|
|
* Marshal the drop target pointer into a shared memory map and
|
|
|
|
* store the map's handle in a Wine specific window prop. We also
|
|
|
|
* store the drop target pointer itself in the
|
|
|
|
* "OleDropTargetInterface" prop for compatibility with Windows.
|
|
|
|
*/
|
2005-07-31 12:11:56 +00:00
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
|
|
|
|
if(FAILED(hr)) return hr;
|
|
|
|
|
2011-11-16 17:01:04 +00:00
|
|
|
/* IDropTarget::QueryInterface() shouldn't be called, some (broken) apps depend on this. */
|
2012-05-17 15:16:51 +00:00
|
|
|
wrapper = WrapDropTarget( hwnd );
|
2011-11-16 17:01:04 +00:00
|
|
|
if(!wrapper)
|
2010-08-05 21:19:46 +00:00
|
|
|
{
|
2011-11-16 17:01:04 +00:00
|
|
|
IStream_Release(stream);
|
|
|
|
return E_OUTOFMEMORY;
|
2010-08-05 21:19:46 +00:00
|
|
|
}
|
2011-11-16 17:01:04 +00:00
|
|
|
hr = CoMarshalInterface(stream, &IID_IDropTarget, (IUnknown*)wrapper, MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
|
|
|
|
IDropTarget_Release(wrapper);
|
2010-08-05 21:19:46 +00:00
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if(SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
hr = create_map_from_stream(stream, &map);
|
|
|
|
if(SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
IDropTarget_AddRef(pDropTarget);
|
|
|
|
SetPropW(hwnd, prop_oledroptarget, pDropTarget);
|
|
|
|
SetPropW(hwnd, prop_marshalleddroptarget, map);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LARGE_INTEGER zero;
|
|
|
|
zero.QuadPart = 0;
|
|
|
|
IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
|
|
|
|
CoReleaseMarshalData(stream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
IStream_Release(stream);
|
|
|
|
|
|
|
|
return hr;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* RevokeDragDrop (OLE32.@)
|
|
|
|
*/
|
2010-05-29 11:34:57 +00:00
|
|
|
HRESULT WINAPI RevokeDragDrop(HWND hwnd)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
HANDLE map;
|
|
|
|
IStream *stream;
|
|
|
|
IDropTarget *drop_target;
|
|
|
|
HRESULT hr;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
TRACE("(%p)\n", hwnd);
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
if (!IsWindow(hwnd))
|
|
|
|
{
|
|
|
|
ERR("invalid hwnd %p\n", hwnd);
|
|
|
|
return DRAGDROP_E_INVALIDHWND;
|
|
|
|
}
|
|
|
|
|
2010-05-29 11:34:57 +00:00
|
|
|
/* no registration data */
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (!(map = get_droptarget_handle(hwnd)))
|
2005-07-31 12:11:56 +00:00
|
|
|
return DRAGDROP_E_NOTREGISTERED;
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
drop_target = GetPropW(hwnd, prop_oledroptarget);
|
|
|
|
if(drop_target) IDropTarget_Release(drop_target);
|
|
|
|
|
2010-05-29 11:34:57 +00:00
|
|
|
RemovePropW(hwnd, prop_oledroptarget);
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
RemovePropW(hwnd, prop_marshalleddroptarget);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
hr = create_stream_from_map(map, &stream);
|
|
|
|
if(SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
CoReleaseMarshalData(stream);
|
|
|
|
IStream_Release(stream);
|
|
|
|
}
|
|
|
|
CloseHandle(map);
|
|
|
|
|
|
|
|
return hr;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* OleRegGetUserType (OLE32.@)
|
|
|
|
*/
|
2016-03-04 09:25:52 +00:00
|
|
|
HRESULT WINAPI OleRegGetUserType(REFCLSID clsid, DWORD form, LPOLESTR *usertype)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2016-03-04 09:25:52 +00:00
|
|
|
static const WCHAR auxusertypeW[] = {'A','u','x','U','s','e','r','T','y','p','e','\\','%','d',0};
|
|
|
|
DWORD valuetype, valuelen;
|
|
|
|
WCHAR auxkeynameW[16];
|
|
|
|
HKEY usertypekey;
|
|
|
|
HRESULT hres;
|
|
|
|
LONG ret;
|
2010-05-29 11:34:57 +00:00
|
|
|
|
2016-03-04 09:25:52 +00:00
|
|
|
TRACE("(%s, %u, %p)\n", debugstr_guid(clsid), form, usertype);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2016-03-04 09:25:52 +00:00
|
|
|
if (!usertype)
|
|
|
|
return E_INVALIDARG;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2016-03-04 09:25:52 +00:00
|
|
|
*usertype = NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2016-03-04 09:25:52 +00:00
|
|
|
/* Return immediately if it's not registered. */
|
|
|
|
hres = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &usertypekey);
|
|
|
|
if (FAILED(hres))
|
|
|
|
return hres;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2016-03-04 09:25:52 +00:00
|
|
|
valuelen = 0;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2016-03-04 09:25:52 +00:00
|
|
|
/* Try additional types if requested. If they don't exist fall back to USERCLASSTYPE_FULL. */
|
|
|
|
if (form != USERCLASSTYPE_FULL)
|
|
|
|
{
|
|
|
|
HKEY auxkey;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2019-11-10 13:10:55 +00:00
|
|
|
swprintf(auxkeynameW, auxusertypeW, form);
|
2016-03-04 09:25:52 +00:00
|
|
|
if (COM_OpenKeyForCLSID(clsid, auxkeynameW, KEY_READ, &auxkey) == S_OK)
|
|
|
|
{
|
|
|
|
if (!RegQueryValueExW(auxkey, emptyW, NULL, &valuetype, NULL, &valuelen) && valuelen)
|
|
|
|
{
|
|
|
|
RegCloseKey(usertypekey);
|
|
|
|
usertypekey = auxkey;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
RegCloseKey(auxkey);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
valuelen = 0;
|
|
|
|
if (RegQueryValueExW(usertypekey, emptyW, NULL, &valuetype, NULL, &valuelen))
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2016-03-04 09:25:52 +00:00
|
|
|
RegCloseKey(usertypekey);
|
2005-07-31 12:11:56 +00:00
|
|
|
return REGDB_E_READREGDB;
|
|
|
|
}
|
|
|
|
|
2016-03-04 09:25:52 +00:00
|
|
|
*usertype = CoTaskMemAlloc(valuelen);
|
|
|
|
if (!*usertype)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2016-03-04 09:25:52 +00:00
|
|
|
RegCloseKey(usertypekey);
|
2005-07-31 12:11:56 +00:00
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
|
2016-03-04 09:25:52 +00:00
|
|
|
ret = RegQueryValueExW(usertypekey,
|
2010-05-29 11:34:57 +00:00
|
|
|
emptyW,
|
2005-07-31 12:11:56 +00:00
|
|
|
NULL,
|
2016-03-04 09:25:52 +00:00
|
|
|
&valuetype,
|
|
|
|
(LPBYTE)*usertype,
|
|
|
|
&valuelen);
|
|
|
|
RegCloseKey(usertypekey);
|
|
|
|
if (ret != ERROR_SUCCESS)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2016-03-04 09:25:52 +00:00
|
|
|
CoTaskMemFree(*usertype);
|
|
|
|
*usertype = NULL;
|
2010-05-29 11:34:57 +00:00
|
|
|
return REGDB_E_READREGDB;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 11:34:57 +00:00
|
|
|
return S_OK;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* 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 */
|
|
|
|
{
|
2010-05-29 11:34:57 +00:00
|
|
|
static const WCHAR trackerW[] = {'T','r','a','c','k','e','r','W','i','n','d','o','w',0};
|
2005-07-31 12:11:56 +00:00
|
|
|
TrackerWindowInfo trackerInfo;
|
|
|
|
HWND hwndTrackWindow;
|
|
|
|
MSG msg;
|
|
|
|
|
2012-05-17 15:16:51 +00:00
|
|
|
TRACE("(%p, %p, %08x, %p)\n", pDataObject, pDropSource, dwOKEffect, pdwEffect);
|
2010-05-29 11:34:57 +00:00
|
|
|
|
|
|
|
if (!pDataObject || !pDropSource || !pdwEffect)
|
|
|
|
return E_INVALIDARG;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup the drag n drop tracking window.
|
|
|
|
*/
|
|
|
|
|
|
|
|
trackerInfo.dataObject = pDataObject;
|
|
|
|
trackerInfo.dropSource = pDropSource;
|
|
|
|
trackerInfo.dwOKEffect = dwOKEffect;
|
|
|
|
trackerInfo.pdwEffect = pdwEffect;
|
|
|
|
trackerInfo.trackingDone = FALSE;
|
|
|
|
trackerInfo.escPressed = FALSE;
|
|
|
|
trackerInfo.curTargetHWND = 0;
|
|
|
|
trackerInfo.curDragTarget = 0;
|
2019-03-15 13:31:13 +00:00
|
|
|
#ifdef __REACTOS__
|
|
|
|
trackerInfo.accepterHWND = NULL;
|
|
|
|
#endif
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2010-05-29 11:34:57 +00:00
|
|
|
hwndTrackWindow = CreateWindowW(OLEDD_DRAGTRACKERCLASS, trackerW,
|
2009-03-03 09:12:43 +00:00
|
|
|
WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
|
|
|
|
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0,
|
|
|
|
&trackerInfo);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2010-05-29 11:34:57 +00:00
|
|
|
if (hwndTrackWindow)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Capture the mouse input
|
|
|
|
*/
|
|
|
|
SetCapture(hwndTrackWindow);
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
msg.message = 0;
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/*
|
2008-01-14 15:45:45 +00:00
|
|
|
* Pump messages. All mouse input should go to the capture window.
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
2010-05-29 11:34:57 +00:00
|
|
|
while (!trackerInfo.trackingDone && GetMessageW(&msg, 0, 0, 0) )
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2005-12-26 23:16:41 +00:00
|
|
|
trackerInfo.curMousePos.x = msg.pt.x;
|
|
|
|
trackerInfo.curMousePos.y = msg.pt.y;
|
|
|
|
trackerInfo.dwKeyState = OLEDD_GetButtonState();
|
2008-01-14 15:45:45 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
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.
|
|
|
|
*/
|
2005-12-26 23:16:41 +00:00
|
|
|
OLEDD_TrackStateChange(&trackerInfo);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Dispatch the messages only when it's not a keyboard message.
|
|
|
|
*/
|
2010-05-29 11:34:57 +00:00
|
|
|
DispatchMessageW(&msg);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
/* re-post the quit message to outer message loop */
|
|
|
|
if (msg.message == WM_QUIT)
|
|
|
|
PostQuitMessage(msg.wParam);
|
2005-07-31 12:11:56 +00:00
|
|
|
/*
|
|
|
|
* Destroy the temporary window.
|
|
|
|
*/
|
|
|
|
DestroyWindow(hwndTrackWindow);
|
|
|
|
|
|
|
|
return trackerInfo.returnValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* OleQueryLinkFromData [OLE32.@]
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI OleQueryLinkFromData(
|
|
|
|
IDataObject* pSrcDataObject)
|
|
|
|
{
|
|
|
|
FIXME("(%p),stub!\n", pSrcDataObject);
|
2009-08-24 10:51:15 +00:00
|
|
|
return S_FALSE;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* OleRegGetMiscStatus [OLE32.@]
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI OleRegGetMiscStatus(
|
|
|
|
REFCLSID clsid,
|
|
|
|
DWORD dwAspect,
|
|
|
|
DWORD* pdwStatus)
|
|
|
|
{
|
2010-05-29 11:34:57 +00:00
|
|
|
static const WCHAR miscstatusW[] = {'M','i','s','c','S','t','a','t','u','s',0};
|
|
|
|
static const WCHAR dfmtW[] = {'%','d',0};
|
2016-03-04 09:25:52 +00:00
|
|
|
WCHAR keyName[16];
|
2005-07-31 12:11:56 +00:00
|
|
|
HKEY miscStatusKey;
|
|
|
|
HKEY aspectKey;
|
|
|
|
LONG result;
|
2016-03-04 09:25:52 +00:00
|
|
|
HRESULT hr;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2016-03-04 09:25:52 +00:00
|
|
|
TRACE("(%s, %d, %p)\n", debugstr_guid(clsid), dwAspect, pdwStatus);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2013-09-26 13:58:03 +00:00
|
|
|
if (!pdwStatus) return E_INVALIDARG;
|
|
|
|
|
|
|
|
*pdwStatus = 0;
|
|
|
|
|
2014-04-24 12:14:13 +00:00
|
|
|
if (actctx_get_miscstatus(clsid, dwAspect, pdwStatus)) return S_OK;
|
|
|
|
|
2016-03-04 09:25:52 +00:00
|
|
|
hr = COM_OpenKeyForCLSID(clsid, miscstatusW, KEY_READ, &miscStatusKey);
|
|
|
|
if (FAILED(hr))
|
|
|
|
/* missing key is not a failure */
|
|
|
|
return hr == REGDB_E_KEYMISSING ? S_OK : hr;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Open the key specific to the requested aspect.
|
|
|
|
*/
|
2019-11-10 13:10:55 +00:00
|
|
|
swprintf(keyName, dfmtW, dwAspect);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2016-03-04 09:25:52 +00:00
|
|
|
result = open_classes_key(miscStatusKey, keyName, KEY_READ, &aspectKey);
|
2005-07-31 12:11:56 +00:00
|
|
|
if (result == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
|
|
|
|
RegCloseKey(aspectKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
RegCloseKey(miscStatusKey);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2005-11-20 15:01:10 +00:00
|
|
|
static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum);
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
2011-11-16 17:01:04 +00:00
|
|
|
IEnumOLEVERB IEnumOLEVERB_iface;
|
2005-11-20 15:01:10 +00:00
|
|
|
LONG ref;
|
|
|
|
|
|
|
|
HKEY hkeyVerb;
|
|
|
|
ULONG index;
|
|
|
|
} EnumOLEVERB;
|
|
|
|
|
2011-11-16 17:01:04 +00:00
|
|
|
static inline EnumOLEVERB *impl_from_IEnumOLEVERB(IEnumOLEVERB *iface)
|
|
|
|
{
|
|
|
|
return CONTAINING_RECORD(iface, EnumOLEVERB, IEnumOLEVERB_iface);
|
|
|
|
}
|
|
|
|
|
2005-11-20 15:01:10 +00:00
|
|
|
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))
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
IEnumOLEVERB_AddRef(iface);
|
2005-11-20 15:01:10 +00:00
|
|
|
*ppv = iface;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI EnumOLEVERB_AddRef(
|
|
|
|
IEnumOLEVERB *iface)
|
|
|
|
{
|
2011-11-16 17:01:04 +00:00
|
|
|
EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
|
2005-11-20 15:01:10 +00:00
|
|
|
TRACE("()\n");
|
|
|
|
return InterlockedIncrement(&This->ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG WINAPI EnumOLEVERB_Release(
|
|
|
|
IEnumOLEVERB *iface)
|
|
|
|
{
|
2011-11-16 17:01:04 +00:00
|
|
|
EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
|
2005-11-20 15:01:10 +00:00
|
|
|
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)
|
|
|
|
{
|
2011-11-16 17:01:04 +00:00
|
|
|
EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
|
2005-11-20 15:01:10 +00:00
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched);
|
2005-11-20 15:01:10 +00:00
|
|
|
|
|
|
|
if (pceltFetched)
|
|
|
|
*pceltFetched = 0;
|
|
|
|
|
|
|
|
for (; celt; celt--, rgelt++)
|
|
|
|
{
|
|
|
|
WCHAR wszSubKey[20];
|
|
|
|
LONG cbData;
|
|
|
|
LPWSTR pwszOLEVERB;
|
|
|
|
LPWSTR pwszMenuFlags;
|
|
|
|
LPWSTR pwszAttribs;
|
2019-01-29 12:15:33 +00:00
|
|
|
LONG res = RegEnumKeyW(This->hkeyVerb, This->index, wszSubKey, ARRAY_SIZE(wszSubKey));
|
2005-11-20 15:01:10 +00:00
|
|
|
if (res == ERROR_NO_MORE_ITEMS)
|
|
|
|
{
|
|
|
|
hr = S_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (res != ERROR_SUCCESS)
|
|
|
|
{
|
2007-04-20 12:23:52 +00:00
|
|
|
ERR("RegEnumKeyW failed with error %d\n", res);
|
2005-11-20 15:01:10 +00:00
|
|
|
hr = REGDB_E_READREGDB;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
res = RegQueryValueW(This->hkeyVerb, wszSubKey, NULL, &cbData);
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
{
|
2007-04-20 12:23:52 +00:00
|
|
|
ERR("RegQueryValueW failed with error %d\n", res);
|
2005-11-20 15:01:10 +00:00
|
|
|
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)
|
|
|
|
{
|
2007-04-20 12:23:52 +00:00
|
|
|
ERR("RegQueryValueW failed with error %d\n", res);
|
2005-11-20 15:01:10 +00:00
|
|
|
hr = REGDB_E_READREGDB;
|
|
|
|
CoTaskMemFree(pwszOLEVERB);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("verb string: %s\n", debugstr_w(pwszOLEVERB));
|
2019-11-10 13:10:55 +00:00
|
|
|
pwszMenuFlags = wcschr(pwszOLEVERB, ',');
|
2005-11-20 15:01:10 +00:00
|
|
|
if (!pwszMenuFlags)
|
|
|
|
{
|
|
|
|
hr = OLEOBJ_E_INVALIDVERB;
|
|
|
|
CoTaskMemFree(pwszOLEVERB);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* nul terminate the name string and advance to first character */
|
|
|
|
*pwszMenuFlags = '\0';
|
|
|
|
pwszMenuFlags++;
|
2019-11-10 13:10:55 +00:00
|
|
|
pwszAttribs = wcschr(pwszMenuFlags, ',');
|
2005-11-20 15:01:10 +00:00
|
|
|
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 */
|
2019-11-10 13:10:55 +00:00
|
|
|
rgelt->lVerb = wcstol(wszSubKey, NULL, 10);
|
2005-11-20 15:01:10 +00:00
|
|
|
rgelt->lpszVerbName = pwszOLEVERB; /* user should free */
|
2019-11-10 13:10:55 +00:00
|
|
|
rgelt->fuFlags = wcstol(pwszMenuFlags, NULL, 10);
|
|
|
|
rgelt->grfAttribs = wcstol(pwszAttribs, NULL, 10);
|
2005-11-20 15:01:10 +00:00
|
|
|
|
|
|
|
if (pceltFetched)
|
2007-04-20 12:23:52 +00:00
|
|
|
(*pceltFetched)++;
|
2005-11-20 15:01:10 +00:00
|
|
|
This->index++;
|
|
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI EnumOLEVERB_Skip(
|
|
|
|
IEnumOLEVERB *iface, ULONG celt)
|
|
|
|
{
|
2011-11-16 17:01:04 +00:00
|
|
|
EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
|
2005-11-20 15:01:10 +00:00
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("(%d)\n", celt);
|
2005-11-20 15:01:10 +00:00
|
|
|
|
|
|
|
This->index += celt;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI EnumOLEVERB_Reset(
|
|
|
|
IEnumOLEVERB *iface)
|
|
|
|
{
|
2011-11-16 17:01:04 +00:00
|
|
|
EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
|
2005-11-20 15:01:10 +00:00
|
|
|
|
|
|
|
TRACE("()\n");
|
|
|
|
|
|
|
|
This->index = 0;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI EnumOLEVERB_Clone(
|
|
|
|
IEnumOLEVERB *iface,
|
|
|
|
IEnumOLEVERB **ppenum)
|
|
|
|
{
|
2011-11-16 17:01:04 +00:00
|
|
|
EnumOLEVERB *This = impl_from_IEnumOLEVERB(iface);
|
2005-11-20 15:01:10 +00:00
|
|
|
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;
|
|
|
|
}
|
2011-11-16 17:01:04 +00:00
|
|
|
This->IEnumOLEVERB_iface.lpVtbl = &EnumOLEVERB_VTable;
|
2005-11-20 15:01:10 +00:00
|
|
|
This->ref = 1;
|
|
|
|
This->index = index;
|
|
|
|
This->hkeyVerb = hkeyVerb;
|
2011-11-16 17:01:04 +00:00
|
|
|
*ppenum = &This->IEnumOLEVERB_iface;
|
|
|
|
return S_OK;
|
2005-11-20 15:01:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* 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
|
2007-04-20 12:23:52 +00:00
|
|
|
ERR("failed to open Verbs key for CLSID %s with error %d\n",
|
2005-11-20 15:01:10 +00:00
|
|
|
debugstr_guid(clsid), res);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = RegQueryInfoKeyW(hkeyVerb, NULL, NULL, NULL, &dwSubKeys, NULL,
|
|
|
|
NULL, NULL, NULL, NULL, NULL, NULL);
|
|
|
|
if (res != ERROR_SUCCESS)
|
|
|
|
{
|
2007-04-20 12:23:52 +00:00
|
|
|
ERR("failed to get subkey count with error %d\n", GetLastError());
|
2005-11-20 15:01:10 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* OleSetContainedObject [OLE32.@]
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI OleSetContainedObject(
|
|
|
|
LPUNKNOWN pUnknown,
|
|
|
|
BOOL fContained)
|
|
|
|
{
|
|
|
|
IRunnableObject* runnable = NULL;
|
|
|
|
HRESULT hres;
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("(%p,%x)\n", pUnknown, fContained);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
hres = IUnknown_QueryInterface(pUnknown,
|
|
|
|
&IID_IRunnableObject,
|
|
|
|
(void**)&runnable);
|
|
|
|
|
|
|
|
if (SUCCEEDED(hres))
|
|
|
|
{
|
|
|
|
hres = IRunnableObject_SetContainedObject(runnable, fContained);
|
|
|
|
|
|
|
|
IRunnableObject_Release(runnable);
|
|
|
|
|
|
|
|
return hres;
|
|
|
|
}
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* 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.
|
|
|
|
*/
|
2015-11-17 10:30:40 +00:00
|
|
|
HRESULT WINAPI DECLSPEC_HOTPATCH OleRun(LPUNKNOWN pUnknown)
|
2007-04-20 12:23:52 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* OleLoad [OLE32.@]
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI OleLoad(
|
|
|
|
LPSTORAGE pStg,
|
|
|
|
REFIID riid,
|
|
|
|
LPOLECLIENTSITE pClientSite,
|
|
|
|
LPVOID* ppvObj)
|
|
|
|
{
|
|
|
|
IPersistStorage* persistStorage = NULL;
|
2007-04-20 12:23:52 +00:00
|
|
|
IUnknown* pUnk;
|
|
|
|
IOleObject* pOleObject = NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
STATSTG storageInfo;
|
|
|
|
HRESULT hres;
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("(%p, %s, %p, %p)\n", pStg, debugstr_guid(riid), pClientSite, ppvObj);
|
|
|
|
|
|
|
|
*ppvObj = NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO, Conversion ... OleDoAutoConvert
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the class ID for the object.
|
|
|
|
*/
|
|
|
|
hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
|
2015-07-19 23:10:53 +00:00
|
|
|
if (FAILED(hres))
|
|
|
|
return hres;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now, try and create the handler for the object
|
|
|
|
*/
|
|
|
|
hres = CoCreateInstance(&storageInfo.clsid,
|
|
|
|
NULL,
|
2007-04-20 12:23:52 +00:00
|
|
|
CLSCTX_INPROC_HANDLER|CLSCTX_INPROC_SERVER,
|
|
|
|
riid,
|
|
|
|
(void**)&pUnk);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If that fails, as it will most times, load the default
|
|
|
|
* OLE handler.
|
|
|
|
*/
|
|
|
|
if (FAILED(hres))
|
|
|
|
{
|
|
|
|
hres = OleCreateDefaultHandler(&storageInfo.clsid,
|
|
|
|
NULL,
|
2007-04-20 12:23:52 +00:00
|
|
|
riid,
|
|
|
|
(void**)&pUnk);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we couldn't find a handler... this is bad. Abort the whole thing.
|
|
|
|
*/
|
|
|
|
if (FAILED(hres))
|
|
|
|
return hres;
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
if (pClientSite)
|
|
|
|
{
|
|
|
|
hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (void **)&pOleObject);
|
|
|
|
if (SUCCEEDED(hres))
|
|
|
|
{
|
|
|
|
DWORD dwStatus;
|
|
|
|
hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
|
|
|
|
}
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2011-11-16 17:01:04 +00:00
|
|
|
/*
|
|
|
|
* Initialize the object with its IPersistStorage interface.
|
|
|
|
*/
|
2012-12-12 21:01:41 +00:00
|
|
|
hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (void**)&persistStorage);
|
2005-07-31 12:11:56 +00:00
|
|
|
if (SUCCEEDED(hres))
|
|
|
|
{
|
2007-04-20 12:23:52 +00:00
|
|
|
hres = IPersistStorage_Load(persistStorage, pStg);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
IPersistStorage_Release(persistStorage);
|
|
|
|
persistStorage = NULL;
|
|
|
|
}
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
if (SUCCEEDED(hres) && pClientSite)
|
|
|
|
/*
|
2014-04-24 12:14:13 +00:00
|
|
|
* Inform the new object of its client site.
|
2007-04-20 12:23:52 +00:00
|
|
|
*/
|
|
|
|
hres = IOleObject_SetClientSite(pOleObject, pClientSite);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Cleanup interfaces used internally
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
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;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2010-03-10 14:28:56 +00:00
|
|
|
|
|
|
|
return S_OK;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
* Internal methods to manage the shared OLE menu in response to the
|
|
|
|
* OLE***MenuDescriptor API
|
|
|
|
*/
|
|
|
|
|
|
|
|
/***
|
|
|
|
* OLEMenu_Initialize()
|
|
|
|
*
|
|
|
|
* Initializes the OLEMENU data structures.
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
static void OLEMenu_Initialize(void)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* OLEMenu_UnInitialize()
|
|
|
|
*
|
|
|
|
* Releases the OLEMENU data structures.
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
static void OLEMenu_UnInitialize(void)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* OLEMenu_InstallHooks
|
|
|
|
* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
|
|
|
|
*
|
|
|
|
* RETURNS: TRUE if message hooks were successfully installed
|
|
|
|
* FALSE on failure
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
static BOOL OLEMenu_InstallHooks( DWORD tid )
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2010-05-29 11:34:57 +00:00
|
|
|
OleMenuHookItem *pHookItem;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/* Create an entry for the hook table */
|
|
|
|
if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
|
|
|
|
sizeof(OleMenuHookItem)) ) )
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
pHookItem->tid = tid;
|
|
|
|
pHookItem->hHeap = GetProcessHeap();
|
2010-05-29 11:34:57 +00:00
|
|
|
pHookItem->CallWndProc_hHook = NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/* Install a thread scope message hook for WH_GETMESSAGE */
|
2010-05-29 11:34:57 +00:00
|
|
|
pHookItem->GetMsg_hHook = SetWindowsHookExW( WH_GETMESSAGE, OLEMenu_GetMsgProc,
|
2005-07-31 12:11:56 +00:00
|
|
|
0, GetCurrentThreadId() );
|
|
|
|
if ( !pHookItem->GetMsg_hHook )
|
|
|
|
goto CLEANUP;
|
|
|
|
|
|
|
|
/* Install a thread scope message hook for WH_CALLWNDPROC */
|
2010-05-29 11:34:57 +00:00
|
|
|
pHookItem->CallWndProc_hHook = SetWindowsHookExW( WH_CALLWNDPROC, OLEMenu_CallWndProc,
|
2005-07-31 12:11:56 +00:00
|
|
|
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
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
static BOOL OLEMenu_UnInstallHooks( DWORD tid )
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2010-05-29 11:34:57 +00:00
|
|
|
OleMenuHookItem *pHookItem;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/* 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 )
|
|
|
|
{
|
2008-11-07 11:00:30 +00:00
|
|
|
INT i, nItems;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
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 */
|
2012-12-12 21:01:41 +00:00
|
|
|
pOleMenuDescriptor->bIsServerItem = i%2;
|
2005-07-31 12:11:56 +00:00
|
|
|
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.
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2010-05-29 11:34:57 +00:00
|
|
|
LPCWPSTRUCT pMsg;
|
2005-07-31 12:11:56 +00:00
|
|
|
HOLEMENU hOleMenu = 0;
|
|
|
|
OleMenuDescriptor *pOleMenuDescriptor = NULL;
|
|
|
|
OleMenuHookItem *pHookItem = NULL;
|
|
|
|
WORD fuFlags;
|
|
|
|
|
2007-07-27 09:49:52 +00:00
|
|
|
TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
2010-05-29 11:34:57 +00:00
|
|
|
hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
|
2005-07-31 12:11:56 +00:00
|
|
|
if ( !hOleMenu )
|
|
|
|
goto NEXTHOOK;
|
|
|
|
|
|
|
|
/* Get the menu descriptor */
|
2009-01-15 17:52:35 +00:00
|
|
|
pOleMenuDescriptor = GlobalLock( hOleMenu );
|
2005-07-31 12:11:56 +00:00
|
|
|
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 */
|
2010-05-29 11:34:57 +00:00
|
|
|
SendMessageW( pOleMenuDescriptor->hwndActiveObject,
|
2005-07-31 12:11:56 +00:00
|
|
|
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 )
|
|
|
|
{
|
2010-05-29 11:34:57 +00:00
|
|
|
SendMessageW( pOleMenuDescriptor->hwndActiveObject,
|
2005-07-31 12:11:56 +00:00
|
|
|
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.
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2010-05-29 11:34:57 +00:00
|
|
|
LPMSG pMsg;
|
2005-07-31 12:11:56 +00:00
|
|
|
HOLEMENU hOleMenu = 0;
|
|
|
|
OleMenuDescriptor *pOleMenuDescriptor = NULL;
|
|
|
|
OleMenuHookItem *pHookItem = NULL;
|
|
|
|
WORD wCode;
|
|
|
|
|
2007-07-27 09:49:52 +00:00
|
|
|
TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
2010-05-29 11:34:57 +00:00
|
|
|
hOleMenu = GetPropW( pMsg->hwnd, prop_olemenuW );
|
2005-07-31 12:11:56 +00:00
|
|
|
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 */
|
2009-01-15 17:52:35 +00:00
|
|
|
pOleMenuDescriptor = GlobalLock( hOleMenu );
|
2005-07-31 12:11:56 +00:00
|
|
|
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;
|
|
|
|
|
2009-01-15 17:52:35 +00:00
|
|
|
pOleMenuDescriptor = GlobalLock( hOleMenu );
|
2005-07-31 12:11:56 +00:00
|
|
|
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(
|
2013-03-23 10:35:27 +00:00
|
|
|
HOLEMENU hmenuDescriptor)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2013-03-23 10:35:27 +00:00
|
|
|
if ( hmenuDescriptor )
|
|
|
|
GlobalFree( hmenuDescriptor );
|
|
|
|
return S_OK;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* OleSetMenuDescriptor [OLE32.@]
|
2005-11-20 15:01:10 +00:00
|
|
|
* Installs or removes OLE dispatching code for the containers frame window.
|
2005-07-31 12:11:56 +00:00
|
|
|
*
|
2005-11-20 15:01:10 +00:00
|
|
|
* PARAMS
|
2005-07-31 12:11:56 +00:00
|
|
|
* 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
|
|
|
|
*
|
2005-11-20 15:01:10 +00:00
|
|
|
* RETURNS
|
2005-07-31 12:11:56 +00:00
|
|
|
* S_OK - menu installed correctly
|
|
|
|
* E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
|
2005-11-20 15:01:10 +00:00
|
|
|
*
|
|
|
|
* 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.
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
|
|
|
HRESULT WINAPI OleSetMenuDescriptor(
|
2013-03-23 10:35:27 +00:00
|
|
|
HOLEMENU hOleMenu,
|
|
|
|
HWND hwndFrame,
|
|
|
|
HWND hwndActiveObject,
|
|
|
|
LPOLEINPLACEFRAME lpFrame,
|
|
|
|
LPOLEINPLACEACTIVEOBJECT lpActiveObject)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2013-03-23 10:35:27 +00:00
|
|
|
OleMenuDescriptor *pOleMenuDescriptor = NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2013-03-23 10:35:27 +00:00
|
|
|
/* Check args */
|
|
|
|
if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
|
|
|
|
return E_INVALIDARG;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2013-03-23 10:35:27 +00:00
|
|
|
if ( lpFrame || lpActiveObject )
|
|
|
|
{
|
|
|
|
FIXME("(%p, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",
|
|
|
|
hOleMenu,
|
|
|
|
hwndFrame,
|
|
|
|
hwndActiveObject,
|
|
|
|
lpFrame,
|
|
|
|
lpActiveObject);
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2013-03-23 10:35:27 +00:00
|
|
|
/* 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.
|
|
|
|
*/
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2013-03-23 10:35:27 +00:00
|
|
|
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 */
|
|
|
|
SetPropW( hwndFrame, prop_olemenuW, 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;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2013-03-23 10:35:27 +00:00
|
|
|
/* Remove the menu descriptor property from the frame window */
|
|
|
|
RemovePropW( hwndFrame, prop_olemenuW );
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2013-03-23 10:35:27 +00:00
|
|
|
return S_OK;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* 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 &&
|
2007-07-27 09:49:52 +00:00
|
|
|
lpMsg->message != WM_SYSCHAR &&
|
2005-07-31 12:11:56 +00:00
|
|
|
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,"
|
2007-07-27 09:49:52 +00:00
|
|
|
"msg->hwnd=%p, msg->message=%04x, wParam=%08lx, lParam=%08lx\n",
|
2005-07-31 12:11:56 +00:00
|
|
|
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))
|
|
|
|
{
|
2007-07-27 09:49:52 +00:00
|
|
|
TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", LOWORD(lpMsg->wParam) & 0xff);
|
2005-07-31 12:11:56 +00:00
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(lpAccelTbl[i].fVirt & FVIRTKEY)
|
|
|
|
{
|
|
|
|
INT mask = 0;
|
2007-07-27 09:49:52 +00:00
|
|
|
TRACE_(accel)("found accel for virt_key %04lx (scan %04x)\n",
|
2005-07-31 12:11:56 +00:00
|
|
|
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 */
|
2007-07-27 09:49:52 +00:00
|
|
|
TRACE_(accel)("found accel for Alt-%c\n", LOWORD(lpMsg->wParam) & 0xff);
|
2005-07-31 12:11:56 +00:00
|
|
|
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.
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
static void OLEDD_Initialize(void)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2010-05-29 11:34:57 +00:00
|
|
|
WNDCLASSW wndClass;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2010-05-29 11:34:57 +00:00
|
|
|
ZeroMemory (&wndClass, sizeof(WNDCLASSW));
|
2005-07-31 12:11:56 +00:00
|
|
|
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;
|
|
|
|
|
2010-05-29 11:34:57 +00:00
|
|
|
RegisterClassW (&wndClass);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* 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.
|
|
|
|
*/
|
2005-12-26 23:16:41 +00:00
|
|
|
|
|
|
|
#define DRAG_TIMER_ID 1
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
|
|
|
|
HWND hwnd,
|
|
|
|
UINT uMsg,
|
|
|
|
WPARAM wParam,
|
|
|
|
LPARAM lParam)
|
|
|
|
{
|
|
|
|
switch (uMsg)
|
|
|
|
{
|
|
|
|
case WM_CREATE:
|
|
|
|
{
|
|
|
|
LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
|
|
|
|
|
2010-05-29 11:34:57 +00:00
|
|
|
SetWindowLongPtrW(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams);
|
2005-12-26 23:16:41 +00:00
|
|
|
SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2005-12-26 23:16:41 +00:00
|
|
|
case WM_TIMER:
|
2005-07-31 12:11:56 +00:00
|
|
|
case WM_MOUSEMOVE:
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
case WM_MBUTTONUP:
|
|
|
|
case WM_RBUTTONUP:
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
case WM_MBUTTONDOWN:
|
|
|
|
case WM_RBUTTONDOWN:
|
|
|
|
{
|
2014-10-03 11:44:27 +00:00
|
|
|
TrackerWindowInfo *trackerInfo = (TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0);
|
|
|
|
if (trackerInfo->trackingDone) break;
|
|
|
|
OLEDD_TrackStateChange(trackerInfo);
|
2005-12-26 23:16:41 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
|
|
{
|
|
|
|
KillTimer(hwnd, DRAG_TIMER_ID);
|
2005-07-31 12:11:56 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is a window proc after all. Let's call the default.
|
|
|
|
*/
|
2010-05-29 11:34:57 +00:00
|
|
|
return DefWindowProcW (hwnd, uMsg, wParam, lParam);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
2019-03-15 13:31:13 +00:00
|
|
|
#ifdef __REACTOS__
|
|
|
|
static HRESULT WINAPI DefaultDragEnter(HWND hwndTarget,
|
|
|
|
IDataObject* pDataObj,
|
|
|
|
DWORD grfKeyState,
|
|
|
|
POINTL pt,
|
|
|
|
DWORD* pdwEffect)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
FORMATETC fme;
|
|
|
|
|
|
|
|
ZeroMemory(&fme, sizeof(fme));
|
|
|
|
fme.cfFormat = CF_HDROP;
|
|
|
|
fme.ptd = NULL;
|
|
|
|
fme.dwAspect = DVASPECT_CONTENT;
|
|
|
|
fme.lindex = -1;
|
|
|
|
fme.tymed = TYMED_HGLOBAL;
|
|
|
|
hr = pDataObj->lpVtbl->QueryGetData(pDataObj, &fme);
|
|
|
|
|
|
|
|
*pdwEffect = SUCCEEDED(hr) ? DROPEFFECT_COPY : DROPEFFECT_NONE;
|
|
|
|
|
|
|
|
if (*pdwEffect == DROPEFFECT_NONE)
|
|
|
|
return DRAGDROP_S_CANCEL;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI DefaultDrop(HWND hwndAccepter,
|
|
|
|
IDataObject* pDataObj,
|
|
|
|
DWORD grfKeyState,
|
|
|
|
POINTL pt,
|
|
|
|
DWORD* pdwEffect)
|
|
|
|
{
|
|
|
|
FORMATETC fme;
|
|
|
|
STGMEDIUM stgm;
|
|
|
|
HRESULT hr;
|
|
|
|
HGLOBAL hGlobal = NULL;
|
|
|
|
|
|
|
|
ZeroMemory(&fme, sizeof(fme));
|
|
|
|
fme.cfFormat = CF_HDROP;
|
|
|
|
fme.ptd = NULL;
|
|
|
|
fme.dwAspect = DVASPECT_CONTENT;
|
|
|
|
fme.lindex = -1;
|
|
|
|
fme.tymed = TYMED_HGLOBAL;
|
|
|
|
hr = pDataObj->lpVtbl->QueryGetData(pDataObj, &fme);
|
|
|
|
if (FAILED(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
ZeroMemory(&stgm, sizeof(stgm));
|
|
|
|
hr = pDataObj->lpVtbl->GetData(pDataObj, &fme, &stgm);
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
hGlobal = stgm.DUMMYUNIONNAME.hGlobal;
|
|
|
|
if (hGlobal)
|
|
|
|
{
|
|
|
|
if (IsWindowUnicode(hwndAccepter))
|
|
|
|
PostMessageW(hwndAccepter, WM_DROPFILES, (WPARAM)hGlobal, 0);
|
|
|
|
else
|
|
|
|
PostMessageA(hwndAccepter, WM_DROPFILES, (WPARAM)hGlobal, 0);
|
|
|
|
}
|
|
|
|
ReleaseStgMedium(&stgm);
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-06-07 10:47:21 +00:00
|
|
|
static void drag_enter( TrackerWindowInfo *info, HWND new_target )
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
2019-03-15 13:31:13 +00:00
|
|
|
#ifdef __REACTOS__
|
|
|
|
DWORD dwEffect = *info->pdwEffect;
|
|
|
|
#endif
|
2016-06-07 10:47:21 +00:00
|
|
|
|
|
|
|
info->curTargetHWND = new_target;
|
|
|
|
|
2019-03-15 13:31:13 +00:00
|
|
|
#ifdef __REACTOS__
|
|
|
|
info->accepterHWND = NULL;
|
|
|
|
while (new_target && !is_droptarget( new_target ))
|
|
|
|
{
|
|
|
|
if (is_acceptfiles(new_target))
|
|
|
|
{
|
|
|
|
dwEffect = info->dwOKEffect;
|
|
|
|
hr = DefaultDragEnter(new_target, info->dataObject,
|
|
|
|
info->dwKeyState, info->curMousePos,
|
|
|
|
&dwEffect);
|
|
|
|
dwEffect &= info->dwOKEffect;
|
|
|
|
|
|
|
|
if (hr == S_OK)
|
|
|
|
{
|
|
|
|
info->accepterHWND = new_target;
|
|
|
|
info->curDragTarget = NULL;
|
|
|
|
*info->pdwEffect = dwEffect;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
new_target = GetParent( new_target );
|
|
|
|
}
|
|
|
|
#else
|
2016-06-07 10:47:21 +00:00
|
|
|
while (new_target && !is_droptarget( new_target ))
|
|
|
|
new_target = GetParent( new_target );
|
2019-03-15 13:31:13 +00:00
|
|
|
#endif
|
2016-06-07 10:47:21 +00:00
|
|
|
|
|
|
|
info->curDragTarget = get_droptarget_pointer( new_target );
|
|
|
|
|
|
|
|
if (info->curDragTarget)
|
|
|
|
{
|
|
|
|
*info->pdwEffect = info->dwOKEffect;
|
|
|
|
hr = IDropTarget_DragEnter( info->curDragTarget, info->dataObject,
|
|
|
|
info->dwKeyState, info->curMousePos,
|
|
|
|
info->pdwEffect );
|
|
|
|
*info->pdwEffect &= info->dwOKEffect;
|
|
|
|
|
|
|
|
/* failed DragEnter() means invalid target */
|
|
|
|
if (hr != S_OK)
|
|
|
|
{
|
|
|
|
IDropTarget_Release( info->curDragTarget );
|
|
|
|
info->curDragTarget = NULL;
|
|
|
|
info->curTargetHWND = NULL;
|
2019-03-15 13:31:13 +00:00
|
|
|
#ifdef __REACTOS__
|
|
|
|
info->accepterHWND = NULL;
|
|
|
|
#endif
|
2016-06-07 10:47:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void drag_end( TrackerWindowInfo *info )
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
info->trackingDone = TRUE;
|
|
|
|
ReleaseCapture();
|
|
|
|
|
|
|
|
if (info->curDragTarget)
|
|
|
|
{
|
|
|
|
if (info->returnValue == DRAGDROP_S_DROP &&
|
|
|
|
*info->pdwEffect != DROPEFFECT_NONE)
|
|
|
|
{
|
|
|
|
*info->pdwEffect = info->dwOKEffect;
|
|
|
|
hr = IDropTarget_Drop( info->curDragTarget, info->dataObject, info->dwKeyState,
|
|
|
|
info->curMousePos, info->pdwEffect );
|
|
|
|
*info->pdwEffect &= info->dwOKEffect;
|
|
|
|
|
|
|
|
if (FAILED( hr ))
|
|
|
|
info->returnValue = hr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IDropTarget_DragLeave( info->curDragTarget );
|
|
|
|
*info->pdwEffect = DROPEFFECT_NONE;
|
|
|
|
}
|
|
|
|
IDropTarget_Release( info->curDragTarget );
|
|
|
|
info->curDragTarget = NULL;
|
|
|
|
}
|
2019-03-15 13:31:13 +00:00
|
|
|
#ifdef __REACTOS__
|
|
|
|
else if (info->accepterHWND)
|
|
|
|
{
|
|
|
|
if (info->returnValue == DRAGDROP_S_DROP &&
|
|
|
|
*info->pdwEffect != DROPEFFECT_NONE)
|
|
|
|
{
|
|
|
|
*info->pdwEffect = info->dwOKEffect;
|
|
|
|
hr = DefaultDrop(info->accepterHWND, info->dataObject, info->dwKeyState,
|
|
|
|
info->curMousePos, info->pdwEffect);
|
|
|
|
*info->pdwEffect &= info->dwOKEffect;
|
|
|
|
|
|
|
|
if (FAILED( hr ))
|
|
|
|
info->returnValue = hr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*info->pdwEffect = DROPEFFECT_NONE;
|
|
|
|
}
|
|
|
|
info->accepterHWND = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
2016-06-07 10:47:21 +00:00
|
|
|
else
|
|
|
|
*info->pdwEffect = DROPEFFECT_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT give_feedback( TrackerWindowInfo *info )
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
int res;
|
|
|
|
HCURSOR cur;
|
|
|
|
|
2019-03-15 13:31:13 +00:00
|
|
|
#ifdef __REACTOS__
|
|
|
|
if (info->curDragTarget == NULL && info->accepterHWND == NULL)
|
|
|
|
*info->pdwEffect = DROPEFFECT_NONE;
|
|
|
|
#else
|
2016-06-07 10:47:21 +00:00
|
|
|
if (info->curDragTarget == NULL)
|
|
|
|
*info->pdwEffect = DROPEFFECT_NONE;
|
2019-03-15 13:31:13 +00:00
|
|
|
#endif
|
2016-06-07 10:47:21 +00:00
|
|
|
|
|
|
|
hr = IDropSource_GiveFeedback( info->dropSource, *info->pdwEffect );
|
|
|
|
|
|
|
|
if (hr == DRAGDROP_S_USEDEFAULTCURSORS)
|
|
|
|
{
|
|
|
|
if (*info->pdwEffect & DROPEFFECT_MOVE)
|
|
|
|
res = CURSOR_MOVE;
|
|
|
|
else if (*info->pdwEffect & DROPEFFECT_COPY)
|
|
|
|
res = CURSOR_COPY;
|
|
|
|
else if (*info->pdwEffect & DROPEFFECT_LINK)
|
|
|
|
res = CURSOR_LINK;
|
|
|
|
else
|
|
|
|
res = CURSOR_NODROP;
|
|
|
|
|
|
|
|
cur = LoadCursorW( hProxyDll, MAKEINTRESOURCEW( res ) );
|
|
|
|
SetCursor( cur );
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/***
|
2014-04-24 12:14:13 +00:00
|
|
|
* OLEDD_TrackStateChange()
|
2005-07-31 12:11:56 +00:00
|
|
|
*
|
|
|
|
* This method is invoked while a drag and drop operation is in effect.
|
|
|
|
*
|
|
|
|
* params:
|
|
|
|
* trackerInfo - Pointer to the structure identifying the
|
|
|
|
* drag & drop operation that is currently
|
|
|
|
* active.
|
|
|
|
*/
|
2014-04-24 12:14:13 +00:00
|
|
|
static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
HWND hwndNewTarget = 0;
|
2005-12-26 23:16:41 +00:00
|
|
|
POINT pt;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the handle of the window under the mouse
|
|
|
|
*/
|
2005-12-26 23:16:41 +00:00
|
|
|
pt.x = trackerInfo->curMousePos.x;
|
|
|
|
pt.y = trackerInfo->curMousePos.y;
|
|
|
|
hwndNewTarget = WindowFromPoint(pt);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2014-04-24 12:14:13 +00:00
|
|
|
trackerInfo->returnValue = IDropSource_QueryContinueDrag(trackerInfo->dropSource,
|
|
|
|
trackerInfo->escPressed,
|
|
|
|
trackerInfo->dwKeyState);
|
|
|
|
|
2016-06-07 10:47:21 +00:00
|
|
|
if (trackerInfo->curTargetHWND != hwndNewTarget &&
|
|
|
|
(trackerInfo->returnValue == S_OK ||
|
|
|
|
trackerInfo->returnValue == DRAGDROP_S_DROP))
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2010-05-29 11:34:57 +00:00
|
|
|
if (trackerInfo->curDragTarget)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2016-06-07 10:47:21 +00:00
|
|
|
IDropTarget_DragLeave(trackerInfo->curDragTarget);
|
|
|
|
IDropTarget_Release(trackerInfo->curDragTarget);
|
|
|
|
trackerInfo->curDragTarget = NULL;
|
|
|
|
trackerInfo->curTargetHWND = NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
2019-03-15 13:31:13 +00:00
|
|
|
#ifdef __REACTOS__
|
|
|
|
trackerInfo->accepterHWND = NULL;
|
|
|
|
#endif
|
2005-07-31 12:11:56 +00:00
|
|
|
|
2016-06-07 10:47:21 +00:00
|
|
|
if (hwndNewTarget)
|
|
|
|
drag_enter( trackerInfo, hwndNewTarget );
|
2010-05-29 11:34:57 +00:00
|
|
|
|
2016-06-07 10:47:21 +00:00
|
|
|
give_feedback( trackerInfo );
|
2010-05-29 11:34:57 +00:00
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
2016-06-07 10:47:21 +00:00
|
|
|
if (trackerInfo->returnValue == S_OK)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2010-05-29 11:34:57 +00:00
|
|
|
if (trackerInfo->curDragTarget)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2016-06-07 10:47:21 +00:00
|
|
|
*trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
|
|
|
|
IDropTarget_DragOver(trackerInfo->curDragTarget,
|
|
|
|
trackerInfo->dwKeyState,
|
|
|
|
trackerInfo->curMousePos,
|
|
|
|
trackerInfo->pdwEffect);
|
|
|
|
*trackerInfo->pdwEffect &= trackerInfo->dwOKEffect;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
2019-03-15 13:31:13 +00:00
|
|
|
#ifdef __REACTOS__
|
|
|
|
else if (trackerInfo->accepterHWND)
|
|
|
|
{
|
|
|
|
*trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
|
|
|
|
}
|
|
|
|
#endif
|
2016-06-07 10:47:21 +00:00
|
|
|
give_feedback( trackerInfo );
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
2016-06-07 10:47:21 +00:00
|
|
|
else
|
|
|
|
drag_end( trackerInfo );
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* 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.
|
|
|
|
*/
|
2007-04-20 12:23:52 +00:00
|
|
|
static DWORD OLEDD_GetButtonState(void)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2015-07-19 23:10:53 +00:00
|
|
|
if ( (keyboardState[VK_MENU] & 0x80) !=0)
|
|
|
|
keyMask |= MK_ALT;
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
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)
|
|
|
|
{
|
2010-05-29 11:34:57 +00:00
|
|
|
WCHAR buffer[20];
|
|
|
|
DWORD cbData = sizeof(buffer);
|
2005-07-31 12:11:56 +00:00
|
|
|
DWORD dwKeyType;
|
|
|
|
LONG lres;
|
|
|
|
|
2010-05-29 11:34:57 +00:00
|
|
|
lres = RegQueryValueExW(regKey,
|
|
|
|
emptyW,
|
2005-07-31 12:11:56 +00:00
|
|
|
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:
|
2019-11-10 13:10:55 +00:00
|
|
|
*pdwValue = wcstoul(buffer, NULL, 10);
|
2005-07-31 12:11:56 +00:00
|
|
|
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,
|
2012-12-12 21:01:41 +00:00
|
|
|
LPCRECT rect)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
HRESULT hres;
|
|
|
|
IViewObject *viewobject;
|
|
|
|
|
2012-12-12 21:01:41 +00:00
|
|
|
if (!pUnk) return E_INVALIDARG;
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
hres = IUnknown_QueryInterface(pUnk,
|
|
|
|
&IID_IViewObject,
|
|
|
|
(void**)&viewobject);
|
|
|
|
if (SUCCEEDED(hres))
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, (RECTL*)rect, 0, 0, 0);
|
2005-07-31 12:11:56 +00:00
|
|
|
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)
|
|
|
|
{
|
2007-04-20 12:23:52 +00:00
|
|
|
HRESULT hres;
|
2005-07-31 12:11:56 +00:00
|
|
|
IUnknown * pUnk = NULL;
|
2007-04-20 12:23:52 +00:00
|
|
|
IOleObject *pOleObject = NULL;
|
2007-04-20 02:30:53 +00:00
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("(%s, %s, %d, %p, %p, %p, %p)\n", debugstr_guid(rclsid),
|
|
|
|
debugstr_guid(riid), renderopt, pFormatEtc, pClientSite, pStg, ppvObj);
|
2007-04-20 02:30:53 +00:00
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
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))
|
2007-04-20 02:30:53 +00:00
|
|
|
{
|
2007-04-20 12:23:52 +00:00
|
|
|
hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (LPVOID*)&pOleObject);
|
|
|
|
if (SUCCEEDED(hres))
|
2007-04-20 02:30:53 +00:00
|
|
|
{
|
2007-04-20 12:23:52 +00:00
|
|
|
DWORD dwStatus;
|
2016-03-04 09:25:52 +00:00
|
|
|
IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
|
2007-04-20 12:23:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
{
|
2016-03-04 09:25:52 +00:00
|
|
|
hres = OleRun(pUnk);
|
2007-04-20 12:23:52 +00:00
|
|
|
if (SUCCEEDED(hres))
|
|
|
|
{
|
2016-03-04 09:25:52 +00:00
|
|
|
IOleCache *pOleCache;
|
|
|
|
|
|
|
|
if (SUCCEEDED(IUnknown_QueryInterface(pUnk, &IID_IOleCache, (void **)&pOleCache)))
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2007-04-20 12:23:52 +00:00
|
|
|
DWORD dwConnection;
|
2011-11-16 17:01:04 +00:00
|
|
|
if (renderopt == OLERENDER_DRAW && !pFormatEtc) {
|
|
|
|
FORMATETC pfe;
|
|
|
|
pfe.cfFormat = 0;
|
|
|
|
pfe.ptd = NULL;
|
|
|
|
pfe.dwAspect = DVASPECT_CONTENT;
|
|
|
|
pfe.lindex = -1;
|
|
|
|
pfe.tymed = TYMED_NULL;
|
|
|
|
hres = IOleCache_Cache(pOleCache, &pfe, ADVF_PRIMEFIRST, &dwConnection);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
hres = IOleCache_Cache(pOleCache, pFormatEtc, ADVF_PRIMEFIRST, &dwConnection);
|
2007-04-20 12:23:52 +00:00
|
|
|
IOleCache_Release(pOleCache);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
if (FAILED(hres) && pUnk)
|
|
|
|
{
|
|
|
|
IUnknown_Release(pUnk);
|
|
|
|
pUnk = NULL;
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
*ppvObj = pUnk;
|
|
|
|
|
2005-11-20 15:01:10 +00:00
|
|
|
TRACE("-- %p\n", pUnk);
|
2005-07-31 12:11:56 +00:00
|
|
|
return hres;
|
|
|
|
}
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* OleSetAutoConvert [OLE32.@]
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
|
|
|
|
{
|
2005-08-03 22:31:39 +00:00
|
|
|
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];
|
2005-07-31 12:11:56 +00:00
|
|
|
HRESULT res = S_OK;
|
|
|
|
|
|
|
|
TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
|
2008-01-14 15:45:45 +00:00
|
|
|
|
2005-11-20 15:01:10 +00:00
|
|
|
res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
|
|
|
|
if (FAILED(res))
|
|
|
|
goto done;
|
2005-08-03 22:31:39 +00:00
|
|
|
StringFromGUID2(clsidNew, szClsidNew, CHARS_IN_GUID);
|
2019-11-10 13:10:55 +00:00
|
|
|
if (RegSetValueW(hkey, wszAutoConvertTo, REG_SZ, szClsidNew, (lstrlenW(szClsidNew)+1) * sizeof(WCHAR)))
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
|
|
|
res = REGDB_E_WRITEREGDB;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (hkey) RegCloseKey(hkey);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* OleDoAutoConvert [OLE32.@]
|
|
|
|
*/
|
2005-09-05 21:56:14 +00:00
|
|
|
HRESULT WINAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew)
|
|
|
|
{
|
2014-04-24 12:14:13 +00:00
|
|
|
WCHAR *user_type_old, *user_type_new;
|
|
|
|
CLIPFORMAT cf;
|
|
|
|
STATSTG stat;
|
|
|
|
CLSID clsid;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
TRACE("(%p, %p)\n", pStg, pClsidNew);
|
|
|
|
|
|
|
|
*pClsidNew = CLSID_NULL;
|
|
|
|
if(!pStg)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
hr = IStorage_Stat(pStg, &stat, STATFLAG_NONAME);
|
|
|
|
if(FAILED(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
*pClsidNew = stat.clsid;
|
|
|
|
hr = OleGetAutoConvert(&stat.clsid, &clsid);
|
|
|
|
if(FAILED(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
hr = IStorage_SetClass(pStg, &clsid);
|
|
|
|
if(FAILED(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
hr = ReadFmtUserTypeStg(pStg, &cf, &user_type_old);
|
|
|
|
if(FAILED(hr)) {
|
|
|
|
cf = 0;
|
|
|
|
user_type_new = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = OleRegGetUserType(&clsid, USERCLASSTYPE_FULL, &user_type_new);
|
|
|
|
if(FAILED(hr))
|
|
|
|
user_type_new = NULL;
|
|
|
|
|
|
|
|
hr = WriteFmtUserTypeStg(pStg, cf, user_type_new);
|
|
|
|
CoTaskMemFree(user_type_new);
|
|
|
|
if(FAILED(hr))
|
|
|
|
{
|
|
|
|
CoTaskMemFree(user_type_old);
|
|
|
|
IStorage_SetClass(pStg, &stat.clsid);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = SetConvertStg(pStg, TRUE);
|
|
|
|
if(FAILED(hr))
|
|
|
|
{
|
|
|
|
WriteFmtUserTypeStg(pStg, cf, user_type_old);
|
|
|
|
IStorage_SetClass(pStg, &stat.clsid);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*pClsidNew = clsid;
|
|
|
|
CoTaskMemFree(user_type_old);
|
|
|
|
return hr;
|
2005-09-05 21:56:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
2005-11-20 15:01:10 +00:00
|
|
|
* OleIsRunning [OLE32.@]
|
2005-09-05 21:56:14 +00:00
|
|
|
*/
|
2011-11-16 17:01:04 +00:00
|
|
|
BOOL WINAPI OleIsRunning(LPOLEOBJECT object)
|
2005-07-31 12:11:56 +00:00
|
|
|
{
|
2005-11-20 15:01:10 +00:00
|
|
|
IRunnableObject *pRunnable;
|
|
|
|
HRESULT hr;
|
|
|
|
BOOL running;
|
|
|
|
|
2011-11-16 17:01:04 +00:00
|
|
|
TRACE("(%p)\n", object);
|
|
|
|
|
|
|
|
if (!object) return FALSE;
|
2005-11-20 15:01:10 +00:00
|
|
|
|
2011-11-16 17:01:04 +00:00
|
|
|
hr = IOleObject_QueryInterface(object, &IID_IRunnableObject, (void **)&pRunnable);
|
2005-11-20 15:01:10 +00:00
|
|
|
if (FAILED(hr))
|
2008-01-14 15:45:45 +00:00
|
|
|
return TRUE;
|
2005-11-20 15:01:10 +00:00
|
|
|
running = IRunnableObject_IsRunning(pRunnable);
|
|
|
|
IRunnableObject_Release(pRunnable);
|
|
|
|
return running;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
/***********************************************************************
|
|
|
|
* OleNoteObjectVisible [OLE32.@]
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL bVisible)
|
|
|
|
{
|
|
|
|
TRACE("(%p, %s)\n", pUnknown, bVisible ? "TRUE" : "FALSE");
|
|
|
|
return CoLockObjectExternal(pUnknown, bVisible, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-31 12:11:56 +00:00
|
|
|
/***********************************************************************
|
|
|
|
* 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++)
|
2016-08-19 09:38:43 +00:00
|
|
|
CoTaskMemFree(pClipDataArray[i].pClipData);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* PropSysAllocString [OLE32.@]
|
2012-12-12 21:01:41 +00:00
|
|
|
* NOTES
|
|
|
|
* Forward to oleaut32.
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
|
|
|
BSTR WINAPI PropSysAllocString(LPCOLESTR str)
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
return SysAllocString(str);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* PropSysFreeString [OLE32.@]
|
|
|
|
* NOTES
|
2012-12-12 21:01:41 +00:00
|
|
|
* Forward to oleaut32.
|
2005-07-31 12:11:56 +00:00
|
|
|
*/
|
|
|
|
void WINAPI PropSysFreeString(LPOLESTR str)
|
|
|
|
{
|
2012-12-12 21:01:41 +00:00
|
|
|
SysFreeString(str);
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* Check if a PROPVARIANT's type is valid.
|
|
|
|
*/
|
|
|
|
static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt)
|
|
|
|
{
|
|
|
|
switch (vt)
|
|
|
|
{
|
|
|
|
case VT_EMPTY:
|
|
|
|
case VT_NULL:
|
2012-12-12 21:01:41 +00:00
|
|
|
case VT_I1:
|
2005-07-31 12:11:56 +00:00
|
|
|
case VT_I2:
|
|
|
|
case VT_I4:
|
2012-12-12 21:01:41 +00:00
|
|
|
case VT_I8:
|
2005-07-31 12:11:56 +00:00
|
|
|
case VT_R4:
|
|
|
|
case VT_R8:
|
|
|
|
case VT_CY:
|
|
|
|
case VT_DATE:
|
|
|
|
case VT_BSTR:
|
|
|
|
case VT_ERROR:
|
|
|
|
case VT_BOOL:
|
2009-03-07 08:34:55 +00:00
|
|
|
case VT_DECIMAL:
|
2005-07-31 12:11:56 +00:00
|
|
|
case VT_UI1:
|
|
|
|
case VT_UI2:
|
|
|
|
case VT_UI4:
|
|
|
|
case VT_UI8:
|
2014-04-24 12:14:13 +00:00
|
|
|
case VT_INT:
|
|
|
|
case VT_UINT:
|
2005-07-31 12:11:56 +00:00
|
|
|
case VT_LPSTR:
|
|
|
|
case VT_LPWSTR:
|
|
|
|
case VT_FILETIME:
|
|
|
|
case VT_BLOB:
|
2014-10-03 11:44:27 +00:00
|
|
|
case VT_DISPATCH:
|
|
|
|
case VT_UNKNOWN:
|
2005-07-31 12:11:56 +00:00
|
|
|
case VT_STREAM:
|
|
|
|
case VT_STORAGE:
|
|
|
|
case VT_STREAMED_OBJECT:
|
|
|
|
case VT_STORED_OBJECT:
|
|
|
|
case VT_BLOB_OBJECT:
|
|
|
|
case VT_CF:
|
|
|
|
case VT_CLSID:
|
2012-12-12 21:01:41 +00:00
|
|
|
case VT_I1|VT_VECTOR:
|
2005-07-31 12:11:56 +00:00
|
|
|
case VT_I2|VT_VECTOR:
|
|
|
|
case VT_I4|VT_VECTOR:
|
2012-12-12 21:01:41 +00:00
|
|
|
case VT_I8|VT_VECTOR:
|
2005-07-31 12:11:56 +00:00
|
|
|
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_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:
|
2019-11-10 13:10:55 +00:00
|
|
|
case VT_ARRAY|VT_I1:
|
|
|
|
case VT_ARRAY|VT_UI1:
|
|
|
|
case VT_ARRAY|VT_I2:
|
|
|
|
case VT_ARRAY|VT_UI2:
|
|
|
|
case VT_ARRAY|VT_I4:
|
|
|
|
case VT_ARRAY|VT_UI4:
|
|
|
|
case VT_ARRAY|VT_INT:
|
|
|
|
case VT_ARRAY|VT_UINT:
|
|
|
|
case VT_ARRAY|VT_R4:
|
|
|
|
case VT_ARRAY|VT_R8:
|
|
|
|
case VT_ARRAY|VT_CY:
|
|
|
|
case VT_ARRAY|VT_DATE:
|
|
|
|
case VT_ARRAY|VT_BSTR:
|
|
|
|
case VT_ARRAY|VT_BOOL:
|
|
|
|
case VT_ARRAY|VT_DECIMAL:
|
|
|
|
case VT_ARRAY|VT_DISPATCH:
|
|
|
|
case VT_ARRAY|VT_UNKNOWN:
|
|
|
|
case VT_ARRAY|VT_ERROR:
|
|
|
|
case VT_ARRAY|VT_VARIANT:
|
2005-07-31 12:11:56 +00:00
|
|
|
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))
|
2014-04-24 12:14:13 +00:00
|
|
|
{
|
|
|
|
memset(pvar, 0, sizeof(*pvar));
|
2005-07-31 12:11:56 +00:00
|
|
|
return hr;
|
2014-04-24 12:14:13 +00:00
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
switch(pvar->vt)
|
|
|
|
{
|
2007-04-20 12:23:52 +00:00
|
|
|
case VT_EMPTY:
|
|
|
|
case VT_NULL:
|
2012-12-12 21:01:41 +00:00
|
|
|
case VT_I1:
|
2007-04-20 12:23:52 +00:00
|
|
|
case VT_I2:
|
|
|
|
case VT_I4:
|
2012-12-12 21:01:41 +00:00
|
|
|
case VT_I8:
|
2007-04-20 12:23:52 +00:00
|
|
|
case VT_R4:
|
|
|
|
case VT_R8:
|
|
|
|
case VT_CY:
|
|
|
|
case VT_DATE:
|
|
|
|
case VT_ERROR:
|
|
|
|
case VT_BOOL:
|
2009-03-07 08:34:55 +00:00
|
|
|
case VT_DECIMAL:
|
2007-04-20 12:23:52 +00:00
|
|
|
case VT_UI1:
|
|
|
|
case VT_UI2:
|
|
|
|
case VT_UI4:
|
|
|
|
case VT_UI8:
|
2014-04-24 12:14:13 +00:00
|
|
|
case VT_INT:
|
|
|
|
case VT_UINT:
|
2007-04-20 12:23:52 +00:00
|
|
|
case VT_FILETIME:
|
|
|
|
break;
|
2014-10-03 11:44:27 +00:00
|
|
|
case VT_DISPATCH:
|
|
|
|
case VT_UNKNOWN:
|
2005-07-31 12:11:56 +00:00
|
|
|
case VT_STREAM:
|
|
|
|
case VT_STREAMED_OBJECT:
|
|
|
|
case VT_STORAGE:
|
|
|
|
case VT_STORED_OBJECT:
|
|
|
|
if (pvar->u.pStream)
|
2012-12-12 21:01:41 +00:00
|
|
|
IStream_Release(pvar->u.pStream);
|
2005-07-31 12:11:56 +00:00
|
|
|
break;
|
|
|
|
case VT_CLSID:
|
|
|
|
case VT_LPSTR:
|
|
|
|
case VT_LPWSTR:
|
2008-07-10 09:14:19 +00:00
|
|
|
/* pick an arbitrary typed pointer - we don't care about the type
|
2005-07-31 12:11:56 +00:00
|
|
|
* 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:
|
2012-12-12 21:01:41 +00:00
|
|
|
PropSysFreeString(pvar->u.bstrVal);
|
2005-07-31 12:11:56 +00:00
|
|
|
break;
|
2007-04-20 12:23:52 +00:00
|
|
|
case VT_CF:
|
2005-07-31 12:11:56 +00:00
|
|
|
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)
|
|
|
|
{
|
2008-07-10 09:14:19 +00:00
|
|
|
/* pick an arbitrary VT_VECTOR structure - they all have the same
|
2005-07-31 12:11:56 +00:00
|
|
|
* memory layout */
|
|
|
|
CoTaskMemFree(pvar->u.capropvar.pElems);
|
|
|
|
}
|
|
|
|
}
|
2019-11-10 13:10:55 +00:00
|
|
|
else if (pvar->vt & VT_ARRAY)
|
|
|
|
hr = SafeArrayDestroy(pvar->u.parray);
|
2005-07-31 12:11:56 +00:00
|
|
|
else
|
2014-04-24 12:14:13 +00:00
|
|
|
{
|
2005-07-31 12:11:56 +00:00
|
|
|
WARN("Invalid/unsupported type %d\n", pvar->vt);
|
2014-04-24 12:14:13 +00:00
|
|
|
hr = STG_E_INVALIDPARAMETER;
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
2014-04-24 12:14:13 +00:00
|
|
|
memset(pvar, 0, sizeof(*pvar));
|
|
|
|
return hr;
|
2005-07-31 12:11:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* PropVariantCopy [OLE32.@]
|
|
|
|
*/
|
|
|
|
HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, /* [out] */
|
|
|
|
const PROPVARIANT *pvarSrc) /* [in] */
|
|
|
|
{
|
|
|
|
ULONG len;
|
|
|
|
HRESULT hr;
|
|
|
|
|
2009-03-07 08:34:55 +00:00
|
|
|
TRACE("(%p, %p vt %04x)\n", pvarDest, pvarSrc, pvarSrc->vt);
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
hr = PROPVARIANT_ValidateType(pvarSrc->vt);
|
|
|
|
if (FAILED(hr))
|
2015-11-17 10:30:40 +00:00
|
|
|
return DISP_E_BADVARTYPE;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
/* this will deal with most cases */
|
2008-07-10 09:14:19 +00:00
|
|
|
*pvarDest = *pvarSrc;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
switch(pvarSrc->vt)
|
|
|
|
{
|
2009-01-15 17:52:35 +00:00
|
|
|
case VT_EMPTY:
|
|
|
|
case VT_NULL:
|
|
|
|
case VT_I1:
|
|
|
|
case VT_UI1:
|
|
|
|
case VT_I2:
|
|
|
|
case VT_UI2:
|
|
|
|
case VT_BOOL:
|
2009-03-07 08:34:55 +00:00
|
|
|
case VT_DECIMAL:
|
2009-01-15 17:52:35 +00:00
|
|
|
case VT_I4:
|
|
|
|
case VT_UI4:
|
|
|
|
case VT_R4:
|
|
|
|
case VT_ERROR:
|
|
|
|
case VT_I8:
|
|
|
|
case VT_UI8:
|
2014-04-24 12:14:13 +00:00
|
|
|
case VT_INT:
|
|
|
|
case VT_UINT:
|
2009-01-15 17:52:35 +00:00
|
|
|
case VT_R8:
|
|
|
|
case VT_CY:
|
|
|
|
case VT_DATE:
|
2007-04-20 12:23:52 +00:00
|
|
|
case VT_FILETIME:
|
|
|
|
break;
|
2014-10-03 11:44:27 +00:00
|
|
|
case VT_DISPATCH:
|
|
|
|
case VT_UNKNOWN:
|
2005-07-31 12:11:56 +00:00
|
|
|
case VT_STREAM:
|
|
|
|
case VT_STREAMED_OBJECT:
|
|
|
|
case VT_STORAGE:
|
|
|
|
case VT_STORED_OBJECT:
|
2014-04-24 12:14:13 +00:00
|
|
|
if (pvarDest->u.pStream)
|
|
|
|
IStream_AddRef(pvarDest->u.pStream);
|
2005-07-31 12:11:56 +00:00
|
|
|
break;
|
|
|
|
case VT_CLSID:
|
|
|
|
pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));
|
2008-07-10 09:14:19 +00:00
|
|
|
*pvarDest->u.puuid = *pvarSrc->u.puuid;
|
2005-07-31 12:11:56 +00:00
|
|
|
break;
|
|
|
|
case VT_LPSTR:
|
2014-04-24 12:14:13 +00:00
|
|
|
if (pvarSrc->u.pszVal)
|
|
|
|
{
|
|
|
|
len = strlen(pvarSrc->u.pszVal);
|
|
|
|
pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
|
|
|
|
CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR));
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
break;
|
|
|
|
case VT_LPWSTR:
|
2014-04-24 12:14:13 +00:00
|
|
|
if (pvarSrc->u.pwszVal)
|
|
|
|
{
|
|
|
|
len = lstrlenW(pvarSrc->u.pwszVal);
|
|
|
|
pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
|
|
|
|
CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR));
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
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);
|
2007-04-20 12:23:52 +00:00
|
|
|
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);
|
2005-07-31 12:11:56 +00:00
|
|
|
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;
|
2009-03-03 09:12:43 +00:00
|
|
|
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;
|
2008-07-10 09:14:19 +00:00
|
|
|
case VT_VARIANT: elemSize = sizeof(*pvarSrc->u.pvarVal); break;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
|
|
|
|
return E_INVALIDARG;
|
|
|
|
}
|
|
|
|
len = pvarSrc->u.capropvar.cElems;
|
2014-04-24 12:14:13 +00:00
|
|
|
pvarDest->u.capropvar.pElems = len ? CoTaskMemAlloc(len * elemSize) : NULL;
|
2005-07-31 12:11:56 +00:00
|
|
|
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);
|
|
|
|
}
|
2019-11-10 13:10:55 +00:00
|
|
|
else if (pvarSrc->vt & VT_ARRAY)
|
|
|
|
{
|
|
|
|
pvarDest->u.uhVal.QuadPart = 0;
|
|
|
|
return SafeArrayCopy(pvarSrc->u.parray, &pvarDest->u.parray);
|
|
|
|
}
|
2005-07-31 12:11:56 +00:00
|
|
|
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;
|
|
|
|
|
2007-04-20 12:23:52 +00:00
|
|
|
TRACE("(%u, %p)\n", cVariants, rgvars);
|
|
|
|
|
|
|
|
if (!rgvars)
|
|
|
|
return E_INVALIDARG;
|
2005-07-31 12:11:56 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|