ole2.c 78.8 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 *	OLE2 library
 *
4 5 6 7
 * Copyright 1995 Martin von Loewis
 * Copyright 1999 Francis Beaudet
 * Copyright 1999 Noel Borthwick
 * Copyright 1999, 2000 Marcus Meissner
8
 * Copyright 2005 Juan Lang
9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * 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
22
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
23 24
 */

25 26
#include "config.h"

27
#include <assert.h>
28
#include <stdlib.h>
29
#include <stdarg.h>
30
#include <stdio.h>
Patrik Stridvall's avatar
Patrik Stridvall committed
31
#include <string.h>
32

33
#define COBJMACROS
34 35
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
36

37
#include "windef.h"
38
#include "winbase.h"
39
#include "winerror.h"
40
#include "wingdi.h"
41
#include "winuser.h"
42
#include "winnls.h"
43
#include "winreg.h"
44 45
#include "ole2.h"
#include "ole2ver.h"
46

47
#include "wine/unicode.h"
48
#include "compobj_private.h"
49
#include "wine/list.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
50

51
#include "wine/debug.h"
52

53 54
WINE_DEFAULT_DEBUG_CHANNEL(ole);
WINE_DECLARE_DEBUG_CHANNEL(accel);
55

56
/******************************************************************************
57
 * These are static/global variables and internal data structures that the
58
 * OLE module uses to maintain it's state.
59
 */
60 61
typedef struct tagDropTargetNode
{
62
  HWND          hwndTarget;
63 64
  IDropTarget*  dropTarget;
  struct list   entry;
65 66 67 68 69 70 71 72
} DropTargetNode;

typedef struct tagTrackerWindowInfo
{
  IDataObject* dataObject;
  IDropSource* dropSource;
  DWORD        dwOKEffect;
  DWORD*       pdwEffect;
73
  BOOL       trackingDone;
74 75
  HRESULT      returnValue;

76
  BOOL       escPressed;
77 78
  HWND       curTargetHWND;	/* window the mouse is hovering over */
  HWND       curDragTargetHWND; /* might be a ancestor of curTargetHWND */
79
  IDropTarget* curDragTarget;
80 81
  POINTL     curMousePos;       /* current position of the mouse in screen coordinates */
  DWORD      dwKeyState;        /* current state of the shift and ctrl keys and the mouse buttons */
82
} TrackerWindowInfo;
83

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
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 */
99
  struct tagOleMenuHookItem *next;
100 101
} OleMenuHookItem;

102
static OleMenuHookItem *hook_list;
103

104 105 106 107
/*
 * This is the lock count on the OLE library. It is controlled by the
 * OLEInitialize/OLEUninitialize methods.
 */
108
static LONG OLE_moduleLockCount = 0;
109 110 111 112 113 114 115 116 117

/*
 * Name of our registered window class.
 */
static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";

/*
 * This is the head of the Drop target container.
 */
118
static struct list targetListHead = LIST_INIT(targetListHead);
119

120
/******************************************************************************
121
 * These are the prototypes of miscellaneous utility methods
122 123 124
 */
static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);

125 126 127
/******************************************************************************
 * These are the prototypes of the utility methods used to manage a shared menu
 */
128 129
static void OLEMenu_Initialize(void);
static void OLEMenu_UnInitialize(void);
130 131 132
static BOOL OLEMenu_InstallHooks( DWORD tid );
static BOOL OLEMenu_UnInstallHooks( DWORD tid );
static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid );
133
static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
134 135 136
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);
137

138 139 140
/******************************************************************************
 * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
 */
141 142
extern void OLEClipbrd_UnInitialize(void);
extern void OLEClipbrd_Initialize(void);
143

144 145 146
/******************************************************************************
 * These are the prototypes of the utility methods used for OLE Drag n Drop
 */
147
static void            OLEDD_Initialize(void);
148
static DropTargetNode* OLEDD_FindDropTarget(
149
                         HWND hwndOfTarget);
150
static void            OLEDD_FreeDropTarget(DropTargetNode*, BOOL);
151
static LRESULT WINAPI  OLEDD_DragTrackerWindowProc(
152
			 HWND   hwnd,
153
			 UINT   uMsg,
154
			 WPARAM wParam,
155 156
			 LPARAM   lParam);
static void OLEDD_TrackMouseMove(
157
                         TrackerWindowInfo* trackerInfo);
158
static void OLEDD_TrackStateChange(
159
                         TrackerWindowInfo* trackerInfo);
160
static DWORD OLEDD_GetButtonState(void);
161

162

163
/******************************************************************************
164
 *		OleBuildVersion [OLE32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
165
 */
166
DWORD WINAPI OleBuildVersion(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
167
{
168
    TRACE("Returning version %d, build %d.\n", rmm, rup);
Alexandre Julliard's avatar
Alexandre Julliard committed
169
    return (rmm<<16)+rup;
Alexandre Julliard's avatar
Alexandre Julliard committed
170 171 172
}

/***********************************************************************
173
 *           OleInitialize       (OLE32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
174
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
175
HRESULT WINAPI OleInitialize(LPVOID reserved)
Alexandre Julliard's avatar
Alexandre Julliard committed
176
{
177 178
  HRESULT hr;

179
  TRACE("(%p)\n", reserved);
180 181 182 183

  /*
   * The first duty of the OleInitialize is to initialize the COM libraries.
   */
184
  hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
185 186

  /*
187
   * If the CoInitializeEx call failed, the OLE libraries can't be
188 189 190
   * initialized.
   */
  if (FAILED(hr))
191
    return hr;
192 193 194 195 196 197 198 199 200

  /*
   * Then, it has to initialize the OLE specific modules.
   * This includes:
   *     Clipboard
   *     Drag and Drop
   *     Object linking and Embedding
   *     In-place activation
   */
201 202
  if (!COM_CurrentInfo()->ole_inits++ &&
      InterlockedIncrement(&OLE_moduleLockCount) == 1)
203
  {
204
    /*
205 206
     * Initialize the libraries.
     */
207
    TRACE("() - Initializing the OLE libraries\n");
208

209 210 211 212 213
    /*
     * OLE Clipboard
     */
    OLEClipbrd_Initialize();

214 215 216 217
    /*
     * Drag and Drop
     */
    OLEDD_Initialize();
218 219 220 221 222

    /*
     * OLE shared menu
     */
    OLEMenu_Initialize();
223
  }
224 225

  return hr;
Alexandre Julliard's avatar
Alexandre Julliard committed
226 227
}

228
/******************************************************************************
229
 *		OleUninitialize	[OLE32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
230
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
231
void WINAPI OleUninitialize(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
232
{
233
  TRACE("()\n");
234 235 236 237

  /*
   * If we hit the bottom of the lock stack, free the libraries.
   */
238
  if (!--COM_CurrentInfo()->ole_inits && !InterlockedDecrement(&OLE_moduleLockCount))
239 240 241 242
  {
    /*
     * Actually free the libraries.
     */
243
    TRACE("() - Freeing the last reference count\n");
244

245 246 247 248 249
    /*
     * OLE Clipboard
     */
    OLEClipbrd_UnInitialize();

250 251 252 253
    /*
     * OLE shared menu
     */
    OLEMenu_UnInitialize();
254
  }
255

256 257 258
  /*
   * Then, uninitialize the COM libraries.
   */
259
  CoUninitialize();
Alexandre Julliard's avatar
Alexandre Julliard committed
260
}
Alexandre Julliard's avatar
Alexandre Julliard committed
261

262
/******************************************************************************
263
 *		OleInitializeWOW	[OLE32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
264
 */
265
HRESULT WINAPI OleInitializeWOW(DWORD x, DWORD y) {
266
        FIXME("(0x%08x, 0x%08x),stub!\n",x, y);
Alexandre Julliard's avatar
Alexandre Julliard committed
267 268
        return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
269

Alexandre Julliard's avatar
Alexandre Julliard committed
270
/***********************************************************************
271
 *           RegisterDragDrop (OLE32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
272
 */
273 274
HRESULT WINAPI RegisterDragDrop(
	HWND hwnd,
275
	LPDROPTARGET pDropTarget)
276 277 278
{
  DropTargetNode* dropTargetInfo;

279
  TRACE("(%p,%p)\n", hwnd, pDropTarget);
280

281 282 283
  if (!COM_CurrentApt())
  {
    ERR("COM not initialized\n");
284
    return E_OUTOFMEMORY;
285 286
  }

287 288
  if (!pDropTarget)
    return E_INVALIDARG;
289 290

  if (!IsWindow(hwnd))
291 292
  {
    ERR("invalid hwnd %p\n", hwnd);
293
    return DRAGDROP_E_INVALIDHWND;
294
  }
295

296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
  /*
   * First, check if the window is already registered.
   */
  dropTargetInfo = OLEDD_FindDropTarget(hwnd);

  if (dropTargetInfo!=NULL)
    return DRAGDROP_E_ALREADYREGISTERED;

  /*
   * If it's not there, we can add it. We first create a node for it.
   */
  dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));

  if (dropTargetInfo==NULL)
    return E_OUTOFMEMORY;

  dropTargetInfo->hwndTarget     = hwnd;

  /*
   * Don't forget that this is an interface pointer, need to nail it down since
   * we keep a copy of it.
   */
318
  IDropTarget_AddRef(pDropTarget);
319
  dropTargetInfo->dropTarget  = pDropTarget;
320

321
  list_add_tail(&targetListHead, &dropTargetInfo->entry);
322

323
  return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
324
}
Alexandre Julliard's avatar
Alexandre Julliard committed
325 326

/***********************************************************************
327
 *           RevokeDragDrop (OLE32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
328
 */
329 330
HRESULT WINAPI RevokeDragDrop(
	HWND hwnd)
