Source code of Windows XP (NT5)
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.

839 lines
20 KiB

  1. //
  2. // This module provides the following functions:
  3. //
  4. // CvtDlgToDlgEx - Converts a DLGTEMPLATE to a DLGTEMPLATEEX
  5. //
  6. //
  7. #include "ctlspriv.h"
  8. #include "dlgcvt.h"
  9. //
  10. // Define the amount (bytes) the stream buffer grows when required.
  11. // It will grow enough to satisfy the required write PLUS this
  12. // amount.
  13. //
  14. #ifdef DEBUG
  15. # define STREAM_GROW_BYTES 32 // Exercise stream growth.
  16. #else
  17. # define STREAM_GROW_BYTES 512
  18. #endif
  19. //
  20. // Simple MIN/MAX inline helpers.
  21. //
  22. #if (defined UNIX && defined ux10)
  23. //IEUNIX: hp's version of "/usr/local/include/sys/param.h defines MAX and MIN
  24. //macro's and breaks hp's build
  25. #undef MAX(a,b)
  26. #undef MIN(a,b)
  27. #endif //UNIX && ux10
  28. template <class T>
  29. inline const T& MIN(const T& a, const T& b)
  30. {
  31. return a < b ? a : b;
  32. }
  33. template <class T>
  34. inline const T& MAX(const T& a, const T& b)
  35. {
  36. return a > b ? a : b;
  37. }
  38. //
  39. // This class implements a simple dynamic stream that grows as you
  40. // add data to it. It's modeled after the strstream class provided
  41. // by the C++ std lib. Unlike the std lib implementation, this one
  42. // doesn't require C++ EH to be enabled. If comctl32 compiled with
  43. // C++ EH enabled, I would have used strstream instead.
  44. // [brianau - 10/5/98]
  45. //
  46. class CByteStream
  47. {
  48. public:
  49. explicit CByteStream(int cbDefGrow = 512);
  50. ~CByteStream(void);
  51. //
  52. // Used as argument to AlignXXXX member functions.
  53. //
  54. enum AlignType { eAlignWrite, eAlignRead };
  55. //
  56. // Basic read/write functions.
  57. //
  58. int Read(LPVOID pb, int cb);
  59. int Write(const VOID *pb, int cb);
  60. //
  61. // Determine if there was an error when reading or
  62. // writing to the stream.
  63. //
  64. bool ReadError(void) const
  65. { return m_bReadErr; }
  66. bool WriteError(void) const
  67. { return m_bWriteErr; }
  68. //
  69. // Reset the stream read or write pointer.
  70. //
  71. void ResetRead(void)
  72. { m_pbRead = m_pbBuf; m_bReadErr = false; }
  73. void ResetWrite(void)
  74. { m_pbWrite = m_pbBuf; m_bWriteErr = false; }
  75. //
  76. // Reset the stream.
  77. //
  78. void Reset(void);
  79. //
  80. // These functions align the read and write stream pointers.
  81. //
  82. void AlignReadWord(void)
  83. { Align(eAlignRead, sizeof(WORD)); }
  84. void AlignReadDword(void)
  85. { Align(eAlignRead, sizeof(DWORD)); }
  86. void AlignReadQword(void)
  87. { Align(eAlignRead, sizeof(ULONGLONG)); }
  88. void AlignWriteWord(void)
  89. { Align(eAlignWrite, sizeof(WORD)); }
  90. void AlignWriteDword(void)
  91. { Align(eAlignWrite, sizeof(DWORD)); }
  92. void AlignWriteQword(void)
  93. { Align(eAlignWrite, sizeof(ULONGLONG)); }
  94. //
  95. // GetBuffer returns the address of the stream buffer in memory.
  96. // The buffer is "frozen" so it will not be released if the stream
  97. // object is destroyed. At this point, you own the buffer.
  98. // If bPermanent is false, you can call ReleaseBuffer to return
  99. // control of the buffer to the stream object.
  100. //
  101. LPBYTE GetBuffer(bool bPermanent = false);
  102. //
  103. // ReleaseBuffer returns control of the buffer obtained with GetBuffer
  104. // to the stream object.
  105. //
  106. bool ReleaseBuffer(LPBYTE pbBuf);
  107. //
  108. // Overload the insertion and extraction operators so we can
  109. // work like a normal std lib stream class.
  110. //
  111. template <class T>
  112. CByteStream& operator >> (T& x)
  113. { Read(&x, sizeof(x)); return *this; }
  114. template <class T>
  115. CByteStream& operator << (const T& x)
  116. { Write(&x, sizeof(x)); return *this; }
  117. private:
  118. int m_cbDefGrow; // Default amount (bytes) to grow when expanding buffer.
  119. LPBYTE m_pbBuf; // Addr of allocated buffer.
  120. LPBYTE m_pbRead; // Addr for next read.
  121. LPBYTE m_pbWrite; // Addr for next write.
  122. LPBYTE m_pbEnd; // Addr of byte following last byte in buffer.
  123. bool m_bWriteErr; // Any read errors?
  124. bool m_bReadErr; // Any write errors?
  125. bool m_bOwnsBuf; // true == delete buffer in dtor.
  126. //
  127. // Expand the buffer as needed.
  128. //
  129. bool GrowBuffer(int cb = 0);
  130. //
  131. // Align the read or write buffer pointer.
  132. // Used internally by the AlignXXXXX member functions.
  133. //
  134. void Align(AlignType a, size_t n);
  135. //
  136. // Internal consistency checks for debug builds.
  137. //
  138. void Validate(void) const;
  139. //
  140. // Prevent copy.
  141. //
  142. CByteStream(const CByteStream& rhs);
  143. CByteStream& operator = (const CByteStream& rhs);
  144. };
  145. //
  146. // Class for converting in-memory dialog templates between the two
  147. // structures DLGTEMPLATE <-> DLGTEMPLATEEX.
  148. //
  149. // Currently, the object only converts from DLGTEMPLATE -> DLGTEMPLATEEX.
  150. // It would be simple to create the code for the inverse conversion. However,
  151. // it's currently not needed so I didn't create it.
  152. //
  153. class CDlgTemplateConverter
  154. {
  155. public:
  156. explicit CDlgTemplateConverter(int iCharSet = DEFAULT_CHARSET)
  157. : m_iCharset(iCharSet),
  158. m_stm(STREAM_GROW_BYTES) { }
  159. ~CDlgTemplateConverter(void) { }
  160. HRESULT DlgToDlgEx(LPDLGTEMPLATE pTemplateIn, LPDLGTEMPLATEEX *ppTemplateOut);
  161. HRESULT DlgExToDlg(LPDLGTEMPLATEEX pTemplateIn, LPDLGTEMPLATE *ppTemplateOut)
  162. { return E_NOTIMPL; }
  163. private:
  164. int m_iCharset;
  165. CByteStream m_stm; // For converted template.
  166. #ifndef UNIX
  167. HRESULT DlgHdrToDlgEx(CByteStream& s, LPWORD *ppw);
  168. HRESULT DlgItemToDlgEx(CByteStream& s, LPWORD *ppw);
  169. #else
  170. HRESULT DlgHdrToDlgEx(CByteStream& s, LPDWORD *ppw);
  171. HRESULT DlgItemToDlgEx(CByteStream& s, LPDWORD *ppw);
  172. #endif
  173. HRESULT DlgExHdrToDlg(CByteStream& s, LPWORD *ppw)
  174. { return E_NOTIMPL; }
  175. HRESULT DlgExItemToDlg(CByteStream& s, LPWORD *ppw)
  176. { return E_NOTIMPL; }
  177. //
  178. // Copy a string from pszW into a CByteStream object.
  179. // Copies at most cch chars. If cch is -1, assumes the string is
  180. // nul-terminated and will copy all chars in string including
  181. // terminating NULL.
  182. //
  183. int CopyStringW(CByteStream& stm, LPWSTR pszW, int cch = -1);
  184. //
  185. // Prevent copy.
  186. //
  187. CDlgTemplateConverter(const CDlgTemplateConverter& rhs);
  188. CDlgTemplateConverter& operator = (const CDlgTemplateConverter& rhs);
  189. };
  190. //
  191. // Generic alignment function.
  192. // Give it an address and an alignment size and it returns
  193. // the address adjusted for the requested alignment.
  194. //
  195. // n : 2 = 16-bit
  196. // 4 = 32-bit
  197. // 8 = 64-bit
  198. //
  199. LPVOID Align(LPVOID pv, size_t n)
  200. {
  201. const ULONG_PTR x = static_cast<ULONG_PTR>(n) - 1;
  202. return reinterpret_cast<LPVOID>((reinterpret_cast<ULONG_PTR>(pv) + x) & ~x);
  203. }
  204. inline LPVOID AlignWord(LPVOID pv)
  205. {
  206. return ::Align(pv, sizeof(WORD));
  207. }
  208. inline LPVOID AlignDWord(LPVOID pv)
  209. {
  210. return ::Align(pv, sizeof(DWORD));
  211. }
  212. inline LPVOID AlignQWord(LPVOID pv)
  213. {
  214. return ::Align(pv, sizeof(ULONGLONG));
  215. }
  216. CByteStream::CByteStream(
  217. int cbDefGrow
  218. ) : m_cbDefGrow(MAX(cbDefGrow, 1)),
  219. m_pbBuf(NULL),
  220. m_pbRead(NULL),
  221. m_pbWrite(NULL),
  222. m_pbEnd(NULL),
  223. m_bWriteErr(false),
  224. m_bReadErr(false),
  225. m_bOwnsBuf(true)
  226. {
  227. }
  228. CByteStream::~CByteStream(
  229. void
  230. )
  231. {
  232. if (m_bOwnsBuf && NULL != m_pbBuf)
  233. {
  234. LocalFree(m_pbBuf);
  235. }
  236. }
  237. //
  238. // Simple checks to validate stream state.
  239. // In non-debug builds, this will be a no-op.
  240. // Use ASSERT_VALIDSTREAM macro.
  241. //
  242. void
  243. CByteStream::Validate(
  244. void
  245. ) const
  246. {
  247. ASSERT(m_pbEnd >= m_pbBuf);
  248. ASSERT(m_pbWrite >= m_pbBuf);
  249. ASSERT(m_pbRead >= m_pbBuf);
  250. ASSERT(m_pbWrite <= m_pbEnd);
  251. ASSERT(m_pbRead <= m_pbEnd);
  252. }
  253. #ifdef DEBUG
  254. # define ASSERT_VALIDSTREAM(ps) ps->Validate()
  255. #else
  256. # define ASSERT_VALIDSTREAM(ps)
  257. #endif
  258. //
  259. // Read "cb" bytes from the stream and write them to
  260. // the location specified in "pb". Return number
  261. // of bytes read. Note that if we don't "own" the
  262. // buffer (i.e. the client has called GetBuffer but
  263. // not ReleaseBuffer), no read will occur.
  264. //
  265. int
  266. CByteStream::Read(
  267. LPVOID pb,
  268. int cb
  269. )
  270. {
  271. ASSERT_VALIDSTREAM(this);
  272. int cbRead = 0;
  273. if (m_bOwnsBuf)
  274. {
  275. cbRead = MIN(static_cast<int>(m_pbEnd - m_pbRead), cb);
  276. CopyMemory(pb, m_pbRead, cbRead);
  277. m_pbRead += cbRead;
  278. if (cb != cbRead)
  279. m_bReadErr = true;
  280. }
  281. ASSERT_VALIDSTREAM(this);
  282. return cbRead;
  283. }
  284. //
  285. // Write "cb" bytes from location "pb" into the stream.
  286. // Return number of bytes written. Note that if we don't "own" the
  287. // buffer (i.e. the client has called GetBuffer but
  288. // not ReleaseBuffer), no write will occur.
  289. //
  290. int
  291. CByteStream::Write(
  292. const VOID *pb,
  293. int cb
  294. )
  295. {
  296. ASSERT_VALIDSTREAM(this);
  297. int cbWritten = 0;
  298. if (m_bOwnsBuf)
  299. {
  300. if (m_pbWrite + cb < m_pbEnd ||
  301. GrowBuffer(static_cast<int>(m_pbEnd - m_pbBuf) + cb + m_cbDefGrow))
  302. {
  303. CopyMemory(m_pbWrite, pb, cb);
  304. m_pbWrite += cb;
  305. cbWritten = cb;
  306. }
  307. else
  308. m_bWriteErr = true;
  309. }
  310. ASSERT_VALIDSTREAM(this);
  311. return cbWritten;
  312. }
  313. //
  314. // Reallocate the buffer by cb or m_cbDefGrow.
  315. // Copy existing contents to new buffer. All internal
  316. // pointers are updated.
  317. //
  318. bool
  319. CByteStream::GrowBuffer(
  320. int cb // optional. Default is 0 causing us to use m_cbDefGrow.
  321. )
  322. {
  323. bool bResult = false;
  324. int cbGrow = 0 < cb ? cb : m_cbDefGrow;
  325. ULONG_PTR ulReadOfs = m_pbRead - m_pbBuf;
  326. ULONG_PTR ulWriteOfs = m_pbWrite - m_pbBuf;
  327. ULONG_PTR cbAlloc = m_pbEnd - m_pbBuf;
  328. LPBYTE pNew = static_cast<LPBYTE>(LocalAlloc(LPTR, cbAlloc + cbGrow));
  329. if (NULL != pNew)
  330. {
  331. if (NULL != m_pbBuf)
  332. {
  333. CopyMemory(pNew, m_pbBuf, cbAlloc);
  334. LocalFree(m_pbBuf);
  335. }
  336. m_pbBuf = pNew;
  337. m_pbRead = m_pbBuf + ulReadOfs;
  338. m_pbWrite = m_pbBuf + ulWriteOfs;
  339. m_pbEnd = m_pbBuf + cbAlloc + cbGrow;
  340. bResult = true;
  341. }
  342. ASSERT_VALIDSTREAM(this);
  343. return bResult;
  344. }
  345. //
  346. // Align the read or write pointer on the stream.
  347. // The write pointer is aligned by padding skipped bytes with 0.
  348. //
  349. void
  350. CByteStream::Align(
  351. CByteStream::AlignType a,
  352. size_t n
  353. )
  354. {
  355. static const BYTE fill[8] = {0};
  356. if (m_bOwnsBuf)
  357. {
  358. switch(a)
  359. {
  360. case eAlignWrite:
  361. Write(fill, static_cast<int>(reinterpret_cast<LPBYTE>(::Align(m_pbWrite, n)) - m_pbWrite));
  362. break;
  363. case eAlignRead:
  364. m_pbRead = reinterpret_cast<LPBYTE>(::Align(m_pbRead, n));
  365. if (m_pbRead >= m_pbEnd)
  366. m_bReadErr = true;
  367. break;
  368. default:
  369. break;
  370. }
  371. }
  372. ASSERT_VALIDSTREAM(this);
  373. }
  374. //
  375. // Caller takes ownership of the buffer.
  376. //
  377. LPBYTE
  378. CByteStream::GetBuffer(
  379. bool bPermanent // optional. Default is false.
  380. )
  381. {
  382. LPBYTE pbRet = m_pbBuf;
  383. if (bPermanent)
  384. {
  385. //
  386. // Caller now permanently owns the buffer.
  387. // Can't return it through ReleaseBuffer().
  388. // Reset the internal stream control values.
  389. //
  390. m_pbBuf = m_pbWrite = m_pbRead = m_pbEnd = NULL;
  391. m_bWriteErr = m_bReadErr = false;
  392. m_bOwnsBuf = true;
  393. }
  394. else
  395. {
  396. //
  397. // Caller now owns the buffer but it can be returned
  398. // through ReleaseBuffer().
  399. //
  400. m_bOwnsBuf = false;
  401. }
  402. return pbRet;
  403. }
  404. //
  405. // Take back ownership of the buffer.
  406. // Returns:
  407. //
  408. // true = CByteStream object took back ownership.
  409. // false = CByteStream object couldn't take ownership.
  410. //
  411. bool
  412. CByteStream::ReleaseBuffer(
  413. LPBYTE pbBuf
  414. )
  415. {
  416. if (pbBuf == m_pbBuf)
  417. {
  418. m_bOwnsBuf = true;
  419. return true;
  420. }
  421. return false;
  422. }
  423. //
  424. // Reset the stream.
  425. //
  426. void
  427. CByteStream::Reset(
  428. void
  429. )
  430. {
  431. if (NULL != m_pbBuf)
  432. {
  433. LocalFree(m_pbBuf);
  434. }
  435. m_pbBuf = m_pbWrite = m_pbRead = m_pbEnd = NULL;
  436. m_bWriteErr = m_bReadErr = false;
  437. m_bOwnsBuf = true;
  438. }
  439. //
  440. // Copy one or more WORDs from the location provided in "pszW" into
  441. // the stream. If cch is -1, it's assumed that the string is nul-terminated.
  442. // Returns the number of WCHARs written.
  443. //
  444. int
  445. CDlgTemplateConverter::CopyStringW(
  446. CByteStream& stm,
  447. LPWSTR pszW,
  448. int cch
  449. )
  450. {
  451. if (-1 == cch)
  452. cch = lstrlenW(pszW) + 1;
  453. return stm.Write(pszW, cch * sizeof(WCHAR)) / sizeof(WCHAR);
  454. }
  455. //
  456. // Convert a DLGTEMPLATE structure to a DLGTEMPLATEEX structure.
  457. // pti is the address of the DLGTEMPLATE to be converted.
  458. // ppto points to a LPDLGTEMPLATEEX ptr to receive the address of the
  459. // converted template structure. Caller is responsible for freeing
  460. // this buffer with LocalFree.
  461. //
  462. // Returns: E_OUTOFMEMORY, NOERROR
  463. //
  464. HRESULT
  465. CDlgTemplateConverter::DlgToDlgEx(
  466. LPDLGTEMPLATE pti,
  467. LPDLGTEMPLATEEX *ppto
  468. )
  469. {
  470. HRESULT hr = NOERROR;
  471. #ifndef UNIX
  472. LPWORD pw = reinterpret_cast<LPWORD>(pti);
  473. #else
  474. LPDWORD pw = reinterpret_cast<LPDWORD>(pti);
  475. #endif
  476. *ppto = NULL;
  477. //
  478. // Reset the stream.
  479. //
  480. m_stm.Reset();
  481. //
  482. // Convert DLGTEMPLATE -> DLGTEMPLATEEX
  483. //
  484. hr = DlgHdrToDlgEx(m_stm, &pw);
  485. //
  486. // Convert each DLGITEMTEMPLATE -> DLGITEMTEMPLATEEX
  487. //
  488. for (int i = 0; i < pti->cdit && SUCCEEDED(hr); i++)
  489. {
  490. #ifndef UNIX
  491. pw = reinterpret_cast<LPWORD>(::AlignDWord(pw));
  492. #else
  493. pw = reinterpret_cast<LPDWORD>(::AlignDWord(pw));
  494. #endif
  495. m_stm.AlignWriteDword();
  496. hr = DlgItemToDlgEx(m_stm, &pw);
  497. }
  498. if (SUCCEEDED(hr))
  499. {
  500. //
  501. // Return the buffer to the caller. Buffer is permanently
  502. // detached from the stream object so the stream's dtor
  503. // won't free it.
  504. //
  505. *ppto = reinterpret_cast<LPDLGTEMPLATEEX>(m_stm.GetBuffer(true));
  506. }
  507. return hr;
  508. };
  509. //
  510. // Convert DLGTEMPLATE -> DLGTEMPLATEEX
  511. //
  512. // s = Stream to hold converted template.
  513. // ppw = Address of current read pointer into the template being converted.
  514. // On exit, the referenced pointer is updated with the current read location.
  515. //
  516. // Returns: E_OUTOFMEMORY, NOERROR
  517. //
  518. HRESULT
  519. CDlgTemplateConverter::DlgHdrToDlgEx(
  520. CByteStream& s,
  521. #ifndef UNIX
  522. LPWORD *ppw
  523. #else
  524. LPDWORD *ppw
  525. #endif
  526. )
  527. {
  528. #ifndef UNIX
  529. LPWORD pw = *ppw;
  530. #else
  531. LPDWORD pw = *ppw;
  532. #endif
  533. LPDLGTEMPLATE pt = reinterpret_cast<LPDLGTEMPLATE>(pw);
  534. //
  535. // Convert the fixed-length stuff.
  536. //
  537. s << static_cast<WORD>(1) // wDlgVer
  538. << static_cast<WORD>(0xFFFF) // wSignature
  539. << static_cast<DWORD>(0) // dwHelpID
  540. << static_cast<DWORD>(pt->dwExtendedStyle)
  541. << static_cast<DWORD>(pt->style)
  542. << static_cast<WORD>(pt->cdit)
  543. << static_cast<short>(pt->x)
  544. << static_cast<short>(pt->y)
  545. << static_cast<short>(pt->cx)
  546. << static_cast<short>(pt->cy);
  547. //
  548. // Arrays are always WORD aligned.
  549. //
  550. #ifndef UNIX
  551. pw = reinterpret_cast<LPWORD>(::AlignWord(reinterpret_cast<LPBYTE>(pw) + sizeof(DLGTEMPLATE)));
  552. s.AlignWriteWord();
  553. #else
  554. pw = reinterpret_cast<LPDWORD>(::AlignDWord(reinterpret_cast<LPBYTE>(pw) + sizeof(DLGTEMPLATE)));
  555. s.AlignWriteDword();
  556. #endif
  557. //
  558. // Copy the menu array.
  559. //
  560. switch(*pw)
  561. {
  562. case 0xFFFF:
  563. s << *pw++;
  564. //
  565. // Fall through...
  566. //
  567. case 0x0000:
  568. s << *pw++;
  569. break;
  570. default:
  571. #ifndef UNIX
  572. pw += CopyStringW(s, (LPWSTR)pw);
  573. #else
  574. pw += CopyStringW (s, reinterpret_cast<LPWSTR>(pw));
  575. #endif
  576. break;
  577. };
  578. //
  579. // Copy the class array.
  580. //
  581. switch(*pw)
  582. {
  583. case 0xFFFF:
  584. s << *pw++;
  585. //
  586. // Fall through...
  587. //
  588. case 0x0000:
  589. s << *pw++;
  590. break;
  591. default:
  592. #ifndef UNIX
  593. pw += CopyStringW(s, (LPWSTR)pw);
  594. #else
  595. pw += CopyStringW (s, reinterpret_cast<LPWSTR>(pw));
  596. #endif
  597. break;
  598. };
  599. //
  600. // Copy the title array.
  601. //
  602. switch(*pw)
  603. {
  604. case 0x0000:
  605. s << *pw++;
  606. break;
  607. default:
  608. #ifndef UNIX
  609. pw += CopyStringW(s, (LPWSTR)pw);
  610. #else
  611. pw += CopyStringW (s, reinterpret_cast<LPWSTR>(pw));
  612. #endif
  613. break;
  614. };
  615. //
  616. // Copy font information if it's present.
  617. //
  618. if (DS_SETFONT & pt->style)
  619. {
  620. s << *pw++; // pt size
  621. s << static_cast<WORD>(FW_NORMAL); // weight (default, not in DLGTEMPLATE)
  622. s << static_cast<BYTE>(FALSE); // italic (default, not in DLGTEMPLATE)
  623. s << static_cast<BYTE>(m_iCharset); // charset (default if not given,
  624. // not in DLGTEMPLATE)
  625. #ifndef UNIX
  626. pw += CopyStringW(s, (LPWSTR)pw);
  627. #else
  628. pw += CopyStringW (s, reinterpret_cast<LPWSTR>(pw));
  629. #endif
  630. }
  631. *ppw = pw;
  632. return s.WriteError() ? E_OUTOFMEMORY : NOERROR;
  633. }
  634. //
  635. // Convert DLGITEMTEMPLATE -> DLGITEMTEMPLATEEX
  636. //
  637. // s = Stream to hold converted template.
  638. // ppw = Address of current read pointer into the template being converted.
  639. // On exit, the referenced pointer is updated with the current read location.
  640. //
  641. // Returns: E_OUTOFMEMORY, NOERROR
  642. //
  643. HRESULT
  644. CDlgTemplateConverter::DlgItemToDlgEx(
  645. CByteStream& s,
  646. #ifndef UNIX
  647. LPWORD *ppw
  648. #else
  649. LPDWORD *ppw
  650. #endif
  651. )
  652. {
  653. #ifndef UNIX
  654. LPWORD pw = *ppw;
  655. #else
  656. LPDWORD pw = *ppw;
  657. #endif
  658. LPDLGITEMTEMPLATE pit = reinterpret_cast<LPDLGITEMTEMPLATE>(pw);
  659. //
  660. // Convert the fixed-length stuff.
  661. //
  662. s << static_cast<DWORD>(0) // dwHelpID
  663. << static_cast<DWORD>(pit->dwExtendedStyle)
  664. << static_cast<DWORD>(pit->style)
  665. << static_cast<short>(pit->x)
  666. << static_cast<short>(pit->y)
  667. << static_cast<short>(pit->cx)
  668. << static_cast<short>(pit->cy)
  669. << static_cast<DWORD>(pit->id);
  670. //
  671. // Arrays are always word aligned.
  672. //
  673. #ifndef UNIX
  674. pw = reinterpret_cast<LPWORD>(::AlignWord(reinterpret_cast<LPBYTE>(pw) + sizeof(DLGITEMTEMPLATE)));
  675. s.AlignWriteWord();
  676. #else
  677. pw = reinterpret_cast<LPDWORD>(::AlignWord(reinterpret_cast<LPBYTE>(pw) + sizeof(DLGITEMTEMPLATE)));
  678. s.AlignWriteDword();
  679. #endif
  680. //
  681. // Copy the class array.
  682. //
  683. switch(*pw)
  684. {
  685. case 0xFFFF:
  686. s << *pw++;
  687. s << *pw++; // Class code.
  688. break;
  689. default:
  690. #ifndef UNIX
  691. pw += CopyStringW(s, (LPWSTR)pw);
  692. #else
  693. pw += CopyStringW (s, reinterpret_cast<LPWSTR>(pw));
  694. #endif
  695. break;
  696. };
  697. //
  698. // Copy the title array.
  699. //
  700. switch(*pw)
  701. {
  702. case 0xFFFF:
  703. s << *pw++;
  704. s << *pw++; // Resource ordinal value.
  705. break;
  706. default:
  707. #ifndef UNIX
  708. pw += CopyStringW(s, (LPWSTR)pw);
  709. #else
  710. pw += CopyStringW (s, reinterpret_cast<LPWSTR>(pw));
  711. #endif
  712. break;
  713. };
  714. //
  715. // Copy the creation data.
  716. // *pw is either 0 or the number of bytes of creation data,
  717. // including *pw.
  718. //
  719. switch(*pw)
  720. {
  721. case 0x0000:
  722. s << *pw++;
  723. break;
  724. default:
  725. #ifndef UNIX
  726. pw += s.Write(pw, *pw) / sizeof(WORD);
  727. #else
  728. pw += s.Write(pw, *pw) / sizeof(DWORD);
  729. #endif
  730. break;
  731. };
  732. *ppw = pw;
  733. return s.WriteError() ? E_OUTOFMEMORY : NOERROR;
  734. }
  735. //
  736. // This is the public function for converting a DLGTEMPLATE to
  737. // a DLGTEMPLATEEX.
  738. //
  739. // Returns: E_OUTOFMEMORY, NOERROR
  740. //
  741. HRESULT
  742. CvtDlgToDlgEx(
  743. LPDLGTEMPLATE pTemplate,
  744. LPDLGTEMPLATEEX *ppTemplateExOut,
  745. int iCharset
  746. )
  747. {
  748. CDlgTemplateConverter dtc(iCharset);
  749. return dtc.DlgToDlgEx(pTemplate, ppTemplateExOut);
  750. }