//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1996.
//
//  File:       create.cpp
//
//  Contents:   creation and miscellaneous APIs
//
//  Classes:
//
//  Functions:  OleCreate
//              OleCreateEx
//              OleCreateFromData
//              OleCreateFromDataEx
//              OleCreateLinkFromData
//              OleCreateLinkFromDataEx
//              OleCreateLink
//              OleCreateLinkEx
//              OleCreateLinkToFile
//              OleCreateLinkToFileEx
//              OleCreateFromFile
//              OleCreateFromFileEx
//              OleDoAutoConvert
//              OleLoad
//              OleCreateStaticFromData
//              OleQueryCreateFromData
//              OleQueryLinkFromData
//              CoIsHashedOle1Class     (internal)
//              EnsureCLSIDIsRegistered (internal)
//
//  History:    dd-mmm-yy Author    Comment
//              26-Apr-96 davidwor  Moved validation into separate function.
//              01-Mar-96 davidwor  Added extended create functions.
//              16-Dec-94 alexgo    added call tracing
//              07-Jul-94 KevinRo   Changed RegQueryValue to RegOpenKey in
//                                  strategic places.
//              10-May-94 KevinRo   Reimplemented OLE 1.0 interop
//              24-Jan-94 alexgo    first pass at converting to Cairo-style
//                                  memory allocation
//              11-Jan-94 alexgo    added VDATEHEAP macros to every function
//              10-Dec-93 AlexT     header clean up - include ole1cls.h
//              08-Dec-93 ChrisWe   added necessary casts to GlobalLock() calls
//                      resulting from removing bogus GlobalLock() macros in
//                      le2int.h
//              29-Nov-93 ChrisWe   changed call to UtIsFormatSupported to
//                                      take a single DWORD of direction flags
//              22-Nov-93 ChrisWe   replaced overloaded == with IsEqualxID
//              28-Oct-93 alexgo    32bit port
//              24-Aug-92 srinik    created
//
//--------------------------------------------------------------------------

#include <le2int.h>
#pragma SEG(create)

#include <create.h>
#include <ole1cls.h>    //  Only needed to get CLSID_WordDocument

// HACK ALERT!!  This is needed for the MFC OleQueryCreateFromData hack
#include "..\clipbrd\clipdata.h"

NAME_SEG(Create)
ASSERTDATA

//used in wCreateObject

#define STG_NONE        0
#define STG_INITNEW     1
#define STG_LOAD        2


#define QUERY_CREATE_NONE               0
#define QUERY_CREATE_OLE                1
#define QUERY_CREATE_STATIC             2

INTERNAL        wDoUpdate(IUnknown FAR* lpUnknown);


//+-------------------------------------------------------------------------
//
//  Function:   wGetEnumFormatEtc
//
//  Synopsis:   retrieves a FormatEtc enumerator
//
//  Effects:
//
//  Arguments:  [pDataObj]      -- the data object
//              [dwDirection]   -- direction
//              [ppenum]        -- where to put the enumerator
//
//  Requires:
//
//  Returns:
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:  asks the data object for the enumerator
//              if it returns OLE_S_USEREG, then get try to get the
//              clsid from IOleObject::GetUserClassID and enumerate
//              the formats from the registry.
//
//  History:    dd-mmm-yy Author    Comment
//              24-Apr-94 alexgo    author
//		13-Mar-95 scottsk   Added hack for the Bob Calendar
//
//  Notes:
//
//--------------------------------------------------------------------------

HRESULT wGetEnumFormatEtc( IDataObject *pDataObj, DWORD dwDirection,
        IEnumFORMATETC **ppIEnum)
{
    HRESULT         hresult;
    IOleObject *    pOleObject;
    CLSID           clsid;

    VDATEHEAP();

    LEDebugOut((DEB_ITRACE, "%p _IN wGetEnumFormatEtc ( %p , %p , %lx )"
        "\n", NULL, pDataObj, ppIEnum, dwDirection));

    hresult = pDataObj->EnumFormatEtc(dwDirection, ppIEnum);

    if( hresult == ResultFromScode(OLE_S_USEREG) )
    {
        hresult = pDataObj->QueryInterface(IID_IOleObject,
                (void **)&pOleObject);

        if( hresult != NOERROR )
        {
            // return E_FAIL vs E_NOINTERFACE
            hresult = ResultFromScode(E_FAIL);
            goto errRtn;
        }

        hresult = pOleObject->GetUserClassID(&clsid);

        if( hresult == NOERROR )
        {
            hresult = OleRegEnumFormatEtc(clsid, dwDirection,
                    ppIEnum);
        }

        pOleObject->Release();
    }
    else if (*ppIEnum == NULL && hresult == NOERROR)
    {
        // HACK ALERT:  NT Bug #8350.   MS Bob Calendar returns success from
        // IDO::EnumFormatEtc and sets *ppIEnum = NULL on the IDO used during
        // drag-drop.  Massage the return value to be failure.
        hresult = E_FAIL;
    }

errRtn:

    LEDebugOut((DEB_ITRACE, "%p OUT wGetEnumFormatEtc ( %lx ) [ %p ]\n",
        NULL, hresult, *ppIEnum));

    return hresult;
}

//+-------------------------------------------------------------------------
//
//  Function:   OleCreate
//
//  Synopsis:   Creates and runs an object of the requested CLSID
//
//  Effects:
//
//  Arguments:  [rclsid]        -- the CLSID of the object to create
//              [iid]           -- the interface to request on the object
//              [renderopt]     -- render options, such as OLERENDER_DRAW
//              [lpFormatEtc]   -- rendering format, if OLERENDER_FORMAT is
//                                 specified in renderopt.
//              [lpClientSite]  -- the client site for the object
//              [lpStg]         -- the object's storage
//              [lplpObj]       -- where to put the pointer to the created
//                                 object
//
//  Requires:   HRESULT
//
//  Returns:
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		16-Dec-94 alexgo    added call tracing
//              05-May-94 alexgo    fixed error case if cache initialization
//                                  fails.
//              28-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(OleCreate)
STDAPI  OleCreate
(
    REFCLSID                rclsid,
    REFIID                  iid,
    DWORD                   renderopt,
    LPFORMATETC             lpFormatEtc,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg,
    void FAR* FAR*          lplpObj
)
{
    DWORD advf = ADVF_PRIMEFIRST;

    return OleCreateEx(rclsid, iid, 0, renderopt,
	(lpFormatEtc ? 1 : 0), (lpFormatEtc ? &advf : NULL),
	lpFormatEtc, NULL, NULL, lpClientSite, lpStg, lplpObj);
}


//+-------------------------------------------------------------------------
//
//  Function:   OleCreateEx
//
//  Synopsis:   Creates and runs an object of the requested CLSID
//
//  Effects:
//
//  Arguments:  [rclsid]        -- the CLSID of the object to create
//              [iid]           -- the interface to request on the object
//              [dwFlags]       -- object creation flags
//              [renderopt]     -- render options, such as OLERENDER_DRAW
//              [cFormats]      -- the number of elements in rgFormatEtc
//              [rgAdvf]        -- array of advise flags, if OLRENDER_FORMAT
//                                 is specified in renderopt
//              [rgFormatEtc]   -- array of rendering formats, if
//                                 OLERENDER_FORMAT is specified in renderopt
//              [lpAdviseSink]  -- the advise sink for the object
//              [rgdwConnection]-- where to put the connection IDs for the
//                                 advisory connections
//              [lpClientSite]  -- the client site for the object
//              [lpStg]         -- the object's storage
//              [lplpObj]       -- where to put the pointer to the created
//                                 object
//
//  Requires:   HRESULT
//
//  Returns:
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		16-Dec-94 alexgo    added call tracing
//              05-May-94 alexgo    fixed error case if cache initialization
//                                  fails.
//              28-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(OleCreateEx)
STDAPI  OleCreateEx
(
    REFCLSID                rclsid,
    REFIID                  iid,
    DWORD		    dwFlags,
    DWORD                   renderopt,
    ULONG		    cFormats,
    DWORD FAR*		    rgAdvf,
    LPFORMATETC             rgFormatEtc,
    IAdviseSink FAR*	    lpAdviseSink,
    DWORD FAR*		    rgdwConnection,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg,
    void FAR* FAR*          lplpObj
)
{
    OLETRACEIN((API_OleCreateEx,
    		PARAMFMT("rclsid= %I, iid= %I, dwFlags= %x, renderopt= %x, cFormats= %x, rgAdvf= %te, rgFormatEtc= %p, lpAdviseSink= %p, rgdwConnection= %p, lpClientSite= %p, lpStg= %p, lplpObj= %p"),
    		&rclsid, &iid, dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite, lpStg, lplpObj));

    VDATEHEAP();

    HRESULT                 error;
    FORMATETC               formatEtc;
    LPFORMATETC		    lpFormatEtc;
    BOOL		    fAlloced = FALSE;

    LEDebugOut((DEB_TRACE, "%p _IN OleCreateEx ( %p , %p , %lx , %lx , %lx ,"
      "%p , %p , %p , %p , %p , %p , %p )\n", 0, &rclsid, &iid, dwFlags,
      renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection,
      lpClientSite, lpStg, lplpObj));

    VDATEPTROUT_LABEL( lplpObj, LPVOID, errRtn, error );
    *lplpObj = NULL;

    VDATEIID_LABEL( iid, errRtn, error);

    error = wValidateCreateParams(dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite, lpStg);
    if (error != NOERROR)
	goto errRtn;

    if ((error = wValidateFormatEtcEx(renderopt, &cFormats, rgFormatEtc,
	&formatEtc, &lpFormatEtc, &fAlloced)) != NOERROR)
        goto LExit;

    if ((error = wCreateObject(rclsid, iid, lpClientSite, lpStg,
        STG_INITNEW, lplpObj)) != NOERROR)
        goto LExit;

    // No need to Run the object if no caches are requested.
    if ((renderopt != OLERENDER_NONE) && (renderopt != OLERENDER_ASIS))
    {
        if ((error = OleRun((LPUNKNOWN) *lplpObj)) != NOERROR)
            goto LExit;

        if ((error = wInitializeCacheEx(NULL, rclsid, renderopt,
            cFormats, rgAdvf, lpFormatEtc, lpAdviseSink, rgdwConnection,
	    *lplpObj))
	    != NOERROR)
        {
            // if this fails, we need to call Close
            // to shut down the embedding (the reverse of Run).
            // the final release below will be the final
            // one to nuke the memory image.
            IOleObject *    lpOleObject;

            if( ((IUnknown *)*lplpObj)->QueryInterface(
                IID_IOleObject, (void **)&lpOleObject) == NOERROR )
            {
                Assert(lpOleObject);
                lpOleObject->Close(OLECLOSE_NOSAVE);
                lpOleObject->Release();
            }
        }
    }

LExit:

    if (fAlloced)
	PubMemFree(lpFormatEtc);

    if (error != NOERROR && *lplpObj) {
        ((IUnknown FAR*) *lplpObj)->Release();
        *lplpObj = NULL;
    }

    LEDebugOut((DEB_TRACE, "%p OUT OleCreateEx ( %lx ) [ %p ]\n", 0,
      error, *lplpObj));

    error = wReturnCreationError(error);

errRtn:
    OLETRACEOUT((API_OleCreateEx, error));

    return error;
}


//+-------------------------------------------------------------------------
//
//  Function:   OleCreateFromData
//
//  Synopsis:   Creates an embedded object from an IDataObject pointer
//              (such as an data object from the clipboard or from a drag
//              and drop operation)
//
//  Effects:
//
//  Arguments:  [lpSrcDataObj]  -- pointer to the data object from which
//                                 the object should be created
//              [iid]           -- interface ID to request
//              [renderopt]     -- rendering options (same as OleCreate)
//              [lpFormatEtc]   -- render format options (same as OleCreate)
//              [lpClientSite]  -- client site for the object
//              [lpStg]         -- storage for the object
//              [lplpObj]       -- where to put the object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		16-Dec-94 alexgo    added call tracing
//              28-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(OleCreateFromData)
STDAPI  OleCreateFromData
(
  IDataObject FAR*            lpSrcDataObj,
  REFIID                      iid,
  DWORD                       renderopt,
  LPFORMATETC                 lpFormatEtc,
  IOleClientSite FAR*         lpClientSite,
  IStorage FAR*               lpStg,
  void FAR* FAR*              lplpObj
)
{
    DWORD advf = ADVF_PRIMEFIRST;

    return OleCreateFromDataEx(lpSrcDataObj, iid, 0, renderopt,
	(lpFormatEtc ? 1 : 0), (lpFormatEtc ? &advf : NULL),
	lpFormatEtc, NULL, NULL, lpClientSite, lpStg, lplpObj);
}


//+-------------------------------------------------------------------------
//
//  Function:   OleCreateFromDataEx
//
//  Synopsis:   Creates an embedded object from an IDataObject pointer
//              (such as an data object from the clipboard or from a drag
//              and drop operation)
//
//  Effects:
//
//  Arguments:  [lpSrcDataObj]  -- pointer to the data object from which
//                                 the object should be created
//              [iid]           -- interface ID to request
//              [dwFlags]       -- object creation flags
//              [renderopt]     -- render options, such as OLERENDER_DRAW
//              [cFormats]      -- the number of elements in rgFormatEtc
//              [rgAdvf]        -- array of advise flags, if OLRENDER_FORMAT
//                                 is specified in renderopt
//              [rgFormatEtc]   -- array of rendering formats, if
//                                 OLERENDER_FORMAT is specified in renderopt
//              [lpAdviseSink]  -- the advise sink for the object
//              [rgdwConnection]-- where to put the connection IDs for the
//                                 advisory connections
//              [lpClientSite]  -- client site for the object
//              [lpStg]         -- storage for the object
//              [lplpObj]       -- where to put the object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		16-Dec-94 alexgo    added call tracing
//              28-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(OleCreateFromDataEx)
STDAPI  OleCreateFromDataEx
(
    IDataObject FAR*        lpSrcDataObj,
    REFIID                  iid,
    DWORD		    dwFlags,
    DWORD                   renderopt,
    ULONG		    cFormats,
    DWORD FAR*		    rgAdvf,
    LPFORMATETC             rgFormatEtc,
    IAdviseSink FAR*	    lpAdviseSink,
    DWORD FAR*		    rgdwConnection,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg,
    void FAR* FAR*          lplpObj
)
{
    HRESULT 	hresult;
    CLIPFORMAT      cfFormat;
    WORD            wStatus;

    OLETRACEIN((API_OleCreateFromDataEx,
    	PARAMFMT("lpSrcDataObj= %p, iid= %I, dwFlags= %x, renderopt= %x, cFormats= %x, rgAdvf= %te, rgFormatEtc= %p, lpAdviseSink= %p, rgdwConnection= %p, lpClientSite= %p, lpStg= %p, lplpObj= %p"),
    	lpSrcDataObj, &iid, dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite, lpStg, lplpObj));

    VDATEHEAP();

    LEDebugOut((DEB_TRACE, "%p _IN OleCreateFromDataEx ( %p , %p , %lx , %lx ,"
	" %lx , %p , %p , %p , %p , %p , %p , %p )\n", 0, lpSrcDataObj, &iid,
	dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink,
	rgdwConnection, lpClientSite, lpStg, lplpObj));

    VDATEPTROUT_LABEL( lplpObj, LPVOID, safeRtn, hresult );
    *lplpObj = NULL;

    VDATEIFACE_LABEL( lpSrcDataObj, errRtn, hresult );
    VDATEIID_LABEL( iid, errRtn, hresult );

    hresult = wValidateCreateParams(dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite, lpStg);
    if (hresult != NOERROR)
	goto errRtn;

    wStatus = wQueryEmbedFormats(lpSrcDataObj, &cfFormat);

    if (!(wStatus & QUERY_CREATE_OLE))
    {
        if (wStatus & QUERY_CREATE_STATIC)
        {
            hresult = OLE_E_STATIC;
        }
        else
        {
            hresult = DV_E_FORMATETC;
        }

        goto errRtn;
    }

    // We can create an OLE object.

    // See whether we have to create a package

    //BUGBUG: REVIEW32:  wQueryEmbedFormats returns the *first*
    //format available, not necessarily the one we wanted.
    //do we necessarily want to create a package, especially if
    //a "normal" embedding format is available??

    if (cfFormat == g_cfFileName || cfFormat == g_cfFileNameW)
    {
        hresult = wCreatePackageEx(lpSrcDataObj, iid, dwFlags, renderopt,
            cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection,
	    lpClientSite, lpStg, FALSE /*fLink*/, lplpObj);
    }
    else
    {
        hresult =  wCreateFromDataEx(lpSrcDataObj, iid, dwFlags, renderopt,
	    cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection,
	    lpClientSite, lpStg, lplpObj);
    }

errRtn:

    LEDebugOut((DEB_TRACE, "%p OUT OleCreateFromDataEx ( %lx ) [ %p ]\n",
        0, hresult, *lplpObj));

safeRtn:

    OLETRACEOUT((API_OleCreateFromDataEx, hresult));

    return hresult;
}



