windows-nt/Source/XPSP1/NT/com/ole32/ole232/base/create.cpp
2020-09-26 16:20:57 +08:00

4823 lines
140 KiB
C++

//+-------------------------------------------------------------------------
//
// 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 <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, FALSE,
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
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, FALSE, 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,
BOOL fPermitCodeDownload, //new parameter to control whether code download occurs or not -RahulTh (11/20/97)
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, fPermitCodeDownload, 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, FALSE,
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, FALSE,
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, FALSE,
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,
BOOL fPermitCodeDownload, //parameter added in order to control whether code download occurs or not -RahulTh (11/20/97)
REFIID iid,
IOleClientSite FAR* lpClientSite,
IStorage FAR * lpStg,
WORD wfStorage,
void FAR* FAR* ppv
)
{
VDATEHEAP();
HRESULT error;
DWORD dwClsCtx;
IOleObject* pOleObject = NULL;
DWORD dwMiscStatus = 0;
DWORD dwAddClsCtx;
dwAddClsCtx = fPermitCodeDownload?0:CLSCTX_NO_CODE_DOWNLOAD;
*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 | dwAddClsCtx;
}
else
{
dwClsCtx = CLSCTX_INPROC | dwAddClsCtx;
}
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");
// Check if we have client site
if(lpClientSite) {
// QI for IOleObject on the server
error = ((IUnknown *)*ppv)->QueryInterface(IID_IOleObject, (void **)&pOleObject);
if(error == NOERROR) {
// Get the MiscStatus bits
error = pOleObject->GetMiscStatus(DVASPECT_CONTENT, &dwMiscStatus);
// Set the client site first if OLEMISC_SETCLIENTSITEFIRST bit is set
if(error == NOERROR && (dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)) {
error = pOleObject->SetClientSite(lpClientSite);
if(error != NOERROR) {
pOleObject->Release();
goto errRtn;
}
}
else if(error != NOERROR) {
error = NOERROR;
dwMiscStatus = 0;
}
}
else
goto errRtn;
}
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) {
// Assert that pOleObject is set
Win4Assert(IsValidInterface(pOleObject));
// Set the client site if it has not been set already
if(!(dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST))
error = pOleObject->SetClientSite (lpClientSite);
// Release the object
pOleObject->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, FALSE, 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 hrFileMoniker;
HRESULT hresult;
BOOL fHaveBoundClsid = FALSE;
LPMONIKER lpFileMoniker;
VDATEHEAP();
*lplpDataObject = NULL;
*lplpmkFile = 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 (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 (!fHaveBoundClsid)
{
// Call GetClassFileEx directly (rather than going through GetClassFile).
hresult = GetClassFileEx ((LPOLESTR)lpszFileName, lpClsid, CLSID_NULL);
Assert( (NOERROR == hresult) || (IsEqualCLSID(*lpClsid, CLSID_NULL)) );
if (NOERROR == hresult)
fHaveBoundClsid = TRUE;
}
// If have a CLSID at this point see if its insertable.
if (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 (hresult == 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, FALSE, &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, FALSE, &hkeyClsid)))
{
DWORD dw;
dw = RegOpenKey(hkeyClsid,OLESTR("UseCustomLink"),&hkeyTmp);
if (ERROR_SUCCESS == dw)
{
RegCloseKey(hkeyTmp);
bUseCustomLink = TRUE;
}
RegCloseKey(hkeyClsid);
}
return bUseCustomLink;
}