You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
764 lines
19 KiB
764 lines
19 KiB
//
|
|
// This module provides the following functions:
|
|
//
|
|
// CvtDlgToDlgEx - Converts a DLGTEMPLATE to a DLGTEMPLATEEX
|
|
//
|
|
//
|
|
#include "ctlspriv.h"
|
|
|
|
|
|
#include "dlgcvt.h"
|
|
|
|
//
|
|
// Define the amount (bytes) the stream buffer grows when required.
|
|
// It will grow enough to satisfy the required write PLUS this
|
|
// amount.
|
|
//
|
|
#ifdef DEBUG
|
|
# define STREAM_GROW_BYTES 32 // Exercise stream growth.
|
|
#else
|
|
# define STREAM_GROW_BYTES 512
|
|
#endif
|
|
|
|
//
|
|
// Simple MIN/MAX inline helpers.
|
|
//
|
|
|
|
template <class T>
|
|
inline const T& MIN(const T& a, const T& b)
|
|
{
|
|
return a < b ? a : b;
|
|
}
|
|
|
|
template <class T>
|
|
inline const T& MAX(const T& a, const T& b)
|
|
{
|
|
return a > b ? a : b;
|
|
}
|
|
|
|
//
|
|
// This class implements a simple dynamic stream that grows as you
|
|
// add data to it. It's modeled after the strstream class provided
|
|
// by the C++ std lib. Unlike the std lib implementation, this one
|
|
// doesn't require C++ EH to be enabled. If comctl32 compiled with
|
|
// C++ EH enabled, I would have used strstream instead.
|
|
// [brianau - 10/5/98]
|
|
//
|
|
class CByteStream
|
|
{
|
|
public:
|
|
explicit CByteStream(int cbDefGrow = 512);
|
|
~CByteStream(void);
|
|
|
|
//
|
|
// Used as argument to AlignXXXX member functions.
|
|
//
|
|
enum AlignType { eAlignWrite, eAlignRead };
|
|
//
|
|
// Basic read/write functions.
|
|
//
|
|
int Read(LPVOID pb, int cb);
|
|
int Write(const VOID *pb, int cb);
|
|
//
|
|
// Determine if there was an error when reading or
|
|
// writing to the stream.
|
|
//
|
|
bool ReadError(void) const
|
|
{ return m_bReadErr; }
|
|
|
|
bool WriteError(void) const
|
|
{ return m_bWriteErr; }
|
|
//
|
|
// Reset the stream read or write pointer.
|
|
//
|
|
void ResetRead(void)
|
|
{ m_pbRead = m_pbBuf; m_bReadErr = false; }
|
|
|
|
void ResetWrite(void)
|
|
{ m_pbWrite = m_pbBuf; m_bWriteErr = false; }
|
|
//
|
|
// Reset the stream.
|
|
//
|
|
void Reset(void);
|
|
//
|
|
// These functions align the read and write stream pointers.
|
|
//
|
|
void AlignReadWord(void)
|
|
{ Align(eAlignRead, sizeof(WORD)); }
|
|
|
|
void AlignReadDword(void)
|
|
{ Align(eAlignRead, sizeof(DWORD)); }
|
|
|
|
void AlignReadQword(void)
|
|
{ Align(eAlignRead, sizeof(ULONGLONG)); }
|
|
|
|
void AlignWriteWord(void)
|
|
{ Align(eAlignWrite, sizeof(WORD)); }
|
|
|
|
void AlignWriteDword(void)
|
|
{ Align(eAlignWrite, sizeof(DWORD)); }
|
|
|
|
void AlignWriteQword(void)
|
|
{ Align(eAlignWrite, sizeof(ULONGLONG)); }
|
|
|
|
//
|
|
// GetBuffer returns the address of the stream buffer in memory.
|
|
// The buffer is "frozen" so it will not be released if the stream
|
|
// object is destroyed. At this point, you own the buffer.
|
|
// If bPermanent is false, you can call ReleaseBuffer to return
|
|
// control of the buffer to the stream object.
|
|
//
|
|
LPBYTE GetBuffer(bool bPermanent = false);
|
|
//
|
|
// ReleaseBuffer returns control of the buffer obtained with GetBuffer
|
|
// to the stream object.
|
|
//
|
|
bool ReleaseBuffer(LPBYTE pbBuf);
|
|
//
|
|
// Overload the insertion and extraction operators so we can
|
|
// work like a normal std lib stream class.
|
|
//
|
|
template <class T>
|
|
CByteStream& operator >> (T& x)
|
|
{ Read(&x, sizeof(x)); return *this; }
|
|
|
|
template <class T>
|
|
CByteStream& operator << (const T& x)
|
|
{ Write(&x, sizeof(x)); return *this; }
|
|
|
|
private:
|
|
int m_cbDefGrow; // Default amount (bytes) to grow when expanding buffer.
|
|
LPBYTE m_pbBuf; // Addr of allocated buffer.
|
|
LPBYTE m_pbRead; // Addr for next read.
|
|
LPBYTE m_pbWrite; // Addr for next write.
|
|
LPBYTE m_pbEnd; // Addr of byte following last byte in buffer.
|
|
bool m_bWriteErr; // Any read errors?
|
|
bool m_bReadErr; // Any write errors?
|
|
bool m_bOwnsBuf; // true == delete buffer in dtor.
|
|
|
|
//
|
|
// Expand the buffer as needed.
|
|
//
|
|
bool GrowBuffer(int cb = 0);
|
|
//
|
|
// Align the read or write buffer pointer.
|
|
// Used internally by the AlignXXXXX member functions.
|
|
//
|
|
void Align(AlignType a, size_t n);
|
|
//
|
|
// Internal consistency checks for debug builds.
|
|
//
|
|
void Validate(void) const;
|
|
//
|
|
// Prevent copy.
|
|
//
|
|
CByteStream(const CByteStream& rhs);
|
|
CByteStream& operator = (const CByteStream& rhs);
|
|
};
|
|
|
|
|
|
//
|
|
// Class for converting in-memory dialog templates between the two
|
|
// structures DLGTEMPLATE <-> DLGTEMPLATEEX.
|
|
//
|
|
// Currently, the object only converts from DLGTEMPLATE -> DLGTEMPLATEEX.
|
|
// It would be simple to create the code for the inverse conversion. However,
|
|
// it's currently not needed so I didn't create it.
|
|
//
|
|
class CDlgTemplateConverter
|
|
{
|
|
public:
|
|
explicit CDlgTemplateConverter(int iCharSet = DEFAULT_CHARSET)
|
|
: m_iCharset(iCharSet),
|
|
m_stm(STREAM_GROW_BYTES) { }
|
|
|
|
~CDlgTemplateConverter(void) { }
|
|
|
|
HRESULT DlgToDlgEx(LPDLGTEMPLATE pTemplateIn, LPDLGTEMPLATEEX *ppTemplateOut);
|
|
|
|
HRESULT DlgExToDlg(LPDLGTEMPLATEEX pTemplateIn, LPDLGTEMPLATE *ppTemplateOut)
|
|
{ return E_NOTIMPL; }
|
|
|
|
private:
|
|
int m_iCharset;
|
|
CByteStream m_stm; // For converted template.
|
|
|
|
HRESULT DlgHdrToDlgEx(CByteStream& s, LPWORD *ppw);
|
|
HRESULT DlgItemToDlgEx(CByteStream& s, LPWORD *ppw);
|
|
HRESULT DlgExHdrToDlg(CByteStream& s, LPWORD *ppw)
|
|
{ return E_NOTIMPL; }
|
|
HRESULT DlgExItemToDlg(CByteStream& s, LPWORD *ppw)
|
|
{ return E_NOTIMPL; }
|
|
//
|
|
// Copy a string from pszW into a CByteStream object.
|
|
// Copies at most cch chars. If cch is -1, assumes the string is
|
|
// nul-terminated and will copy all chars in string including
|
|
// terminating NULL.
|
|
//
|
|
int CopyStringW(CByteStream& stm, LPWSTR pszW, int cch = -1);
|
|
//
|
|
// Prevent copy.
|
|
//
|
|
CDlgTemplateConverter(const CDlgTemplateConverter& rhs);
|
|
CDlgTemplateConverter& operator = (const CDlgTemplateConverter& rhs);
|
|
};
|
|
|
|
|
|
//
|
|
// Generic alignment function.
|
|
// Give it an address and an alignment size and it returns
|
|
// the address adjusted for the requested alignment.
|
|
//
|
|
// n : 2 = 16-bit
|
|
// 4 = 32-bit
|
|
// 8 = 64-bit
|
|
//
|
|
LPVOID Align(LPVOID pv, size_t n)
|
|
{
|
|
const ULONG_PTR x = static_cast<ULONG_PTR>(n) - 1;
|
|
return reinterpret_cast<LPVOID>((reinterpret_cast<ULONG_PTR>(pv) + x) & ~x);
|
|
}
|
|
|
|
inline LPVOID AlignWord(LPVOID pv)
|
|
{
|
|
return ::Align(pv, sizeof(WORD));
|
|
}
|
|
|
|
inline LPVOID AlignDWord(LPVOID pv)
|
|
{
|
|
return ::Align(pv, sizeof(DWORD));
|
|
}
|
|
|
|
inline LPVOID AlignQWord(LPVOID pv)
|
|
{
|
|
return ::Align(pv, sizeof(ULONGLONG));
|
|
}
|
|
|
|
|
|
|
|
CByteStream::CByteStream(
|
|
int cbDefGrow
|
|
) : m_cbDefGrow(MAX(cbDefGrow, 1)),
|
|
m_pbBuf(NULL),
|
|
m_pbRead(NULL),
|
|
m_pbWrite(NULL),
|
|
m_pbEnd(NULL),
|
|
m_bWriteErr(false),
|
|
m_bReadErr(false),
|
|
m_bOwnsBuf(true)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
CByteStream::~CByteStream(
|
|
void
|
|
)
|
|
{
|
|
if (m_bOwnsBuf && NULL != m_pbBuf)
|
|
{
|
|
LocalFree(m_pbBuf);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Simple checks to validate stream state.
|
|
// In non-debug builds, this will be a no-op.
|
|
// Use ASSERT_VALIDSTREAM macro.
|
|
//
|
|
void
|
|
CByteStream::Validate(
|
|
void
|
|
) const
|
|
{
|
|
ASSERT(m_pbEnd >= m_pbBuf);
|
|
ASSERT(m_pbWrite >= m_pbBuf);
|
|
ASSERT(m_pbRead >= m_pbBuf);
|
|
ASSERT(m_pbWrite <= m_pbEnd);
|
|
ASSERT(m_pbRead <= m_pbEnd);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
# define ASSERT_VALIDSTREAM(ps) ps->Validate()
|
|
#else
|
|
# define ASSERT_VALIDSTREAM(ps)
|
|
#endif
|
|
|
|
//
|
|
// Read "cb" bytes from the stream and write them to
|
|
// the location specified in "pb". Return number
|
|
// of bytes read. Note that if we don't "own" the
|
|
// buffer (i.e. the client has called GetBuffer but
|
|
// not ReleaseBuffer), no read will occur.
|
|
//
|
|
int
|
|
CByteStream::Read(
|
|
LPVOID pb,
|
|
int cb
|
|
)
|
|
{
|
|
ASSERT_VALIDSTREAM(this);
|
|
|
|
int cbRead = 0;
|
|
if (m_bOwnsBuf)
|
|
{
|
|
cbRead = MIN(static_cast<int>(m_pbEnd - m_pbRead), cb);
|
|
CopyMemory(pb, m_pbRead, cbRead);
|
|
m_pbRead += cbRead;
|
|
if (cb != cbRead)
|
|
m_bReadErr = true;
|
|
}
|
|
|
|
ASSERT_VALIDSTREAM(this);
|
|
|
|
return cbRead;
|
|
}
|
|
|
|
|
|
//
|
|
// Write "cb" bytes from location "pb" into the stream.
|
|
// Return number of bytes written. Note that if we don't "own" the
|
|
// buffer (i.e. the client has called GetBuffer but
|
|
// not ReleaseBuffer), no write will occur.
|
|
//
|
|
int
|
|
CByteStream::Write(
|
|
const VOID *pb,
|
|
int cb
|
|
)
|
|
{
|
|
ASSERT_VALIDSTREAM(this);
|
|
|
|
int cbWritten = 0;
|
|
if (m_bOwnsBuf)
|
|
{
|
|
if (m_pbWrite + cb < m_pbEnd ||
|
|
GrowBuffer(static_cast<int>(m_pbEnd - m_pbBuf) + cb + m_cbDefGrow))
|
|
{
|
|
CopyMemory(m_pbWrite, pb, cb);
|
|
m_pbWrite += cb;
|
|
cbWritten = cb;
|
|
}
|
|
else
|
|
m_bWriteErr = true;
|
|
}
|
|
|
|
ASSERT_VALIDSTREAM(this);
|
|
|
|
return cbWritten;
|
|
}
|
|
|
|
//
|
|
// Reallocate the buffer by cb or m_cbDefGrow.
|
|
// Copy existing contents to new buffer. All internal
|
|
// pointers are updated.
|
|
//
|
|
bool
|
|
CByteStream::GrowBuffer(
|
|
int cb // optional. Default is 0 causing us to use m_cbDefGrow.
|
|
)
|
|
{
|
|
bool bResult = false;
|
|
int cbGrow = 0 < cb ? cb : m_cbDefGrow;
|
|
ULONG_PTR ulReadOfs = m_pbRead - m_pbBuf;
|
|
ULONG_PTR ulWriteOfs = m_pbWrite - m_pbBuf;
|
|
ULONG_PTR cbAlloc = m_pbEnd - m_pbBuf;
|
|
LPBYTE pNew = static_cast<LPBYTE>(LocalAlloc(LPTR, cbAlloc + cbGrow));
|
|
if (NULL != pNew)
|
|
{
|
|
if (NULL != m_pbBuf)
|
|
{
|
|
CopyMemory(pNew, m_pbBuf, cbAlloc);
|
|
LocalFree(m_pbBuf);
|
|
}
|
|
m_pbBuf = pNew;
|
|
m_pbRead = m_pbBuf + ulReadOfs;
|
|
m_pbWrite = m_pbBuf + ulWriteOfs;
|
|
m_pbEnd = m_pbBuf + cbAlloc + cbGrow;
|
|
bResult = true;
|
|
}
|
|
|
|
ASSERT_VALIDSTREAM(this);
|
|
return bResult;
|
|
}
|
|
|
|
//
|
|
// Align the read or write pointer on the stream.
|
|
// The write pointer is aligned by padding skipped bytes with 0.
|
|
//
|
|
void
|
|
CByteStream::Align(
|
|
CByteStream::AlignType a,
|
|
size_t n
|
|
)
|
|
{
|
|
static const BYTE fill[8] = {0};
|
|
if (m_bOwnsBuf)
|
|
{
|
|
switch(a)
|
|
{
|
|
case eAlignWrite:
|
|
Write(fill, static_cast<int>(reinterpret_cast<LPBYTE>(::Align(m_pbWrite, n)) - m_pbWrite));
|
|
break;
|
|
|
|
case eAlignRead:
|
|
m_pbRead = reinterpret_cast<LPBYTE>(::Align(m_pbRead, n));
|
|
if (m_pbRead >= m_pbEnd)
|
|
m_bReadErr = true;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
ASSERT_VALIDSTREAM(this);
|
|
}
|
|
|
|
|
|
//
|
|
// Caller takes ownership of the buffer.
|
|
//
|
|
LPBYTE
|
|
CByteStream::GetBuffer(
|
|
bool bPermanent // optional. Default is false.
|
|
)
|
|
{
|
|
LPBYTE pbRet = m_pbBuf;
|
|
if (bPermanent)
|
|
{
|
|
//
|
|
// Caller now permanently owns the buffer.
|
|
// Can't return it through ReleaseBuffer().
|
|
// Reset the internal stream control values.
|
|
//
|
|
m_pbBuf = m_pbWrite = m_pbRead = m_pbEnd = NULL;
|
|
m_bWriteErr = m_bReadErr = false;
|
|
m_bOwnsBuf = true;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Caller now owns the buffer but it can be returned
|
|
// through ReleaseBuffer().
|
|
//
|
|
m_bOwnsBuf = false;
|
|
}
|
|
return pbRet;
|
|
}
|
|
|
|
|
|
//
|
|
// Take back ownership of the buffer.
|
|
// Returns:
|
|
//
|
|
// true = CByteStream object took back ownership.
|
|
// false = CByteStream object couldn't take ownership.
|
|
//
|
|
bool
|
|
CByteStream::ReleaseBuffer(
|
|
LPBYTE pbBuf
|
|
)
|
|
{
|
|
if (pbBuf == m_pbBuf)
|
|
{
|
|
m_bOwnsBuf = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
//
|
|
// Reset the stream.
|
|
//
|
|
void
|
|
CByteStream::Reset(
|
|
void
|
|
)
|
|
{
|
|
if (NULL != m_pbBuf)
|
|
{
|
|
LocalFree(m_pbBuf);
|
|
}
|
|
m_pbBuf = m_pbWrite = m_pbRead = m_pbEnd = NULL;
|
|
m_bWriteErr = m_bReadErr = false;
|
|
m_bOwnsBuf = true;
|
|
}
|
|
|
|
|
|
//
|
|
// Copy one or more WORDs from the location provided in "pszW" into
|
|
// the stream. If cch is -1, it's assumed that the string is nul-terminated.
|
|
// Returns the number of WCHARs written.
|
|
//
|
|
int
|
|
CDlgTemplateConverter::CopyStringW(
|
|
CByteStream& stm,
|
|
LPWSTR pszW,
|
|
int cch
|
|
)
|
|
{
|
|
if (-1 == cch)
|
|
cch = lstrlenW(pszW) + 1;
|
|
return stm.Write(pszW, cch * sizeof(WCHAR)) / sizeof(WCHAR);
|
|
}
|
|
|
|
//
|
|
// Convert a DLGTEMPLATE structure to a DLGTEMPLATEEX structure.
|
|
// pti is the address of the DLGTEMPLATE to be converted.
|
|
// ppto points to a LPDLGTEMPLATEEX ptr to receive the address of the
|
|
// converted template structure. Caller is responsible for freeing
|
|
// this buffer with LocalFree.
|
|
//
|
|
// Returns: E_OUTOFMEMORY, NOERROR
|
|
//
|
|
HRESULT
|
|
CDlgTemplateConverter::DlgToDlgEx(
|
|
LPDLGTEMPLATE pti,
|
|
LPDLGTEMPLATEEX *ppto
|
|
)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
LPWORD pw = reinterpret_cast<LPWORD>(pti);
|
|
*ppto = NULL;
|
|
|
|
//
|
|
// Reset the stream.
|
|
//
|
|
m_stm.Reset();
|
|
//
|
|
// Convert DLGTEMPLATE -> DLGTEMPLATEEX
|
|
//
|
|
hr = DlgHdrToDlgEx(m_stm, &pw);
|
|
//
|
|
// Convert each DLGITEMTEMPLATE -> DLGITEMTEMPLATEEX
|
|
//
|
|
for (int i = 0; i < pti->cdit && SUCCEEDED(hr); i++)
|
|
{
|
|
pw = reinterpret_cast<LPWORD>(::AlignDWord(pw));
|
|
m_stm.AlignWriteDword();
|
|
hr = DlgItemToDlgEx(m_stm, &pw);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Return the buffer to the caller. Buffer is permanently
|
|
// detached from the stream object so the stream's dtor
|
|
// won't free it.
|
|
//
|
|
*ppto = reinterpret_cast<LPDLGTEMPLATEEX>(m_stm.GetBuffer(true));
|
|
}
|
|
return hr;
|
|
};
|
|
|
|
|
|
//
|
|
// Convert DLGTEMPLATE -> DLGTEMPLATEEX
|
|
//
|
|
// s = Stream to hold converted template.
|
|
// ppw = Address of current read pointer into the template being converted.
|
|
// On exit, the referenced pointer is updated with the current read location.
|
|
//
|
|
// Returns: E_OUTOFMEMORY, NOERROR
|
|
//
|
|
HRESULT
|
|
CDlgTemplateConverter::DlgHdrToDlgEx(
|
|
CByteStream& s,
|
|
LPWORD *ppw
|
|
)
|
|
{
|
|
LPWORD pw = *ppw;
|
|
LPDLGTEMPLATE pt = reinterpret_cast<LPDLGTEMPLATE>(pw);
|
|
|
|
//
|
|
// Convert the fixed-length stuff.
|
|
//
|
|
s << static_cast<WORD>(1) // wDlgVer
|
|
<< static_cast<WORD>(0xFFFF) // wSignature
|
|
<< static_cast<DWORD>(0) // dwHelpID
|
|
<< static_cast<DWORD>(pt->dwExtendedStyle)
|
|
<< static_cast<DWORD>(pt->style)
|
|
<< static_cast<WORD>(pt->cdit)
|
|
<< static_cast<short>(pt->x)
|
|
<< static_cast<short>(pt->y)
|
|
<< static_cast<short>(pt->cx)
|
|
<< static_cast<short>(pt->cy);
|
|
|
|
//
|
|
// Arrays are always WORD aligned.
|
|
//
|
|
pw = reinterpret_cast<LPWORD>(::AlignWord(reinterpret_cast<LPBYTE>(pw) + sizeof(DLGTEMPLATE)));
|
|
s.AlignWriteWord();
|
|
|
|
//
|
|
// Copy the menu array.
|
|
//
|
|
switch(*pw)
|
|
{
|
|
case 0xFFFF:
|
|
s << *pw++;
|
|
//
|
|
// Fall through...
|
|
//
|
|
case 0x0000:
|
|
s << *pw++;
|
|
break;
|
|
|
|
default:
|
|
pw += CopyStringW(s, (LPWSTR)pw);
|
|
break;
|
|
};
|
|
//
|
|
// Copy the class array.
|
|
//
|
|
switch(*pw)
|
|
{
|
|
case 0xFFFF:
|
|
s << *pw++;
|
|
//
|
|
// Fall through...
|
|
//
|
|
case 0x0000:
|
|
s << *pw++;
|
|
break;
|
|
|
|
default:
|
|
pw += CopyStringW(s, (LPWSTR)pw);
|
|
break;
|
|
};
|
|
//
|
|
// Copy the title array.
|
|
//
|
|
switch(*pw)
|
|
{
|
|
case 0x0000:
|
|
s << *pw++;
|
|
break;
|
|
|
|
default:
|
|
pw += CopyStringW(s, (LPWSTR)pw);
|
|
break;
|
|
};
|
|
//
|
|
// Copy font information if it's present.
|
|
//
|
|
if (DS_SETFONT & pt->style)
|
|
{
|
|
s << *pw++; // pt size
|
|
s << static_cast<WORD>(FW_NORMAL); // weight (default, not in DLGTEMPLATE)
|
|
s << static_cast<BYTE>(FALSE); // italic (default, not in DLGTEMPLATE)
|
|
s << static_cast<BYTE>(m_iCharset); // charset (default if not given,
|
|
// not in DLGTEMPLATE)
|
|
pw += CopyStringW(s, (LPWSTR)pw);
|
|
}
|
|
|
|
*ppw = pw;
|
|
|
|
return s.WriteError() ? E_OUTOFMEMORY : NOERROR;
|
|
}
|
|
|
|
|
|
//
|
|
// Convert DLGITEMTEMPLATE -> DLGITEMTEMPLATEEX
|
|
//
|
|
// s = Stream to hold converted template.
|
|
// ppw = Address of current read pointer into the template being converted.
|
|
// On exit, the referenced pointer is updated with the current read location.
|
|
//
|
|
// Returns: E_OUTOFMEMORY, NOERROR
|
|
//
|
|
HRESULT
|
|
CDlgTemplateConverter::DlgItemToDlgEx(
|
|
CByteStream& s,
|
|
LPWORD *ppw
|
|
)
|
|
{
|
|
LPWORD pw = *ppw;
|
|
LPDLGITEMTEMPLATE pit = reinterpret_cast<LPDLGITEMTEMPLATE>(pw);
|
|
|
|
//
|
|
// Convert the fixed-length stuff.
|
|
//
|
|
s << static_cast<DWORD>(0) // dwHelpID
|
|
<< static_cast<DWORD>(pit->dwExtendedStyle)
|
|
<< static_cast<DWORD>(pit->style)
|
|
<< static_cast<short>(pit->x)
|
|
<< static_cast<short>(pit->y)
|
|
<< static_cast<short>(pit->cx)
|
|
<< static_cast<short>(pit->cy)
|
|
<< static_cast<DWORD>(pit->id);
|
|
|
|
//
|
|
// Arrays are always word aligned.
|
|
//
|
|
pw = reinterpret_cast<LPWORD>(::AlignWord(reinterpret_cast<LPBYTE>(pw) + sizeof(DLGITEMTEMPLATE)));
|
|
s.AlignWriteWord();
|
|
|
|
//
|
|
// Copy the class array.
|
|
//
|
|
switch(*pw)
|
|
{
|
|
case 0xFFFF:
|
|
s << *pw++;
|
|
s << *pw++; // Class code.
|
|
break;
|
|
|
|
default:
|
|
pw += CopyStringW(s, (LPWSTR)pw);
|
|
break;
|
|
};
|
|
//
|
|
// Copy the title array.
|
|
//
|
|
switch(*pw)
|
|
{
|
|
case 0xFFFF:
|
|
s << *pw++;
|
|
s << *pw++; // Resource ordinal value.
|
|
break;
|
|
|
|
default:
|
|
pw += CopyStringW(s, (LPWSTR)pw);
|
|
break;
|
|
};
|
|
//
|
|
// Copy the creation data.
|
|
// *pw is either 0 or the number of bytes of creation data,
|
|
// including *pw.
|
|
//
|
|
switch(*pw)
|
|
{
|
|
case 0x0000:
|
|
s << *pw++;
|
|
break;
|
|
|
|
default:
|
|
pw += s.Write(pw, *pw) / sizeof(WORD);
|
|
break;
|
|
};
|
|
|
|
*ppw = pw;
|
|
|
|
return s.WriteError() ? E_OUTOFMEMORY : NOERROR;
|
|
}
|
|
|
|
|
|
//
|
|
// This is the public function for converting a DLGTEMPLATE to
|
|
// a DLGTEMPLATEEX.
|
|
//
|
|
// Returns: E_OUTOFMEMORY, NOERROR
|
|
//
|
|
HRESULT
|
|
CvtDlgToDlgEx(
|
|
LPDLGTEMPLATE pTemplate,
|
|
LPDLGTEMPLATEEX *ppTemplateExOut,
|
|
int iCharset
|
|
)
|
|
{
|
|
CDlgTemplateConverter dtc(iCharset);
|
|
return dtc.DlgToDlgEx(pTemplate, ppTemplateExOut);
|
|
}
|
|
|