//+-------------------------------------------------------------------------
//
//  Function:   OleCreateLinkFromData
//
//  Synopsis:   Creates a link from a data object (e.g. for Paste->Link)
//
//  Effects:
//
//  Arguments:  [lpSrcDataObj]  -- pointer to the data object
//              [iid]           -- requested interface ID
//              [renderopt]     -- rendering options
//              [lpFormatEtc]   -- format to render (if renderopt ==
//                                 OLERENDER_FORMAT)
//              [lpClientSite]  -- pointer to the client site
//              [lpStg]         -- pointer to the storage
//              [lplpObj]       -- where to put the object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		16-Dec-94 alexgo    added call tracing
//              28-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(OleCreateLinkFromData)
STDAPI  OleCreateLinkFromData
(
  IDataObject FAR*            lpSrcDataObj,
  REFIID                      iid,
  DWORD                       renderopt,
  LPFORMATETC                 lpFormatEtc,
  IOleClientSite FAR*          lpClientSite,
  IStorage FAR*                lpStg,
  void FAR* FAR*               lplpObj
)
{
    DWORD advf = ADVF_PRIMEFIRST;

    return OleCreateLinkFromDataEx(lpSrcDataObj, iid, 0, renderopt,
	(lpFormatEtc ? 1 : 0), (lpFormatEtc ? &advf : NULL),
	lpFormatEtc, NULL, NULL, lpClientSite, lpStg, lplpObj);
}


//+-------------------------------------------------------------------------
//
//  Function:   OleCreateLinkFromDataEx
//
//  Synopsis:   Creates a link from a data object (e.g. for Paste->Link)
//
//  Effects:
//
//  Arguments:  [lpSrcDataObj]  -- pointer to the data object
//              [iid]           -- requested interface ID
//              [dwFlags]       -- object creation flags
//              [renderopt]     -- render options, such as OLERENDER_DRAW
//              [cFormats]      -- the number of elements in rgFormatEtc
//              [rgAdvf]        -- array of advise flags, if OLRENDER_FORMAT
//                                 is specified in renderopt
//              [rgFormatEtc]   -- array of rendering formats, if
//                                 OLERENDER_FORMAT is specified in renderopt
//              [lpAdviseSink]  -- the advise sink for the object
//              [rgdwConnection]-- where to put the connection IDs for the
//                                 advisory connections
//              [lpClientSite]  -- pointer to the client site
//              [lpStg]         -- pointer to the storage
//              [lplpObj]       -- where to put the object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		16-Dec-94 alexgo    added call tracing
//              28-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(OleCreateLinkFromDataEx)
STDAPI  OleCreateLinkFromDataEx
(
    IDataObject FAR*        lpSrcDataObj,
    REFIID                  iid,
    DWORD		    dwFlags,
    DWORD                   renderopt,
    ULONG		    cFormats,
    DWORD FAR*		    rgAdvf,
    LPFORMATETC             rgFormatEtc,
    IAdviseSink FAR*	    lpAdviseSink,
    DWORD FAR*		    rgdwConnection,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg,
    void FAR* FAR*          lplpObj
)
{
    OLETRACEIN((API_OleCreateLinkFromDataEx,
    	PARAMFMT("lpSrcDataObj= %p, iid= %I, dwFlags= %x, renderopt= %x, cFormats= %x, rgAdvf= %te, rgFormatEtc= %p, lpAdviseSink= %p, rgdwConnection= %p, lpClientSite= %p, lpStg= %p, lplpObj= %p"),
    	lpSrcDataObj, &iid, dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite, lpStg, lplpObj));

    VDATEHEAP();

    HRESULT         error;
    FORMATETC       formatEtc;
    LPFORMATETC	    lpFormatEtc;
    BOOL	    fAlloced = FALSE;
    CLIPFORMAT      cfFormat;

    LEDebugOut((DEB_TRACE, "%p _IN OleCreateLinkFromDataEx ( %p , %p , %lx,"
	" %lx, %lx , %p , %p , %p, %p , %p , %p, %p )\n", NULL, lpSrcDataObj,
	&iid, dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink,
	rgdwConnection, lpClientSite, lpStg, lplpObj));

    VDATEPTROUT_LABEL( lplpObj, LPVOID, safeRtn, error );
    *lplpObj = NULL;

    VDATEIFACE_LABEL( lpSrcDataObj, errRtn, error );
    VDATEIID_LABEL( iid, errRtn, error );

    error = wValidateCreateParams(dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite, lpStg);
    if (error != NOERROR)
	goto errRtn;

    cfFormat = wQueryLinkFormats(lpSrcDataObj);

    if (cfFormat == g_cfLinkSource) {
        CLSID                   clsidLast;
        LPMONIKER               lpmkSrc;
        LPDATAOBJECT    lpBoundDataObj = NULL;

        // we are going to create a normal link
        if ((error = wValidateFormatEtcEx(renderopt, &cFormats, rgFormatEtc,
	    &formatEtc, &lpFormatEtc, &fAlloced)) != NOERROR)
	{
            goto errRtn;
	}

        if ((error = wGetMonikerAndClassFromObject(lpSrcDataObj,
            &lpmkSrc, &clsidLast)) != NOERROR)
	{
            goto errRtn;
	}

        if (wQueryUseCustomLink(clsidLast)) {
            // the object supports Custom Link Source, so bind
            // to the object and pass its IDataObject pointer
            // to wCreateLinkEx()

            if (BindMoniker(lpmkSrc, NULL /*grfOpt*/, IID_IDataObject,
		(LPLPVOID) &lpBoundDataObj) == NOERROR)
	    {
                lpSrcDataObj = lpBoundDataObj;
	    }
        }

        // otherwise continue to use StdOleLink implementation
        error = wCreateLinkEx(lpmkSrc, clsidLast, lpSrcDataObj, iid,
            dwFlags, renderopt, cFormats, rgAdvf, lpFormatEtc, lpAdviseSink,
	    rgdwConnection, lpClientSite, lpStg, lplpObj);

        // we don't need the moniker anymore
        lpmkSrc->Release();

        // we would have bound in the custom link source case,
        // release the pointer
        if (lpBoundDataObj)
	{
	    if (error == NOERROR && (dwFlags & OLECREATE_LEAVERUNNING))
		OleRun((LPUNKNOWN)*lplpObj);

            lpBoundDataObj->Release();
	}

    } else if (cfFormat == g_cfFileName || cfFormat == g_cfFileNameW) {
        // See whether we have to create a packaged link

        error = wCreatePackageEx(lpSrcDataObj, iid, dwFlags, renderopt,
            cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection,
	    lpClientSite, lpStg, TRUE /*fLink*/, lplpObj);
    }
    else
    {
	error = DV_E_FORMATETC;
    }

errRtn:

    if (fAlloced)
	PubMemFree(lpFormatEtc);

    LEDebugOut((DEB_TRACE, "%p OUT OleCreateLinkFromDataEx ( %lx ) [ %p ]\n",
	NULL, error, *lplpObj));

safeRtn:

    OLETRACEOUT((API_OleCreateLinkFromDataEx, error));

    return error;
}


//+-------------------------------------------------------------------------
//
//  Function:   OleCreateLink
//
//  Synopsis:   Create a link to the object referred to by a moniker
//
//  Effects:
//
//  Arguments:  [lpmkSrc]       -- source of the link
//              [iid]           -- interface requested
//              [renderopt]     -- rendering options
//              [lpFormatEtc]   -- rendering format (if needed)
//              [lpClientSite]  -- pointer to the client site for the link
//              [lpStg]         -- storage for the link
//              [lplpObj]       -- where to put the link object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		16-Dec-94 alexgo    added call tracing
//              28-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(OleCreateLink)
STDAPI  OleCreateLink
(
    IMoniker FAR*           lpmkSrc,
    REFIID                  iid,
    DWORD                   renderopt,
    LPFORMATETC             lpFormatEtc,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg,
    void FAR* FAR*          lplpObj
)
{
    DWORD advf = ADVF_PRIMEFIRST;

    return OleCreateLinkEx(lpmkSrc, iid, 0, renderopt,
	(lpFormatEtc ? 1 : 0), (lpFormatEtc ? &advf : NULL),
	lpFormatEtc, NULL, NULL, lpClientSite, lpStg, lplpObj);
}


//+-------------------------------------------------------------------------
//
//  Function:   OleCreateLinkEx
//
//  Synopsis:   Create a link to the object referred to by a moniker
//
//  Effects:
//
//  Arguments:  [lpmkSrc]       -- source of the link
//              [iid]           -- interface requested
//              [dwFlags]       -- object creation flags
//              [renderopt]     -- render options, such as OLERENDER_DRAW
//              [cFormats]      -- the number of elements in rgFormatEtc
//              [rgAdvf]        -- array of advise flags, if OLRENDER_FORMAT
//                                 is specified in renderopt
//              [rgFormatEtc]   -- array of rendering formats, if
//                                 OLERENDER_FORMAT is specified in renderopt
//              [lpAdviseSink]  -- the advise sink for the object
//              [rgdwConnection]-- where to put the connection IDs for the
//                                 advisory connections
//              [lpClientSite]  -- pointer to the client site for the link
//              [lpStg]         -- storage for the link
//              [lplpObj]       -- where to put the link object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		16-Dec-94 alexgo    added call tracing
//              28-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(OleCreateLinkEx)
STDAPI  OleCreateLinkEx
(
    IMoniker FAR*           lpmkSrc,
    REFIID                  iid,
    DWORD		    dwFlags,
    DWORD                   renderopt,
    ULONG		    cFormats,
    DWORD FAR*		    rgAdvf,
    LPFORMATETC             rgFormatEtc,
    IAdviseSink FAR*	    lpAdviseSink,
    DWORD FAR*		    rgdwConnection,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg,
    void FAR* FAR*          lplpObj
)
{
    OLETRACEIN((API_OleCreateLinkEx,
    	PARAMFMT("lpmkSrc= %p, iid= %I, dwFlags= %x, renderopt= %x, cFormats= %x, rgAdvf= %te, rgFormatEtc= %p, lpAdviseSink= %p, rgdwConnection= %p, lpClientSite= %p, lpStg= %p, lplpObj= %p"),
    	lpmkSrc, &iid, dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite, lpStg, lplpObj));
    	
    VDATEHEAP();

    FORMATETC       formatEtc;
    LPFORMATETC	    lpFormatEtc;
    BOOL	    fAlloced = FALSE;
    HRESULT         error;

    LEDebugOut((DEB_TRACE, "%p _IN OleCreateLinkEx ( %p , %p , %lx, %lx,"
	" %lx , %p , %p , %p, %p , %p , %p , %p )\n", NULL, lpmkSrc, &iid,
	dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink,
	rgdwConnection, lpClientSite, lpStg, lplpObj));

    VDATEPTROUT_LABEL( lplpObj, LPVOID, errRtn, error );
    *lplpObj = NULL;

    VDATEIFACE_LABEL( lpmkSrc, errRtn, error);
    VDATEIID_LABEL( iid, errRtn, error );

    error = wValidateCreateParams(dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite, lpStg);
    if (error != NOERROR)
	goto errRtn;

    if ((error = wValidateFormatEtcEx(renderopt, &cFormats, rgFormatEtc,
	&formatEtc, &lpFormatEtc, &fAlloced)) == NOERROR)
    {
	error = wCreateLinkEx(lpmkSrc, CLSID_NULL, NULL /* lpSrcDataObj */,
	    iid, dwFlags, renderopt, cFormats, rgAdvf, lpFormatEtc,
	    lpAdviseSink, rgdwConnection, lpClientSite, lpStg, lplpObj);

	if (fAlloced)
	    PubMemFree(lpFormatEtc);
    }

    LEDebugOut((DEB_TRACE, "%p OUT OleCreateLinkEx ( %lx ) [ %p ]\n", NULL,
	error, *lplpObj));

errRtn:
    OLETRACEOUT((API_OleCreateLinkEx, error));

    return error;
}


//+-------------------------------------------------------------------------
//
//  Function:   OleCreateLinkToFile
//
//  Synopsis:   Creates a link object to the file specified in [lpszFileName]
//
//  Effects:
//
//  Arguments:  [lpszFileName]  --  the name of the file
//              [iid]           --  interface ID requested
//              [renderopt]     --  rendering options
//              [lpFormatEtc]   --  format in which to render (if [renderopt]
//                                  == OLERENDER_FORMAT);
//              [lpClientSite]  --  pointer to the client site for the link
//              [lpStg]         --  pointer to the storage for the object
//              [lplpObj]       --  where to put a pointer to new link object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		16-Dec-94 alexgo    added call tracing
//              28-Oct-93 alexgo    32bit port, fixed memory leak in error
//                                      case
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(OleCreateLinkToFile)
STDAPI  OleCreateLinkToFile
(
    LPCOLESTR                       lpszFileName,
    REFIID                  iid,
    DWORD                   renderopt,
    LPFORMATETC             lpFormatEtc,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg,
    void FAR* FAR*          lplpObj
)
{
    DWORD advf = ADVF_PRIMEFIRST;

    return OleCreateLinkToFileEx(lpszFileName, iid, 0, renderopt,
	(lpFormatEtc ? 1 : 0), (lpFormatEtc ? &advf : NULL),
	lpFormatEtc, NULL, NULL, lpClientSite, lpStg, lplpObj);
}



//+-------------------------------------------------------------------------
//
//  Function:   OleCreateLinkToFileEx
//
//  Synopsis:   Creates a link object to the file specified in [lpszFileName]
//
//  Effects:
//
//  Arguments:  [lpszFileName]  --  the name of the file
//              [iid]           --  interface ID requested
//              [dwFlags]       -- object creation flags
//              [renderopt]     -- render options, such as OLERENDER_DRAW
//              [cFormats]      -- the number of elements in rgFormatEtc
//              [rgAdvf]        -- array of advise flags, if OLRENDER_FORMAT
//                                 is specified in renderopt
//              [rgFormatEtc]   -- array of rendering formats, if
//                                 OLERENDER_FORMAT is specified in renderopt
//              [lpAdviseSink]  -- the advise sink for the object
//              [rgdwConnection]-- where to put the connection IDs for the
//                                 advisory connections
//              [lpClientSite]  --  pointer to the client site for the link
//              [lpStg]         --  pointer to the storage for the object
//              [lplpObj]       --  where to put a pointer to new link object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		16-Dec-94 alexgo    added call tracing
//              28-Oct-93 alexgo    32bit port, fixed memory leak in error
//                                      case
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(OleCreateLinkToFileEx)
STDAPI  OleCreateLinkToFileEx
(
    LPCOLESTR               lpszFileName,
    REFIID                  iid,
    DWORD		    dwFlags,
    DWORD                   renderopt,
    ULONG		    cFormats,
    DWORD FAR*		    rgAdvf,
    LPFORMATETC             rgFormatEtc,
    IAdviseSink FAR*	    lpAdviseSink,
    DWORD FAR*		    rgdwConnection,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg,
    void FAR* FAR*          lplpObj
)
{
    OLETRACEIN((API_OleCreateLinkToFileEx,
    	PARAMFMT("lpszFileName= %ws, iid= %I, dwFlags= %x, renderopt= %x, cFormats= %x, rgAdvf= %te, rgFormatEtc= %p, lpAdviseSink= %p, rgdwConnection= %p, lpClientSite= %p, lpStg= %p, lplpObj= %p"),
    	lpszFileName, &iid, dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite, lpStg, lplpObj));
    	
    VDATEHEAP();

    LPMONIKER       lpmkFile = NULL;
    LPDATAOBJECT    lpDataObject = NULL;
    HRESULT         error;
    BOOL            fPackagerMoniker = FALSE;
    CLSID           clsidFile;

    LEDebugOut((DEB_TRACE, "%p _IN OleCreateLinkToFileEx ( \"%s\" , %p , %lx ,"
	" %lx , %lx , %p , %p , %p, %p , %p , %p , %p )\n", NULL, lpszFileName,
	&iid, dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink,
	rgdwConnection, lpClientSite, lpStg, lplpObj));

    VDATEPTROUT_LABEL( lplpObj, LPVOID, safeRtn, error );
    *lplpObj = NULL;

    VDATEPTRIN_LABEL( (LPVOID)lpszFileName, OLECHAR, logRtn, error );
    VDATEIID_LABEL( iid, logRtn, error );

    error = wValidateCreateParams(dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite, lpStg);
    if (error != NOERROR)
	goto logRtn;

    if (((error = wGetMonikerAndClassFromFile(lpszFileName,
        TRUE /*fLink*/, &lpmkFile, &fPackagerMoniker, &clsidFile,&lpDataObject))
        != NOERROR))
    {
	goto logRtn;
    }

    Verify(lpmkFile);

   if (fPackagerMoniker) {
        // wValidateFormatEtc() will be done in wCreateFromFile()

	Assert(NULL == lpDataObject); // Shouldn't be a BoundDataObject for Packager.

        error =  wCreateFromFileEx(lpmkFile,lpDataObject, iid, dwFlags, renderopt,
            cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection,
	    lpClientSite, lpStg, lplpObj);

    } else {
	FORMATETC       formatEtc;
	LPFORMATETC	lpFormatEtc;
	BOOL		fAlloced = FALSE;

        if ((error = wValidateFormatEtcEx(renderopt, &cFormats, rgFormatEtc,
	    &formatEtc, &lpFormatEtc, &fAlloced)) != NOERROR)
	{
            goto ErrRtn;
	}

        error = wCreateLinkEx(lpmkFile, clsidFile, lpDataObject,
            iid, dwFlags, renderopt, cFormats, rgAdvf, lpFormatEtc,
	    lpAdviseSink, rgdwConnection, lpClientSite, lpStg, lplpObj);

	if (fAlloced)
	    PubMemFree(lpFormatEtc);
    }

ErrRtn:

    if (lpmkFile)
    {
	lpmkFile->Release();
    }

    // if the moniker was bound in CreateFromFile, release it now.
    if (lpDataObject)
    {
	lpDataObject->Release();
    }

    if (error == NOERROR && !lpAdviseSink) {
        wStuffIconOfFileEx(lpszFileName, TRUE /*fAddLabel*/,
	    renderopt, cFormats, rgFormatEtc, (LPUNKNOWN) *lplpObj);
    }

logRtn:

    LEDebugOut((DEB_TRACE, "%p OUT OleCreateLinkToFileEx ( %lx ) [ %p ]\n",
	NULL, error, *lplpObj));

safeRtn:
    OLETRACEOUT((API_OleCreateLinkToFileEx, error));

    return error;
}



