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.

2228 lines
60 KiB

  1. /*
  2. ** CUTILS.C
  3. **
  4. ** Common utilities for common controls
  5. **
  6. */
  7. #include "ctlspriv.h"
  8. #include "advpub.h" // For REGINSTALL
  9. #include <ntverp.h>
  10. #include "ccver.h" // App compat version hacks
  11. #ifndef SSW_EX_IGNORESETTINGS
  12. #define SSW_EX_IGNORESETTINGS 0x00040000 // ignore system settings to turn on/off smooth scroll
  13. #endif
  14. //
  15. // Globals - REVIEW_32
  16. //
  17. BOOL g_fAnimate;
  18. BOOL g_fSmoothScroll;
  19. int g_cxEdge;
  20. int g_cyEdge;
  21. int g_cxBorder;
  22. int g_cyBorder;
  23. int g_cxScreen;
  24. int g_cyScreen;
  25. int g_cxFrame;
  26. int g_cyFrame;
  27. int g_cxVScroll;
  28. int g_cyHScroll;
  29. int g_cxIcon, g_cyIcon;
  30. int g_cxSmIcon, g_cySmIcon;
  31. int g_cxIconSpacing, g_cyIconSpacing;
  32. int g_cxIconMargin, g_cyIconMargin;
  33. int g_cyLabelSpace;
  34. int g_cxLabelMargin;
  35. int g_cxDoubleClk;
  36. int g_cyDoubleClk;
  37. int g_cxScrollbar;
  38. int g_cyScrollbar;
  39. int g_fDragFullWindows;
  40. COLORREF g_clrWindow;
  41. COLORREF g_clrWindowText;
  42. COLORREF g_clrWindowFrame;
  43. COLORREF g_clrGrayText;
  44. COLORREF g_clrBtnText;
  45. COLORREF g_clrBtnFace;
  46. COLORREF g_clrBtnShadow;
  47. COLORREF g_clrBtnHighlight;
  48. COLORREF g_clrHighlight;
  49. COLORREF g_clrHighlightText;
  50. COLORREF g_clrInfoText;
  51. COLORREF g_clrInfoBk;
  52. COLORREF g_clr3DDkShadow;
  53. COLORREF g_clr3DLight;
  54. HBRUSH g_hbrGrayText;
  55. HBRUSH g_hbrWindow;
  56. HBRUSH g_hbrWindowText;
  57. HBRUSH g_hbrWindowFrame;
  58. HBRUSH g_hbrBtnFace;
  59. HBRUSH g_hbrBtnHighlight;
  60. HBRUSH g_hbrBtnShadow;
  61. HBRUSH g_hbrHighlight;
  62. DWORD g_dwHoverSelectTimeout;
  63. HFONT g_hfontSystem;
  64. #define CCS_ALIGN (CCS_TOP | CCS_NOMOVEY | CCS_BOTTOM)
  65. int TrueMapWindowPoints(HWND hwndFrom, HWND hwndTo, LPPOINT lppt, UINT cPoints);
  66. // Note that the default alignment is CCS_BOTTOM
  67. //
  68. void FAR PASCAL NewSize(HWND hWnd, int nThickness, LONG style, int left, int top, int width, int height)
  69. {
  70. // Resize the window unless the user said not to
  71. //
  72. if (!(style & CCS_NORESIZE))
  73. {
  74. RECT rc, rcWindow, rcBorder;
  75. // Remember size that was passed in and don't bother calling SetWindowPos if we're not
  76. // actually going to change the window size
  77. int leftSave = left;
  78. int topSave = top;
  79. int widthSave = width;
  80. int heightSave = height;
  81. // Calculate the borders around the client area of the status bar
  82. GetWindowRect(hWnd, &rcWindow);
  83. rcWindow.right -= rcWindow.left; // -> dx
  84. rcWindow.bottom -= rcWindow.top; // -> dy
  85. GetClientRect(hWnd, &rc);
  86. //
  87. // If the window is mirrored, mirror the anchor point
  88. // since it will be passed to SWP which accepts screen
  89. // ccordinates. This mainly fixes the display of status bar
  90. // and others. [samera]
  91. //
  92. if (IS_WINDOW_RTL_MIRRORED(hWnd))
  93. {
  94. TrueMapWindowPoints(hWnd, NULL, (LPPOINT)&rc.left, 1);
  95. }
  96. else
  97. {
  98. ClientToScreen(hWnd, (LPPOINT)&rc);
  99. }
  100. rcBorder.left = rc.left - rcWindow.left;
  101. rcBorder.top = rc.top - rcWindow.top ;
  102. rcBorder.right = rcWindow.right - rc.right - rcBorder.left;
  103. rcBorder.bottom = rcWindow.bottom - rc.bottom - rcBorder.top ;
  104. if (style & CCS_VERT)
  105. nThickness += rcBorder.left + rcBorder.right;
  106. else
  107. nThickness += rcBorder.top + rcBorder.bottom;
  108. // Check whether to align to the parent window
  109. //
  110. if (style & CCS_NOPARENTALIGN)
  111. {
  112. // Check out whether this bar is top aligned or bottom aligned
  113. //
  114. switch (style & CCS_ALIGN)
  115. {
  116. case CCS_TOP:
  117. case CCS_NOMOVEY:
  118. break;
  119. default: // CCS_BOTTOM
  120. if(style & CCS_VERT)
  121. left = left + width - nThickness;
  122. else
  123. top = top + height - nThickness;
  124. }
  125. }
  126. else
  127. {
  128. // It is assumed there is a parent by default
  129. //
  130. GetClientRect(GetParent(hWnd), &rc);
  131. // Don't forget to account for the borders
  132. //
  133. if(style & CCS_VERT)
  134. {
  135. top = -rcBorder.right;
  136. height = rc.bottom + rcBorder.top + rcBorder.bottom;
  137. }
  138. else
  139. {
  140. left = -rcBorder.left;
  141. width = rc.right + rcBorder.left + rcBorder.right;
  142. }
  143. if ((style & CCS_ALIGN) == CCS_TOP)
  144. {
  145. if(style & CCS_VERT)
  146. left = -rcBorder.left;
  147. else
  148. top = -rcBorder.top;
  149. }
  150. else if ((style & CCS_ALIGN) != CCS_NOMOVEY)
  151. {
  152. if (style & CCS_VERT)
  153. left = rc.right - nThickness + rcBorder.right;
  154. else
  155. top = rc.bottom - nThickness + rcBorder.bottom;
  156. }
  157. }
  158. if (!(style & CCS_NOMOVEY) && !(style & CCS_NODIVIDER))
  159. {
  160. if (style & CCS_VERT)
  161. left += g_cxEdge;
  162. else
  163. top += g_cyEdge; // double pixel edge thing
  164. }
  165. if(style & CCS_VERT)
  166. width = nThickness;
  167. else
  168. height = nThickness;
  169. SetWindowPos(hWnd, NULL, left, top, width, height, SWP_NOZORDER);
  170. }
  171. }
  172. BOOL FAR PASCAL MGetTextExtent(HDC hdc, LPCTSTR lpstr, int cnt, int FAR * pcx, int FAR * pcy)
  173. {
  174. BOOL fSuccess;
  175. SIZE size = {0,0};
  176. if (cnt == -1)
  177. cnt = lstrlen(lpstr);
  178. fSuccess=GetTextExtentPoint(hdc, lpstr, cnt, &size);
  179. if (pcx)
  180. *pcx=size.cx;
  181. if (pcy)
  182. *pcy=size.cy;
  183. return fSuccess;
  184. }
  185. // these are the default colors used to map the dib colors
  186. // to the current system colors
  187. #define RGB_BUTTONTEXT (RGB(000,000,000)) // black
  188. #define RGB_BUTTONSHADOW (RGB(128,128,128)) // dark grey
  189. #define RGB_BUTTONFACE (RGB(192,192,192)) // bright grey
  190. #define RGB_BUTTONHILIGHT (RGB(255,255,255)) // white
  191. #define RGB_BACKGROUNDSEL (RGB(000,000,255)) // blue
  192. #define RGB_BACKGROUND (RGB(255,000,255)) // magenta
  193. #ifdef UNIX
  194. RGBQUAD CLR_TO_RGBQUAD( COLORREF clr)
  195. {
  196. /* main modif for unix: keep the extra byte in the rgbReserved field
  197. This is used for our motif colors that are expressed in term of
  198. CMAPINDEX rather than real RGBs, this function is also portable
  199. and immune to endianness*/
  200. RGBQUAD rgbqResult;
  201. rgbqResult.rgbRed=GetRValue(clr);
  202. rgbqResult.rgbGreen=GetGValue(clr);
  203. rgbqResult.rgbBlue=GetBValue(clr);
  204. rgbqResult.rgbReserved=(BYTE)((clr>>24)&0xff);
  205. return rgbqResult;
  206. }
  207. COLORREF RGBQUAD_TO_CLR( RGBQUAD rgbQ )
  208. {
  209. return ( ((DWORD)rgbQ.rgbRed) | ((DWORD)(rgbQ.rgbGreen << 8)) |
  210. ((DWORD)(rgbQ.rgbBlue << 16)) | ((DWORD)(rgbQ.rgbReserved << 24)) );
  211. }
  212. /* This is just plain wrong
  213. 1) they definition of COLORMAP is based on COLORREFs but a
  214. DIB color map is RGBQUAD
  215. 2) FlipColor as per previous definition does not flip at all
  216. since it goes from COLORREF to COLORREF
  217. so we are better doing nothing, so we dont loose our CMAP flag
  218. (Jose)
  219. */
  220. #define FlipColor(rgb) (rgb)
  221. #else
  222. #define FlipColor(rgb) (RGB(GetBValue(rgb), GetGValue(rgb), GetRValue(rgb)))
  223. #endif /* UNIX */
  224. #define MAX_COLOR_MAPS 16
  225. // This is almost the same as LoadImage(..., LR_MAP3DCOLORS) except that
  226. //
  227. // - The app can specify a custom color map,
  228. // - The default color map maps colors beyond the 3D colors,
  229. // - strange UNIX stuff happens that I'm afraid to mess with.
  230. //
  231. HBITMAP WINAPI CreateMappedBitmap(HINSTANCE hInstance, INT_PTR idBitmap,
  232. UINT wFlags, LPCOLORMAP lpColorMap, int iNumMaps)
  233. {
  234. HDC hdc, hdcMem = NULL;
  235. HANDLE h;
  236. COLOR_STRUCT FAR *p;
  237. COLOR_STRUCT FAR *lpTable;
  238. LPBYTE lpBits;
  239. HANDLE hRes;
  240. LPBITMAPINFOHEADER lpBitmapInfo;
  241. HBITMAP hbm = NULL, hbmOld;
  242. int numcolors, i;
  243. int wid, hgt;
  244. LPBITMAPINFOHEADER lpMungeInfo;
  245. int offBits;
  246. COLOR_STRUCT rgbMaskTable[16];
  247. COLOR_STRUCT rgbBackground;
  248. #ifdef UNIX
  249. const curColorRes = GetScreenDepth();
  250. #endif /* UNIX */
  251. static const COLORMAP SysColorMap[] = {
  252. {RGB_BUTTONTEXT, COLOR_BTNTEXT}, // black
  253. {RGB_BUTTONSHADOW, COLOR_BTNSHADOW}, // dark grey
  254. {RGB_BUTTONFACE, COLOR_BTNFACE}, // bright grey
  255. {RGB_BUTTONHILIGHT, COLOR_BTNHIGHLIGHT},// white
  256. {RGB_BACKGROUNDSEL, COLOR_HIGHLIGHT}, // blue
  257. {RGB_BACKGROUND, COLOR_WINDOW} // magenta
  258. };
  259. #define NUM_DEFAULT_MAPS (sizeof(SysColorMap)/sizeof(COLORMAP))
  260. COLORMAP DefaultColorMap[NUM_DEFAULT_MAPS];
  261. #ifndef UNIX
  262. COLORMAP DIBColorMap[MAX_COLOR_MAPS];
  263. #else
  264. COLORREF DIBColorRefs[MAX_COLOR_MAPS];
  265. #endif
  266. h = FindResource(hInstance, MAKEINTRESOURCE(idBitmap), RT_BITMAP);
  267. if (!h)
  268. return NULL;
  269. hRes = LoadResource(hInstance, h);
  270. /* Lock the bitmap and get a pointer to the color table. */
  271. lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes);
  272. if (!lpBitmapInfo)
  273. return NULL;
  274. // munge on a copy of the color table instead of the original
  275. // (prevent possibility of "reload" with messed table
  276. offBits = (int)lpBitmapInfo->biSize + ((1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD));
  277. lpMungeInfo = GlobalAlloc(GPTR, offBits);
  278. if (!lpMungeInfo)
  279. goto Exit1;
  280. hmemcpy(lpMungeInfo, lpBitmapInfo, offBits);
  281. /* Get system colors for the default color map */
  282. if (!lpColorMap) {
  283. lpColorMap = DefaultColorMap;
  284. iNumMaps = NUM_DEFAULT_MAPS;
  285. for (i=0; i < iNumMaps; i++) {
  286. lpColorMap[i].from = SysColorMap[i].from;
  287. lpColorMap[i].to = GetSysColor((int)SysColorMap[i].to);
  288. }
  289. }
  290. /* Transform RGB color map to a BGR DIB format color map */
  291. if (iNumMaps > MAX_COLOR_MAPS)
  292. iNumMaps = MAX_COLOR_MAPS;
  293. #ifndef UNIX
  294. /* IEUNIX
  295. 1) their definition of COLORMAP is based on COLORREFs but a
  296. DIB color map is RGBQUAD
  297. 2) FlipColor as per definition above does not flip at all
  298. since it goes from COLORREF to COLORREF
  299. so we are better doing nothing, this the(Jose)
  300. */
  301. for (i=0; i < iNumMaps; i++) {
  302. DIBColorMap[i].to = FlipColor(lpColorMap[i].to);
  303. DIBColorMap[i].from = FlipColor(lpColorMap[i].from);
  304. }
  305. #endif /* !UNIX */
  306. // use the table in the munging buffer
  307. lpTable = p = (COLOR_STRUCT FAR *)(((LPBYTE)lpMungeInfo) + lpMungeInfo->biSize);
  308. /* Replace button-face and button-shadow colors with the current values
  309. */
  310. numcolors = 16;
  311. #ifdef UNIX
  312. for (i=0; i<numcolors; i++) {
  313. if (p[i].rgbReserved & 0x04) // if colormap index
  314. DIBColorRefs[i] = MwGetTrueRGBValue(RGBQUAD_TO_CLR(p[i]));
  315. else
  316. DIBColorRefs[i] = RGB(p[i].rgbRed, p[i].rgbGreen, p[i].rgbBlue);
  317. }
  318. #endif
  319. // if we are creating a mask, build a color table with white
  320. // marking the transparent section (where it used to be background)
  321. // and black marking the opaque section (everything else). this
  322. // table is used below to build the mask using the original DIB bits.
  323. #ifndef UNIX
  324. if (wFlags & CMB_MASKED) {
  325. rgbBackground = FlipColor(RGB_BACKGROUND);
  326. for (i = 0; i < 16; i++) {
  327. if (p[i] == rgbBackground)
  328. rgbMaskTable[i] = 0xFFFFFF; // transparent section
  329. else
  330. rgbMaskTable[i] = 0x000000; // opaque section
  331. }
  332. }
  333. while (numcolors-- > 0) {
  334. for (i = 0; i < iNumMaps; i++) {
  335. if ((*p & 0x00FFFFFF) == DIBColorMap[i].from) {
  336. *p = DIBColorMap[i].to;
  337. break;
  338. }
  339. }
  340. p++;
  341. }
  342. #else
  343. if (wFlags & CMB_MASKED) {
  344. /* IEUNIX - Varmac: later on change the below to use MwXPixel */
  345. for (i = 0; i < 16; i++) {
  346. if (DIBColorRefs[i] == RGB_BACKGROUND) {
  347. rgbMaskTable[i].rgbRed = 0xFF; // transparent section
  348. rgbMaskTable[i].rgbGreen = 0xFF;
  349. rgbMaskTable[i].rgbBlue = 0xFF;
  350. } else {
  351. rgbMaskTable[i].rgbRed = 0x00; // opaque section
  352. rgbMaskTable[i].rgbGreen = 0x00;
  353. rgbMaskTable[i].rgbBlue = 0x00;
  354. }
  355. rgbMaskTable[i].rgbReserved = 0;
  356. }
  357. }
  358. p += (numcolors-1);
  359. while (numcolors-- > 0) {
  360. for (i = 0; i < iNumMaps; i++) {
  361. if (DIBColorRefs[numcolors] == lpColorMap[i].from) {
  362. // if (GetScreenDepth() < 2) {
  363. // if (lpColorMap[i].from != RGB_BUTTONTEXT)
  364. // *p = CLR_TO_RGBQUAD(RGB(255,255,255));
  365. // } else
  366. *p = CLR_TO_RGBQUAD(lpColorMap[i].to);
  367. break;
  368. }
  369. }
  370. p--;
  371. }
  372. #endif /* !UNIX */
  373. /* First skip over the header structure */
  374. lpBits = (LPBYTE)(lpBitmapInfo) + offBits;
  375. /* Create a color bitmap compatible with the display device */
  376. i = wid = (int)lpBitmapInfo->biWidth;
  377. hgt = (int)lpBitmapInfo->biHeight;
  378. hdc = GetDC(NULL);
  379. hdcMem = CreateCompatibleDC(hdc);
  380. if (!hdcMem)
  381. goto cleanup;
  382. // if creating a mask, the bitmap needs to be twice as wide.
  383. if (wFlags & CMB_MASKED)
  384. i = wid*2;
  385. // discardable bitmaps aren't much use anymore...
  386. //
  387. // if (wFlags & CMB_DISCARDABLE)
  388. // hbm = CreateDiscardableBitmap(hdc, i, hgt);
  389. // else
  390. if (wFlags & CMB_DIBSECTION)
  391. {
  392. // Have to edit the header slightly, since CreateDIBSection supports
  393. // only BI_RGB and BI_BITFIELDS. This is the same whackery that USER
  394. // does in LoadImage.
  395. LPVOID pvDummy;
  396. DWORD dwCompression = lpMungeInfo->biCompression;
  397. if (dwCompression != BI_BITFIELDS)
  398. lpMungeInfo->biCompression = BI_RGB;
  399. hbm = CreateDIBSection(hdc, (LPBITMAPINFO)lpMungeInfo, DIB_RGB_COLORS,
  400. &pvDummy, NULL, 0);
  401. lpMungeInfo->biCompression = dwCompression;
  402. }
  403. // If CMB_DIBSECTION failed, then create a DDB instead. Not perfect,
  404. // but better than creating nothing. We also get here if the caller
  405. // didn't ask for a DIB section.
  406. if (hbm == NULL)
  407. hbm = CreateCompatibleBitmap(hdc, i, hgt);
  408. if (hbm) {
  409. hbmOld = SelectObject(hdcMem, hbm);
  410. // set the main image
  411. StretchDIBits(hdcMem, 0, 0, wid, hgt, 0, 0, wid, hgt, lpBits,
  412. (LPBITMAPINFO)lpMungeInfo, DIB_RGB_COLORS, SRCCOPY);
  413. // if building a mask, replace the DIB's color table with the
  414. // mask's black/white table and set the bits. in order to
  415. // complete the masked effect, the actual image needs to be
  416. // modified so that it has the color black in all sections
  417. // that are to be transparent.
  418. if (wFlags & CMB_MASKED) {
  419. hmemcpy(lpTable, (DWORD FAR *)rgbMaskTable, 16 * sizeof(RGBQUAD));
  420. StretchDIBits(hdcMem, wid, 0, wid, hgt, 0, 0, wid, hgt, lpBits,
  421. (LPBITMAPINFO)lpMungeInfo, DIB_RGB_COLORS, SRCCOPY);
  422. #ifdef UNIX
  423. if (MwGetTrueRGBValue(GetSysColor(COLOR_WINDOW)) != 0xffffff)
  424. #endif
  425. BitBlt(hdcMem, 0, 0, wid, hgt, hdcMem, wid, 0, 0x00220326); // DSna
  426. }
  427. SelectObject(hdcMem, hbmOld);
  428. }
  429. cleanup:
  430. if (hdcMem)
  431. DeleteObject(hdcMem);
  432. ReleaseDC(NULL, hdc);
  433. GlobalFree(lpMungeInfo);
  434. Exit1:
  435. UnlockResource(hRes);
  436. FreeResource(hRes);
  437. return hbm;
  438. }
  439. // moved from shelldll\dragdrop.c
  440. // should caller pass in message that indicates termination
  441. // (WM_LBUTTONUP, WM_RBUTTONUP)?
  442. //
  443. // in:
  444. // hwnd to do check on
  445. // x, y in client coordinates
  446. //
  447. // returns:
  448. // TRUE the user began to drag (moved mouse outside double click rect)
  449. // FALSE mouse came up inside click rect
  450. //
  451. // BUGBUG, should support VK_ESCAPE to cancel
  452. BOOL PASCAL CheckForDragBegin(HWND hwnd, int x, int y)
  453. {
  454. RECT rc;
  455. int dxClickRect = GetSystemMetrics(SM_CXDRAG);
  456. int dyClickRect = GetSystemMetrics(SM_CYDRAG);
  457. if (dxClickRect < 4)
  458. {
  459. dxClickRect = dyClickRect = 4;
  460. }
  461. // See if the user moves a certain number of pixels in any direction
  462. SetRect(&rc, x - dxClickRect, y - dyClickRect, x + dxClickRect, y + dyClickRect);
  463. MapWindowRect(hwnd, HWND_DESKTOP, &rc); // client -> screen
  464. //
  465. // SUBTLE! We use PeekMessage+WaitMessage instead of GetMessage,
  466. // because WaitMessage will return when there is an incoming
  467. // SendMessage, whereas GetMessage does not. This is important,
  468. // because the incoming message might've been WM_CAPTURECHANGED.
  469. //
  470. SetCapture(hwnd);
  471. do {
  472. MSG32 msg32;
  473. if (PeekMessage32(&msg32, NULL, 0, 0, PM_REMOVE, TRUE))
  474. {
  475. // See if the application wants to process the message...
  476. if (CallMsgFilter32(&msg32, MSGF_COMMCTRL_BEGINDRAG, TRUE) != 0)
  477. continue;
  478. switch (msg32.message) {
  479. case WM_LBUTTONUP:
  480. case WM_RBUTTONUP:
  481. case WM_LBUTTONDOWN:
  482. case WM_RBUTTONDOWN:
  483. ReleaseCapture();
  484. return FALSE;
  485. case WM_MOUSEMOVE:
  486. if (IsWindow(hwnd) && !PtInRect(&rc, msg32.pt)) {
  487. ReleaseCapture();
  488. return TRUE;
  489. }
  490. break;
  491. default:
  492. TranslateMessage32(&msg32, TRUE);
  493. DispatchMessage32(&msg32, TRUE);
  494. break;
  495. }
  496. }
  497. else WaitMessage();
  498. // WM_CANCELMODE messages will unset the capture, in that
  499. // case I want to exit this loop
  500. } while (IsWindow(hwnd) && GetCapture() == hwnd);
  501. return FALSE;
  502. }
  503. /* Regular StrToInt; stops at first non-digit. */
  504. int WINAPI StrToInt(LPCTSTR lpSrc) // atoi()
  505. {
  506. #define ISDIGIT(c) ((c) >= TEXT('0') && (c) <= TEXT('9'))
  507. int n = 0;
  508. BOOL bNeg = FALSE;
  509. if (*lpSrc == TEXT('-')) {
  510. bNeg = TRUE;
  511. lpSrc++;
  512. }
  513. while (ISDIGIT(*lpSrc)) {
  514. n *= 10;
  515. n += *lpSrc - TEXT('0');
  516. lpSrc++;
  517. }
  518. return bNeg ? -n : n;
  519. }
  520. #ifdef UNICODE
  521. //
  522. // Wrappers for StrToInt
  523. //
  524. int WINAPI StrToIntA(LPCSTR lpSrc) // atoi()
  525. {
  526. LPWSTR lpString;
  527. INT iResult;
  528. lpString = ProduceWFromA (CP_ACP, lpSrc);
  529. if (!lpString) {
  530. return 0;
  531. }
  532. iResult = StrToIntW(lpString);
  533. FreeProducedString (lpString);
  534. return iResult;
  535. }
  536. #else
  537. //
  538. // Stub W version when Built ANSI
  539. //
  540. #ifndef UNIX
  541. int WINAPI StrToIntW(LPCWSTR lpSrc) // atoi()
  542. {
  543. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  544. return 0;
  545. }
  546. #endif /* !UNIX */
  547. #endif
  548. #undef StrToLong
  549. #ifdef WIN32
  550. //
  551. // No need to Unicode this since it is not
  552. // exported.
  553. //
  554. LONG WINAPI StrToLong(LPCTSTR lpSrc) // atoi()
  555. {
  556. return StrToInt(lpSrc);
  557. }
  558. #else
  559. /* Regular StrToLong; stops at first non-digit. */
  560. LONG WINAPI StrToLong(LPCSTR lpSrc) // atoi()
  561. {
  562. #define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
  563. LONG n = 0;
  564. BOOL bNeg = FALSE;
  565. if (*lpSrc == TEXT('-')) {
  566. bNeg = TRUE;
  567. lpSrc++;
  568. }
  569. while (ISDIGIT(*lpSrc)) {
  570. n *= 10;
  571. n += *lpSrc - TEXT('0');
  572. lpSrc++;
  573. }
  574. return bNeg ? -n : n;
  575. }
  576. #endif
  577. #pragma code_seg(CODESEG_INIT)
  578. //
  579. // From zmouse.h in the Magellan SDK
  580. //
  581. #define MSH_MOUSEWHEEL TEXT("MSWHEEL_ROLLMSG")
  582. // Class name for Magellan/Z MSWHEEL window
  583. // use FindWindow to get hwnd to MSWHEEL
  584. #define MOUSEZ_CLASSNAME TEXT("MouseZ") // wheel window class
  585. #define MOUSEZ_TITLE TEXT("Magellan MSWHEEL") // wheel window title
  586. #define MSH_WHEELMODULE_CLASS (MOUSEZ_CLASSNAME)
  587. #define MSH_WHEELMODULE_TITLE (MOUSEZ_TITLE)
  588. #define MSH_SCROLL_LINES TEXT("MSH_SCROLL_LINES_MSG")
  589. #define DI_GETDRAGIMAGE TEXT("ShellGetDragImage") // Copied from Shlobj.w
  590. UINT g_msgMSWheel;
  591. UINT g_ucScrollLines = 3; /* default */
  592. int gcWheelDelta;
  593. UINT g_uDragImages;
  594. void FAR PASCAL InitGlobalMetrics(WPARAM wParam)
  595. {
  596. static BOOL fInitMouseWheel;
  597. static HWND hwndMSWheel;
  598. static UINT msgMSWheelGetScrollLines;
  599. if (!fInitMouseWheel)
  600. {
  601. fInitMouseWheel = TRUE;
  602. if (g_bRunOnNT || g_bRunOnMemphis)
  603. g_msgMSWheel = WM_MOUSEWHEEL;
  604. else
  605. {
  606. g_msgMSWheel = RegisterWindowMessage(MSH_MOUSEWHEEL);
  607. msgMSWheelGetScrollLines = RegisterWindowMessage(MSH_SCROLL_LINES);
  608. hwndMSWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);
  609. }
  610. }
  611. g_uDragImages = RegisterWindowMessage(DI_GETDRAGIMAGE);
  612. #ifndef UNIX
  613. if (g_bRunOnNT || g_bRunOnMemphis)
  614. {
  615. SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &g_ucScrollLines, 0);
  616. }
  617. else if (hwndMSWheel && msgMSWheelGetScrollLines)
  618. {
  619. g_ucScrollLines =
  620. (UINT)SendMessage(hwndMSWheel, msgMSWheelGetScrollLines, 0, 0);
  621. }
  622. #endif
  623. // bug fix HACK: these are NOT members of USER's NONCLIENTMETRICS struct
  624. g_cxIcon = GetSystemMetrics(SM_CXICON);
  625. g_cyIcon = GetSystemMetrics(SM_CYICON);
  626. g_cxSmIcon = GetSystemMetrics(SM_CXSMICON);
  627. g_cySmIcon = GetSystemMetrics(SM_CYSMICON);
  628. g_cxIconSpacing = GetSystemMetrics( SM_CXICONSPACING );
  629. g_cyIconSpacing = GetSystemMetrics( SM_CYICONSPACING );
  630. // Full window drag stays off if running remotely
  631. if (!g_bRemoteSession &&
  632. (wParam == 0 || wParam == SPI_SETDRAGFULLWINDOWS)) {
  633. SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, sizeof(g_fDragFullWindows), &g_fDragFullWindows, 0);
  634. }
  635. // Smooth scrolling stays off if running remotely
  636. if (!g_bRemoteSession) {
  637. HKEY hkey;
  638. g_fSmoothScroll = TRUE;
  639. if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, KEY_READ, &hkey) == ERROR_SUCCESS) {
  640. DWORD dwSize = sizeof(g_fSmoothScroll);
  641. RegQueryValueEx(hkey, TEXT("SmoothScroll"), 0, NULL, (LPBYTE)&g_fSmoothScroll, &dwSize);
  642. RegCloseKey(hkey);
  643. }
  644. }
  645. if (g_bRemoteSession)
  646. {
  647. // Nobody should've turned these on
  648. ASSERT(g_fDragFullWindows == FALSE);
  649. ASSERT(g_fSmoothScroll == FALSE);
  650. }
  651. // BUGBUG: some of these are also not members of NONCLIENTMETRICS
  652. if ((wParam == 0) || (wParam == SPI_SETNONCLIENTMETRICS))
  653. {
  654. NONCLIENTMETRICS ncm;
  655. // REVIEW, make sure all these vars are used somewhere.
  656. g_cxEdge = GetSystemMetrics(SM_CXEDGE);
  657. g_cyEdge = GetSystemMetrics(SM_CYEDGE);
  658. g_cxBorder = GetSystemMetrics(SM_CXBORDER);
  659. g_cyBorder = GetSystemMetrics(SM_CYBORDER);
  660. g_cxScreen = GetSystemMetrics(SM_CXSCREEN);
  661. g_cyScreen = GetSystemMetrics(SM_CYSCREEN);
  662. g_cxFrame = GetSystemMetrics(SM_CXFRAME);
  663. g_cyFrame = GetSystemMetrics(SM_CYFRAME);
  664. ncm.cbSize = sizeof(ncm);
  665. SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
  666. g_cxVScroll = g_cxScrollbar = (int)ncm.iScrollWidth;
  667. g_cyHScroll = g_cyScrollbar = (int)ncm.iScrollHeight;
  668. // this is true for 4.0 modules only
  669. // for 3.x modules user lies and adds one to these values
  670. // ASSERT(g_cxVScroll == GetSystemMetrics(SM_CXVSCROLL));
  671. // ASSERT(g_cyHScroll == GetSystemMetrics(SM_CYHSCROLL));
  672. g_cxIconMargin = g_cxBorder * 8;
  673. g_cyIconMargin = g_cyEdge;
  674. g_cyLabelSpace = g_cyIconMargin + (g_cyEdge);
  675. g_cxLabelMargin = g_cxEdge;
  676. g_cxDoubleClk = GetSystemMetrics(SM_CXDOUBLECLK);
  677. g_cyDoubleClk = GetSystemMetrics(SM_CYDOUBLECLK);
  678. }
  679. #if defined(UNIX)
  680. g_dwHoverSelectTimeout = 0;
  681. #elif defined(WINNT) && defined(SPI_GETMOUSEHOVERTIME)
  682. //NT 4.0 has this SPI_GETMOUSEHOVERTIME
  683. SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &g_dwHoverSelectTimeout, 0);
  684. #else
  685. // For Win95, we get this from the registry directly.
  686. {
  687. HKEY hkey;
  688. DWORD dwType;
  689. g_dwHoverSelectTimeout = 0;
  690. if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Mouse"), 0, KEY_READ, &hkey) == ERROR_SUCCESS) {
  691. DWORD dwSize = sizeof(g_dwHoverSelectTimeout);
  692. if((RegQueryValueEx(hkey, TEXT("MouseHoverTime"), 0, &dwType, (LPBYTE)&g_dwHoverSelectTimeout, &dwSize) != ERROR_SUCCESS) ||
  693. (dwType != REG_DWORD))
  694. g_dwHoverSelectTimeout = 0;
  695. RegCloseKey(hkey);
  696. }
  697. }
  698. #endif
  699. }
  700. void FAR PASCAL InitGlobalColors()
  701. {
  702. g_clrWindow = GetSysColor(COLOR_WINDOW);
  703. g_clrWindowText = GetSysColor(COLOR_WINDOWTEXT);
  704. g_clrWindowFrame = GetSysColor(COLOR_WINDOWFRAME);
  705. g_clrGrayText = GetSysColor(COLOR_GRAYTEXT);
  706. g_clrBtnText = GetSysColor(COLOR_BTNTEXT);
  707. g_clrBtnFace = GetSysColor(COLOR_BTNFACE);
  708. g_clrBtnShadow = GetSysColor(COLOR_BTNSHADOW);
  709. g_clrBtnHighlight = GetSysColor(COLOR_BTNHIGHLIGHT);
  710. g_clrHighlight = GetSysColor(COLOR_HIGHLIGHT);
  711. g_clrHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  712. g_clrInfoText = GetSysColor(COLOR_INFOTEXT);
  713. g_clrInfoBk = GetSysColor(COLOR_INFOBK);
  714. g_clr3DDkShadow = GetSysColor(COLOR_3DDKSHADOW);
  715. g_clr3DLight = GetSysColor(COLOR_3DLIGHT);
  716. g_hbrGrayText = GetSysColorBrush(COLOR_GRAYTEXT);
  717. g_hbrWindow = GetSysColorBrush(COLOR_WINDOW);
  718. g_hbrWindowText = GetSysColorBrush(COLOR_WINDOWTEXT);
  719. g_hbrWindowFrame = GetSysColorBrush(COLOR_WINDOWFRAME);
  720. g_hbrBtnFace = GetSysColorBrush(COLOR_BTNFACE);
  721. g_hbrBtnHighlight = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
  722. g_hbrBtnShadow = GetSysColorBrush(COLOR_BTNSHADOW);
  723. g_hbrHighlight = GetSysColorBrush(COLOR_HIGHLIGHT);
  724. g_hfontSystem = GetStockObject(SYSTEM_FONT);
  725. }
  726. #pragma code_seg()
  727. void FAR PASCAL RelayToToolTips(HWND hwndToolTips, HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  728. {
  729. if(hwndToolTips) {
  730. MSG msg;
  731. msg.lParam = lParam;
  732. msg.wParam = wParam;
  733. msg.message = wMsg;
  734. msg.hwnd = hWnd;
  735. SendMessage(hwndToolTips, TTM_RELAYEVENT, 0, (LPARAM)(LPMSG)&msg);
  736. }
  737. }
  738. #define DT_SEARCHTIMEOUT 1000L // 1 seconds
  739. __inline BOOL IsISearchTimedOut(PISEARCHINFO pis)
  740. {
  741. return GetMessageTime() - pis->timeLast > DT_SEARCHTIMEOUT &&
  742. !IsFlagSet(g_dwPrototype, PTF_NOISEARCHTO);
  743. }
  744. int FAR PASCAL GetIncrementSearchString(PISEARCHINFO pis, LPTSTR lpsz)
  745. {
  746. if (IsISearchTimedOut(pis))
  747. {
  748. pis->iIncrSearchFailed = 0;
  749. pis->ichCharBuf = 0;
  750. }
  751. if (pis->ichCharBuf && lpsz) {
  752. lstrcpyn(lpsz, pis->pszCharBuf, pis->ichCharBuf + 1);
  753. lpsz[pis->ichCharBuf] = TEXT('\0');
  754. }
  755. return pis->ichCharBuf;
  756. }
  757. #if defined(FE_IME)
  758. // Now only Korean version is interested in incremental search with composition string.
  759. BOOL FAR PASCAL IncrementSearchImeCompStr(PISEARCHINFO pis, BOOL fCompStr, LPTSTR lpszCompStr, LPTSTR FAR *lplpstr)
  760. {
  761. BOOL fRestart = FALSE;
  762. if (!pis->fReplaceCompChar && IsISearchTimedOut(pis))
  763. {
  764. pis->iIncrSearchFailed = 0;
  765. pis->ichCharBuf = 0;
  766. }
  767. if (pis->ichCharBuf == 0)
  768. {
  769. fRestart = TRUE;
  770. pis->fReplaceCompChar = FALSE;
  771. }
  772. pis->timeLast = GetMessageTime();
  773. // Is there room for new character plus zero terminator?
  774. //
  775. #ifdef UNICODE
  776. if (!pis->fReplaceCompChar && pis->ichCharBuf + 1 + 1 > pis->cbCharBuf)
  777. #else
  778. if (!pis->fReplaceCompChar && pis->ichCharBuf + 2 + 1 > pis->cbCharBuf)
  779. #endif
  780. {
  781. LPTSTR psz = ReAlloc(pis->pszCharBuf, sizeof(TCHAR)*(pis->cbCharBuf + 16));
  782. if (!psz)
  783. return fRestart;
  784. pis->cbCharBuf += 16;
  785. pis->pszCharBuf = psz;
  786. }
  787. if (pis->fReplaceCompChar)
  788. {
  789. if (lpszCompStr[0])
  790. {
  791. #ifdef UNICODE
  792. pis->pszCharBuf[pis->ichCharBuf-1] = lpszCompStr[0];
  793. #else
  794. pis->pszCharBuf[pis->ichCharBuf-2] = lpszCompStr[0];
  795. pis->pszCharBuf[pis->ichCharBuf-1] = lpszCompStr[1];
  796. #endif
  797. pis->pszCharBuf[pis->ichCharBuf] = 0;
  798. }
  799. else
  800. {
  801. #ifdef UNICODE
  802. pis->ichCharBuf--;
  803. #else
  804. pis->ichCharBuf -= 2;
  805. #endif
  806. pis->pszCharBuf[pis->ichCharBuf] = 0;
  807. }
  808. }
  809. else
  810. {
  811. #ifdef UNICODE
  812. pis->pszCharBuf[pis->ichCharBuf++] = lpszCompStr[0];
  813. #else
  814. pis->pszCharBuf[pis->ichCharBuf++] = lpszCompStr[0];
  815. pis->pszCharBuf[pis->ichCharBuf++] = lpszCompStr[1];
  816. #endif
  817. pis->pszCharBuf[pis->ichCharBuf] = 0;
  818. }
  819. pis->fReplaceCompChar = (fCompStr && lpszCompStr[0]);
  820. #ifdef UNICODE
  821. if (pis->ichCharBuf == 1 && pis->fReplaceCompChar)
  822. #else
  823. if (pis->ichCharBuf == 2 && pis->fReplaceCompChar)
  824. #endif
  825. fRestart = TRUE;
  826. *lplpstr = pis->pszCharBuf;
  827. return fRestart;
  828. }
  829. #endif FE_IME
  830. #ifdef UNICODE
  831. /*
  832. * Thunk for LVM_GETISEARCHSTRINGA
  833. */
  834. int FAR PASCAL GetIncrementSearchStringA(PISEARCHINFO pis, UINT uiCodePage, LPSTR lpsz)
  835. {
  836. if (IsISearchTimedOut(pis))
  837. {
  838. pis->iIncrSearchFailed = 0;
  839. pis->ichCharBuf = 0;
  840. }
  841. if (pis->ichCharBuf && lpsz) {
  842. ConvertWToAN( uiCodePage, lpsz, pis->ichCharBuf, pis->pszCharBuf, pis->ichCharBuf );
  843. lpsz[pis->ichCharBuf] = '\0';
  844. }
  845. return pis->ichCharBuf;
  846. }
  847. #endif
  848. // Beep only on the first failure.
  849. void FAR PASCAL IncrementSearchBeep(PISEARCHINFO pis)
  850. {
  851. if (!pis->iIncrSearchFailed)
  852. {
  853. pis->iIncrSearchFailed = TRUE;
  854. MessageBeep(0);
  855. }
  856. }
  857. //
  858. // IncrementSearchString - Add or clear the search string
  859. //
  860. // ch == 0: Reset the search string. Return value meaningless.
  861. //
  862. // ch != 0: Append the character to the search string, starting
  863. // a new search string if we timed out the last one.
  864. // lplpstr receives the string so far.
  865. // Return value is TRUE if a new search string was
  866. // created, or FALSE if we appended to an existing one.
  867. //
  868. BOOL FAR PASCAL IncrementSearchString(PISEARCHINFO pis, UINT ch, LPTSTR FAR *lplpstr)
  869. {
  870. BOOL fRestart = FALSE;
  871. if (!ch) {
  872. pis->ichCharBuf =0;
  873. pis->iIncrSearchFailed = 0;
  874. return FALSE;
  875. }
  876. if (IsISearchTimedOut(pis))
  877. {
  878. pis->iIncrSearchFailed = 0;
  879. pis->ichCharBuf = 0;
  880. }
  881. if (pis->ichCharBuf == 0)
  882. fRestart = TRUE;
  883. pis->timeLast = GetMessageTime();
  884. // Is there room for new character plus zero terminator?
  885. //
  886. if (pis->ichCharBuf + 1 + 1 > pis->cbCharBuf)
  887. {
  888. LPTSTR psz = ReAlloc(pis->pszCharBuf, ((pis->cbCharBuf + 16) * sizeof(TCHAR)));
  889. if (!psz)
  890. return fRestart;
  891. pis->cbCharBuf += 16;
  892. pis->pszCharBuf = psz;
  893. }
  894. pis->pszCharBuf[pis->ichCharBuf++] = (TCHAR)ch;
  895. pis->pszCharBuf[pis->ichCharBuf] = 0;
  896. *lplpstr = pis->pszCharBuf;
  897. return fRestart;
  898. }
  899. // strips out the accelerators. they CAN be the same buffers.
  900. void PASCAL StripAccelerators(LPTSTR lpszFrom, LPTSTR lpszTo, BOOL fAmpOnly)
  901. {
  902. BOOL fRet = FALSE;
  903. while ( *lpszTo = *lpszFrom ) {
  904. #if !defined(UNICODE) // && defined(DBCS)
  905. if (IsDBCSLeadByte(*lpszFrom)) {
  906. (*((WORD FAR*)lpszTo)) = (*((WORD FAR *)lpszFrom));
  907. lpszTo += 2;
  908. lpszFrom += 2;
  909. continue;
  910. }
  911. #endif
  912. if (!fAmpOnly && (g_fDBCSInputEnabled))
  913. {
  914. if (*lpszFrom == TEXT('(') && *(lpszFrom+1)==CH_PREFIX)
  915. {
  916. int i;
  917. LPTSTR psz = lpszFrom+2;
  918. for(i=0; i<2 && *psz;i++, psz=FastCharNext(psz))
  919. ;
  920. if (*psz == '\0') {
  921. *lpszTo = 0;
  922. break;
  923. }
  924. else if (i == 2 && *psz == TEXT(')'))
  925. {
  926. lpszTo--;
  927. lpszFrom = psz+1;
  928. continue;
  929. }
  930. }
  931. }
  932. if (*lpszFrom == TEXT('\t')) {
  933. *lpszTo = TEXT('\0');
  934. break;
  935. }
  936. if ( (*lpszFrom++ != CH_PREFIX) || (*lpszFrom == CH_PREFIX) ) {
  937. lpszTo++;
  938. }
  939. }
  940. }
  941. void ScrollShrinkRect(int x, int y, LPRECT lprc)
  942. {
  943. if (lprc) {
  944. if (x > 0) {
  945. lprc->left += x;
  946. } else {
  947. lprc->right += x;
  948. }
  949. if (y > 0) {
  950. lprc->top += y;
  951. } else {
  952. lprc->bottom += y;
  953. }
  954. }
  955. }
  956. // common control info helpers
  957. void FAR PASCAL CIInitialize(LPCONTROLINFO lpci, HWND hwnd, LPCREATESTRUCT lpcs)
  958. {
  959. lpci->hwnd = hwnd;
  960. lpci->hwndParent = lpcs->hwndParent;
  961. lpci->style = lpcs->style;
  962. lpci->uiCodePage = CP_ACP;
  963. lpci->dwExStyle = lpcs->dwExStyle;
  964. lpci->bUnicode = lpci->hwndParent &&
  965. SendMessage (lpci->hwndParent, WM_NOTIFYFORMAT,
  966. (WPARAM)lpci->hwnd, NF_QUERY) == NFR_UNICODE;
  967. #ifdef KEYBOARDCUES
  968. if (lpci->hwndParent)
  969. {
  970. LRESULT lRes = SendMessage(lpci->hwndParent, WM_QUERYUISTATE, 0, 0);
  971. lpci->wUIState = LOWORD(lRes);
  972. }
  973. #endif
  974. }
  975. LRESULT FAR PASCAL CIHandleNotifyFormat(LPCONTROLINFO lpci, LPARAM lParam)
  976. {
  977. if (lParam == NF_QUERY) {
  978. #ifdef UNICODE
  979. return NFR_UNICODE;
  980. #else
  981. return NFR_ANSI;
  982. #endif
  983. } else if (lParam == NF_REQUERY) {
  984. LRESULT uiResult;
  985. uiResult = SendMessage (lpci->hwndParent, WM_NOTIFYFORMAT,
  986. (WPARAM)lpci->hwnd, NF_QUERY);
  987. lpci->bUnicode = BOOLIFY(uiResult == NFR_UNICODE);
  988. return uiResult;
  989. }
  990. return 0;
  991. }
  992. UINT CCSwapKeys(WPARAM wParam, UINT vk1, UINT vk2)
  993. {
  994. if (wParam == vk1)
  995. return vk2;
  996. if (wParam == vk2)
  997. return vk1;
  998. return (UINT)wParam;
  999. }
  1000. UINT RTLSwapLeftRightArrows(CONTROLINFO *pci, WPARAM wParam)
  1001. {
  1002. if (pci->dwExStyle & RTL_MIRRORED_WINDOW) {
  1003. return CCSwapKeys(wParam, VK_LEFT, VK_RIGHT);
  1004. }
  1005. return (UINT)wParam;
  1006. }
  1007. //
  1008. // New for v5.01:
  1009. //
  1010. // Accessibility (and some other callers, sometimes even us) relies on
  1011. // a XXM_GETITEM call filling the buffer and not just redirecting the
  1012. // pointer. Accessibility is particularly impacted by this because they
  1013. // live outside the process, so the redirected pointer means nothing
  1014. // to them. Here, we copy the result back into the app buffer and return
  1015. // the raw pointer. The caller will return the raw pointer back to the
  1016. // app, so the answer is in two places, either the app buffer, or in
  1017. // the raw pointer.
  1018. //
  1019. // Usage:
  1020. //
  1021. // if (nm.item.mask & LVIF_TEXT)
  1022. // pitem->pszText = CCReturnDispInfoText(nm.item.pszText,
  1023. // pitem->pszText, pitem->cchTextMax);
  1024. //
  1025. LPTSTR CCReturnDispInfoText(LPTSTR pszSrc, LPTSTR pszDest, UINT cchDest)
  1026. {
  1027. // Test pszSrc != pszDest first since the common case is that they
  1028. // are equal.
  1029. if (pszSrc != pszDest && !IsFlagPtr(pszSrc) && !IsFlagPtr(pszDest))
  1030. StrCpyN(pszDest, pszSrc, cchDest);
  1031. return pszSrc;
  1032. }
  1033. #define SUBSCROLLS 100
  1034. #define abs(x) ( ( x > 0 ) ? x : -x)
  1035. #define DEFAULT_MAXSCROLLTIME ((GetDoubleClickTime() / 2) + 1) // Ensure >= 1
  1036. #define DEFAULT_MINSCROLL 8
  1037. int SmoothScrollWindow(PSMOOTHSCROLLINFO psi)
  1038. {
  1039. int dx = psi->dx;
  1040. int dy = psi->dy;
  1041. LPCRECT lprcSrc = psi->lprcSrc;
  1042. LPCRECT lprcClip = psi->lprcClip;
  1043. HRGN hrgnUpdate = psi->hrgnUpdate;
  1044. LPRECT lprcUpdate = psi->lprcUpdate;
  1045. UINT fuScroll = psi->fuScroll;
  1046. int iRet = SIMPLEREGION;
  1047. RECT rcUpdate;
  1048. RECT rcSrc;
  1049. RECT rcClip;
  1050. int xStep;
  1051. int yStep;
  1052. int iSlicesDone = 0;
  1053. int iSlices;
  1054. DWORD dwTimeStart, dwTimeNow;
  1055. HRGN hrgnLocalUpdate;
  1056. UINT cxMinScroll = psi->cxMinScroll;
  1057. UINT cyMinScroll = psi->cyMinScroll;
  1058. UINT uMaxScrollTime = psi->uMaxScrollTime;
  1059. int iSubScrolls;
  1060. PFNSMOOTHSCROLLPROC pfnScrollProc;
  1061. if (!lprcUpdate)
  1062. lprcUpdate = &rcUpdate;
  1063. SetRectEmpty(lprcUpdate);
  1064. if (psi->cbSize != sizeof(SMOOTHSCROLLINFO))
  1065. return 0;
  1066. // check the defaults
  1067. if (!(psi->fMask & SSIF_MINSCROLL )
  1068. || cxMinScroll == SSI_DEFAULT)
  1069. cxMinScroll = DEFAULT_MINSCROLL;
  1070. if (!(psi->fMask & SSIF_MINSCROLL)
  1071. || cyMinScroll == SSI_DEFAULT)
  1072. cyMinScroll = DEFAULT_MINSCROLL;
  1073. if (!(psi->fMask & SSIF_MAXSCROLLTIME)
  1074. || uMaxScrollTime == SSI_DEFAULT)
  1075. uMaxScrollTime = DEFAULT_MAXSCROLLTIME;
  1076. if (uMaxScrollTime < SUBSCROLLS)
  1077. uMaxScrollTime = SUBSCROLLS;
  1078. if ((!(fuScroll & SSW_EX_IGNORESETTINGS)) &&
  1079. (!g_fSmoothScroll)) {
  1080. fuScroll |= SSW_EX_IMMEDIATE;
  1081. }
  1082. if ((psi->fMask & SSIF_SCROLLPROC) && psi->pfnScrollProc) {
  1083. pfnScrollProc = psi->pfnScrollProc;
  1084. } else {
  1085. pfnScrollProc = ScrollWindowEx;
  1086. }
  1087. #ifdef ScrollWindowEx
  1088. #undef ScrollWindowEx
  1089. #endif
  1090. if (fuScroll & SSW_EX_IMMEDIATE) {
  1091. return pfnScrollProc(psi->hwnd, dx, dy, lprcSrc, lprcClip, hrgnUpdate,
  1092. lprcUpdate, LOWORD(fuScroll));
  1093. }
  1094. // copy input rects locally
  1095. if (lprcSrc) {
  1096. rcSrc = *lprcSrc;
  1097. lprcSrc = &rcSrc;
  1098. }
  1099. if (lprcClip) {
  1100. rcClip = *lprcClip;
  1101. lprcClip = &rcClip;
  1102. }
  1103. if (!hrgnUpdate)
  1104. hrgnLocalUpdate = CreateRectRgn(0,0,0,0);
  1105. else
  1106. hrgnLocalUpdate = hrgnUpdate;
  1107. //set up initial vars
  1108. dwTimeStart = GetTickCount();
  1109. if (fuScroll & SSW_EX_NOTIMELIMIT) {
  1110. xStep = cxMinScroll * (dx < 0 ? -1 : 1);
  1111. yStep = cyMinScroll * (dy < 0 ? -1 : 1);
  1112. } else {
  1113. iSubScrolls = (uMaxScrollTime / DEFAULT_MAXSCROLLTIME) * SUBSCROLLS;
  1114. if (!iSubScrolls)
  1115. iSubScrolls = SUBSCROLLS;
  1116. xStep = dx / iSubScrolls;
  1117. yStep = dy / iSubScrolls;
  1118. }
  1119. if (xStep == 0 && dx)
  1120. xStep = dx < 0 ? -1 : 1;
  1121. if (yStep == 0 && dy)
  1122. yStep = dy < 0 ? -1 : 1;
  1123. while (dx || dy) {
  1124. int x,y;
  1125. RECT rcTempUpdate;
  1126. if (fuScroll & SSW_EX_NOTIMELIMIT) {
  1127. x = xStep;
  1128. y = yStep;
  1129. if (abs(x) > abs(dx))
  1130. x = dx;
  1131. if (abs(y) > abs(dy))
  1132. y = dy;
  1133. } else {
  1134. int iTimePerScroll = uMaxScrollTime / iSubScrolls;
  1135. if (!iTimePerScroll)
  1136. iTimePerScroll = 1;
  1137. dwTimeNow = GetTickCount();
  1138. iSlices = ((dwTimeNow - dwTimeStart) / iTimePerScroll) - iSlicesDone;
  1139. if (iSlices < 0)
  1140. iSlices = 0;
  1141. do {
  1142. int iRet = 0;
  1143. iSlices++;
  1144. if ((iSlicesDone + iSlices) <= iSubScrolls) {
  1145. x = xStep * iSlices;
  1146. y = yStep * iSlices;
  1147. // this could go over if we rounded ?Step up to 1(-1) above
  1148. if (abs(x) > abs(dx))
  1149. x = dx;
  1150. if (abs(y) > abs(dy))
  1151. y = dy;
  1152. } else {
  1153. x = dx;
  1154. y = dy;
  1155. }
  1156. //DebugMsg(DM_TRACE, "SmoothScrollWindowCallback %d", iRet);
  1157. if (x == dx && y == dy)
  1158. break;
  1159. if ((((UINT)(abs(x)) >= cxMinScroll) || !x) &&
  1160. (((UINT)(abs(y)) >= cyMinScroll) || !y))
  1161. break;
  1162. } while (1);
  1163. }
  1164. if (pfnScrollProc(psi->hwnd, x, y, lprcSrc, lprcClip, hrgnLocalUpdate, &rcTempUpdate, LOWORD(fuScroll)) == ERROR) {
  1165. iRet = ERROR;
  1166. goto Bail;
  1167. }
  1168. // we don't need to do this always because if iSlices >= iSlicesDone, we'll have scrolled blanks
  1169. //if (iSlices < iSlicesDone)
  1170. RedrawWindow(psi->hwnd, NULL, hrgnLocalUpdate, RDW_ERASE | RDW_ERASENOW | RDW_INVALIDATE);
  1171. UnionRect(lprcUpdate, &rcTempUpdate, lprcUpdate);
  1172. ScrollShrinkRect(x,y, (LPRECT)lprcSrc);
  1173. ScrollShrinkRect(x,y, (LPRECT)lprcClip);
  1174. dx -= x;
  1175. dy -= y;
  1176. iSlicesDone += iSlices;
  1177. }
  1178. Bail:
  1179. if (fuScroll & SW_SCROLLCHILDREN) {
  1180. RedrawWindow(psi->hwnd, lprcUpdate, NULL, RDW_INVALIDATE);
  1181. }
  1182. if (hrgnLocalUpdate != hrgnUpdate)
  1183. DeleteObject(hrgnLocalUpdate);
  1184. return iRet;
  1185. }
  1186. typedef BOOL (WINAPI *PLAYSOUNDFN)(LPCTSTR lpsz, HANDLE hMod, DWORD dwFlags);
  1187. typedef UINT (WINAPI *UINTVOIDFN)();
  1188. TCHAR const c_szWinMMDll[] = TEXT("winmm.dll");
  1189. #ifdef UNICODE
  1190. char const c_szPlaySound[] = "PlaySoundW";
  1191. #else
  1192. char const c_szPlaySound[] = "PlaySoundA";
  1193. #endif
  1194. char const c_szwaveOutGetNumDevs[] = "waveOutGetNumDevs";
  1195. extern TCHAR const c_szExplorer[];
  1196. #define CCH_KEYMAX 256
  1197. BOOL g_fNeverPlaySound = FALSE;
  1198. void CCPlaySound(LPCTSTR lpszName)
  1199. {
  1200. TCHAR szFileName[MAX_PATH];
  1201. LONG cbSize = SIZEOF(szFileName);
  1202. TCHAR szKey[CCH_KEYMAX];
  1203. if (g_fNeverPlaySound)
  1204. return;
  1205. // check the registry first
  1206. // if there's nothing registered, we blow off the play,
  1207. // but we don't set the MM_DONTLOAD flag so taht if they register
  1208. // something we will play it
  1209. wsprintf(szKey, TEXT("AppEvents\\Schemes\\Apps\\.Default\\%s\\.current"), lpszName);
  1210. if ((RegQueryValue(HKEY_CURRENT_USER, szKey, szFileName, &cbSize) == ERROR_SUCCESS) &&
  1211. (cbSize > SIZEOF(szFileName[0]))) {
  1212. PLAYSOUNDFN pfnPlaySound;
  1213. UINTVOIDFN pfnwaveOutGetNumDevs;
  1214. HANDLE hMM;
  1215. hMM = GetModuleHandle(c_szWinMMDll);
  1216. if (!hMM)
  1217. hMM = LoadLibrary(c_szWinMMDll);
  1218. if (!hMM)
  1219. return;
  1220. /// are there any devices?
  1221. pfnwaveOutGetNumDevs = (UINTVOIDFN)GetProcAddress(hMM, c_szwaveOutGetNumDevs);
  1222. pfnPlaySound = (PLAYSOUNDFN)GetProcAddress(hMM, c_szPlaySound);
  1223. if (!pfnPlaySound || !pfnwaveOutGetNumDevs || !pfnwaveOutGetNumDevs()) {
  1224. g_fNeverPlaySound = TRUE;
  1225. return;
  1226. }
  1227. pfnPlaySound(szFileName, NULL, SND_FILENAME | SND_ASYNC);
  1228. }
  1229. }
  1230. BOOL CCForwardEraseBackground(HWND hwnd, HDC hdc)
  1231. {
  1232. HWND hwndParent = GetParent(hwnd);
  1233. LRESULT lres = 0;
  1234. if (hwndParent)
  1235. {
  1236. // Adjust the origin so the parent paints in the right place
  1237. POINT pt = {0,0};
  1238. MapWindowPoints(hwnd, hwndParent, &pt, 1);
  1239. OffsetWindowOrgEx(hdc,
  1240. pt.x,
  1241. pt.y,
  1242. &pt);
  1243. lres = SendMessage(hwndParent, WM_ERASEBKGND, (WPARAM) hdc, 0L);
  1244. SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
  1245. }
  1246. return(lres != 0);
  1247. }
  1248. HFONT CCGetHotFont(HFONT hFont, HFONT *phFontHot)
  1249. {
  1250. if (!*phFontHot) {
  1251. LOGFONT lf;
  1252. // create the underline font
  1253. GetObject(hFont, sizeof(lf), &lf);
  1254. #ifndef DONT_UNDERLINE
  1255. lf.lfUnderline = TRUE;
  1256. #endif
  1257. *phFontHot = CreateFontIndirect(&lf);
  1258. }
  1259. return *phFontHot;
  1260. }
  1261. HFONT CCCreateStatusFont(void)
  1262. {
  1263. NONCLIENTMETRICS ncm;
  1264. ncm.cbSize = sizeof(NONCLIENTMETRICS);
  1265. SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
  1266. return CreateFontIndirect(&ncm.lfStatusFont);
  1267. }
  1268. void* CCLocalReAlloc(void* p, UINT uBytes)
  1269. {
  1270. if (uBytes) {
  1271. if (p) {
  1272. return LocalReAlloc(p, uBytes, LMEM_MOVEABLE | LMEM_ZEROINIT);
  1273. } else {
  1274. return LocalAlloc(LPTR, uBytes);
  1275. }
  1276. } else {
  1277. if (p)
  1278. LocalFree(p);
  1279. return NULL;
  1280. }
  1281. }
  1282. /*----------------------------------------------------------
  1283. Purpose: This function provides the commctrl version info. This
  1284. allows the caller to distinguish running NT SUR vs.
  1285. Win95 shell vs. Nashville, etc.
  1286. This API was not supplied in Win95 or NT SUR, so
  1287. the caller must GetProcAddress it. If this fails,
  1288. the caller is running on Win95 or NT SUR.
  1289. Returns: NO_ERROR
  1290. ERROR_INVALID_PARAMETER if pinfo is invalid
  1291. Cond: --
  1292. */
  1293. // All we have to do is declare this puppy and CCDllGetVersion does the rest
  1294. // Note that we use VER_FILEVERSION_DW because comctl32 uses a funky
  1295. // version scheme
  1296. DLLVER_DUALBINARY(VER_FILEVERSION_DW, VER_PRODUCTBUILD_QFE);
  1297. //
  1298. // Translate the given font to a code page used for thunking text
  1299. //
  1300. UINT GetCodePageForFont (HFONT hFont)
  1301. {
  1302. #ifdef WINNT
  1303. LOGFONT lf;
  1304. TCHAR szFontName[MAX_PATH];
  1305. CHARSETINFO csi;
  1306. DWORD dwSize, dwType;
  1307. HKEY hKey;
  1308. if (!GetObject (hFont, sizeof(lf), &lf)) {
  1309. return CP_ACP;
  1310. }
  1311. //
  1312. // Check for font substitutes
  1313. //
  1314. lstrcpy (szFontName, lf.lfFaceName);
  1315. if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  1316. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes"),
  1317. 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
  1318. dwSize = MAX_PATH * sizeof(TCHAR);
  1319. RegQueryValueEx (hKey, lf.lfFaceName, NULL, &dwType,
  1320. (LPBYTE) szFontName, &dwSize);
  1321. RegCloseKey (hKey);
  1322. }
  1323. //
  1324. // This is to fix office for locales that use non 1252 versions
  1325. // of Ms Sans Serif and Ms Serif. These fonts incorrectly identify
  1326. // themselves as having an Ansi charset, so TranslateCharsetInfo will
  1327. // return the wrong value.
  1328. //
  1329. // NT bug 260697: Office 2000 uses Tahoma.
  1330. //
  1331. if ((lf.lfCharSet == ANSI_CHARSET) &&
  1332. (!lstrcmpi(L"Helv", szFontName) ||
  1333. !lstrcmpi(L"Ms Sans Serif", szFontName) ||
  1334. !lstrcmpi(L"Ms Serif", szFontName) ||
  1335. !lstrcmpi(L"Tahoma", szFontName)))
  1336. {
  1337. return CP_ACP;
  1338. }
  1339. //
  1340. // This is to fix FE office95a and Pro. msofe95.dll sets wrong charset when create
  1341. // listview control. so TranslateCharsetInfo will return the wrong value.
  1342. // Korea : DotumChe.
  1343. // Taiwan : New MingLight
  1344. // China : SongTi
  1345. if ((lf.lfCharSet == SHIFTJIS_CHARSET) &&
  1346. (!lstrcmpi(L"\xb3cb\xc6c0\xccb4", lf.lfFaceName)) || // Korea
  1347. (!lstrcmpi(L"\x65b0\x7d30\x660e\x9ad4", lf.lfFaceName)) || // Taiwan
  1348. (!lstrcmpi(L"\x5b8b\x4f53", lf.lfFaceName))) // PRC
  1349. {
  1350. return CP_ACP;
  1351. }
  1352. if (!TranslateCharsetInfo((DWORD FAR *) lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
  1353. return CP_ACP;
  1354. }
  1355. return csi.ciACP;
  1356. #else
  1357. return CP_ACP;
  1358. #endif
  1359. }
  1360. typedef void (CALLBACK* NOTIFYWINEVENTPROC)(UINT, HWND, LONG, LONG_PTR);
  1361. #define DONOTHING_NOTIFYWINEVENT ((NOTIFYWINEVENTPROC)1)
  1362. // --------------------------------------------------------------------------
  1363. //
  1364. // MyNotifyWinEvent()
  1365. //
  1366. // This tries to get the proc address of NotifyWinEvent(). If it fails, we
  1367. // remember that and do nothing.
  1368. //
  1369. // NOTE TO NT FOLKS:
  1370. // Don't worry about this code. It will do nothing on NT, nothing yet
  1371. // that is. Active Accessibility will be ported to NT for Service Pack #1
  1372. // or at worst #2 after NT SUR ships, this code will work magically when
  1373. // that is done/
  1374. //
  1375. // --------------------------------------------------------------------------
  1376. void MyNotifyWinEvent(UINT event, HWND hwnd, LONG idContainer, LONG_PTR idChild)
  1377. {
  1378. static NOTIFYWINEVENTPROC s_pfnNotifyWinEvent = NULL;
  1379. if (!s_pfnNotifyWinEvent)
  1380. {
  1381. HMODULE hmod;
  1382. if (hmod = GetModuleHandle(TEXT("USER32")))
  1383. s_pfnNotifyWinEvent = (NOTIFYWINEVENTPROC)GetProcAddress(hmod,
  1384. "NotifyWinEvent");
  1385. if (!s_pfnNotifyWinEvent)
  1386. s_pfnNotifyWinEvent = DONOTHING_NOTIFYWINEVENT;
  1387. }
  1388. if (s_pfnNotifyWinEvent != DONOTHING_NOTIFYWINEVENT)
  1389. (* s_pfnNotifyWinEvent)(event, hwnd, idContainer, idChild);
  1390. }
  1391. LONG GetMessagePosClient(HWND hwnd, LPPOINT ppt)
  1392. {
  1393. LPARAM lParam;
  1394. POINT pt;
  1395. if (!ppt)
  1396. ppt = &pt;
  1397. lParam = GetMessagePos();
  1398. ppt->x = GET_X_LPARAM(lParam);
  1399. ppt->y = GET_Y_LPARAM(lParam);
  1400. ScreenToClient(hwnd, ppt);
  1401. return MAKELONG(ppt->x, ppt->y);
  1402. }
  1403. LPTSTR StrDup(LPCTSTR lpsz)
  1404. {
  1405. LPTSTR lpszRet = (LPTSTR)LocalAlloc(LPTR, (lstrlen(lpsz) + 1) * sizeof(TCHAR));
  1406. if (lpszRet) {
  1407. lstrcpy(lpszRet, lpsz);
  1408. }
  1409. return lpszRet;
  1410. }
  1411. #ifdef UNICODE
  1412. LPSTR StrDupA(LPCSTR lpsz)
  1413. {
  1414. LPSTR lpszRet = (LPSTR)LocalAlloc(LPTR, (lstrlenA(lpsz) + 1) * sizeof(CHAR));
  1415. if (lpszRet) {
  1416. lstrcpyA(lpszRet, lpsz);
  1417. }
  1418. return lpszRet;
  1419. }
  1420. #endif
  1421. HWND GetDlgItemRect(HWND hDlg, int nIDItem, LPRECT prc) //relative to hDlg
  1422. {
  1423. HWND hCtrl = NULL;
  1424. if (prc)
  1425. {
  1426. hCtrl = GetDlgItem(hDlg, nIDItem);
  1427. if (hCtrl)
  1428. {
  1429. GetWindowRect(hCtrl, prc);
  1430. MapWindowRect(NULL, hDlg, prc);
  1431. }
  1432. else
  1433. SetRectEmpty(prc);
  1434. }
  1435. return hCtrl;
  1436. }
  1437. /*----------------------------------------------------------
  1438. Purpose: Calls the ADVPACK entry-point which executes an inf
  1439. file section.
  1440. */
  1441. HRESULT CallRegInstall(LPSTR szSection)
  1442. {
  1443. HRESULT hr = E_FAIL;
  1444. HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL"));
  1445. if (hinstAdvPack)
  1446. {
  1447. REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, "RegInstall");
  1448. if (pfnri)
  1449. {
  1450. hr = pfnri(g_hinst, szSection, NULL);
  1451. }
  1452. FreeLibrary(hinstAdvPack);
  1453. }
  1454. return hr;
  1455. }
  1456. /*----------------------------------------------------------
  1457. Purpose: Install/uninstall user settings
  1458. */
  1459. STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine)
  1460. {
  1461. #ifdef DEBUG
  1462. if (IsFlagSet(g_dwBreakFlags, BF_ONAPIENTER))
  1463. {
  1464. TraceMsg(TF_ALWAYS, "Stopping in DllInstall");
  1465. DEBUG_BREAK;
  1466. }
  1467. #endif
  1468. if (bInstall)
  1469. {
  1470. // Delete any old registration entries, then add the new ones.
  1471. // Keep ADVPACK.DLL loaded across multiple calls to RegInstall.
  1472. // (The inf engine doesn't guarantee DelReg/AddReg order, that's
  1473. // why we explicitly unreg and reg here.)
  1474. //
  1475. CallRegInstall("RegDll");
  1476. }
  1477. else
  1478. {
  1479. CallRegInstall("UnregDll");
  1480. }
  1481. return S_OK;
  1482. }
  1483. //---------------------------------------------------------------------------------------
  1484. void FAR PASCAL FlipRect(LPRECT prc)
  1485. {
  1486. SWAP(prc->left, prc->top, int);
  1487. SWAP(prc->right, prc->bottom, int);
  1488. }
  1489. //---------------------------------------------------------------------------------------
  1490. //
  1491. // Returns previous window bits.
  1492. DWORD SetWindowBits(HWND hWnd, int iWhich, DWORD dwBits, DWORD dwValue)
  1493. {
  1494. DWORD dwStyle;
  1495. DWORD dwNewStyle;
  1496. dwStyle = GetWindowLong(hWnd, iWhich);
  1497. dwNewStyle = ( dwStyle & ~dwBits ) | (dwValue & dwBits);
  1498. if (dwStyle != dwNewStyle) {
  1499. dwStyle = SetWindowLong(hWnd, iWhich, dwNewStyle);
  1500. }
  1501. return dwStyle;
  1502. }
  1503. //---------------------------------------------------------------------------------------
  1504. BOOL CCDrawEdge(HDC hdc, LPRECT lprc, UINT edge, UINT flags, LPCOLORSCHEME lpclrsc)
  1505. {
  1506. RECT rc, rcD;
  1507. UINT bdrType;
  1508. COLORREF clrTL, clrBR;
  1509. //
  1510. // Enforce monochromicity and flatness
  1511. //
  1512. // if (oemInfo.BitCount == 1)
  1513. // flags |= BF_MONO;
  1514. if (flags & BF_MONO)
  1515. flags |= BF_FLAT;
  1516. CopyRect(&rc, lprc);
  1517. //
  1518. // Draw the border segment(s), and calculate the remaining space as we
  1519. // go.
  1520. //
  1521. if (bdrType = (edge & BDR_OUTER))
  1522. {
  1523. DrawBorder:
  1524. //
  1525. // Get colors. Note the symmetry between raised outer, sunken inner and
  1526. // sunken outer, raised inner.
  1527. //
  1528. if (flags & BF_FLAT)
  1529. {
  1530. if (flags & BF_MONO)
  1531. clrBR = (bdrType & BDR_OUTER) ? g_clrWindowFrame : g_clrWindow;
  1532. else
  1533. clrBR = (bdrType & BDR_OUTER) ? g_clrBtnShadow: g_clrBtnFace;
  1534. clrTL = clrBR;
  1535. }
  1536. else
  1537. {
  1538. // 5 == HILIGHT
  1539. // 4 == LIGHT
  1540. // 3 == FACE
  1541. // 2 == SHADOW
  1542. // 1 == DKSHADOW
  1543. switch (bdrType)
  1544. {
  1545. // +2 above surface
  1546. case BDR_RAISEDOUTER: // 5 : 4
  1547. clrTL = ((flags & BF_SOFT) ? g_clrBtnHighlight : g_clr3DLight);
  1548. clrBR = g_clr3DDkShadow; // 1
  1549. if (lpclrsc) {
  1550. if (lpclrsc->clrBtnHighlight != CLR_DEFAULT)
  1551. clrTL = lpclrsc->clrBtnHighlight;
  1552. if (lpclrsc->clrBtnShadow != CLR_DEFAULT)
  1553. clrBR = lpclrsc->clrBtnShadow;
  1554. }
  1555. break;
  1556. // +1 above surface
  1557. case BDR_RAISEDINNER: // 4 : 5
  1558. clrTL = ((flags & BF_SOFT) ? g_clr3DLight : g_clrBtnHighlight);
  1559. clrBR = g_clrBtnShadow; // 2
  1560. if (lpclrsc) {
  1561. if (lpclrsc->clrBtnHighlight != CLR_DEFAULT)
  1562. clrTL = lpclrsc->clrBtnHighlight;
  1563. if (lpclrsc->clrBtnShadow != CLR_DEFAULT)
  1564. clrBR = lpclrsc->clrBtnShadow;
  1565. }
  1566. break;
  1567. // -1 below surface
  1568. case BDR_SUNKENOUTER: // 1 : 2
  1569. clrTL = ((flags & BF_SOFT) ? g_clr3DDkShadow : g_clrBtnShadow);
  1570. clrBR = g_clrBtnHighlight; // 5
  1571. if (lpclrsc) {
  1572. if (lpclrsc->clrBtnShadow != CLR_DEFAULT)
  1573. clrTL = lpclrsc->clrBtnShadow;
  1574. if (lpclrsc->clrBtnHighlight != CLR_DEFAULT)
  1575. clrBR = lpclrsc->clrBtnHighlight;
  1576. }
  1577. break;
  1578. // -2 below surface
  1579. case BDR_SUNKENINNER: // 2 : 1
  1580. clrTL = ((flags & BF_SOFT) ? g_clrBtnShadow : g_clr3DDkShadow);
  1581. clrBR = g_clr3DLight; // 4
  1582. if (lpclrsc) {
  1583. if (lpclrsc->clrBtnShadow != CLR_DEFAULT)
  1584. clrTL = lpclrsc->clrBtnShadow;
  1585. if (lpclrsc->clrBtnHighlight != CLR_DEFAULT)
  1586. clrBR = lpclrsc->clrBtnHighlight;
  1587. }
  1588. break;
  1589. default:
  1590. return(FALSE);
  1591. }
  1592. }
  1593. //
  1594. // Draw the sides of the border. NOTE THAT THE ALGORITHM FAVORS THE
  1595. // BOTTOM AND RIGHT SIDES, since the light source is assumed to be top
  1596. // left. If we ever decide to let the user set the light source to a
  1597. // particular corner, then change this algorithm.
  1598. //
  1599. // Bottom Right edges
  1600. if (flags & (BF_RIGHT | BF_BOTTOM))
  1601. {
  1602. // Right
  1603. if (flags & BF_RIGHT)
  1604. {
  1605. rc.right -= g_cxBorder;
  1606. // PatBlt(hdc, rc.right, rc.top, g_cxBorder, rc.bottom - rc.top, PATCOPY);
  1607. rcD.left = rc.right;
  1608. rcD.right = rc.right + g_cxBorder;
  1609. rcD.top = rc.top;
  1610. rcD.bottom = rc.bottom;
  1611. FillRectClr(hdc, &rcD, clrBR);
  1612. }
  1613. // Bottom
  1614. if (flags & BF_BOTTOM)
  1615. {
  1616. rc.bottom -= g_cyBorder;
  1617. // PatBlt(hdc, rc.left, rc.bottom, rc.right - rc.left, g_cyBorder, PATCOPY);
  1618. rcD.left = rc.left;
  1619. rcD.right = rc.right;
  1620. rcD.top = rc.bottom;
  1621. rcD.bottom = rc.bottom + g_cyBorder;
  1622. FillRectClr(hdc, &rcD, clrBR);
  1623. }
  1624. }
  1625. // Top Left edges
  1626. if (flags & (BF_TOP | BF_LEFT))
  1627. {
  1628. // Left
  1629. if (flags & BF_LEFT)
  1630. {
  1631. // PatBlt(hdc, rc.left, rc.top, g_cxBorder, rc.bottom - rc.top, PATCOPY);
  1632. rc.left += g_cxBorder;
  1633. rcD.left = rc.left - g_cxBorder;
  1634. rcD.right = rc.left;
  1635. rcD.top = rc.top;
  1636. rcD.bottom = rc.bottom;
  1637. FillRectClr(hdc, &rcD, clrTL);
  1638. }
  1639. // Top
  1640. if (flags & BF_TOP)
  1641. {
  1642. // PatBlt(hdc, rc.left, rc.top, rc.right - rc.left, g_cyBorder, PATCOPY);
  1643. rc.top += g_cyBorder;
  1644. rcD.left = rc.left;
  1645. rcD.right = rc.right;
  1646. rcD.top = rc.top - g_cyBorder;
  1647. rcD.bottom = rc.top;
  1648. FillRectClr(hdc, &rcD, clrTL);
  1649. }
  1650. }
  1651. }
  1652. if (bdrType = (edge & BDR_INNER))
  1653. {
  1654. //
  1655. // Strip this so the next time through, bdrType will be 0.
  1656. // Otherwise, we'll loop forever.
  1657. //
  1658. edge &= ~BDR_INNER;
  1659. goto DrawBorder;
  1660. }
  1661. //
  1662. // Fill the middle & clean up if asked
  1663. //
  1664. if (flags & BF_MIDDLE)
  1665. FillRectClr(hdc, &rc, (flags & BF_MONO) ? g_clrWindow : g_clrBtnFace);
  1666. if (flags & BF_ADJUST)
  1667. CopyRect(lprc, &rc);
  1668. return(TRUE);
  1669. }
  1670. //---------------------------------------------------------------------------------------
  1671. //CCInvalidateFrame -- SWP_FRAMECHANGED, w/o all the extra params
  1672. //
  1673. void CCInvalidateFrame(HWND hwnd)
  1674. {
  1675. SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
  1676. return;
  1677. }
  1678. //---------------------------------------------------------------------------------------
  1679. // FlipPoint - flip the x and y coordinates of a point
  1680. //
  1681. void FlipPoint(LPPOINT lppt)
  1682. {
  1683. SWAP(lppt->x, lppt->y, int);
  1684. }
  1685. //
  1686. // When we want to turn a tooltip into an infotip, we set its
  1687. // width to 300 "small pixels", where there are 72 small pixels
  1688. // per inch when you are in small fonts mode.
  1689. //
  1690. // Scale this value based on the magnification in effect
  1691. // on the owner's monitor. But never let the tooltip get
  1692. // bigger than 3/4 of the screen.
  1693. //
  1694. void CCSetInfoTipWidth(HWND hwndOwner, HWND hwndToolTips)
  1695. {
  1696. HDC hdc = GetDC(hwndOwner);
  1697. int iWidth = MulDiv(GetDeviceCaps(hdc, LOGPIXELSX), 300, 72);
  1698. int iMaxWidth = GetDeviceCaps(hdc, HORZRES) * 3 / 4;
  1699. SendMessage(hwndToolTips, TTM_SETMAXTIPWIDTH, 0, min(iWidth, iMaxWidth));
  1700. ReleaseDC(hwndOwner, hdc);
  1701. }
  1702. // Mirror a bitmap in a DC (mainly a text object in a DC)
  1703. //
  1704. // [samera]
  1705. //
  1706. void MirrorBitmapInDC( HDC hdc , HBITMAP hbmOrig )
  1707. {
  1708. HDC hdcMem;
  1709. HBITMAP hbm;
  1710. BITMAP bm;
  1711. if( !GetObject( hbmOrig , sizeof(BITMAP) , &bm ))
  1712. return;
  1713. hdcMem = CreateCompatibleDC( hdc );
  1714. if( !hdcMem )
  1715. return;
  1716. hbm = CreateCompatibleBitmap( hdc , bm.bmWidth , bm.bmHeight );
  1717. if( !hbm )
  1718. {
  1719. DeleteDC( hdcMem );
  1720. return;
  1721. }
  1722. //
  1723. // Flip the bitmap
  1724. //
  1725. SelectObject( hdcMem , hbm );
  1726. SET_DC_RTL_MIRRORED(hdcMem);
  1727. BitBlt( hdcMem , 0 , 0 , bm.bmWidth , bm.bmHeight ,
  1728. hdc , 0 , 0 , SRCCOPY );
  1729. SET_DC_LAYOUT(hdcMem,0);
  1730. //
  1731. // BUGBUG : The offset by 1 is to solve the off-by-one (in hdcMem) problem. Solved.
  1732. // [samera]
  1733. //
  1734. BitBlt( hdc , 0 , 0 , bm.bmWidth , bm.bmHeight ,
  1735. hdcMem , 0 , 0 , SRCCOPY );
  1736. DeleteDC( hdcMem );
  1737. DeleteObject( hbm );
  1738. return;
  1739. }
  1740. // returns TRUE if handled
  1741. BOOL CCWndProc(CONTROLINFO* pci, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
  1742. {
  1743. if (uMsg >= CCM_FIRST && uMsg < CCM_LAST) {
  1744. LRESULT lres = 0;
  1745. switch (uMsg) {
  1746. case CCM_SETUNICODEFORMAT:
  1747. lres = pci->bUnicode;
  1748. pci->bUnicode = BOOLFROMPTR(wParam);
  1749. break;
  1750. case CCM_GETUNICODEFORMAT:
  1751. lres = pci->bUnicode;
  1752. break;
  1753. case CCM_SETVERSION:
  1754. if (wParam <= COMCTL32_VERSION) {
  1755. lres = pci->iVersion;
  1756. pci->iVersion = (int)wParam;
  1757. } else
  1758. lres = -1;
  1759. break;
  1760. case CCM_GETVERSION:
  1761. lres = pci->iVersion;
  1762. break;
  1763. }
  1764. ASSERT(plres);
  1765. *plres = lres;
  1766. return TRUE;
  1767. }
  1768. return FALSE;
  1769. }
  1770. #ifdef KEYBOARDCUES
  1771. // The return value tells if the state changed or not (TRUE == change)
  1772. BOOL NEAR PASCAL CCOnUIState(LPCONTROLINFO pControlInfo,
  1773. UINT uMessage, WPARAM wParam, LPARAM lParam)
  1774. {
  1775. WORD wOldUIState = pControlInfo->wUIState;
  1776. // That's the only message we handle
  1777. if (WM_UPDATEUISTATE == uMessage)
  1778. {
  1779. switch (LOWORD(wParam))
  1780. {
  1781. case UIS_SET:
  1782. pControlInfo->wUIState |= HIWORD(wParam);
  1783. break;
  1784. case UIS_CLEAR:
  1785. pControlInfo->wUIState &= ~(HIWORD(wParam));
  1786. break;
  1787. }
  1788. }
  1789. // These message always need to be passed to DefWindowProc
  1790. return (wOldUIState != pControlInfo->wUIState);
  1791. }
  1792. BOOL CCNotifyNavigationKeyUsage(LPCONTROLINFO pControlInfo, WORD wFlag)
  1793. {
  1794. BOOL fRet = FALSE;
  1795. // do something only if not already in keyboard mode
  1796. if ((CCGetUIState(pControlInfo) & (UISF_HIDEFOCUS | UISF_HIDEACCEL)) != wFlag)
  1797. {
  1798. SendMessage(pControlInfo->hwndParent, WM_CHANGEUISTATE,
  1799. MAKELONG(UIS_CLEAR, wFlag), 0);
  1800. pControlInfo->wUIState &= ~(HIWORD(wFlag));
  1801. // we did the notify
  1802. fRet = TRUE;
  1803. }
  1804. return fRet;
  1805. }
  1806. BOOL CCGetUIState(LPCONTROLINFO pControlInfo)
  1807. {
  1808. return pControlInfo->wUIState;
  1809. }
  1810. #endif
  1811. LONG g_dwWindowCount = 0;
  1812. void CCCreateWindow()
  1813. {
  1814. if (InterlockedIncrement(&g_dwWindowCount) == 1)
  1815. {
  1816. // If the count goes to one, Refresh the global metrics
  1817. InitGlobalColors();
  1818. InitGlobalMetrics(0);
  1819. }
  1820. }
  1821. void CCDestroyWindow()
  1822. {
  1823. InterlockedDecrement(&g_dwWindowCount);
  1824. }