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.

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