//+-------------------------------------------------------------------------
//
//  Function:   OleCreateFromFile
//
//  Synopsis:   Creates an ole object for embedding from a file (for
//              InstertObject->From File type things)
//
//  Effects:
//
//  Arguments:  [rclsid]        -- CLSID to use for creating the object
//              [lpszFileName]  -- the filename
//              [iid]           -- the requested interface ID
//              [renderopt]     -- rendering options
//              [lpFormatEtc]   -- rendering format (if needed)
//              [lpClientSite]  -- pointer to the object's client site
//              [lpStg]         -- pointer to the storage for the object
//              [lplpObj]       -- where to put the pointer to the new object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		16-Dec-94 alexgo    added call tracing
//              28-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(OleCreateFromFile)
STDAPI  OleCreateFromFile
(
    REFCLSID                rclsid,
    LPCOLESTR                       lpszFileName,
    REFIID                  iid,
    DWORD                   renderopt,
    LPFORMATETC             lpFormatEtc,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg,
    void FAR* FAR*          lplpObj
)
{
    DWORD advf = ADVF_PRIMEFIRST;

    return OleCreateFromFileEx(rclsid, lpszFileName, iid, 0, renderopt,
	(lpFormatEtc ? 1 : 0), (lpFormatEtc ? &advf : NULL),
	lpFormatEtc, NULL, NULL, lpClientSite, lpStg, lplpObj);
}


//+-------------------------------------------------------------------------
//
//  Function:   OleCreateFromFileEx
//
//  Synopsis:   Creates an ole object for embedding from a file (for
//              InstertObject->From File type things)
//
//  Effects:
//
//  Arguments:  [rclsid]        -- CLSID to use for creating the object
//              [lpszFileName]  -- the filename
//              [iid]           -- the requested interface ID
//              [dwFlags]       -- object creation flags
//              [renderopt]     -- render options, such as OLERENDER_DRAW
//              [cFormats]      -- the number of elements in rgFormatEtc
//              [rgAdvf]        -- array of advise flags, if OLRENDER_FORMAT
//                                 is specified in renderopt
//              [rgFormatEtc]   -- array of rendering formats, if
//                                 OLERENDER_FORMAT is specified in renderopt
//              [lpAdviseSink]  -- the advise sink for the object
//              [rgdwConnection]-- where to put the connection IDs for the
//                                 advisory connections
//              [lpClientSite]  -- pointer to the object's client site
//              [lpStg]         -- pointer to the storage for the object
//              [lplpObj]       -- where to put the pointer to the new object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		16-Dec-94 alexgo    added call tracing
//              28-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(OleCreateFromFileEx)
STDAPI  OleCreateFromFileEx
(
    REFCLSID                rclsid,
    LPCOLESTR               lpszFileName,
    REFIID                  iid,
    DWORD		    dwFlags,
    DWORD                   renderopt,
    ULONG		    cFormats,
    DWORD FAR*		    rgAdvf,
    LPFORMATETC             rgFormatEtc,
    IAdviseSink FAR*	    lpAdviseSink,
    DWORD FAR*		    rgdwConnection,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg,
    void FAR* FAR*          lplpObj
)
{
    OLETRACEIN((API_OleCreateFromFileEx,
    	PARAMFMT("rclsid= %I, lpszFileName= %ws, iid= %I, dwFlags= %x, renderopt= %x, cFormats= %x, rgAdvf= %te, rgFormatEtc= %p, lpAdviseSink= %p, rgdwConnection= %p, lpClientSite= %p, lpStg= %p, lplpObj= %p"),
    	&rclsid, lpszFileName, &iid, dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite, lpStg, lplpObj));

    VDATEHEAP();

    LPMONIKER               lpmkFile = NULL;
    LPDATAOBJECT	    lpDataObject = NULL;
    HRESULT                 error;
    CLSID                   clsid;

    LEDebugOut((DEB_TRACE, "%p _IN OleCreateFromFileEx ( %p , \"%s\" , %p ,"
	" %lx , %lx , %lx , %p , %p , %p , %p , %p , %p , %p )\n", NULL,
	&rclsid, lpszFileName, &iid, dwFlags, renderopt, cFormats, rgAdvf,
	rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite, lpStg,
	lplpObj));

    VDATEPTROUT_LABEL( lplpObj, LPVOID, safeRtn, error );
    *lplpObj = NULL;

    VDATEPTRIN_LABEL( (LPVOID)lpszFileName, char, errRtn, error );
    VDATEIID_LABEL( iid, errRtn, error );

    error = wValidateCreateParams(dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite, lpStg);
    if (error != NOERROR)
	goto errRtn;

    if (((error = wGetMonikerAndClassFromFile(lpszFileName,
        FALSE /*fLink*/, &lpmkFile, NULL /*lpfPackagerMoniker*/,
        &clsid,&lpDataObject)) != NOERROR))
    {
        goto errRtn;
    }

    Verify(lpmkFile);

    // wValidateFormatEtc() will be done in wCreateFromFile()
    error = wCreateFromFileEx(lpmkFile,lpDataObject, iid, dwFlags, renderopt, cFormats,
	rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite,
	lpStg, lplpObj);

    if (lpDataObject)
    {
	lpDataObject->Release();
    }

    if (lpmkFile)
    {
	lpmkFile->Release();
    }


    if (error == NOERROR && !lpAdviseSink) {
        wStuffIconOfFileEx(lpszFileName, FALSE /*fAddLabel*/,
            renderopt, cFormats, rgFormatEtc, (LPUNKNOWN) *lplpObj);
    }

errRtn:

    LEDebugOut((DEB_TRACE, "%p OUT OleCreateFromFileEx ( %lx ) [ %p ]\n",
	NULL, error, *lplpObj));

safeRtn:

    OLETRACEOUT((API_OleCreateFromFileEx, error));

    return error;
}


//+-------------------------------------------------------------------------
//
//  Function:   OleDoAutoConvert
//
//  Synopsis:   Converts the storage to use the clsid given in
//              [pClsidNew].  Private ole streams are updated with the new
//              info
//
//  Effects:
//
//  Arguments:  [pStg]          -- storage to modify
//              [pClsidNew]     -- pointer to the new class ID
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              28-Oct-93 alexgo    32bit port
//
//  Notes:      REVIEW32:  this function should be rewritten to use
//              the new internal API for writing to ole-private streams
//
//--------------------------------------------------------------------------

#pragma SEG(OleDoAutoConvert)
STDAPI OleDoAutoConvert(LPSTORAGE pStg, LPCLSID pClsidNew)
{
    OLETRACEIN((API_OleDoAutoConvert, PARAMFMT("pStg= %p, pClsidNew= %I"),
	pStg, pClsidNew));

    VDATEHEAP();

    HRESULT error;
    CLSID clsidOld;
    CLIPFORMAT cfOld;
    LPOLESTR lpszOld = NULL;
    LPOLESTR lpszNew = NULL;

    if ((error = ReadClassStg(pStg, &clsidOld)) != NOERROR) {
        clsidOld = CLSID_NULL;
        goto errRtn;
    }

    if ((error = OleGetAutoConvert(clsidOld, pClsidNew)) != NOERROR)
        goto errRtn;

    // read old fmt/old user type; sets out params to NULL on error
    error = ReadFmtUserTypeStg(pStg, &cfOld, &lpszOld);
    Assert(error == NOERROR || (cfOld == NULL && lpszOld == NULL));

    // get new user type name; if error, set to NULL string
    if ((error = OleRegGetUserType(*pClsidNew, USERCLASSTYPE_FULL,
        &lpszNew)) != NOERROR)
        lpszNew = NULL;

    // write class stg
    if ((error = WriteClassStg(pStg, *pClsidNew)) != NOERROR)
        goto errRtn;

    // write old fmt/new user type;
    if ((error = WriteFmtUserTypeStg(pStg, cfOld, lpszNew)) != NOERROR)
        goto errRewriteInfo;

    // set convert bit
    if ((error = SetConvertStg(pStg, TRUE)) != NOERROR)
        goto errRewriteInfo;

    goto okRtn;

errRewriteInfo:
    (void)WriteClassStg(pStg, clsidOld);
    (void)WriteFmtUserTypeStg(pStg, cfOld, lpszOld);

errRtn:
    *pClsidNew = clsidOld;

okRtn:
    PubMemFree(lpszOld);
    PubMemFree(lpszNew);

    OLETRACEOUT((API_OleDoAutoConvert, error));
    return error;
}


//+-------------------------------------------------------------------------
//
//  Function:   OleLoad
//
//  Synopsis:   Loads an object from the given storage
//
//  Effects:
//
//  Arguments:  [lpStg]         -- the storage to load from
//              [iid]           -- the requested interface ID
//              [lpClientSite]  -- client site for the object
//              [lplpObj]       -- where to put the pointer to the
//                                 new object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		16-Dec-94 alexgo    added call tracing
//              28-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(OleLoad)
STDAPI  OleLoad
(
    IStorage FAR*           lpStg,
    REFIID                  iid,
    IOleClientSite FAR*     lpClientSite,
    void FAR* FAR*          lplpObj
)
{
    OLETRACEIN((API_OleLoad, PARAMFMT("lpStg= %p, iid= %I, lpClientSite= %p, lplpObj= %p"),
	lpStg, &iid, lpClientSite, lplpObj));

    VDATEHEAP();

    HRESULT error;

    LEDebugOut((DEB_TRACE, "%p _IN OleLoad ( %p , %p , %p , %p )\n",
	NULL, lpStg, &iid, lpClientSite, lplpObj));

    if ((error = OleLoadWithoutBinding(lpStg, iid, lpClientSite, lplpObj))
        == NOERROR) {
        // The caller specify that he want a disconnected object by
        // passing NULL for pClientSite
        if (lpClientSite != NULL)
            wBindIfRunning((LPUNKNOWN) *lplpObj);
    }

    LEDebugOut((DEB_TRACE, "%p OUT OleLoad ( %lx ) [ %p ]\n", NULL, error,
	(error == NOERROR ? *lplpObj : NULL)));

    OLETRACEOUT((API_OleLoad, error));

    return error;
}

//+-------------------------------------------------------------------------
//
//  Function:   OleLoadWithoutBinding
//
//  Synopsis:   Internal function to load/create an object from a storage
//              called by OleLoad, etc.
//
//  Effects:
//
//  Arguments:  [lpStg]         -- storage to load from
//              [iid]           -- requested interface ID
//              [lpClientSite]  -- pointer to the client site
//              [lplpObj]       -- where to put the pointer to the object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              28-Oct-93 alexgo    32bit port
//
//  Notes:      REVIEW32:  this function is only used in a few, known
//              places.  we can maybe get rid of the VDATEPTR's.
//
//--------------------------------------------------------------------------


INTERNAL  OleLoadWithoutBinding
(
    IStorage FAR*           lpStg,
    REFIID                  iid,
    IOleClientSite FAR*     lpClientSite,
    void FAR* FAR*          lplpObj
)
{
    VDATEHEAP();

    HRESULT error;
    CLSID   clsid;

    VDATEPTROUT( lplpObj, LPVOID );
    *lplpObj = NULL;
    VDATEIID( iid );
    VDATEIFACE( lpStg );

    if (lpClientSite)
        VDATEIFACE( lpClientSite );

    error = OleDoAutoConvert(lpStg, &clsid);

    // error only used when clsid could not be read (when CLSID_NULL)
    if (IsEqualCLSID(clsid, CLSID_NULL))
        return error;

    return wCreateObject (clsid, iid, lpClientSite, lpStg, STG_LOAD,
        lplpObj);
}




//+-------------------------------------------------------------------------
//
//  Function:   OleCreateStaticFromData
//
//  Synopsis:   Creates a static ole object from the data in [lpSrcDataObject]
//              If [lpFormatEtcIn] is NULL, then the best possible
//              presentation is extracted.
//
//  Effects:
//
//  Arguments:  [lpSrcDataObj]  -- pointer to the data object
//              [iid]           -- requested interface ID for the new object
//              [renderopt]     -- redering options
//              [lpClientSite]  -- pointer to the client site
//              [lpStg]         -- pointer to the storage for the object
//              [lplpObj]       -- where to put the pointer to the object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		16-Dec-94 alexgo    added call tracing
//              08-Jun-94 davepl    Added EMF support
//              28-Oct-93 alexgo    32bit port
//
//--------------------------------------------------------------------------

#pragma SEG(OleCreateStaticFromData)
STDAPI OleCreateStaticFromData(
    IDataObject FAR*        lpSrcDataObj,
    REFIID                  iid,
    DWORD                   renderopt,
    LPFORMATETC             lpFormatEtcIn,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg,
    void FAR* FAR*          lplpObj
)
{
    OLETRACEIN((API_OleCreateStaticFromData,
    	PARAMFMT("lpSrcDataObj= %p, iid= %I, renderopt= %x, lpFormatEtcIn= %te, lpClientSite= %p, lpStg= %p, lplpObj= %p"),
    	lpSrcDataObj, &iid, renderopt, lpFormatEtcIn, lpClientSite, lpStg, lplpObj));

    VDATEHEAP();

    IOleObject FAR*         lpOleObj = NULL;
    IOleCache FAR*          lpOleCache = NULL;
    HRESULT                 error;
    FORMATETC               foretc;
    FORMATETC               foretcCache;
    STGMEDIUM               stgmed;
    CLSID                   clsid;
    BOOL                    fReleaseStgMed = TRUE;
    LPOLESTR                        lpszUserType = NULL;


    LEDebugOut((DEB_TRACE, "%p _IN OleCreateStaticFromData ( %p , %p , %lx ,"
	" %p , %p , %p , %p , %p )\n", NULL, lpSrcDataObj, &iid, renderopt,
	lpFormatEtcIn, lpClientSite, lpStg, lplpObj));

    VDATEPTROUT_LABEL(lplpObj, LPVOID, safeRtn, error);
    *lplpObj = NULL;
    VDATEIFACE_LABEL( lpSrcDataObj, logRtn, error );
    VDATEIID_LABEL(iid, logRtn, error);

    //VDATEPTRIN rejects NULL
    if ( lpFormatEtcIn )
        VDATEPTRIN_LABEL( lpFormatEtcIn, FORMATETC, logRtn, error );
    VDATEIFACE_LABEL(lpStg, logRtn, error);
    if (lpClientSite)
        VDATEIFACE_LABEL(lpClientSite, logRtn, error);

    if (renderopt == OLERENDER_NONE || renderopt == OLERENDER_ASIS)
    {
	error = E_INVALIDARG;
	goto logRtn;
    }

    if ((error = wValidateFormatEtc (renderopt, lpFormatEtcIn, &foretc))
            != NOERROR)
    {
	goto logRtn;
    }

    if (renderopt == OLERENDER_DRAW)
    {
        if (!UtQueryPictFormat(lpSrcDataObj, &foretc))
	{
	    error = DV_E_CLIPFORMAT;
	    goto logRtn;
	}
    }

    // Set the proper CLSID, or return error if that isn't possible

    if (foretc.cfFormat == CF_METAFILEPICT)
    {
        clsid = CLSID_StaticMetafile;
    }
    else if (foretc.cfFormat == CF_BITMAP ||  foretc.cfFormat == CF_DIB)
    {
        clsid = CLSID_StaticDib;
    }
    else if (foretc.cfFormat == CF_ENHMETAFILE)
    {
        clsid = CLSID_Picture_EnhMetafile;
    }
    else
    {
        error = DV_E_CLIPFORMAT;
	goto logRtn;
    }

    error = lpSrcDataObj->GetData(&foretc, &stgmed);
    if (NOERROR != error)
    {
        // We should support the case where the caller wants one of
        // CF_BITMAP and CF_DIB, and the object supports the other
        // one those 2 formats. In this case we should do the proper
        // conversion. Finally the cache that is going to be created
        // would be a DIB cache.

        AssertOutStgmedium(error, &stgmed);

        if (foretc.cfFormat == CF_DIB)
        {
            foretc.cfFormat = CF_BITMAP;
            foretc.tymed = TYMED_GDI;
        }
        else if (foretc.cfFormat == CF_BITMAP)
        {
            foretc.cfFormat = CF_DIB;
            foretc.tymed = TYMED_HGLOBAL;
        }
        else
        {
            goto logRtn;
        }

        error = lpSrcDataObj->GetData(&foretc, &stgmed);
        if (NOERROR != error)
        {
            AssertOutStgmedium(error, &stgmed);
            goto logRtn;
        }
    }

    AssertOutStgmedium(error, &stgmed);

    foretcCache = foretc;
    foretcCache.dwAspect = foretc.dwAspect = DVASPECT_CONTENT;
    foretcCache.ptd = NULL;

    // Even when the caller asks for bitmap cache we create the DIB cache.

    BITMAP_TO_DIB(foretcCache);

    error = wCreateObject (clsid, IID_IOleObject, lpClientSite,
        lpStg, STG_INITNEW, (LPLPVOID) &lpOleObj);

    if (NOERROR != error)
    {
        goto errRtn;
    }

    if (lpOleObj->QueryInterface(IID_IOleCache, (LPLPVOID) &lpOleCache)
            != NOERROR)
    {
        goto errRtn;
    }

    error = lpOleCache->Cache (&foretcCache, ADVF_PRIMEFIRST,
                        NULL /*pdwConnection*/);

    if (FAILED(error))
    {
        goto errRtn;
    }

    //REVIEW32: err, are we sure this is a good idea???
    //clearing out the error, that is

    error = NOERROR;

    // take ownership of the data
    foretc.ptd = NULL;
    if ((error = lpOleCache->SetData (&foretc, &stgmed,
            TRUE)) != NOERROR)
        goto errRtn;

    // Write format and user type
    error = lpOleObj->GetUserType(USERCLASSTYPE_FULL, &lpszUserType);
    AssertOutPtrParam(error, lpszUserType);
    WriteFmtUserTypeStg(lpStg, foretcCache.cfFormat, lpszUserType);
    if (lpszUserType)
        PubMemFree(lpszUserType);

    fReleaseStgMed = FALSE;

    error = lpOleObj->QueryInterface (iid, lplpObj);

errRtn:
    if (fReleaseStgMed)
        ReleaseStgMedium(&stgmed);

    if (lpOleCache)
        lpOleCache->Release();

    if (error != NOERROR && *lplpObj) {
        ((IUnknown FAR*) *lplpObj)->Release();
        *lplpObj = NULL;
    }

    if (lpOleObj)
        lpOleObj->Release();

logRtn:

    LEDebugOut((DEB_TRACE, "%p OUT OleCreateStaticFromData ( %lx ) [ %p ]\n",
	NULL, error, *lplpObj));

safeRtn:
    OLETRACEOUT((API_OleCreateStaticFromData, error));

    return error;
}