331 332 333
{
  DropTargetNode* dropTargetInfo;

334
  TRACE("(%p)\n", hwnd);
335

336 337 338 339 340 341
  if (!IsWindow(hwnd))
  {
    ERR("invalid hwnd %p\n", hwnd);
    return DRAGDROP_E_INVALIDHWND;
  }

342 343 344
  /*
   * First, check if the window is already registered.
   */
345
  dropTargetInfo = OLEDD_FindDropTarget(hwnd);
346 347 348 349 350 351 352

  /*
   * If it ain't in there, it's an error.
   */
  if (dropTargetInfo==NULL)
    return DRAGDROP_E_NOTREGISTERED;

353
  OLEDD_FreeDropTarget(dropTargetInfo, TRUE);
354

355
  return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
356
}
357

358
/***********************************************************************
359
 *           OleRegGetUserType (OLE32.@)
360 361 362 363 364
 *
 * This implementation of OleRegGetUserType ignores the dwFormOfType
 * parameter and always returns the full name of the object. This is
 * not too bad since this is the case for many objects because of the
 * way they are registered.
365
 */
366 367
HRESULT WINAPI OleRegGetUserType(
	REFCLSID clsid,
368
	DWORD dwFormOfType,
369
	LPOLESTR* pszUserType)
370
{
371 372 373 374 375
  char    keyName[60];
  DWORD   dwKeyType;
  DWORD   cbData;
  HKEY    clsidKey;
  LONG    hres;
376
  LPSTR   buffer;
377
  HRESULT retVal;
378 379 380 381 382 383 384 385
  /*
   * Initialize the out parameter.
   */
  *pszUserType = NULL;

  /*
   * Build the key name we're looking for
   */
386
  sprintf( keyName, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
387 388 389
           clsid->Data1, clsid->Data2, clsid->Data3,
           clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
           clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
390

391
  TRACE("(%s, %d, %p)\n", keyName, dwFormOfType, pszUserType);
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423

  /*
   * Open the class id Key
   */
  hres = RegOpenKeyA(HKEY_CLASSES_ROOT,
		     keyName,
		     &clsidKey);

  if (hres != ERROR_SUCCESS)
    return REGDB_E_CLASSNOTREG;

  /*
   * Retrieve the size of the name string.
   */
  cbData = 0;

  hres = RegQueryValueExA(clsidKey,
			  "",
			  NULL,
			  &dwKeyType,
			  NULL,
			  &cbData);

  if (hres!=ERROR_SUCCESS)
  {
    RegCloseKey(clsidKey);
    return REGDB_E_READREGDB;
  }

  /*
   * Allocate a buffer for the registry value.
   */
424
  *pszUserType = CoTaskMemAlloc(cbData*2);
425 426 427 428 429 430 431

  if (*pszUserType==NULL)
  {
    RegCloseKey(clsidKey);
    return E_OUTOFMEMORY;
  }

432 433 434 435 436 437 438 439 440 441
  buffer = HeapAlloc(GetProcessHeap(), 0, cbData);

  if (buffer == NULL)
  {
    RegCloseKey(clsidKey);
    CoTaskMemFree(*pszUserType);
    *pszUserType=NULL;
    return E_OUTOFMEMORY;
  }

442
  hres = RegQueryValueExA(clsidKey,
443 444 445
			  "",
			  NULL,
			  &dwKeyType,
446
			  (LPBYTE) buffer,
447 448 449
			  &cbData);

  RegCloseKey(clsidKey);
450

451

452 453 454 455 456
  if (hres!=ERROR_SUCCESS)
  {
    CoTaskMemFree(*pszUserType);
    *pszUserType=NULL;

457 458 459 460
    retVal = REGDB_E_READREGDB;
  }
  else
  {
461
    MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ );
462
    retVal = S_OK;
463
  }
464
  HeapFree(GetProcessHeap(), 0, buffer);
465

466
  return retVal;
467 468
}

469
/***********************************************************************
470
 * DoDragDrop [OLE32.@]
471
 */
472
HRESULT WINAPI DoDragDrop (
473 474 475 476
  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 */
477
{
478
  TrackerWindowInfo trackerInfo;
479 480
  HWND            hwndTrackWindow;
  MSG             msg;
481

482
  TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource);
483 484 485 486

  /*
   * Setup the drag n drop tracking window.
   */
487 488 489
  if (!IsValidInterface((LPUNKNOWN)pDropSource))
      return E_INVALIDARG;

490 491 492 493 494 495 496
  trackerInfo.dataObject        = pDataObject;
  trackerInfo.dropSource        = pDropSource;
  trackerInfo.dwOKEffect        = dwOKEffect;
  trackerInfo.pdwEffect         = pdwEffect;
  trackerInfo.trackingDone      = FALSE;
  trackerInfo.escPressed        = FALSE;
  trackerInfo.curDragTargetHWND = 0;
497
  trackerInfo.curTargetHWND     = 0;
498 499
  trackerInfo.curDragTarget     = 0;

500 501 502 503
  hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS, "TrackerWindow",
                                  WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
                                  CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0,
                                  &trackerInfo);
504 505 506 507 508 509

  if (hwndTrackWindow!=0)
  {
    /*
     * Capture the mouse input
     */
510
    SetCapture(hwndTrackWindow);
511

512 513
    msg.message = 0;

514
    /*
515
     * Pump messages. All mouse input should go to the capture window.
516
     */
517
    while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
518
    {
519 520 521 522
      trackerInfo.curMousePos.x = msg.pt.x;
      trackerInfo.curMousePos.y = msg.pt.y;
      trackerInfo.dwKeyState = OLEDD_GetButtonState();
	    
523
      if ( (msg.message >= WM_KEYFIRST) &&
524
	   (msg.message <= WM_KEYLAST) )
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
      {
	/*
	 * 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.
540
	 */
541
        OLEDD_TrackStateChange(&trackerInfo);
542 543 544 545 546 547
      }
      else
      {
	/*
	 * Dispatch the messages only when it's not a keyboard message.
	 */
548
	DispatchMessageA(&msg);
549 550 551
      }
    }

552 553 554
    /* re-post the quit message to outer message loop */
    if (msg.message == WM_QUIT)
        PostQuitMessage(msg.wParam);
555 556 557
    /*
     * Destroy the temporary window.
     */
558
    DestroyWindow(hwndTrackWindow);
559 560 561 562 563 564 565 566

    return trackerInfo.returnValue;
  }

  return E_FAIL;
}

/***********************************************************************
567
 * OleQueryLinkFromData [OLE32.@]
568
 */
569
HRESULT WINAPI OleQueryLinkFromData(
570 571
  IDataObject* pSrcDataObject)
{
572
  FIXME("(%p),stub!\n", pSrcDataObject);
573 574 575 576
  return S_OK;
}

/***********************************************************************
577
 * OleRegGetMiscStatus [OLE32.@]
578
 */
579
HRESULT WINAPI OleRegGetMiscStatus(
580 581 582 583
  REFCLSID clsid,
  DWORD    dwAspect,
  DWORD*   pdwStatus)
{
584 585 586 587 588 589 590 591 592 593 594 595 596 597
  char    keyName[60];
  HKEY    clsidKey;
  HKEY    miscStatusKey;
  HKEY    aspectKey;
  LONG    result;

  /*
   * Initialize the out parameter.
   */
  *pdwStatus = 0;

  /*
   * Build the key name we're looking for
   */
598
  sprintf( keyName, "CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\",
599 600 601
           clsid->Data1, clsid->Data2, clsid->Data3,
           clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3],
           clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] );
602

603
  TRACE("(%s, %d, %p)\n", keyName, dwAspect, pdwStatus);
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621

  /*
   * Open the class id Key
   */
  result = RegOpenKeyA(HKEY_CLASSES_ROOT,
		       keyName,
		       &clsidKey);

  if (result != ERROR_SUCCESS)
    return REGDB_E_CLASSNOTREG;

  /*
   * Get the MiscStatus
   */
  result = RegOpenKeyA(clsidKey,
		       "MiscStatus",
		       &miscStatusKey);

622

623 624 625 626 627 628 629 630 631 632 633 634 635 636
  if (result != ERROR_SUCCESS)
  {
    RegCloseKey(clsidKey);
    return REGDB_E_READREGDB;
  }

  /*
   * Read the default value
   */
  OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);

  /*
   * Open the key specific to the requested aspect.
   */
637
  sprintf(keyName, "%d", dwAspect);
638 639 640 641

  result = RegOpenKeyA(miscStatusKey,
		       keyName,
		       &aspectKey);
642

643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
  if (result == ERROR_SUCCESS)
  {
    OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
    RegCloseKey(aspectKey);
  }

  /*
   * Cleanup
   */
  RegCloseKey(miscStatusKey);
  RegCloseKey(clsidKey);

  return S_OK;
}

658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum);

typedef struct
{
    const IEnumOLEVERBVtbl *lpvtbl;
    LONG ref;

    HKEY hkeyVerb;
    ULONG index;
} EnumOLEVERB;

static HRESULT WINAPI EnumOLEVERB_QueryInterface(
    IEnumOLEVERB *iface, REFIID riid, void **ppv)
{
    TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
    if (IsEqualIID(riid, &IID_IUnknown) ||
        IsEqualIID(riid, &IID_IEnumOLEVERB))
    {
        IUnknown_AddRef(iface);
        *ppv = iface;
        return S_OK;
    }
    return E_NOINTERFACE;
}

static ULONG WINAPI EnumOLEVERB_AddRef(
    IEnumOLEVERB *iface)
{
    EnumOLEVERB *This = (EnumOLEVERB *)iface;
    TRACE("()\n");
    return InterlockedIncrement(&This->ref);
}

static ULONG WINAPI EnumOLEVERB_Release(
    IEnumOLEVERB *iface)
{
    EnumOLEVERB *This = (EnumOLEVERB *)iface;
    LONG refs = InterlockedDecrement(&This->ref);
    TRACE("()\n");
    if (!refs)
    {
        RegCloseKey(This->hkeyVerb);
        HeapFree(GetProcessHeap(), 0, This);
    }
    return refs;
}

