|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: ostm2stg.cpp
//
// Contents: OLE 1 - OLE 2 Stream/IStorage Interoperatbility
//
// Functions: Implements API functions:
// OleConvertOLESTREAMToIStorage
// OleConvertIStorageToOLESTREAM
// OleConvertOLESTREAMToIStorageEx
// OleConvertIStorageToOLESTREAMEx
//
//
// History: dd-mmm-yy Author Comment
// 03-Feb-92 jasonful original version
// 08-Aug-93 srinik added Ex functions
// 12-Feb-94 davepl 32-bit port
//
//--------------------------------------------------------------------------
#include <le2int.h>
#include "ostm2stg.h"
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <ole1cls.h>
ASSERTDATA
// We need a ptr value which will indicate that the associated handle
// is a metafile handle, and therefore cannot be cleaned up as if
// it were a normal global memory handle
#define METADATAPTR ((void *) -1)
// This fn is not prototyped in any include file, since it was static
// to its file. Need to add the prototype to a common include file.
HRESULT STDAPICALLTYPE CreateOle1FileMoniker(LPWSTR,REFCLSID,LPMONIKER FAR*);
// This is defined in the new privstm.cpp; must be added to an include file.
STDAPI ReadFmtProgIdStg ( IStorage * pstg, LPOLESTR * pszProgID ); FARINTERNAL wWriteFmtUserType (LPSTORAGE, REFCLSID);
//+-------------------------------------------------------------------------
//
// Member: CGenericObject::CGenericObject
//
// Synopsis: Constructor for CGenericObject class
//
// Effects: Initializes all child pointers to NULL and sets
// flags to FALSE
//
// History: dd-mmm-yy Author Comment
// 14-Feb-94 davepl Cleanup and document
//
// Notes:
//
//--------------------------------------------------------------------------
CGenericObject::CGenericObject(void) { m_ppres = NULL; // Presentation data
m_fLink = FALSE; // Flag: Linked (T) or Embedded (F)
m_fStatic = FALSE; // Flag: Static object
m_fNoBlankPres = FALSE; // Flag: do not want a blank presentation
m_szTopic = NULL; // Topic string for this object
m_szItem = NULL; // Item (file) string for this object
}
//+-------------------------------------------------------------------------
//
// Member: CGenericObject::~CGenericObject
//
// Synopsis: Desctuctor for CGenericObject class
//
// Effects: Removes children then self
//
// History: dd-mmm-yy Author Comment
// 12-Aug-94 alexgo check for NULL before delete
// 14-Feb-94 davepl Cleanup and document
//
// Notes: As much as I hated to do it, some of these strings
// have to be freed with PubMemFree because they are
// allocated by UtDupString, which allocates public memory.
//
//--------------------------------------------------------------------------
CGenericObject::~CGenericObject (void) { if( m_ppres ) { delete m_ppres; // Presentation data
}
if( m_szTopic ) { PubMemFree(m_szTopic); // Topic string
}
if( m_szItem ) { PubMemFree(m_szItem); // Item string
} }
//+-------------------------------------------------------------------------
//
// Member: CData::CData
//
// Synopsis: Constructor for a simple class which holds a piece of
// memory.
//
// Effects: Clears size, flags, and pointer
//
// History: dd-mmm-yy Author Comment
//
// Notes: 14-Feb-94 davepl Cleanup and document
//
//--------------------------------------------------------------------------
CData::CData (void) { m_cbSize = 0; // Count, in bytes, of data size
m_h = NULL; // Memory handke
m_pv= NULL; // Memory pointer
m_fNoFree = FALSE; // Flag: Should memory be freed in destructor
}
//+-------------------------------------------------------------------------
//
// Member: CData::~CData
//
// Synopsis: Destructor for simple data class
//
// Effects: Unlocks and frees memory if m_fNoFree is not set
//
// History: dd-mmm-yy Author Comment
// 14-Feb-94 davepl Cleanup and document
//
// Notes: If a metafile handle is stored in the handle, the
// pointer will be marked with a special value, indicating
// that we must DeleteMetafile, not GlobalFree the handle.
//
//--------------------------------------------------------------------------
CData::~CData (void) { if (m_h) // Do we have a handle?
{ if (m_pv == METADATAPTR) { LEVERIFY(DeleteMetaFile((HMETAFILE) m_h)); } else { GlobalUnlock (m_h); // Dec lock count
if (!m_fNoFree) // Free this memory if we
{ // have been flagged to do so
LEVERIFY(0==GlobalFree (m_h)); } } } }
//+-------------------------------------------------------------------------
//
// Member: CFormat::CFormat
//
// Synopsis: CFormat class constructor
//
// Effects: Initializes format tag and clipboard format
//
// History: dd-mmm-yy Author Comment
//
// Notes: 14-Feb-94 davepl Cleanup and document
//
//--------------------------------------------------------------------------
CFormat::CFormat (void) { m_ftag = ftagNone; // Format tag (string, clipformat, or none)
m_cf = 0; // Clipboard format
}
//+-------------------------------------------------------------------------
//
// Member: CClass::CClass
//
// Synopsis: CClass constructor
//
// Effects: sets class ID and class ID string to NULL
//
// History: dd-mmm-yy Author Comment
//
// Notes:
//
//--------------------------------------------------------------------------
CClass::CClass (void) { m_szClsid = NULL; m_clsid = CLSID_NULL; }
//+-------------------------------------------------------------------------
//
// Member: CPres::CPres
//
// Synopsis: CPres constructor
//
// Effects: Initializes height & width of presentation data to zero.
//
// History: dd-mmm-yy Author Comment
//
// Notes:
//
//--------------------------------------------------------------------------
CPres::CPres (void) { m_ulHeight = 0L; m_ulWidth = 0L; }
//+-------------------------------------------------------------------------
//
// Member: CClass::Set, INTERNAL
//
// Synopsis: Sets the m_szClsid based on clsid
//
// Effects: Sets m_szClsid in the following order of preference:
// - ProgID obtained from ProgIDFromCLSID()
// - If it is a static type, m_szClsid is left blank
// - Tries to read it from [pstg]
// - Tries to obtain it from registry based on CLSID
//
//
// Arguments: [clsid] - class id object is to be set to
// [pstg] - storage which may contain info on the
// clipboard format as a last resort
//
// Returns: NOERROR on success
// REGDB_E_CLASSNOTREG unknown class
//
// History: dd-mmm-yy Author Comment
// 16-Feb-94 davepl Cleaned up and documented
//
// Notes: Hard-coded maximum of 256 character clip format name.
// On failure, m_clsid has still been set to clsid.
//
//--------------------------------------------------------------------------
INTERNAL CClass::Set (REFCLSID clsid, LPSTORAGE pstg) { CLIPFORMAT cf; unsigned short const ccBufSize = 256; LPOLESTR szProgId = NULL;
Assert (m_clsid == CLSID_NULL && m_szClsid == NULL);
// set the m_clsid member in the object
m_clsid = clsid;
// If we can get it using ProgIDFromCLSID, that's the simplest case
if (NOERROR == wProgIDFromCLSID (clsid, &m_szClsid)) { return NOERROR; }
// If not, maybe the object is static, in which case we leave the
// class string NULL
if (IsEqualCLSID(CLSID_StaticMetafile, clsid) || IsEqualCLSID(CLSID_StaticDib, clsid)) { return NOERROR; }
// If still no luck, try to read the clipboard format from the storage
// and then look that up.
if (pstg && SUCCEEDED(ReadFmtUserTypeStg(pstg, &cf, NULL)) && SUCCEEDED(ReadFmtProgIdStg (pstg, &szProgId))) { // Last-ditch effort. If the class is an unregistered OLE1 class,
// the ProgID should still be obtainable from the format tag.
// If the class is an unregistered OLE2 class, the ProgId should be
// at the end of the CompObj stream.
if (CoIsOle1Class(clsid)) { Verify (GetClipboardFormatName (cf, szProgId, ccBufSize)); } else { // If its an OLE 2 object and we couldn't get the program ID from
// the storage, we're out of luck
if (szProgId == NULL || szProgId[0] == L'\0') { if (szProgId) { PubMemFree(szProgId); } return ResultFromScode (REGDB_E_CLASSNOTREG); } }
// At this point we know we have a program ID and that this is an
// OLE 2 object, so we use the program ID as the class name.
m_szClsid = szProgId; return NOERROR; } else { // If we hit this path, we couldn't read from the storage
return ResultFromScode (REGDB_E_CLASSNOTREG); } }
//+-------------------------------------------------------------------------
//
// Member: CClass:SetSz, INTERNAL
//
// Synopsis: Sets CGenericObject's CLASS member ID based on the class
// name passed in.
//
// History: dd-mmm-yy Author Comment
// 15-Feb-94 davepl Cleaned up and documented
//
//--------------------------------------------------------------------------
INTERNAL CClass::SetSz (LPOLESTR sz) { HRESULT hr;
// The class info should be completely unset at this point
Assert (m_clsid==CLSID_NULL && m_szClsid==NULL);
m_szClsid = sz;
if (FAILED(hr = wCLSIDFromProgID (sz, &m_clsid, TRUE))) { return hr; }
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CClass::Reset
//
// Synopsis: Frees the Class ID string for CClass and resets the pointer,
// then sets the class ID and string bassed on the CLSID
// passed in.
//
// History: dd-mmm-yy Author Comment
// 16-Feb-94 davepl Cleaned up and documented
//
// Notes: Class ID must already be set before calling RESET
//
//--------------------------------------------------------------------------
INTERNAL CClass::Reset (REFCLSID clsid) { m_clsid = clsid;
// We should already have a class ID string if we are _re_setting it
Assert(m_szClsid);
PubMemFree(m_szClsid);
HRESULT hr; m_szClsid = NULL;
if (FAILED(hr = wProgIDFromCLSID (clsid, &m_szClsid))) { return hr; }
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CClass::~CClass
//
// Synopsis: CClass destructor
//
// History: dd-mmm-yy Author Comment
// 12-Aug-94 alexgo check for NULL before free'ing memory
// Notes:
//
//--------------------------------------------------------------------------
CClass::~CClass (void) { // The string is created by UtDupString, so its public memory
if( m_szClsid ) { PubMemFree(m_szClsid); } }
//+-------------------------------------------------------------------------
//
// Function: wConvertOLESTREAMToIStorage, INTERNAL
//
// Synopsis: Worker function. Ensures the OLESTREAM is correctly
// set up then calls OLESTREAMToGenericObject.
//
// History: dd-mmm-yy Author Comment
// 15-Feb-94 davepl Cleaned up and documented
// Notes:
//
//--------------------------------------------------------------------------
INTERNAL wConvertOLESTREAMToIStorage( LPOLESTREAM polestream, LPSTORAGE pstg, PGENOBJ pgenobj) { VDATEIFACE (pstg);
#if DBG==1
if (!IsValidReadPtrIn (polestream, sizeof(OLESTREAM)) || !IsValidReadPtrIn (polestream->lpstbl, sizeof(OLESTREAMVTBL)) || !IsValidCodePtr ((FARPROC)polestream->lpstbl->Get)) { AssertSz (0, "Bad OLESTREAM"); return ResultFromScode (E_INVALIDARG); } #endif
return OLESTREAMToGenericObject (polestream, pgenobj); }
//+-------------------------------------------------------------------------
//
// Function: OleConvertOLESTREAMToIStorage, STDAPI
//
// Synopsis: Given an OLE 1 stream and an OLE 2 storage, reads an object
// from the OLE 1 stream into a CGenericObject. Once read in,
// the object is written from generic format back into the OLE 2
// storage object.
//
// Arguments: [polestream] -- OLE 1 stream to read object from
// [pstg] -- OLE 2 storage to write object to
// [ptd] -- Target device
//
// Requires: Streams should be set up, and OLE 1 stream should be
// positioned at the beginning of the next OLE 1 object
// to be read.
//
// Returns: [DV_E_DVTARGETDEVICE] Invalid write ptr to target device
// CONVERT10_E_OLESTREAM_FMT On unknown OLE 1 format
// CONVERT10_E_OLESTREAM_GET On stream read failue
// E_OUTOFMEMORY On stream I/O memory failure
//
// History: dd-mmm-yy Author Comment
// 14-Feb-94 davepl Cleanup and documentation
//
// Notes:
//
//--------------------------------------------------------------------------
STDAPI OleConvertOLESTREAMToIStorage( LPOLESTREAM polestream, LPSTORAGE pstg, const DVTARGETDEVICE FAR* ptd) {
OLETRACEIN((API_OleConvertOLESTREAMToIStorage, PARAMFMT("polestream= %p, pstg= %p, ptd= %td"), polestream, pstg, ptd));
LEDebugOut((DEB_TRACE, "%p _IN OleConvertOLESTREAMToIStorage (" " %p , %p , %p)\n", 0 /*function*/, polestream, pstg, ptd )); CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStorage,(IUnknown **)&pstg);
HRESULT hresult;
// This is the generic object we will use as intermediate storage to
// hold the contents of the OLESTREAM
CGenericObject genobj;
if (ptd) { // The side of the td is the first DWORD. Ensure that much is
// valid and then we can use it to check the whole structure.
if (!IsValidReadPtrIn (ptd, sizeof(DWORD))) { hresult = ResultFromScode (DV_E_DVTARGETDEVICE); goto errRtn; } if (!IsValidReadPtrIn (ptd, (UINT) ptd->tdSize)) { hresult = ResultFromScode (DV_E_DVTARGETDEVICE_SIZE); goto errRtn; } }
if (FAILED(hresult=wConvertOLESTREAMToIStorage(polestream,pstg,&genobj))) { goto errRtn; }
// If we were able to read the object out of the stream, we can now try
// to write it back out to the storage
hresult = GenericObjectToIStorage (genobj, pstg, ptd);
errRtn: LEDebugOut((DEB_TRACE, "%p OUT OleConvertOLESTREAMToIStorage ( %lx ) " "\n", 0 /*function*/, hresult));
OLETRACEOUT((API_OleConvertOLESTREAMToIStorage, hresult)); return hresult;
}
//+-------------------------------------------------------------------------
//
// Function: PrependUNCName
//
// Synopsis: Convert *pszFile to use szUNC=="\\server\share" instead
// of drive letter
//
// Effects: Deletes the UNC name and returns *ppszFile as a NEW string
// with the full UNC filename. The string originally held at
// *ppszFile is deleted by this function.
//
// Arguments: [ppszFile] Pointer to incoming filename string pointer
//
// History: dd-mmm-yy Author Comment
// 16-Feb-94 davepl Cleanup, documentation, allocation fixes
//
// Notes: This function does some frightening things by changing the
// caller's pointer and deleting various reference parameters.
// Be sure you know what's going on before turning this function
// loose on one of your own pointers.
//
//--------------------------------------------------------------------------
static INTERNAL PrependUNCName (LPOLESTR FAR* ppszFile, LPOLESTR szUNC) { HRESULT hresult = NOERROR; LPOLESTR szNew;
// No place to put result, so nothing to do...
if (NULL==szUNC) { return hresult; }
// Ensure the caller's pointer is valid
if (NULL == *ppszFile) { return ResultFromScode(CONVERT10_E_OLESTREAM_FMT); }
// Ensure the second letter of path is a colon (ie; X:\file)
if((*ppszFile)[1] != L':') { return ResultFromScode(CONVERT10_E_OLESTREAM_FMT); }
// Allocate enough space for new filename (we will be
// omitting the X: portion of the filename, so this calculation
// is _not_ short by 2 as it may appear)
szNew = (LPOLESTR) PubMemAlloc((_xstrlen(*ppszFile)+_xstrlen (szUNC)) * sizeof(OLECHAR));
if (NULL == szNew) { return ResultFromScode(E_OUTOFMEMORY); }
// Copy over the UNC name
_xstrcpy (szNew, szUNC);
// Add the original name, except for the X:
_xstrcat (szNew, (*ppszFile) + 2);
// Free the original name
PubMemFree(*ppszFile); *ppszFile = szNew;
// Delete the UNC name
PubMemFree(szUNC); return hresult; }
//+-------------------------------------------------------------------------
//
// Function: OLESTREAMToGenericObject, INTERNAL
//
// Synopsis: Reads and OLE 1.0 version of an object from an OLE 1 stream
// and stores it internally, including presentation and native
// data, in a GenericObject.
//
// Effects: Creates a GenericObject that can be written back in OLE 1
// or OLE 2 format
//
// Arguments: [pos] -- pointer to OLE 1 stream to read object from
// [pgenobj] -- pointer to generic object to read into
//
// Requires: Input stream setup and GenObj created
//
// Returns: NOERROR On success
// CONVERT10_E_OLESTREAM_FMT On unknown OLE 1 format
// CONVERT10_E_OLESTREAM_GET On stream read failue
// E_OUTOFMEMORY On stream I/O memory failure
//
// Signals: (none)
//
// Modifies: Stream position, GenObj
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 14-Feb-94 davepl Added Trace code
// davepl Cleaned up and documented
// davepl Rerouted errors through central return
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(OLESTREAMToGenericObject)
static INTERNAL OLESTREAMToGenericObject ( LPOLESTREAM pos, PGENOBJ pgenobj ) { HRESULT error = NOERROR; ULONG ulFmtId; LPOLESTR szClass = NULL;
// Read OLE Version # from the stream and discard it
if (FAILED(error = OLE1StreamToUL(pos, NULL))) { LEDebugOut(( DEB_ERROR, "Unable to read OLE ver# from stream at line %d in %s\n", __LINE__, __FILE__)); goto errRtn; }
// Get Format ID from the stream
if (FAILED(error = OLE1StreamToUL(pos, &ulFmtId))) { LEDebugOut(( DEB_ERROR, "Unable to read format ID from stream at line %d in %s\n", __LINE__, __FILE__)); goto errRtn; }
// If this is a static object, read it into the generic object and return
if (ulFmtId == FMTID_STATIC) { if (FAILED(error = GetStaticObject (pos, pgenobj))) { LEDebugOut(( DEB_ERROR, "Unable to read static object at line %d in %s\n", __LINE__, __FILE__)); } goto errRtn; }
// If this is neither a linked nor an embedded object, something
// is wrong
if (ulFmtId != FMTID_LINK && ulFmtId != FMTID_EMBED) { LEDebugOut(( DEB_ERROR, "Object is neither linked nor embedded at line %d in %s\n", __LINE__, __FILE__));
error = ResultFromScode(CONVERT10_E_OLESTREAM_FMT); goto errRtn; }
// If this is a linked object, set our flag in GenericObject
if (FMTID_LINK == ulFmtId) { pgenobj->m_fLink = TRUE; }
// Read the class name from the stream
if (FAILED(error = OLE1StmToString(pos, &szClass))) { LEDebugOut(( DEB_ERROR, "Unable to read the class name from stream at line %d in %s\n", __LINE__, __FILE__));
goto errRtn; } if (NULL == szClass) { LEDebugOut(( DEB_ERROR, "Class name was returned NULL at line %d in %s\n", __LINE__, __FILE__));
error = CONVERT10_E_OLESTREAM_FMT; goto errRtn; }
// If this is an embedded object, set the class ID and class string
// If it is a linked object, set the class name but set the class ID
// to CLSID_StdOleLink
if (FMTID_EMBED == ulFmtId) { pgenobj->m_class.SetSz (szClass); } else { Assert (ulFmtId == FMTID_LINK); pgenobj->m_classLast.SetSz (szClass); pgenobj->m_class.Set (CLSID_StdOleLink, NULL); }
// Read the Topic string from the stream
if (FAILED(error = OLE1StmToString(pos, &(pgenobj->m_szTopic)))) { LEDebugOut(( DEB_ERROR, "Unable to read topic string from stream at line %d in %s\n", __LINE__, __FILE__));
goto errRtn; }
// Read the Item string from the stream
if (FAILED(error = OLE1StmToString(pos, &(pgenobj->m_szItem)))) { LEDebugOut(( DEB_ERROR, "Unable to get item string from stream at line %d in %s\n", __LINE__, __FILE__));
goto errRtn; }
// If this is a linked object, set up the filename etc.
if (FMTID_LINK == ulFmtId) { LPOLESTR szUNCName = NULL;
// Read the network name from the stream
if (FAILED(error = OLE1StmToString(pos, &szUNCName))) { LEDebugOut(( DEB_ERROR, "Unable to get network name from stream at line %d in %s\n", __LINE__, __FILE__));
goto errRtn; }
// Convert a drive-letter based name to \\srv\share name
if (FAILED(error = PrependUNCName (&(pgenobj->m_szTopic), szUNCName))) { LEDebugOut(( DEB_ERROR, "Unable to convert drv ltr to UNC name at line %d in %s\n", __LINE__, __FILE__));
goto errRtn; }
// Read network type and network driver version # from stream
// (They are both shorts and we discarding them, so read a LONG)
if (FAILED(error = OLE1StreamToUL (pos, NULL))) { LEDebugOut(( DEB_ERROR, "Unable to get net type/ver from stream at line %d in %s\n", __LINE__, __FILE__));
goto errRtn; }
// Read the link-updating options from the stream. This field
// use OLE 1.0 enumeration values for the link update options
if (FAILED(error = OLE1StreamToUL(pos, &(pgenobj->m_lnkupdopt)))) { LEDebugOut(( DEB_ERROR, "Unable to read link update opts at line %d in %s\n", __LINE__, __FILE__));
goto errRtn; }
// OLE 1.0 duplicates the link update options in the highword
// of the LONG, and we don't want that, so clear the highword.
pgenobj->m_lnkupdopt &= 0x0000FFFF; } else // This path is taken to read in embedded objects
{ Assert (ulFmtId == FMTID_EMBED);
// Read and store the native data from the stream
if (FAILED(error = GetSizedDataOLE1Stm (pos, &(pgenobj->m_dataNative)))) { LEDebugOut(( DEB_ERROR, "Unable to get native data from stream at line %d in %s\n", __LINE__, __FILE__));
goto errRtn; } }
// For both linked and embedded objects, we need to read in any
// presentation data that may be present. Note that certain formats
// such as MS-Paint will not provide presentation data; this is OK
// since they can be rendered by native data alone (space saving measure)
if (FAILED(error = GetPresentationObject (pos, pgenobj))) { LEDebugOut(( DEB_ERROR, "Unable to get presentation data from stream at line %d in %s\n", __LINE__, __FILE__));
goto errRtn; }
errRtn:
LEDebugOut((DEB_ITRACE, "%p OUT OLESTREAMToGenericObject ( %lx ) \n", NULL /*function*/, error));
return error; }
//+-------------------------------------------------------------------------
//
// Function: GetStaticObject, INTERNAL
//
// Synopsis: Reads the presentation data for a static object into the
// PPRES member of GenericObject, and sets format and class
// flags accordingly
//
// Effects:
//
// Arguments: [pos] -- stream we are reading OLE 1 object from
// [pgenobj] -- GenericObject we are reading into
// Requires:
//
// Returns: NOERROR On success
// CONVERT10_E_OLESTREAM_FMT On unknown OLE 1 format
// CONVERT10_E_OLESTREAM_GET On stream read failue
// E_OUTOFMEMORY On stream I/O memory failure
//
// Signals: (none)
//
// Modifies: Stream position, GenericObject
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 14-Feb-94 davepl Cleanup and documentation
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL GetStaticObject (LPOLESTREAM pos, PGENOBJ pgenobj) { HRESULT error;
// Read the presentation data, standard or generic, into the
// PPRES member of the GenericObject
if (FAILED(error = GetPresentationObject(pos, pgenobj, TRUE))) { return ResultFromScode(error); }
// Ensure that the format tag is a clipboard format
if (ftagClipFormat != pgenobj->m_ppres->m_format.m_ftag) { return ResultFromScode(CONVERT10_E_OLESTREAM_FMT); }
// If the clipboard format is a METAFILEPIC, set the CLASS
// member of GenericObject to CLSID_StaticMetafile
if (CF_METAFILEPICT == pgenobj->m_ppres->m_format.m_cf) { pgenobj->m_class.Set (CLSID_StaticMetafile, NULL); }
// Otherwise, check to see if it is a DIB, and set the CLASS
// member accordingly
else if (CF_DIB == pgenobj->m_ppres->m_format.m_cf) { pgenobj->m_class.Set (CLSID_StaticDib, NULL); }
// If it is neither a METAFILEPIC nor a DIB, we have a problem
else { AssertSz (0, "1.0 static object not in one of 3 standard formats"); return ResultFromScode (CONVERT10_E_OLESTREAM_FMT); }
// Flag the GenericObject as Static
pgenobj->m_fStatic = TRUE; return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: CreateBlankPres, INTERNAL
//
// Synopsis: Sets up the format in the PPRES struct as ClipFormat 0
//
// History: dd-mmm-yy Author Comment
// 16-Feb-94 davepl Cleaned up
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL CreateBlankPres(PPRES ppres) { Assert (ppres); ppres->m_format.m_ftag = ftagClipFormat; ppres->m_format.m_cf = 0; return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: GetPresentationObject, INTERNAL
//
// Synopsis: Reads the presentation data into the CGenericObject object
//
// Arguments: [pos] -- OLE 1 stream we are reading from
// [pgenobj] -- Generic object we are reading to
// [fStatic] -- Flag: getting a static pres object?
//
// Requires: stream open, object allocated
//
// Returns: CONVERT10_E_OLESTREAM_FMT unknown format id in stream
//
//
// History: dd-mmm-yy Author Comment
// 16-Feb-94 davepl Cleaned up and documented
//
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL GetPresentationObject( LPOLESTREAM pos, PGENOBJ pgenobj, BOOL fStatic) { LPOLESTR szClass = NULL; HRESULT hresult = NOERROR;
Assert (pgenobj->m_ppres==NULL);
if (TRUE != fStatic) //FALSE!
{ // Pull the OLE version number out of the stream, we don't want it
if (FAILED(hresult = OLE1StreamToUL(pos, NULL))) { return hresult; }
// Pull the OLE 1 format identifier out of the stream
ULONG ulFmtId; if (FAILED(hresult = OLE1StreamToUL (pos, &ulFmtId))) { return hresult; }
// If the format identifier is not FMTID_PRES, we've got a
// problem... unless it's 0 in which case it simply means
// that there _is no_ presentation data, ie: PBrush, Excel
if (ulFmtId != FMTID_PRES) { if (0==ulFmtId) { return NOERROR; } else { return ResultFromScode(CONVERT10_E_OLESTREAM_FMT); } } }
// Pull in the type name for the OLE1 data
if (FAILED(hresult = OLE1StmToString (pos, &szClass))) { return hresult; }
if (0==_xstrcmp (szClass, OLESTR("METAFILEPICT"))) { hresult = GetStandardPresentation (pos, pgenobj, CF_METAFILEPICT); } else if (0==_xstrcmp (szClass, OLESTR("BITMAP"))) { hresult = GetStandardPresentation (pos, pgenobj, CF_BITMAP); } else if (0==_xstrcmp (szClass, OLESTR("DIB"))) { hresult = GetStandardPresentation (pos, pgenobj, CF_DIB); } else if (0==_xstrcmp (szClass, OLESTR("ENHMETAFILE"))) { Assert (0 && "Encountered an unsupported format: ENHMETAFILE"); } else { // This is a Generic Presentation stream
#if DBG==1
Assert (!fStatic); if (_xstrcmp (pgenobj->m_fLink ? pgenobj->m_classLast.m_szClsid : pgenobj->m_class.m_szClsid, szClass)) { Assert (0 && "Class name in embedded object stream does\n" "not match class name in pres object stream"); } #endif
hresult = GetGenericPresentation (pos, pgenobj); }
if (szClass) { PubMemFree(szClass); }
return hresult; }
//+-------------------------------------------------------------------------
//
// Function: GetBitmapAsDib, INTERNAL
//
// Synopsis: Reads a bitmap from the OLE1 stream, converts it to a DIB,
// and stores it in the DATA member of CGenericObject
//
// Arguments: [pos] -- The OLE 1 stream to read from
// [pdata] -- The DATA object to read into
//
// Requires:
//
// Returns: NOERROR success
// CONVERT10_E_OLESTREAM_GET I/O error
// CONVERT10_E_OLESTREAM_BITMAP_TO_DIB conversion error
//
// History: dd-mmm-yy Author Comment
// 16-Feb-94 davepl Cleaned up and documented
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL GetBitmapAsDib(LPOLESTREAM pos, PDATA pdata) { HRESULT hresult= NOERROR; HGLOBAL hBits = NULL; HGLOBAL hDib = NULL; LPVOID pBits = NULL; WIN16BITMAP bm; HBITMAP hBitmap = NULL; ULONG cbBits; ULONG ul;
Assert (pdata->m_h==NULL && pdata->m_pv==NULL && pdata->m_cbSize==0);
// Get size of all bitmap data, including the bitmap header struct
if (FAILED(hresult = OLE1StreamToUL(pos, &ul))) { return hresult; }
// Read the bitmap header structure. Since this was stored as Win16
// BITMAP, we have to pull a structure of that size from the stream
// (A Win32 BITMAP uses LONGs and hence is larger).
if (pos->lpstbl->Get (pos, &bm, sizeof(WIN16BITMAP)) < sizeof(WIN16BITMAP)) { return ResultFromScode (CONVERT10_E_OLESTREAM_GET); }
// The bitmap data is total size - header size
// Allocate enough memory to hold the bitmap data
cbBits = ul - sizeof(WIN16BITMAP); hBits = GlobalAlloc (GMEM_MOVEABLE, cbBits); if (NULL == hBits) { hresult = ResultFromScode(E_OUTOFMEMORY); goto errRtn; }
pBits = (void FAR*) GlobalLock (hBits); if (pBits == NULL) { hresult = ResultFromScode(E_OUTOFMEMORY); goto errRtn; }
// Read the header data into our allocated buffer
if (pos->lpstbl->Get (pos, pBits, cbBits) < cbBits) { hresult = ResultFromScode (CONVERT10_E_OLESTREAM_GET); goto errRtn; }
// Turn that raw data into a bitmap
hBitmap = CreateBitmap (bm.bmWidth, bm.bmHeight, bm.bmPlanes, bm.bmBitsPixel, pBits);
if (NULL == hBitmap) { hresult = ResultFromScode(CONVERT10_E_OLESTREAM_BITMAP_TO_DIB); goto errRtn; }
// NOTE: The following call gave only the first parameter in the
// (davepl) original source; The second is the palette handle, which
// I've passed as NULL to indicate the default stock palette.
hDib = UtConvertBitmapToDib (hBitmap, NULL); if (NULL == hDib) { hresult = ResultFromScode(CONVERT10_E_OLESTREAM_BITMAP_TO_DIB); goto errRtn; }
// Set the presentation data pointers to point to this new DIB
pdata->m_pv = GlobalLock (hDib); if (NULL == pdata->m_pv) { hresult = ResultFromScode(E_OUTOFMEMORY); goto errRtn; }
pdata->m_cbSize = (ULONG) GlobalSize (hDib); pdata->m_h = hDib;
// Free up allocations and resources, return result
errRtn:
if (pBits) { Verify (0==GlobalUnlock (hBits)); } if (hBits) { Verify (0==GlobalFree (hBits)); } if (hBitmap) { Verify (DeleteObject (hBitmap)); } return hresult; }
//+-------------------------------------------------------------------------
//
// Function: GetMfBits, INTERNAL
//
// Synopsis: Strips the METAFILE header from the stream and then reads
// the metafile bits into an allocated memory area; the
// presentation data member of [pos] is then set to point
// to this memory.
//
// Arguments: [pos] -- the OLE 1 stream to read from
// [pdata] -- the presentation data member of generic object
//
// Returns: NOERROR success
// CONVERT10_E_OLESTREAM_GET stream error
// E_OUTOFMEMORY allocation failure
//
// History: dd-mmm-yy Author Comment
// 16-Feb-94 davepl Cleaned up and documented
//
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL GetMfBits(LPOLESTREAM pos, PDATA pdata) { ULONG cbSize; WIN16METAFILEPICT mfpictDummy; HRESULT hresult = NOERROR;
Assert (0==pdata->m_cbSize && pdata->m_h==NULL && NULL==pdata->m_pv);
// Read the data size from the stream
if (FAILED(hresult = (OLE1StreamToUL (pos, &cbSize)))) { return hresult; }
// Now read the actual data
if (cbSize <= sizeof(WIN16METAFILEPICT)) { return ResultFromScode(CONVERT10_E_OLESTREAM_FMT); }
// An OLESTREAM contains a METAFILEPICT structure (with a meaningless
// handle) followed by the metafile bits. So consume the METAFILEPICT.
if (pos->lpstbl->Get (pos, &mfpictDummy, sizeof(WIN16METAFILEPICT)) < sizeof(WIN16METAFILEPICT)) { return ResultFromScode(CONVERT10_E_OLESTREAM_GET); }
// Deduct from our count of bytes to read the size of the header which
// we just consumed. Set the presentation data size to be this new size.
cbSize -= sizeof(WIN16METAFILEPICT); pdata->m_cbSize = cbSize;
// Grad some memory to store the metafile bits
pdata->m_h = GlobalAlloc (GMEM_MOVEABLE, cbSize); if (NULL==pdata->m_h) { return ResultFromScode(E_OUTOFMEMORY); }
pdata->m_pv = GlobalLock (pdata->m_h); if (NULL==pdata->m_pv) { return ResultFromScode(E_OUTOFMEMORY); } // Get the actual metafile bits
if (pos->lpstbl->Get (pos, pdata->m_pv, cbSize) < cbSize) { return ResultFromScode(CONVERT10_E_OLESTREAM_GET); }
return hresult; }
//+-------------------------------------------------------------------------
//
// Function: GetStandardPresentation, INTERNAL
//
// Synopsis: Allocates a PRES member for generic object, then reads
// whatever presentation may be found in the stream into
// that PRES.
//
// Arguments: [pos] -- the OLE 1 stream to read from
// [pgenobj] -- the generic object we are going to set
// up with the presentation data
// [cf] -- the clipboad format we are to read
//
// Returns: NOERROR success
// E_OUTOFMEMORY allocation failure
//
// Modifies: [pgenobj] - sets up the m_ppres member
//
// History: dd-mmm-yy Author Comment
// 16-Feb-94 davepl Cleaned up and documented
//
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL GetStandardPresentation( LPOLESTREAM pos, PGENOBJ pgenobj, CLIPFORMAT cf) { HRESULT hresult = NOERROR;
// Allocate enough memory for the PRES object
pgenobj->m_ppres = new PRES; if (NULL == pgenobj->m_ppres) { return ResultFromScode(E_OUTOFMEMORY); }
// Set up the format tag and clipboard format
pgenobj->m_ppres->m_format.m_ftag = ftagClipFormat; pgenobj->m_ppres->m_format.m_cf = cf;
// Get the width of the data from the stream
if (FAILED(hresult = OLE1StreamToUL(pos, &(pgenobj->m_ppres->m_ulWidth)))) { return hresult; } // Get the height of the data from the stream
if (FAILED(hresult=OLE1StreamToUL(pos, &(pgenobj->m_ppres->m_ulHeight)))) { return hresult; }
// The height saved by OLE 1.0 objects into the stream is always a
// negative value (Y-increase in pixel is negative upward?) so we
// have to correct that value.
pgenobj->m_ppres->m_ulHeight = (ULONG) -((LONG) pgenobj->m_ppres->m_ulHeight);
// Read the appropriate presentation data based on the clipboard
// format ID
switch(cf) { case CF_METAFILEPICT: { hresult = GetMfBits (pos, &(pgenobj->m_ppres->m_data)); break; }
case CF_BITMAP: { // When reading a bitmap, we will convert from Bitmap to
// DIB in the process, so update the PRES clipboard format ID
pgenobj->m_ppres->m_format.m_cf = CF_DIB; hresult = GetBitmapAsDib (pos, &(pgenobj->m_ppres->m_data)); break; }
case CF_DIB: { Assert (CF_DIB==cf); hresult = GetSizedDataOLE1Stm (pos, &(pgenobj->m_ppres->m_data)); break; }
default: { Assert(0 && "Unexpected clipboard format reading PRES"); } }
return hresult; }
//+-------------------------------------------------------------------------
//
// Function: GetGenericPresentation, INTERNAL
//
// Synopsis: Allocated the PRES member of the generic object and reads
// the generic presentation data into it.
//
// Effects: If the format is a known clipboard format, we set the
// format tag to indicate this, and set the format type
// to indicate the clipboard format type. If it is unknown,
// we set the format tag to string and read the description
// of the format.
//
// Arguments: [pos] -- the OLE 1 stream we are reading from
// [pgenobj] -- the generic object we are reading to
//
// Returns: NOERROR on success
// E_OUTOFMEMORY on allocation failure
//
// History: dd-mmm-yy Author Comment
// 16-Feb-94 davepl Code cleanup and document
//
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL GetGenericPresentation( LPOLESTREAM pos, PGENOBJ pgenobj) { ULONG ulClipFormat; HRESULT hresult = NOERROR;
// The PRES member should not exist at this point
Assert (NULL==pgenobj->m_ppres);
// Allocate the PRES member of the generic object
pgenobj->m_ppres = new PRES; if (NULL == pgenobj->m_ppres) { return ResultFromScode(E_OUTOFMEMORY); }
// Read the clipboard format ID
if (FAILED(hresult = OLE1StreamToUL (pos, &ulClipFormat))) { delete (pgenobj->m_ppres); return hresult; }
// If the clipboard format is not 0, we have a known clipboard
// format and we should set the tag type and ID accordingly
if (ulClipFormat) { pgenobj->m_ppres->m_format.m_ftag = ftagClipFormat; pgenobj->m_ppres->m_format.m_cf = (CLIPFORMAT) ulClipFormat; } else { // Otherwise, we have a custom format so we need to set the
// tag type to string and read in the data format string
pgenobj->m_ppres->m_format.m_ftag = ftagString; if (FAILED(hresult = (GetSizedDataOLE1Stm (pos, &(pgenobj->m_ppres->m_format.m_dataFormatString))))) { delete (pgenobj->m_ppres); return hresult; } }
// We don't know the size, so reset to 0
pgenobj->m_ppres->m_ulHeight = 0; pgenobj->m_ppres->m_ulWidth = 0;
// Read the raw generic presentation data into the PRES member
if (FAILED(hresult=GetSizedDataOLE1Stm(pos,&(pgenobj->m_ppres->m_data)))) { delete (pgenobj->m_ppres); return hresult; }
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: GetSizedDataOLE1Stm, INTERNAL
//
// Synopsis: Reads bytes from an OLE 1 stream into a CData object.
// Obtains the number of bytes to read from the first
// ULONG in the stream
//
// Arguments: [pos] -- the stream to read from
// [pdata] -- the CData object to read to
//
// Requires:
//
// Returns: NOERROR on success
// CONVERT10_E_OLESTREAM_GET on stream read problem
// E_OUTOFMEMORY on allocation failure
//
// History: dd-mmm-yy Author Comment
// 16-Feb-94 davepl Cleaned up and documented
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL GetSizedDataOLE1Stm(LPOLESTREAM pos, PDATA pdata) { ULONG cbSize; HRESULT hr; Assert (0==pdata->m_cbSize && pdata->m_h==NULL && NULL==pdata->m_pv);
// Read size of data
if (FAILED(hr = OLE1StreamToUL(pos, &cbSize))) { return hr; }
if (cbSize==0) { return NOERROR; }
// Allocate memory for data
pdata->m_cbSize = cbSize;
pdata->m_h = GlobalAlloc (GMEM_MOVEABLE, cbSize); if (NULL==pdata->m_h) { return ResultFromScode(E_OUTOFMEMORY); } pdata->m_pv = GlobalLock (pdata->m_h);
if (NULL==pdata->m_pv) { return ResultFromScode(E_OUTOFMEMORY); }
// Read data into allocated buffer
if (pos->lpstbl->Get (pos, pdata->m_pv, cbSize) < cbSize) { return ResultFromScode(CONVERT10_E_OLESTREAM_GET); }
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: OLE1StreamToUL, INTERNAL
//
// Synopsis: Reads a ULONG from an OLE1 stream
//
// Arguments: [pos] -- the OLE 1 stream to read from
// [pul] -- the ULONG to read into
//
// Returns: NOERROR on success
// CONVERT10_E_OLESTREAM_GET on stream read failure
//
// History: dd-mmm-yy Author Comment
// 16-Feb-94 davepl Cleaned up and documented
//
// Notes: on failure [pul] is preserved
//
//--------------------------------------------------------------------------
static INTERNAL OLE1StreamToUL(LPOLESTREAM pos, ULONG FAR* pul) { ULONG ul;
// Read the data from the stream into the local ULONG
if (pos->lpstbl->Get (pos, &ul, sizeof(ULONG)) < sizeof(ULONG)) { return ResultFromScode(CONVERT10_E_OLESTREAM_GET); }
// If all went well, store the data into [pul]
if (pul != NULL) { Assert (IsValidPtrOut (pul, sizeof(ULONG))); *pul = ul; } return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: DataToOLE1Stm, INTERNAL INLINE
//
// Synopsis: Writes raw data out to an OLE 1 stream
//
// Arguments: [pos] -- the stream to write to
// [pvBuf] -- the buffer to write from
// [ulSize] -- the number of bytes to write
//
// Returns: NOERROR on success
// CONVERT10_E_OLESTREAM_PUT on stream write failure
//
// History: dd-mmm-yy Author Comment
// 16-Feb-94 davepl Cleaned up and documented
// Notes:
//
//--------------------------------------------------------------------------
inline static INTERNAL DataToOLE1Stm(LPOLESTREAM pos, LPVOID pvBuf, ULONG ulSize) { // Write the data out to the stream
if (pos->lpstbl->Put(pos, pvBuf, ulSize) < ulSize) { return ResultFromScode(CONVERT10_E_OLESTREAM_PUT); } return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: ULToOLE1Stream, INTERNAL INLINE
//
// Synopsis: Write a ULONG to the specified OLESTREAM via the Put()
// member of the stream's VTBL
//
// Effects: Advances stream position by sizeof(ULONG) on success.
//
// Arguments: [pos] -- The stream into which the ULONG is written
// [ul] -- The ULONG, passed by value
//
// Requires:
//
// Returns: NOERROR on success
// CONVERT10_E_OLESTREAM_PUT on failure
//
// Signals: (none)
//
// Modifies: Stream position
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 11-Jan-93 davepl Cleaned up and documented
//
// Notes: On failure 0-3 bytes may have been written
//
//--------------------------------------------------------------------------
inline static INTERNAL ULToOLE1Stream(LPOLESTREAM pos, ULONG ul) { if (pos->lpstbl->Put (pos, &ul, sizeof(ULONG)) < sizeof(ULONG)) { return ResultFromScode(CONVERT10_E_OLESTREAM_PUT); } return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: StringToOLE1Stm, INTERNAL
//
// Synopsis: Converts the input OLESTR to ANSI and writes it to an
// OLE 1 stream, preceded by a ULONG indicating the number
// of bytes in the ANSI representation (terminator included).
//
// Arguments: [pos] -- The stream into which the ULONG is written
// [szOleStr] -- The STR to be written
//
// Returns: NOERROR on success
// CONVERT10_E_OLESTREAM_PUT on stream write failure
// E_NOMEMORY on allocation failure
//
// Modifies: Stream position
//
// History: dd-mmm-yy Author Comment
// 11-Feb-94 davepl Cleaned up and documented
// 15-Feb-94 davepl Re-write for ANSI/WCHAR handling
// 17-Feb-94 davepl Restructured error handling
//
// Notes: On failure, 0 to (cbSize-1) bytes may have been written
//
//--------------------------------------------------------------------------
static INTERNAL StringToOLE1Stm(LPOLESTREAM pos, LPCOLESTR pszOleStr) { HRESULT hr = NOERROR; LPSTR pszAnsi = NULL; // Ansi version of OLE input string
if (pszOleStr) { // This handy function will calculate the size of the buffer we
// need to represent the OLESTR in ANSI format for us.
ULONG cbSize = WideCharToMultiByte(CP_ACP, // Code Page ANSI
0, // No flags
pszOleStr, // Input OLESTR
-1, // Input len (auto detect)
NULL, // Output buffer
0, // Output len (check only)
NULL, // Default char
NULL);// Flag: Default char used
if (cbSize == FALSE) { return ResultFromScode(E_UNSPEC); }
// Now that we know the actual needed length, allocate a buffer
pszAnsi = (LPSTR) PrivMemAlloc(cbSize); if (NULL == pszAnsi) { return ResultFromScode(E_OUTOFMEMORY); }
// We've got out buffer and our length, so do the conversion now
// We don't need to check for cbSize == FALSE since that was
// already done during the length test, but we need to check
// for substitution. Iff this call sets the fDefChar even when
// only doing a length check, these two tests could be merged,
// but I don't believe this is the case.
BOOL fDefUsed = 0; cbSize = WideCharToMultiByte(CP_ACP, // Code Page ANSI
0, // No flags
pszOleStr, // Input OLESTR
-1, // Input len (auto detect)
pszAnsi, // Output buffer
cbSize, // Output len
NULL, // Default char (use system's)
&fDefUsed); // Flag: Default char used
// If number of bytes converted was 0, we failed
if (fDefUsed) { hr = ResultFromScode(E_UNSPEC); }
// Write the size of the string (including null terminator) to stream
else if (FAILED(hr = ULToOLE1Stream(pos, cbSize))) { NULL; }
// Write the Ansi version of the string into the stream
else if (pos->lpstbl->Put(pos, pszAnsi, cbSize) < cbSize) { hr = ResultFromScode(CONVERT10_E_OLESTREAM_PUT); }
if (pszAnsi) { PrivMemFree(pszAnsi); } }
// If the pointer is not valid, we write a length of zero into
// the stream
else { hr = ULToOLE1Stream(pos, 0); }
return hr; }
//+-------------------------------------------------------------------------
//
// Function: OLE2StmToUL, INTERNAL
//
// Synopsis: Reads a ULONG from the specified ISTREAM and stores it at
// the ULONG deferenced by pul
//
// Effects: Writes the value read into memory at pul
//
// Arguments: [pstm] -- The stream from which the ULONG is read
// [pul] -- ULONG to hold the value read
//
// Requires:
//
// Returns: NOERROR on success
// CONVERT10_E_OLESTREAM_PUT on failure
//
// Signals: (none)
//
// Modifies: Stream position
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 11-Feb-93 davepl Cleaned up and documented
//
// Notes: On failure, *pul is not disturbed regardless of how
// many bytes were actually read from the stream
//
//--------------------------------------------------------------------------
static INTERNAL OLE2StmToUL(LPSTREAM pstm, ULONG FAR* pul) { ULONG ul; ULONG cbRead; HRESULT hr = NOERROR;
// Attempt to read 4 bytes from the stream to form a ULONG.
if (FAILED(hr = pstm->Read (&ul, sizeof(ULONG), &cbRead))) { return hr; }
if (cbRead != sizeof(ULONG)) { hr = STG_E_READFAULT; } // Ensure that the [pul] pointer is valid and that we have write
// access to all 4 bytes (assertion only). If OK, transfer the
// ULONG to [*pul]
else if (pul != NULL) { Assert (FALSE == !IsValidPtrOut(pul, sizeof(ULONG))); *pul = ul; } return hr; }
//+-------------------------------------------------------------------------
//
// Function: OLE1StmToString, INTERNAL
//
// Synopsis: Reads a cstr from the specified STREAM and stores it in
// a dynamically allocated buffer as an OLESTR; sets the
// user's pointer to point to this new buffer.
//
// Effects: Allocates memory on the input pointer, advances stream pos'n
//
// Arguments: [pos ] -- The stream from which the STR is read
// [ppsz] -- OLESTR ** which allows this fn to modify the
// caller's pointer to point to memory allocated
// by this fn to hold the OLESTR
//
// Requires: Stream must be set up. Caller's responsibilty to free memory.
//
// Returns: NOERROR on success
// CONVERT10_E_OLESTREAM_GET on failure
// E_OUTOFMEMORY if buffers couldn't be allocated
//
// Signals: (none)
//
// Modifies: Stream position, caller's string pointer
//
// Algorithm: if ppsz == NULL, string is read from stream and discarded
// if ppsz != NULL, string is read and converted into a
// dynamically allocated buffer. *ppsz is set
// to point to this buffer, which must be later
// freed by the caller
//
// History: dd-mmm-yy Author Comment
// 12-Jan-93 davepl Cleaned up and documented
// 14-Jan-93 davepl Changed to return LPOLESTR
//
// Notes: [ppsz] may be NULL on entry; string is read and discarded
// with no cleanup required by the caller
//
//
//--------------------------------------------------------------------------
static INTERNAL OLE1StmToString(LPOLESTREAM pos, LPOLESTR FAR* ppsz) { ULONG cbSize; // Size in bytes of cstr
LPOLESTR pszOleStr = NULL; LPSTR pszAnsiStr = NULL; HRESULT error = NOERROR;
// if ppsz is valid, NULL out *ppsz as default out parameter
if (NULL != ppsz) { *ppsz = NULL; }
// Retrieve the incoming string size from the stream
if (FAILED(error = OLE1StreamToUL (pos, &cbSize))) { goto errRtn; }
// If there are chars to be read, allocate memory for the
// ANSI and OLESTR versions. Read the string into the
// ANSI version and convert it to OLESTR
if (0 < cbSize) { // Allocate the ANSI buffer
pszAnsiStr = (LPSTR) PrivMemAlloc((size_t)cbSize); if (NULL == pszAnsiStr) { error = ResultFromScode(E_OUTOFMEMORY); goto errRtn; }
// Read the string into the ANSI buffer
if (pos->lpstbl->Get (pos, pszAnsiStr, cbSize) < cbSize) { error = ResultFromScode(CONVERT10_E_OLESTREAM_GET); goto errRtn; }
// We only need to perform the ANSI->OLESTR conversion in those
// cases where the caller needs an out parameter
if (NULL != ppsz) { // Allocate the OLESTR buffer
pszOleStr = (LPOLESTR) PubMemAlloc((size_t)cbSize * 2); if (NULL == pszOleStr) { error = ResultFromScode(E_OUTOFMEMORY); goto errRtn; }
// Convert from ANSI buffer to OLESTR buffer
if (FALSE==MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszAnsiStr, cbSize, pszOleStr, cbSize *2)) { error = HRESULT_FROM_WIN32(ERROR_NO_UNICODE_TRANSLATION); PubMemFree(pszOleStr); goto errRtn; } *ppsz = pszOleStr; } }
errRtn:
if (pszAnsiStr) { PrivMemFree(pszAnsiStr); }
return error;
}
//+-------------------------------------------------------------------------
//
// Function: GenericObjectToIStorage
//
// Synopsis: Write the generic object in memory out to an OLE 2 IStorage
// This invovles writing the class, native data, and
// presentation data out where applicable.
//
// Arguments: [genobj] -- the generic object holding the info
// [pstg] -- the IStorage object to write to
// [ptd] -- target device
//
// Returns: NOERROR on success
// CONVERT10_S_NO_PRESENTATION in cases where the object did
// not have needed presentation data
//
// History: dd-mmm-yy Author Comment
// 17-Feb-94 davepl Cleanup and document
//
// Notes:
//
//--------------------------------------------------------------------------
FARINTERNAL GenericObjectToIStorage( const GENOBJ FAR& genobj, LPSTORAGE pstg, const DVTARGETDEVICE FAR* ptd) { HRESULT hr = NOERROR;
// Assert (genobj.m_class.m_clsid != CLSID_NULL);
// Write the class ID out to the storage
if (FAILED(hr = WriteClassStg (pstg, genobj.m_class.m_clsid))) { LEDebugOut(( DEB_ERROR, "Unable to WriteClassStg at line %d in %s\n", __LINE__, __FILE__));
return hr; }
if (!genobj.m_fLink) { if (genobj.m_fStatic) { // If we are a static embedded object, get the format name from
// the registration database and write it out to the IStorage
LPOLESTR pszUserType = NULL;
OleRegGetUserType(genobj.m_class.m_clsid, USERCLASSTYPE_FULL, &pszUserType);
WriteFmtUserTypeStg (pstg, genobj.m_ppres->m_format.m_cf, pszUserType);
if (pszUserType) { PubMemFree(pszUserType); } } else if (wWriteFmtUserType (pstg, genobj.m_class.m_clsid) != NOERROR) { // This happens when the class is not registered.
// Use ProgId as UserType.
WriteFmtUserTypeStg (pstg, (CLIPFORMAT) RegisterClipboardFormat (genobj.m_class.m_szClsid), genobj.m_class.m_szClsid); } }
if (FAILED(hr = GenObjToOLE2Stm (pstg, genobj))) { LEDebugOut(( DEB_ERROR, "Unable to write gen obj to stream at line %d in %s\n", __LINE__, __FILE__));
return hr; }
// If it's not a link and not a static object, dump its native
// data out to the storage
if (!genobj.m_fLink && !genobj.m_fStatic) { if (FAILED(hr=Write20NativeStreams (pstg, genobj))) { LEDebugOut(( DEB_ERROR, "Unable to write native stream at line %d in %s\n", __LINE__, __FILE__));
return hr; } }
if (! genobj.m_fLink) { if (genobj.m_class.m_clsid == CLSID_PBrush) { if (! genobj.m_ppres || (genobj.m_ppres->m_format.m_cf == CF_DIB)) { // If the object is not a link, and it is a PBrush object with
// either a DIB presentation or no presentation at all, we
// don't need to do anything.
return NOERROR; } }
if (genobj.m_class.m_clsid == CLSID_MSDraw) { if (! genobj.m_ppres || (genobj.m_ppres->m_format.m_cf == CF_METAFILEPICT)) { // Similarly, if it is not a link, and it is an MSDraw object
// with no presentation or a METAFILEPICT presentation, we
// don't need to do anything.
return NOERROR; } } }
// In all other cases, we have to dump the presenation data out to
// the storage.
if (FAILED(hr = PresToIStorage (pstg, genobj, ptd))) { LEDebugOut(( DEB_ERROR, "Unable to write pres to IStorage at line %d in %s\n", __LINE__, __FILE__));
return hr; }
// If we are a static object, copy the contents of the presentation
// stream over to the contents stream.
if (genobj.m_fStatic) { UINT uiStatus; return UtOlePresStmToContentsStm(pstg, OLE_PRESENTATION_STREAM, TRUE, &uiStatus); }
// If we don't have a presentation (but weren't one of the special
// cases handled above), we have a problem
//
// We don't care if genobj.m_pres is NULL if a blank presentation is
// permited as the routine PresToIStorage will generate a blank pres.
//
if ((NULL == genobj.m_ppres) && genobj.m_fNoBlankPres) { LEDebugOut(( DEB_ERROR, "We have no presentation at line %d in %s\n", __LINE__, __FILE__));
return ResultFromScode(CONVERT10_S_NO_PRESENTATION); }
return NOERROR;
}
//+-------------------------------------------------------------------------
//
// Function: GenObjToOLE2Stm, INTERNAL
//
// Synopsis: Write the generic object out to the OLE 2 stream
//
// Effects: Write the whole object, including presentation data, etc.
//
// Arguments: [pstg] -- the IStorage to write to
// [genobj] -- the generic object to write
//
// Returns: NOERROR on success
// This is an upper level function, so there are numerous
// error that could be propagated up through it
//
// History: dd-mmm-yy Author Comment
// 14-Feb-94 davepl Code cleanup and document
//
// Notes: The code is enclosed in a do{}while(FALSE) block so that
// we can break out of it on any error and fall through to
// the cleanup and error return code.
//
//--------------------------------------------------------------------------
static INTERNAL GenObjToOLE2Stm(LPSTORAGE pstg, const GENOBJ FAR& genobj) { HRESULT hr = NOERROR; LPSTREAM pstm=NULL;
do { // The do{}while(FALSE) allows us to break out on error
// Create a stream in the current IStorage
if (FAILED(hr = OpenOrCreateStream (pstg, OLE_STREAM, &pstm))) { LEDebugOut(( DEB_ERROR, "Can't create streamat line %d in %s\n", __LINE__, __FILE__));
break; }
// Write the Ole version out to that new stream
if (FAILED(hr = ULToOLE2Stm (pstm, gdwOleVersion))) { break; } // Write the object flags (for links only, otherwise 0) to the stream
if (FAILED(hr = ULToOLE2Stm (pstm, genobj.m_fLink ? OBJFLAGS_LINK : 0L))) { break; }
// Write the update options out to the stream
if (genobj.m_fLink || genobj.m_class.m_clsid == CLSID_StdOleLink) { // If our object's link update options are UPDATE_ONCALL, we
// write out the corresponding OLE 2 flags, otherwise, we
// write out OLEUPDATE_ALWAYS
if (genobj.m_lnkupdopt==UPDATE_ONCALL) { if (FAILED(hr = ULToOLE2Stm (pstm, OLEUPDATE_ONCALL))) { break; } } else { if (FAILED(hr = ULToOLE2Stm (pstm, OLEUPDATE_ALWAYS))) { break; } }
} else { // We are neither a link nor a StdOleLink, so we have no
// update options.. just write out a 0.
if (FAILED(hr = ULToOLE2Stm (pstm, 0L))) { break; } }
// This is a reserved filed (was View Format), just write a 0
if (FAILED(hr = ULToOLE2Stm (pstm, 0L))) { break; }
// We have no relative moniker, write out NULL
if (FAILED(hr = WriteMonikerStm (pstm, (LPMONIKER)NULL))) { LEDebugOut(( DEB_ERROR, "Unable to write moniker to stream at line %d in %s\n", __LINE__, __FILE__));
break; }
// If we are a link, we have to write out all of that information...
if (genobj.m_fLink || genobj.m_class.m_clsid == CLSID_StdOleLink) { // relative source moniker
if (FAILED(hr = WriteMonikerStm (pstm, (LPMONIKER)NULL))) { LEDebugOut(( DEB_ERROR, "Unable to write moniker to stream at line %d in %s\n", __LINE__, __FILE__)); break; }
// absolute source moniker
if (FAILED(hr = MonikerToOLE2Stm (pstm, genobj.m_szTopic, genobj.m_szItem, genobj.m_classLast.m_clsid))) { LEDebugOut(( DEB_ERROR, "Unable to write moniker to stream at line %d in %s\n", __LINE__, __FILE__)); break; }
// write the classLast field to the stream
CLSID clsid;
// If we have the classLast already, use that clsid
if (genobj.m_classLast.m_szClsid) { clsid = genobj.m_classLast.m_clsid; } else { // Otherwise, if it's a StdOleLink, class id is NULL
if (genobj.m_class.m_clsid == CLSID_StdOleLink) { clsid = CLSID_NULL; } else { // If we don't have last class and not a link, use the
// class id of the generic object
clsid = genobj.m_class.m_clsid; } }
if (FAILED(hr = WriteM1ClassStm(pstm, clsid))) { LEDebugOut(( DEB_ERROR, "Unable to write M1 to stream at line %d in %s\n", __LINE__, __FILE__)); break; }
// last display == NULL string
if (FAILED(hr = ULToOLE2Stm (pstm, 0L))) { break; }
// Last Change time
if (FAILED(hr = FTToOle2Stm (pstm))) { break; }
// Last known up to date
if (FAILED(hr = FTToOle2Stm (pstm))) { break; }
// rtUpdate
if (FAILED(hr = FTToOle2Stm (pstm))) { break; }
// end marker
if (FAILED(hr = ULToOLE2Stm(pstm, (ULONG) -1L))) { break; } }
} while (FALSE); // This do{}while(FALSE) is a once-through "loop"
// that we can break out of on error and fall
// through to the return.
if (pstm) { pstm->Release(); }
return hr; }
//+-------------------------------------------------------------------------
//
// Function: MonikerToOLE2Stm, INTERNAL
//
// Synopsis: Write the file and item moniker as a composite to the stream
//
// Effects: Builds a composite of the file and item monikers, and then
// writes them out. If there is no file, a NULL moniker is
// written in its place
//
// Arguments: [pstm] -- The OLE2 storage we are writing to
// [pszFile] -- The file associated with the object
// [spzItem] -- The item
// [clsid] -- The class ID of the object
//
// Returns: NOERROR on success
//
// History: dd-mmm-yy Author Comment
// 18-Feb-94 davepl Reworked, cleaned up and documented
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(MonikerToOLE2Stm)
static INTERNAL MonikerToOLE2Stm( LPSTREAM pstm, LPOLESTR szFile, LPOLESTR szItem, CLSID clsid) // CLSID of the link source file, szFile
{ HRESULT hr = NOERROR; LPMONIKER pmkFile = NULL; // File moniker
LPMONIKER pmkItem = NULL; // Item moniker
LPMONIKER pmkComp = NULL; // Composite of file + item monikers
// If we don't have a file, write a NULL moniker
if (NULL == szFile) { if (FAILED(hr = WriteMonikerStm (pstm, NULL))) { goto errRtn; } } else { // Otherwise, create a file moniker (OLE1 or OLE2 as appplicable)
if (CoIsOle1Class (clsid)) { if (FAILED(hr = CreateOle1FileMoniker (szFile, clsid, &pmkFile))) { LEDebugOut(( DEB_ERROR, "Can't create OLE 1 moniker at line %d in %s\n", __LINE__, __FILE__)); goto errRtn; } } else { if (FAILED(hr = CreateFileMoniker (szFile, &pmkFile))) { LEDebugOut(( DEB_ERROR, "Can't create file moniker at line %d in %s\n", __LINE__, __FILE__)); goto errRtn; } }
// If we don't have an Item, write just the file moniker
if (NULL==szItem) { if (FAILED(hr = WriteMonikerStm (pstm, pmkFile))) { LEDebugOut(( DEB_ERROR, "Unable to write moniker to stream at line %d in %s\n", __LINE__, __FILE__)); goto errRtn; }
}
// Otherwise, create a composite of the file + item monikers
// and write it out
else { if (FAILED(hr=CreateItemMoniker(OLESTR("!"), szItem, &pmkItem))) { LEDebugOut(( DEB_ERROR, "Unable to create item moniker at line %d in %s\n", __LINE__, __FILE__)); goto errRtn; }
if (FAILED(hr=CreateGenericComposite(pmkFile, pmkItem, &pmkComp))) { LEDebugOut(( DEB_ERROR, "Unable to create generic pres at line %d in %s\n", __LINE__, __FILE__)); goto errRtn; }
if (FAILED(hr = WriteMonikerStm (pstm, pmkComp))) { LEDebugOut(( DEB_ERROR, "Unable to write moniker to stream at line %d in %s\n", __LINE__, __FILE__)); goto errRtn; } } }
errRtn: if (pmkFile) { pmkFile->Release(); } if (pmkItem) { pmkItem->Release(); } if (pmkComp) { pmkComp->Release(); } return hr; }
//+-------------------------------------------------------------------------
//
// Function: IsStandardFormat, INTERNAL
//
// Synopsis: Returns TRUE if object is in clipboard format and is one
// one of the three standard formats (METAFILE, DIB, BITMAP)
//
// Arguments: [format] -- the format object which contains the
// format tag and clipboard format type
//
// Returns: TRUE if METAFILE, DIB, or BITMAP
// FALSE if other format or not clipboard format at all
//
// History: dd-mmm-yy Author Comment
// 16-Feb-94 davepl documented and chaged from big
// conditional to a switch()
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL_(BOOL) IsStandardFormat(const FORMAT FAR& format) { // First we must ensure that the format tag indicates that this
// object is in clipboard format at all...
if (format.m_ftag == ftagClipFormat) { // If so, there is a limited set of clipboard formats which
// we consider "standard". If it is not among these,
// we return FALSE.
switch(format.m_cf) { case CF_METAFILEPICT: case CF_BITMAP: case CF_DIB:
return TRUE;
default:
return FALSE;
} } return FALSE; }
//+-------------------------------------------------------------------------
//
// Function: PresToIStorage, INTERNAL
//
// Synopsis: Given an generic object and an IStorage, write genobj's
// presentation data out to the storage
//
// Effects: Will call PresToNewOLE2Stm to create a stream in this
// storage to hold the presentation data
//
// Arguments: [pstg] -- the storage to save to
// [genobj] -- the generic object holding the presenation
// [ptd] -- the target device for the presentation
//
// Returns: NOERROR on success
// Various other errors may propagate back up from I/O funcs
//
// History: dd-mmm-yy Author Comment
// 18-Feb-94 davepl ARRGR! Cleanup and document
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL PresToIStorage( LPSTORAGE pstg, const GENOBJ FAR& genobj, const DVTARGETDEVICE FAR* ptd) { HRESULT hr = NOERROR;
if (genobj.m_fNoBlankPres) { return NOERROR; }
PRES pres;
if (NULL==genobj.m_ppres) { // If we're not a link, and we don't have a presentation, we will
// create a blank presentation and write it out. If we are a link,
// we will do nothing, and just fall through to the return.
if (!genobj.m_fLink) { if (FAILED(hr = CreateBlankPres (&pres))) { LEDebugOut(( DEB_ERROR, "Unable to create blank pres at line %d in %s\n", __LINE__, __FILE__)); return hr; }
if (FAILED(hr = PresToNewOLE2Stm (pstg, genobj.m_fLink, pres, ptd, OLE_PRESENTATION_STREAM))) { LEDebugOut(( DEB_ERROR, "Unable to write pres to new stream at line %d in %s\n", __LINE__, __FILE__)); return hr; } } } else { // If the object did indeed have a presentation, we write it
// out to a new stream
if (IsStandardFormat (genobj.m_ppres->m_format)) { // If the presentation is a standard clipboard
// format, we can write it out with no other work
if (FAILED(hr = PresToNewOLE2Stm ( pstg, genobj.m_fLink, *(genobj.m_ppres), ptd, OLE_PRESENTATION_STREAM))) { LEDebugOut(( DEB_ERROR, "Unable to write pres to new stream at line %d in %s\n", __LINE__, __FILE__));
return hr; }
} else { // If the presentation is not a standard format,
// it may be a PBrush object (handled below), or if
// not, we write it as a generic presentation stream
if (genobj.m_classLast.m_clsid != CLSID_PBrush) { if(FAILED(hr = PresToNewOLE2Stm ( pstg, genobj.m_fLink, *(genobj.m_ppres), ptd, OLE_PRESENTATION_STREAM))) { LEDebugOut(( DEB_ERROR, "Unable to write pres to new stream at line %d in %s\n", __LINE__, __FILE__));
return hr; } } else // PBrush
{ BOOL fPBrushNative = FALSE;
// We know this is a PBrush object. If the
// format tag is a format string, check to see
// if that string is "Native", in which case
// we set the flag to indicate that this is
// native pbrush data.
if (genobj.m_ppres->m_format.m_ftag == ftagString) { if (!strcmp( (LPCSTR) genobj.m_ppres-> m_format.m_dataFormatString.m_pv, "Native" ) ) { fPBrushNative = TRUE; } }
if (FAILED(hr = PresToNewOLE2Stm( pstg, genobj.m_fLink, *(genobj.m_ppres), ptd, OLE_PRESENTATION_STREAM, fPBrushNative))) { LEDebugOut(( DEB_ERROR, "Unable to write pres to new stream at line %d in %s\n", __LINE__, __FILE__));
return hr; }
}
} } return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: PresToNewOLE2Stm, INTERNAL
//
// Synopsis: Creates a new stream within a storage and writes the
// generic object's presentation data out to it.
//
// Arguments: [pstg] -- the storage in which to create the stream
// [fLink] -- flag: is this object a link?
// [pres] -- the presentation data to be saved
// [ptd] -- the target render device
// [szStream] -- the name of the new stream
// [fPBrushNative] -- flag: is this native PBrush pres data?
//
// Returns: NOERROR on success
// STG_E_WRITEFAULT on stream write failure
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleanup and documentation
//
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL PresToNewOLE2Stm( LPSTORAGE pstg, BOOL fLink, const PRES FAR& pres, const DVTARGETDEVICE FAR* ptd, LPOLESTR szStream, BOOL fPBrushNative ) { HRESULT hr = NOERROR; LPSTREAM pstm=NULL; FORMATETC foretc;
// Create the new stream to hold the presentation data
if (FAILED(hr = OpenOrCreateStream (pstg, szStream, &pstm))) { goto errRtn; }
// Fill in the FormatEtc structure
if (fPBrushNative) { foretc.cfFormat = CF_DIB; } else { switch( pres.m_format.m_ftag) { case ftagClipFormat: foretc.cfFormat = pres.m_format.m_cf; break; case ftagString: // m_dataFormatString is an ASCII string.
foretc.cfFormat = (CLIPFORMAT) SSRegisterClipboardFormatA( (LPCSTR) pres.m_format.m_dataFormatString.m_pv); Assert(0 != foretc.cfFormat); break; default: AssertSz(0,"Error in Format"); hr = E_UNEXPECTED; goto errRtn; break; } }
foretc.ptd = (DVTARGETDEVICE *) ptd; foretc.dwAspect = DVASPECT_CONTENT; foretc.lindex = -1; foretc.tymed = TYMED_NULL; // tymed field is ignored by utWriteOlePresStmHeader.
if (FAILED(hr = UtWriteOlePresStmHeader(pstm,&foretc,(fLink) ? (ADVF_PRIMEFIRST) : (0L)))) { goto errRtn; }
if (fPBrushNative) { if (FAILED(hr = UtHDIBFileToOlePresStm(pres.m_data.m_h, pstm))) { LEDebugOut(( DEB_ERROR, "Unable to write DIB to stream at line %d in %s\n", __LINE__, __FILE__));
goto errRtn; } } else { // Compression
if (FAILED(hr = ULToOLE2Stm (pstm, 0L))) { goto errRtn; }
// Width / Height
if (FAILED(hr = ULToOLE2Stm (pstm, pres.m_ulWidth))) { goto errRtn; } if (FAILED(hr = ULToOLE2Stm (pstm, pres.m_ulHeight))) { goto errRtn; }
// Presentation data
if (FAILED(hr = DataObjToOLE2Stm (pstm, pres.m_data))) { goto errRtn; } }
errRtn: if (pstm) { pstm->Release(); } return hr; }
//+-------------------------------------------------------------------------
//
// Function: ULToOLE2Stm, INTERNAL
//
// Synopsis: Writes a ULONG out to an OLE2 stream
//
// Arguments: [pstm] -- the stream to write to
// [ul] -- the ULONG to write to that stream
//
// Returns: NOERROR on success
// STG_E_WRITEFAULT on write failure
//
// History: dd-mmm-yy Author Comment
// 18-Feb-94 davepl Cleaned up and documented
//
//--------------------------------------------------------------------------
inline static INTERNAL ULToOLE2Stm(LPSTREAM pstm, ULONG ul) { // Write the ULONG out
return pstm->Write (&ul, sizeof(ULONG), NULL);
}
//+-------------------------------------------------------------------------
//
// Function: FTToOLE2Stm, INTERNAL
//
// Synopsis: Writes a dummy filetime out to an OLE2 stream
//
// Arguments: [pstm] -- the stream to write to
//
// Returns: NOERROR on success
// STG_E_WRITEFAULT on write failure
//
// History: dd-mmm-yy Author Comment
// 31-Mar-95 scottsk Created
//
//--------------------------------------------------------------------------
inline static INTERNAL FTToOle2Stm(LPSTREAM pstm) { FILETIME ft = { 0, 0 };
return pstm->Write (&ft, sizeof(FILETIME), NULL);
}
//+-------------------------------------------------------------------------
//
// Function: DataObjToOLE2Stm
//
// Synopsis: Writes a fixed-size data buffer to an OLE2 stream preceded
// by a ULONG indicating the number of bytes to follow.
//
// Returns: NOERROR on success
// STG_E_WRITEFAULT on write failure
//
// History: dd-mmm-yy Author Comment
// 18-Feb-94 davepl Code cleanup
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL DataObjToOLE2Stm(LPSTREAM pstm, const DATA FAR& data) { HRESULT hr;
// Write a ULONG indicating the number of bytes to follow
if (FAILED(hr = ULToOLE2Stm (pstm, data.m_cbSize))) { return hr; }
// If there are any bytes to follow...
if (data.m_cbSize) { if (FAILED(hr = pstm->Write (data.m_pv, data.m_cbSize, NULL))) { return hr; } } return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: SizedDataToOLE1Stm
//
// Synopsis: Writes a fixed-size data buffer to an OLE1 stream preceded
// by a ULONG indicating the number of bytes to follow.
//
// Parameters: [pos] -- The stream to write to
// [data] -- The data object to write out
//
// Returns: NOERROR on success
// STG_E_WRITEFAULT on write failure
//
// History: dd-mmm-yy Author Comment
// 18-Feb-94 davepl Code cleanup
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL SizedDataToOLE1Stm(LPOLESTREAM pos, const DATA FAR& data) { HRESULT hr = NOERROR;
// Ensure the memory we are going to write out is valid
Assert (data.m_pv);
// Write the ULONG representing the byte count of the sized data
if (FAILED(hr = ULToOLE1Stream (pos, data.m_cbSize))) { Assert (0 && "Can't write UL to ole1 stream"); return hr; }
if (pos->lpstbl->Put (pos, data.m_pv, data.m_cbSize) < data.m_cbSize) { Assert (0 && "Cant write sized data to ole1 stream"); return ResultFromScode(CONVERT10_E_OLESTREAM_PUT); } return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: Write20NativeStreams, INTERNAL
//
// Synopsis: Writes the generic object's native data out to an OLE 2 stream
//
// Effects: Creates an ILockBytes on the handle to the native data, and
// then attempts to create a storage on it. If it can, it uses
// the CopyTo interface to write that storage into our OLE 2
// stream. Otherwise, it manually creates a stream in the OLE 2
// storage and dumps the native data into it.
//
// Arguments: [pstg] -- the OLE 2 storage we are saving genobj to
// [genobj] -- the generic object we are writing
//
// Returns: NOERROR on success
// E_OUTOFMEMORY on allocation failure
// STG_E_WRITEFAULT on storage write failure
//
// History: dd-mmm-yy Author Comment
// 18-Feb-94 davepl Removed 14 goto's (for better or worse)
// See "Notes" for new control flow
// 24-Mar-94 alext Fix OLE 1 native case (there was an
// extra stream open)
//
// Notes: There are two possible major codepaths based on the creation
// of the Stg on ILockBytes. The outcome is handled by a
// switch statement, and both the TRUE and FALSE cases are
// loaded with break statements that will bail out to the
// bottom of the function on any failure. This gives us a
// single entry and exit point, without all the gotos
//
//--------------------------------------------------------------------------
static INTERNAL Write20NativeStreams(LPSTORAGE pstg, const GENOBJ FAR& genobj) { LPLOCKBYTES plkbyt = NULL; LPSTORAGE pstgNative = NULL; LPSTREAM pstmNative = NULL; HRESULT hr = NOERROR;
// Create an ILockBytes instance on our generic object's native data
if (SUCCEEDED(hr = CreateILockBytesOnHGlobal (genobj.m_dataNative.m_h, FALSE, &plkbyt))) { // If the ILockBytes appears to contain an IStorage, then this was
// an OLE 2 object "hiding" within the OLE 1 stream as native data
switch ((DWORD)(S_OK == StgIsStorageILockBytes (plkbyt))) { case (TRUE):
// Open the IStorage contained in the ILockBytes
if (FAILED(hr = StgOpenStorageOnILockBytes (plkbyt, (LPSTORAGE)NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT, (SNB)NULL, 0, &pstgNative))) { LEDebugOut(( DEB_ERROR, "Can't open storage on ILBytes at line %d in %s\n", __LINE__, __FILE__));
break; // on failure fall through to error return
}
// Remove the stream from the native data
if (FAILED(hr = UtDoStreamOperation(pstgNative, NULL, // pstgDst
OPCODE_REMOVE, // operation
STREAMTYPE_CACHE))) // stream
{ LEDebugOut(( DEB_ERROR, "OPCODE REMOVE stream op failed at line %d in %s\n", __LINE__, __FILE__));
break; // on failure fall through to error return
}
// Copy the "hidden" IStorage to our destination storage
if (FAILED(hr = pstgNative->CopyTo (0, NULL,(SNB)NULL, pstg))) { LEDebugOut(( DEB_ERROR, "CopyTo member fn failed at line %d in %s\n", __LINE__, __FILE__));
break; // on failure fall through to error return
}
break; // end case TRUE
case FALSE:
// This is the typical case, where the OLE 1 stream had just
// plain old native data, so write it to a stream inside our
// output IStorage and call it OLE10_NATIVE_STREAM
ULONG cb; LPVOID pv = genobj.m_dataNative.m_pv;
if (NULL == pv) { hr = ResultFromScode(E_OUTOFMEMORY); break; }
// Create the new stream to hold the native data
if (FAILED(hr = OpenOrCreateStream (pstg, OLE10_NATIVE_STREAM, &pstmNative))) { break; // on failure fall through to error return
}
// Write the length of the native data to the stream
if (FAILED(hr = pstmNative->Write (&genobj.m_dataNative.m_cbSize, sizeof(ULONG), &cb))) { break; // on failure fall through to error return
}
// Now write the actual native data
if (FAILED(hr = pstmNative->Write (pv, genobj.m_dataNative.m_cbSize, &cb))) { break; // on failure fall through to error return
}
// Write out the item name
if (genobj.m_szItem) { ULONG cchItem; LPSTR pszAnsiItem; int cbWritten;
// We need to convert m_szItem from Wide to Ansi
// The ANSI string is bounded by the byte length of the
// Unicode string (one Unicode character maximally translates
// to one double-byte char, so we just use that length
cchItem = lstrlenW(genobj.m_szItem) + 1;
pszAnsiItem = (LPSTR) PrivMemAlloc(cchItem * sizeof(OLECHAR)); if (NULL == pszAnsiItem) { hr = E_OUTOFMEMORY; break; }
// We've got out buffer and our length, so do the conversion now
// We don't need to check for cbSize == FALSE since that was
// already done during the length test, but we need to check
// for substitution. Iff this call sets the fDefChar even when
// only doing a length check, these two tests could be merged,
// but I don't believe this is the case.
BOOL fDefUsed = 0; cbWritten = WideCharToMultiByte(CP_ACP, // Code Page ANSI
0, // No flags
genobj.m_szItem, // Input OLESTR
cchItem, // Input len (auto detect)
pszAnsiItem, // Output buffer
cchItem * sizeof(OLECHAR), // Output len
NULL, // Default char (use system's)
&fDefUsed); // Flag: Default char used
// If number of bytes converted was 0, we failed
if ((FALSE == cbWritten) || fDefUsed) { hr = ResultFromScode(E_UNSPEC); } else { // Write the size of the string (including null terminator) to stream
hr = StSave10ItemName(pstg, pszAnsiItem); }
PrivMemFree(pszAnsiItem);
if (FAILED(hr)) { break; // on failure fall through to error return
} } break;
} // end switch
} // end if
// Free up any resources that may have been allocated in any of the
// code paths above
if (NULL != plkbyt) { plkbyt->Release(); }
if (NULL != pstgNative) { pstgNative->Release(); }
if (NULL != pstmNative) { pstmNative->Release(); }
return hr; }
//+-------------------------------------------------------------------------
//
// Function: wConvertIStorageToOLESTREAM, INTERNAL
//
// Synopsis: Worker function; brings object from the IStorage into
// the internal generic object representation
//
// Arguments: [pstg] -- the IStorage the object resides in
// [polestream]-- the OLE 1 stream it will be going to
// [pgenobj] -- the generic object to hold the internal rep
//
// Returns: NOERROR on success
// STG_E_FILENOTFOUND bad IStorage
// CONVERT10_E_STG_NO_STD_STREAM the IStorage was missing one
// of the required standard streams
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleanup and documentation
//
// Notes:
//
//--------------------------------------------------------------------------
INTERNAL wConvertIStorageToOLESTREAM ( LPSTORAGE pstg, LPOLESTREAM polestream, PGENOBJ pgenobj ) { SCODE scode = S_OK;
VDATEIFACE (pstg);
// Ensure that all of the pointers are valid
#if DBG==1
if (!IsValidReadPtrIn (polestream, sizeof(OLESTREAM)) || !IsValidReadPtrIn (polestream->lpstbl, sizeof(OLESTREAMVTBL)) || !IsValidCodePtr ((FARPROC)polestream->lpstbl->Put)) { LEDebugOut(( DEB_ERROR, "Bad OLESTREAM at line %d in %s\n", __LINE__, __FILE__));
return ResultFromScode (E_INVALIDARG); } #endif
scode = GetScode (StorageToGenericObject (pstg, pgenobj));
// If the storage was not there, modify the return code to
// make it specific to the conversion process, otherwise just
// return whatever error code came back.
if (scode != S_OK) { if (scode == STG_E_FILENOTFOUND) { return ResultFromScode(CONVERT10_E_STG_NO_STD_STREAM); } else { return ResultFromScode(scode); } }
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: OleConvertIStorageToOLESTREAM, STDAPI
//
// Synopsis: Reads an object from an IStorage into a generic internal
// representation, then writes it back out to an OLE 1 stream
//
// Arguments: [pstg] -- the IStorage to read from
// [polestream] -- the OLESTREAM to write to
//
// Returns: NOERROR on success
// CONVERT10_E_STG_NO_STD_STREAM when one of the needed streams
// inside the IStorage was not
// present
// E_INVALIDARG bad input argument
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Cleanup and documentation
//
// Notes:
//
//--------------------------------------------------------------------------
STDAPI OleConvertIStorageToOLESTREAM(LPSTORAGE pstg, LPOLESTREAM polestream) { OLETRACEIN((API_OleConvertIStorageToOLESTREAM, PARAMFMT("pstg= %p, polestream= %p"), pstg, polestream));
LEDebugOut((DEB_TRACE, "%p _IN OleConvertIStorageToOLESTREAM (" " %p , %p )\n", 0 /*function*/, pstg, polestream )); CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStorage,(IUnknown **)&pstg);
HRESULT hr; CGenericObject genobj;
// Read from the IStorage into the generic object
hr = wConvertIStorageToOLESTREAM(pstg, polestream, &genobj); if (FAILED(hr)) { goto errRtn; }
// Write from the generic object out to the OLE 1 stream
hr = GenericObjectToOLESTREAM (genobj, polestream);
errRtn: LEDebugOut((DEB_TRACE,"%p OUT OleConvertIStorageToOLESTREAM ( %lx ) " "\n", 0 /*function*/, hr));
OLETRACEOUT((API_OleConvertIStorageToOLESTREAM, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: wFillPpres, INTERNAL
//
// Synopsis: Fills in the generic object's presentation data by
// building a presentation out of the native data
//
// Arguments: [pstg] -- the IStorage we are reading from
// [pgenobj] -- the generic object
// [cfFormat] -- what clipboard format is being used
// [fOle10Native] -- flag: is this OLE 1 native data?
//
// Returns: NOERROR on success
// E_OUTOFMEMORY can't allocate mem for PRES member
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleanup, documentation
// 19-Jul-94 davepl Fixed HMETAFILE cases
//
// Notes: Since most of this code treats HMETAFILE handles and
// HGLOBALS indentically, we need to special case the
// the HMETAFILE case by marking the pointer with a
// special value
//
//--------------------------------------------------------------------------
static INTERNAL wFillPpres( LPSTORAGE pstg, PGENOBJ pgenobj, CLIPFORMAT cfFormat, BOOL fOle10Native) { pgenobj->m_ppres = new PRES;
if (pgenobj->m_ppres == NULL) { return ResultFromScode(E_OUTOFMEMORY); }
// Set the format tag and clipboard format in the PRES member
pgenobj->m_ppres->m_format.m_cf = cfFormat; pgenobj->m_ppres->m_format.m_ftag = ftagClipFormat;
// Build the presentation based on the object's native data
HANDLE hpres = UtGetHPRESFromNative(pstg, NULL, pgenobj->m_ppres->m_format.m_cf, fOle10Native);
void * lppres = NULL;
if (hpres == NULL) { return NOERROR; }
// Lock the DIB or the METAFILEPICT structure
lppres = GlobalLock(hpres); if (NULL == lppres) { goto errRtn; }
if (cfFormat == CF_DIB) { // If it's a DIB, fill in the extents
LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER) lppres; UtGetDibExtents(lpbmi, (LPLONG) &(pgenobj->m_ppres->m_ulWidth), (LPLONG) &(pgenobj->m_ppres->m_ulHeight));
GlobalUnlock(hpres); pgenobj->m_ppres->m_data.m_h = hpres; pgenobj->m_ppres->m_data.m_cbSize = (ULONG) GlobalSize(pgenobj->m_ppres->m_data.m_h); pgenobj->m_ppres->m_data.m_pv = GlobalLock(pgenobj->m_ppres->m_data.m_h);
} else if (cfFormat == CF_METAFILEPICT) { LPMETAFILEPICT lpmfp = (LPMETAFILEPICT) lppres;
// If it's a METAFILE, fill in the width, height
pgenobj->m_ppres->m_ulWidth = (ULONG) lpmfp->xExt; pgenobj->m_ppres->m_ulHeight = (ULONG) lpmfp->yExt; pgenobj->m_ppres->m_data.m_h = lpmfp->hMF; GlobalFree(hpres); hpres = NULL;
// We place a special known value in the pointer field
// to indicate that the associated handle is a metafile
// handle (as opposed to a global memory handle), which
// signals us to special case its cleanup.
pgenobj->m_ppres->m_data.m_pv = METADATAPTR;
// We cannot merely GlobalSize() the HMETAFILE, so we
// ask the GDI how many bytes we will need to store the
// data.
pgenobj->m_ppres->m_data.m_cbSize = GetMetaFileBitsEx((HMETAFILE) pgenobj->m_ppres->m_data.m_h, 0, NULL); if (0 == pgenobj->m_ppres->m_data.m_cbSize) { pgenobj->m_ppres->m_data.m_h = NULL; goto errRtn; } } else { goto errRtn; }
return NOERROR;
errRtn: if (hpres) { Verify(GlobalUnlock(hpres)); GlobalFree(hpres); }
delete pgenobj->m_ppres; pgenobj->m_ppres = NULL; return ResultFromScode(E_OUTOFMEMORY); }
//+-------------------------------------------------------------------------
//
// Function: StorageToGenericObject, INTERNAL
//
// Synopsis: Read an object from an IStorage into the generic object,
// and set up the format type, native and pres data.
//
// Arguments: [pstg] -- the IStorage we are reading from
// [pgenobj] -- the generic object we are reading into
//
// Returns: NOERROR on success
// various possible errors from lower-level fns
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleanup and documentation
//
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL StorageToGenericObject(LPSTORAGE pstg, PGENOBJ pgenobj) { CLSID clsid; CLIPFORMAT cf = NULL; BOOL fObjFmtKnown = FALSE; HRESULT hr;
// Get the class ID from the IStorage
if (FAILED(hr = ReadRealClassStg (pstg, &clsid))) { return hr; }
// Set the class ID in our generic object
if (CLSID_StaticMetafile == clsid || CLSID_StaticDib == clsid) { if (CLSID_StaticMetafile == clsid) { cf = CF_METAFILEPICT; } else { cf = CF_DIB; } fObjFmtKnown = TRUE;
pgenobj->m_class.Set(clsid, NULL); pgenobj->m_fStatic = TRUE; } else { if (FAILED(hr = pgenobj->m_class.Set (clsid, pstg))) { return hr; } }
// Get the OLE version, flags, update opts, and moniker
SCODE sc = GetScode (Read20OleStream (pstg, pgenobj));
// It is okay for the Ole Stream to be missing.
if (sc != S_OK) { if (sc != STG_E_FILENOTFOUND) { return ResultFromScode (sc); } }
// Read the native data into the generic object
if (FAILED(hr = Read20NativeStreams (pstg, &(pgenobj->m_dataNative)))) { return hr; }
// Try to ascertain the clipboard format
if (cf == 0) { if (clsid == CLSID_PBrush) { cf = CF_DIB; } else if (clsid == CLSID_MSDraw) { cf = CF_METAFILEPICT; } else { ReadFmtUserTypeStg (pstg, &cf, NULL); }
fObjFmtKnown = (cf == CF_METAFILEPICT || cf == CF_DIB); }
// Read the presentation data if possible
if (FAILED(hr = Read20PresStream (pstg, pgenobj, fObjFmtKnown))) { return hr; }
// If we don't have a presentation, it might be a PBrush object,
// which is OK because OLE 1 DLLs know how to draw them based on
// the native data. Otherwise, we will try and create a presentation
// based on the native data.
if (pgenobj->m_ppres == NULL) { if (clsid == CLSID_PBrush) { return NOERROR; } if (cf == CF_METAFILEPICT || cf == CF_DIB) { if (FAILED(hr=wFillPpres(pstg,pgenobj,cf,clsid == CLSID_MSDraw))) { return hr; } } }
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: GenericObjectToOLESTREAM, INTERNAL
//
// Synopsis: Writes the interal object representation out to an OLE1
// stream.
//
// Arguments: [genobj] -- the object to write out
// [pos] -- the OLE 1 stream to write to
//
// Returns: NOERROR on success
//
// History: dd-mmm-yy Author Comment
// 22-Feb-94 davepl 32-bit port
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL GenericObjectToOLESTREAM( const GENOBJ FAR& genobj, LPOLESTREAM pos) { HRESULT hr;
if (genobj.m_fStatic) { return PutPresentationObject (pos, genobj.m_ppres, genobj.m_class, TRUE /* fStatic*/ ); }
// OLE version
if (FAILED(hr = ULToOLE1Stream (pos, dwVerToFile))) { return hr; }
// Format ID for embedded or linked object
if (FAILED(hr = ULToOLE1Stream (pos, genobj.m_fLink ? FMTID_LINK : FMTID_EMBED))) { return hr; }
// We must have the class id string by this point
Assert (genobj.m_class.m_szClsid);
// Write out the class ID string
if (FAILED(hr = StringToOLE1Stm (pos, genobj.m_class.m_szClsid))) { return hr; }
// Write out the topic string
if (FAILED(hr = StringToOLE1Stm (pos, genobj.m_szTopic))) { return hr; }
// Write out the item string
if (FAILED(hr = StringToOLE1Stm (pos, genobj.m_szItem))) { return hr; }
// Write out the update options, network info for a link,
// or the native data for an embedded object
if (genobj.m_fLink) { // Network information
if (FAILED(hr = PutNetworkInfo (pos, genobj.m_szTopic))) { return hr; } // Link update options
if (FAILED(hr = ULToOLE1Stream (pos, genobj.m_lnkupdopt))) { return hr; } } else { if (FAILED(hr = SizedDataToOLE1Stm (pos, genobj.m_dataNative))) { return hr; } }
// Write out the presentation data
return PutPresentationObject (pos, genobj.m_ppres, genobj.m_class); }
//+-------------------------------------------------------------------------
//
// Function: PutNetworkInfo, INTERNAL
//
// Synopsis: If needed, converts a DOS-style path to a proper network
// path. In any case, writes network path to OLE 1 stream
//
// Arguments: [pos] -- the OLE 1 stream we are writing to
// [szTopic] -- the topic string for this object
//
// Returns: NOERROR on success
// Various possible I/O errors on write
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleanup and documentation
//
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL PutNetworkInfo(LPOLESTREAM pos, LPOLESTR szTopic) { LPOLESTR szNetName = NULL; HRESULT hr = NOERROR;
// If we have an X:\ style path, we want to convert that
// to a proper network name
if (szTopic && IsCharAlphaW(szTopic[0]) && szTopic[1]==':') { OLECHAR szBuf[80]; DWORD u; OLECHAR szDrive[3];
szDrive[0] = (OLECHAR)CharUpperW((LPWSTR)szTopic[0]); szDrive[1] = ':' ; szDrive[2] = '\0';
if (GetDriveType (szDrive) == DRIVE_REMOTE && WNetGetConnection (szDrive, szBuf, &u) == WN_SUCCESS) { szNetName =szBuf; } }
// We now have the network name, so write it out to OLE 1 stream
if (FAILED(hr = StringToOLE1Stm (pos, szNetName))) { return hr; }
// Network type, driver version number, but we have to pad for
// the space anyway
if (FAILED(hr = ULToOLE1Stream (pos, 0L))) { return hr; }
Assert (hr == NOERROR); return hr; }
//+-------------------------------------------------------------------------
//
// Function: OpenStream, INTERNAL
//
// Synopsis: Opens a stream in SHARE_EXCLUSIVE, READ mode
//
// Arguments: [pstg] -- the storage the stream resides in
// [szName] -- the name of the stream
// [ppstm] -- out parameter for stream
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleanup and document
//
// Notes:
//
//--------------------------------------------------------------------------
static inline INTERNAL OpenStream( LPSTORAGE pstg, LPOLESTR szName, LPSTREAM FAR* ppstm) { return pstg->OpenStream (szName, NULL, STGM_SHARE_EXCLUSIVE| STGM_READ, 0, ppstm); }
//+-------------------------------------------------------------------------
//
// Function: ReadRealClassStg, INTERNAL
//
// Synopsis: Reads the _real_ class of the object. ie: if the class is
// StdOleLink, we need to find out the class of the object
// to which this is linked
//
// Arguments: pstg -- the storage to read from
// pclsid -- caller's CLSID holder
//
// Returns: NOERROR on success
//
// History: dd-mmm-yy Author Comment
// 04-Mar-04 davepl 32-bit port
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL ReadRealClassStg(LPSTORAGE pstg, LPCLSID pclsid) { LPSTREAM pstm = NULL; HRESULT hr = NOERROR;
// Get the class ID from the IStorage
if (FAILED(hr = ReadClassStg (pstg, pclsid))) { return hr; }
// If it's a link, we have to figure out what class its a link _to_
if (CLSID_StdOleLink == *pclsid) { LPMONIKER pmk = NULL;
if (FAILED(hr = ReadOleStg (pstg, NULL, NULL, NULL, NULL, &pstm))) { return hr; }
if (FAILED(hr = ReadMonikerStm (pstm, &pmk))) { goto errRtn; }
if (pmk) { pmk->Release(); }
if (FAILED(hr = ReadMonikerStm (pstm, &pmk))) { goto errRtn; }
if (pmk) { pmk->Release(); }
// Read "last class"
if (FAILED(hr = ReadM1ClassStm (pstm, pclsid))) { goto errRtn; } }
errRtn:
if (pstm) { pstm->Release(); } return hr; }
//+-------------------------------------------------------------------------
//
// Function: Read20OleStream, INTERNAL
//
// Synopsis: Reads the update options and absolute source class from
// an OLE 2 object
//
// Arguments: pstg -- the IStorage to read from
// pgenobj -- the genobj we are reading into
//
// Returns: NOERROR on success
//
// History: dd-mmm-yy Author Comment
// 06-Mar-94 davepl 32-bit port
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL Read20OleStream(LPSTORAGE pstg, PGENOBJ pgenobj) { LPMONIKER pmk = NULL; HRESULT hr = NOERROR; LPSTREAM pstm = NULL; ULONG ul = (ULONG) -1L; CLSID clsidLast;
if (SUCCEEDED(hr = OpenStream (pstg, OLE_STREAM, &pstm))) { // OLE version
if (SUCCEEDED(hr = OLE2StmToUL (pstm, NULL))) { // Object flags
if (SUCCEEDED(hr = OLE2StmToUL (pstm, &ul))) { if (ul & OBJFLAGS_LINK) { pgenobj->m_fLink = TRUE; }
// Update options
hr = OLE2StmToUL (pstm, &ul); } } }
// If no errors so far...
// If this is a link, get the update options
if (SUCCEEDED(hr) && pgenobj->m_fLink) { switch (ul) { case OLEUPDATE_ALWAYS: pgenobj->m_lnkupdopt = UPDATE_ALWAYS; break;
case OLEUPDATE_ONCALL: pgenobj->m_lnkupdopt = UPDATE_ONCALL; break;
default: AssertSz (0, "Warning: Invalid update options in Storage"); hr = ResultFromScode(CONVERT10_E_STG_FMT); } }
if (SUCCEEDED(hr)) // Only continue if no failures so far
{ // Reserved (was view format)
if (SUCCEEDED(hr = OLE2StmToUL (pstm, NULL))) { if (pgenobj->m_fLink) {
// All 4 of these calls must succeed or we simply fall
// through to the cleanup code
// ignore relative moniker
if (SUCCEEDED(hr = OLE2StmToMoniker (pstm, NULL)) && // ignore relative source moniker
SUCCEEDED(hr = OLE2StmToMoniker (pstm, NULL)) && // get absolute source moniker
SUCCEEDED(hr = OLE2StmToMoniker (pstm, &pmk)) && // get class from abs moniker
SUCCEEDED(hr = ReadM1ClassStm (pstm, &clsidLast)) ) { hr = MonikerIntoGenObj (pgenobj, clsidLast, pmk); } } } }
// Clean up any resources and return status to caller
if (pstm) { pstm->Release(); } if (pmk) { pmk->Release(); } return hr; }
//+-------------------------------------------------------------------------
//
// Function: OLE2StmToMoniker, INTERNAL
//
// Synopsis: Calls ReadMonikerStm to get a moniker from a stream,
// and if the ppmk parameter was NULL, it does a Release()
// on the moniker object immediately, otherwise sets the
// caller's pointer to point to the moniker that was read.
//
// Arguments: [pstm] -- the stream to read the moniker from
// [ppmk] -- points to caller's moniker ptr
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleanup and documentation
//
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL OLE2StmToMoniker(LPSTREAM pstm, LPMONIKER FAR* ppmk) { LPMONIKER pmk = NULL; HRESULT hr = NOERROR;
if (FAILED(hr = ReadMonikerStm (pstm, &pmk))) { return hr; }
if (ppmk) // If the callers wanted a result, return the
{ // moniker as an out parameter
*ppmk = pmk; } else // Otherwise, release it immediately and
{ // return to caller
if (pmk) { pmk->Release(); } }
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: ReadFormat, INTERNAL
//
// Synopsis: Reads the format ID type from the stream, and based on that,
// reads the format ID from the stream.
//
// Arguments: [pstm] -- the stream to read from
// [pformat] -- caller's format member object
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleanup and documentation
//
// Notes: The first ULONG indicates the type (standard clipboard,
// Mac, NULL, or string) of the identifier
//
//--------------------------------------------------------------------------
static INTERNAL ReadFormat(LPSTREAM pstm, PFORMAT pformat) { ULONG ul; HRESULT hr = NOERROR;
// Get the format ID type indicator
if (FAILED(hr = OLE2StmToUL (pstm, &ul))) { return hr; }
// The first ULONG indicates what kind of format ID will
// found in the stream:
//
// -1 => A standard clipboard format ID
// -2 => A Macintosh format
// 0 => NULL format
// >0 => The number of bytes of the text string
// identifier to follow
switch ((signed long)ul) { case -1L: // Standard clipboard format
ULONG ulClipFormat; pformat->m_ftag = ftagClipFormat; if (FAILED(hr = OLE2StmToUL (pstm, &ulClipFormat))) { return hr; } pformat->m_cf = (CLIPFORMAT) ulClipFormat; break;
case -2L: // Macintosh format
return ResultFromScode(CONVERT10_E_STG_FMT);
case 0: // NULL format
pformat->m_ftag = ftagNone; pformat->m_cf = 0; return NOERROR;
default: // ul == size of string (format name)
pformat->m_ftag = ftagString; if (FAILED(hr = OLE2StmToSizedData (pstm, &(pformat->m_dataFormatString), 0, ul))) { return hr; } break;
} return NOERROR; }
#ifdef _OBSOLETE
//+-------------------------------------------------------------------------
//
// Function: WriteFormat, INTERNAL
//
// Synopsis: Depending on what kind of format (standard cf, string, etc)
// the format object holds, this fn writes out the appropriate
// information to the stream
//
// Arguments: [pstm] -- the stream to write to
// [format] -- the format object to get info from
//
// Returns: NOERROR on success
// E_UNEXPECTED for a NULL format tag
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleanup and documentation
// Notes:
//--------------------------------------------------------------------------
static INTERNAL WriteFormat(LPSTREAM pstm, const FORMAT FAR& format) { HRESULT hr;
switch (format.m_ftag) { case ftagNone: Assert (0 && "Cant write a NULL format tag"); return ResultFromScode (E_UNEXPECTED);
case ftagClipFormat: if (FAILED(hr = ULToOLE2Stm (pstm, (ULONG) -1L))) { return hr; } if (FAILED(hr = ULToOLE2Stm (pstm, format.m_cf))) { return hr; } break;
case ftagString: if (FAILED(hr=DataObjToOLE2Stm(pstm,format.m_dataFormatString))) { return hr; } break;
default: AssertSz (0, "invalid m_ftag value"); return ResultFromScode (E_UNEXPECTED); } return NOERROR; }
#endif // _OBSOLETE
//+-------------------------------------------------------------------------
//
// Function: ReadDibAsBitmap, INTERNAL
//
// Synopsis: Reads a DIB from an OLE 2 stream and stores it as a
// Bitmap in a DATA structure
//
// Arguments: [pstm] -- the OLE 2 stream to read from
// [pdata] -- the data object to hold the bitmap
//
// Returns: NOERROR on success
// CONVERT10_E_STG_DIB_TO_BITMAP conversion failure
// E_OUTOFMEMORY allocation failure
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleanup and documentation
//
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL ReadDibAsBitmap(LPSTREAM pstm, PDATA pdata) { DATA dataDib; ULONG cb; ULONG cbBits; ULONG cbBitsFake; BITMAP bm;
HBITMAP hBitmap = NULL; HRESULT hr = NOERROR; HGLOBAL hBits = NULL; LPBYTE pBits = NULL;
Assert (pdata&&pdata->m_cbSize==0&&pdata->m_h==NULL&&pdata->m_pv==NULL);
// Read the DIB into our local DATA object
if (FAILED(hr = OLE2StmToSizedData (pstm, &dataDib))) { return hr; }
// Convert the DIB to a Bitmap
hBitmap = UtConvertDibToBitmap (dataDib.m_h); if (NULL == hBitmap ) { return ResultFromScode(CONVERT10_E_STG_DIB_TO_BITMAP); }
if (0 == GetObject (hBitmap, sizeof(BITMAP), &bm)) { return ResultFromScode(CONVERT10_E_STG_DIB_TO_BITMAP); }
cbBits = (DWORD) bm.bmHeight * (DWORD) bm.bmWidthBytes * (DWORD) bm.bmPlanes;
// There was a bug in OLE 1.0. It calculated the size of a bitmap
// as Height * WidthBytes * Planes * BitsPixel.
// So we need to put that many bytes here even if most of the end of that
// data block is garbage. Otherwise OLE 1.0 will try to read too many
// bytes of the OLESTREAM as bitmap bits.
cbBitsFake = cbBits * (DWORD) bm.bmBitsPixel;
// Allocate enough memory for our resultant BITMAP & header
hBits = GlobalAlloc (GMEM_MOVEABLE, cbBitsFake + sizeof (BITMAP)); if (NULL == hBits) { if (hBitmap) { Verify (DeleteObject (hBitmap)); } return ResultFromScode(E_OUTOFMEMORY); }
// Get a pointer to the memory
pBits = (LPBYTE) GlobalLock (hBits); if (NULL == pBits) { if (hBitmap) { Verify (DeleteObject (hBitmap)); } GlobalFree(hBits); return ResultFromScode(E_OUTOFMEMORY); }
// Copy the raw bitmap data
cb = GetBitmapBits (hBitmap, cbBits, pBits + sizeof(BITMAP)); if (cb != cbBits) { if (hBitmap) { Verify (DeleteObject (hBitmap)); } GlobalFree(hBits); return ResultFromScode(CONVERT10_E_STG_DIB_TO_BITMAP); }
// Set the caller's pointer to point to the bitmap
*((BITMAP FAR*)pBits) = bm;
pdata->m_h = hBits; pdata->m_pv = pBits; pdata->m_cbSize = cbBitsFake + sizeof(BITMAP);
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: Read20PresStream, INTERNAL
//
// Synopsis: Reads presentation data from an IStorage into a
// generic object
//
// Arguments: [pstg] -- the IStorage holding the pres stream
// [pgenobj] -- the generic object to read to
// [fObjFmtKnown] -- flag: Do we know the object format?
//
// Returns: NOEROR on success
// E_OUTOFMEMORY on allocation failure
//
// History: dd-mmm-yy Author Comment
// 22-Feb-94 davepl Code cleanup and documentation
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL Read20PresStream( LPSTORAGE pstg, PGENOBJ pgenobj, BOOL fObjFmtKnown) { HRESULT hr = NOERROR; LPSTREAM pstm = NULL;
// Find the best presentation stream in this IStorage
if (FAILED(hr = FindPresStream (pstg, &pstm, fObjFmtKnown))) { return hr; }
if (pstm) { // Allocate a generic presentation object
Assert (NULL==pgenobj->m_ppres); pgenobj->m_ppres = new PRES; if (NULL == pgenobj->m_ppres) { pstm->Release(); return ResultFromScode(E_OUTOFMEMORY); } } else { // No presentation stream
Assert (NULL == pgenobj->m_ppres); return NOERROR; }
// read the format
if (FAILED(hr = ReadFormat (pstm, &(pgenobj->m_ppres->m_format)))) { pstm->Release(); return hr; }
// This is the fix for Bug 4020, highly requested by Access
if (pgenobj->m_ppres->m_format.m_ftag == ftagNone) { // NULL format
delete pgenobj->m_ppres; pgenobj->m_ppres = NULL; Assert (hr == NOERROR); pstm->Release(); return hr; }
// Each of the following calls must succeed in order for the following
// one to be executed; if any fails, the if( .. && ..) will be false
// and hr will be set to the error that caused the failure
// target device
if (SUCCEEDED(hr = OLE2StmToSizedData (pstm, NULL, 4)) && // aspect
SUCCEEDED(hr = OLE2StmToUL (pstm, NULL)) && // lIndex
SUCCEEDED(hr = OLE2StmToUL (pstm, NULL)) && // cache flags
SUCCEEDED(hr = OLE2StmToUL (pstm, NULL)) && // compression
SUCCEEDED(hr = OLE2StmToUL (pstm, NULL)) && // width
SUCCEEDED(hr = OLE2StmToUL (pstm, &(pgenobj->m_ppres->m_ulWidth)))) { // height
hr = OLE2StmToUL (pstm, &(pgenobj->m_ppres->m_ulHeight)); }
// We only proceed if everything so far has suceeded
if (SUCCEEDED(hr)) { if (pgenobj->m_ppres->m_format.m_ftag == ftagClipFormat && pgenobj->m_ppres->m_format.m_cf == CF_DIB && !pgenobj->m_fStatic) { pgenobj->m_ppres->m_format.m_cf = CF_BITMAP; hr = ReadDibAsBitmap (pstm, &(pgenobj->m_ppres->m_data)); } else { // In most cases, we look for a sized block of data in the
// stream.
hr = OLE2StmToSizedData (pstm, &(pgenobj->m_ppres->m_data)); } }
// Free up the stream and return status to caller
if (pstm) { pstm->Release(); } return hr; }
//+-------------------------------------------------------------------------
//
// Function: OLE2StmToSizedData, INTERNAL
//
// Synopsis: Reads a set amount of data from an OLE 2 stream into a
// DATA structure. If the number of bytes are not known
// ahead of time, the data length is pulled as the first
// ULONG at the current stream position.
//
// Arguments: [pstm] -- the stream to read from
// [pdata] -- the DATA structure to read to
// [cbSizeDelta] -- amount to be subtracted from
// length; used to read target devices
// where the length of data includes
// prefixed length
// [cbSizeKnown] -- number of bytes to read if known
// ahead of time
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleanup and documentation
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL OLE2StmToSizedData( LPSTREAM pstm, PDATA pdata, ULONG cbSizeDelta, // default 0
ULONG cbSizeKnown) // default 0
{ ULONG cbSize; ULONG cbRead; LARGE_INTEGER large_integer; HRESULT hr = NOERROR;
// If we don't know the data size ahead of time, read it from the stream;
// it will be the first ULONG at the current position
if (cbSizeKnown) { cbSize = cbSizeKnown; } else { if (FAILED(hr = (OLE2StmToUL (pstm, &cbSize)))) { return hr; } }
cbSize -= cbSizeDelta;
// If pdata is set, it means we actually do want to read the
// data to a buffer, rather than just skip over it (the NULL case)
if (pdata) { Assert (pdata->m_cbSize==0 && pdata->m_h==NULL && pdata->m_pv==NULL);
// Set the number of bytes in the DATA structure
pdata->m_cbSize = cbSize;
// If there are any, allocate a buffer and read them.
if (cbSize) { // Allocate memory on the DATA handle
pdata->m_h = GlobalAlloc (GMEM_MOVEABLE, cbSize); if (NULL == pdata->m_h) { return ResultFromScode(E_OUTOFMEMORY); }
// Lock memory in for the read
pdata->m_pv = GlobalLock (pdata->m_h); if (NULL == pdata->m_pv) { GlobalFree(pdata->m_h); return ResultFromScode(E_OUTOFMEMORY); }
// Read the data to the buffer
if (FAILED(hr = pstm->Read (pdata->m_pv, cbSize, &cbRead))) { GlobalUnlock(pdata->m_h); GlobalFree(pdata->m_h); return hr; }
// If we didn't get enough bytes, bail now
if (cbRead != cbSize) { GlobalUnlock(pdata->m_h); GlobalFree(pdata->m_h); return ResultFromScode(STG_E_READFAULT); } } else { // We have 0 bytes to read, so mark the
// memory handle and ptr as NULL
pdata->m_h = NULL; pdata->m_pv = NULL; } } else { // we don't care what the data is, so just skip it
LISet32( large_integer, cbSize ); if (FAILED(hr = pstm->Seek (large_integer, STREAM_SEEK_CUR, NULL))) { return hr; } } return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: RankOfPres, INTERNAL
//
// Synopsis: Returns a ULONG indicating the relative "goodness" of a
// presentation. The preference is, in descending order:
//
// Type Rank
// ---------- ----------
// METAFILE x30000
// DIB x20000
// none x10000
//
// Add x200 for fScreenTargDev being set
// Add x4 for Content aspect
// Add x3 for Thumbnail aspect
// Add x2 for Icon aspect
// Add x1 for Docprint aspect
//
// Eg: Metafile in Content aspect, with ScreenTargDev: 30204
//
// The whole point of this is that there may be many
// presentation streams available in the IStorage. This fn
// is used to select the best one.
//
// Arguments: [format] -- the format tag & type structure
// [fScreenTargDev]-- do we have a handle to the target dev
// [dwAspect] -- the aspect type
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleanup and documentation
//
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL_(ULONG) RankOfPres( const FORMAT FAR& format, const BOOL fScreenTargDev, const DWORD dwAspect) { ULONG ul = 0L;
if (format.m_cf==CF_METAFILEPICT) { ul += 0x030000; } else if (format.m_cf==CF_DIB) { ul += 0x020000; } else if (format.m_ftag != ftagNone) { ul += 0x010000; }
ul += (fScreenTargDev + 1) * 0x0100;
switch (dwAspect) { case DVASPECT_CONTENT: ul += 0x04; break;
case DVASPECT_THUMBNAIL: ul += 0x03; break;
case DVASPECT_ICON: ul += 0x02; break;
case DVASPECT_DOCPRINT: ul += 0x01; break; }
return ul; }
//+-------------------------------------------------------------------------
//
// Function: IsBetter, INTERNAL INLINE
//
// Synopsis: Calls RankOfPres to determine if one presentation is
// better than another
//
// Effects:
//
// Arguments: [format] -- the format tag and type
// [fScreenTargDev]-- do we have a handle to target device
// [dwAspect] -- the aspect of the presentation
// [formatBest] -- the best format seen so far
// [fScreenTargDevBest] -- flag for best format seen so far
// [dwAspectBest] -- the aspect of best format seen so far
//
// History: dd-mmm-yy Author Comment
/// 21-Feb-94 davepl Code cleanup and documentation
//
// Notes:
//
//--------------------------------------------------------------------------
inline static INTERNAL_(BOOL) IsBetter( const FORMAT FAR& format, const BOOL fScreenTargDev, const DWORD dwAspect, const FORMAT FAR& formatBest, const BOOL fScreenTargDevBest, const DWORD dwAspectBest) { return RankOfPres (format, fScreenTargDev, dwAspect) > RankOfPres (formatBest, fScreenTargDevBest, dwAspectBest); }
//+-------------------------------------------------------------------------
//
// Function: FindPresStream, INTERNAL
//
// Synopsis: Enumerates over the streams in an IStorage, looking for
// presentation streams. Selects the best stream among
// these based on the comparison fn, IsBetter(), which uses
// for comparison the criteria established in RankOfPres().
//
// Arguments: [pstg] -- the IStorage to look in
// [ppstmBest] -- out param for best pres stream
// [fObjFmtKnown] is the object format known
//
// Returns: NOERROR on success
// If no presentation is found, it is not an error but
// *ppstm is set to NULL.
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleanup and documentation
//
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL FindPresStream( LPSTORAGE pstg, LPSTREAM FAR* ppstmBest, BOOL fObjFmtKnown) { HRESULT hr = NOERROR; LPSTREAM pstm = NULL; IEnumSTATSTG FAR* penumStg = NULL; DWORD dwAspectBest = 0; BOOL fTargDevBest = -1; STATSTG statstg; FORMAT formatBest;
Assert (ppstmBest);
*ppstmBest = NULL;
// Set up the enumeration on the available IStreams in the storage
if (FAILED(hr = pstg->EnumElements (NULL, NULL, NULL, &penumStg))) { return hr; }
// Enumerate through them and search for the best among all
// presentation streams
while (penumStg->Next (1, &statstg, NULL) == NOERROR) { // Check to see if this a presentation stream
if (lstrlenW(statstg.pwcsName) >= 8 && 0==memcmp(statstg.pwcsName, OLESTR("\2OlePres"), 8*sizeof(WCHAR))) { FORMAT format; DATA dataTargDev; DWORD dwAspect;
// Open the presentation stream
if (FAILED(hr = OpenStream (pstg, statstg.pwcsName, &pstm))) { goto errRtn; }
// Read the format from the pres stream
if (FAILED(hr = ReadFormat (pstm, &format))) { goto errRtn; }
// Read the target device from the pres stream
if (FAILED(hr = OLE2StmToSizedData (pstm, &dataTargDev, 4))) { goto errRtn; }
// Get the aspect from the pres stream
if (FAILED(hr = OLE2StmToUL (pstm, &dwAspect))) { goto errRtn; }
// Check to see if this presentation stream is better
// than the best seen so far
if (IsBetter (format, dataTargDev.m_h==NULL, dwAspect, formatBest, fTargDevBest, dwAspectBest)) { // If it is, we can release the "best"
if (*ppstmBest) { (*ppstmBest)->Release(); }
// The king is dead, long live the king
*ppstmBest = pstm; pstm->AddRef();
formatBest = format; fTargDevBest = (dataTargDev.m_h==NULL); dwAspectBest = dwAspect; } pstm->Release(); pstm = NULL; } PubMemFree(statstg.pwcsName); statstg.pwcsName = NULL; }
// On Windows For Workgroups machines, statstg.pwcsName!=NULL when
// Next() returns S_FALSE. Bug 3370.
statstg.pwcsName = NULL;
errRtn:
if (statstg.pwcsName) { PubMemFree(statstg.pwcsName); }
if (*ppstmBest) { if (dwAspectBest != DVASPECT_CONTENT && fObjFmtKnown) { // then don't use this stream, we will get the presentaion
// from the CONTENTS stream
(*ppstmBest)->Release(); *ppstmBest = NULL; } else { LARGE_INTEGER large_integer; LISet32( large_integer, 0); hr = (*ppstmBest)->Seek(large_integer, STREAM_SEEK_SET,NULL); } }
if (penumStg) { penumStg->Release(); } if (pstm) { pstm->Release(); }
return hr; }
//+-------------------------------------------------------------------------
//
// Function: Reads native data from an OLE 2 stream
//
// Synopsis: If the fn can find OLE 1 native data in the stream, it is
// read out; otherwise, it attempts to create an IStorage
// in memory on the data in the stream, and then uses the
// CopyTo interface to extract the data.
//
// Arguments: [pstg] -- The OLE 2 IStorage to look in
// [pdata] -- The DATA object to read native data to
//
// Returns: NOERROR on success
// STG_E_READFAULT on read failure
// E_OUTOFMEMORY on allocation failure
//
// History: dd-mmm-yy Author Comment
// 21-feb-94 davepl Cleaned up and documented code
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL Read20NativeStreams(LPSTORAGE pstg, PDATA pdata) { LPSTREAM pstm = NULL; LPLOCKBYTES plkbyt = NULL; LPSTORAGE pstgNative= NULL;
HRESULT hr = NOERROR;
// There are two possible codepaths based on the success of
// OpenStream. If it is true, it is because we were able to
// open the OLE 1 presentation stream in the OLE 2 object.
// Thus, it must have been an OLE 1 object "hidden" in
// an OLE 2 IStream.
//
// If that fails, we create an in-memory IStorage based on
// the native data and use the CopyTo member to extract the
// natice data.
//
// If we experience a failure at any point, a "break" statement
// bails us out past everything to the error cleanup and return
// code following the closure of the switch() statement.
switch ((DWORD)(NOERROR==OpenStream (pstg, OLE10_NATIVE_STREAM, &pstm))) { case TRUE: { // This was a 1.0 object "hidden" inside a 2.0 IStorage
ULONG cbRead;
Assert (pdata->m_cbSize==0 && NULL==pdata->m_h && NULL==pdata->m_pv);
// read size
if (FAILED(hr = pstm->Read(&(pdata->m_cbSize),sizeof(DWORD),&cbRead))) { break; }
if (sizeof(DWORD) != cbRead) { hr = ResultFromScode (STG_E_READFAULT); break; }
// allocate memory to store copy of stream
pdata->m_h = GlobalAlloc (GMEM_MOVEABLE, pdata->m_cbSize); if (NULL == pdata->m_h) { hr = ResultFromScode(E_OUTOFMEMORY); break; }
pdata->m_pv = GlobalLock (pdata->m_h); if (NULL == pdata->m_pv) { hr = ResultFromScode(E_OUTOFMEMORY); break; }
// read stream
if (FAILED(hr = pstm->Read(pdata->m_pv,pdata->m_cbSize,&cbRead))) { break; }
if (pdata->m_cbSize != cbRead) { hr= ResultFromScode (STG_E_READFAULT); break; } break; }
case FALSE: { const DWORD grfCreateStg = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | STGM_CREATE ;
// Copy pstg into pstgNative, thereby removing slack and
// giving us access to the bits via an ILockBytes
if (FAILED(hr = CreateILockBytesOnHGlobal (NULL, FALSE, &plkbyt))) { break; } if (FAILED(hr = StgCreateDocfileOnILockBytes (plkbyt, grfCreateStg, 0, &pstgNative))) { break; } if (FAILED(hr = pstg->CopyTo (0, NULL, 0, pstgNative))) { break; }
// Set pdata->m_cbSize
STATSTG statstg; if (FAILED(hr = plkbyt->Stat (&statstg, 0))) { break; } pdata->m_cbSize = statstg.cbSize.LowPart;
// Set pdata->m_h
if (FAILED(hr = GetHGlobalFromILockBytes (plkbyt, &(pdata->m_h)))) { break; } Assert (GlobalSize (pdata->m_h) >= pdata->m_cbSize);
// Set pdata->m_pv
pdata->m_pv = GlobalLock (pdata->m_h); if (NULL == pdata->m_pv) { hr = ResultFromScode(E_OUTOFMEMORY); break; } } // end case
} // end switch
// Cleanup and return status to caller
if (pstm) { pstm->Release(); } if (plkbyt) { plkbyt->Release(); } if (pstgNative) { pstgNative->Release(); } return hr; }
//+-------------------------------------------------------------------------
//
// Function: PutPresentationObject, INTERNAL
//
// Synopsis: Writes a presentation to an OLE 1 stream.
//
// Arguments: [pos] -- the OLE 1 stream to write to
// [ppres] -- the presentation object
// [cls] -- the class object
// [fStatic] -- flag: is this a static object
//
// Returns: NOERROR on success
// various possible I/O errors on failure
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleaned up and documented
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL PutPresentationObject( LPOLESTREAM pos, const PRES FAR* ppres, const CLASS FAR& cls, BOOL fStatic) // optional
{ HRESULT hr;
// Is there a real presentation?
BOOL fIsPres = FALSE; if (ppres) { if (ppres->m_format.m_ftag != ftagClipFormat || ppres->m_format.m_cf != 0 ) { fIsPres = TRUE; } }
// write the OLE version to the stream
if (FAILED(hr = ULToOLE1Stream (pos, dwVerToFile))) { return hr; }
// Calc format ID for presentation object, use 0 for no presentation
ULONG id = 0L;
if (fIsPres) { if (fStatic) { id = FMTID_STATIC; } else { id = FMTID_PRES; } } if (FAILED(hr = ULToOLE1Stream(pos, id))) { return hr; }
if (!fIsPres) { // No presentation
return NOERROR; }
if (IsStandardFormat (ppres->m_format)) { return PutStandardPresentation (pos, ppres); } else { Assert (!fStatic); return PutGenericPresentation (pos, ppres, cls.m_szClsid); } }
//+-------------------------------------------------------------------------
//
// Function: PutStandardPresentation, INTERNAL
//
// Synopsis: Writes a standard presentation (META, DIB, or BITMAP) out
// to an OLE 1 stream. Creates the METAFILEPICT header
// as required.
//
// Arguments: [pos] -- the OLE 1 stream to write to
// [ppres] -- the presentation to write
//
// Returns: NOERROR on success
// Various other errors are possible from I/O routines
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Cleaned up and documented
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL PutStandardPresentation( LPOLESTREAM pos, const PRES FAR* ppres) { HRESULT hr = NOERROR;
Assert (ppres->m_format.m_ftag == ftagClipFormat);
// Write the clipboard format string to the OLE 1 stream
// (Will be written in ANSI, not OLESTR format)
switch (ppres->m_format.m_cf) { case CF_METAFILEPICT: if (FAILED(hr = StringToOLE1Stm (pos, OLESTR("METAFILEPICT")))) { return hr; } break;
case CF_DIB: if (FAILED(hr = StringToOLE1Stm (pos, OLESTR("DIB")))) { return hr; } break;
case CF_BITMAP: if (FAILED(hr = StringToOLE1Stm (pos, OLESTR("BITMAP")))) { return hr; } break;
default: Assert (0 && "Don't know how to write pres format"); }
// Write width
if (FAILED(hr = ULToOLE1Stream(pos, ppres->m_ulWidth))) { return hr; } // OLE 1.0 file format expects height to be saved as a negative value
if (FAILED(hr = ULToOLE1Stream(pos, - ((LONG)ppres->m_ulHeight)))) { return hr; }
// Do special handling for CF_METAFILEPICT
if (ppres->m_format.m_cf == CF_METAFILEPICT) { // Need a header to write, crete one here
WIN16METAFILEPICT mfpict = { MM_ANISOTROPIC, (short) ppres->m_ulWidth, (short) ppres->m_ulHeight, 0 };
// put size ater adjusting it for metafilepict
if (FAILED(hr = ULToOLE1Stream (pos, (ppres->m_data.m_cbSize + sizeof(WIN16METAFILEPICT))))) { return hr; }
// put metafilepict
if (FAILED(hr = DataToOLE1Stm(pos, &mfpict, sizeof(mfpict)))) { return hr; }
// put metafile bits
// There are two possible means by which we got these metafile
// bits: either we have an in-memory metafile, or raw bits
// which we read from disk. If it is an in-memory metafile,
// the m_pv ptr will have been set to METADATAPTR, and we need
// to extract the bits to our own buffer before saving them.
// If they came from disk, we can just re-write the buffer
// into which we read them.
if (METADATAPTR == ppres->m_data.m_pv) { BYTE *pb = (BYTE *) PrivMemAlloc(ppres->m_data.m_cbSize); if (NULL == pb) { return E_OUTOFMEMORY; }
if (0 == GetMetaFileBitsEx((HMETAFILE) ppres->m_data.m_h, ppres->m_data.m_cbSize, pb)) { PrivMemFree(pb); return HRESULT_FROM_WIN32(GetLastError()); }
if (FAILED(hr = DataToOLE1Stm(pos, pb, ppres->m_data.m_cbSize))) { PrivMemFree(pb); return hr; } PrivMemFree(pb); } else // Bits were originally read into our buffer from disk
{ if (FAILED(hr = DataToOLE1Stm(pos, ppres->m_data.m_pv, ppres->m_data.m_cbSize))) { return hr; } } } else { // Not a METAFILE, just write the data
if (FAILED(hr = SizedDataToOLE1Stm (pos, ppres->m_data))) { return hr; } }
return hr; }
//+-------------------------------------------------------------------------
//
// Function: PutGenericPresentation, INTERNAL
//
// Synopsis: Writes a generic presentation to the stream based on
// the clipboard format. (Dumps raw pres data to stm)
//
// Arguments: [pos] -- the stream to write to
// [ppres] -- the presentation
// [szClass] -- class name
//
// History: dd-mmm-yy Author Comment
// 16-Feb-94 davepl 32-bit port'n'doc
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL PutGenericPresentation( LPOLESTREAM pos, const PRES FAR* ppres, LPCOLESTR szClass) { Assert (szClass); HRESULT hr = NOERROR;
// Write the format class name out to the stream
if (FAILED(hr = StringToOLE1Stm(pos, szClass))) { return hr; }
// This semi-mythical 0xC000 occurs in
// other code I've seen in this project also; if there's
// a constant defined, someone ought to fix this
if (ppres->m_format.m_ftag == ftagClipFormat) { if (ppres->m_format.m_cf < 0xc000) { if (FAILED(hr = ULToOLE1Stream (pos, ppres->m_format.m_cf))) { return hr; } } else { if (FAILED(hr = ULToOLE1Stream (pos, 0L))) { return hr; }
OLECHAR buf[256];
if (!GetClipboardFormatName(ppres->m_format.m_cf, buf, sizeof(buf)/sizeof(OLECHAR))) { return ResultFromScode(DV_E_CLIPFORMAT); }
if (FAILED(hr = StringToOLE1Stm (pos, buf))) { return hr; } } } else if (ppres->m_format.m_ftag == ftagString) { // Write the format string to the stream
if (FAILED(hr = ULToOLE1Stream (pos, 0L))) { return hr; } if (FAILED(hr = SizedDataToOLE1Stm (pos, ppres->m_format.m_dataFormatString))) { return hr; }
} else { AssertSz (0, "Bad format"); }
Assert (ppres->m_data.m_cbSize && ppres->m_data.m_h);
// Write the raw presentation data out
if (FAILED(hr = SizedDataToOLE1Stm (pos, ppres->m_data))) { return hr; }
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: wClassesMatchW, INTERNAL INLINE
//
// Synopsis: Worker function to compare classes. Special case for
// handling when the class of the file cannot be determined
// because it is not a real file; this returns NOERROR
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Cleaned up and documented
//
// Notes:
//
//--------------------------------------------------------------------------
inline INTERNAL wClassesMatchW(REFCLSID clsidIn, LPOLESTR szFile) { CLSID clsid;
// If we can get the CLSID for the code that works with this file,
// compare it to the CLSID passed in, and return the result of
// that comparison
if (NOERROR==GetClassFile (szFile, &clsid)) { if (IsEqualCLSID(clsid, clsidIn)) { return NOERROR; } else { return ResultFromScode(S_FALSE); } } else { // If we can't determine the class of the file (because it's
// not a real file) then OK.
// Bug 3937.
return NOERROR; } }
//+-------------------------------------------------------------------------
//
// Function: MonikerIntoGenObj, INTERNAL
//
// Synopsis: Merges an OLE 2.0 moniker into a generic object
//
// Effects: Sets ths Topic, Item, and class members
//
// Arguments: [pgenobj] -- the generic object to receive moniker
// [clsidLast] -- if a link, what its a link to
// [pmk] -- the moniker to merge in
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Code cleanup
//
// Notes:
//
//--------------------------------------------------------------------------
static INTERNAL MonikerIntoGenObj( PGENOBJ pgenobj, REFCLSID clsidLast, LPMONIKER pmk ) { LPOLESTR szFile=NULL; LPOLESTR szItem=NULL; BOOL fClassesMatch = FALSE;
// If the classes match, that implies this is a link to a pseudo-object
// not to an embedded object. If GetClassFile fails because the file
// does not exist or is unsaved then we give the link the benefit
// of the doubt and let it stay a link. Only if we know the
// classes do NOT match do we change the link into an Ole2Link
// embedded object.
// Ole10_PareMoniker returns S_FALSE in the FileMoniker - ItemMoniker - ItemMoniker... case
// so check for NOERROR explicitly.
if (NOERROR == Ole10_ParseMoniker (pmk, &szFile, &szItem)) { if (szFile) { SCODE sc = GetScode(wClassesMatchW(clsidLast, szFile)); if (sc == S_OK || sc == MK_E_CANTOPENFILE) { pgenobj->m_szTopic = szFile; pgenobj->m_szItem = szItem; fClassesMatch = TRUE; } } } if (FALSE == fClassesMatch) { // This moniker is either not a File or File::Item moniker,
// or is a link to an embedded object, so the only
// way we can convert it to OLE 1.0 is to make it an opaque Ole2Link
pgenobj->m_fLink = FALSE; pgenobj->m_class.Reset (CLSID_StdOleLink); }
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Function: OleConvertIStorageToOLESTREAMEx, STDAPI
//
// Synopsis: Similar to OleConvertIStorageToOLESTREAM, except that the
// presentation data that needs to be written into OLESTREAM
// is passed in. pmedium->tymed can only be TYMED_HGLOBAL
// or TYMED_ISTREAM and the medium will not be released by the
// api. cfFormat can be NULL, If it is NULL then the other
// parameters (lWidth, lHeight, dwSize, pmedium) will be ignored.
//
// Arguments: [pstg] -- the storage object to convert from
// [cfFormat] -- clipboard format
// [lWidth] -- width
// [lHeight] -- height
// [dwSize] -- size in bytes
// [pmedium] -- serialized bytes
// [polestm] -- the OLE 1 stream to write to
//
// Returns: NOERROR on success
// DV_E_TYMED invalid clipboard format
// E_INVALIDARG invalid arg, normally stg or stm
// DV_E_STGMEDIUM bad medium ptr
// E_OUTOFMEMORY allocation failure
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Cleaned up and documented
//
// Notes:
//
//--------------------------------------------------------------------------
STDAPI OleConvertIStorageToOLESTREAMEx ( LPSTORAGE pstg, CLIPFORMAT cfFormat, LONG lWidth, LONG lHeight, DWORD dwSize, LPSTGMEDIUM pmedium, LPOLESTREAM polestm ) {
OLETRACEIN((API_OleConvertIStorageToOLESTREAMEx, PARAMFMT("pstg= %p, cfFormat= %x, lWidth= %d, lHeight= %d, dwSize= %ud, pmedium= %ts, polestm= %p"), pstg, cfFormat, lWidth, lHeight, dwSize, pmedium, polestm));
LEDebugOut((DEB_ITRACE, "%p _IN OleConvertIStorageToOLESTREAMEx (" " %p, %x , %lx , %lx , %x , %p , %p )\n", 0 /*function*/, pstg, cfFormat, lWidth, lHeight, dwSize, pmedium, polestm )); CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStorage,(IUnknown **)&pstg);
HGLOBAL hGlobal = NULL; HRESULT hr = NOERROR; BOOL fFree = FALSE; CGenericObject genobj;
// If we are given a clipboard format...
if (cfFormat) {
VDATEPTRIN_LABEL(pmedium, STGMEDIUM, errRtn, hr);
// Check that the medium ptr is valid
if (pmedium->hGlobal == NULL) { hr = ResultFromScode(DV_E_STGMEDIUM); goto errRtn; }
// Cannot have a 0 sized clipboard representation
if (dwSize == 0) { hr = ResultFromScode(E_INVALIDARG); goto errRtn; }
switch (pmedium->tymed) { case TYMED_HGLOBAL: hGlobal = pmedium->hGlobal; break;
case TYMED_ISTREAM: VDATEIFACE_LABEL(pmedium->pstm, errRtn, hr); if ((hr = UtGetHGLOBALFromStm(pmedium->pstm, dwSize, &hGlobal)) != NOERROR) { goto errRtn; } fFree = TRUE; break;
default: hr = ResultFromScode(DV_E_TYMED); goto errRtn; } }
if (FAILED(hr = wConvertIStorageToOLESTREAM(pstg, polestm, &genobj))) { goto errRtn; }
// Clean m_ppres
if (genobj.m_ppres) { delete genobj.m_ppres; genobj.m_ppres = NULL; }
if (cfFormat) { // fill genobj.m_ppres
PPRES ppres;
if ((genobj.m_ppres = ppres = new PRES) == NULL) { hr = ResultFromScode(E_OUTOFMEMORY); goto errRtn; }
ppres->m_ulWidth = (ULONG) lWidth; ppres->m_ulHeight = (ULONG) lHeight; ppres->m_data.m_cbSize = dwSize; ppres->m_data.m_fNoFree = !fFree; ppres->m_data.m_h = hGlobal; ppres->m_data.m_pv = GlobalLock(hGlobal); ppres->m_format.m_ftag = ftagClipFormat; ppres->m_format.m_cf = cfFormat;
} else { genobj.m_fNoBlankPres = TRUE; }
// REVIEW: We may not want to allow NULL cfFormat with static object
hr = GenericObjectToOLESTREAM (genobj, polestm);
LEDebugOut((DEB_ITRACE, "%p OUT OleConvertIStorageToOLESTREAMEx ( %lx ) " "\n", 0 /*function*/, hr));
OLETRACEOUT((API_OleConvertIStorageToOLESTREAMEx, hr));
return hr;
errRtn:
if (fFree && hGlobal != NULL) { GlobalFree(hGlobal); }
LEDebugOut((DEB_ITRACE, "%p OUT OleConvertIStorageToOLESTREAMEx ( %lx ) " "\n", 0 /*function*/, hr));
OLETRACEOUT((API_OleConvertIStorageToOLESTREAMEx, hr));
return hr; }
//+-------------------------------------------------------------------------
//
// Function: OleConvertOLESTREAMToIStorageEx, STDAPI
//
// Synopsis: Similar to OleConvertOLESTREAMToIStorage, except that the
// presentation data that is read from OLESTREAM is passed out.
// And no presentation stream will written in to the storage.
// pmedium->tymed can be TYMED_ISTREAM ot TYMED_NULL. If
// TYMED_NULL, then the bits will be returned in a global
// handle through pmedium->hGlobal. Otherwise data will be
// written into pmedium->pstm. NULL will be returned through
// *pcfFormat, if there is no presentation in the OLESTREAM.
//
// Arguments: [pstg] -- the storage object to convert to
// [cfFormat] -- clipboard format
// [lWidth] -- width
// [lHeight] -- height
// [dwSize] -- size in bytes
// [pmedium] -- serialized bytes
// [polestm] -- the OLE 1 stream to write from
//
// Returns: DV_E_TYMED invalid clipboard format
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Cleaned up and documented
// Notes:
//
//--------------------------------------------------------------------------
STDAPI OleConvertOLESTREAMToIStorageEx ( LPOLESTREAM polestm, LPSTORAGE pstg, CLIPFORMAT FAR* pcfFormat, LONG FAR* plWidth, LONG FAR* plHeight, DWORD FAR* pdwSize, LPSTGMEDIUM pmedium ) { OLETRACEIN((API_OleConvertOLESTREAMToIStorageEx, PARAMFMT("polestm= %p, pstg= %p, pcfFormat= %p, plWidth= %p, plHeight= %p, pdwSize= %p, pmedium= %p"), polestm, pstg, pcfFormat, plWidth, plHeight, pdwSize, pmedium));
LEDebugOut((DEB_ITRACE, "%p _IN OleConvertOLESTREAMToIStorageEx (" " %p , %p , %p , %p , %p , %p , %p )\n", 0 /*function*/, polestm, pstg, pcfFormat,plWidth,plHeight,pdwSize,pmedium ));
HRESULT hr; PPRES ppres = NULL; GENOBJ genobj;
VDATEPTROUT_LABEL(pcfFormat, CLIPFORMAT, errRtn, hr); VDATEPTROUT_LABEL(plWidth, LONG, errRtn, hr); VDATEPTROUT_LABEL(plHeight, LONG, errRtn, hr); VDATEPTROUT_LABEL(pdwSize, DWORD, errRtn, hr); VDATEPTROUT_LABEL(pmedium, STGMEDIUM, errRtn, hr);
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStorage,(IUnknown **)&pstg);
if (pmedium->tymed == TYMED_ISTREAM) { VDATEIFACE_LABEL(pmedium->pstm, errRtn, hr); } else if (pmedium->tymed != TYMED_NULL) { hr = ResultFromScode(DV_E_TYMED); goto errRtn; }
// Bring the object into genobj
if (FAILED((hr = wConvertOLESTREAMToIStorage(polestm, pstg, &genobj)))) { goto errRtn; }
ppres = genobj.m_ppres; genobj.m_ppres = NULL;
if (FAILED(hr = GenericObjectToIStorage (genobj, pstg, NULL))) { goto errRtn; }
// If no presentation is available, clear our all the pres
// dimensions and format
if (ppres == NULL) { *pcfFormat = 0; *plWidth = 0L; *plHeight = 0L; *pdwSize = 0L;
// Don't worry about the pmedium, it is already in the proper state
hr = NOERROR; goto errRtn; }
// If we reach here, we have a presentation, so set the OUT
// parameters accordingly
*plWidth = (LONG) ppres->m_ulWidth; *plHeight = (LONG) ppres->m_ulHeight; *pdwSize = ppres->m_data.m_cbSize;
Assert(ppres->m_format.m_ftag != ftagNone);
// If we have a clipboard format ID, return that in the OUT paramter,
// otherwise return whatever we get back from an attempt to register
// the format string
if (ppres->m_format.m_ftag == ftagClipFormat) { *pcfFormat = ppres->m_format.m_cf; } else { // m_dataFormatString is an ASCII string.
*pcfFormat = (CLIPFORMAT) SSRegisterClipboardFormatA( (LPCSTR) ppres->m_format.m_dataFormatString.m_pv); Assert(0 != *pcfFormat); }
if (pmedium->tymed == TYMED_NULL) { if (ppres->m_data.m_h) { Assert(ppres->m_data.m_pv != NULL); GlobalUnlock(ppres->m_data.m_h); }
// transfer the ownership
pmedium->tymed = TYMED_HGLOBAL; pmedium->hGlobal = ppres->m_data.m_h;
// Null out the handle and pointer so that destructor of PRES will not
// free it.
ppres->m_data.m_h = NULL; ppres->m_data.m_pv = NULL;
} else { hr = pmedium->pstm->Write(ppres->m_data.m_pv, *pdwSize, NULL); }
errRtn:
if (ppres) { delete ppres; }
LEDebugOut((DEB_ITRACE, "%p OUT OleConvertOLESTREAMToIStorageEx ( %lx ) " "\n", 0 /*function*/, hr));
OLETRACEOUT((API_OleConvertOLESTREAMToIStorageEx, hr));
return hr; }
//+-------------------------------------------------------------------------
//
// Function: wWriteFmtUserType, INTERNAL
//
// Synopsis: Gets the user type for a class ID and writes it to
// an IStorage
//
//
// Arguments: [pstg] -- the storage to write to
// [clsid] -- the class ID
//
//
// Returns: NOERROR on success
//
// History: dd-mmm-yy Author Comment
// 21-Feb-94 davepl Cleaned up and documented
// Notes:
//
//--------------------------------------------------------------------------
FARINTERNAL wWriteFmtUserType(LPSTORAGE pstg, REFCLSID clsid) { HRESULT hr = NOERROR; LPOLESTR szProgID = NULL; LPOLESTR szUserType = NULL;
// Get the program ID
if (FAILED(hr = ProgIDFromCLSID (clsid, &szProgID))) { goto errRtn; }
// Get the user type
if (FAILED(hr = OleRegGetUserType(clsid,USERCLASSTYPE_FULL,&szUserType))) { goto errRtn; }
// Write the user type out to the storage
if (FAILED(hr = WriteFmtUserTypeStg (pstg, (CLIPFORMAT) RegisterClipboardFormat (szProgID), szUserType))) { goto errRtn; }
// Clean up and return status
errRtn:
if (szProgID) { PubMemFree(szProgID); } if (szUserType) { PubMemFree(szUserType); } return hr; }
//+-------------------------------------------------------------------------
//
// Function: wCLSIDFromProgID
//
// Synopsis: Looks for the key HKEY_CLASSES_ROOT\{ProgID}\Clsid\ to get
// the string version of the class ID, then returns the CLSID
// value of whatever it found.
//
// History: dd-mmm-yy Author Comment
// 25-Jun-94 alexgo fixed Ole1 CLSID creation
// 15-Apr-94 davepl Rewrite
//
// Notes: Used to be in clipboard code, but used in this file
//
//--------------------------------------------------------------------------
INTERNAL wCLSIDFromProgID(LPOLESTR szProgID, LPCLSID pclsid, BOOL fForceAssign) { VDATEHEAP();
// Apparently some optimization. If the class name is "OLE2Link", we can
// return CLSID_StdOleLInk without even bothering to check the registry.
if (0 == _xstrcmp(szProgID, OLESTR("OLE2Link"))) { *pclsid = CLSID_StdOleLink; return NOERROR; } else { // this function will look for a CLSID under the ProgID entry in
// the registry or manufacture one if none present.
return CLSIDFromOle1Class(szProgID, pclsid, fForceAssign); } }
//+-------------------------------------------------------------------------
//
// Function: wProgIDFromCLSID
//
// Synopsis: A wrapper for ProgIDFromCLSID. The only change in
// functionality is to check and see if this is a
// CLSID_StdOleLink, and if so, return a prog ID of
// "OLE2Link" rather than failing.
//
//
// History: dd-mmm-yy Author Comment
// 15-Feb-94 davepl Rewrite
//
//--------------------------------------------------------------------------
FARINTERNAL wProgIDFromCLSID(REFCLSID clsid, LPOLESTR FAR* psz) { VDATEHEAP();
HRESULT hresult;
// If we can get the ProgID by conventional methods, great, just
// return it.
if (NOERROR == (hresult = ProgIDFromCLSID(clsid, psz))) { return hresult; }
// If we failed, it might be because this is a standard OLE link, which
// will not have a ProgID entry in the registry, so we fake it out by
// returning the ProgID manually.
if (IsEqualCLSID(clsid, CLSID_StdOleLink)) { *psz = UtDupString(OLESTR("OLE2Link"));
if (*psz == NULL) { hresult = E_OUTOFMEMORY; } else { hresult = NOERROR; } }
// Must not have been able to resolve for ProgID, so return the error.
return(hresult); }
#if 0
// We don't need these conversion fns yet, but we likely will soon.
inline INTERNAL_(VOID) ConvertBM32to16(LPBITMAP lpsrc, LPWIN16BITMAP lpdest) { lpdest->bmType = (short)lpsrc->bmType; lpdest->bmWidth = (short)lpsrc->bmWidth; lpdest->bmHeight = (short)lpsrc->bmHeight; lpdest->bmWidthBytes = (short)lpsrc->bmWidthBytes; lpdest->bmPlanes = (BYTE)lpsrc->bmPlanes; lpdest->bmBitsPixel = (BYTE)lpsrc->bmBitsPixel; }
inline INTERNAL_(VOID) ConvertBM16to32(LPWIN16BITMAP lpsrc, LPBITMAP lpdest) { lpdest->bmType = MAKELONG(lpsrc->bmType,NULL_WORD); lpdest->bmWidth = MAKELONG(lpsrc->bmWidth,NULL_WORD); lpdest->bmHeight = MAKELONG(lpsrc->bmHeight,NULL_WORD); lpdest->bmWidthBytes = MAKELONG(lpsrc->bmWidthBytes,NULL_WORD); lpdest->bmPlanes = (WORD)lpsrc->bmPlanes; lpdest->bmBitsPixel = (WORD)lpsrc->bmBitsPixel; }
inline INTERNAL_(VOID) ConvertMF16to32( LPWIN16METAFILEPICT lpsrc, LPMETAFILEPICT lpdest ) { lpdest->mm = (DWORD)lpsrc->mm; lpdest->xExt = (DWORD)MAKELONG(lpsrc->xExt,NULL_WORD); lpdest->yExt = (DWORD)MAKELONG(lpsrc->yExt,NULL_WORD); }
inline INTERNAL_(VOID) ConvertMF32to16( LPMETAFILEPICT lpsrc, LPWIN16METAFILEPICT lpdest ) { lpdest->mm = (short)lpsrc->mm; lpdest->xExt = (short)lpsrc->xExt; lpdest->yExt = (short)lpsrc->yExt; }
#endif
|