//+-------------------------------------------------------------------------
//
//  Function:   OleQueryCreateFromData
//
//  Synopsis:   Finds out what we can create from a data object (if anything)
//
//  Effects:
//
//  Arguments:  [lpSrcDataObj]  -- pointer to the data object of interest
//
//  Requires:
//
//  Returns:    NOERROR         -- an OLE object can be created
//              QUERY_CREATE_STATIC     -- a static object can be created
//              S_FALSE         -- nothing can be created
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              28-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(OleQueryCreateFromData)
STDAPI  OleQueryCreateFromData (LPDATAOBJECT lpSrcDataObj)
{
    OLETRACEIN((API_OleQueryCreateFromData, PARAMFMT("lpSrcDataObj= %p"), lpSrcDataObj));

    VDATEHEAP();
    VDATEIFACE( lpSrcDataObj );
    CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IDataObject,(IUnknown **)&lpSrcDataObj);

    CLIPFORMAT      cfFormat;
    WORD            wStatus = wQueryEmbedFormats(lpSrcDataObj, &cfFormat);
    HRESULT hr;

    if (wStatus & QUERY_CREATE_OLE)
        // OLE object can be created
        hr = NOERROR;
    else if (wStatus & QUERY_CREATE_STATIC)
        // static object can be created
        hr = ResultFromScode(OLE_S_STATIC);
    else    // no object can be created
        hr = ResultFromScode(S_FALSE);

    OLETRACEOUT((API_OleQueryCreateFromData, hr));

    return hr;
}


//+-------------------------------------------------------------------------
//
//  Function:   wQueryEmbedFormats
//
//  Synopsis:   Enumerates the formats of the object and looks for
//              ones that let us create either an embeded or static object
//
//  Effects:
//
//  Arguments:  [lpSrcDataObj]          -- pointer to the data object
//              [lpcfFormat]            -- place to put the clipboard format
//                                         of the object
//  Returns:    WORD -- bit flag of QUERY_CREATE_NONE, QUERY_CREATE_STATIC
//                      and QUERY_CREATE_OLE
//
//  History:    dd-mmm-yy Author    Comment
//              28-Oct-93 alexgo    32bit port
//              08-Jun-94 davepl    Optimized by unwinding while() loop
//		22-Aug-94 alexgo    added MFC hack
//
//--------------------------------------------------------------------------

static const unsigned int MAX_ENUM_STEP = 20;

INTERNAL_(WORD) wQueryEmbedFormats
(
    LPDATAOBJECT    lpSrcDataObj,
    CLIPFORMAT FAR* lpcfFormat
)
{
    VDATEHEAP();

    // This adjusts the number of formats requested per enumeration
    // step.  If we are running in the WOW box, we should only ask
    // for one at a time since it is unknown how well old code will
    // support bulk enumerations.

    ULONG ulEnumSize = IsWOWThread() ? 1 : MAX_ENUM_STEP;

    FORMATETC               fetcarray[MAX_ENUM_STEP];
    IEnumFORMATETC FAR*     penm;
    ULONG                   ulNumFetched;
    HRESULT                 error;
    WORD                    wStatus = QUERY_CREATE_NONE;
                    // no object can be created
    BOOL                    fDone   = FALSE;

    *lpcfFormat = NULL;

    // Grab the enumerator.  If this fails, just return
    // QUERY_CREATE_NONE

    error = wGetEnumFormatEtc(lpSrcDataObj, DATADIR_GET, &penm);
    if (error != NOERROR)
    {
        return QUERY_CREATE_NONE;
    }

    // Enumerate over the formats available in chunks for ulEnumSize.  For
    // each format we were able to grab, check to see if the clipformat
    // indicates that we have a creation candidate (static or otherwise),
    // and set bits in the bitmask as appropriate

    while (!fDone && (SUCCEEDED(penm->Next(ulEnumSize, fetcarray, &ulNumFetched))))
    {
      // We will normally get at least one, unless there are 0,
      // ulEnumSize, 2*ulEnumSize, and so on...

      if (ulNumFetched == 0)
        break;

      for (ULONG c=0; c<ulNumFetched; c++)
      {
        // We care not about the target device

        if (NULL != fetcarray[c].ptd)
        {
          PubMemFree(fetcarray[c].ptd);
        }

        CLIPFORMAT cf = fetcarray[c].cfFormat;

          // In these cases it is an internal
          // format which is a candidate for
          // OLE creation directly.

        if (cf == g_cfEmbedSource       ||
          cf == g_cfEmbeddedObject    ||
          cf == g_cfFileName          ||
          cf == g_cfFileNameW)
        {
          wStatus |= QUERY_CREATE_OLE;
          *lpcfFormat = cf;
          fDone = TRUE;
          break;
        }
          // These formats indicate it is a
          // candidate for static creation.

        else if (cf == CF_METAFILEPICT  ||
            cf == CF_DIB           ||
            cf == CF_BITMAP        ||
            cf == CF_ENHMETAFILE)
        {
          wStatus = QUERY_CREATE_STATIC;
          *lpcfFormat = cf;

        }
      } // end for

      if (fDone)
      {
        // Starting at the _next_ formatetc, free up
        // any remaining target devices among the
        // fetcs we got in the enumeration step.

        for (++c; c<ulNumFetched; c++)
        {
          if(fetcarray[c].ptd)
          {
            PubMemFree(fetcarray[c].ptd);
          }
        }
      }

    } // end while



    if (!(wStatus & QUERY_CREATE_OLE))
    {
        // MFC HACK ALERT!!  MFC3.0 used to re-implement
        // OleQueryCreateFromData themselves because they did not
        // want to make the QI RPC below.  Since they do a great
        // many of these calls, making the RPC can be expensive
        // and destabilising for them (as this hack is being put
        // in just weeks before final release of Windows NT 3.5).
        //
        // Note that this changes the behaviour of clipboard from
        // 16bit.  You will no longer know that you can paste objects
        // that only support IPersistStorage but offer no data in
        // in their IDataOjbect implementation.

        CClipDataObject ClipDataObject;	// just allocate one of these
                        // on the stack.  We won't
                        // do any real work with
                        // this except look at the
                        // vtable.
        IPersistStorage FAR* lpPS;


        // MFC HACK (continued):  If we are working with a clipboard
        // data object, then we do not want to make the QI call
        // below.  We determine if the given data object is a
        // clipboard data object by comparing vtable addresses.

        // REVIEW:  this will potentially break if we make all objects
        // use the same IUnknown implementation

        if( (*(DWORD *)lpSrcDataObj) !=
            (*(DWORD *)((IDataObject *)&ClipDataObject)) )
        {

            if (lpSrcDataObj->QueryInterface(IID_IPersistStorage,
                (LPLPVOID)&lpPS) == NOERROR)
            {
                lpPS->Release();
                wStatus |= QUERY_CREATE_OLE;
                    // OLE object can be created
            }
        }
    }

    penm->Release();
    return wStatus;
}


//+-------------------------------------------------------------------------
//
//  Function:   OleQueryLinkFromData
//
//  Synopsis:   Calls wQueryLinkFormats to determine if a link could be
//              created from this data object.
//
//  Arguments:  [lpSrcDataObj]  -- the data object
//
//  Returns:    NOERROR, if a link can be created, S_FALSE otherwise
//
//  History:    dd-mmm-yy Author    Comment
//              28-Oct-93 alexgo    32bit port
//
//--------------------------------------------------------------------------

STDAPI  OleQueryLinkFromData (LPDATAOBJECT lpSrcDataObj)
{
    OLETRACEIN((API_OleQueryLinkFromData, PARAMFMT("lpSrcDataObj= %p"),
											lpSrcDataObj));
												
    VDATEHEAP();
	VDATEIFACE( lpSrcDataObj );
    CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IDataObject,(IUnknown **)&lpSrcDataObj);

    HRESULT hr = NOERROR;

    if(wQueryLinkFormats(lpSrcDataObj) == NULL)
    {
	hr = ResultFromScode(S_FALSE);
    }

    OLETRACEOUT((API_OleQueryLinkFromData, hr));

    return hr;
}

//+-------------------------------------------------------------------------
//
//  Function:   wQueryLinkFormats
//
//  Synopsis:   Enumerates the formats of a data object to see if
//              a link object could be created from one of them
//
//  Arguments:  [lpSrcDataObj]  -- pointer to the data object
//
//  Returns:    CLIPFORMAT of the data in the object that would enable
//              link object creation.
//
//  History:    dd-mmm-yy Author    Comment
//              28-Oct-93 alexgo    32bit port
//              14-Jun-94 davepl    Added bulk enumeration for non-Wow runs
//
//--------------------------------------------------------------------------


INTERNAL_(CLIPFORMAT) wQueryLinkFormats(LPDATAOBJECT lpSrcDataObj)
{
    VDATEHEAP();

    // This adjusts the number of formats requested per enumeration
    // step.  If we are running in the WOW box, we should only ask
    // for one at a time since it is unknown how well old code will
    // support bulk enumerations.

    ULONG ulEnumSize = IsWOWThread() ? 1 : MAX_ENUM_STEP;

    FORMATETC               fetcarray[MAX_ENUM_STEP];
    IEnumFORMATETC FAR*     penm;
    ULONG                   ulNumFetched;
    HRESULT                 error;
    BOOL                    fDone    = FALSE;
    CLIPFORMAT              cf       = 0;


    // Grab the enumerator.  If this fails, just return
    // QUERY_CREATE_NONE

    error = wGetEnumFormatEtc(lpSrcDataObj, DATADIR_GET, &penm);
    if (error != NOERROR)
    {
        return (CLIPFORMAT) 0;
    }

    // Enumerate over the formats available in chunks for ulEnumSize.  For
    // each format we were able to grab, check to see if the clipformat
    // indicates that we have a creation candidate (static or otherwise),
    // and set bits in the bitmask as appropriate

    while (!fDone && (SUCCEEDED(penm->Next(ulEnumSize, fetcarray, &ulNumFetched))))
    {
      // We will normally get at least one, unless there are 0,
      // ulEnumSize, 2*ulEnumSize, and so on...

      if (ulNumFetched == 0)
        break;

      for (ULONG c=0; c<ulNumFetched; c++)
      {
        // We care not about the target device

        if (NULL != fetcarray[c].ptd)
        {
          PubMemFree(fetcarray[c].ptd);
        }

        CLIPFORMAT cfTemp = fetcarray[c].cfFormat;

          // In these cases it is an internal
          // format which is a candidate for
          // OLE creation directly.

        if (cfTemp == g_cfLinkSource       ||
          cfTemp == g_cfFileName         ||
          cfTemp == g_cfFileNameW)
        {
          cf = cfTemp;
          fDone = TRUE;
          break;
        }

      } // end for

      if (fDone)
      {
        // Starting at the _next_ formatetc, free up
        // any remaining target devices among the
        // fetcs we got in the enumeration step.

        for (++c; c<ulNumFetched; c++)
        {
          if(fetcarray[c].ptd)
          {
            PubMemFree(fetcarray[c].ptd);
          }
        }
      }  // end if

    } // end while


    penm->Release();
    return cf;
}


//+-------------------------------------------------------------------------
//
//  Function:   wClearRelativeMoniker
//
//  Synopsis:   Replaces an old relative moniker with the absolute moniker
//              Internal function
//
//  Effects:
//
//  Arguments:  [pInitObj]      -- the original object
//              [pNewObj]       -- the object to which to set the new
//                                 absolute moniker
//
//  Requires:
//
//  Returns:    void
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              28-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(wClearRelativeMoniker)
INTERNAL_(void) wClearRelativeMoniker
    (LPUNKNOWN      pInitObj,
    LPUNKNOWN       pNewObj)
{
    VDATEHEAP();

    LPOLELINK       pOleLink = NULL;
    LPMONIKER       pmkAbsolute = NULL;
    CLSID           clsidLink = CLSID_NULL;
    LPOLEOBJECT     pOleObj=NULL;

    if (NOERROR==pInitObj->QueryInterface (IID_IOleLink,
                                                (LPLPVOID) &pOleLink))
    {
        // Get absolute moniker ...
        pOleLink->GetSourceMoniker (&pmkAbsolute);
        Assert(pmkAbsolute == NULL || IsValidInterface(pmkAbsolute));
        if (NOERROR==pInitObj->QueryInterface (IID_IOleObject,
                                                    (LPLPVOID) &pOleObj))
        {
            // .. and its class
            pOleObj->GetUserClassID (&clsidLink);
            pOleObj->Release();
            pOleObj = NULL;
        }
        pOleLink->Release();
        pOleLink = NULL;
    }
    if (pmkAbsolute &&
        NOERROR==pNewObj->QueryInterface (IID_IOleLink,
        (LPLPVOID) &pOleLink))
    {
        // Restore the absolute moniker.  This will effectively
        // overwrite the old relative moniker.
        // This is important because when copying and pasting a link
        // object between documents, the relative moniker is never
        // correct.  Sometimes, though, it might happen to bind
        // to a different object, which is confusing to say the least.
        pOleLink->SetSourceMoniker (pmkAbsolute, clsidLink);
    }
    if (pOleLink)
        pOleLink->Release();
    if (pOleObj)
        pOleObj->Release();
    if (pmkAbsolute)
        pmkAbsolute->Release();
}