static HRESULT WINAPI EnumOLEVERB_Next(
    IEnumOLEVERB *iface, ULONG celt, LPOLEVERB rgelt,
    ULONG *pceltFetched)
{
    EnumOLEVERB *This = (EnumOLEVERB *)iface;
    HRESULT hr = S_OK;

712
    TRACE("(%d, %p, %p)\n", celt, rgelt, pceltFetched);
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731

    if (pceltFetched)
        *pceltFetched = 0;

    for (; celt; celt--, rgelt++)
    {
        WCHAR wszSubKey[20];
        LONG cbData;
        LPWSTR pwszOLEVERB;
        LPWSTR pwszMenuFlags;
        LPWSTR pwszAttribs;
        LONG res = RegEnumKeyW(This->hkeyVerb, This->index, wszSubKey, sizeof(wszSubKey)/sizeof(wszSubKey[0]));
        if (res == ERROR_NO_MORE_ITEMS)
        {
            hr = S_FALSE;
            break;
        }
        else if (res != ERROR_SUCCESS)
        {
732
            ERR("RegEnumKeyW failed with error %d\n", res);
733 734 735 736 737 738
            hr = REGDB_E_READREGDB;
            break;
        }
        res = RegQueryValueW(This->hkeyVerb, wszSubKey, NULL, &cbData);
        if (res != ERROR_SUCCESS)
        {
739
            ERR("RegQueryValueW failed with error %d\n", res);
740 741 742 743 744 745 746 747 748 749 750 751
            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)
        {
752
            ERR("RegQueryValueW failed with error %d\n", res);
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
            hr = REGDB_E_READREGDB;
            CoTaskMemFree(pwszOLEVERB);
            break;
        }

        TRACE("verb string: %s\n", debugstr_w(pwszOLEVERB));
        pwszMenuFlags = strchrW(pwszOLEVERB, ',');
        if (!pwszMenuFlags)
        {
            hr = OLEOBJ_E_INVALIDVERB;
            CoTaskMemFree(pwszOLEVERB);
            break;
        }
        /* nul terminate the name string and advance to first character */
        *pwszMenuFlags = '\0';
        pwszMenuFlags++;
        pwszAttribs = strchrW(pwszMenuFlags, ',');
        if (!pwszAttribs)
        {
            hr = OLEOBJ_E_INVALIDVERB;
            CoTaskMemFree(pwszOLEVERB);
            break;
        }
        /* nul terminate the menu string and advance to first character */
        *pwszAttribs = '\0';
        pwszAttribs++;

        /* fill out structure for this verb */
        rgelt->lVerb = atolW(wszSubKey);
        rgelt->lpszVerbName = pwszOLEVERB; /* user should free */
        rgelt->fuFlags = atolW(pwszMenuFlags);
        rgelt->grfAttribs = atolW(pwszAttribs);

        if (pceltFetched)
787
            (*pceltFetched)++;
788 789 790 791 792 793 794 795 796 797
        This->index++;
    }
    return hr;
}

static HRESULT WINAPI EnumOLEVERB_Skip(
    IEnumOLEVERB *iface, ULONG celt)
{
    EnumOLEVERB *This = (EnumOLEVERB *)iface;

798
    TRACE("(%d)\n", celt);
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878

    This->index += celt;
    return S_OK;
}

static HRESULT WINAPI EnumOLEVERB_Reset(
    IEnumOLEVERB *iface)
{
    EnumOLEVERB *This = (EnumOLEVERB *)iface;

    TRACE("()\n");

    This->index = 0;
    return S_OK;
}

static HRESULT WINAPI EnumOLEVERB_Clone(
    IEnumOLEVERB *iface,
    IEnumOLEVERB **ppenum)
{
    EnumOLEVERB *This = (EnumOLEVERB *)iface;
    HKEY hkeyVerb;
    TRACE("(%p)\n", ppenum);
    if (!DuplicateHandle(GetCurrentProcess(), This->hkeyVerb, GetCurrentProcess(), (HANDLE *)&hkeyVerb, 0, FALSE, DUPLICATE_SAME_ACCESS))
        return HRESULT_FROM_WIN32(GetLastError());
    return EnumOLEVERB_Construct(hkeyVerb, This->index, ppenum);
}

static const IEnumOLEVERBVtbl EnumOLEVERB_VTable =
{
    EnumOLEVERB_QueryInterface,
    EnumOLEVERB_AddRef,
    EnumOLEVERB_Release,
    EnumOLEVERB_Next,
    EnumOLEVERB_Skip,
    EnumOLEVERB_Reset,
    EnumOLEVERB_Clone
};

static HRESULT EnumOLEVERB_Construct(HKEY hkeyVerb, ULONG index, IEnumOLEVERB **ppenum)
{
    EnumOLEVERB *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
    if (!This)
    {
        RegCloseKey(hkeyVerb);
        return E_OUTOFMEMORY;
    }
    This->lpvtbl = &EnumOLEVERB_VTable;
    This->ref = 1;
    This->index = index;
    This->hkeyVerb = hkeyVerb;
    *ppenum = (IEnumOLEVERB *)&This->lpvtbl;
    return S_OK;    
}

/***********************************************************************
 *           OleRegEnumVerbs    [OLE32.@]
 *
 * Enumerates verbs associated with a class stored in the registry.
 *
 * PARAMS
 *  clsid  [I] Class ID to enumerate the verbs for.
 *  ppenum [O] Enumerator.
 *
 * RETURNS
 *  S_OK: Success.
 *  REGDB_E_CLASSNOTREG: The specified class does not have a key in the registry.
 *  REGDB_E_READREGDB: The class key could not be opened for some other reason.
 *  OLE_E_REGDB_KEY: The Verb subkey for the class is not present.
 *  OLEOBJ_E_NOVERBS: The Verb subkey for the class is empty.
 */
HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum)
{
    LONG res;
    HKEY hkeyVerb;
    DWORD dwSubKeys;
    static const WCHAR wszVerb[] = {'V','e','r','b',0};

    TRACE("(%s, %p)\n", debugstr_guid(clsid), ppenum);

879 880
    res = COM_OpenKeyForCLSID(clsid, wszVerb, KEY_READ, &hkeyVerb);
    if (FAILED(res))
881
    {
882 883 884 885 886
        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
887
            ERR("failed to open Verbs key for CLSID %s with error %d\n",
888 889
                debugstr_guid(clsid), res);
        return res;
890 891 892 893 894 895
    }

    res = RegQueryInfoKeyW(hkeyVerb, NULL, NULL, NULL, &dwSubKeys, NULL,
                          NULL, NULL, NULL, NULL, NULL, NULL);
    if (res != ERROR_SUCCESS)
    {
896
        ERR("failed to get subkey count with error %d\n", GetLastError());
897 898 899 900 901 902 903 904 905 906 907 908 909
        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);
}

910
/******************************************************************************
911
 *              OleSetContainedObject        [OLE32.@]
912 913
 */
HRESULT WINAPI OleSetContainedObject(
914
  LPUNKNOWN pUnknown,
915 916 917 918 919
  BOOL      fContained)
{
  IRunnableObject* runnable = NULL;
  HRESULT          hres;

920
  TRACE("(%p,%x)\n", pUnknown, fContained);
921 922 923

  hres = IUnknown_QueryInterface(pUnknown,
				 &IID_IRunnableObject,
924
				 (void**)&runnable);
925 926 927 928 929 930 931 932 933 934 935 936 937

  if (SUCCEEDED(hres))
  {
    hres = IRunnableObject_SetContainedObject(runnable, fContained);

    IRunnableObject_Release(runnable);

    return hres;
  }

  return S_OK;
}

938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
/******************************************************************************
 *              OleRun        [OLE32.@]
 *
 * Set the OLE object to the running state.
 *
 * PARAMS
 *  pUnknown [I] OLE object to run.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: Any HRESULT code.
 */
HRESULT WINAPI OleRun(LPUNKNOWN pUnknown)
{
    IRunnableObject *runable;
    HRESULT hres;

    TRACE("(%p)\n", pUnknown);

    hres = IUnknown_QueryInterface(pUnknown, &IID_IRunnableObject, (void**)&runable);
    if (FAILED(hres))
        return S_OK; /* Appears to return no error. */

    hres = IRunnableObject_Run(runable, NULL);
    IRunnableObject_Release(runable);
    return hres;
}

966
/******************************************************************************
967
 *              OleLoad        [OLE32.@]
968 969
 */
HRESULT WINAPI OleLoad(
970 971 972
  LPSTORAGE       pStg,
  REFIID          riid,
  LPOLECLIENTSITE pClientSite,
973 974 975
  LPVOID*         ppvObj)
{
  IPersistStorage* persistStorage = NULL;
976 977
  IUnknown*        pUnk;
  IOleObject*      pOleObject      = NULL;
978 979 980
  STATSTG          storageInfo;
  HRESULT          hres;

981
  TRACE("(%p, %s, %p, %p)\n", pStg, debugstr_guid(riid), pClientSite, ppvObj);
982

983 984
  *ppvObj = NULL;

985 986 987 988 989 990 991 992 993 994 995 996 997 998
  /*
   * TODO, Conversion ... OleDoAutoConvert
   */

  /*
   * Get the class ID for the object.
   */
  hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);

  /*
   * Now, try and create the handler for the object
   */
  hres = CoCreateInstance(&storageInfo.clsid,
			  NULL,
999
			  CLSCTX_INPROC_HANDLER|CLSCTX_INPROC_SERVER,
1000 1001
			  riid,
			  (void**)&pUnk);
1002 1003 1004 1005 1006 1007 1008 1009 1010

  /*
   * If that fails, as it will most times, load the default
   * OLE handler.
   */
  if (FAILED(hres))
  {
    hres = OleCreateDefaultHandler(&storageInfo.clsid,
				   NULL,
1011 1012
				   riid,
				   (void**)&pUnk);
1013 1014 1015 1016 1017 1018 1019 1020
  }

  /*
   * If we couldn't find a handler... this is bad. Abort the whole thing.
   */
  if (FAILED(hres))
    return hres;

1021 1022 1023 1024 1025 1026 1027 1028 1029
  if (pClientSite)
  {
    hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (void **)&pOleObject);
    if (SUCCEEDED(hres))
    {
        DWORD dwStatus;
        hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
    }
  }
