4823 lines
140 KiB
C++
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;
|
|
}
|
|
|