//+-------------------------------------------------------------------------
//
//  Function:   wCreateFromDataEx
//
//  Synopsis:   This function does the real work of creating from data.
//              Basically, the data is GetData'ed from the data object,
//              copied into a storage, and then loaded
//
//  Effects:
//
//  Arguments:  [lpSrcDataObj]  -- pointer to the data object
//              [iid]           -- requested interface
//              [dwFlags]       -- object creation flags
//              [renderopt]     -- render options, such as OLERENDER_DRAW
//              [cFormats]      -- the number of elements in rgFormatEtc
//              [rgAdvf]        -- array of advise flags, if OLRENDER_FORMAT
//                                 is specified in renderopt
//              [rgFormatEtc]   -- array of rendering formats, if
//                                 OLERENDER_FORMAT is specified in renderopt
//              [lpAdviseSink]  -- the advise sink for the object
//              [rgdwConnection]-- where to put the connection IDs for the
//                                 advisory connections
//              [lpClientSite]  -- pointer to the client site
//              [lpStg]         -- pointer to the storage for the object
//              [lplpObj]       -- where to put the pointer to the object
//
//  Requires:
//
//  Returns:   HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              28-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(wCreateFromDataEx)
INTERNAL wCreateFromDataEx
(
    IDataObject FAR*        lpSrcDataObj,
    REFIID                  iid,
    DWORD		    dwFlags,
    DWORD                   renderopt,
    ULONG		    cFormats,
    DWORD FAR*		    rgAdvf,
    LPFORMATETC             rgFormatEtc,
    IAdviseSink FAR*	    lpAdviseSink,
    DWORD FAR*		    rgdwConnection,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg,
    void FAR* FAR*          lplpObj
)
{
    VDATEHEAP();

    #define OLE_TEMP_STG    "\1OleTempStg"

    HRESULT                 error = NOERROR;
    IPersistStorage FAR*    lpPS = NULL;
    FORMATETC		    formatEtc;
    LPFORMATETC		    lpFormatEtc;
    BOOL		    fAlloced = FALSE;
    FORMATETC               foretcTmp;
    STGMEDIUM               medTmp;

    if ((error = wValidateFormatEtcEx(renderopt, &cFormats, rgFormatEtc,
	&formatEtc, &lpFormatEtc, &fAlloced)) != NOERROR)
    {
        return error;
    }

    *lplpObj = NULL;

    INIT_FORETC(foretcTmp);
    medTmp.pUnkForRelease = NULL;


    // try to get "EmbeddedObject" data

    LPSTORAGE       lpstgSrc = NULL;

    foretcTmp.cfFormat      = g_cfEmbeddedObject;
    foretcTmp.tymed         = TYMED_ISTORAGE;

    if (lpSrcDataObj->QueryGetData(&foretcTmp) != NOERROR)
        goto Next;

    if ((error = StgCreateDocfile (NULL,
            STGM_SALL|STGM_CREATE|STGM_DELETEONRELEASE,
            NULL, &lpstgSrc)) != NOERROR)
	goto errRtn;

    medTmp.tymed = TYMED_ISTORAGE;
    medTmp.pstg = lpstgSrc;

    if ((error = lpSrcDataObj->GetDataHere(&foretcTmp, &medTmp))
        == NOERROR)
    {
        // lpSrcDataObj passed to this api is a wrapper object
        // (which offers g_cfEmbeddedObject) for the original
        // embedded object. Now we got the original embedded object
        // data into medTmp.pstg.

        // copy the source data into lpStg.
        if ((error = lpstgSrc->CopyTo (0, NULL, NULL, lpStg))
            != NOERROR)
            goto errEmbeddedObject;

        // By doing the following we will be getting a data object
        // pointer to original embedded object, which we can use to
        // initialize the cache of the object that we are going to
        // create. We can not use the lpSrcDataObj passed to this api,
        // 'cause the presentation data that it may give through the
        // GetData call may be the one that it generated for the
        // object. (ex: the container can create an object with
        // olerender_none an then draw it's own representaion
        // (icon, etc) for the object.

        LPDATAOBJECT lpInitDataObj = NULL;

        // We pass a NULL client site so we know wClearRelativeMoniker
        // will be able to get the absolute moniker, not the relative.
        if ((error = OleLoadWithoutBinding (lpstgSrc, IID_IDataObject,
            /*lpClientSite*/NULL, (LPLPVOID) &lpInitDataObj))
            != NOERROR)
            goto errEmbeddedObject;

        if (renderopt != OLERENDER_ASIS )
            UtDoStreamOperation(lpStg,              /* pstgSrc */
                NULL,                           /* pstgDst */
                OPCODE_REMOVE,  /* operation to performed */
                STREAMTYPE_CACHE);
                    /* stream to be operated upon */

        error = wLoadAndInitObjectEx(lpInitDataObj, iid, renderopt,
                cFormats, rgAdvf, lpFormatEtc, lpAdviseSink, rgdwConnection,
		lpClientSite, lpStg, lplpObj);

        if (NOERROR==error)
            wClearRelativeMoniker (lpInitDataObj,
                (LPUNKNOWN)*lplpObj);

        if (lpInitDataObj)
            lpInitDataObj->Release();

	// HACK ALERT!!  If wLoadAndInitObject failed, it may have been
	// because the little trick above with OleLoadWithoutBinding doesn't
	// work with all objects.  Some OLE1 objects (Clipart Gallery in
	// particular) don't like offer presentions without being edited.
	//
	// So if there was an error, we'll just try again with the *real*
	// data object passed into us.  Needless to say, it would be much
	// nicer to do this in the first place, but that breaks the old
	// behavior.

	if( error != NOERROR )
	{
	    error = wLoadAndInitObjectEx( lpSrcDataObj, iid, renderopt,
		    cFormats, rgAdvf, lpFormatEtc, lpAdviseSink, rgdwConnection,
		    lpClientSite, lpStg, lplpObj);
	}

    }

errEmbeddedObject:
    if (lpstgSrc)
        lpstgSrc->Release();

    goto errRtn;

Next:

    // try to get "EmbedSource" data

    foretcTmp.cfFormat      = g_cfEmbedSource;
    foretcTmp.tymed         = TYMED_ISTORAGE;

    medTmp.tymed = TYMED_ISTORAGE;
    medTmp.pstg = lpStg;

    if ((error = lpSrcDataObj->GetDataHere(&foretcTmp, &medTmp))
        == NOERROR)
    {
        error = wLoadAndInitObjectEx(lpSrcDataObj, iid, renderopt,
		cFormats, rgAdvf, lpFormatEtc, lpAdviseSink, rgdwConnection,
		lpClientSite, lpStg, lplpObj);
	goto errRtn;
    }

    // If we have come here, and if the object doesn't support
    // IPersistStorage, then we will fail.

    if ((error = wSaveObjectWithoutCommit(lpSrcDataObj, lpStg, FALSE))
            != NOERROR)
        goto errRtn;;

    if (renderopt != OLERENDER_ASIS )
        UtDoStreamOperation(lpStg,      /* pstgSrc */
                    NULL,   /* pstgDst */
                    OPCODE_REMOVE,
                    /* operation to performed */
                    STREAMTYPE_CACHE);
                    /* stream to be operated upon */

    error = wLoadAndInitObjectEx(lpSrcDataObj, iid, renderopt,
	    cFormats, rgAdvf, lpFormatEtc, lpAdviseSink, rgdwConnection,
	    lpClientSite, lpStg, lplpObj);

errRtn:
    if (fAlloced)
	PubMemFree(lpFormatEtc);

    return error;
}



//+-------------------------------------------------------------------------
//
//  Function:   wCreateLinkEx
//
//  Synopsis:   Creates a link by binding the moniker (if necessary),
//              doing a GetData into a storage, and then loading the
//              object from the storage.
//
//  Effects:
//
//  Arguments:  [lpmkSrc]       -- moniker to the link source
//              [rclsid]        -- clsid of the link source
//              [lpSrcDataObj]  -- pointer to the source data object
//                                 (may be NULL)
//              [iid]           -- requested interface ID
//              [dwFlags]       -- object creation flags
//              [renderopt]     -- render options, such as OLERENDER_DRAW
//              [cFormats]      -- the number of elements in rgFormatEtc
//              [rgAdvf]        -- array of advise flags, if OLRENDER_FORMAT
//                                 is specified in renderopt
//              [rgFormatEtc]   -- array of rendering formats, if
//                                 OLERENDER_FORMAT is specified in renderopt
//              [lpAdviseSink]  -- the advise sink for the object
//              [rgdwConnection]-- where to put the connection IDs for the
//                                 advisory connections
//              [lpClientSite]  -- pointer to the client site
//              [lpStg]         -- storage for the link object
//              [lplpObj]       -- where to put the pointer to the new
//                                 link object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              29-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(wCreateLinkEx)
INTERNAL wCreateLinkEx
(
    IMoniker FAR*           lpmkSrc,
    REFCLSID                rclsid,
    IDataObject FAR*        lpSrcDataObj,
    REFIID                  iid,
    DWORD		    dwFlags,
    DWORD                   renderopt,
    ULONG		    cFormats,
    DWORD FAR*		    rgAdvf,
    LPFORMATETC             rgFormatEtc,
    IAdviseSink FAR*	    lpAdviseSink,
    DWORD FAR*		    rgdwConnection,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg,
    void FAR* FAR*          lplpObj
)
{
    VDATEHEAP();

    IPersistStorage FAR *   lpPS = NULL;
    IOleLink FAR*           lpLink = NULL;
    IDataObject FAR*        lpBoundDataObj = NULL;
    HRESULT                 error;
    CLSID                   clsidLast = rclsid;
    BOOL                    fNeedsUpdate = FALSE;

    if (!lpSrcDataObj && ((renderopt != OLERENDER_NONE)
        || (IsEqualCLSID(rclsid,CLSID_NULL))
        || wQueryUseCustomLink(rclsid))) {

        // if renderopt is not OLERENDER_NONE, then we must have
        // a data obj pointer which will be used to initialize cache.

        // We also bind if we are not able to find from regdb whether
        // the class has custom link implementation or not

        if ((error = BindMoniker(lpmkSrc, NULL /* grfOpt */,
            IID_IDataObject, (LPLPVOID) &lpBoundDataObj))
            != NOERROR) {

            if (OLERENDER_NONE != renderopt)
                return ResultFromScode(
                    OLE_E_CANT_BINDTOSOURCE);


        // else we assume StdOleLink and continue with creation
        } else {
            lpSrcDataObj = lpBoundDataObj;

            if (IsEqualCLSID(clsidLast, CLSID_NULL))
                UtGetClassID((LPUNKNOWN)lpSrcDataObj,
                    &clsidLast);
        }
    }

    // Deal with CustomLinkSource
    // (see notes below)
    if (lpSrcDataObj) {
        STGMEDIUM       medTmp;
        FORMATETC       foretcTmp;

        INIT_FORETC(foretcTmp);
        foretcTmp.cfFormat = g_cfCustomLinkSource;
        foretcTmp.tymed = TYMED_ISTORAGE;

        if (lpSrcDataObj->QueryGetData(&foretcTmp) == NOERROR) {
            medTmp.tymed = TYMED_ISTORAGE;
            medTmp.pstg     = lpStg;
            medTmp.pUnkForRelease = NULL;

            if (error = lpSrcDataObj->GetDataHere(&foretcTmp,
                &medTmp))
                goto errRtn;

            error = wLoadAndInitObjectEx(lpSrcDataObj, iid,
                renderopt, cFormats, rgAdvf, rgFormatEtc,
		lpAdviseSink, rgdwConnection, lpClientSite,
		lpStg, lplpObj);

            // This is a really strange peice of logic,
            // spaghetti code at it's finest.  Basically,
            // this says that if there is *NOT* a
            // custom link source, then we want to do the
            // logic of wCreateObject, etc. below.  If we
            // got to this line in the code, then we
            // *did* have a custom link source, so
            // don't do the stuff below (thus the goto).

            // REVIEW32: If there are any bugs in here,
            // then rewrite this in a more sensible fashion.
            // I'm leaving as is for now due to time constraints.

            goto errRtn;
        }
    }

    // Otherwise
    if ((error = wCreateObject (CLSID_StdOleLink, iid, lpClientSite,
                lpStg, STG_INITNEW, lplpObj)) != NOERROR)
        goto errRtn;

    if (lpSrcDataObj)
    {
        BOOL fCacheNodeCreated = FALSE;

        if ((error = wInitializeCacheEx(lpSrcDataObj, clsidLast,
            renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink,
	    rgdwConnection, *lplpObj, &fCacheNodeCreated)) != NOERROR)
        {

            if (error != NOERROR && fCacheNodeCreated)
            {
                fNeedsUpdate = TRUE;
                error = NOERROR;
            }

        }
    }

errRtn:

    if (error == NOERROR && *lplpObj)
        error = ((LPUNKNOWN) *lplpObj)->QueryInterface(IID_IOleLink,
                            (LPLPVOID) &lpLink);

    if (error == NOERROR && lpLink && (dwFlags & OLECREATE_LEAVERUNNING)) {
        // This will connect to the object if it is already running.
        lpLink->SetSourceMoniker (lpmkSrc, clsidLast);
    }

    // We bound to the object to initialize the cache. We don't need
    // it anymore
    if (lpBoundDataObj)
    {
	if (error == NOERROR && (dwFlags & OLECREATE_LEAVERUNNING))
	    OleRun((LPUNKNOWN)*lplpObj);

        // this will give a chance to the object to go away, if it can
        wDoLockUnlock(lpBoundDataObj);
        lpBoundDataObj->Release();
    }

    // If the source object started running as a result of BindMoniker,
    // then we would've got rid of it by now.

    if (error == NOERROR && lpLink)
    {
	if ( !(dwFlags & OLECREATE_LEAVERUNNING) ) {
	    // This will connect to the object if it is already running.
	    lpLink->SetSourceMoniker (lpmkSrc, clsidLast);
	}

        if (fNeedsUpdate) {
            // relevant cache data is not available from the
            // lpSrcDataObj. So do Update and get the right cache
            // data.
            error = wDoUpdate ((LPUNKNOWN) *lplpObj);

            if (GetScode(error) == CACHE_E_NOCACHE_UPDATED)
                error = ReportResult(0, DV_E_FORMATETC, 0, 0);
        }

        // Release on lpLink is necessary only if error == NOERROR
        lpLink->Release();

    }

    if (error != NOERROR && *lplpObj) {
        ((IUnknown FAR*) *lplpObj)->Release();
        *lplpObj = NULL;
    }

    return error;
}


//+-------------------------------------------------------------------------
//
//  Function:   wCreateFromFileEx
//
//  Synopsis:   Creates an ole object from a file by binding the given
//              moniker and creating the object from the IDataObject pointer
//
//  Effects:
//
//  Arguments:  [lpmkFile]      -- moniker to the file
//              [iid]           -- requested interface ID
//              [dwFlags]       -- object creation flags
//              [renderopt]     -- render options, such as OLERENDER_DRAW
//              [cFormats]      -- the number of elements in rgFormatEtc
//              [rgAdvf]        -- array of advise flags, if OLRENDER_FORMAT
//                                 is specified in renderopt
//              [rgFormatEtc]   -- array of rendering formats, if
//                                 OLERENDER_FORMAT is specified in renderopt
//              [lpAdviseSink]  -- the advise sink for the object
//              [rgdwConnection]-- where to put the connection IDs for the
//                                 advisory connections
//              [lpClientSite]  -- pointer to the client site
//              [lpStg]         -- pointer to the storage for the new object
//              [lplpObj]       -- where to put the pointer to the object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              29-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(wCreateFromFileEx)
INTERNAL wCreateFromFileEx
(
    LPMONIKER               lpmkFile,
    LPDATAOBJECT	    lpDataObject,
    REFIID                  iid,
    DWORD		    dwFlags,
    DWORD                   renderopt,
    ULONG		    cFormats,
    DWORD FAR*		    rgAdvf,
    LPFORMATETC             rgFormatEtc,
    IAdviseSink FAR*	    lpAdviseSink,
    DWORD FAR*		    rgdwConnection,
    LPOLECLIENTSITE         lpClientSite,
    LPSTORAGE               lpStg,
    LPLPVOID                lplpObj
)
{
    VDATEHEAP();

    HRESULT         error;
    LPDATAOBJECT    lpLocalDataObj;


    if (!lpDataObject)
    {
	if ((error = BindMoniker(lpmkFile, NULL, IID_IDataObject,
	    (LPLPVOID) &lpLocalDataObj)) != NOERROR)
	    return error;
    }
    else
    {
	lpLocalDataObj = lpDataObject;
    }

    Verify(lpLocalDataObj);

    error = wCreateFromDataEx(lpLocalDataObj, iid, dwFlags, renderopt, cFormats,
	rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection, lpClientSite,
	lpStg, lplpObj);

    if (error == NOERROR && (dwFlags & OLECREATE_LEAVERUNNING))
	OleRun((LPUNKNOWN)*lplpObj);

    // If we bound locally release it now, else it is up to the caller to do the right thing.

    if (!lpDataObject)
    {
	wDoLockUnlock(lpLocalDataObj);
	lpLocalDataObj->Release();
    }

    return error;
}



//+-------------------------------------------------------------------------
//
//  Function:   CoIsHashedOle1Class
//
//  Synopsis:   Determines whether or not a CLSID is an OLE1 class
//
//  Effects:
//
//  Arguments:  [rclsid]        -- the class ID in question
//
//  Requires:
//
//  Returns:    TRUE if ole1.0, FALSE otherwise
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              29-Oct-93 alexgo    32bit port
//
//  Notes:      REVIEW32:  This is a strange function..consider nuking
//              it for 32bit, we may not need it (only used in 1 place)
//
//--------------------------------------------------------------------------


#pragma SEG(CoIsHashedOle1Class)
STDAPI_(BOOL) CoIsHashedOle1Class(REFCLSID rclsid)
{
    VDATEHEAP();

    CLSID clsid = rclsid;
    clsid.Data1 = 0L;
    WORD wHiWord = HIWORD(rclsid.Data1);
    return IsEqualGUID(clsid, IID_IUnknown) && wHiWord==4;
}