1030

1031 1032 1033 1034 1035 1036 1037
  if (SUCCEEDED(hres))
    /*
     * Initialize the object with it's IPersistStorage interface.
     */
    hres = IOleObject_QueryInterface(pUnk,
				     &IID_IPersistStorage,
				     (void**)&persistStorage);
1038

1039
  if (SUCCEEDED(hres))
1040
  {
1041
    hres = IPersistStorage_Load(persistStorage, pStg);
1042 1043 1044 1045 1046

    IPersistStorage_Release(persistStorage);
    persistStorage = NULL;
  }

1047 1048 1049 1050 1051
  if (SUCCEEDED(hres) && pClientSite)
    /*
     * Inform the new object of it's client site.
     */
    hres = IOleObject_SetClientSite(pOleObject, pClientSite);
1052 1053 1054 1055

  /*
   * Cleanup interfaces used internally
   */
1056 1057 1058
  if (pOleObject)
    IOleObject_Release(pOleObject);

1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
  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);
    }
  }

1071 1072 1073 1074 1075 1076 1077
  if (FAILED(hres))
  {
    IUnknown_Release(pUnk);
    pUnk = NULL;
  }

  *ppvObj = pUnk;
1078 1079

  return hres;
1080 1081
}

1082
/***********************************************************************
1083
 *           OleSave     [OLE32.@]
1084 1085 1086 1087 1088 1089 1090 1091 1092
 */
HRESULT WINAPI OleSave(
  LPPERSISTSTORAGE pPS,
  LPSTORAGE        pStg,
  BOOL             fSameAsLoad)
{
  HRESULT hres;
  CLSID   objectClass;

1093
  TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad);
1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115

  /*
   * 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);
  }
1116

1117 1118 1119 1120
  return hres;
}


1121
/******************************************************************************
1122
 *              OleLockRunning        [OLE32.@]
1123
 */
1124
HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)
1125 1126 1127 1128 1129 1130 1131 1132
{
  IRunnableObject* runnable = NULL;
  HRESULT          hres;

  TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses);

  hres = IUnknown_QueryInterface(pUnknown,
				 &IID_IRunnableObject,
1133
				 (void**)&runnable);
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147

  if (SUCCEEDED(hres))
  {
    hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses);

    IRunnableObject_Release(runnable);

    return hres;
  }
  else
    return E_INVALIDARG;
}


1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
/**************************************************************************
 * Internal methods to manage the shared OLE menu in response to the
 * OLE***MenuDescriptor API
 */

/***
 * OLEMenu_Initialize()
 *
 * Initializes the OLEMENU data structures.
 */
1158
static void OLEMenu_Initialize(void)
1159 1160 1161 1162 1163 1164 1165 1166
{
}

/***
 * OLEMenu_UnInitialize()
 *
 * Releases the OLEMENU data structures.
 */
1167
static void OLEMenu_UnInitialize(void)
1168 1169 1170 1171 1172 1173 1174
{
}

/*************************************************************************
 * OLEMenu_InstallHooks
 * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
 *
1175
 * RETURNS: TRUE if message hooks were successfully installed
1176 1177
 *          FALSE on failure
 */
1178
static BOOL OLEMenu_InstallHooks( DWORD tid )
1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
{
  OleMenuHookItem *pHookItem = NULL;

  /* Create an entry for the hook table */
  if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0,
                               sizeof(OleMenuHookItem)) ) )
    return FALSE;

  pHookItem->tid = tid;
  pHookItem->hHeap = GetProcessHeap();
1189

1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202
  /* Install a thread scope message hook for WH_GETMESSAGE */
  pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
                                               0, GetCurrentThreadId() );
  if ( !pHookItem->GetMsg_hHook )
    goto CLEANUP;

  /* Install a thread scope message hook for WH_CALLWNDPROC */
  pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
                                                    0, GetCurrentThreadId() );
  if ( !pHookItem->CallWndProc_hHook )
    goto CLEANUP;

  /* Insert the hook table entry */
1203 1204
  pHookItem->next = hook_list;
  hook_list = pHookItem;
1205

1206
  return TRUE;
1207

1208 1209 1210 1211 1212 1213 1214 1215
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 );
1216

1217 1218 1219 1220 1221 1222 1223
  return FALSE;
}

/*************************************************************************
 * OLEMenu_UnInstallHooks
 * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
 *
1224
 * RETURNS: TRUE if message hooks were successfully installed
1225 1226
 *          FALSE on failure
 */
1227
static BOOL OLEMenu_UnInstallHooks( DWORD tid )
1228 1229
{
  OleMenuHookItem *pHookItem = NULL;
1230
  OleMenuHookItem **ppHook = &hook_list;
1231

1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
  while (*ppHook)
  {
      if ((*ppHook)->tid == tid)
      {
          pHookItem = *ppHook;
          *ppHook = pHookItem->next;
          break;
      }
      ppHook = &(*ppHook)->next;
  }
  if (!pHookItem) return FALSE;
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256

  /* 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 */
1257
  HeapFree(pHookItem->hHeap, 0, pHookItem );
1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268

  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
 */
1269
static OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid )
1270 1271 1272 1273 1274
{
  OleMenuHookItem *pHookItem = NULL;

  /* Do a simple linear search for an entry whose tid matches ours.
   * We really need a map but efficiency is not a concern here. */
1275
  for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next)
1276 1277 1278 1279
  {
    if ( tid == pHookItem->tid )
      return pHookItem;
  }
1280

1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
  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 )
{
1294
  INT i, nItems;
1295 1296 1297 1298 1299 1300

  nItems = GetMenuItemCount( hMainMenu );

  for (i = 0; i < nItems; i++)
  {
    HMENU hsubmenu;
1301

1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332
    /*  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
1333
 *          FALSE if the popup menu is part of a container owned group
1334
 */
1335
static BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
{
  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;
1348

1349 1350 1351 1352
  /* 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.
1353
   * Loop through the group widths and locate the group we are a member of.
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373
   */
  for ( i = 0, nWidth = 0; i < 6; i++ )
  {
    nWidth += pOleMenuDescriptor->mgw.width[i];
    if ( nPos < nWidth )
    {
      /* Odd elements are server menu widths */
      pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
      break;
    }
  }

  return pOleMenuDescriptor->bIsServerItem;
}

/*************************************************************************
 * OLEMenu_CallWndProc
 * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
 * This is invoked from a message hook installed in OleSetMenuDescriptor.
 */
1374
static LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
1375 1376 1377 1378 1379 1380
{
  LPCWPSTRUCT pMsg = NULL;
  HOLEMENU hOleMenu = 0;
  OleMenuDescriptor *pOleMenuDescriptor = NULL;
  OleMenuHookItem *pHookItem = NULL;
  WORD fuFlags;
1381

1382
  TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
1383 1384 1385 1386

  /* Check if we're being asked to process the message */
  if ( HC_ACTION != code )
    goto NEXTHOOK;
1387

1388 1389 1390 1391 1392 1393 1394
  /* 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. */

1395
  hOleMenu = GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1396 1397 1398 1399
  if ( !hOleMenu )
    goto NEXTHOOK;

  /* Get the menu descriptor */
1400
  pOleMenuDescriptor = GlobalLock( hOleMenu );
1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416
  if ( !pOleMenuDescriptor ) /* Bad descriptor! */
    goto NEXTHOOK;

  /* Process menu messages */
  switch( pMsg->message )
  {
    case WM_INITMENU:
    {
      /* Reset the menu descriptor state */
      pOleMenuDescriptor->bIsServerItem = FALSE;

      /* Send this message to the server as well */
      SendMessageA( pOleMenuDescriptor->hwndActiveObject,
                  pMsg->message, pMsg->wParam, pMsg->lParam );
      goto NEXTHOOK;
    }
1417

1418 1419 1420 1421 1422 1423
    case WM_INITMENUPOPUP:
    {
      /* Save the state for whether this is a server owned menu */
      OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
      break;
    }
1424

1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436
    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;
    }
1437

1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456
    case WM_DRAWITEM:
    {
      LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
      if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
        goto NEXTHOOK;  /* Not a menu message */

      break;
    }

    default:
      goto NEXTHOOK;
  }

  /* If the message was for the server dispatch it accordingly */
  if ( pOleMenuDescriptor->bIsServerItem )
  {
    SendMessageA( pOleMenuDescriptor->hwndActiveObject,
                  pMsg->message, pMsg->wParam, pMsg->lParam );
  }
1457

1458 1459 1460
NEXTHOOK:
  if ( pOleMenuDescriptor )
    GlobalUnlock( hOleMenu );
1461

1462
  /* Lookup the hook item for the current thread */
1463
  if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1464 1465
  {
    /* This should never fail!! */
1466
    WARN("could not retrieve hHook for current thread!\n" );
1467 1468
    return 0;
  }
1469

1470 1471 1472 1473 1474 1475 1476 1477 1478
  /* 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.
 */
1479
static LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
1480 1481 1482 1483 1484 1485
{
  LPMSG pMsg = NULL;
  HOLEMENU hOleMenu = 0;
  OleMenuDescriptor *pOleMenuDescriptor = NULL;
  OleMenuHookItem *pHookItem = NULL;
  WORD wCode;
1486

1487
  TRACE("%i, %04lx, %08lx\n", code, wParam, lParam );
1488 1489 1490 1491

  /* Check if we're being asked to process a  messages */
  if ( HC_ACTION != code )
    goto NEXTHOOK;
1492

1493 1494 1495 1496 1497 1498 1499
  /* 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. */

1500
  hOleMenu = GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
  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 */
1519
  pOleMenuDescriptor = GlobalLock( hOleMenu );
1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530
  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;
  }
1531

1532 1533 1534
NEXTHOOK:
  if ( pOleMenuDescriptor )
    GlobalUnlock( hOleMenu );
1535

1536
  /* Lookup the hook item for the current thread */
1537
  if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) )
1538 1539
  {
    /* This should never fail!! */
1540
    WARN("could not retrieve hHook for current thread!\n" );
1541 1542
    return FALSE;
  }
