WindowsXP-SP1/admin/activec/inc/guidhelp.inl
2020-09-30 16:53:49 +02:00

139 lines
3.6 KiB
C++

/*--------------------------------------------------------------------------*
*
* Microsoft Windows
* Copyright (C) Microsoft Corporation, 1992 - 000
*
* File: guidhelp.inl
*
* Contents:
*
* History: 13-Apr-2000 jeffro Created
*
*--------------------------------------------------------------------------*/
#pragma once
#include "xmlbase.h" // for CXMLBinary
/*+-------------------------------------------------------------------------*
* ExtractString
*
* Gets string data representing the given clipboard format from the data
* object. StringType must be a type that can accept assignment from
* LPCTSTR (WTL::CString, CStr, tstring, etc.)
*
* Many (many!) implementations of IDataObject::GetDataHere incorrectly call
* CreateStreamOnHGlobal using the HGLOBAL we get them (calling it is
* incorrect because GetDataHere is specifically forbidden from reallocating
* the medium that is given to it, which the IStream implementation returned
* from CreateStreamOnHGlobal will do if it needs more room).
*
* We would be more robust if we used TYMED_STREAM in preference to
* TYMED_HGLOBAL, if the snap-in supported it.
*--------------------------------------------------------------------------*/
template<class StringType>
HRESULT ExtractString (
IDataObject* piDataObject,
CLIPFORMAT cfClipFormat,
StringType& str)
{
DECLARE_SC (sc, _T("ExtractString"));
sc = ScCheckPointers (piDataObject);
if (sc)
return (sc.ToHr());
/*
* clear out the output
*/
str = _T("");
FORMATETC formatetc = {cfClipFormat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
STGMEDIUM stgmedium = {TYMED_HGLOBAL, NULL};
CXMLBinary xmlBin;
/*
* 1024 isn't a random number. It must be (at least) this large to
* maintain compatibility with buggy snap-ins.
*/
const int cchGrow = 1024;
int cchBuffer = 0;
/*
* to enter the loop the first time
*/
sc = STG_E_MEDIUMFULL;
while (sc == STG_E_MEDIUMFULL)
{
/*
* increase the buffer size
*/
cchBuffer += cchGrow;
const int cbBuffer = cchBuffer * sizeof(WCHAR);
/*
* Allocate a buffer for the string. In the reallocation case,
* it is safe to store the return value from GlobalReAlloc in
* stgmedium.hGlobal because the original handle is also held
* in autoGlobal
*/
if (cchBuffer == cchGrow)
sc = xmlBin.ScAlloc (cbBuffer, true /* fZeroInit */);
else
sc = xmlBin.ScRealloc (cbBuffer, true /* fZeroInit */);
if (sc)
return (sc.ToHr());
/*
* get the HGLOBAL out of the CXMLBinary
*/
stgmedium.hGlobal = xmlBin.GetHandle();
sc = ScCheckPointers (stgmedium.hGlobal, E_UNEXPECTED);
if (sc)
return (sc.ToHr());
/*
* get the string from the data object
*/
sc = piDataObject->GetDataHere (&formatetc, &stgmedium);
// don't check for error here, it'll be checked at the top of the loop
}
/*
* this will handle all non-STG_E_MEDIUMFULL errors from
* IDataObject::GetDataHere
*/
if (sc)
{
// don't trace these errors
SC scTemp = sc;
sc.Clear();
return scTemp.ToHr();
}
/*
* lock down the returned data in preparation for copying
*/
CXMLBinaryLock lock (xmlBin);
LPWSTR pchBuffer = NULL;
sc = lock.ScLock (&pchBuffer);
if (sc)
return (sc.ToHr());
/*
* Copy the string. The termination isn't unjustified paranoia.
* Many implementations of IDataObject::GetDataHere don't terminate
* their strings.
*/
USES_CONVERSION;
pchBuffer[cchBuffer-1] = 0;
str = W2CT (pchBuffer);
return (sc.ToHr());
}