//+-------------------------------------------------------------------------
//
//  Function:   EnsureCLSIDIsRegistered
//
//  Synopsis:   Checks to see if the clsid is in the registration database,
//              if not, puts it there
//
//  Effects:
//
//  Arguments:  [clsid]         -- the clsid in question
//              [pstg]          -- storage to get more info about the
//                                 clsid if we need to register it
//
//  Requires:
//
//  Returns:    void
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              29-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(EnsureCLSIDIsRegistered)
void EnsureCLSIDIsRegistered
    (REFCLSID       clsid,
    LPSTORAGE       pstg)
{
    VDATEHEAP();

    LPOLESTR        szProgId = NULL;

    if (NOERROR == ProgIDFromCLSID (clsid, &szProgId))
    {
        PubMemFree(szProgId);
    }
    else
    {
        // This is the case of getting a hashed CLSID from a file from
        // another machine and the ProgId is not yet in the reg db,
        // so we must get it from the storage.
        // This code should rarely be executed.
        CLIPFORMAT      cf = 0;
        CLSID           clsidT;
        OLECHAR                 szProgId[256];

        if (ReadFmtUserTypeStg (pstg, &cf, NULL) != NOERROR)
            return;
        // Format is the ProgId
        if (0==GetClipboardFormatName (cf, szProgId, 256))
            return;
        // Will force registration of the CLSID if the ProgId (the OLE1
        // classname) is registered
        CLSIDFromProgID (szProgId, &clsidT);
    }
}



//+-------------------------------------------------------------------------
//
//  Function:   wCreateObject
//
//  Synopsis:   Calls CoCreateInstance to create an object, a defhandler
//              is created if necessary and CLSID info is written to
//              the storage.
//
//  Effects:
//
//  Arguments:  [clsid]         -- the class id of the object to create
//              [iid]           -- the requested interface ID
//              [lpClientSite]  -- pointer to the client site
//              [lpStg]         -- storage for the object
//              [wfStorage]     -- flags for the STORAGE, one of
//                                 STG_NONE, STD_INITNEW, STG_LOAD,
//                                 defined at the beginning of this file
//              [ppv]           -- where to put the pointer to the object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              01-Feb-94 alexgo    fixed memory leak
//              29-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(wCreateObject)
INTERNAL        wCreateObject
(
    CLSID                   clsid,
    REFIID                  iid,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR *          lpStg,
    WORD                    wfStorage,
    void FAR* FAR*          ppv
)
{
    VDATEHEAP();

    HRESULT         error;
    DWORD           dwClsCtx;

    *ppv = NULL;

    CLSID clsidNew;
    if (wfStorage == STG_INITNEW
        && SUCCEEDED(OleGetAutoConvert (clsid, &clsidNew)))
        // Insert an object of the new class
        clsid = clsidNew;


    if (wfStorage == STG_LOAD && CoIsHashedOle1Class (clsid))
        EnsureCLSIDIsRegistered (clsid, lpStg);


    if (IsWOWThread())
    {
        // CLSCTX needs to be turned on for possible 16 bit inproc server
        // such as OLE controls
        dwClsCtx = CLSCTX_INPROC | CLSCTX_INPROC_SERVER16;
    }
    else
    {
#ifdef WX86OLE
        if (gcwx86.IsWx86Enabled())
        {
            dwClsCtx = CLSCTX_INPROC | CLSCTX_INPROC_SERVERX86 |
                                       CLSCTX_INPROC_HANDLERX86;
        }
        else
        {
            dwClsCtx = CLSCTX_INPROC;
        }
#else
        dwClsCtx = CLSCTX_INPROC;
#endif
    }

    if ((error = CoCreateInstance (clsid, NULL /*pUnkOuter*/,
            dwClsCtx, iid, ppv)) != NOERROR) {

        // if not OleLoad or error other than class not registered,
        // exit
        if (wfStorage != STG_LOAD || GetScode(error)
            != REGDB_E_CLASSNOTREG)
            goto errRtn;

        // OleLoad and class not registered: use default handler
        // directly
        if ((error = OleCreateDefaultHandler(clsid, NULL, iid, ppv))
                != NOERROR)
            goto errRtn;
    }

    AssertSz(*ppv, "HRESULT is OK, but pointer is NULL");

    if (wfStorage != STG_NONE)
    {
        IPersistStorage FAR* lpPS;

        if ((error = ((LPUNKNOWN) *ppv)->QueryInterface(
            IID_IPersistStorage, (LPLPVOID)&lpPS)) != NOERROR)
        {
            goto errRtn;
        }

        if (wfStorage == STG_INITNEW)
        {
            error = WriteClassStg(lpStg, clsid);

	    if (SUCCEEDED(error))
	    {
                error = lpPS->InitNew (lpStg);
	    }
        }
        else
        {
            error = lpPS->Load (lpStg);
        }

        lpPS->Release();

	if (FAILED(error))
	{
	    goto errRtn;
	}

    }

    if (lpClientSite) {
        LPOLEOBJECT lpOleObj = NULL;

        if ((error =((LPUNKNOWN) *ppv)->QueryInterface(IID_IOleObject,
                (LPLPVOID) &lpOleObj)) != NOERROR)
            goto errRtn;

        error = lpOleObj->SetClientSite (lpClientSite);

        lpOleObj->Release();

        if (FAILED(error))
            goto errRtn;
    }

    AssertSz(error == NOERROR, "Invalid code path");

    return NOERROR;

errRtn:

    if (*ppv) {
        ((LPUNKNOWN) *ppv)->Release();
        *ppv = NULL;
    }

    return error;
}



//+-------------------------------------------------------------------------
//
//  Function:   wLoadAndInitObjectEx
//
//  Synopsis:   Loads and binds an object from the given storage.
//              A cacle is initialized from the data object
//
//  Effects:
//
//  Arguments:  [lpSrcDataObj]  -- pointer to the data object to initialize
//                                 the cache with
//              [iid]           -- requested interface ID
//              [renderopt]     -- render options, such as OLERENDER_DRAW
//              [cFormats]      -- the number of elements in rgFormatEtc
//              [rgAdvf]        -- array of advise flags, if OLRENDER_FORMAT
//                                 is specified in renderopt
//              [rgFormatEtc]   -- array of rendering formats, if
//                                 OLERENDER_FORMAT is specified in renderopt
//              [lpAdviseSink]  -- the advise sink for the object
//              [rgdwConnection]-- where to put the connection IDs for the
//                                 advisory connections
//              [lpClientSite]  -- pointer to the client site.
//              [lpStg]         -- storage for the new object
//              [lplpObj]       -- where to put the pointer to the new object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              29-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(wLoadAndInitObjectEx)
INTERNAL wLoadAndInitObjectEx
(
    IDataObject FAR*        lpSrcDataObj,
    REFIID                  iid,
    DWORD                   renderopt,
    ULONG		    cFormats,
    DWORD FAR*		    rgAdvf,
    LPFORMATETC             rgFormatEtc,
    IAdviseSink FAR*	    lpAdviseSink,
    DWORD FAR*		    rgdwConnection,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg,
    void FAR* FAR*          lplpObj
)
{
    VDATEHEAP();

    HRESULT                 error;
    CLSID                   clsid;

    if ((error = OleLoadWithoutBinding(lpStg, iid, lpClientSite,
            lplpObj)) != NOERROR)
        return error;

    UtGetClassID((LPUNKNOWN) *lplpObj, &clsid);

    error = wInitializeCacheEx(lpSrcDataObj, clsid, renderopt,
	cFormats, rgAdvf, rgFormatEtc, lpAdviseSink, rgdwConnection,
	*lplpObj);

    if (error != NOERROR) {
        // relevant cache data is not available from the lpSrcDataObj.
        // So do Update and get the right cache data.
        error = wDoUpdate ((LPUNKNOWN) *lplpObj);
    }

    if (GetScode(error) == CACHE_E_NOCACHE_UPDATED) {
        error = ReportResult(0, DV_E_FORMATETC, 0, 0);
        goto errRtn;
    }

    if (error == NOERROR)
        wBindIfRunning((LPUNKNOWN) *lplpObj);

errRtn:
    if (error != NOERROR && *lplpObj) {
        ((IUnknown FAR*) *lplpObj)->Release();
        *lplpObj = NULL;
    }

    return error;
}


//+-------------------------------------------------------------------------
//
//  Function:   wInitializeCacheEx
//
//  Synopsis:   Query's for IOleCache on the given object and calls IOC->Cache
//              to initialize a cache node.
//
//  Effects:
//
//  Arguments:  [lpSrcDataObj]  -- pointer to data to initialize the cache
//                                 with
//              [rclsid]        -- CLSID to use if an icon is needed
//              [renderopt]     -- render options, such as OLERENDER_DRAW
//              [cFormats]      -- the number of elements in rgFormatEtc
//              [rgAdvf]        -- array of advise flags, if OLRENDER_FORMAT
//                                 is specified in renderopt
//              [rgFormatEtc]   -- array of rendering formats, if
//                                 OLERENDER_FORMAT is specified in renderopt
//              [lpAdviseSink]  -- the advise sink for the object
//              [rgdwConnection]-- where to put the connection IDs for the
//                                 advisory connections
//              [lpNewObj]      -- the object on which the cache should
//                                 be initialized
//              [pfCacheNodeCreated]    -- where to return a flag indicating
//                                         whether or not a cache node was
//                                         created
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              31-Oct-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


// This routine modifies lpFormatEtc's fields.

#pragma SEG(wInitializeCacheEx)
INTERNAL wInitializeCacheEx
(
    IDataObject FAR*        lpSrcDataObj,
    REFCLSID                rclsid,
    DWORD                   renderopt,
    ULONG		    cFormats,
    DWORD FAR*		    rgAdvf,
    LPFORMATETC             rgFormatEtc,
    IAdviseSink FAR*	    lpAdviseSink,
    DWORD FAR*		    rgdwConnection,
    void FAR*               lpNewObj,
    BOOL FAR*               pfCacheNodeCreated
)
{
    VDATEHEAP();

    IDataObject FAR*	    lpNewDataObj = NULL;
    IOleCache FAR*          lpOleCache = NULL;
    HRESULT                 error;
    LPFORMATETC		    lpFormatEtc;
    DWORD                   advf;
    STGMEDIUM               stgmed;
    DWORD		    dwConnId = 0;
    BOOL		    fIconCase;

    if (pfCacheNodeCreated)
        *pfCacheNodeCreated = FALSE;

    if (renderopt == OLERENDER_NONE || renderopt == OLERENDER_ASIS)
        return NOERROR;

    if (lpAdviseSink) {
	if ((error = ((IUnknown FAR*)lpNewObj)->QueryInterface(IID_IDataObject,
	    (LPLPVOID) &lpNewDataObj)) != NOERROR)
	    return error;
    }
    else {
	if (((IUnknown FAR*)lpNewObj)->QueryInterface(IID_IOleCache,
	    (LPLPVOID) &lpOleCache) != NOERROR)
	    return wQueryFormatSupport(lpNewObj, renderopt, rgFormatEtc);
    }

    for (ULONG i=0; i<cFormats; i++)
    {
	advf = (rgAdvf ? rgAdvf[i] : ADVF_PRIMEFIRST);
	lpFormatEtc = &rgFormatEtc[i];
	fIconCase = FALSE;

	if (lpFormatEtc->dwAspect == DVASPECT_ICON) {
	    if (lpFormatEtc->cfFormat == NULL) {
		lpFormatEtc->cfFormat = CF_METAFILEPICT;
		lpFormatEtc->tymed = TYMED_MFPICT;
	    }
	    fIconCase = (lpFormatEtc->cfFormat == CF_METAFILEPICT);
	}

	if (lpAdviseSink)
	{
	    // if icon case, must use these advise flags or the icon
	    // data won't get passed back correctly
	    if (fIconCase)
		advf |= (ADVF_PRIMEFIRST | ADVF_ONLYONCE);

	    // should we send the data immediately?
	    if ((advf & ADVF_PRIMEFIRST) && lpSrcDataObj)
	    {
		stgmed.tymed = TYMED_NULL;
		stgmed.pUnkForRelease = NULL;

		if (advf & ADVF_NODATA)
		{
		    // don't sent data, send only the notification
		    lpAdviseSink->OnDataChange(lpFormatEtc, &stgmed);
		}
		else
		{
		    if (fIconCase)
			error = UtGetIconData(lpSrcDataObj, rclsid, lpFormatEtc, &stgmed);
		    else
			error = lpSrcDataObj->GetData(lpFormatEtc, &stgmed);

		    if (error != NOERROR)
			goto errRtn;

		    // send data to sink and release stdmedium
		    lpAdviseSink->OnDataChange(lpFormatEtc, &stgmed);
		    ReleaseStgMedium(&stgmed);
		}

		if (advf & ADVF_ONLYONCE)
		    continue;

		// remove the ADVF_PRIMEFIRST from flags.
		advf &= (~ADVF_PRIMEFIRST);
	    }

	    // setup advisory connection
	    if ((error = lpNewDataObj->DAdvise(lpFormatEtc, advf,
		lpAdviseSink, &dwConnId)) != NOERROR)
		goto errRtn;

	    // optionally stuff the id in the array
	    if (rgdwConnection)
		rgdwConnection[i] = dwConnId;
	}
	else
	{
	    if (fIconCase)
		advf = ADVF_NODATA;

	    // Create a cache of already specified view format.
	    // In case of olerender_draw, lpFormatEtc->cfFormat would have already
	    // been set to NULL.

	    error = lpOleCache->Cache(lpFormatEtc, advf, &dwConnId);

	    if (FAILED(GetScode(error))) {
		if (! ((dwConnId != 0) && fIconCase) )
		    goto errRtn;

		// In icon case we can ignore the cache's QueryGetData failure
	    }

	    error = NOERROR;
	    if (pfCacheNodeCreated)
		*pfCacheNodeCreated = TRUE;

	    if (fIconCase) {
		if ((error = UtGetIconData(lpSrcDataObj, rclsid, lpFormatEtc,
		    &stgmed)) == NOERROR) {
		    if ((error = lpOleCache->SetData(lpFormatEtc, &stgmed,
			TRUE)) != NOERROR)
			ReleaseStgMedium(&stgmed);
		}
	    }
	}
    }

    if (error == NOERROR && !lpAdviseSink && lpSrcDataObj)
        error = lpOleCache->InitCache(lpSrcDataObj);

errRtn:
    if (lpNewDataObj)
	lpNewDataObj->Release();
    if (lpOleCache)
        lpOleCache->Release();
    return error;
}


//+-------------------------------------------------------------------------
//
//  Function:   wReturnCreationError
//
//  Synopsis:   modifies the return code, used internally in creation api's
//
//  Effects:
//
//  Arguments:  [hresult]       -- the original error code
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              01-Nov-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


INTERNAL wReturnCreationError(HRESULT hresult)
{
    VDATEHEAP();

    if (hresult != NOERROR) {
        SCODE sc = GetScode(hresult);

        if (sc == CACHE_S_FORMATETC_NOTSUPPORTED
                || sc == CACHE_E_NOCACHE_UPDATED)
            return ReportResult(0, DV_E_FORMATETC, 0, 0);
    }

    return hresult;
}


//+-------------------------------------------------------------------------
//
//  Function:   wGetMonikerAndClassFromFile
//
//  Synopsis:   gets a moniker and class id from the given file
//
//  Effects:
//
//  Arguments:  [lpszFileName]  -- the file
//              [fLink]         -- passed onto CreatePackagerMoniker
//              [lplpmkFile]    -- where to put the pointer to the file
//                                 moniker
//              [lpfPackagerMoniker]    -- where to put a flag indicating
//                                         whether or not a packager moniker
//                                         was created.
//              [lpClsid]       -- where to put the class ID
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              01-Nov-93 alexgo    32bit port
//              10-May-94 KevinRo   Reimplemented OLE 1.0 interop
//		03-Mar-95 ScottSk   Added STG_E_FILENOTFOUND
//
//
//--------------------------------------------------------------------------