1543

1544 1545 1546 1547
  /* Pass on the message to the next hooker */
  return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
}

1548
/***********************************************************************
1549
 * OleCreateMenuDescriptor [OLE32.@]
1550 1551 1552 1553 1554 1555 1556
 * 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
 *
1557
 */
1558 1559 1560
HOLEMENU WINAPI OleCreateMenuDescriptor(
  HMENU                hmenuCombined,
  LPOLEMENUGROUPWIDTHS lpMenuWidths)
1561
{
1562 1563 1564 1565 1566 1567
  HOLEMENU hOleMenu;
  OleMenuDescriptor *pOleMenuDescriptor;
  int i;

  if ( !hmenuCombined || !lpMenuWidths )
    return 0;
1568

1569 1570 1571
  /* Create an OLE menu descriptor */
  if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
                                sizeof(OleMenuDescriptor) ) ) )
1572
  return 0;
1573

1574
  pOleMenuDescriptor = GlobalLock( hOleMenu );
1575 1576 1577 1578 1579 1580
  if ( !pOleMenuDescriptor )
    return 0;

  /* Initialize menu group widths and hmenu */
  for ( i = 0; i < 6; i++ )
    pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
1581

1582 1583 1584
  pOleMenuDescriptor->hmenuCombined = hmenuCombined;
  pOleMenuDescriptor->bIsServerItem = FALSE;
  GlobalUnlock( hOleMenu );
1585

1586
  return hOleMenu;
1587 1588 1589
}

/***********************************************************************
1590
 * OleDestroyMenuDescriptor [OLE32.@]
1591
 * Destroy the shared menu descriptor
1592
 */
1593
HRESULT WINAPI OleDestroyMenuDescriptor(
1594
  HOLEMENU hmenuDescriptor)
1595
{
1596 1597
  if ( hmenuDescriptor )
    GlobalFree( hmenuDescriptor );
1598
	return S_OK;
1599 1600 1601
}

/***********************************************************************
1602
 * OleSetMenuDescriptor [OLE32.@]
1603
 * Installs or removes OLE dispatching code for the containers frame window.
1604
 *
1605
 * PARAMS
1606 1607 1608 1609 1610 1611
 *     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
 *
1612
 * RETURNS
1613 1614
 *      S_OK                               - menu installed correctly
 *      E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
1615 1616 1617 1618 1619
 *
 * 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.
1620 1621
 */
HRESULT WINAPI OleSetMenuDescriptor(
1622
  HOLEMENU               hOleMenu,
1623 1624
  HWND                   hwndFrame,
  HWND                   hwndActiveObject,
1625 1626 1627
  LPOLEINPLACEFRAME        lpFrame,
  LPOLEINPLACEACTIVEOBJECT lpActiveObject)
{
1628 1629 1630 1631 1632 1633 1634 1635
  OleMenuDescriptor *pOleMenuDescriptor = NULL;

  /* Check args */
  if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
    return E_INVALIDARG;

  if ( lpFrame || lpActiveObject )
  {
1636 1637
     FIXME("(%p, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n",
	hOleMenu,
1638 1639 1640 1641
	hwndFrame,
	hwndActiveObject,
	lpFrame,
	lpActiveObject);
1642 1643 1644 1645 1646 1647
  }

  /* 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.
   */
1648

1649 1650 1651 1652 1653 1654
  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 */
1655
    if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) )
1656
  return E_FAIL;
1657

1658
    /* Get the menu descriptor */
1659
    pOleMenuDescriptor = GlobalLock( hOleMenu );
1660 1661 1662 1663 1664 1665 1666 1667 1668
    if ( !pOleMenuDescriptor )
      return E_UNEXPECTED;

    /* Update the menu descriptor */
    pOleMenuDescriptor->hwndFrame = hwndFrame;
    pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;

    GlobalUnlock( hOleMenu );
    pOleMenuDescriptor = NULL;
1669

1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681
    /* Add a menu descriptor windows property to the frame window */
    SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );

    /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
    if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
      return E_FAIL;
  }
  else  /* Want to uninstall dispatching code */
  {
    /* Uninstall the hooks */
    if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
      return E_FAIL;
1682

1683 1684 1685
    /* Remove the menu descriptor property from the frame window */
    RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
  }
1686

1687
  return S_OK;
1688 1689
}

1690
/******************************************************************************
1691
 *              IsAccelerator        [OLE32.@]
1692 1693 1694 1695
 * Mostly copied from controls/menu.c TranslateAccelerator implementation
 */
BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd)
{
1696
    LPACCEL lpAccelTbl;
1697 1698 1699
    int i;

    if(!lpMsg) return FALSE;
1700
    if (!hAccel)
1701
    {
1702
	WARN_(accel)("NULL accel handle\n");
1703 1704 1705 1706
	return FALSE;
    }
    if((lpMsg->message != WM_KEYDOWN &&
	lpMsg->message != WM_SYSKEYDOWN &&
1707
	lpMsg->message != WM_SYSCHAR &&
1708
	lpMsg->message != WM_CHAR)) return FALSE;
1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719
    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;
    }
1720

1721
    TRACE_(accel)("hAccel=%p, cAccelEntries=%d,"
1722
		"msg->hwnd=%p, msg->message=%04x, wParam=%08lx, lParam=%08lx\n",
1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733
		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))
	    {
1734
		TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", LOWORD(lpMsg->wParam) & 0xff);
1735 1736 1737 1738 1739 1740 1741 1742
		goto found;
	    }
	}
	else
	{
	    if(lpAccelTbl[i].fVirt & FVIRTKEY)
	    {
		INT mask = 0;
1743
		TRACE_(accel)("found accel for virt_key %04lx (scan %04x)\n",
1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756
				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 */
1757
			TRACE_(accel)("found accel for Alt-%c\n", LOWORD(lpMsg->wParam) & 0xff);
1758 1759 1760 1761 1762
			goto found;
		    }
		}
	    }
	}
1763
    }
1764 1765

    WARN_(accel)("couldn't translate accelerator key\n");
1766
    HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1767 1768 1769 1770
    return FALSE;

found:
    if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd;
1771
    HeapFree(GetProcessHeap(), 0, lpAccelTbl);
1772 1773 1774
    return TRUE;
}

1775
/***********************************************************************
1776
 * ReleaseStgMedium [OLE32.@]
1777 1778 1779 1780 1781 1782 1783 1784
 */
void WINAPI ReleaseStgMedium(
  STGMEDIUM* pmedium)
{
  switch (pmedium->tymed)
  {
    case TYMED_HGLOBAL:
    {
1785
      if ( (pmedium->pUnkForRelease==0) &&
1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797
	   (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);
	}
1798

1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820
	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:
    {
1821
      if ( (pmedium->pUnkForRelease==0) &&
1822 1823
	   (pmedium->u.hBitmap!=0) )
	DeleteObject(pmedium->u.hBitmap);
1824 1825 1826 1827
      break;
    }
    case TYMED_MFPICT:
    {
1828
      if ( (pmedium->pUnkForRelease==0) &&
1829 1830
	   (pmedium->u.hMetaFilePict!=0) )
      {
1831
	LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict);
1832
	DeleteMetaFile(pMP->hMF);
1833 1834
	GlobalUnlock(pmedium->u.hMetaFilePict);
	GlobalFree(pmedium->u.hMetaFilePict);
1835 1836 1837 1838 1839
      }
      break;
    }
    case TYMED_ENHMF:
    {
1840
      if ( (pmedium->pUnkForRelease==0) &&
1841 1842 1843 1844 1845 1846 1847 1848 1849 1850
	   (pmedium->u.hEnhMetaFile!=0) )
      {
	DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
      }
      break;
    }
    case TYMED_NULL:
    default:
      break;
  }
1851
  pmedium->tymed=TYMED_NULL;
1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862

  /*
   * After cleaning up, the unknown is released
   */
  if (pmedium->pUnkForRelease!=0)
  {
    IUnknown_Release(pmedium->pUnkForRelease);
    pmedium->pUnkForRelease = 0;
  }
}

1863 1864 1865 1866 1867
/***
 * OLEDD_Initialize()
 *
 * Initializes the OLE drag and drop data structures.
 */
1868
static void OLEDD_Initialize(void)
1869
{
1870
    WNDCLASSA wndClass;
1871

1872
    ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1873
    wndClass.style         = CS_GLOBALCLASS;
1874
    wndClass.lpfnWndProc   = OLEDD_DragTrackerWindowProc;
1875 1876 1877 1878 1879
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(TrackerWindowInfo*);
    wndClass.hCursor       = 0;
    wndClass.hbrBackground = 0;
    wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
1880

1881
    RegisterClassA (&wndClass);
1882 1883 1884
}

/***
1885
 * OLEDD_FreeDropTarget()
1886
 *
1887
 * Frees the drag and drop data structure
1888
 */
1889
static void OLEDD_FreeDropTarget(DropTargetNode *dropTargetInfo, BOOL release_drop_target)
1890
{
1891
  list_remove(&dropTargetInfo->entry);
1892
  if (release_drop_target) IDropTarget_Release(dropTargetInfo->dropTarget);
1893
  HeapFree(GetProcessHeap(), 0, dropTargetInfo);
1894
}
1895 1896

/***
1897
 * OLEDD_UnInitialize()
1898
 *
1899
 * Releases the OLE drag and drop data structures.
1900
 */
1901
void OLEDD_UnInitialize(void)
1902 1903
{
  /*
1904
   * Simply empty the list.
1905
   */
1906
  while (!list_empty(&targetListHead))
1907
  {
1908 1909
    DropTargetNode* curNode = LIST_ENTRY(list_head(&targetListHead), DropTargetNode, entry);
    OLEDD_FreeDropTarget(curNode, FALSE);
1910 1911 1912 1913 1914 1915 1916 1917
  }
}

/***
 * OLEDD_FindDropTarget()
 *
 * Finds information about the drop target.
 */
