//+------------------------------------------------------------------------- // // 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 #pragma SEG(create) #include #include // Only needed to get CLSID_WordDocument // HACK ALERT!! This is needed for the MFC OleQueryCreateFromData hack #include 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; cQueryInterface(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; cRelease(); 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; idwAspect == 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; icfFormat) { 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; iQueryInterface(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; }