INTERNAL wGetMonikerAndClassFromFile
(
    LPCOLESTR               lpszFileName,
    BOOL                    fLink,
    LPMONIKER FAR*  	    lplpmkFile,
    BOOL FAR*               lpfPackagerMoniker,
    CLSID FAR*              lpClsid,
    LPDATAOBJECT *	    lplpDataObject
)
{
HRESULT hrGetClassFile;
HRESULT hrFileMoniker;
HRESULT hresult;
BOOL fHaveBoundClsid = FALSE;
LPMONIKER  lpFileMoniker;
    
    VDATEHEAP();

     *lplpDataObject = NULL;
     *lplpmkFile = NULL;


    // Call GetClassFileEx directly (rather than going through GetClassFile).
    hrGetClassFile = GetClassFileEx ((LPOLESTR)lpszFileName, lpClsid, CLSID_NULL);
 
    Assert( (NOERROR == hrGetClassFile) || (IsEqualCLSID(*lpClsid, CLSID_NULL)) );

     // To ensure the same error codes are returned as before we don't return immediately if CreateFileMoniker fails.
    hrFileMoniker = CreateFileMoniker((LPOLESTR)lpszFileName, &lpFileMoniker);
    Assert( (NOERROR == hrFileMoniker) || (NULL == lpFileMoniker) );

    // If couldn't get the Clsid because an error other than
    //  MK_E_INVALIDEXTENSION occured see if it is already running

    if (FAILED(hrGetClassFile) && (MK_E_INVALIDEXTENSION != hrGetClassFile) && (NOERROR == hrFileMoniker) )
    {
    LPBINDCTX pbc;

	if (SUCCEEDED(CreateBindCtx( 0, &pbc )))
	{
    	    if (S_OK == lpFileMoniker->IsRunning(pbc,NULL,NULL))
	    {

		// If the Object is Running Bind and get the CLSID
	       if (NOERROR == lpFileMoniker->BindToObject(pbc, NULL, IID_IDataObject,
			(LPLPVOID) lplpDataObject))
		{
		    fHaveBoundClsid = UtGetClassID((LPUNKNOWN)*lplpDataObject,lpClsid);
		    Assert( (TRUE == fHaveBoundClsid) || (IsEqualCLSID(*lpClsid, CLSID_NULL)) );
		}

	    }
	    
	    pbc->Release();
	}
    }
   
    // If have a CLSID at this point see if its insertable.
    if ( (NOERROR == hrGetClassFile) || (TRUE == fHaveBoundClsid) )
    {
	
	Assert(!IsEqualCLSID(*lpClsid, CLSID_NULL));

	// Check whether we need package this file, even though it is an
        // OLE class file.
        if (!wNeedToPackage(*lpClsid))
        {
            if (lpfPackagerMoniker != NULL)
            {
                *lpfPackagerMoniker = FALSE;
            }

	    *lplpmkFile = lpFileMoniker;
            return hrFileMoniker; 
        }
    }
    
    //
    // We didnt' find an OLE insertable object or couldn't get the CLSID. Therefore, create a
    // packager moniker for it.
    //

     // If Bound to the DataObject, release it.
    if (*lplpDataObject)
    {
	(*lplpDataObject)->Release();
	*lplpDataObject = NULL;
    }


    // If GetClassFileEx() failed because the file was not found or could not be openned.
    // don't try to bind with Packager.
    if (hrGetClassFile == MK_E_CANTOPENFILE)
    {
	if (NOERROR == hrFileMoniker)
	{
	    lpFileMoniker->Release();
	}

        return STG_E_FILENOTFOUND;
    }

    // If we failed to create the file moniker its finally safe to bail without changing the error code.
    if (NOERROR != hrFileMoniker)
    {
	return hrFileMoniker;
    }

    if (lpfPackagerMoniker != NULL)
    {
	*lpfPackagerMoniker = TRUE;
    }

    hresult =  CreatePackagerMonikerEx(lpszFileName,lpFileMoniker,fLink,lplpmkFile);
    lpFileMoniker->Release();
 
    return hresult;
}
    


//+-------------------------------------------------------------------------
//
//  Function:   wCreatePackageEx
//
//  Synopsis:   Internal function, does a IDO->GetData for a filename, and
//              then creates either a link or normal object from that file
//
//  Effects:
//
//  Arguments:  [lpSrcDataObj]  -- the source for the filename
//              [iid]           -- the requested interface ID
//              [dwFlags]       -- object creation flags
//              [renderopt]     -- render options, such as OLERENDER_DRAW
//              [cFormats]      -- the number of elements in rgFormatEtc
//              [rgAdvf]        -- array of advise flags, if OLRENDER_FORMAT
//                                 is specified in renderopt
//              [rgFormatEtc]   -- array of rendering formats, if
//                                 OLERENDER_FORMAT is specified in renderopt
//              [lpAdviseSink]  -- the advise sink for the object
//              [rgdwConnection]-- where to put the connection IDs for the
//                                 advisory connections
//              [lpClientSite]  -- client site for the object
//              [lpStg]         -- storage for the object
//              [fLink]         -- if TRUE, create a link
//              [lplpObj]       -- where to put the pointer to the object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:  Gets a filename from the data object (converting to Unicode
//              if necessary) and then creates either an embedding or link
//              from that filename.
//
//  History:    dd-mmm-yy Author    Comment
//              24-Apr-94 alexgo    rewrote to handle FileNameW
//              01-Nov-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(wCreatePackageEx)
INTERNAL wCreatePackageEx
(
    LPDATAOBJECT            lpSrcDataObj,
    REFIID                  iid,
    DWORD		    dwFlags,
    DWORD                   renderopt,
    ULONG		    cFormats,
    DWORD FAR*		    rgAdvf,
    LPFORMATETC             rgFormatEtc,
    IAdviseSink FAR*	    lpAdviseSink,
    DWORD FAR*		    rgdwConnection,
    LPOLECLIENTSITE         lpClientSite,
    LPSTORAGE               lpStg,
    BOOL                    fLink,
    LPLPVOID                lplpObj
)
{
    VDATEHEAP();

    FORMATETC               formatetc;
    STGMEDIUM               medium;
    HRESULT                 hresult;
    CLSID                   clsid = CLSID_NULL;
    LPOLESTR                pszFileName = NULL;
    OLECHAR                 szFileName[MAX_PATH +1];        // in case we
                                // have to
                                // translate

    LEDebugOut((DEB_ITRACE, "%p _IN wCreatePackageEx ( %p , %p , %lx , %lx ,"
	" %lx , %p , %p , %p , %p , %p , %p , %lu , %p )\n", NULL, lpSrcDataObj,
	&iid, dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc, lpAdviseSink,
	rgdwConnection, lpClientSite, lpStg, fLink, lplpObj));

    INIT_FORETC(formatetc);
    formatetc.cfFormat      = g_cfFileNameW;
    formatetc.tymed         = TYMED_HGLOBAL;

    // zero the medium
    _xmemset(&medium, 0, sizeof(STGMEDIUM));

    // we don't need to do a QueryGetData, because we will have only
    // gotten here on the advice of a formatetc enumerator from the
    // data object (and thus, one of the GetData calls should succeed).


    hresult = lpSrcDataObj->GetData(&formatetc, &medium);

    // if we couldn't get the Unicode filename for some reason, try
    // for the ANSI version

    if( hresult != NOERROR )
    {
        char *          pszAnsiFileName;
        DWORD           cwchSize;

        formatetc.cfFormat = g_cfFileName;
        // re-NULL the medium, just in case it was messed up by
        // the first call above

        _xmemset( &medium, 0, sizeof(STGMEDIUM));

        hresult = lpSrcDataObj->GetData(&formatetc, &medium);

        if( hresult == NOERROR )
        {
            pszAnsiFileName = (char *)GlobalLock(medium.hGlobal);

            cwchSize = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
                pszAnsiFileName, -1, szFileName, MAX_PATH);

            if( cwchSize == 0 )
            {
                GlobalUnlock(medium.hGlobal);
                ReleaseStgMedium(&medium);
                hresult = ResultFromScode(E_FAIL);
            }
            else
            {
                pszFileName = szFileName;
            }
            // we will Unlock at the end of the routine
        }
    }
    else
    {
        pszFileName = (LPOLESTR)GlobalLock(medium.hGlobal);
    }

    if( hresult == NOERROR )
    {
        if (fLink)
        {
            hresult = OleCreateLinkToFileEx(pszFileName, iid,
                dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc,
                lpAdviseSink, rgdwConnection, lpClientSite, lpStg, lplpObj);
        }
        else
        {
            hresult = OleCreateFromFileEx(clsid, pszFileName, iid,
                dwFlags, renderopt, cFormats, rgAdvf, rgFormatEtc,
                lpAdviseSink, rgdwConnection, lpClientSite, lpStg, lplpObj);
        }

        GlobalUnlock(medium.hGlobal);
        ReleaseStgMedium(&medium);
    }

    LEDebugOut((DEB_ITRACE, "%p OUT wCreatePackageEx ( %lx ) [ %p ]\n",
        NULL, hresult, *lplpObj));

    return hresult;
}


//+-------------------------------------------------------------------------
//
//  Function:   wValidateCreateParams
//
//  Synopsis:   Validate the incoming create parameters
//
//  Effects:
//
//  Arguments:  [cFormats]      -- the number of elements in rgAdvf
//              [rgAdvf]        -- array of advise flags
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              26-Apr-96 davidwor  added function
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(wValidateCreateParams)
INTERNAL wValidateCreateParams
(
    DWORD		    dwFlags,
    DWORD                   renderopt,
    ULONG		    cFormats,
    DWORD FAR*		    rgAdvf,
    LPFORMATETC             rgFormatEtc,
    IAdviseSink FAR*	    lpAdviseSink,
    DWORD FAR*		    rgdwConnection,
    IOleClientSite FAR*     lpClientSite,
    IStorage FAR*           lpStg
)
{
    HRESULT	hresult = NOERROR;

    VDATEHEAP();

    if (dwFlags != (dwFlags & OLECREATE_LEAVERUNNING)) {
	VdateAssert(dwFlags, "Invalid creation flags");
	hresult = ResultFromScode(E_INVALIDARG);
	goto errRtn;
    }

    if (renderopt == OLERENDER_DRAW && cFormats > 1) {
	VdateAssert(cFormats, "Multiple formats not allowed with OLERENDER_DRAW");
	hresult = ResultFromScode(E_INVALIDARG);
	goto errRtn;
    }

    if (renderopt != OLERENDER_FORMAT)
	VDATEPTRNULL_LABEL( lpAdviseSink, errRtn, hresult );

    if (cFormats == 0) {
	VDATEPTRNULL_LABEL( rgAdvf, errRtn, hresult );
	VDATEPTRNULL_LABEL( rgFormatEtc, errRtn, hresult );
	VDATEPTRNULL_LABEL( rgdwConnection, errRtn, hresult );
    }
    else {
	VDATESIZEREADPTRIN_LABEL( rgAdvf, cFormats * sizeof(DWORD), errRtn, hresult );
	VDATESIZEREADPTRIN_LABEL( rgFormatEtc, cFormats * sizeof(FORMATETC), errRtn, hresult );
	if ( rgdwConnection ) {
	    VDATESIZEPTROUT_LABEL( rgdwConnection, cFormats * sizeof(DWORD), errRtn, hresult );
	    _xmemset(rgdwConnection, 0, cFormats * sizeof(DWORD));
	}
    }

    if ((hresult = wValidateAdvfEx(cFormats, rgAdvf)) != NOERROR)
	goto errRtn;

    VDATEIFACE_LABEL( lpStg, errRtn, hresult );
    if ( lpAdviseSink )
        VDATEIFACE_LABEL( lpAdviseSink, errRtn, hresult );
    if ( lpClientSite )
        VDATEIFACE_LABEL( lpClientSite, errRtn, hresult );

errRtn:
    return hresult;
}


//+-------------------------------------------------------------------------
//
//  Function:   wValidateAdvfEx
//
//  Synopsis:   Validate the incoming array of ADVF values
//
//  Effects:
//
//  Arguments:  [cFormats]      -- the number of elements in rgAdvf
//              [rgAdvf]        -- array of advise flags
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              19-Mar-96 davidwor  added function
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(wValidateAdvfEx)
INTERNAL wValidateAdvfEx
(
    ULONG		    cFormats,
    DWORD FAR*		    rgAdvf
)
{
    VDATEHEAP();

    if ((cFormats != 0) != (rgAdvf != NULL))
	return ResultFromScode(E_INVALIDARG);

    for (ULONG i=0; i<cFormats; i++)
    {
	if (rgAdvf[i] != (rgAdvf[i] & MASK_VALID_ADVF))
	{
	    VdateAssert(rgAdvf, "Invalid ADVF value specified");
	    return ResultFromScode(E_INVALIDARG);
	}
    }

    return NOERROR;
}


//+-------------------------------------------------------------------------
//
//  Function:   wValidateFormatEtc
//
//  Synopsis:   Validate the incoming formatetc and initialize the
//              out formatetc with the correct info
//
//  Effects:
//
//  Arguments:  [renderopt]     -- rendering option
//              [lpFormatEtc]   -- the incoming formatetc
//              [lpMyFormatEtc] -- the out formatetc
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              01-Nov-93 alexgo    32bit port
//
//  Notes:  The original comments,
//
// Validate the lpFormatEtc that's been passed to the creation APIs. And then
// initialize our formateEtc structure with the appropriate info.
//
// We allow NULL lpFormatEtc if the render option is olerender_draw
// We ignore lpFormatEtc if the render option is olerender_none
//
//--------------------------------------------------------------------------


#pragma SEG(wValidateFormatEtc)
INTERNAL wValidateFormatEtc
(
    DWORD                   renderopt,
    LPFORMATETC             lpFormatEtc,
    LPFORMATETC             lpMyFormatEtc
)
{
    VDATEHEAP();

    SCODE sc = S_OK;

    if (renderopt == OLERENDER_NONE || renderopt == OLERENDER_ASIS)
        return NOERROR;

    if (renderopt == OLERENDER_FORMAT) {
        if (!lpFormatEtc || !lpFormatEtc->cfFormat) {
            sc = E_INVALIDARG;
            goto errRtn;
        }

        if (lpFormatEtc->tymed !=
            UtFormatToTymed(lpFormatEtc->cfFormat)) {
            sc = DV_E_TYMED;
            goto errRtn;
        }

    } else if (renderopt == OLERENDER_DRAW) {
        if (lpFormatEtc) {
            if (lpFormatEtc->cfFormat != NULL) {
                VdateAssert(lpFormatEtc->cfFormat,"NON-NULL clipformat specified with OLERENDER_DRAW");
                sc = DV_E_CLIPFORMAT;
                goto errRtn;
            }

            if (lpFormatEtc->tymed != TYMED_NULL) {
                VdateAssert(lpFormatEtc->tymed,"TYMED_NULL is not specified with OLERENDER_DRAW");
                sc = DV_E_TYMED;
                goto errRtn;
            }
        }
    } else {
        VdateAssert(renderopt, "Unexpected value for OLERENDER_ option");
        sc = E_INVALIDARG;
        goto errRtn;
    }

    if (lpFormatEtc) {
        if (!HasValidLINDEX(lpFormatEtc))
        {
          sc = DV_E_LINDEX;
          goto errRtn;
        }

        VERIFY_ASPECT_SINGLE(lpFormatEtc->dwAspect)

        *lpMyFormatEtc = *lpFormatEtc;

    } else {
        INIT_FORETC(*lpMyFormatEtc);
        lpMyFormatEtc->tymed    = TYMED_NULL;
        lpMyFormatEtc->cfFormat = NULL;
    }

errRtn:
    return ReportResult(0, sc, 0, 0);
}


//+-------------------------------------------------------------------------
//
//  Function:   wValidateFormatEtcEx
//
//  Synopsis:   Validate the incoming formatetc and initialize the
//              out formatetc with the correct info
//
//  Effects:
//
//  Arguments:  [renderopt]     -- rendering option
//              [lpcFormats]    -- the number of elements in rgFormatEtc
//              [rgFormatEtc]   -- array of rendering formats
//              [lpFormatEtc]   -- place to store valid formatetc if only one
//              [lplpFormatEtc] -- the out array of formatetcs
//              [lpfAlloced]    -- place to store whether array was allocated
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              01-Nov-93 alexgo    32bit port
//
//  Notes:  The original comments,
//
// Validate the lpFormatEtc that's been passed to the creation APIs. And then
// initialize our formateEtc structure with the appropriate info.
//
// We allow NULL lpFormatEtc if the render option is olerender_draw
// We ignore lpFormatEtc if the render option is olerender_none
//
//--------------------------------------------------------------------------


#pragma SEG(wValidateFormatEtcEx)
INTERNAL wValidateFormatEtcEx
(
    DWORD                   renderopt,
    ULONG FAR*		    lpcFormats,
    LPFORMATETC             rgFormatEtc,
    LPFORMATETC		    lpFormatEtc,
    LPFORMATETC FAR*	    lplpFormatEtc,
    LPBOOL		    lpfAlloced
)
{
    LPFORMATETC		    lpfmtetc;

    VDATEHEAP();

    SCODE sc = S_OK;

    *lplpFormatEtc = lpFormatEtc;
    *lpfAlloced = FALSE;

    if (renderopt == OLERENDER_NONE || renderopt == OLERENDER_ASIS)
        return NOERROR;

    if (renderopt != OLERENDER_FORMAT && renderopt != OLERENDER_DRAW) {
        VdateAssert(renderopt, "Unexpected value for OLERENDER_ option");
	return ResultFromScode(E_INVALIDARG);
    }

    if ((*lpcFormats != 0) != (rgFormatEtc != NULL))
	return ResultFromScode(E_INVALIDARG);

    if (*lpcFormats <= 1) {
	if (*lpcFormats == 0)
	    *lpcFormats = 1;
	return wValidateFormatEtc(renderopt, rgFormatEtc, lpFormatEtc);
    }

    *lplpFormatEtc = (LPFORMATETC)PubMemAlloc(*lpcFormats * sizeof(FORMATETC));
    if (!*lplpFormatEtc)
	return E_OUTOFMEMORY;

    *lpfAlloced = TRUE;

    for (ULONG i=0; i<*lpcFormats; i++)
    {
	lpfmtetc = &rgFormatEtc[i];

	if (renderopt == OLERENDER_FORMAT)
	{
	    if (!lpfmtetc->cfFormat) {
		sc = E_INVALIDARG;
		goto errRtn;
	    }

	    if (lpfmtetc->tymed !=
		UtFormatToTymed(lpfmtetc->cfFormat)) {
		sc = DV_E_TYMED;
		goto errRtn;
	    }
	}
	else if (renderopt == OLERENDER_DRAW)
	{
            if (lpfmtetc->cfFormat != NULL) {
                VdateAssert(lpfmtetc->cfFormat,"NON-NULL clipformat specified with OLERENDER_DRAW");
                sc = DV_E_CLIPFORMAT;
                goto errRtn;
            }

            if (lpfmtetc->tymed != TYMED_NULL) {
                VdateAssert(lpfmtetc->tymed,"TYMED_NULL is not specified with OLERENDER_DRAW");
                sc = DV_E_TYMED;
                goto errRtn;
            }
	}

        if (!HasValidLINDEX(lpfmtetc))
        {
	    sc = DV_E_LINDEX;
	    goto errRtn;
        }

        VERIFY_ASPECT_SINGLE(lpfmtetc->dwAspect)

	(*lplpFormatEtc)[i] = *lpfmtetc;
    }

errRtn:
    if (sc != S_OK) {
	PubMemFree(*lplpFormatEtc);
	*lpfAlloced = FALSE;
    }
    return ReportResult(0, sc, 0, 0);
}