1918
static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
1919 1920 1921 1922
{
  DropTargetNode*  curNode;

  /*
1923
   * Iterate the list to find the HWND value.
1924
   */
1925 1926
  LIST_FOR_EACH_ENTRY(curNode, &targetListHead, DropTargetNode, entry)
    if (hwndOfTarget==curNode->hwndTarget)
1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942
      return curNode;

  /*
   * If we get here, the item is not in the list
   */
  return NULL;
}

/***
 * OLEDD_DragTrackerWindowProc()
 *
 * This method is the WindowProcedure of the drag n drop tracking
 * window. During a drag n Drop operation, an invisible window is created
 * to receive the user input and act upon it. This procedure is in charge
 * of this behavior.
 */
1943 1944 1945

#define DRAG_TIMER_ID 1

1946
static LRESULT WINAPI OLEDD_DragTrackerWindowProc(
1947
			 HWND   hwnd,
1948
			 UINT   uMsg,
1949
			 WPARAM wParam,
1950 1951 1952 1953 1954 1955
			 LPARAM   lParam)
{
  switch (uMsg)
  {
    case WM_CREATE:
    {
1956
      LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
1957

1958
      SetWindowLongPtrA(hwnd, 0, (LONG_PTR)createStruct->lpCreateParams);
1959
      SetTimer(hwnd, DRAG_TIMER_ID, 50, NULL);
1960 1961 1962

      break;
    }
1963
    case WM_TIMER:
1964 1965
    case WM_MOUSEMOVE:
    {
1966
      OLEDD_TrackMouseMove((TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0));
1967 1968 1969 1970 1971 1972 1973 1974 1975
      break;
    }
    case WM_LBUTTONUP:
    case WM_MBUTTONUP:
    case WM_RBUTTONUP:
    case WM_LBUTTONDOWN:
    case WM_MBUTTONDOWN:
    case WM_RBUTTONDOWN:
    {
1976
      OLEDD_TrackStateChange((TrackerWindowInfo*)GetWindowLongPtrA(hwnd, 0));
1977 1978 1979 1980 1981
      break;
    }
    case WM_DESTROY:
    {
      KillTimer(hwnd, DRAG_TIMER_ID);
1982 1983 1984 1985 1986 1987 1988
      break;
    }
  }

  /*
   * This is a window proc after all. Let's call the default.
   */
1989
  return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004
}

/***
 * OLEDD_TrackMouseMove()
 *
 * This method is invoked while a drag and drop operation is in effect.
 * it will generate the appropriate callbacks in the drop source
 * and drop target. It will also provide the expected feedback to
 * the user.
 *
 * params:
 *    trackerInfo - Pointer to the structure identifying the
 *                  drag & drop operation that is currently
 *                  active.
 */
2005
static void OLEDD_TrackMouseMove(TrackerWindowInfo* trackerInfo)
2006
{
2007
  HWND   hwndNewTarget = 0;
2008
  HRESULT  hr = S_OK;
2009
  POINT pt;
2010 2011 2012 2013

  /*
   * Get the handle of the window under the mouse
   */
2014 2015 2016
  pt.x = trackerInfo->curMousePos.x;
  pt.y = trackerInfo->curMousePos.y;
  hwndNewTarget = WindowFromPoint(pt);
2017

2018 2019 2020 2021 2022 2023
  /*
   * Every time, we re-initialize the effects passed to the
   * IDropTarget to the effects allowed by the source.
   */
  *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;

2024 2025 2026 2027
  /*
   * If we are hovering over the same target as before, send the
   * DragOver notification
   */
2028
  if ( (trackerInfo->curDragTarget != 0) &&
2029
       (trackerInfo->curTargetHWND == hwndNewTarget) )
2030 2031
  {
    IDropTarget_DragOver(trackerInfo->curDragTarget,
2032 2033
                         trackerInfo->dwKeyState,
                         trackerInfo->curMousePos,
2034 2035 2036
			 trackerInfo->pdwEffect);
  }
  else
2037
  {
2038
    DropTargetNode* newDropTargetNode = 0;
2039

2040 2041 2042 2043 2044 2045 2046 2047
    /*
     * If we changed window, we have to notify our old target and check for
     * the new one.
     */
    if (trackerInfo->curDragTarget!=0)
    {
      IDropTarget_DragLeave(trackerInfo->curDragTarget);
    }
2048

2049 2050 2051 2052 2053 2054 2055 2056
    /*
     * Make sure we're hovering over a window.
     */
    if (hwndNewTarget!=0)
    {
      /*
       * Find-out if there is a drag target under the mouse
       */
2057
      HWND nexttar = hwndNewTarget;
2058 2059
      trackerInfo->curTargetHWND = hwndNewTarget;

2060 2061 2062 2063 2064
      do {
	newDropTargetNode = OLEDD_FindDropTarget(nexttar);
      } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0);
      if(nexttar) hwndNewTarget = nexttar;

2065 2066
      trackerInfo->curDragTargetHWND = hwndNewTarget;
      trackerInfo->curDragTarget     = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
2067

2068 2069 2070 2071 2072 2073 2074
      /*
       * If there is, notify it that we just dragged-in
       */
      if (trackerInfo->curDragTarget!=0)
      {
	IDropTarget_DragEnter(trackerInfo->curDragTarget,
			      trackerInfo->dataObject,
2075 2076
                              trackerInfo->dwKeyState,
                              trackerInfo->curMousePos,
2077 2078 2079 2080 2081 2082 2083 2084 2085
			      trackerInfo->pdwEffect);
      }
    }
    else
    {
      /*
       * The mouse is not over a window so we don't track anything.
       */
      trackerInfo->curDragTargetHWND = 0;
2086
      trackerInfo->curTargetHWND     = 0;
2087 2088 2089 2090 2091
      trackerInfo->curDragTarget     = 0;
    }
  }

  /*
2092 2093
   * Now that we have done that, we have to tell the source to give
   * us feedback on the work being done by the target.  If we don't
2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111
   * have a target, simulate no effect.
   */
  if (trackerInfo->curDragTarget==0)
  {
    *trackerInfo->pdwEffect = DROPEFFECT_NONE;
  }

  hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
  				*trackerInfo->pdwEffect);

  /*
   * When we ask for feedback from the drop source, sometimes it will
   * do all the necessary work and sometimes it will not handle it
   * when that's the case, we must display the standard drag and drop
   * cursors.
   */
  if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
  {
2112
    if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE)
2113
    {
2114
      SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(1)));
2115 2116 2117
    }
    else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY)
    {
2118
      SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(2)));
2119 2120 2121
    }
    else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK)
    {
2122
      SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(3)));
2123 2124 2125
    }
    else
    {
2126
      SetCursor(LoadCursorA(hProxyDll, MAKEINTRESOURCEA(0)));
2127
    }
2128
  }
2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142
}

/***
 * OLEDD_TrackStateChange()
 *
 * This method is invoked while a drag and drop operation is in effect.
 * It is used to notify the drop target/drop source callbacks when
 * the state of the keyboard or mouse button change.
 *
 * params:
 *    trackerInfo - Pointer to the structure identifying the
 *                  drag & drop operation that is currently
 *                  active.
 */
2143
static void OLEDD_TrackStateChange(TrackerWindowInfo* trackerInfo)
2144 2145 2146 2147 2148 2149
{
  /*
   * Ask the drop source what to do with the operation.
   */
  trackerInfo->returnValue = IDropSource_QueryContinueDrag(
			       trackerInfo->dropSource,
2150
			       trackerInfo->escPressed,
2151
                               trackerInfo->dwKeyState);
2152

2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164
  /*
   * All the return valued will stop the operation except the S_OK
   * return value.
   */
  if (trackerInfo->returnValue!=S_OK)
  {
    /*
     * Make sure the message loop in DoDragDrop stops
     */
    trackerInfo->trackingDone = TRUE;

    /*
2165
     * Release the mouse in case the drop target decides to show a popup
2166 2167 2168
     * or a menu or something.
     */
    ReleaseCapture();
2169

2170
    /*
2171
     * If we end-up over a target, drop the object in the target or
2172 2173 2174 2175 2176 2177 2178
     * inform the target that the operation was cancelled.
     */
    if (trackerInfo->curDragTarget!=0)
    {
      switch (trackerInfo->returnValue)
      {
	/*
2179
	 * If the source wants us to complete the operation, we tell
2180 2181 2182 2183 2184 2185
	 * the drop target that we just dropped the object in it.
	 */
        case DRAGDROP_S_DROP:
	{
	  IDropTarget_Drop(trackerInfo->curDragTarget,
			   trackerInfo->dataObject,
2186 2187
                           trackerInfo->dwKeyState,
                           trackerInfo->curMousePos,
2188 2189 2190 2191
			   trackerInfo->pdwEffect);
	  break;
	}
	/*
2192
	 * If the source told us that we should cancel, fool the drop
2193
	 * target by telling it that the mouse left it's window.
2194
	 * Also set the drop effect to "NONE" in case the application
2195
	 * ignores the result of DoDragDrop.
2196 2197 2198
	 */
        case DRAGDROP_S_CANCEL:
	  IDropTarget_DragLeave(trackerInfo->curDragTarget);
2199
	  *trackerInfo->pdwEffect = DROPEFFECT_NONE;
2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212
	  break;
      }
    }
  }
}

/***
 * OLEDD_GetButtonState()
 *
 * This method will use the current state of the keyboard to build
 * a button state mask equivalent to the one passed in the
 * WM_MOUSEMOVE wParam.
 */
2213
static DWORD OLEDD_GetButtonState(void)
2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237
{
  BYTE  keyboardState[256];
  DWORD keyMask = 0;

  GetKeyboardState(keyboardState);

  if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
    keyMask |= MK_SHIFT;

  if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
    keyMask |= MK_CONTROL;

  if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
    keyMask |= MK_LBUTTON;

  if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
    keyMask |= MK_RBUTTON;

  if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
    keyMask |= MK_MBUTTON;

  return keyMask;
}

2238 2239 2240 2241 2242 2243 2244 2245 2246
/***
 * 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
2247
 *     pdwValue - Pointer to the location where the DWORD
2248 2249 2250 2251 2252
 *                value is returned. This value is not modified
 *                if the value is not found.
 */

