Leaked source code of windows server 2003
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.

1765 lines
41 KiB

  1. //
  2. // CCL32.CPP
  3. // Common Control Classes
  4. //
  5. // Copyright Microsoft 1998-
  6. //
  7. // PRECOMP
  8. #include "precomp.h"
  9. #define COMPILE_MULTIMON_STUBS
  10. #include <multimon.h>
  11. LRESULT CALLBACK DummyMouseHookProc( int code, WPARAM wParam, LPARAM lParam );
  12. HHOOK g_utMouseHookHandle = NULL;
  13. HWND g_utCaptureWindow = NULL;
  14. void UT_CaptureMouse( HWND hwnd )
  15. {
  16. // disable asynchronous input so we don't lose capture because the
  17. // left button isn't down
  18. g_utMouseHookHandle = SetWindowsHookEx( WH_JOURNALRECORD,
  19. DummyMouseHookProc,
  20. g_hInstance,
  21. NULL );
  22. if( g_utMouseHookHandle == NULL )
  23. {
  24. WARNING_OUT(("Failed to insert JournalRecord hook"));
  25. }
  26. // grap mouse
  27. ::SetCapture(hwnd);
  28. g_utCaptureWindow = hwnd;
  29. }
  30. void UT_ReleaseMouse( HWND hwnd )
  31. {
  32. ::ReleaseCapture();
  33. g_utCaptureWindow = NULL;
  34. if (g_utMouseHookHandle != NULL )
  35. {
  36. // le go my lego
  37. ::UnhookWindowsHookEx( g_utMouseHookHandle );
  38. g_utMouseHookHandle = NULL;
  39. }
  40. }
  41. LRESULT CALLBACK DummyMouseHookProc( int code, WPARAM wParam, LPARAM lParam )
  42. {
  43. return( CallNextHookEx( g_utMouseHookHandle, code, wParam, lParam ) );
  44. }
  45. //
  46. // General definitions
  47. //
  48. #define MAX_OPTIONS_LINE_LENGTH 255
  49. #define MAX_SECTION_LEN 200
  50. //
  51. //
  52. // Function: HexDigitToByte
  53. //
  54. // Purpose: Helper function to convert a single hex digit to a byte value.
  55. //
  56. //
  57. BOOL HexDigitToByte(char cHexDigit, BYTE& byte);
  58. BOOL HexDigitToByte(char cHexDigit, BYTE& byte)
  59. {
  60. // Decimal digits
  61. if ( (cHexDigit >= '0')
  62. && (cHexDigit <= '9'))
  63. {
  64. byte = (BYTE) (cHexDigit - '0');
  65. return(TRUE);
  66. }
  67. // Uppercase characters
  68. if ( (cHexDigit >= 'A')
  69. && (cHexDigit <= 'F'))
  70. {
  71. byte = (BYTE) ((cHexDigit - 'A') + 10);
  72. return(TRUE);
  73. }
  74. // Lowercase characters
  75. if ( (cHexDigit >= 'a')
  76. && (cHexDigit <= 'f'))
  77. {
  78. byte = (BYTE) ((cHexDigit - 'a') + 10);
  79. return(TRUE);
  80. }
  81. // The character is not a valid hex digit
  82. return(FALSE);
  83. }
  84. //
  85. //
  86. // Function: GetIntegerOption
  87. //
  88. // Purpose: Retrieve a named option from the dictionary and convert the
  89. // option string to a long integer value.
  90. //
  91. //
  92. LONG OPT_GetIntegerOption
  93. (
  94. LPCSTR cstrOptionName,
  95. LONG lDefault
  96. )
  97. {
  98. LONG lResult;
  99. TCHAR cstrValue[MAX_OPTIONS_LINE_LENGTH];
  100. if (OPT_Lookup(cstrOptionName, cstrValue, MAX_OPTIONS_LINE_LENGTH))
  101. {
  102. // Option has been found, convert it to a long
  103. lResult = RtStrToInt(cstrValue);
  104. }
  105. else
  106. {
  107. // The option is not in the dictionary, return the default
  108. lResult = lDefault;
  109. }
  110. return lResult;
  111. }
  112. //
  113. //
  114. // Function: GetBooleanOption
  115. //
  116. // Purpose: Retrieve a named option from the dictionary and convert it to
  117. // a boolean value.
  118. //
  119. //
  120. BOOL OPT_GetBooleanOption
  121. (
  122. LPCSTR cstrOptionName,
  123. BOOL bDefault
  124. )
  125. {
  126. TCHAR cstrValue[MAX_OPTIONS_LINE_LENGTH];
  127. // Lookup the option
  128. if (OPT_Lookup(cstrOptionName, cstrValue,MAX_OPTIONS_LINE_LENGTH))
  129. {
  130. return(cstrValue[0] == 'y' || cstrValue[0] =='Y') ;
  131. }
  132. return bDefault;
  133. }
  134. //
  135. //
  136. // Function: GetStringOption
  137. //
  138. // Purpose: Retrieve a named option from the dictionary and return a copy
  139. // of it. No conversion of the string is performed.
  140. //
  141. //
  142. void OPT_GetStringOption
  143. (
  144. LPCSTR cstrOptionName,
  145. LPSTR cstrValue,
  146. UINT size
  147. )
  148. {
  149. if (!OPT_Lookup(cstrOptionName, cstrValue, size) || !(lstrlen(cstrValue)))
  150. {
  151. *cstrValue = _T('\0');
  152. }
  153. }
  154. //
  155. //
  156. // Function: Lookup
  157. //
  158. // Purpose: Retrieve a named option from the dictionary and return a copy
  159. // of it in the CString object passed. No conversion is performed.
  160. //
  161. //
  162. BOOL OPT_Lookup
  163. (
  164. LPCSTR cstrOptionName,
  165. LPCSTR cstrResult,
  166. UINT size
  167. )
  168. {
  169. BOOL fSuccess = FALSE;
  170. HKEY read_hkey = NULL;
  171. DWORD read_type;
  172. DWORD read_bufsize;
  173. // open key
  174. if (RegOpenKeyEx( HKEY_CURRENT_USER,
  175. WHITEBOARD_KEY,
  176. 0,
  177. KEY_EXECUTE,
  178. &read_hkey )
  179. != ERROR_SUCCESS )
  180. {
  181. TRACE_MSG(("Could not open key"));
  182. goto bail_out;
  183. }
  184. // read key's value
  185. read_bufsize = size;
  186. if (RegQueryValueEx( read_hkey,
  187. cstrOptionName,
  188. NULL,
  189. &read_type,
  190. (LPBYTE)cstrResult,
  191. &read_bufsize )
  192. != ERROR_SUCCESS )
  193. {
  194. TRACE_MSG(("Could not read key"));
  195. goto bail_out;
  196. }
  197. // check for valid type
  198. if (read_type != REG_SZ)
  199. {
  200. WARNING_OUT(("Bad key data"));
  201. goto bail_out;
  202. }
  203. fSuccess = TRUE;
  204. bail_out:
  205. if (read_hkey != NULL)
  206. RegCloseKey(read_hkey);
  207. return (fSuccess);
  208. }
  209. //
  210. //
  211. // Function: GetWindowRectOption
  212. //
  213. // Purpose: Retrieve a named option from the dictionary and convert it to
  214. // a window rectangle. The rectangle is checked to make sure that
  215. // it is at least partially on screen, and not zero sized.
  216. //
  217. //
  218. void OPT_GetWindowRectOption
  219. (
  220. LPCSTR optionName,
  221. LPRECT lprc,
  222. LPCRECT lprcDefault
  223. )
  224. {
  225. int iLeft;
  226. int iTop;
  227. int iRight;
  228. int iBottom;
  229. TCHAR cstrValue[MAX_OPTIONS_LINE_LENGTH];
  230. if (OPT_Lookup(optionName, cstrValue,MAX_OPTIONS_LINE_LENGTH))
  231. {
  232. // Option has been found, parse it to a rectangle
  233. iLeft = RtStrToInt(StrTok(cstrValue, " ,"));
  234. iTop = RtStrToInt(StrTok(NULL, " ,"));
  235. iRight = RtStrToInt(StrTok(NULL, " ,"));
  236. iBottom = RtStrToInt(StrTok(NULL, " ,"));
  237. // Check for non-zero size
  238. if ((iRight <= iLeft) || (iBottom <= iTop))
  239. {
  240. *lprc = *lprcDefault;
  241. }
  242. else
  243. {
  244. // Make sure that the window rectangle is (at least partially) on
  245. // screen, and not too large. First get the screen size
  246. int screenWidth = ::GetSystemMetrics(SM_CXSCREEN);
  247. int screenHeight = ::GetSystemMetrics(SM_CYSCREEN);
  248. // Check the window size
  249. if ((iRight - iLeft) > screenWidth)
  250. {
  251. iRight = iLeft + screenWidth;
  252. }
  253. if ((iBottom - iTop) > screenHeight)
  254. {
  255. iTop = screenHeight;
  256. }
  257. // Check the window position
  258. if (iLeft >= screenWidth)
  259. {
  260. // Off screen to the right - keep the width the same
  261. iLeft = screenWidth - (iRight - iLeft);
  262. iRight = screenWidth;
  263. }
  264. if (iRight < 0)
  265. {
  266. // Off screen to the left - keep the width the same
  267. iRight = iRight - iLeft;
  268. iLeft = 0;
  269. }
  270. if (iTop >= screenHeight)
  271. {
  272. // Off screen to the bottom - keep the height the same
  273. iTop = screenHeight - (iBottom - iTop);
  274. iBottom = screenHeight;
  275. }
  276. if (iBottom < 0)
  277. {
  278. // Off screen to the top - keep the height the same
  279. iBottom = (iBottom - iTop);
  280. iTop = 0;
  281. }
  282. lprc->left = iLeft;
  283. lprc->top = iTop;
  284. lprc->right = iRight;
  285. lprc->bottom = iBottom;
  286. }
  287. }
  288. else
  289. {
  290. // The option is not in the dictionary, return the default
  291. *lprc = *lprcDefault;
  292. }
  293. }
  294. //
  295. //
  296. // Function: GetDataOption
  297. //
  298. // Purpose: Retrieve a named option from the dictionary and parse it as
  299. // an ASCII representation of a string of hex bytes.
  300. //
  301. //
  302. int OPT_GetDataOption
  303. (
  304. LPCSTR cstrOptionName,
  305. int iBufferLength,
  306. BYTE* pbResult
  307. )
  308. {
  309. TCHAR cstrValue[MAX_OPTIONS_LINE_LENGTH];
  310. BYTE* pbSaveResult = pbResult;
  311. // Lookup the option
  312. OPT_GetStringOption(cstrOptionName, cstrValue,MAX_OPTIONS_LINE_LENGTH);
  313. if (lstrlen(cstrValue))
  314. {
  315. // Calculate the maximum number of characters to convert
  316. int iMaxChars = min(2 * iBufferLength, lstrlen(cstrValue));
  317. // Option found, convert the string to hex bytes
  318. for (int iIndex = 0; iIndex < iMaxChars; iIndex += 2)
  319. {
  320. BYTE bByteHigh = 0;
  321. BYTE bByteLow = 0;
  322. if ( (HexDigitToByte(cstrValue[iIndex], bByteHigh) == FALSE)
  323. || (HexDigitToByte(cstrValue[iIndex + 1], bByteLow) == FALSE))
  324. {
  325. // The character was not a valid hex digit
  326. break;
  327. }
  328. // Build the result byte
  329. *pbResult++ = (BYTE) ((bByteHigh << 4) | bByteLow);
  330. }
  331. }
  332. // Return the length of data in the buffer
  333. return (int)(pbResult - pbSaveResult);
  334. }
  335. //
  336. //
  337. // Function: SetStringOption
  338. //
  339. // Purpose: Set the value of an option in the dictionary.
  340. //
  341. //
  342. BOOL OPT_SetStringOption
  343. (
  344. LPCSTR cstrOptionName,
  345. LPCSTR cstrValue
  346. )
  347. {
  348. BOOL fSuccess = FALSE;
  349. HKEY write_hkey = NULL;
  350. DWORD disposition;
  351. // open or create the key
  352. if (RegCreateKeyEx( HKEY_CURRENT_USER,
  353. WHITEBOARD_KEY,
  354. 0,
  355. NULL,
  356. REG_OPTION_NON_VOLATILE,
  357. KEY_ALL_ACCESS,
  358. NULL,
  359. &write_hkey,
  360. &disposition) != ERROR_SUCCESS)
  361. {
  362. WARNING_OUT(("Could not write key"));
  363. goto bail_out;
  364. }
  365. // got data, write the value
  366. if (RegSetValueEx( write_hkey,
  367. cstrOptionName,
  368. 0,
  369. REG_SZ,
  370. (LPBYTE)cstrValue,
  371. _tcsclen(cstrValue) + sizeof(TCHAR)) != ERROR_SUCCESS )
  372. {
  373. WARNING_OUT(("Could not write key value"));
  374. goto bail_out;
  375. }
  376. fSuccess = TRUE;
  377. bail_out:
  378. if (write_hkey != NULL)
  379. RegCloseKey(write_hkey);
  380. return(fSuccess);
  381. }
  382. //
  383. //
  384. // Function: SetIntegerOption
  385. //
  386. // Purpose: Write an integer option
  387. //
  388. //
  389. BOOL OPT_SetIntegerOption
  390. (
  391. LPCSTR cstrOptionName,
  392. LONG lValue
  393. )
  394. {
  395. char cBuffer[20];
  396. // Convert the integer value to ASCII decimal
  397. wsprintf(cBuffer, "%ld", lValue);
  398. // Write the option
  399. return OPT_SetStringOption(cstrOptionName, cBuffer);
  400. }
  401. //
  402. //
  403. // Function: SetBooleanOption
  404. //
  405. // Purpose: Write a boolean option
  406. //
  407. //
  408. BOOL OPT_SetBooleanOption
  409. (
  410. LPCSTR cstrOptionName,
  411. BOOL bValue
  412. )
  413. {
  414. char cBuffer[8];
  415. wsprintf(cBuffer, "%c", (bValue ? 'Y' : 'N'));
  416. // Write the option
  417. return OPT_SetStringOption(cstrOptionName, cBuffer);
  418. }
  419. //
  420. //
  421. // Function: SetWindowRectOption
  422. //
  423. // Purpose: Write a window position rectangle
  424. //
  425. //
  426. BOOL OPT_SetWindowRectOption
  427. (
  428. LPCSTR optionName,
  429. LPCRECT lpwindowRect
  430. )
  431. {
  432. char cBuffer[64];
  433. // Convert the integer values to ASCII decimal
  434. wsprintf(cBuffer, "%d,%d,%d,%d",
  435. lpwindowRect->left, lpwindowRect->top, lpwindowRect->right,
  436. lpwindowRect->bottom);
  437. // Write the option
  438. return OPT_SetStringOption(optionName, cBuffer);
  439. }
  440. //
  441. //
  442. // Function: SetDataOption
  443. //
  444. // Purpose: Write a data option to the options file
  445. //
  446. //
  447. BOOL OPT_SetDataOption
  448. (
  449. LPCSTR cstrOptionName,
  450. int iBufferLength,
  451. BYTE* pbBuffer
  452. )
  453. {
  454. char cBuffer[1024];
  455. LPSTR cTmp;
  456. ASSERT(iBufferLength*2 < sizeof(cBuffer));
  457. // Loop through the data array converting a byte at a time
  458. cTmp = cBuffer;
  459. for (int iIndex = 0; iIndex < iBufferLength; iIndex++)
  460. {
  461. // Convert the next byte to ASCII hex
  462. wsprintf(cTmp, "%02x", pbBuffer[iIndex]);
  463. // add it to the string to be written
  464. cTmp += lstrlen(cTmp);
  465. }
  466. // Write the option
  467. return OPT_SetStringOption(cstrOptionName, cBuffer);
  468. }
  469. //
  470. //
  471. // Function: CreateSystemPalette
  472. //
  473. // Purpose: Get a palette representing the system palette
  474. //
  475. //
  476. HPALETTE CreateSystemPalette(void)
  477. {
  478. LPLOGPALETTE lpLogPal;
  479. HDC hdc;
  480. HPALETTE hPal = NULL;
  481. int nColors;
  482. MLZ_EntryOut(ZONE_FUNCTION, "CreateSystemPalette");
  483. hdc = ::CreateIC("DISPLAY", NULL, NULL, NULL);
  484. if (!hdc)
  485. {
  486. ERROR_OUT(("Couldn't create DISPLAY IC"));
  487. return(NULL);
  488. }
  489. nColors = ::GetDeviceCaps(hdc, SIZEPALETTE);
  490. ::DeleteDC(hdc);
  491. if (nColors == 0)
  492. {
  493. TRACE_MSG(("CreateSystemPalette: device has no palette"));
  494. return(NULL);
  495. }
  496. // Allocate room for the palette and lock it.
  497. lpLogPal = (LPLOGPALETTE)::GlobalAlloc(GPTR, sizeof(LOGPALETTE) +
  498. nColors * sizeof(PALETTEENTRY));
  499. if (lpLogPal != NULL)
  500. {
  501. lpLogPal->palVersion = PALVERSION;
  502. lpLogPal->palNumEntries = (WORD) nColors;
  503. for (int iIndex = 0; iIndex < nColors; iIndex++)
  504. {
  505. lpLogPal->palPalEntry[iIndex].peBlue = 0;
  506. *((LPWORD) (&lpLogPal->palPalEntry[iIndex].peRed)) = (WORD) iIndex;
  507. lpLogPal->palPalEntry[iIndex].peFlags = PC_EXPLICIT;
  508. }
  509. hPal = ::CreatePalette(lpLogPal);
  510. // Free the logical palette structure
  511. ::GlobalFree((HGLOBAL)lpLogPal);
  512. }
  513. return(hPal);
  514. }
  515. //
  516. //
  517. // Function: CreateColorPalette
  518. //
  519. // Purpose: Get a 256-color palette
  520. //
  521. //
  522. HPALETTE CreateColorPalette(void)
  523. {
  524. HDC hdc;
  525. HPALETTE hPal = NULL;
  526. MLZ_EntryOut(ZONE_FUNCTION, "CreateColorPalette");
  527. // Find out how many colors are reserved
  528. hdc = ::CreateIC("DISPLAY", NULL, NULL, NULL);
  529. if (!hdc)
  530. {
  531. ERROR_OUT(("Couldn't create DISPLAY IC"));
  532. return(NULL);
  533. }
  534. UINT uiSystemUse = ::GetSystemPaletteUse(hdc);
  535. // Get the number of static colors
  536. int iCountStatic = 20;
  537. int iHalfCountStatic = 10;
  538. if (uiSystemUse == SYSPAL_NOSTATIC)
  539. {
  540. iCountStatic = 2;
  541. iHalfCountStatic = 1;
  542. }
  543. LOGPALETTE_NM gIndeoPalette = gcLogPaletteIndeo;
  544. // put system colors in correct lower and upper pal entries (bug NM4db:817)
  545. ::GetSystemPaletteEntries(hdc,
  546. 0,
  547. iHalfCountStatic,
  548. &(gIndeoPalette.aEntries[0]) );
  549. ::GetSystemPaletteEntries(hdc,
  550. MAXPALETTE - iHalfCountStatic,
  551. iHalfCountStatic,
  552. &(gIndeoPalette.aEntries[MAXPALETTE - iHalfCountStatic]) );
  553. // Create the windows object for this palette
  554. // from the logical palette
  555. hPal = CreatePalette( (LOGPALETTE *)&gIndeoPalette );
  556. // Delete the display DC
  557. ::DeleteDC(hdc);
  558. return(hPal);
  559. }
  560. //
  561. //
  562. // Function: FromScreenAreaBmp
  563. //
  564. // Purpose: Create a bitmap from an area of the screen
  565. //
  566. //
  567. HBITMAP FromScreenAreaBmp(LPCRECT lprect)
  568. {
  569. RECT rcScreen;
  570. HBITMAP hBitMap = NULL;
  571. //
  572. // Get screen boundaries, in a way that works for single and multiple
  573. // monitor scenarios.
  574. //
  575. if (rcScreen.right = ::GetSystemMetrics(SM_CXVIRTUALSCREEN))
  576. {
  577. //
  578. // This is Win98, NT 4.0 SP-3, or NT5
  579. //
  580. rcScreen.bottom = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
  581. rcScreen.left = ::GetSystemMetrics(SM_XVIRTUALSCREEN);
  582. rcScreen.top = ::GetSystemMetrics(SM_YVIRTUALSCREEN);
  583. }
  584. else
  585. {
  586. //
  587. // The VIRTUALSCREEN size metrics are zero on older platforms
  588. // which don't support them.
  589. //
  590. rcScreen.right = ::GetSystemMetrics(SM_CXSCREEN);
  591. rcScreen.bottom = ::GetSystemMetrics(SM_CYSCREEN);
  592. rcScreen.left = 0;
  593. rcScreen.top = 0;
  594. }
  595. rcScreen.right += rcScreen.left;
  596. rcScreen.bottom += rcScreen.top;
  597. //
  598. // Clip bitmap rectangle to the screen.
  599. //
  600. if (IntersectRect(&rcScreen, &rcScreen, lprect))
  601. {
  602. // Create a DC for the screen and create
  603. // a memory DC compatible to screen DC
  604. HDC hdisplayDC;
  605. hdisplayDC = ::CreateDC("DISPLAY", NULL, NULL, NULL);
  606. HDC hmemDC;
  607. hmemDC = ::CreateCompatibleDC(hdisplayDC);
  608. // Create a bitmap compatible with the screen DC
  609. hBitMap = ::CreateCompatibleBitmap(hdisplayDC,
  610. rcScreen.right - rcScreen.left,
  611. rcScreen.bottom - rcScreen.top);
  612. if (hBitMap != NULL)
  613. {
  614. // Select new bitmap into memory DC
  615. HBITMAP hOldBitmap = SelectBitmap(hmemDC, hBitMap);
  616. // BitBlt screen DC to memory DC
  617. ::BitBlt(hmemDC, 0, 0, rcScreen.right - rcScreen.left,
  618. rcScreen.bottom - rcScreen.top, hdisplayDC,
  619. rcScreen.left, rcScreen.top, SRCCOPY);
  620. // Select old bitmap back into memory DC and get handle to
  621. // bitmap of the screen
  622. SelectBitmap(hmemDC, hOldBitmap);
  623. }
  624. ::DeleteDC(hmemDC);
  625. ::DeleteDC(hdisplayDC);
  626. }
  627. // return handle to the bitmap
  628. return hBitMap;
  629. }
  630. // Macro to round off the given value to the closest byte
  631. #define WIDTHBYTES(i) (((i+31)/32)*4)
  632. //
  633. //
  634. // Function: DIB_NumberOfColors
  635. //
  636. // Purpose: Calculates the number of colours in the DIB
  637. //
  638. //
  639. UINT DIB_NumberOfColors(LPBITMAPINFOHEADER lpbi)
  640. {
  641. UINT numColors;
  642. int bits;
  643. MLZ_EntryOut(ZONE_FUNCTION, "DIB_NumberOfColors");
  644. ASSERT(lpbi != NULL);
  645. // With the BITMAPINFO format headers, the size of the palette
  646. // is in biClrUsed, whereas in the BITMAPCORE - style headers, it
  647. // is dependent on the bits per pixel ( = 2 raised to the power of
  648. // bits/pixel).
  649. if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
  650. {
  651. // Old DIB format, some apps still put this on the clipboard
  652. numColors = 0;
  653. bits = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
  654. }
  655. else
  656. {
  657. numColors = lpbi->biClrUsed;
  658. bits = lpbi->biBitCount;
  659. }
  660. if ((numColors == 0) && (bits <= 8))
  661. {
  662. numColors = (1 << bits);
  663. }
  664. return numColors;
  665. }
  666. //
  667. //
  668. // Function: DIB_PaletteLength
  669. //
  670. // Purpose: Calculates the palette size in bytes
  671. //
  672. //
  673. UINT DIB_PaletteLength(LPBITMAPINFOHEADER lpbi)
  674. {
  675. UINT size;
  676. MLZ_EntryOut(ZONE_FUNCTION, "DIB_PaletteLength");
  677. if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
  678. {
  679. size = DIB_NumberOfColors(lpbi) * sizeof(RGBTRIPLE);
  680. }
  681. else
  682. {
  683. size = DIB_NumberOfColors(lpbi) * sizeof(RGBQUAD);
  684. }
  685. TRACE_MSG(("Palette length %d", size));
  686. return(size);
  687. }
  688. //
  689. //
  690. // Function: DIB_DataLength
  691. //
  692. // Purpose: Return the length of the DIB data (after the header and the
  693. // color table.
  694. //
  695. //
  696. UINT DIB_DataLength(LPBITMAPINFOHEADER lpbi)
  697. {
  698. MLZ_EntryOut(ZONE_FUNCTION, "DIB_DataLength");
  699. ASSERT(lpbi);
  700. UINT dwLength = 0;
  701. // If the image is not compressed, calculate the length of the data
  702. if (lpbi->biCompression == BI_RGB)
  703. {
  704. // Image is not compressed, the size can be given as zero in the header
  705. // Calculate the width in bytes of the image
  706. DWORD dwByteWidth = ( ((DWORD) lpbi->biWidth) * (DWORD) lpbi->biBitCount);
  707. TRACE_MSG(("Data byte width is %ld",dwByteWidth));
  708. // Round the width to a multiple of 4 bytes
  709. dwByteWidth = WIDTHBYTES(dwByteWidth);
  710. TRACE_MSG(("Rounded up to %ld",dwByteWidth));
  711. dwLength = (dwByteWidth * ((DWORD) lpbi->biHeight));
  712. }
  713. else
  714. {
  715. // Image is compressed, the length should be correct in the header
  716. dwLength = lpbi->biSizeImage;
  717. }
  718. TRACE_MSG(("Total data length is %d",dwLength));
  719. return(dwLength);
  720. }
  721. //
  722. //
  723. // Function: DIB_TotalLength
  724. //
  725. // Purpose: Return the total length of the DIB (header + colors + data).
  726. //
  727. //
  728. UINT DIB_TotalLength(LPBITMAPINFOHEADER lpbi)
  729. {
  730. MLZ_EntryOut(ZONE_FUNCTION, "DIB_TotalLength");
  731. ASSERT(lpbi);
  732. // Header + Palette + Bits
  733. return(lpbi->biSize + DIB_PaletteLength(lpbi) + DIB_DataLength(lpbi));
  734. }
  735. //
  736. //
  737. // Function: DIB_CreatePalette
  738. //
  739. // Purpose: Create a palette object from the bitmap info color table
  740. //
  741. //
  742. HPALETTE DIB_CreatePalette(LPBITMAPINFOHEADER lpbi)
  743. {
  744. LOGPALETTE *pPal;
  745. HPALETTE hpal = NULL;
  746. WORD nNumColors;
  747. BYTE red;
  748. BYTE green;
  749. BYTE blue;
  750. WORD i;
  751. RGBQUAD FAR * pRgb;
  752. MLZ_EntryOut(ZONE_FUNCTION, "DIB_CreatePalette");
  753. if (!lpbi)
  754. return NULL;
  755. if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
  756. return NULL;
  757. // Get a pointer to the color table and the number of colors in it
  758. pRgb = (RGBQUAD FAR *)((LPSTR)lpbi + (WORD)lpbi->biSize);
  759. nNumColors = (WORD)DIB_NumberOfColors(lpbi);
  760. if (nNumColors)
  761. {
  762. TRACE_MSG(("There are %d colors in the palette",nNumColors));
  763. // Allocate for the logical palette structure
  764. pPal = (LOGPALETTE*) ::GlobalAlloc(GPTR, sizeof(LOGPALETTE)
  765. + (nNumColors * sizeof(PALETTEENTRY)));
  766. if (!pPal)
  767. {
  768. ERROR_OUT(("Couldn't allocate palette memory"));
  769. return(NULL);
  770. }
  771. pPal->palNumEntries = nNumColors;
  772. pPal->palVersion = PALVERSION;
  773. // Fill in the palette entries from the DIB color table and
  774. // create a logical color palette.
  775. for (i = 0; i < nNumColors; i++)
  776. {
  777. pPal->palPalEntry[i].peRed = pRgb[i].rgbRed;
  778. pPal->palPalEntry[i].peGreen = pRgb[i].rgbGreen;
  779. pPal->palPalEntry[i].peBlue = pRgb[i].rgbBlue;
  780. pPal->palPalEntry[i].peFlags = (BYTE)0;
  781. }
  782. hpal = ::CreatePalette(pPal);
  783. ::GlobalFree((HGLOBAL)pPal);
  784. }
  785. else
  786. {
  787. if (lpbi->biBitCount == 24)
  788. {
  789. // A 24 bitcount DIB has no color table entries so, set the number
  790. // of to the maximum value (256).
  791. nNumColors = MAXPALETTE;
  792. pPal = (LOGPALETTE*) ::GlobalAlloc(GPTR, sizeof(LOGPALETTE)
  793. + (nNumColors * sizeof(PALETTEENTRY)));
  794. if (!pPal)
  795. {
  796. ERROR_OUT(("Couldn't allocate palette memory"));
  797. return NULL;
  798. }
  799. pPal->palNumEntries = nNumColors;
  800. pPal->palVersion = PALVERSION;
  801. red = green = blue = 0;
  802. // Generate 256 (= 8*8*4) RGB combinations to fill the palette
  803. // entries.
  804. for (i = 0; i < pPal->palNumEntries; i++)
  805. {
  806. pPal->palPalEntry[i].peRed = red;
  807. pPal->palPalEntry[i].peGreen = green;
  808. pPal->palPalEntry[i].peBlue = blue;
  809. pPal->palPalEntry[i].peFlags = (BYTE) 0;
  810. if (!(red += 32))
  811. if (!(green += 32))
  812. blue += 64;
  813. }
  814. hpal = ::CreatePalette(pPal);
  815. ::GlobalFree((HGLOBAL)pPal);
  816. }
  817. }
  818. return hpal;
  819. }
  820. //
  821. //
  822. // Function: DIB_Bits
  823. //
  824. // Purpose: Return a pointer to the bitmap bits data (from a pointer
  825. // to the bitmap info header).
  826. //
  827. //
  828. LPSTR DIB_Bits(LPBITMAPINFOHEADER lpbi)
  829. {
  830. MLZ_EntryOut(ZONE_FUNCTION, "DIB_Bits");
  831. ASSERT(lpbi);
  832. return ((LPSTR) (((char *) lpbi)
  833. + lpbi->biSize
  834. + DIB_PaletteLength(lpbi)));
  835. }
  836. //
  837. //
  838. // Function: DIB_FromScreenArea
  839. //
  840. // Purpose: Create a DIB from an area of the screen
  841. //
  842. //
  843. LPBITMAPINFOHEADER DIB_FromScreenArea(LPCRECT lprect)
  844. {
  845. HBITMAP hBitmap = NULL;
  846. HPALETTE hPalette = NULL;
  847. LPBITMAPINFOHEADER lpbi = NULL;
  848. MLZ_EntryOut(ZONE_FUNCTION, "DIB_FromScreenArea");
  849. // Get the device-dependent bitmap from the screen area
  850. hBitmap = FromScreenAreaBmp(lprect);
  851. if (hBitmap != NULL)
  852. {
  853. // Get the current system palette
  854. hPalette = CreateSystemPalette();
  855. lpbi = DIB_FromBitmap(hBitmap, hPalette, FALSE);
  856. }
  857. if (hPalette != NULL)
  858. ::DeletePalette(hPalette);
  859. if (hBitmap != NULL)
  860. ::DeleteBitmap(hBitmap);
  861. return(lpbi);
  862. }
  863. //
  864. //
  865. // Function: DIB_Copy
  866. //
  867. // Purpose: Make a copy of the DIB memory
  868. //
  869. //
  870. LPBITMAPINFOHEADER DIB_Copy(LPBITMAPINFOHEADER lpbi)
  871. {
  872. LPBITMAPINFOHEADER lpbiNew = NULL;
  873. MLZ_EntryOut(ZONE_FUNCTION, "DIB_Copy");
  874. ASSERT(lpbi);
  875. // Get the length of memory
  876. DWORD dwLen = DIB_TotalLength(lpbi);
  877. lpbiNew = (LPBITMAPINFOHEADER)::GlobalAlloc(GPTR, dwLen);
  878. if (lpbiNew != NULL)
  879. {
  880. // Copy the data
  881. memcpy(lpbiNew, lpbi, dwLen);
  882. }
  883. return(lpbiNew);
  884. }
  885. //
  886. //
  887. // Function: DIB_FromBitmap
  888. //
  889. // Purpose: Creates a DIB from a bitmap and palette
  890. //
  891. //
  892. LPBITMAPINFOHEADER DIB_FromBitmap
  893. (
  894. HBITMAP hBitmap,
  895. HPALETTE hPalette,
  896. BOOL fGHandle
  897. )
  898. {
  899. LPBITMAPINFOHEADER lpbi = NULL;
  900. HGLOBAL hmem = NULL;
  901. BITMAP bm;
  902. BITMAPINFOHEADER bi;
  903. DWORD dwLen;
  904. WORD biBits;
  905. MLZ_EntryOut(ZONE_FUNCTION, "DIB_FromBitmap");
  906. // If the bitmap handle given is null, do nothing
  907. if (hBitmap != NULL)
  908. {
  909. if (hPalette == NULL)
  910. hPalette = (HPALETTE)::GetStockObject(DEFAULT_PALETTE);
  911. // Get the bitmap information
  912. ::GetObject(hBitmap, sizeof(bm), (LPSTR) &bm);
  913. biBits = (WORD) (bm.bmPlanes * bm.bmBitsPixel);
  914. if (biBits > 8)
  915. {
  916. // If > 8, make life easy and use plain R-G-B 24-bits
  917. biBits = 24;
  918. }
  919. bi.biSize = sizeof(BITMAPINFOHEADER);
  920. bi.biWidth = bm.bmWidth;
  921. bi.biHeight = bm.bmHeight;
  922. bi.biPlanes = 1;
  923. bi.biBitCount = biBits;
  924. bi.biCompression = 0;
  925. bi.biSizeImage = 0;
  926. bi.biXPelsPerMeter = 0;
  927. bi.biYPelsPerMeter = 0;
  928. bi.biClrUsed = 0;
  929. bi.biClrImportant = 0;
  930. dwLen = bi.biSize + DIB_PaletteLength(&bi);
  931. HDC hdc;
  932. HPALETTE hPalOld;
  933. hdc = ::CreateDC("DISPLAY", NULL, NULL, NULL);
  934. hPalOld = ::SelectPalette(hdc, hPalette, FALSE);
  935. ::RealizePalette(hdc);
  936. // Allocate memory for the DIB
  937. if (fGHandle)
  938. {
  939. // For the clipboard, we MUST use GHND
  940. hmem = ::GlobalAlloc(GHND, dwLen);
  941. lpbi = (LPBITMAPINFOHEADER)::GlobalLock(hmem);
  942. }
  943. else
  944. {
  945. lpbi = (LPBITMAPINFOHEADER)::GlobalAlloc(GPTR, dwLen);
  946. }
  947. if (lpbi != NULL)
  948. {
  949. *lpbi = bi;
  950. // Call GetDIBits with a NULL lpBits param, so it will calculate the
  951. // biSizeImage field for us
  952. ::GetDIBits(hdc, hBitmap, 0, (WORD) bi.biHeight, NULL,
  953. (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
  954. bi = *lpbi;
  955. // If the driver did not fill in the biSizeImage field, make one up
  956. if (bi.biSizeImage == 0)
  957. {
  958. bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;
  959. }
  960. // Realloc the buffer big enough to hold all the bits
  961. dwLen = bi.biSize + DIB_PaletteLength(&bi) + bi.biSizeImage;
  962. if (fGHandle)
  963. {
  964. HGLOBAL hT;
  965. ::GlobalUnlock(hmem);
  966. hT = ::GlobalReAlloc(hmem, dwLen, GHND);
  967. if (!hT)
  968. {
  969. ERROR_OUT(("Can't reallocate DIB handle"));
  970. ::GlobalFree(hmem);
  971. hmem = NULL;
  972. lpbi = NULL;
  973. }
  974. else
  975. {
  976. hmem = hT;
  977. lpbi = (LPBITMAPINFOHEADER)::GlobalLock(hmem);
  978. }
  979. }
  980. else
  981. {
  982. LPBITMAPINFOHEADER lpbiT;
  983. lpbiT = (LPBITMAPINFOHEADER)::GlobalReAlloc((HGLOBAL)lpbi, dwLen, GMEM_MOVEABLE);
  984. if (!lpbiT)
  985. {
  986. ERROR_OUT(("Can't reallocate DIB ptr"));
  987. ::GlobalFree((HGLOBAL)lpbi);
  988. lpbi = NULL;
  989. }
  990. else
  991. {
  992. lpbi = lpbiT;
  993. }
  994. }
  995. }
  996. if (lpbi != NULL)
  997. {
  998. ::GetDIBits(hdc, hBitmap, 0,
  999. (WORD)bi.biHeight,
  1000. DIB_Bits(lpbi),
  1001. (LPBITMAPINFO)lpbi,
  1002. DIB_RGB_COLORS);
  1003. if (fGHandle)
  1004. {
  1005. // We want to return the HANDLE, not the POINTER
  1006. ::GlobalUnlock(hmem);
  1007. lpbi = (LPBITMAPINFOHEADER)hmem;
  1008. }
  1009. }
  1010. // Restore the old palette and give back the device context
  1011. ::SelectPalette(hdc, hPalOld, FALSE);
  1012. ::DeleteDC(hdc);
  1013. }
  1014. return(lpbi);
  1015. }
  1016. //
  1017. // AbortProc()
  1018. // Process messages during printing
  1019. //
  1020. //
  1021. BOOL CALLBACK AbortProc(HDC, int)
  1022. {
  1023. MSG msg;
  1024. ASSERT(g_pPrinter);
  1025. // Message pump in case user wants to cancel printing
  1026. while (!g_pPrinter->Aborted()
  1027. && PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
  1028. {
  1029. if ( (g_pPrinter->m_hwndDialog == NULL) ||
  1030. !::IsDialogMessage(g_pPrinter->m_hwndDialog, &msg))
  1031. {
  1032. TranslateMessage(&msg);
  1033. DispatchMessage(&msg);
  1034. }
  1035. }
  1036. return !g_pPrinter->Aborted();
  1037. }
  1038. //
  1039. //
  1040. // Function: WbPrinter
  1041. //
  1042. // Purpose: Constructor for a printer object
  1043. //
  1044. //
  1045. WbPrinter::WbPrinter(LPCTSTR szDeviceName)
  1046. {
  1047. m_szDeviceName = szDeviceName;
  1048. m_szPrintPageText[0] = 0;
  1049. // Set up the global pointer for the abort procedure
  1050. g_pPrinter = this;
  1051. // Create the dialog window
  1052. m_hwndDialog = ::CreateDialogParam(g_hInstance, MAKEINTRESOURCE(PRINTCANCEL),
  1053. g_pMain->m_hwnd, CancelPrintDlgProc, 0);
  1054. // Save the original text for the page number area
  1055. ::GetDlgItemText(m_hwndDialog, IDD_PRINT_PAGE, m_szPrintPageText, _MAX_PATH);
  1056. }
  1057. //
  1058. //
  1059. // Function: ~WbPrinter
  1060. //
  1061. // Purpose: Destructor for a printer object
  1062. //
  1063. //
  1064. WbPrinter::~WbPrinter(void)
  1065. {
  1066. // Kill off the dialog etc. if still around
  1067. StopDialog();
  1068. ASSERT(m_hwndDialog == NULL);
  1069. g_pPrinter = NULL;
  1070. }
  1071. //
  1072. // StopDialog()
  1073. // If the dialog is up, ends it.
  1074. //
  1075. void WbPrinter::StopDialog(void)
  1076. {
  1077. ::EnableWindow(g_pMain->m_hwnd, TRUE);
  1078. // Close and destroy the dialog
  1079. if (m_hwndDialog != NULL)
  1080. {
  1081. ::DestroyWindow(m_hwndDialog);
  1082. m_hwndDialog = NULL;
  1083. }
  1084. }
  1085. //
  1086. //
  1087. // Function: StartDoc
  1088. //
  1089. // Purpose: Tell the printer we are starting a new document
  1090. //
  1091. //
  1092. int WbPrinter::StartDoc
  1093. (
  1094. HDC hdc,
  1095. LPCTSTR szJobName,
  1096. int nStartPage
  1097. )
  1098. {
  1099. // Initialize the result codes and page number
  1100. m_bAborted = FALSE; // Not aborted
  1101. m_nPrintResult = 1; // Greater than 0 implies all is well
  1102. // Disable the main window
  1103. ::EnableWindow(g_pMain->m_hwnd, FALSE);
  1104. // Attach the printer DC
  1105. SetPrintPageNumber(nStartPage);
  1106. // Set up the abort routine for the print
  1107. if (SetAbortProc(hdc, AbortProc) >= 0)
  1108. {
  1109. // Abort routine successfully set
  1110. ::ShowWindow(m_hwndDialog, SW_SHOW);
  1111. ::UpdateWindow(m_hwndDialog);
  1112. DOCINFO docinfo;
  1113. docinfo.cbSize = sizeof(DOCINFO);
  1114. docinfo.lpszDocName = szJobName;
  1115. docinfo.lpszOutput = NULL;
  1116. docinfo.lpszDatatype = NULL; // Windows 95 only; ignored on Windows NT
  1117. docinfo.fwType = 0; // Windows 95 only; ignored on Windows NT
  1118. // Initialize the document.
  1119. m_nPrintResult = ::StartDoc(hdc, &docinfo);
  1120. }
  1121. return m_nPrintResult;
  1122. }
  1123. //
  1124. //
  1125. // Function: StartPage
  1126. //
  1127. // Purpose: Tell the printer we are starting a new page
  1128. //
  1129. //
  1130. int WbPrinter::StartPage(HDC hdc, int nPageNumber)
  1131. {
  1132. MLZ_EntryOut(ZONE_FUNCTION, "WbPrinter::StartPage");
  1133. m_nPrintResult = -1; // Initialise to error
  1134. // If the print has been aborted, return an error.
  1135. if (m_bAborted)
  1136. {
  1137. TRACE_DEBUG(("Print has been aborted"));
  1138. }
  1139. else
  1140. {
  1141. SetPrintPageNumber(nPageNumber);
  1142. // Tell the printer of the new page number
  1143. m_nPrintResult = ::StartPage(hdc);
  1144. }
  1145. return(m_nPrintResult);
  1146. }
  1147. //
  1148. //
  1149. // Function: EndPage
  1150. //
  1151. // Purpose: Tell the printer we are finishing a page
  1152. //
  1153. //
  1154. int WbPrinter::EndPage(HDC hdc)
  1155. {
  1156. MLZ_EntryOut(ZONE_FUNCTION, "WbPrinter::EndPage");
  1157. m_nPrintResult = -1; // Initialise to error
  1158. // If the print has been aborted, return an error.
  1159. if (m_bAborted)
  1160. {
  1161. TRACE_DEBUG(("Print has been aborted"));
  1162. }
  1163. else
  1164. {
  1165. // Tell the printer of the new page number
  1166. m_nPrintResult = ::EndPage(hdc);
  1167. }
  1168. return(m_nPrintResult);
  1169. }
  1170. //
  1171. //
  1172. // Function: EndDoc
  1173. //
  1174. // Purpose: Tell the printer we have completed a document
  1175. //
  1176. //
  1177. int WbPrinter::EndDoc(HDC hdc)
  1178. {
  1179. // If an error has occurred the driver will already have aborted the print
  1180. if (m_nPrintResult > 0)
  1181. {
  1182. if (!m_bAborted)
  1183. {
  1184. // If we have not been aborted, and no error has occurred
  1185. // end the document
  1186. m_nPrintResult = ::EndDoc(hdc);
  1187. }
  1188. else
  1189. {
  1190. m_nPrintResult = ::AbortDoc(hdc);
  1191. }
  1192. }
  1193. StopDialog();
  1194. // Return an the error indicator
  1195. return m_nPrintResult;
  1196. }
  1197. //
  1198. //
  1199. // Function: AbortDoc
  1200. //
  1201. // Purpose: Abort the document currently in progress
  1202. //
  1203. //
  1204. int WbPrinter::AbortDoc()
  1205. {
  1206. // Show that we have been aborted, the actual abort is
  1207. // done by the EndDoc call.
  1208. m_bAborted = TRUE;
  1209. //
  1210. // Renable the application window.
  1211. //
  1212. StopDialog();
  1213. // Return a positive value indicating "aborted OK"
  1214. return 1;
  1215. }
  1216. //
  1217. //
  1218. // Function: SetPrintPageNumber
  1219. //
  1220. // Purpose: Set the number of the page currently being printed
  1221. //
  1222. //
  1223. void WbPrinter::SetPrintPageNumber(int nPageNumber)
  1224. {
  1225. // Display the number of the page currently being printed
  1226. TCHAR szPageNumber [10 + _MAX_PATH];
  1227. wsprintf(szPageNumber, m_szPrintPageText, nPageNumber);
  1228. ::SetDlgItemText(m_hwndDialog, IDD_PRINT_PAGE, szPageNumber);
  1229. }
  1230. //
  1231. // CancelPrintDlgProc()
  1232. // Dialog message handler for the cancel printing dialog
  1233. //
  1234. INT_PTR CALLBACK CancelPrintDlgProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  1235. {
  1236. BOOL fHandled = FALSE;
  1237. switch (uMessage)
  1238. {
  1239. case WM_INITDIALOG:
  1240. ASSERT(g_pPrinter != NULL);
  1241. ::SetDlgItemText(hwnd, IDD_DEVICE_NAME, g_pPrinter->m_szDeviceName);
  1242. fHandled = TRUE;
  1243. break;
  1244. case WM_COMMAND:
  1245. switch (GET_WM_COMMAND_ID(wParam, lParam))
  1246. {
  1247. case IDOK:
  1248. case IDCANCEL:
  1249. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  1250. {
  1251. case BN_CLICKED:
  1252. ASSERT(g_pPrinter != NULL);
  1253. g_pPrinter->AbortDoc();
  1254. break;
  1255. }
  1256. }
  1257. fHandled = TRUE;
  1258. break;
  1259. }
  1260. return(fHandled);
  1261. }
  1262. //
  1263. // Bogus Bogus LAURABU
  1264. // STRING ARRAY (TEMP!)
  1265. //
  1266. StrArray::StrArray()
  1267. {
  1268. m_pData = NULL;
  1269. m_nSize = m_nMaxSize = 0;
  1270. }
  1271. StrArray::~StrArray()
  1272. {
  1273. ClearOut();
  1274. }
  1275. void StrArray::ClearOut(void)
  1276. {
  1277. int iItem;
  1278. for (iItem = 0; iItem < m_nSize; iItem++)
  1279. {
  1280. if (m_pData[iItem] != NULL)
  1281. {
  1282. delete (LPTSTR)m_pData[iItem];
  1283. m_pData[iItem] = NULL;
  1284. }
  1285. }
  1286. m_nSize = 0;
  1287. m_nMaxSize = 0;
  1288. if (m_pData != NULL)
  1289. {
  1290. delete[] m_pData;
  1291. m_pData = NULL;
  1292. }
  1293. }
  1294. void StrArray::SetSize(int nNewSize)
  1295. {
  1296. if (nNewSize == 0)
  1297. {
  1298. // shrink to nothing
  1299. ClearOut();
  1300. }
  1301. else if (nNewSize <= m_nMaxSize)
  1302. {
  1303. // No shrinking allowed.
  1304. ASSERT(nNewSize >= m_nSize);
  1305. // We're still within the alloced block range
  1306. m_nSize = nNewSize;
  1307. }
  1308. else
  1309. {
  1310. //
  1311. // Make a larger array (isn't this lovely if you already have an
  1312. // array, we alloc a new one and free the old one)
  1313. //
  1314. int nNewMax;
  1315. nNewMax = (nNewSize + (ALLOC_CHUNK -1)) & ~(ALLOC_CHUNK-1);
  1316. ASSERT(nNewMax >= m_nMaxSize); // no wrap around
  1317. LPCTSTR* pNewData = new LPCTSTR[nNewMax];
  1318. if (!pNewData)
  1319. {
  1320. ERROR_OUT(("StrArray::SetSize failed, couldn't allocate larger array"));
  1321. }
  1322. else
  1323. {
  1324. // Zero out the memory
  1325. ZeroMemory(pNewData, nNewMax * sizeof(LPCTSTR));
  1326. // If an old array exists, copy the existing string ptrs.
  1327. if (m_pData != NULL)
  1328. {
  1329. CopyMemory(pNewData, m_pData, m_nSize * sizeof(LPCTSTR));
  1330. //
  1331. // Delete the old array, but not the strings inside, we're
  1332. // keeping them around in the new array
  1333. //
  1334. delete[] m_pData;
  1335. }
  1336. m_pData = pNewData;
  1337. m_nSize = nNewSize;
  1338. m_nMaxSize = nNewMax;
  1339. }
  1340. }
  1341. }
  1342. void StrArray::SetAtGrow(int nIndex, LPCTSTR newElement)
  1343. {
  1344. ASSERT(nIndex >= 0);
  1345. if (nIndex >= m_nSize)
  1346. SetSize(nIndex+1);
  1347. SetAt(nIndex, newElement);
  1348. }
  1349. LPCTSTR StrArray::operator[](int nIndex) const
  1350. {
  1351. ASSERT(nIndex >= 0);
  1352. if (nIndex < m_nSize)
  1353. {
  1354. ASSERT(m_pData != NULL);
  1355. return(m_pData[nIndex]);
  1356. }
  1357. else
  1358. {
  1359. WARNING_OUT(("StrArray[] got index outside of bounds"));
  1360. return(NULL);
  1361. }
  1362. }
  1363. void StrArray::SetAt(int nIndex, LPCTSTR newElement)
  1364. {
  1365. ASSERT(nIndex >= 0);
  1366. if (nIndex >= m_nSize)
  1367. {
  1368. WARNING_OUT(("StrArray::SetAt got index outside of bounds"));
  1369. return;
  1370. }
  1371. ASSERT(m_pData != NULL);
  1372. m_pData[nIndex] = new TCHAR[lstrlen(newElement) + 1];
  1373. if (!m_pData[nIndex])
  1374. {
  1375. ERROR_OUT(("StrArray::SetAt failed to allocate string %s at pos %d",
  1376. newElement, nIndex));
  1377. }
  1378. else
  1379. {
  1380. lstrcpy((LPTSTR)m_pData[nIndex], newElement);
  1381. }
  1382. }
  1383. void StrArray::Add(LPCTSTR newElement)
  1384. {
  1385. SetAtGrow(m_nSize, newElement);
  1386. }
  1387. //
  1388. //char *StrTok(string, control) - tokenize string with delimiter in control
  1389. //
  1390. char * StrTok (char * string, char * control)
  1391. {
  1392. char *str;
  1393. char *ctrl = control;
  1394. unsigned char map[32];
  1395. int count;
  1396. static char *nextoken;
  1397. /* Clear control map */
  1398. for (count = 0; count < 32; count++)
  1399. map[count] = 0;
  1400. /* Set bits in delimiter table */
  1401. do {
  1402. map[*ctrl >> 3] |= (1 << (*ctrl & 7));
  1403. } while (*ctrl++);
  1404. /* Initialize str. If string is NULL, set str to the saved
  1405. * pointer (i.e., continue breaking tokens out of the string
  1406. * from the last StrTok call) */
  1407. if (string)
  1408. str = string;
  1409. else
  1410. str = nextoken;
  1411. /* Find beginning of token (skip over leading delimiters). Note that
  1412. * there is no token iff this loop sets str to point to the terminal
  1413. * null (*str == '\0') */
  1414. while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
  1415. str++;
  1416. string = str;
  1417. /* Find the end of the token. If it is not the end of the string,
  1418. * put a null there. */
  1419. for ( ; *str ; str++ )
  1420. if ( map[*str >> 3] & (1 << (*str & 7)) ) {
  1421. *str++ = '\0';
  1422. break;
  1423. }
  1424. /* Update nextoken (or the corresponding field in the per-thread data
  1425. * structure */
  1426. nextoken = str;
  1427. /* Determine if a token has been found. */
  1428. if ( string == str )
  1429. return NULL;
  1430. else
  1431. return string;
  1432. }
  1433.