1477 lines
43 KiB
C++
1477 lines
43 KiB
C++
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1994.
|
|
//
|
|
// File: privstm.cpp
|
|
//
|
|
// Contents: Handles all reading/writing of the \1CompObj stream
|
|
//
|
|
// Functions: Implements:
|
|
//
|
|
// INTERNAL ReadCompObjStm
|
|
// INTERNAL WriteCompObjStm
|
|
// INTERNAL ClipfmtToStm
|
|
// INTERNAL StmToClipfmt
|
|
// INTERNAL GetUNICODEUserType
|
|
// INTERNAL GetUNICODEProgID
|
|
// INTERNAL GetUNICODEClipFormat
|
|
// INTERNAL PutUNICODEUserType
|
|
// INTERNAL PutUNICODEProgID
|
|
// INTERNAL PutUNICODEClipFormat
|
|
// INTERNAL UtGetUNICODEData
|
|
// INTERNAL ANSIStrToStm
|
|
// INTERNAL ANSIStmToStr
|
|
//
|
|
// STDAPI WriteFmtUserTypeStg
|
|
// STDAPI ReadFmtUserTypeStg
|
|
// STDAPI ReadFmtProgIdStg
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 08-Feb-94 davepl Created
|
|
//
|
|
//
|
|
// Notes: The CompObj stream (in 16-bit OLE) contained fields for
|
|
// the ClassID, UserType, Clipboard format, and (in later
|
|
// versions only) ProgID. These were always written in ANSI
|
|
// format.
|
|
//
|
|
// The file format has been extended such that ANSI data is
|
|
// written to the stream in much the same way as before. The
|
|
// key difference is that in the event the internal UNICODE
|
|
// versions of this data cannot be losslessly converted to
|
|
// ANSI, the ANSI version is written as a NULL string, and
|
|
// the UNICODE version follows at the end of the stream. This
|
|
// way, 16-bit apps see as much of what they expect as possible,
|
|
// and 32-bit apps can write UNICODE transparently in a
|
|
// backwards-compatible way.
|
|
//
|
|
// The file format of the stream is:
|
|
//
|
|
// (A) WORD Byte Order
|
|
// WORD Format Version
|
|
// DWORD Original OS ver Always Windows 3.1
|
|
// DWORD -1
|
|
// CLSID Class ID
|
|
// ULONG Length of UserType
|
|
// <var> User Type string ANSI
|
|
// <var> Clipformat ANSI (when using string tag)
|
|
// ----------------------------
|
|
// (B) ULONG Length of Prog ID
|
|
// <var> Prog ID ANSI (not always present)
|
|
// ----------------------------
|
|
// (C) ULONG Magic Number Signified UNICODE data present
|
|
// ULONG Length of UserType
|
|
// ULONG User Type string UNICODE
|
|
// <var> Clipformat UNICODE (when tag is string)
|
|
// ULONG Length of Prog ID
|
|
// <var> Prog ID UNICODE
|
|
//
|
|
// Section (A) is always present. Section (B) is present when
|
|
// stream has been written by a later 16-bit app or by a
|
|
// 32-bit app. Section (C) is present when written by a
|
|
// 32-bit app.
|
|
//
|
|
// If a string is present in UNICODE, the ANSI version will be
|
|
// NULL (a zero for length and _no_ <var> data). When the
|
|
// UNICODE section is present, strings that were not needed
|
|
// because the ANSI conversion was successful are written
|
|
// as NULL (again, zero len and no <var> data).
|
|
//
|
|
// A NULL clipboard format is written as a 0 tag.
|
|
//
|
|
// In order to read any field, the entire string is read into
|
|
// an internal object, and the fields are extracted individually.
|
|
// In order to write an fields, the stream is read into the
|
|
// object (if possible), the fields updated, and then rewritten
|
|
// as an atomic object.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#include <le2int.h>
|
|
|
|
static const ULONG COMP_OBJ_MAGIC_NUMBER = 0x71B239F4;
|
|
|
|
#define MAX_CFNAME 400 // Maximum size of a clipformat name
|
|
// (my choice, none documented)
|
|
|
|
const DWORD gdwFirstDword = (DWORD)MAKELONG(COMPOBJ_STREAM_VERSION,
|
|
BYTE_ORDER_INDICATOR);
|
|
|
|
enum TXTTYPE
|
|
{
|
|
TT_UNICODE = 0, TT_ANSI = 1
|
|
};
|
|
|
|
// This is the data object into which the stream is read prior to
|
|
// extracting fields.
|
|
|
|
struct CompObjHdr // The leading data in the CompObj stream
|
|
{
|
|
DWORD m_dwFirstDword; // First DWORD, byte order and format ver
|
|
DWORD m_dwOSVer; // Originating OS Ver (eg: Win31)
|
|
DWORD m_unused; // Always a -1L in the stream
|
|
CLSID m_clsClass; // Class ID of this object
|
|
};
|
|
|
|
class CompObjStmData : public CPrivAlloc
|
|
{
|
|
public:
|
|
|
|
CompObjHdr m_hdr;
|
|
ULONG m_cchUserType; // Number of CHARACTERS in UserType
|
|
ULONG m_cchProgID; // Number of CHARACTERS in ProgID
|
|
DWORD m_dwFormatTag; // Clipformat type (none, string, clip, etc)
|
|
ULONG m_ulFormatID; // If tag is std clipformat, what type?
|
|
|
|
LPOLESTR m_pszOUserType; // Pointer to OLESTR UserType
|
|
LPOLESTR m_pszOProgID; // Pointer to OLESTR ProgID
|
|
|
|
LPSTR m_pszAUserType; // Pointer to ANSI UserType
|
|
LPSTR m_pszAProgID; // Pointer to ANSI ProgID
|
|
|
|
TXTTYPE ttClipString; // Format needed for the clipformat string
|
|
|
|
CompObjStmData(void)
|
|
{
|
|
memset(this, 0, sizeof(CompObjStmData));
|
|
ttClipString = TT_ANSI; // By default, use ANSI Clipformat
|
|
};
|
|
|
|
~CompObjStmData(void)
|
|
{
|
|
PubMemFree(m_pszOUserType);
|
|
PubMemFree(m_pszOProgID);
|
|
PubMemFree(m_pszAUserType);
|
|
PubMemFree(m_pszAProgID);
|
|
};
|
|
};
|
|
|
|
// Prototypes for fns declared in this file
|
|
|
|
INTERNAL ReadCompObjStm (IStorage *, CompObjStmData *);
|
|
INTERNAL WriteCompObjStm (IStorage *, CompObjStmData *);
|
|
INTERNAL ClipfmtToStm (CStmBufWrite &, ULONG, ULONG, TXTTYPE);
|
|
INTERNAL StmToClipfmt (CStmBufRead &, DWORD *, DWORD *, TXTTYPE);
|
|
INTERNAL GetUNICODEUserType (CompObjStmData *, LPOLESTR *);
|
|
INTERNAL GetUNICODEProgID (CompObjStmData *, LPOLESTR *);
|
|
INTERNAL GetClipFormat (CompObjStmData *, DWORD *, DWORD *);
|
|
INTERNAL PutUNICODEUserType (CompObjStmData *, LPOLESTR);
|
|
INTERNAL PutUNICODEProgID (CompObjStmData *, LPOLESTR);
|
|
INTERNAL PutClipFormat (CompObjStmData *, DWORD, DWORD);
|
|
INTERNAL ANSIStrToStm (CStmBufWrite &, LPCSTR);
|
|
INTERNAL ANSIStmToStr (CStmBufRead & StmRead, LPSTR * pstr, ULONG *);
|
|
|
|
STDAPI WriteFmtUserTypeStg (IStorage *, CLIPFORMAT, LPOLESTR);
|
|
STDAPI ReadFmtUserTypeStg (IStorage *, CLIPFORMAT *, LPOLESTR *);
|
|
STDAPI ReadFmtProgIdStg (IStorage *, LPOLESTR *);
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: ReadCompObjStm, PRIVATE INTERNAL
|
|
//
|
|
// Synopsis: Reads the \1CompObj stream into an internal data structure
|
|
// that will contain the best-case representation of that
|
|
// stream (ie: ANSI where possible, UNICODE where needed).
|
|
//
|
|
// Effects: Reads ANSI data where available. At end of standard ANSI
|
|
// data, looks for ANSI ProgID field. If found, looks for
|
|
// MagicNumber indicating UNICODE data is to follow. If this
|
|
// matches, UNICODE strings are pulled from the stream. They
|
|
// should only be found where the ANSI version was NULL
|
|
// (because it could not be converted from UNICODE).
|
|
//
|
|
// Capable of reading 3 stream formats seamlessly:
|
|
// - Original ANSI sans ProgID field
|
|
// - Extended OLE 2.01 version with ProgID
|
|
// - Extended OLE 2/32 version with ProgID and UNICODE extensions
|
|
//
|
|
// Arguments: [pstg] -- ptr to IStorage to read from
|
|
// [pcod] -- ptr to already-allocated CompObjData object
|
|
//
|
|
// Returns: NOERROR on success
|
|
// INVALIDARG on missing pcod
|
|
// Various I/O on stream missing, read errors, etc
|
|
// E_OUTOFMEMORY on any allocation failure
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 08-Mar-94 davepl Created
|
|
//
|
|
// Notes: Any memory allocated herein will be allocated on
|
|
// pointers in the pcod object, which will be freed by its
|
|
// destructor when it exits scope or is deleted explicitly.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
INTERNAL ReadCompObjStm(IStorage * pstg, CompObjStmData * pcod)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT hr; // Result code
|
|
const ULONG RESERVED = 0; // For reserved parameters
|
|
ULONG ulSize = 0; // Holder for length of ProgID string
|
|
BOOL fExtStm = 1; // Could this be ext with UNICODE?
|
|
CStmBufRead StmRead;
|
|
|
|
|
|
Win4Assert(pcod);
|
|
|
|
// Validate the pstg interface
|
|
VDATEIFACE(pstg);
|
|
|
|
// Open the CompObj stream
|
|
if (FAILED(hr = StmRead.OpenStream(pstg, COMPOBJ_STREAM))) // L"\1CompObj"
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
// Read the header from the CompObj stream:
|
|
//
|
|
// WORD Byte Order Indicator 02 bytes
|
|
// WORD Format version 02 bytes
|
|
// DWORD Originating OS version 04 bytes
|
|
// DWORD -1 04 bytes
|
|
// CLSID Class ID 16 bytes
|
|
// --------
|
|
// 28 bytes == sizeof(dwBuf)
|
|
|
|
Win4Assert(sizeof(CompObjHdr) == 28 &&
|
|
"Warning: possible packing error in CompObjHdr struct");
|
|
|
|
hr = StmRead.Read(&pcod->m_hdr, sizeof(CompObjHdr));
|
|
if (FAILED(hr))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
// NB: There used to be a check against the OS version here,
|
|
// but since the version number has been forced to always
|
|
// be written as Win3.1, checking it would be redundant.
|
|
|
|
// Win4Assert(pcod->m_hdr.m_dwOSVer == 0x00000a03);
|
|
#if DBG==1
|
|
if (pcod->m_hdr.m_dwOSVer != 0x00000a03)
|
|
{
|
|
LEDebugOut((DEB_WARN, "ReadCompObjStm found unexpected OSVer %lx",
|
|
pcod->m_hdr.m_dwOSVer));
|
|
}
|
|
#endif
|
|
|
|
// Get the User type string from the stream (ANSI FORMAT!)
|
|
if (FAILED(hr = ANSIStmToStr(StmRead, &pcod->m_pszAUserType,
|
|
&pcod->m_cchUserType)))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
// Get the clipboard format data from the stream
|
|
if (FAILED(hr = StmToClipfmt(StmRead, // Stream to read from
|
|
&pcod->m_dwFormatTag, // DWORD clip format
|
|
&pcod->m_ulFormatID, // DWORD clip type
|
|
TT_ANSI))) // Use ANSI
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
// We have to special-case the ProgID field, because it may not
|
|
// be present in objects written by early (pre-2.01) versions
|
|
// of OLE. We only continue when ProgID can be found, but
|
|
// its absence is not an error, so return what we have so far.
|
|
|
|
hr = StmRead.Read(&ulSize, sizeof(ULONG));
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// We were unable to read the size field; make sure ulSize is 0
|
|
ulSize = 0;
|
|
}
|
|
|
|
// The ProgID can be no longer than 39 chars plus a NULL. Other
|
|
// numbers likely indicate garbage.
|
|
|
|
if (ulSize > 40 || 0 == ulSize)
|
|
{
|
|
#if DBG==1
|
|
if (ulSize > 40)
|
|
{
|
|
LEDebugOut((DEB_WARN,"ReadCompObjStm: ulSize > 40 for ProgID\n"));
|
|
}
|
|
#endif
|
|
fExtStm = 0; // No ProgID implies no UNICODE to follow
|
|
}
|
|
|
|
// If it looks like we have a hope of findind the ProgID and maybe
|
|
// even UNICODE, try to fetch the ProdID
|
|
|
|
if (fExtStm)
|
|
{
|
|
// Allocate memory for string on our ProgID pointer
|
|
pcod->m_pszAProgID = (char *) PubMemAlloc(ulSize);
|
|
if (NULL == pcod->m_pszAProgID)
|
|
{
|
|
hr = ResultFromScode(E_OUTOFMEMORY);
|
|
goto errRtn;
|
|
}
|
|
if (FAILED(hr = StmRead.Read(pcod->m_pszAProgID, ulSize)))
|
|
{
|
|
// OK, we give up on ProgID and the UNICODE, but that's
|
|
// _not_ reason to fail, since ProgID could just be missing
|
|
|
|
pcod->m_cchProgID = 0;
|
|
PubMemFree(pcod->m_pszAProgID);
|
|
pcod->m_pszAProgID = NULL;
|
|
fExtStm = 0;
|
|
}
|
|
else
|
|
{
|
|
// We managed to get ProgID from the stream, so set the
|
|
// length in pcod and go looking for the UNICODE...
|
|
pcod->m_cchProgID = ulSize;
|
|
}
|
|
}
|
|
|
|
// See if we can find the Magic number
|
|
|
|
DWORD dwMagic;
|
|
if (fExtStm)
|
|
{
|
|
if (FAILED(StmRead.Read(&dwMagic, sizeof(dwMagic))))
|
|
{
|
|
fExtStm = 0;
|
|
}
|
|
}
|
|
|
|
if (fExtStm && dwMagic != COMP_OBJ_MAGIC_NUMBER)
|
|
{
|
|
fExtStm = 0;
|
|
}
|
|
|
|
// If fExtStm is still TRUE, we go ahead and read the UNICODE
|
|
|
|
if (fExtStm)
|
|
{
|
|
// Get the UNICODE version of the user type
|
|
if (FAILED(hr = ReadStringStream(StmRead, &pcod->m_pszOUserType)))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
// Get the clipboard format (UNICODE)
|
|
|
|
DWORD dwFormatTag;
|
|
ULONG ulFormatID;
|
|
if (FAILED(hr = StmToClipfmt(StmRead, // Stream to read from
|
|
&dwFormatTag, // DWORD clip format
|
|
&ulFormatID, // DWORD clip type
|
|
TT_UNICODE))) // Use UNICODE
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
// If we found some form of clipboard format, that implies the ANSI
|
|
// was missing, so set up all of the fields based on this data.
|
|
|
|
if (dwFormatTag)
|
|
{
|
|
pcod->m_dwFormatTag = dwFormatTag;
|
|
pcod->m_ulFormatID = ulFormatID;
|
|
}
|
|
|
|
// Get the UNICODE version of the ProgID. If there was any UNICODE at
|
|
// all, we know for sure there is a UNICODE ProgID, so no special casing
|
|
// as was needed for the ANSI version
|
|
|
|
if (FAILED(hr = ReadStringStream(StmRead, &pcod->m_pszOProgID)))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
if (pcod->m_pszOProgID)
|
|
{
|
|
pcod->m_cchProgID = _xstrlen(pcod->m_pszOProgID) + 1;
|
|
}
|
|
}
|
|
|
|
// We successfully read the CompObj stream
|
|
hr = NOERROR;
|
|
|
|
errRtn:
|
|
|
|
StmRead.Release();
|
|
|
|
return(hr);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: StmToClipfmt, PRIVATE INTERNAL
|
|
//
|
|
// Synopsis: Reads the clipboard format from the given stream. Caller
|
|
// specifies whether or not the string format description,
|
|
// if present, should be expected in ANSI or UNICODE format.
|
|
//
|
|
// Effects: If the clipboard format is a length followed by a
|
|
// string, then the string is read and registered as a
|
|
// clipboard format (and the new format number is returned).
|
|
//
|
|
// Arguments: [lpstream] -- pointer to the stream
|
|
// [lpdwCf] -- where to put the clipboard format
|
|
// [lpdTag] -- format type (string, clip, etc)
|
|
// [ttType] -- text type TT_ANSI or TT_UNICODE
|
|
//
|
|
// Returns: hr
|
|
//
|
|
// Algorithm: the format of the stream must be one of the following:
|
|
//
|
|
// 0 No clipboard format
|
|
// -1 DWORD predefined windows clipboard format in
|
|
// the second dword.
|
|
// -2 DWORD predefined mac clipboard format in the
|
|
// second dword. This may be obsolete or
|
|
// irrelevant for us. REVIEW32
|
|
// num STRING clipboard format name string (prefaced
|
|
// by length of string).
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 08-Mar-94 davepl Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
INTERNAL StmToClipfmt
|
|
(CStmBufRead & StmRead,
|
|
DWORD * lpdTag,
|
|
DWORD * lpdwCf,
|
|
TXTTYPE ttText)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT hr;
|
|
DWORD dwValue;
|
|
|
|
VDATEPTROUT(lpdwCf, DWORD);
|
|
|
|
Win4Assert (lpdwCf); // These ptrs are always required
|
|
Win4Assert (lpdTag);
|
|
|
|
// Read the format type tag from the stream
|
|
|
|
if (FAILED(hr = StmRead.Read(&dwValue, sizeof(DWORD))))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
*lpdTag = dwValue;
|
|
|
|
// If the tag is zero, there is no clipboard format info
|
|
|
|
if (dwValue == 0)
|
|
{
|
|
*lpdwCf = 0; // NULL cf value
|
|
}
|
|
|
|
// If it is -1, then it is a standard Windows clipboard format
|
|
|
|
else if (dwValue == -1L)
|
|
{
|
|
// Then this is a NON-NULL predefined windows clipformat.
|
|
// The clipformat values follows
|
|
|
|
if (FAILED(hr = StmRead.Read(&dwValue, sizeof(DWORD))))
|
|
{
|
|
return hr;
|
|
}
|
|
*lpdwCf = dwValue;
|
|
}
|
|
|
|
// If it is -2, it is a MAC format
|
|
|
|
else if (dwValue == -2L)
|
|
{
|
|
// Then this is a NON-NULL MAC clipboard format.
|
|
// The clipformat value follows. For MAC the CLIPFORMAT
|
|
// is 4 bytes
|
|
|
|
if (FAILED(hr = StmRead.Read(&dwValue, sizeof(DWORD))))
|
|
{
|
|
return hr;
|
|
}
|
|
*lpdwCf = dwValue;
|
|
return ResultFromScode(OLE_S_MAC_CLIPFORMAT);
|
|
}
|
|
|
|
// Anything but a 0, -1, or -2 indicates a string is to follow, and the
|
|
// DWORD we already read is the length of the that string
|
|
|
|
else
|
|
{
|
|
// Allocate enough memory for whatever type of string it is
|
|
// we expect to find, and read the string
|
|
|
|
if (dwValue > MAX_CFNAME)
|
|
{
|
|
return ResultFromScode(DV_E_CLIPFORMAT);
|
|
}
|
|
|
|
if (TT_ANSI == ttText) // READ ANSI
|
|
{
|
|
char szCf[MAX_CFNAME];
|
|
|
|
if (FAILED(hr = StmRead.Read(szCf, dwValue)))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Try to register the clipboard format and return the result
|
|
// (Note: must explicitly call ANSI version)
|
|
|
|
if (((*lpdwCf = (DWORD) SSRegisterClipboardFormatA(szCf))) == 0)
|
|
{
|
|
return ResultFromScode(DV_E_CLIPFORMAT);
|
|
}
|
|
}
|
|
else // READ UNICODE
|
|
{
|
|
OLECHAR wszCf[MAX_CFNAME];
|
|
|
|
Win4Assert(dwValue < MAX_CFNAME);
|
|
if (FAILED(hr=StmRead.Read(wszCf, dwValue * sizeof(OLECHAR))))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
// Try to register the clipboard format and return the result
|
|
|
|
if (((*lpdwCf = (DWORD) RegisterClipboardFormat(wszCf))) == 0)
|
|
{
|
|
return ResultFromScode(DV_E_CLIPFORMAT);
|
|
}
|
|
}
|
|
}
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: GetUNICODEUserType, PRIVATE INTERNAL
|
|
//
|
|
// Synopsis: Given a CompObjStmData object, returns the User Type
|
|
// in UNICODE format, converting the ANSI rep as required.
|
|
//
|
|
// Effects: Allocates memory on the caller's ptr to hold the string
|
|
//
|
|
// Arguments: [pcod] -- The CompObjStmData object
|
|
// [pstr] -- Pointer to allocate resultant string on
|
|
//
|
|
// Returns: NOERROR on success
|
|
// E_OUTOFMEMORY on allocation failure
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 08-Mar-94 davepl Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
INTERNAL GetUNICODEUserType
|
|
( CompObjStmData * pcod,
|
|
LPOLESTR * pstr )
|
|
{
|
|
VDATEHEAP();
|
|
HRESULT hr = NOERROR;
|
|
|
|
// Validate and NULL the OUT parameter, or return if none given
|
|
if (pstr)
|
|
{
|
|
VDATEPTROUT(pstr, LPOLESTR);
|
|
*pstr = NULL;
|
|
}
|
|
else
|
|
{
|
|
return(NOERROR);
|
|
}
|
|
|
|
// Either get the UNICODE string, or convert the ANSI version and
|
|
// get it as UNICODE.
|
|
|
|
if (pcod->m_cchUserType)
|
|
{
|
|
hr = UtGetUNICODEData( pcod->m_cchUserType,
|
|
pcod->m_pszAUserType,
|
|
pcod->m_pszOUserType,
|
|
pstr );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: GetUNICODEProgID, PRIVATE INTERNAL
|
|
//
|
|
// Synopsis: Given a CompObjStmData object, returns the ProgID string
|
|
// in UNICODE format, converting the ANSI rep as required.
|
|
//
|
|
// Effects: Allocates memory on the caller's ptr to hold the string
|
|
//
|
|
// Arguments: [pcod] -- The CompObjStmData object
|
|
// [pstr] -- Pointer to allocate resultant string on
|
|
//
|
|
// Returns: NOERROR on success
|
|
// E_OUTOFMEMORY on allocation failure
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 08-Mar-94 davepl Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
INTERNAL GetUNICODEProgID
|
|
( CompObjStmData * pcod,
|
|
LPOLESTR * pstr )
|
|
{
|
|
VDATEHEAP();
|
|
HRESULT hr = NOERROR;
|
|
|
|
// Validate and NULL the OUT parameter, or return if none given
|
|
if (pstr)
|
|
{
|
|
VDATEPTROUT(pstr, LPOLESTR);
|
|
*pstr = NULL;
|
|
}
|
|
else
|
|
{
|
|
return(NOERROR);
|
|
}
|
|
|
|
// Either get the UNICODE string, or convert the ANSI version and
|
|
// get it as UNICODE.
|
|
|
|
if (pcod->m_cchProgID)
|
|
{
|
|
hr = UtGetUNICODEData( pcod->m_cchProgID,
|
|
pcod->m_pszAProgID,
|
|
pcod->m_pszOProgID,
|
|
pstr );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: GetClipFormat, PRIVATE INTERNAL
|
|
//
|
|
// Synopsis: Given a CompObjStmData object, extracts the clipboard format
|
|
// type (none, standard, string).
|
|
//
|
|
// Effects: If string type, memory is allocated on the caller's ptr
|
|
//
|
|
// Arguments: [pcod] -- The CompObjStmData object to extract from
|
|
// [pdwFormatID] -- Tag type OUT parameter
|
|
// [pdwFormatTag] -- Tag OUT parameter
|
|
//
|
|
// Returns: NOERROR on success
|
|
// E_OUTOFMEMORY on allocation failures
|
|
// OLE_S_MAC_CLIPFORMAT as a warning that a MAC fmt is returned
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 08-Mar-94 davepl Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
INTERNAL GetClipFormat
|
|
( CompObjStmData * pcod,
|
|
DWORD * pdwFormatID,
|
|
DWORD * pdwFormatTag )
|
|
{
|
|
VDATEHEAP();
|
|
*pdwFormatTag = (DWORD) pcod->m_dwFormatTag;
|
|
*pdwFormatID = pcod->m_ulFormatID;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: PutUNICODEUserType, PRIVATE INTERNAL
|
|
//
|
|
// Synopsis: Given a UNICODE string, stores it in the CompObjDataStm
|
|
// object in ANSI if possible. If the UNICODE -> ANSI
|
|
// conversion is not possible, it is stored in the object
|
|
// in UNICODE.
|
|
//
|
|
// Notes: Input string is duplicated, so it adds no references
|
|
// to the string passed in.
|
|
//
|
|
// Arguments: [pcod] -- The CompObjDataStm object
|
|
// [szUser] -- The UNICODE UserType string
|
|
//
|
|
// Returns: NOERROR on success
|
|
// E_OUTOFMEMORY on allocation failure
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 08-Mar-94 davepl Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
INTERNAL PutUNICODEUserType(CompObjStmData * pcod, LPOLESTR szUser)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT hr;
|
|
|
|
// If no string supplied, clear UserType fields, otherwise
|
|
// if it can be converted to ANSI, store it an ANSI. Last
|
|
// resort, store it as UNICODE.
|
|
|
|
if (NULL == szUser)
|
|
{
|
|
pcod->m_cchUserType = 0;
|
|
|
|
PubMemFree(pcod->m_pszAUserType);
|
|
PubMemFree(pcod->m_pszOUserType);
|
|
pcod->m_pszAUserType = NULL;
|
|
pcod->m_pszOUserType = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (FAILED(hr = UtPutUNICODEData( _xstrlen(szUser)+1,
|
|
szUser,
|
|
&pcod->m_pszAUserType,
|
|
&pcod->m_pszOUserType,
|
|
&pcod->m_cchUserType )))
|
|
{
|
|
return(hr);
|
|
}
|
|
|
|
}
|
|
return(NOERROR);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: PutUNICODEProgID, PRIVATE INTERNAL
|
|
//
|
|
// Synopsis: Given a UNICODE string, stores it in the CompObjDataStm
|
|
// object in ANSI if possible. If the UNICODE -> ANSI
|
|
// conversion is not possible, it is stored in the object
|
|
// in UNICODE.
|
|
//
|
|
// Notes: Input string is duplicated, so it adds no references
|
|
// to the string passed in.
|
|
//
|
|
// Arguments: [pcod] -- The CompObjDataStm object
|
|
// [szProg] -- The UNICODE ProgID string
|
|
//
|
|
// Returns: NOERROR on success
|
|
// E_OUTOFMEMORY on allocation failure
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 08-Mar-94 davepl Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
INTERNAL PutUNICODEProgID(CompObjStmData * pcod, LPOLESTR szProg)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT hr;
|
|
|
|
// If no string supplied, clear ProgID fields, otherwise
|
|
// if it can be converted to ANSI, store it an ANSI. Last
|
|
// resort, store it as UNICODE.
|
|
|
|
if (NULL == szProg)
|
|
{
|
|
pcod->m_cchProgID = 0;
|
|
PubMemFree(pcod->m_pszAProgID);
|
|
PubMemFree(pcod->m_pszOProgID);
|
|
pcod->m_pszAProgID = NULL;
|
|
pcod->m_pszOProgID = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (FAILED(hr = UtPutUNICODEData( _xstrlen(szProg)+1,
|
|
szProg,
|
|
&pcod->m_pszAProgID,
|
|
&pcod->m_pszOProgID,
|
|
&pcod->m_cchProgID )))
|
|
{
|
|
return(hr);
|
|
}
|
|
|
|
}
|
|
return(NOERROR);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: PutClipFormat
|
|
//
|
|
// Synopsis: Stores the clipformat in the internal data structure
|
|
//
|
|
// Effects: Input string is duplicated as required, so no references are
|
|
// kept by this function.
|
|
//
|
|
// Arguments: [pcod] -- The CompObjStmData object
|
|
// [dwFormatTag] -- Format tag (string, clipboard, none)
|
|
// [ulFormatID] -- If format tag is clipboard, what format
|
|
//
|
|
// Returns: NOERROR on success
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 08-Mar-94 davepl Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
INTERNAL PutClipFormat
|
|
( CompObjStmData * pcod,
|
|
DWORD dwFormatTag,
|
|
ULONG ulFormatID
|
|
)
|
|
{
|
|
VDATEHEAP();
|
|
pcod->m_dwFormatTag = (ULONG) dwFormatTag;
|
|
pcod->m_ulFormatID = ulFormatID;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: WriteCompObjStm, PRIVATE INTERNAL
|
|
//
|
|
// Synopsis: Writes CompObjStmData object to the CompObj stream in
|
|
// the IStorage provided.
|
|
//
|
|
// First the ANSI fields are written (including the ProgID),
|
|
// followed by a MagicNumber, followed by whatever OLESTR
|
|
// versions were required because ANSI fields could not be
|
|
// converted.
|
|
//
|
|
// Destroys any existing CompObj stream!
|
|
//
|
|
// Arguments: [pstg] -- The IStorage to write the stream to
|
|
// [pcod] -- The CompObjStmData object to write out
|
|
//
|
|
// Returns: NOERROR on success
|
|
// E_OUTOFMEMORY on allocation failure
|
|
// Various I/O on stream failures
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 08-Mar-94 davepl Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
INTERNAL WriteCompObjStm(IStorage * pstg, CompObjStmData * pcod)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT hr = NOERROR;
|
|
const ULONG RESERVED = 0;
|
|
const ULONG ulMagic = COMP_OBJ_MAGIC_NUMBER;
|
|
CStmBufWrite StmWrite;
|
|
|
|
|
|
// The CompObjStmData parameter must be supplied
|
|
if (NULL == pcod)
|
|
{
|
|
return ResultFromScode(E_INVALIDARG);
|
|
}
|
|
|
|
VDATEIFACE(pstg);
|
|
|
|
// Open the CompObj stm for writing (and overwrite it if
|
|
// if already exists, which is why we _don't_ specify the
|
|
// STGM_FAILIFTHERE flag)
|
|
|
|
if (FAILED(hr = StmWrite.CreateStream(pstg, COMPOBJ_STREAM)))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
// Set up the header
|
|
|
|
pcod->m_hdr.m_dwFirstDword = gdwFirstDword;
|
|
|
|
// The OSVer _must_ be Win 3.10 (0a03), since the old DLL will bail if
|
|
// it finds anything else.
|
|
|
|
pcod->m_hdr.m_dwOSVer = 0x00000a03; // gdwOrgOSVersion;
|
|
pcod->m_hdr.m_unused = (DWORD) -1;
|
|
|
|
if (ReadClassStg(pstg, &pcod->m_hdr.m_clsClass) != NOERROR)
|
|
{
|
|
pcod->m_hdr.m_clsClass = CLSID_NULL;
|
|
}
|
|
|
|
// Write the CompObj stream header
|
|
|
|
Win4Assert(sizeof(CompObjHdr) == 28 &&
|
|
"Warning: possible packing error in CompObjHdr struct");
|
|
|
|
if (FAILED(hr = StmWrite.Write(pcod, sizeof(CompObjHdr))))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
// Write the ANSI UserType
|
|
|
|
if (FAILED(hr = ANSIStrToStm(StmWrite, pcod->m_pszAUserType)))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
if (TT_ANSI == pcod->ttClipString)
|
|
{
|
|
if (FAILED(hr = ClipfmtToStm(StmWrite, // the stream
|
|
pcod->m_dwFormatTag, // format tag
|
|
pcod->m_ulFormatID, // format ID
|
|
TT_ANSI)))// TRUE==use ANSI
|
|
{
|
|
goto errRtn;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const ULONG ulDummy = 0;
|
|
if (FAILED(hr = StmWrite.Write(&ulDummy, sizeof(ULONG))))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
}
|
|
|
|
// Write the ANSI ProgID
|
|
|
|
if (FAILED(hr = ANSIStrToStm(StmWrite, pcod->m_pszAProgID)))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
// Write the Magic Number
|
|
|
|
if (FAILED(hr = StmWrite.Write(&ulMagic, sizeof(ULONG))))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
// Write the OLESTR version of UserType
|
|
|
|
if (FAILED(hr = WriteStringStream(StmWrite, pcod->m_pszOUserType)))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
// If we have to write a UNICODE clipformat string, do it now. If
|
|
// ANSI was sufficient, just write a 0 to the stream here.
|
|
|
|
if (TT_UNICODE == pcod->ttClipString)
|
|
{
|
|
if (FAILED(hr = ClipfmtToStm(StmWrite, // the stream
|
|
pcod->m_dwFormatTag, // format tag
|
|
pcod->m_ulFormatID, // format ID
|
|
TT_UNICODE))) // FALSE==use UNICODE
|
|
{
|
|
goto errRtn;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const ULONG ulDummy = 0;
|
|
if (FAILED(hr = StmWrite.Write(&ulDummy, sizeof(ULONG))))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
}
|
|
|
|
// Write the OLESTR version of ProgID
|
|
|
|
if (FAILED(hr = WriteStringStream(StmWrite, pcod->m_pszOProgID)))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
|
|
hr = StmWrite.Flush();
|
|
|
|
// That's it.. clean up and exit
|
|
|
|
errRtn:
|
|
|
|
StmWrite.Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: ClipFtmToStm, PRIVATE INTERNAL
|
|
//
|
|
// Synopsis: Writes out the clipboard format information at the
|
|
// current point in the stream. A flag is available
|
|
// to specify whether or not the string format desc
|
|
// (if present) is in ANSI or UNICODE format.
|
|
//
|
|
// Arguments: [pstm] -- the stream to write to
|
|
// [dwFormatTag] -- format tag (string, clipfmt, etc)
|
|
// [ulFormatID] -- if clipfmt, which one
|
|
// [szClipFormat] -- if string format, the string itself
|
|
// [ttText] -- text type: TT_ANSI or TT_UNICODE
|
|
//
|
|
// Returns: NOERROR on success
|
|
// E_OUTOFMEMORY on allocation failure
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 08-Mar-94 davepl Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
INTERNAL ClipfmtToStm
|
|
( CStmBufWrite & StmWrite,
|
|
DWORD dwFormatTag,
|
|
ULONG ulFormatID,
|
|
TXTTYPE ttText )
|
|
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT hr;
|
|
|
|
const ULONG ulDummy = 0;
|
|
switch((DWORD)dwFormatTag)
|
|
{
|
|
|
|
// If the tag is 0, there is no clipboard format info.
|
|
|
|
case 0:
|
|
|
|
if (FAILED(hr = StmWrite.Write(&ulDummy, sizeof(ULONG))))
|
|
{
|
|
return(hr);
|
|
}
|
|
|
|
return(NOERROR);
|
|
|
|
// In the -1 and -2 cases (yes, I wish there were constants too) all we
|
|
// need to write is the format ID
|
|
|
|
case -1:
|
|
case -2:
|
|
|
|
// Write the format tag to the stream
|
|
if (FAILED(hr = StmWrite.Write(&dwFormatTag, sizeof(dwFormatTag))))
|
|
{
|
|
return hr;
|
|
}
|
|
return(StmWrite.Write(&ulFormatID, sizeof(ulFormatID)));
|
|
|
|
|
|
// In all other cases, we need to write the string raw with termination
|
|
// (ie: the format tag we've already written was the length).
|
|
|
|
default:
|
|
|
|
|
|
if (TT_ANSI == ttText)
|
|
{
|
|
char szClipName[MAX_CFNAME];
|
|
int cbLen = SSGetClipboardFormatNameA(ulFormatID, szClipName, MAX_CFNAME);
|
|
if (cbLen == 0)
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
cbLen++; // Account for NULL terminator
|
|
szClipName[cbLen] = '\0';
|
|
// Write the format tag to the stream
|
|
if (FAILED(hr = StmWrite.Write(&cbLen, sizeof(cbLen))))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
return (StmWrite.Write(szClipName, cbLen));
|
|
|
|
}
|
|
else
|
|
{
|
|
OLECHAR wszClipName[MAX_CFNAME];
|
|
int ccLen = GetClipboardFormatName(ulFormatID, wszClipName, MAX_CFNAME);
|
|
if (ccLen == 0)
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
ccLen++; // Account for NULL terminator
|
|
wszClipName[ccLen] = OLESTR('\0');
|
|
|
|
// Write the format tag to the stream
|
|
if (FAILED(hr = StmWrite.Write(&ccLen, sizeof(ccLen))))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
return (StmWrite.Write(wszClipName, ccLen*sizeof(OLECHAR)));
|
|
}
|
|
|
|
} // end switch()
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: ANSIStrToStm, PRIVATE INTERNAL
|
|
//
|
|
// Synopsis: Writes an ANSI string out to a stream, preceded by a ULONG
|
|
// indicating its length (INCLUDING TERMINATOR). If the
|
|
// string is 0-length, or a NULL ptr is passed in, just
|
|
// the length (0) is written, and no blank string is stored
|
|
// in the stream.
|
|
//
|
|
// Arguments: [pstm] -- the stream to write to
|
|
// [str] -- the string to write
|
|
//
|
|
//
|
|
//
|
|
//
|
|
// Returns: NOERROR on success
|
|
// E_OUTOFMEMORY on allocation failure
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 08-Mar-94 davepl Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
INTERNAL ANSIStrToStm(CStmBufWrite & StmWrite, LPCSTR str)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT hr;
|
|
ULONG ulDummy = 0;
|
|
ULONG ulLen;
|
|
|
|
// If the pointer is NULL or if it is valid but points to
|
|
// a 0-length string, _just_ write the 0-length, but no
|
|
// string.
|
|
|
|
if (NULL == str || (ulLen = strlen(str) + 1) == 1)
|
|
{
|
|
return(StmWrite.Write(&ulDummy, sizeof(ulDummy)));
|
|
}
|
|
|
|
if (FAILED(hr = StmWrite.Write(&ulLen, sizeof(ulLen))))
|
|
{
|
|
return(hr);
|
|
}
|
|
|
|
return StmWrite.Write(str, ulLen);
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: ANSIStmToStr, PRIVATE INTERNAL
|
|
//
|
|
// Synopsis: Reads a string from a stream, which is preceded by a ULONG
|
|
// giving its length. If the string OUT parameter is NULL,
|
|
// the string is read but not returned. If the parameter is
|
|
// a valid pointer, memory is allocated on it to hold the str.
|
|
//
|
|
// Arguments: [pstm] -- the stream to write to
|
|
// [pstr] -- the caller's string pointer
|
|
//
|
|
// Returns: NOERROR on success
|
|
// E_OUTOFMEMORY on allocation failure
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 08-Mar-94 davepl Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
INTERNAL ANSIStmToStr(CStmBufRead & StmRead, LPSTR * pstr, ULONG * pulLen)
|
|
{
|
|
VDATEHEAP();
|
|
LPSTR szTmp = NULL;
|
|
ULONG ulTmp;
|
|
HRESULT hr;
|
|
|
|
if (pstr)
|
|
{
|
|
VDATEPTROUT(pstr, LPSTR);
|
|
*pstr = NULL;
|
|
}
|
|
|
|
if (pulLen)
|
|
{
|
|
VDATEPTROUT(pulLen, ULONG *);
|
|
*pulLen = 0;
|
|
}
|
|
|
|
// Find out how many bytes are to follow as a string
|
|
|
|
if (FAILED(hr = StmRead.Read(&ulTmp, sizeof(ulTmp))))
|
|
{
|
|
return(hr);
|
|
}
|
|
|
|
// If none, we can just return now
|
|
|
|
if (0 == ulTmp)
|
|
{
|
|
return(NOERROR);
|
|
}
|
|
|
|
if (pulLen)
|
|
{
|
|
*pulLen = ulTmp;
|
|
}
|
|
|
|
// Allocate a buffer to read the string into
|
|
|
|
szTmp = (LPSTR) PubMemAlloc(ulTmp);
|
|
if (NULL == szTmp)
|
|
{
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
}
|
|
|
|
if (FAILED(hr = StmRead.Read(szTmp, ulTmp)))
|
|
{
|
|
PubMemFree(szTmp);
|
|
return(hr);
|
|
}
|
|
|
|
// If the caller wanted the string, assign it over, otherwise
|
|
// just free it now.
|
|
|
|
if (pstr)
|
|
{
|
|
*pstr = szTmp;
|
|
}
|
|
else
|
|
{
|
|
PubMemFree(szTmp);
|
|
}
|
|
|
|
return(NOERROR);
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: ReadFmtUserTypeStg
|
|
//
|
|
// Synopsis: Read ClipFormat, UserType from CompObj stream
|
|
//
|
|
// Arguments: [pstg] -- storage containing CompObj stream
|
|
// [pcf] -- place holder for clip format, may be NULL
|
|
// [ppszUserType] -- place holder for User Type, may be NULL
|
|
//
|
|
// Returns: If NOERROR, *pcf is clip format and *ppszUserType is User Type
|
|
// If ERROR, *pcf is 0 and *ppszUserType is NULL
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: ??-???-?? ? Ported
|
|
// 15-Jul-94 AlexT Make sure *pcf & *pszUserType are clear
|
|
// on error
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
STDAPI ReadFmtUserTypeStg
|
|
( IStorage * pstg,
|
|
CLIPFORMAT * pcf,
|
|
LPOLESTR * ppszUserType )
|
|
{
|
|
OLETRACEOUTEX((API_ReadFmtUserTypeStg,
|
|
PARAMFMT("pstg= %p, pcf= %p, ppszUserType= %p"),
|
|
pstg, pcf, ppszUserType));
|
|
|
|
VDATEHEAP();
|
|
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStorage,(IUnknown **)&pstg);
|
|
|
|
HRESULT hr;
|
|
CompObjStmData cod;
|
|
|
|
do
|
|
{
|
|
// Read the CompObj stream
|
|
hr = ReadCompObjStm(pstg, &cod);
|
|
if (FAILED(hr))
|
|
{
|
|
// clean up and return
|
|
break;
|
|
}
|
|
|
|
// Extract the clipboard format
|
|
if (NULL != pcf)
|
|
{
|
|
ULONG ulFormatID = 0;
|
|
DWORD dwFormatTag = 0;
|
|
|
|
if (FAILED(hr = GetClipFormat(&cod, &ulFormatID, &dwFormatTag))
|
|
&& GetScode(hr) != OLE_S_MAC_CLIPFORMAT)
|
|
{
|
|
// clean up and return
|
|
break;
|
|
}
|
|
|
|
*pcf = (CLIPFORMAT) ulFormatID;
|
|
}
|
|
|
|
// Extract the User Type
|
|
if (NULL != ppszUserType)
|
|
{
|
|
if (FAILED(hr = GetUNICODEUserType(&cod, ppszUserType)))
|
|
{
|
|
// clean up and return
|
|
break;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
} while (FALSE);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// Make sure the out parameters are zeroed out in the failure case
|
|
|
|
if (NULL != pcf)
|
|
{
|
|
*pcf = 0;
|
|
}
|
|
|
|
if (NULL != ppszUserType)
|
|
{
|
|
*ppszUserType = NULL;
|
|
}
|
|
}
|
|
|
|
OLETRACEOUT((API_ReadFmtUserTypeStg, hr));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
STDAPI ReadFmtProgIdStg
|
|
( IStorage * pstg,
|
|
LPOLESTR * pszProgID )
|
|
{
|
|
VDATEHEAP();
|
|
|
|
HRESULT hr;
|
|
CompObjStmData cod;
|
|
|
|
// Read the CompObj stream
|
|
if (FAILED(hr = ReadCompObjStm(pstg, &cod)))
|
|
{
|
|
return(hr);
|
|
|
|
}
|
|
|
|
// Extract the User Type
|
|
if (pszProgID)
|
|
{
|
|
if (FAILED(hr = GetUNICODEProgID(&cod, pszProgID)))
|
|
{
|
|
return(hr);
|
|
}
|
|
}
|
|
return(NOERROR);
|
|
}
|
|
|
|
|
|
|
|
STDAPI WriteFmtUserTypeStg
|
|
( LPSTORAGE pstg,
|
|
CLIPFORMAT cf,
|
|
LPOLESTR szUserType)
|
|
{
|
|
OLETRACEIN((API_WriteFmtUserTypeStg, PARAMFMT("pstg= %p, cf= %x, szUserType= %ws"),
|
|
pstg, cf, szUserType));
|
|
|
|
VDATEHEAP();
|
|
HRESULT hr;
|
|
CompObjStmData cod;
|
|
CLSID clsid;
|
|
LPOLESTR szProgID = NULL;
|
|
|
|
VDATEIFACE_LABEL(pstg, errRtn, hr);
|
|
|
|
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStorage,(IUnknown **)&pstg);
|
|
|
|
|
|
// Read the CompObj stream. If it's not there, we don't care,
|
|
// we'll build a new one. Some errors, such as E_OUTOFMEMORY, cannot
|
|
// be overlooked, so we must return them.
|
|
|
|
if (FAILED(hr = ReadCompObjStm(pstg, &cod)))
|
|
{
|
|
if (hr == ResultFromScode(E_OUTOFMEMORY))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
}
|
|
|
|
// Set the User Type in the Object.
|
|
|
|
if (szUserType)
|
|
{
|
|
if (FAILED(hr = PutUNICODEUserType(&cod, szUserType)))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
}
|
|
|
|
// Set the ProgID field
|
|
|
|
if (ReadClassStg(pstg, &clsid) != NOERROR)
|
|
{
|
|
clsid = CLSID_NULL;
|
|
}
|
|
|
|
if (SUCCEEDED(ProgIDFromCLSID (clsid, &szProgID)))
|
|
{
|
|
PutUNICODEProgID(&cod, szProgID);
|
|
}
|
|
|
|
if (szProgID)
|
|
{
|
|
PubMemFree(szProgID);
|
|
}
|
|
|
|
// Set the clipboard format. 0xC000 is a magical constant which
|
|
// bounds the standard clipboard format type IDs
|
|
|
|
if (cf < 0xC000)
|
|
{
|
|
if (0 == cf)
|
|
{
|
|
PutClipFormat(&cod, 0, 0); // NULL format
|
|
}
|
|
else
|
|
{
|
|
PutClipFormat(&cod, (DWORD)-1, cf); // Standard format
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PutClipFormat(&cod, MAX_CFNAME, cf); // Custom format
|
|
|
|
}
|
|
|
|
// Now we have all the info in the CompObjData object.
|
|
// Now we can write it out to the stream as a big atomic object.
|
|
|
|
if (FAILED(hr = WriteCompObjStm(pstg, &cod)))
|
|
{
|
|
if (hr == ResultFromScode(E_OUTOFMEMORY))
|
|
{
|
|
goto errRtn;
|
|
}
|
|
}
|
|
|
|
hr = NOERROR;
|
|
|
|
errRtn:
|
|
OLETRACEOUT((API_WriteFmtUserTypeStg, hr));
|
|
|
|
return hr;
|
|
}
|