static void OLEUTL_ReadRegistryDWORDValue(
2253
  HKEY   regKey,
2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282
  DWORD* pdwValue)
{
  char  buffer[20];
  DWORD dwKeyType;
  DWORD cbData = 20;
  LONG  lres;

  lres = RegQueryValueExA(regKey,
			  "",
			  NULL,
			  &dwKeyType,
			  (LPBYTE)buffer,
			  &cbData);

  if (lres==ERROR_SUCCESS)
  {
    switch (dwKeyType)
    {
      case REG_DWORD:
	*pdwValue = *(DWORD*)buffer;
	break;
      case REG_EXPAND_SZ:
      case REG_MULTI_SZ:
      case REG_SZ:
	*pdwValue = (DWORD)strtoul(buffer, NULL, 10);
	break;
    }
  }
}
2283

Troy Rollo's avatar
Troy Rollo committed
2284
/******************************************************************************
2285
 * OleDraw (OLE32.@)
Troy Rollo's avatar
Troy Rollo committed
2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301
 *
 * The operation of this function is documented literally in the WinAPI
 * documentation to involve a QueryInterface for the IViewObject interface,
 * followed by a call to IViewObject::Draw.
 */
HRESULT WINAPI OleDraw(
	IUnknown *pUnk,
	DWORD dwAspect,
	HDC hdcDraw,
	LPCRECT lprcBounds)
{
  HRESULT hres;
  IViewObject *viewobject;

  hres = IUnknown_QueryInterface(pUnk,
				 &IID_IViewObject,
2302
				 (void**)&viewobject);
Troy Rollo's avatar
Troy Rollo committed
2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322

  if (SUCCEEDED(hres))
  {
    RECTL rectl;

    rectl.left = lprcBounds->left;
    rectl.right = lprcBounds->right;
    rectl.top = lprcBounds->top;
    rectl.bottom = lprcBounds->bottom;
    hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, &rectl, 0, 0, 0);

    IViewObject_Release(viewobject);
    return hres;
  }
  else
  {
    return DV_E_NOIVIEWOBJECT;
  }
}

2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351
/***********************************************************************
 *             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)
{
2352
    HRESULT hres;
2353
    IUnknown * pUnk = NULL;
2354
    IOleObject *pOleObject = NULL;
2355

2356 2357
    TRACE("(%s, %s, %d, %p, %p, %p, %p)\n", debugstr_guid(rclsid),
        debugstr_guid(riid), renderopt, pFormatEtc, pClientSite, pStg, ppvObj);
2358

2359
    hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, riid, (LPVOID*)&pUnk);
2360 2361 2362 2363

    if (SUCCEEDED(hres))
        hres = IStorage_SetClass(pStg, rclsid);

2364
    if (pClientSite && SUCCEEDED(hres))
2365
    {
2366
        hres = IUnknown_QueryInterface(pUnk, &IID_IOleObject, (LPVOID*)&pOleObject);
2367 2368 2369 2370 2371 2372
        if (SUCCEEDED(hres))
        {
            DWORD dwStatus;
            hres = IOleObject_GetMiscStatus(pOleObject, DVASPECT_CONTENT, &dwStatus);
        }
    }
2373

2374
    if (SUCCEEDED(hres))
2375
    {
2376 2377
        IPersistStorage * pPS;
        if (SUCCEEDED((hres = IUnknown_QueryInterface(pUnk, &IID_IPersistStorage, (LPVOID*)&pPS))))
2378
        {
2379 2380
            TRACE("trying to set stg %p\n", pStg);
            hres = IPersistStorage_InitNew(pPS, pStg);
2381
            TRACE("-- result 0x%08x\n", hres);
2382
            IPersistStorage_Release(pPS);
2383 2384 2385
        }
    }

2386 2387 2388 2389
    if (pClientSite && SUCCEEDED(hres))
    {
        TRACE("trying to set clientsite %p\n", pClientSite);
        hres = IOleObject_SetClientSite(pOleObject, pClientSite);
2390
        TRACE("-- result 0x%08x\n", hres);
2391 2392 2393 2394
    }

    if (pOleObject)
        IOleObject_Release(pOleObject);
2395 2396 2397 2398 2399 2400

    if (((renderopt == OLERENDER_DRAW) || (renderopt == OLERENDER_FORMAT)) &&
        SUCCEEDED(hres))
    {
        IRunnableObject *pRunnable;
        IOleCache *pOleCache;
2401
        HRESULT hres2;
2402

2403 2404
        hres2 = IUnknown_QueryInterface(pUnk, &IID_IRunnableObject, (void **)&pRunnable);
        if (SUCCEEDED(hres2))
2405 2406 2407 2408 2409 2410 2411
        {
            hres = IRunnableObject_Run(pRunnable, NULL);
            IRunnableObject_Release(pRunnable);
        }

        if (SUCCEEDED(hres))
        {
2412 2413 2414 2415 2416 2417 2418
            hres2 = IUnknown_QueryInterface(pUnk, &IID_IOleCache, (void **)&pOleCache);
            if (SUCCEEDED(hres2))
            {
                DWORD dwConnection;
                hres = IOleCache_Cache(pOleCache, pFormatEtc, ADVF_PRIMEFIRST, &dwConnection);
                IOleCache_Release(pOleCache);
            }
2419 2420 2421
        }
    }

2422
    if (FAILED(hres) && pUnk)
2423 2424 2425 2426 2427
    {
        IUnknown_Release(pUnk);
        pUnk = NULL;
    }

2428 2429
    *ppvObj = pUnk;

2430
    TRACE("-- %p\n", pUnk);
2431 2432 2433
    return hres;
}

2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460
/******************************************************************************
 *              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;
}

2461 2462 2463 2464 2465
/******************************************************************************
 *              OleSetAutoConvert        [OLE32.@]
 */
HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
{
2466 2467 2468
    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];
2469 2470 2471
    HRESULT res = S_OK;

    TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew));
2472
    
2473 2474 2475
    res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
    if (FAILED(res))
        goto done;
2476 2477
    StringFromGUID2(clsidNew, szClsidNew, CHARS_IN_GUID);
    if (RegSetValueW(hkey, wszAutoConvertTo, REG_SZ, szClsidNew, (strlenW(szClsidNew)+1) * sizeof(WCHAR)))
2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490
    {
        res = REGDB_E_WRITEREGDB;
	goto done;
    }

done:
    if (hkey) RegCloseKey(hkey);
    return res;
}

/******************************************************************************
 *              OleDoAutoConvert        [OLE32.@]
 */
2491
HRESULT WINAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew)
2492 2493 2494 2495 2496
{
    FIXME("(%p,%p) : stub\n",pStg,pClsidNew);
    return E_NOTIMPL;
}

2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509
/******************************************************************************
 *              OleIsRunning        [OLE32.@]
 */
BOOL WINAPI OleIsRunning(LPOLEOBJECT pObject)
{
    IRunnableObject *pRunnable;
    HRESULT hr;
    BOOL running;

    TRACE("(%p)\n", pObject);

    hr = IOleObject_QueryInterface(pObject, &IID_IRunnableObject, (void **)&pRunnable);
    if (FAILED(hr))
2510
        return TRUE;
2511 2512 2513 2514 2515
    running = IRunnableObject_IsRunning(pRunnable);
    IRunnableObject_Release(pRunnable);
    return running;
}

2516 2517 2518 2519 2520 2521 2522 2523 2524 2525
/***********************************************************************
 *           OleNoteObjectVisible			    [OLE32.@]
 */
HRESULT WINAPI OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL bVisible)
{
    TRACE("(%p, %s)\n", pUnknown, bVisible ? "TRUE" : "FALSE");
    return CoLockObjectExternal(pUnknown, bVisible, TRUE);
}


2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539
/***********************************************************************
 *           OLE_FreeClipDataArray   [internal]
 *
 * NOTES:
 *  frees the data associated with an array of CLIPDATAs
 */
static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray)
{
    ULONG i;
    for (i = 0; i < count; i++)
        if (pClipDataArray[i].pClipData)
            CoTaskMemFree(pClipDataArray[i].pClipData);
}

2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555
/***********************************************************************
 *           PropSysAllocString			    [OLE32.@]
 * NOTES:
 *  Basically a copy of SysAllocStringLen.
 */
BSTR WINAPI PropSysAllocString(LPCOLESTR str)
{
    DWORD  bufferSize;
    DWORD* newBuffer;
    WCHAR* stringBuffer;
    int len;

    if (!str) return 0;

    len = lstrlenW(str);
    /*
2556
     * Find the length of the buffer passed-in, in bytes.
2557 2558 2559 2560 2561
     */
    bufferSize = len * sizeof (WCHAR);

    /*
     * Allocate a new buffer to hold the string.
2562
     * Don't forget to keep an empty spot at the beginning of the
2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584
     * buffer for the character count and an extra character at the
     * end for the NULL.
     */
    newBuffer = HeapAlloc(GetProcessHeap(), 0,
                          bufferSize + sizeof(WCHAR) + sizeof(DWORD));

    /*
     * If the memory allocation failed, return a null pointer.
     */
    if (newBuffer==0)
      return 0;

    /*
     * Copy the length of the string in the placeholder.
     */
    *newBuffer = bufferSize;

    /*
     * Skip the byte count.
     */
    newBuffer++;

2585
    memcpy(newBuffer, str, bufferSize);
2586 2587 2588 2589 2590 2591

    /*
     * Make sure that there is a nul character at the end of the
     * string.
     */
    stringBuffer = (WCHAR*)newBuffer;
2592
    stringBuffer[len] = '\0';
2593

2594
    return stringBuffer;
2595 2596 2597 2598 2599 2600 2601
}

/***********************************************************************
 *           PropSysFreeString			    [OLE32.@]
 * NOTES
 *  Copy of SysFreeString.
 */