//+-------------------------------------------------------------------------
//
//  Function:   wQueryFormatSupport
//
//  Synopsis:   check to see whether we will be able to Get and SetData of
//              the given format
//
//  Effects:
//
//  Arguments:  [lpObj]         -- pointer to the object
//              [renderopt]     -- rendering options
//              [lpFormatEtc]   -- the formatetc in question
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:  Internal function, calls UtIsFormatSupported (which calls
//              EnumFormatEtc and checks all of the formats) if renderopt
//              is OLERENDER_FORMAT
//
//  History:    dd-mmm-yy Author    Comment
//              01-Nov-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


#pragma SEG(wQueryFormatSupport)
INTERNAL wQueryFormatSupport
    (LPVOID lpObj, DWORD renderopt, LPFORMATETC lpFormatEtc)
{
    VDATEHEAP();

    IDataObject FAR*        lpDataObj;
    HRESULT                 error = NOERROR;

    if (renderopt == OLERENDER_FORMAT)
    {
        if ((error = ((IUnknown FAR*) lpObj)->QueryInterface(
            IID_IDataObject, (LPLPVOID)&lpDataObj)) == NOERROR)
        {
            if (!UtIsFormatSupported(lpDataObj,
                    DATADIR_GET | DATADIR_SET,
                    lpFormatEtc->cfFormat))
                error = ResultFromScode(DV_E_CLIPFORMAT);

            lpDataObj->Release();
        }
    }

    return error;
}


//+-------------------------------------------------------------------------
//
//  Function:   wGetMonikerAndClassFromObject
//
//  Synopsis:   Gets the moniker and class ID from the given object
//
//  Effects:
//
//  Arguments:  [lpSrcDataObj]  -- the data object
//              [lplpmkSrc]     -- where to put a pointer to the moniker
//              [lpclsidLast]   -- where to put the clsid
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//		15-Mar-95 alexgo    added a hack for CorelDraw5
//              01-Nov-93 alexgo    32bit port
//
//  Notes:      see also wGetMonikerAndClassFromFile
//
//--------------------------------------------------------------------------



#pragma SEG(wGetMonikerAndClassFromObject)
INTERNAL wGetMonikerAndClassFromObject(
    LPDATAOBJECT            lpSrcDataObj,
    LPMONIKER FAR*          lplpmkSrc,
    CLSID FAR*              lpclsidLast
)
{
    VDATEHEAP();

    HRESULT                 error;
    FORMATETC               foretcTmp;
    STGMEDIUM               medium;
    LPMONIKER               lpmkSrc = NULL;
    LARGE_INTEGER   large_integer;

    INIT_FORETC(foretcTmp);
    foretcTmp.cfFormat = g_cfLinkSource;
    foretcTmp.tymed    = TYMED_ISTREAM;

    // 16bit OLE had a bug where the medium was uninitialized at this
    // point.  Corel5, when doing a paste-link to itself, actually
    // checked the tymed and compared it with TYMED_NULL.  So here
    // we set the value to something recognizeable.
    //
    // NB!  In the thunk layer, if we are *NOT* in Corel Draw, this
    // value will be reset to TYMED_NULL.

    if( IsWOWThread() )
    {
	medium.tymed = 0x66666666;
    }
    else
    {
	medium.tymed = TYMED_NULL;
    }
    medium.pstm  = NULL;
    medium.pUnkForRelease = NULL;

    if ((error = lpSrcDataObj->GetData(&foretcTmp, &medium)) != NOERROR)
            return ReportResult(0, OLE_E_CANT_GETMONIKER, 0, 0);

    LISet32( large_integer, 0 );
    if ((error = (medium.pstm)->Seek (large_integer, STREAM_SEEK_SET,
        NULL)) != NOERROR)
        goto FreeStgMed;

    // get moniker from the stream
    if ((error = OleLoadFromStream (medium.pstm, IID_IMoniker,
        (LPLPVOID) lplpmkSrc)) != NOERROR)
        goto FreeStgMed;

    // read class stm; if error, use CLSID_NULL (for compatibility with
    // prior times when the clsid was missing).
    ReadClassStm(medium.pstm, lpclsidLast);

FreeStgMed:
    ReleaseStgMedium (&medium);
    if (error != NOERROR)
        return ReportResult(0, OLE_E_CANT_GETMONIKER, 0, 0);

    return NOERROR;
}


//+-------------------------------------------------------------------------
//
//  Function:   wDoLockUnlock
//
//  Synopsis:   tickles an object by locking and unlocking, used to resolve
//              ambiguities with stub manager locks
//
//  Effects:    the object may go away as a result of this call, if the
//              object is invisible and the lock count goes to zero as
//              a result of locking/unlocking.
//
//  Arguments:  [lpUnk]         -- pointer to the object to lock/unlock
//
//  Requires:
//
//  Returns:    void
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              01-Nov-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(wDoLockUnlock)
void wDoLockUnlock(IUnknown FAR* lpUnk)
{
    VDATEHEAP();

    IRunnableObject FAR* pRO;

    if (lpUnk->QueryInterface(IID_IRunnableObject, (LPLPVOID)&pRO)
        == NOERROR)
    {       // increase lock count
        if (pRO->LockRunning(TRUE, FALSE) == NOERROR)
            // decrease lock count
            pRO->LockRunning(FALSE, TRUE);
        pRO->Release();
    }
}

//+-------------------------------------------------------------------------
//
//  Function:   wSaveObjectWithoutCommit
//
//  Synopsis:   Saves an object without committing (to preserve the
//              container's undo state)
//
//  Effects:
//
//  Arguments:  [lpUnk]         -- pointer to the object
//              [pstgSave]      -- storage in which to save
//              [fSameAsLoad]   -- indicates SaveAs operation
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              02-Nov-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

INTERNAL wSaveObjectWithoutCommit
    (LPUNKNOWN lpUnk, LPSTORAGE pstgSave, BOOL fSameAsLoad)
{
    VDATEHEAP();

    LPPERSISTSTORAGE                pPS;
    HRESULT                         error;
    CLSID                           clsid;

    if (error = lpUnk->QueryInterface(IID_IPersistStorage, (LPLPVOID)&pPS))
        return error;

    if (error = pPS->GetClassID(&clsid))
        goto errRtn;

    if (error = WriteClassStg(pstgSave, clsid))
        goto errRtn;

    if (error = pPS->Save(pstgSave, fSameAsLoad))
        goto errRtn;

    pPS->SaveCompleted(NULL);

errRtn:
    pPS->Release();
    return error;
}


//+-------------------------------------------------------------------------
//
//  Function:   wStuffIconOfFileEx
//
//  Synopsis:   Retrieves the icon if file [lpszFile] and stuffs it into
//              [lpUnk]'s cache
//
//  Effects:
//
//  Arguments:  [lpszFile]      -- the file where the icon is stored
//              [fAddLabel]     -- if TRUE, adds a label to the icon
//                                 presentation
//              [renderopt]     -- must be OLERENDER_DRAW or
//                                 OLERENDER_FORMAT for anything to happen
//              [cFormats]      -- the number of elements in rgFormatEtc
//              [rgFormatEtc]   -- array of rendering formats, aspect must be
//                                 DVASPECT_ICON and the clipboard format
//                                 must be NULL or CF_METAFILE for anything
//                                 to happen
//              [lpUnk]         -- pointer to the object in which the icon
//                                 should be stuffed
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              02-Nov-93 alexgo    32bit port
//
//  Notes:
//              REVIEW32: maybe we should support enhanced metafiles for NT
//
//--------------------------------------------------------------------------


#pragma SEG(wStuffIconOfFileEx)
INTERNAL wStuffIconOfFileEx
(
    LPCOLESTR       lpszFile,
    BOOL            fAddLabel,
    DWORD           renderopt,
    ULONG	    cFormats,
    LPFORMATETC	    rgFormatEtc,
    LPUNKNOWN       lpUnk
)
{
    VDATEHEAP();

    IOleCache FAR*  lpOleCache;
    HRESULT         error;
    BOOL	    fFound = FALSE;
    FORMATETC       foretc;
    STGMEDIUM       stgmed;

    if (renderopt == OLERENDER_NONE || renderopt == OLERENDER_ASIS)
        return NOERROR;

    if (rgFormatEtc == NULL)
        return NOERROR; // in this case we default to DVASPECT_CONTENT

    for (ULONG i=0; i<cFormats; i++)
    {
	if ((rgFormatEtc[i].dwAspect == DVASPECT_ICON) &&
	    (rgFormatEtc[i].cfFormat == NULL ||
	     rgFormatEtc[i].cfFormat == CF_METAFILEPICT))
	{
	   foretc = rgFormatEtc[i];
	   fFound = TRUE;
	}
    }

    if (!fFound)
        return NOERROR;

    foretc.cfFormat = CF_METAFILEPICT;
    foretc.tymed = TYMED_MFPICT;

    if ((error = lpUnk->QueryInterface(IID_IOleCache,
	(LPLPVOID) &lpOleCache)) != NOERROR)
	return error;

    stgmed.tymed = TYMED_MFPICT;
    stgmed.pUnkForRelease = NULL;

    // get icon data of file, from registration database
    if (!(stgmed.hGlobal = OleGetIconOfFile((LPOLESTR) lpszFile,
	fAddLabel))) {
	error = ResultFromScode(E_OUTOFMEMORY);
	goto errRtn;
    }

    // take ownership of the data
    if ((error = lpOleCache->SetData(&foretc, &stgmed, TRUE)) != NOERROR)
	ReleaseStgMedium(&stgmed);

errRtn:
    lpOleCache->Release();
    return error;

}


//+-------------------------------------------------------------------------
//
//  Function:   wNeedToPackage
//
//  Synopsis:   Determines whether or not a given CLSID should be
//              packaged.
//
//  Effects:
//
//  Arguments:  [rclsid]        -- the class ID
//
//  Requires:
//
//  Returns:    BOOL
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:  Looks for the reg key PackageOnFileDrop, or if it's a
//              Word document, or if it is insertable, or if it's an OLE1
//              class
//
//  History:    dd-mmm-yy Author    Comment
//              02-Nov-93 alexgo    32bit port
//              03-Jun-94 AlexT     Just check for Insertable key (instead
//                                    of requiring a value)
//
//  Notes:
//--------------------------------------------------------------------------



INTERNAL_(BOOL) wNeedToPackage(REFCLSID rclsid)
{
    VDATEHEAP();

    HKEY    hkeyClsid;
    HKEY    hkeyTmp;
    HKEY    hkeyTmp2;
    BOOL    fPackage = FALSE;
    LPOLESTR        lpszProgID;
    DWORD   dw;
    LONG    cbValue = sizeof(dw);
    LONG    lRet;
	CLSID	clsidNew;
	
	if (NOERROR != OleGetAutoConvert (rclsid, &clsidNew))
	{
		if (NOERROR != CoGetTreatAsClass (rclsid, &clsidNew))
		{
			clsidNew = rclsid;
		}
	}

    if (CoOpenClassKey(clsidNew, &hkeyClsid) != NOERROR)
        return TRUE;    // NON-OLE file, package it

    if (ProgIDFromCLSID(clsidNew, &lpszProgID) == NOERROR) {
        // see whether we can open this key

        dw = (DWORD) RegOpenKey(HKEY_CLASSES_ROOT, lpszProgID,
            &hkeyTmp);

        PubMemFree(lpszProgID);

        if (dw == ERROR_SUCCESS) {
            // This is definitely a OLE insertable file.
            lRet = RegOpenKey(hkeyTmp,
                     OLESTR("PackageOnFileDrop"),
                     &hkeyTmp2);
            // Check whether we need to package this file
            if (ERROR_SUCCESS == lRet)
            {
              RegCloseKey(hkeyTmp2);
              fPackage = TRUE;
            }
            else if (IsEqualCLSID(clsidNew, CLSID_WordDocument))
            {
            // Hack to make sure Word documents are always
            // Packaged on file drop.  We write the key here
            // so that we can say that a file is Packaged if
            // and only if its ProgID has the "PackageOnFileDrop"
            // key.
                RegSetValue (hkeyTmp,
                    OLESTR("PackageOnFileDrop"),
                    REG_SZ, (LPOLESTR)NULL, 0);
                fPackage = TRUE;
            }

            RegCloseKey(hkeyTmp);

            if (fPackage) {
                RegCloseKey(hkeyClsid);
                return TRUE;
            }
        }
    }

    // There is no "PackageOnFileDrop" key defined.

    // See whether this is an "Insertable" class by checking for the
    // existence of the Insertable key - we don't require a value

    lRet = RegOpenKey(hkeyClsid, OLESTR("Insertable"), &hkeyTmp);

    if (ERROR_SUCCESS == lRet)
    {
      //  Insertable key exists - close it and return
      RegCloseKey(hkeyTmp);
      goto errRtn;
    }

    //
    // See whether this is a "Ole1Class" class by opening the
    // registry key Ole1Class. We don't require a value
    //
    cbValue = sizeof(dw);
    lRet = RegOpenKey(hkeyClsid,OLESTR("Ole1Class"),&hkeyTmp);
    if (ERROR_SUCCESS == lRet)
    {
      RegCloseKey(hkeyTmp);
      goto errRtn;
    }
    else
    {
      fPackage = TRUE;
    }



errRtn:
    RegCloseKey(hkeyClsid);
    return fPackage;
}

//+-------------------------------------------------------------------------
//
//  Function:   wDoUpdate
//
//  Synopsis:   calls IOleObject->Update() on the given object, internal
//              function
//
//  Effects:
//
//  Arguments:  [lpUnkown]      -- the object to update
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              02-Nov-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------

#pragma SEG(wDoUpdate)
INTERNAL  wDoUpdate(IUnknown FAR* lpUnknown)
{
    VDATEHEAP();

    HRESULT                 error = NOERROR;
    IOleObject FAR*         lpOle;

    if (lpUnknown->QueryInterface (IID_IOleObject, (LPLPVOID)&lpOle)
        == NOERROR) {
        error = lpOle->Update();
        lpOle->Release();
    }

    return error;
}




//+-------------------------------------------------------------------------
//
//  Function:   wBindIfRunning
//
//  Synopsis:   calls IOleLink->BindIfRunning() on the given object
//
//  Effects:
//
//  Arguments:  [lpUnk]         -- the object
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              02-Nov-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


INTERNAL_(void) wBindIfRunning(LPUNKNOWN lpUnk)
{
    VDATEHEAP();

    IOleLink FAR* lpLink;

    if (lpUnk->QueryInterface (IID_IOleLink, (LPLPVOID)&lpLink)
        == NOERROR)
    {
        lpLink->BindIfRunning();
        lpLink->Release();
    }
}


//+-------------------------------------------------------------------------
//
//  Function:   wQueryUseCustomLink
//
//  Synopsis:   look at the registry and see if the class ID has a custom
//              link regisetered
//
//  Effects:
//
//  Arguments:  [rclsid]        -- the class ID in question
//
//  Requires:
//
//  Returns:    BOOL
//
//  Signals:
//
//  Modifies:
//
//  Algorithm:
//
//  History:    dd-mmm-yy Author    Comment
//              02-Nov-93 alexgo    32bit port
//
//  Notes:
//
//--------------------------------------------------------------------------


INTERNAL_(BOOL) wQueryUseCustomLink(REFCLSID rclsid)
{
    VDATEHEAP();

    // see whether it has Custom Link implementation
    HKEY    hkeyClsid;
    HKEY    hkeyTmp;
    BOOL    bUseCustomLink = FALSE;

    if (SUCCEEDED(CoOpenClassKey(rclsid, &hkeyClsid)))
    {
        DWORD   dw;
        dw = RegOpenKey(hkeyClsid,OLESTR("UseCustomLink"),&hkeyTmp);

        if (ERROR_SUCCESS == dw)
        {
          RegCloseKey(hkeyTmp);
          bUseCustomLink = TRUE;
        }

        RegCloseKey(hkeyClsid);
    }

    return bUseCustomLink;
}