695 lines
20 KiB
C++
695 lines
20 KiB
C++
#include <stdafx.h>
|
|
#include <afx.h>
|
|
#include <ole2.h>
|
|
#include <basetyps.h>
|
|
#include <atlbase.h>
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1999 - 1999
|
|
//
|
|
// File: cstr.h
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifndef __STR_H__
|
|
#define __STR_H__
|
|
|
|
#include <tchar.h>
|
|
|
|
#define STRAPI __stdcall
|
|
struct _STR_DOUBLE { BYTE doubleBits[sizeof(double)]; };
|
|
|
|
BOOL STRAPI IsValidString(LPCSTR lpsz, int nLength);
|
|
BOOL STRAPI IsValidString(LPCWSTR lpsz, int nLength);
|
|
|
|
BOOL STRAPI IsValidAddressz(const void* lp, UINT nBytes, BOOL bReadWrite=TRUE);
|
|
|
|
int STRAPI StrLoadString(HINSTANCE hInst, UINT nID, LPTSTR lpszBuf);
|
|
|
|
class CStr
|
|
{
|
|
public:
|
|
|
|
// Constructors
|
|
CStr();
|
|
CStr(const CStr& stringSrc);
|
|
CStr(TCHAR ch, int nRepeat = 1);
|
|
CStr(LPCSTR lpsz);
|
|
CStr(LPCWSTR lpsz);
|
|
CStr(LPCTSTR lpch, int nLength);
|
|
CStr(const unsigned char* psz);
|
|
|
|
// Attributes & Operations
|
|
// as an array of characters
|
|
int GetLength() const;
|
|
BOOL IsEmpty() const;
|
|
void Empty(); // free up the data
|
|
|
|
TCHAR GetAt(int nIndex) const; // 0 based
|
|
TCHAR operator[](int nIndex) const; // same as GetAt
|
|
void SetAt(int nIndex, TCHAR ch);
|
|
operator LPCTSTR() const; // as a C string
|
|
|
|
// overloaded assignment
|
|
const CStr& operator=(const CStr& stringSrc);
|
|
const CStr& operator=(TCHAR ch);
|
|
#ifdef UNICODE
|
|
const CStr& operator=(char ch);
|
|
#endif
|
|
const CStr& operator=(LPCSTR lpsz);
|
|
const CStr& operator=(LPCWSTR lpsz);
|
|
const CStr& operator=(const unsigned char* psz);
|
|
|
|
// string concatenation
|
|
const CStr& operator+=(const CStr& string);
|
|
const CStr& operator+=(TCHAR ch);
|
|
#ifdef UNICODE
|
|
const CStr& operator+=(char ch);
|
|
#endif
|
|
const CStr& operator+=(LPCTSTR lpsz);
|
|
|
|
friend CStr STRAPI operator+(const CStr& string1,
|
|
const CStr& string2);
|
|
friend CStr STRAPI operator+(const CStr& string, TCHAR ch);
|
|
friend CStr STRAPI operator+(TCHAR ch, const CStr& string);
|
|
#ifdef UNICODE
|
|
friend CStr STRAPI operator+(const CStr& string, char ch);
|
|
friend CStr STRAPI operator+(char ch, const CStr& string);
|
|
#endif
|
|
friend CStr STRAPI operator+(const CStr& string, LPCTSTR lpsz);
|
|
friend CStr STRAPI operator+(LPCTSTR lpsz, const CStr& string);
|
|
|
|
// string comparison
|
|
int Compare(LPCTSTR lpsz) const; // straight character
|
|
int CompareNoCase(LPCTSTR lpsz) const; // ignore case
|
|
int Collate(LPCTSTR lpsz) const; // NLS aware
|
|
|
|
// simple sub-string extraction
|
|
CStr Mid(int nFirst, int nCount) const;
|
|
CStr Mid(int nFirst) const;
|
|
CStr Left(int nCount) const;
|
|
CStr Right(int nCount) const;
|
|
|
|
CStr SpanIncluding(LPCTSTR lpszCharSet) const;
|
|
CStr SpanExcluding(LPCTSTR lpszCharSet) const;
|
|
|
|
// upper/lower/reverse conversion
|
|
void MakeUpper();
|
|
void MakeLower();
|
|
void MakeReverse();
|
|
|
|
// trimming whitespace (either side)
|
|
void TrimRight();
|
|
void TrimLeft();
|
|
|
|
// searching (return starting index, or -1 if not found)
|
|
// look for a single character match
|
|
int Find(TCHAR ch) const; // like "C" strchr
|
|
int ReverseFind(TCHAR ch) const;
|
|
int FindOneOf(LPCTSTR lpszCharSet) const;
|
|
|
|
// look for a specific sub-string
|
|
int Find(LPCTSTR lpszSub) const; // like "C" strstr
|
|
|
|
// simple formatting
|
|
void Format(LPCTSTR lpszFormat, ...);
|
|
|
|
#ifndef _MAC
|
|
// formatting for localization (uses FormatMessage API)
|
|
void __cdecl FormatMessage(LPCTSTR lpszFormat, ...);
|
|
void __cdecl FormatMessage(UINT nFormatID, ...);
|
|
#endif
|
|
|
|
// Windows support
|
|
BOOL LoadString(HINSTANCE hInst, UINT nID); // load from string resource
|
|
// 255 chars max
|
|
#ifndef UNICODE
|
|
// ANSI <-> OEM support (convert string in place)
|
|
void AnsiToOem();
|
|
void OemToAnsi();
|
|
#endif
|
|
BSTR AllocSysString();
|
|
BSTR SetSysString(BSTR* pbstr);
|
|
|
|
// Access to string implementation buffer as "C" character array
|
|
LPTSTR GetBuffer(int nMinBufLength);
|
|
void ReleaseBuffer(int nNewLength = -1);
|
|
LPTSTR GetBufferSetLength(int nNewLength);
|
|
void FreeExtra();
|
|
|
|
// Implementation
|
|
public:
|
|
~CStr();
|
|
int GetAllocLength() const;
|
|
|
|
protected:
|
|
// lengths/sizes in characters
|
|
// (note: an extra character is always allocated)
|
|
LPTSTR m_pchData; // actual string (zero terminated)
|
|
int m_nDataLength; // does not include terminating 0
|
|
int m_nAllocLength; // does not include terminating 0
|
|
|
|
// implementation helpers
|
|
void Init();
|
|
void AllocCopy(CStr& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const;
|
|
void AllocBuffer(int nLen);
|
|
void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);
|
|
void ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTSTR lpszSrc2Data);
|
|
void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData);
|
|
static void SafeDelete(LPTSTR lpch);
|
|
static int SafeStrlen(LPCTSTR lpsz);
|
|
};
|
|
|
|
// Compare helpers
|
|
BOOL STRAPI operator==(const CStr& s1, const CStr& s2);
|
|
BOOL STRAPI operator==(const CStr& s1, LPCTSTR s2);
|
|
BOOL STRAPI operator==(LPCTSTR s1, const CStr& s2);
|
|
BOOL STRAPI operator!=(const CStr& s1, const CStr& s2);
|
|
BOOL STRAPI operator!=(const CStr& s1, LPCTSTR s2);
|
|
BOOL STRAPI operator!=(LPCTSTR s1, const CStr& s2);
|
|
BOOL STRAPI operator<(const CStr& s1, const CStr& s2);
|
|
BOOL STRAPI operator<(const CStr& s1, LPCTSTR s2);
|
|
BOOL STRAPI operator<(LPCTSTR s1, const CStr& s2);
|
|
BOOL STRAPI operator>(const CStr& s1, const CStr& s2);
|
|
BOOL STRAPI operator>(const CStr& s1, LPCTSTR s2);
|
|
BOOL STRAPI operator>(LPCTSTR s1, const CStr& s2);
|
|
BOOL STRAPI operator<=(const CStr& s1, const CStr& s2);
|
|
BOOL STRAPI operator<=(const CStr& s1, LPCTSTR s2);
|
|
BOOL STRAPI operator<=(LPCTSTR s1, const CStr& s2);
|
|
BOOL STRAPI operator>=(const CStr& s1, const CStr& s2);
|
|
BOOL STRAPI operator>=(const CStr& s1, LPCTSTR s2);
|
|
BOOL STRAPI operator>=(LPCTSTR s1, const CStr& s2);
|
|
|
|
// conversion helpers
|
|
int mmc_wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count);
|
|
int mmc_mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count);
|
|
|
|
// Globals
|
|
extern const CStr strEmptyString;
|
|
extern TCHAR strChNil;
|
|
|
|
// Compiler doesn't inline for DBG
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Inline function declarations
|
|
|
|
inline int CStr::SafeStrlen(LPCTSTR lpsz)
|
|
{ return (lpsz == NULL) ? NULL : _tcslen(lpsz); }
|
|
inline CStr::CStr(const unsigned char* lpsz)
|
|
{ Init(); *this = (LPCSTR)lpsz; }
|
|
inline const CStr& CStr::operator=(const unsigned char* lpsz)
|
|
{ *this = (LPCSTR)lpsz; return *this; }
|
|
|
|
#ifdef _UNICODE
|
|
inline const CStr& CStr::operator+=(char ch)
|
|
{ *this += (TCHAR)ch; return *this; }
|
|
inline const CStr& CStr::operator=(char ch)
|
|
{ *this = (TCHAR)ch; return *this; }
|
|
inline CStr STRAPI operator+(const CStr& string, char ch)
|
|
{ return string + (TCHAR)ch; }
|
|
inline CStr STRAPI operator+(char ch, const CStr& string)
|
|
{ return (TCHAR)ch + string; }
|
|
#endif
|
|
|
|
inline int CStr::GetLength() const
|
|
{ return m_nDataLength; }
|
|
inline int CStr::GetAllocLength() const
|
|
{ return m_nAllocLength; }
|
|
inline BOOL CStr::IsEmpty() const
|
|
{ return m_nDataLength == 0; }
|
|
inline CStr::operator LPCTSTR() const
|
|
{ return (LPCTSTR)m_pchData; }
|
|
|
|
// String support (windows specific)
|
|
inline int CStr::Compare(LPCTSTR lpsz) const
|
|
{ return _tcscmp(m_pchData, lpsz); } // MBCS/Unicode aware
|
|
inline int CStr::CompareNoCase(LPCTSTR lpsz) const
|
|
{ return _tcsicmp(m_pchData, lpsz); } // MBCS/Unicode aware
|
|
// CStr::Collate is often slower than Compare but is MBSC/Unicode
|
|
// aware as well as locale-sensitive with respect to sort order.
|
|
inline int CStr::Collate(LPCTSTR lpsz) const
|
|
{ return _tcscoll(m_pchData, lpsz); } // locale sensitive
|
|
inline void CStr::MakeUpper()
|
|
{ ::CharUpper(m_pchData); }
|
|
inline void CStr::MakeLower()
|
|
{ ::CharLower(m_pchData); }
|
|
|
|
inline void CStr::MakeReverse()
|
|
{ _tcsrev(m_pchData); }
|
|
inline TCHAR CStr::GetAt(int nIndex) const
|
|
{
|
|
ASSERT(nIndex >= 0);
|
|
ASSERT(nIndex < m_nDataLength);
|
|
|
|
return m_pchData[nIndex];
|
|
}
|
|
inline TCHAR CStr::operator[](int nIndex) const
|
|
{
|
|
// same as GetAt
|
|
|
|
ASSERT(nIndex >= 0);
|
|
ASSERT(nIndex < m_nDataLength);
|
|
|
|
return m_pchData[nIndex];
|
|
}
|
|
inline void CStr::SetAt(int nIndex, TCHAR ch)
|
|
{
|
|
ASSERT(nIndex >= 0);
|
|
ASSERT(nIndex < m_nDataLength);
|
|
ASSERT(ch != 0);
|
|
|
|
m_pchData[nIndex] = ch;
|
|
}
|
|
inline BOOL STRAPI operator==(const CStr& s1, const CStr& s2)
|
|
{ return s1.Compare(s2) == 0; }
|
|
inline BOOL STRAPI operator==(const CStr& s1, LPCTSTR s2)
|
|
{ return s1.Compare(s2) == 0; }
|
|
inline BOOL STRAPI operator==(LPCTSTR s1, const CStr& s2)
|
|
{ return s2.Compare(s1) == 0; }
|
|
inline BOOL STRAPI operator!=(const CStr& s1, const CStr& s2)
|
|
{ return s1.Compare(s2) != 0; }
|
|
inline BOOL STRAPI operator!=(const CStr& s1, LPCTSTR s2)
|
|
{ return s1.Compare(s2) != 0; }
|
|
inline BOOL STRAPI operator!=(LPCTSTR s1, const CStr& s2)
|
|
{ return s2.Compare(s1) != 0; }
|
|
inline BOOL STRAPI operator<(const CStr& s1, const CStr& s2)
|
|
{ return s1.Compare(s2) < 0; }
|
|
inline BOOL STRAPI operator<(const CStr& s1, LPCTSTR s2)
|
|
{ return s1.Compare(s2) < 0; }
|
|
inline BOOL STRAPI operator<(LPCTSTR s1, const CStr& s2)
|
|
{ return s2.Compare(s1) > 0; }
|
|
inline BOOL STRAPI operator>(const CStr& s1, const CStr& s2)
|
|
{ return s1.Compare(s2) > 0; }
|
|
inline BOOL STRAPI operator>(const CStr& s1, LPCTSTR s2)
|
|
{ return s1.Compare(s2) > 0; }
|
|
inline BOOL STRAPI operator>(LPCTSTR s1, const CStr& s2)
|
|
{ return s2.Compare(s1) < 0; }
|
|
inline BOOL STRAPI operator<=(const CStr& s1, const CStr& s2)
|
|
{ return s1.Compare(s2) <= 0; }
|
|
inline BOOL STRAPI operator<=(const CStr& s1, LPCTSTR s2)
|
|
{ return s1.Compare(s2) <= 0; }
|
|
inline BOOL STRAPI operator<=(LPCTSTR s1, const CStr& s2)
|
|
{ return s2.Compare(s1) >= 0; }
|
|
inline BOOL STRAPI operator>=(const CStr& s1, const CStr& s2)
|
|
{ return s1.Compare(s2) >= 0; }
|
|
inline BOOL STRAPI operator>=(const CStr& s1, LPCTSTR s2)
|
|
{ return s1.Compare(s2) >= 0; }
|
|
inline BOOL STRAPI operator>=(LPCTSTR s1, const CStr& s2)
|
|
{ return s2.Compare(s1) <= 0; }
|
|
|
|
#ifndef UNICODE
|
|
inline void CStr::AnsiToOem()
|
|
{ ::AnsiToOem(m_pchData, m_pchData); }
|
|
inline void CStr::OemToAnsi()
|
|
{ ::OemToAnsi(m_pchData, m_pchData); }
|
|
|
|
#endif // UNICODE
|
|
|
|
// General Exception for memory
|
|
class MemoryException
|
|
{
|
|
public:
|
|
MemoryException(){}
|
|
void DisplayMessage()
|
|
{
|
|
::MessageBox(NULL, _T("Memory Exception"), _T("System Out of Memory"), MB_OK|MB_ICONSTOP);
|
|
}
|
|
};
|
|
|
|
// General Exception for memory
|
|
class ResourceException
|
|
{
|
|
public:
|
|
ResourceException()
|
|
{
|
|
::MessageBox(NULL, _T("Resource Exception"), _T("Unable to Load Resource"), MB_OK|MB_ICONSTOP);
|
|
}
|
|
};
|
|
|
|
#endif // __STR_H__
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//____________________________________________________________________________
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1999
|
|
//
|
|
// File: macros.h
|
|
//
|
|
// Contents: Useful macros
|
|
//
|
|
// Macros: ARRAYLEN
|
|
//
|
|
// BREAK_ON_FAIL(hresult)
|
|
// BREAK_ON_FAIL(hresult)
|
|
//
|
|
// DECLARE_IUNKNOWN_METHODS
|
|
// DECLARE_STANDARD_IUNKNOWN
|
|
// IMPLEMENT_STANDARD_IUNKNOWN
|
|
//
|
|
// SAFE_RELEASE
|
|
//
|
|
// DECLARE_SAFE_INTERFACE_PTR_MEMBERS
|
|
//
|
|
// History: 6/3/1996 RaviR Created
|
|
// 7/23/1996 JonN Added exception handling macros
|
|
//
|
|
//____________________________________________________________________________
|
|
|
|
#ifndef _MACROS_H_
|
|
#define _MACROS_H_
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Macro: ARRAYLEN
|
|
//
|
|
// Purpose: To determine the length of an array.
|
|
//____________________________________________________________________________
|
|
//
|
|
|
|
#define ARRAYLEN(a) (sizeof(a) / sizeof((a)[0]))
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Macros: BREAK_ON_FAIL(hresult), BREAK_ON_ERROR(lastError)
|
|
//
|
|
// Purpose: To break out of a loop on error.
|
|
//____________________________________________________________________________
|
|
//
|
|
|
|
#define BREAK_ON_FAIL(hr) if (FAILED(hr)) { break; } else 1;
|
|
|
|
#define BREAK_ON_ERROR(lr) if (lr != ERROR_SUCCESS) { break; } else 1;
|
|
|
|
#define RETURN_ON_FAIL(hr) if (FAILED(hr)) { return(hr); } else 1;
|
|
|
|
#define THROW_ON_FAIL(hr) if (FAILED(hr)) { _com_issue_error(hr); } else 1;
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Macros: DwordAlign(n)
|
|
//____________________________________________________________________________
|
|
//
|
|
|
|
#define DwordAlign(n) (((n) + 3) & ~3)
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Macros: SAFE_RELEASE
|
|
//____________________________________________________________________________
|
|
//
|
|
|
|
#ifndef SAFE_RELEASE
|
|
#define SAFE_RELEASE(punk) \
|
|
if (punk != NULL) \
|
|
{ \
|
|
punk##->Release(); \
|
|
punk = NULL; \
|
|
} \
|
|
else \
|
|
{ \
|
|
TRACE(_T("Release called on NULL interface ptr")); \
|
|
}
|
|
#endif // SAFE_RELEASE
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Macros: IF_NULL_RETURN_INVALIDARG
|
|
//____________________________________________________________________________
|
|
//
|
|
|
|
#define IF_NULL_RETURN_INVALIDARG(x) \
|
|
{ \
|
|
ASSERT((x) != NULL); \
|
|
if ((x) == NULL) \
|
|
return E_INVALIDARG; \
|
|
}
|
|
|
|
#define IF_NULL_RETURN_INVALIDARG2(x, y) \
|
|
IF_NULL_RETURN_INVALIDARG(x) \
|
|
IF_NULL_RETURN_INVALIDARG(y)
|
|
|
|
#define IF_NULL_RETURN_INVALIDARG3(x, y, z) \
|
|
IF_NULL_RETURN_INVALIDARG(x) \
|
|
IF_NULL_RETURN_INVALIDARG(y) \
|
|
IF_NULL_RETURN_INVALIDARG(z)
|
|
|
|
#endif // _MACROS_H_
|
|
|
|
|
|
|
|
HRESULT ExtractString( IDataObject* piDataObject,
|
|
CLIPFORMAT cfClipFormat,
|
|
CStr* pstr, // OUT: Pointer to CStr to store data
|
|
DWORD cchMaxLength)
|
|
{
|
|
IF_NULL_RETURN_INVALIDARG2( piDataObject, pstr );
|
|
ASSERT( cchMaxLength > 0 );
|
|
|
|
HRESULT hr = S_OK;
|
|
FORMATETC formatetc = {cfClipFormat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
STGMEDIUM stgmedium = {TYMED_HGLOBAL, NULL};
|
|
stgmedium.hGlobal = ::GlobalAlloc(GPTR, sizeof(WCHAR)*cchMaxLength);
|
|
do // false loop
|
|
{
|
|
if (NULL == stgmedium.hGlobal)
|
|
{
|
|
ASSERT(FALSE);
|
|
////AfxThrowMemoryException();
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
hr = piDataObject->GetDataHere( &formatetc, &stgmedium );
|
|
if ( FAILED(hr) )
|
|
{
|
|
// This failure happens when 'searching' for
|
|
// clipboard format supported by the IDataObject.
|
|
// t-danmo (24-Oct-96)
|
|
// Skipping ASSERT( FALSE );
|
|
break;
|
|
}
|
|
|
|
LPWSTR pszNewData = reinterpret_cast<LPWSTR>(stgmedium.hGlobal);
|
|
if (NULL == pszNewData)
|
|
{
|
|
ASSERT(FALSE);
|
|
hr = E_UNEXPECTED;
|
|
break;
|
|
}
|
|
pszNewData[cchMaxLength-1] = L'\0'; // just to be safe
|
|
USES_CONVERSION;
|
|
*pstr = OLE2T(pszNewData);
|
|
} while (FALSE); // false loop
|
|
|
|
if (NULL != stgmedium.hGlobal)
|
|
{
|
|
#if (_MSC_VER >= 1200)
|
|
#pragma warning (push)
|
|
#endif
|
|
#pragma warning(disable: 4553) // "==" operator has no effect
|
|
VERIFY( NULL == ::GlobalFree(stgmedium.hGlobal) );
|
|
#if (_MSC_VER >= 1200)
|
|
#pragma warning (pop)
|
|
#endif
|
|
}
|
|
return hr;
|
|
} // ExtractString()
|
|
|
|
TCHAR strChNil = '\0';
|
|
void CStr::Init()
|
|
{
|
|
m_nDataLength = m_nAllocLength = 0;
|
|
m_pchData = (LPTSTR)&strChNil;
|
|
}
|
|
|
|
// declared static
|
|
void CStr::SafeDelete(LPTSTR lpch)
|
|
{
|
|
if (lpch != (LPTSTR)&strChNil)
|
|
delete[] lpch;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
|
|
// begin_extractstring
|
|
CStr::CStr()
|
|
{
|
|
Init();
|
|
}
|
|
|
|
CStr::CStr(const CStr& stringSrc)
|
|
{
|
|
// if constructing a String from another String, we make a copy of the
|
|
// original string data to enforce value semantics (i.e. each string
|
|
// gets a copy of its own
|
|
|
|
stringSrc.AllocCopy(*this, stringSrc.m_nDataLength, 0, 0);
|
|
}
|
|
|
|
void CStr::AllocBuffer(int nLen)
|
|
// always allocate one extra character for '\0' termination
|
|
// assumes [optimistically] that data length will equal allocation length
|
|
{
|
|
ASSERT(nLen >= 0);
|
|
|
|
if (nLen == 0)
|
|
{
|
|
Init();
|
|
}
|
|
else
|
|
{
|
|
m_pchData = new TCHAR[nLen+1]; //REVIEW may throw an exception
|
|
m_pchData[nLen] = '\0';
|
|
m_nDataLength = nLen;
|
|
m_nAllocLength = nLen;
|
|
}
|
|
}
|
|
|
|
void CStr::Empty()
|
|
{
|
|
SafeDelete(m_pchData);
|
|
Init();
|
|
ASSERT(m_nDataLength == 0);
|
|
ASSERT(m_nAllocLength == 0);
|
|
}
|
|
|
|
CStr::~CStr()
|
|
// free any attached data
|
|
{
|
|
SafeDelete(m_pchData);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Helpers for the rest of the implementation
|
|
|
|
static inline int SafeStrlen(LPCTSTR lpsz)
|
|
{
|
|
ASSERT(lpsz == NULL || IsValidString(lpsz, FALSE));
|
|
return (lpsz == NULL) ? 0 : lstrlen(lpsz);
|
|
}
|
|
|
|
void CStr::AllocCopy(CStr& dest, int nCopyLen, int nCopyIndex,
|
|
int nExtraLen) const
|
|
{
|
|
// will clone the data attached to this string
|
|
// allocating 'nExtraLen' characters
|
|
// Places results in uninitialized string 'dest'
|
|
// Will copy the part or all of original data to start of new string
|
|
|
|
int nNewLen = nCopyLen + nExtraLen;
|
|
|
|
if (nNewLen == 0)
|
|
{
|
|
dest.Init();
|
|
}
|
|
else
|
|
{
|
|
dest.AllocBuffer(nNewLen);
|
|
memcpy(dest.m_pchData, &m_pchData[nCopyIndex], nCopyLen*sizeof(TCHAR));
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// More sophisticated construction
|
|
|
|
CStr::CStr(LPCTSTR lpsz)
|
|
{
|
|
if (lpsz != NULL && (DWORD_PTR)lpsz <= 0xffff)
|
|
{
|
|
Init();
|
|
UINT nID = LOWORD((DWORD_PTR)lpsz);
|
|
// REVIEW hInstance for LoadString(hInst, nID);
|
|
}
|
|
else
|
|
{
|
|
int nLen;
|
|
if ((nLen = SafeStrlen(lpsz)) == 0)
|
|
Init();
|
|
else
|
|
{
|
|
AllocBuffer(nLen);
|
|
memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Assignment operators
|
|
// All assign a new value to the string
|
|
// (a) first see if the buffer is big enough
|
|
// (b) if enough room, copy on top of old buffer, set size and type
|
|
// (c) otherwise free old string data, and create a new one
|
|
//
|
|
// All routines return the new string (but as a 'const CStr&' so that
|
|
// assigning it again will cause a copy, eg: s1 = s2 = "hi there".
|
|
//
|
|
|
|
void CStr::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
|
|
{
|
|
// check if it will fit
|
|
if (nSrcLen > m_nAllocLength)
|
|
{
|
|
// it won't fit, allocate another one
|
|
Empty();
|
|
AllocBuffer(nSrcLen);
|
|
}
|
|
if (nSrcLen != 0)
|
|
memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));
|
|
m_nDataLength = nSrcLen;
|
|
m_pchData[nSrcLen] = '\0';
|
|
}
|
|
|
|
const CStr& CStr::operator=(const CStr& stringSrc)
|
|
{
|
|
AssignCopy(stringSrc.m_nDataLength, stringSrc.m_pchData);
|
|
return *this;
|
|
}
|
|
|
|
const CStr& CStr::operator=(LPCTSTR lpsz)
|
|
{
|
|
ASSERT(lpsz == NULL || IsValidString(lpsz, FALSE));
|
|
AssignCopy(SafeStrlen(lpsz), lpsz);
|
|
return *this;
|
|
}
|
|
HRESULT ExtractString( IDataObject* piDataObject,
|
|
CLIPFORMAT cfClipFormat,
|
|
CString* pstr, // OUT: Pointer to CStr to store data
|
|
DWORD cchMaxLength)
|
|
{
|
|
if (pstr == NULL)
|
|
return E_POINTER;
|
|
|
|
CStr cstr(*pstr);
|
|
|
|
HRESULT hr = ExtractString(piDataObject, cfClipFormat, &cstr, cchMaxLength);
|
|
|
|
*pstr = cstr;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
BOOL STRAPI IsValidString(LPCSTR lpsz, int nLength)
|
|
{
|
|
if (lpsz == NULL)
|
|
return FALSE;
|
|
return ::IsBadStringPtrA(lpsz, nLength) == 0;
|
|
}
|
|
|
|
BOOL STRAPI IsValidString(LPCWSTR lpsz, int nLength)
|
|
{
|
|
if (lpsz == NULL)
|
|
return FALSE;
|
|
|
|
return ::IsBadStringPtrW(lpsz, nLength) == 0;
|
|
}
|