2602
void WINAPI PropSysFreeString(LPOLESTR str)
2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623
{
    DWORD* bufferPointer;

    /* NULL is a valid parameter */
    if(!str) return;

    /*
     * We have to be careful when we free a BSTR pointer, it points to
     * the beginning of the string but it skips the byte count contained
     * before the string.
     */
    bufferPointer = (DWORD*)str;

    bufferPointer--;

    /*
     * Free the memory from its "real" origin.
     */
    HeapFree(GetProcessHeap(), 0, bufferPointer);
}

2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641
/******************************************************************************
 * Check if a PROPVARIANT's type is valid.
 */
static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt)
{
    switch (vt)
    {
    case VT_EMPTY:
    case VT_NULL:
    case VT_I2:
    case VT_I4:
    case VT_R4:
    case VT_R8:
    case VT_CY:
    case VT_DATE:
    case VT_BSTR:
    case VT_ERROR:
    case VT_BOOL:
2642
    case VT_DECIMAL:
2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684
    case VT_UI1:
    case VT_UI2:
    case VT_UI4:
    case VT_I8:
    case VT_UI8:
    case VT_LPSTR:
    case VT_LPWSTR:
    case VT_FILETIME:
    case VT_BLOB:
    case VT_STREAM:
    case VT_STORAGE:
    case VT_STREAMED_OBJECT:
    case VT_STORED_OBJECT:
    case VT_BLOB_OBJECT:
    case VT_CF:
    case VT_CLSID:
    case VT_I2|VT_VECTOR:
    case VT_I4|VT_VECTOR:
    case VT_R4|VT_VECTOR:
    case VT_R8|VT_VECTOR:
    case VT_CY|VT_VECTOR:
    case VT_DATE|VT_VECTOR:
    case VT_BSTR|VT_VECTOR:
    case VT_ERROR|VT_VECTOR:
    case VT_BOOL|VT_VECTOR:
    case VT_VARIANT|VT_VECTOR:
    case VT_UI1|VT_VECTOR:
    case VT_UI2|VT_VECTOR:
    case VT_UI4|VT_VECTOR:
    case VT_I8|VT_VECTOR:
    case VT_UI8|VT_VECTOR:
    case VT_LPSTR|VT_VECTOR:
    case VT_LPWSTR|VT_VECTOR:
    case VT_FILETIME|VT_VECTOR:
    case VT_CF|VT_VECTOR:
    case VT_CLSID|VT_VECTOR:
        return S_OK;
    }
    WARN("Bad type %d\n", vt);
    return STG_E_INVALIDPARAMETER;
}

2685 2686 2687 2688 2689
/***********************************************************************
 *           PropVariantClear			    [OLE32.@]
 */
HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */
{
2690 2691
    HRESULT hr;

2692 2693 2694 2695 2696
    TRACE("(%p)\n", pvar);

    if (!pvar)
        return S_OK;

2697 2698 2699 2700
    hr = PROPVARIANT_ValidateType(pvar->vt);
    if (FAILED(hr))
        return hr;

2701 2702
    switch(pvar->vt)
    {
2703 2704 2705 2706 2707 2708 2709 2710 2711 2712
    case VT_EMPTY:
    case VT_NULL:
    case VT_I2:
    case VT_I4:
    case VT_R4:
    case VT_R8:
    case VT_CY:
    case VT_DATE:
    case VT_ERROR:
    case VT_BOOL:
2713
    case VT_DECIMAL:
2714 2715 2716 2717 2718 2719 2720
    case VT_UI1:
    case VT_UI2:
    case VT_UI4:
    case VT_I8:
    case VT_UI8:
    case VT_FILETIME:
        break;
2721 2722 2723 2724
    case VT_STREAM:
    case VT_STREAMED_OBJECT:
    case VT_STORAGE:
    case VT_STORED_OBJECT:
2725 2726
        if (pvar->u.pStream)
            IUnknown_Release(pvar->u.pStream);
2727 2728 2729 2730
        break;
    case VT_CLSID:
    case VT_LPSTR:
    case VT_LPWSTR:
2731
        /* pick an arbitrary typed pointer - we don't care about the type
2732 2733 2734 2735 2736 2737 2738 2739
         * 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:
2740
        if (pvar->u.bstrVal)
2741
            PropSysFreeString(pvar->u.bstrVal);
2742
        break;
2743
    case VT_CF:
2744 2745 2746 2747 2748 2749 2750
        if (pvar->u.pclipdata)
        {
            OLE_FreeClipDataArray(1, pvar->u.pclipdata);
            CoTaskMemFree(pvar->u.pclipdata);
        }
        break;
    default:
2751
        if (pvar->vt & VT_VECTOR)
2752
        {
2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777
            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)
            {
2778
                /* pick an arbitrary VT_VECTOR structure - they all have the same
2779 2780 2781
                 * memory layout */
                CoTaskMemFree(pvar->u.capropvar.pElems);
            }
2782
        }
2783 2784
        else
            WARN("Invalid/unsupported type %d\n", pvar->vt);
2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798
    }

    ZeroMemory(pvar, sizeof(*pvar));

    return S_OK;
}

/***********************************************************************
 *           PropVariantCopy			    [OLE32.@]
 */
HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest,      /* [out] */
                               const PROPVARIANT *pvarSrc) /* [in] */
{
    ULONG len;
2799 2800
    HRESULT hr;

2801
    TRACE("(%p, %p vt %04x)\n", pvarDest, pvarSrc, pvarSrc->vt);
2802 2803 2804 2805

    hr = PROPVARIANT_ValidateType(pvarSrc->vt);
    if (FAILED(hr))
        return hr;
2806 2807

    /* this will deal with most cases */
2808
    *pvarDest = *pvarSrc;
2809 2810 2811

    switch(pvarSrc->vt)
    {
2812 2813 2814 2815 2816 2817 2818
    case VT_EMPTY:
    case VT_NULL:
    case VT_I1:
    case VT_UI1:
    case VT_I2:
    case VT_UI2:
    case VT_BOOL:
2819
    case VT_DECIMAL:
2820 2821 2822 2823 2824 2825 2826 2827 2828
    case VT_I4:
    case VT_UI4:
    case VT_R4:
    case VT_ERROR:
    case VT_I8:
    case VT_UI8:
    case VT_R8:
    case VT_CY:
    case VT_DATE:
2829 2830
    case VT_FILETIME:
        break;
2831 2832 2833 2834 2835 2836 2837 2838
    case VT_STREAM:
    case VT_STREAMED_OBJECT:
    case VT_STORAGE:
    case VT_STORED_OBJECT:
        IUnknown_AddRef((LPUNKNOWN)pvarDest->u.pStream);
        break;
    case VT_CLSID:
        pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID));
2839
        *pvarDest->u.puuid = *pvarSrc->u.puuid;
2840 2841 2842
        break;
    case VT_LPSTR:
        len = strlen(pvarSrc->u.pszVal);
2843 2844
        pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR));
        CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR));
2845 2846 2847
        break;
    case VT_LPWSTR:
        len = lstrlenW(pvarSrc->u.pwszVal);
2848 2849
        pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
        CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR));
2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860
        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:
2861
        pvarDest->u.bstrVal = PropSysAllocString(pvarSrc->u.bstrVal);
2862 2863 2864 2865 2866
        break;
    case VT_CF:
        if (pvarSrc->u.pclipdata)
        {
            len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt);
2867 2868 2869
            pvarDest->u.pclipdata = CoTaskMemAlloc(sizeof (CLIPDATA));
            pvarDest->u.pclipdata->cbSize = pvarSrc->u.pclipdata->cbSize;
            pvarDest->u.pclipdata->ulClipFmt = pvarSrc->u.pclipdata->ulClipFmt;
Mike McCormack's avatar
Mike McCormack committed
2870
            pvarDest->u.pclipdata->pClipData = CoTaskMemAlloc(len);
2871 2872 2873 2874 2875 2876 2877
            CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len);
        }
        break;
    default:
        if (pvarSrc->vt & VT_VECTOR)
        {
            int elemSize;
2878 2879 2880
            ULONG i;

            switch(pvarSrc->vt & ~VT_VECTOR)
2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898
            {
            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;
2899 2900 2901
            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;
2902
            case VT_VARIANT:  elemSize = sizeof(*pvarSrc->u.pvarVal); break;
2903 2904

            default:
2905
                FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR);
2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920
                return E_INVALIDARG;
            }
            len = pvarSrc->u.capropvar.cElems;
            pvarDest->u.capropvar.pElems = CoTaskMemAlloc(len * elemSize);
            if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT))
            {
                for (i = 0; i < len; i++)
                    PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]);
            }
            else if (pvarSrc->vt == (VT_VECTOR | VT_CF))
            {
                FIXME("Copy clipformats\n");
            }
            else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR))
            {
2921 2922
                for (i = 0; i < len; i++)
                    pvarDest->u.cabstr.pElems[i] = PropSysAllocString(pvarSrc->u.cabstr.pElems[i]);
2923 2924 2925
            }
            else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR))
            {
2926 2927 2928 2929 2930 2931 2932 2933
                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);
                }
2934
            }
2935
            else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR))
2936
            {
2937 2938 2939 2940 2941 2942 2943 2944 2945
                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);
                }
2946 2947 2948 2949
            }
            else
                CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize);
        }
2950 2951
        else
            WARN("Invalid/unsupported type %d\n", pvarSrc->vt);
2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964
    }

    return S_OK;
}

/***********************************************************************
 *           FreePropVariantArray			    [OLE32.@]
 */
HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */
                                    PROPVARIANT *rgvars)    /* [in/out] */
{
    ULONG i;

2965
    TRACE("(%u, %p)\n", cVariants, rgvars);
2966

2967 2968 2969
    if (!rgvars)
        return E_INVALIDARG;

2970 2971 2972 2973 2974 2975
    for(i = 0; i < cVariants; i++)
        PropVariantClear(&rgvars[i]);

    return S_OK;
}

2976
/******************************************************************************
2977
 * DllDebugObjectRPCHook (OLE32.@)
2978 2979 2980 2981 2982 2983 2984 2985
 * turns on and off internal debugging,  pointer is only used on macintosh
 */

BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy)
{
  FIXME("stub\n");
  return TRUE;
}