CLOCK.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:43k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples. 
  3. *       Copyright (C) 1993-1997 Microsoft Corporation.
  4. *       All rights reserved. 
  5. *       This source code is only intended as a supplement to 
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the 
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. /*
  11.  *  CLOCK.C - Windows DDEML Clock
  12.  *
  13.  *  DDE Transactions:
  14.  *  ----------------
  15.  *  Service: Clock
  16.  *  Topic  : Time
  17.  *  Item   : Now
  18.  *
  19.  *  Use Request or Advise to get the time or use Poke to change the time.
  20.  *  Time Format Hour:Minute:Seconds where
  21.  *   Hour    = 0-23
  22.  *   Minute  = 0-59
  23.  *   Seconds = 0-59
  24.  */
  25. #include <time.h>
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include "windows.h"
  30. #include <ddeml.h>
  31. #include "clock.h"
  32. DWORD   idInst = 0;
  33. CLOCKDISPSTRUCT ClockDisp;
  34. HANDLE  hInst;
  35. HWND    hWindow;
  36. HBRUSH  hbrBackground;
  37. HBRUSH  hbrColorWindow;
  38. HBRUSH  hbrColorBlack;
  39. HBRUSH  hbrForeground;
  40. HFONT   hFont;
  41. HPEN    hpenForeground;
  42. HPEN    hpenBackground;
  43. INT     nLeadZero   = 0;
  44. INT     TimerID     = 1;    /* number used for timer-id */
  45. INT     clockRadius;
  46. INT     HorzRes;
  47. INT     VertRes;
  48. LONG    aspectD;
  49. LONG    aspectN;
  50. CHAR    szBuffer[BUFLEN];    /* buffer for stringtable stuff */
  51. CHAR    szFontFile[20];
  52. CHAR    szIniFile[20];
  53. CHAR    szSection[30];
  54. POINT   clockCenter;
  55. TIME    oTime;
  56. RECT    clockRect;
  57. RECT    rCoordRect;
  58. HDDEDATA CALLBACK DdeCallback(WORD usType, WORD usFmt, HCONV hConv, HSZ hsz1,
  59.         HSZ hsz2, HDDEDATA hData, DWORD lData1, DWORD lData2);
  60. HSZ hszTime, hszNow, hszClock;    /* Hszs for DDEML use */
  61. /*
  62.  *  Function Prototypes
  63.  */
  64. LONG APIENTRY ClockWndProc(register HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
  65. void NEAR PASCAL ClockCreate(HWND hWnd);
  66. BOOL NEAR PASCAL ClockInit(HANDLE hInstance);
  67. void NEAR PASCAL ClockPaint(HWND hWnd, register HDC hDC, INT hint);
  68. void NEAR PASCAL ClockSize(register HWND hWnd,INT newWidth,INT newHeight, WORD SizeWord);
  69. void NEAR PASCAL ClockTimer(HWND hWnd, UINT msg);
  70. void NEAR PASCAL CompClockDim(void);
  71. void NEAR PASCAL CreateTools(void);
  72. void NEAR PASCAL DeleteTools(void);
  73. void NEAR PASCAL DrawBorder(HWND hWnd, register HDC hDC);
  74. void NEAR PASCAL DrawFace(HDC hDC);
  75. void NEAR PASCAL DrawHand(register HDC hDC, INT pos, HPEN hPen, INT scale, INT patMode);
  76. void NEAR PASCAL DrawFatHand(register HDC hDC, INT pos, HPEN hPen, BOOL hHand);
  77. void NEAR PASCAL FormatInit(register HANDLE hInstance, BOOL fModeChange);
  78. void NEAR PASCAL SizeFont(HWND hWnd, INT newHeight, INT newWidth, INT wlen);
  79. void NEAR PASCAL SetMenuBar( HWND hWnd );
  80. /*
  81.  *  CreateTools()
  82.  */
  83. void NEAR PASCAL CreateTools(void)
  84. {
  85.   hbrForeground  = CreateSolidBrush(GetSysColor(COLOR_WINDOWTEXT));
  86.   hbrColorWindow = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  87.   hbrColorBlack  = CreateSolidBrush(0L);
  88.   hbrBackground  = hbrColorWindow;
  89.   hpenForeground = CreatePen(0, 1, GetSysColor(COLOR_WINDOWTEXT));
  90.   hpenBackground = CreatePen(0, 1, GetSysColor(COLOR_WINDOW));
  91. }
  92. /*
  93.  *  DeleteTools()
  94.  */
  95. void NEAR PASCAL DeleteTools(void)
  96. {
  97.   DeleteObject(hbrForeground);
  98.   DeleteObject(hbrColorWindow);
  99.   DeleteObject(hbrColorBlack);
  100.   DeleteObject(hpenForeground);
  101.   DeleteObject(hpenBackground);
  102. }
  103. /*
  104.  * SizeFont() - size font according to window size
  105.  */
  106. void NEAR PASCAL SizeFont(HWND hWnd, INT newHeight, INT newWidth, INT wlen)
  107. {
  108. register HDC    hDC;
  109. TEXTMETRIC    tm;
  110. LOGFONT    FontStruct;
  111.     hDC = GetDC(hWnd);
  112.     GetTextMetrics(hDC, &tm);
  113.     if (ClockDisp.wFormat == IDM_DIGITAL) {
  114.         if (hFont != NULL)
  115.             DeleteObject(hFont);
  116.         FontStruct.lfUnderline = FALSE;
  117.         FontStruct.lfStrikeOut = FALSE;
  118.         FontStruct.lfItalic    = FALSE;
  119.         FontStruct.lfEscapement = FALSE;
  120.         FontStruct.lfOrientation = FALSE;
  121.         FontStruct.lfOutPrecision = OUT_DEFAULT_PRECIS;
  122.         FontStruct.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  123.         /* Note that the numbers used in this formula depend on the
  124.          * size of the numbers in the fonts which are 12 vert, 7 horz.
  125.         */
  126.         if (!ClockDisp.bIconic)  {
  127.             FontStruct.lfHeight = (SHORT)min(newHeight/2, 45);
  128.             /* The formula at the end is somewhat empirical. */
  129.             FontStruct.lfWidth = (SHORT)min(25, newWidth/(wlen*3/2));
  130.             /* This if is here because of a problem where:  if a clock
  131.              * existed with a maximum size font, any new clock with a
  132.              * smaller client area would get the same font that would not
  133.              * fit in the Window.  So here, if the width does not match
  134.              * maximum font dimensions, don't use the maximum height.
  135.              */
  136.             if (FontStruct.lfWidth != 25 && FontStruct.lfHeight == 45)
  137.                 FontStruct.lfHeight = 40;
  138.         }
  139.         else {
  140.             FontStruct.lfHeight = (SHORT)(newHeight/3);
  141.             FontStruct.lfWidth  = (SHORT)(newWidth/5);
  142.         }
  143.         FontStruct.lfCharSet      = ANSI_CHARSET;
  144.         FontStruct.lfQuality      = DRAFT_QUALITY;
  145.         FontStruct.lfWeight      = FW_NORMAL;
  146.         FontStruct.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
  147.         lstrcpy(FontStruct.lfFaceName, "DIGITAL");
  148.         hFont = CreateFontIndirect(&FontStruct);
  149.         SelectObject(hDC, hFont);
  150.         GetTextMetrics(hDC, &tm);
  151.         SelectObject(hDC, GetStockObject(SYSTEM_FONT));
  152.     }
  153.     ReleaseDC(hWnd, hDC);
  154.     /* Compute placement for digital text. */
  155.     ClockDisp.line1.x = (newWidth) / 2;
  156.     ClockDisp.line1.y = (newHeight - (tm.tmHeight)) / 2;
  157.     ClockDisp.yline2  = ClockDisp.line1.y + tm.tmHeight;
  158. }
  159. /*
  160.  *  CompClockDim() - Recompute the clock's dimensions.
  161.  */
  162. void NEAR PASCAL CompClockDim(void)
  163. {
  164. INT        i;
  165. register INT    tWidth;
  166. register INT    tHeight;
  167.     tWidth = clockRect.right - clockRect.left;
  168.     tHeight = clockRect.bottom - clockRect.top;
  169.     if (tWidth > (INT)((tHeight * aspectD) / aspectN)) {
  170.         i = (INT)((tHeight * aspectD) / aspectN);
  171.         clockRect.left += (tWidth - i) >> 1;
  172.         clockRect.right = clockRect.left + i;
  173.     }
  174.     else {
  175.         i = (INT)((tWidth * aspectN) / aspectD);
  176.         clockRect.top += (tHeight - i) >> 1;
  177.         clockRect.bottom = clockRect.top + i;
  178.     }
  179. }
  180. /*
  181.  *  ClockSize()
  182.  */
  183. void NEAR PASCAL ClockSize(register HWND hWnd,
  184.                INT       newWidth,
  185.                INT       newHeight,
  186.                WORD      SizeWord)
  187. {
  188.     SetRect((LPRECT)&(clockRect), 0, 0, newWidth, newHeight);
  189.     CompClockDim();
  190.     if (SizeWord == SIZEICONIC) {
  191.         /* Update once every 1/2 minute in the iconic state */
  192.         KillTimer(hWnd, TimerID);
  193.         SetTimer(hWnd, TimerID, (WORD)ICON_TLEN, 0L);
  194.         ClockDisp.bIconic = TRUE;
  195.     }
  196.     else if (ClockDisp.bIconic) {
  197.         /* Update every 1/2 second in the opened state. */
  198.         KillTimer(hWnd, TimerID);
  199.         SetTimer(hWnd, TimerID, OPEN_TLEN, 0L);
  200.         ClockDisp.bIconic = FALSE;
  201.     }
  202.     /* Compute where the digital readout should go. */
  203.     SizeFont(hWnd, newHeight, newWidth, ClockDisp.wDigTimeLen);
  204. }
  205. /*
  206.  *  DrawBorder() - Draws a Red Border around either clock.
  207.  */
  208. void NEAR PASCAL DrawBorder(HWND hWnd, register HDC hDC)
  209. {
  210. RECT Rect;
  211. HPEN hPen;
  212.     GetClientRect(hWnd, (LPRECT) &Rect);
  213.     hPen = CreatePen(PS_SOLID, (ClockDisp.bIconic) ? 1 : 2,
  214.                (ClockDisp.bColor)  ? RGB(255,0,0) : RGB(255,255,255));
  215.     SelectObject(hDC, hPen);
  216.     Rectangle(hDC, Rect.left+1, Rect.top+1, Rect.right, Rect.bottom);
  217.     SelectObject(hDC, GetStockObject(BLACK_PEN));
  218.     DeleteObject(hPen);
  219.     /* Draw an external black border on an icon without killing the client area. */
  220.     if (ClockDisp.bIconic) {
  221.         MoveToEx(hDC, Rect.left, Rect.top, NULL);
  222.         LineTo(hDC, Rect.left,  Rect.bottom);
  223.         LineTo(hDC, Rect.right, Rect.bottom);
  224.         LineTo(hDC, Rect.right, Rect.top);
  225.         LineTo(hDC, Rect.left,  Rect.top);
  226.     }
  227. }
  228. /*
  229.  *  DrawFace()
  230.  */
  231. void NEAR PASCAL DrawFace(HDC hDC)
  232. {
  233. INT        i;
  234. RECT       tRect;
  235. INT        blobHeight, blobWidth;
  236.     blobWidth = (INT)((MAXBLOBWIDTH * (LONG)(clockRect.right - clockRect.left)) / HorzRes);
  237.     blobHeight = (INT)((blobWidth * aspectN) / aspectD);
  238.     if (blobHeight < 2)
  239.         blobHeight = 1;
  240.     if (blobWidth < 2)
  241.         blobWidth = 2;
  242.     InflateRect((LPRECT)&clockRect, -(blobHeight >> 1), -(blobWidth >> 1));
  243.     clockRadius = (clockRect.right - clockRect.left-6) >> 1;
  244.     clockCenter.y = clockRect.top + ((clockRect.bottom - clockRect.top) >> 1);
  245.     clockCenter.x = clockRect.left + clockRadius+3;
  246.     for (i=0; i < 60; i++) {
  247.         tRect.top  = (INT)(((LONG)(CirTab[i].cos) * clockRadius) / CLKSCALE + clockCenter.y);
  248.         tRect.left = (INT)(((LONG)(CirTab[i].sin) * clockRadius) / CLKSCALE + clockCenter.x);
  249.         if (i % 5) {
  250.             /* Draw a dot. */
  251.             if (blobWidth > 2 && blobHeight >= 2) {
  252.                 tRect.right = tRect.left + 1;
  253.                 tRect.bottom = tRect.top + 1;
  254.                 FillRect(hDC, (LPRECT)&tRect, hbrForeground);
  255.             }
  256.         }
  257.         else {
  258.             tRect.right = tRect.left + blobWidth;
  259.             tRect.bottom = tRect.top + blobHeight;
  260.             OffsetRect((LPRECT)&tRect, -(blobWidth >> 1) , -(blobHeight >> 1));
  261.             FillRect(hDC, (LPRECT)&tRect, hbrForeground);
  262.         }
  263.     }
  264.     InflateRect((LPRECT)&clockRect, (blobHeight >> 1), (blobWidth >> 1));
  265. }
  266. /*
  267.  *  DrawHand() - Draw the second hand using XOR mode.
  268.  */
  269. void NEAR PASCAL DrawHand(register HDC hDC,
  270.               INT          pos,
  271.               HPEN         hPen,
  272.               INT          scale,
  273.               INT          patMode)
  274. {
  275. INT       radius;
  276.     MoveToEx(hDC, clockCenter.x, clockCenter.y, NULL);
  277.     radius = (INT)(((LONG)clockRadius * scale) / 100);
  278.     SetROP2(hDC, patMode);
  279.     SelectObject(hDC, hPen);
  280.     LineTo(hDC, clockCenter.x + (INT)(((LONG)(CirTab[pos].sin) * (radius)) / CLKSCALE),
  281.         clockCenter.y + (INT)(((LONG)(CirTab[pos].cos) * (radius)) / CLKSCALE));
  282. }
  283. /*
  284.  *  DrawFatHand() - Draws either hour or minute hand.
  285.  */
  286. void NEAR PASCAL DrawFatHand(register HDC hDC, INT pos, HPEN hPen, BOOL hHand)
  287. {
  288. register INT    m;
  289. INT        n;
  290. INT        scale;
  291. POINT      tip;
  292. POINT      stip;
  293.     SetROP2(hDC, R2_COPYPEN);
  294.     SelectObject(hDC, hPen);
  295.     scale = hHand ? 7 : 5;
  296.     n = (pos+15)%60;
  297.     m = (INT)((((LONG)clockRadius*scale) / 100));
  298.     stip.y = (INT)((LONG)(CirTab[n].cos) * m / CLKSCALE);
  299.     stip.x = (INT)((LONG)(CirTab[n].sin) * m / CLKSCALE);
  300.     scale = hHand ? 65 : 80;
  301.     tip.y = (INT)((LONG)(CirTab[pos].cos) * (((LONG)clockRadius * scale) / 100) / CLKSCALE);
  302.     tip.x = (INT)((LONG)(CirTab[pos].sin) * (((LONG)clockRadius * scale) / 100) / CLKSCALE);
  303.     MoveToEx(hDC, clockCenter.x+stip.x, clockCenter.y+stip.y, NULL);
  304.     LineTo(hDC, clockCenter.x+tip.x,  clockCenter.y+tip.y);
  305.     MoveToEx(hDC, clockCenter.x-stip.x, clockCenter.y-stip.y, NULL);
  306.     LineTo(hDC, clockCenter.x+tip.x,  clockCenter.y+tip.y);
  307.     scale = hHand ? 15 : 20;
  308.     n = (pos + 30) % 60;
  309.     m = (INT)(((LONG)clockRadius * scale) / 100);
  310.     tip.y = (INT)((LONG)(CirTab[n].cos) * m / CLKSCALE);
  311.     tip.x = (INT)((LONG)(CirTab[n].sin) * m / CLKSCALE);
  312.     MoveToEx(hDC, clockCenter.x+stip.x, clockCenter.y+stip.y, NULL);
  313.     LineTo(hDC, clockCenter.x+tip.x,  clockCenter.y+tip.y);
  314.     MoveToEx(hDC, clockCenter.x-stip.x, clockCenter.y-stip.y, NULL);
  315.     LineTo(hDC, clockCenter.x+tip.x,  clockCenter.y+tip.y);
  316. }
  317. /*
  318.  *  ClockPaint()
  319.  */
  320. void NEAR PASCAL ClockPaint(HWND hWnd, register HDC hDC, INT hint)
  321. {
  322. INT     hour;
  323. CHAR    *pszTime;
  324. RECT    Rect;
  325. TIME    nTime;
  326. DWORD   rgbCol;
  327. HBRUSH  hBr;
  328.     GetClientRect(hWnd, (LPRECT) &Rect);
  329.     GetTime(&nTime);
  330.     if (ClockDisp.wFormat == IDM_DIGITAL) {  /* Digital Display */
  331.         if (hint == REPAINT || ClockDisp.bIconic) {
  332.             SelectObject(hDC, GetStockObject(BLACK_BRUSH));
  333.             DrawBorder(hWnd, hDC);
  334.             /* Set old values as undefined, so entire clock updated. */
  335.             oTime.hour24 = 25;
  336.             oTime.minute = 60;
  337.             oTime.ampm   = 2;
  338.         }
  339.         if (oTime.hour24 != nTime.hour24) {
  340.             if (ClockDisp.wTimeFormat)
  341.                 hour = nTime.hour24;
  342.             else
  343.                 hour = nTime.hour12;
  344.             ClockDisp.szDigTime[0] = (CHAR)('0' + hour / 10);
  345.             ClockDisp.szDigTime[1] = (CHAR)('0' + hour % 10);
  346.         }
  347.         if (oTime.minute != nTime.minute) {
  348.             ClockDisp.szDigTime[3]  = (CHAR)('0' + nTime.minute / 10);
  349.             ClockDisp.szDigTime[4]  = (CHAR)('0' + nTime.minute % 10);
  350.         }
  351.         /* Kill Leading zero if needed. */
  352.         if (nLeadZero == 0 && ClockDisp.szDigTime[0] == '0')
  353.             pszTime = ClockDisp.szDigTime + 1;
  354.         else
  355.             pszTime = ClockDisp.szDigTime;
  356.         SetTextColor(hDC, (ClockDisp.bColor) ? RGB(0,255,0) : RGB(255,255,255));
  357.         SetBkColor(hDC, 0L);
  358.         SetTextAlign(hDC, TA_CENTER);
  359.         ClockDisp.wDigTimeLen = (WORD)((ClockDisp.bIconic ? 5 : 8) + ClockDisp.szDigTime - pszTime);
  360.         /* Is the font ready yet? */
  361.         if (hFont == 0 || ClockDisp.bNewFont)  {
  362.             /* Create a suitable font */
  363.             SizeFont(hWnd, Rect.bottom - Rect.top, Rect.right - Rect.left, ClockDisp.wDigTimeLen);
  364.             ClockDisp.bNewFont = FALSE;
  365.         }
  366.         SelectObject(hDC, hFont);
  367.         ClockDisp.szDigTime[6] = (CHAR)('0' + nTime.second / 10);
  368.         ClockDisp.szDigTime[7] = (CHAR)('0' + nTime.second % 10);
  369.         Rect.left += 4;
  370.         Rect.right -= 4;
  371.         Rect.top = ClockDisp.line1.y;
  372.         Rect.bottom = ClockDisp.yline2;
  373.         ExtTextOut(hDC, ClockDisp.line1.x, ClockDisp.line1.y, ETO_OPAQUE | ETO_CLIPPED,
  374.           (LPRECT)&Rect, pszTime, (UINT)ClockDisp.wDigTimeLen, (LPINT)NULL);
  375.         SelectObject(hDC, GetStockObject(SYSTEM_FONT));
  376.     }
  377.     else {
  378.         /* Analog display */
  379.         SetBkMode(hDC, TRANSPARENT);
  380.         if (hint == REPAINT) {
  381.             SetBkMode(hDC, OPAQUE);
  382.             /* When switching from Digital to analog, the brush selected
  383.              *  continued to be black; So, the current background is to be
  384.              * selected;
  385.              * Fix for Bug #6385 -- SANKAR -- 11-26-89 */
  386.             SelectObject(hDC, hbrBackground);
  387.             /* Make a temp brush to color the background.  This is to
  388.              * force use of a solid color so the hand motion is painted
  389.              * correctly.
  390.              */
  391.             rgbCol = GetNearestColor(hDC, GetSysColor(COLOR_WINDOW));
  392.             hBr = CreateSolidBrush(rgbCol);
  393.             FillRect(hDC, &Rect, hBr);
  394.             DeleteObject(hBr);
  395.             SetBkMode(hDC, TRANSPARENT);
  396.             DrawBorder(hWnd, hDC);
  397.             DrawFace(hDC);
  398.             DrawFatHand(hDC, oTime.hour * 5 + (oTime.minute / 12), hpenForeground, HHAND);
  399.             DrawFatHand(hDC, oTime.minute, hpenForeground, MHAND);
  400.             if (!ClockDisp.bIconic)       /* Draw the second hand. */
  401.                 DrawHand(hDC, oTime.second, hpenBackground, SECONDSCALE, R2_NOT);
  402.             /* NOTE: Don't update oTime in this case! */
  403.             return;
  404.         }
  405.         else if (hint == HANDPAINT) {
  406.             if ((!ClockDisp.bIconic) && nTime.second != oTime.second) /* Erase the old second hand. */
  407.                 DrawHand(hDC, oTime.second, hpenBackground, SECONDSCALE, R2_NOT);
  408.             if (nTime.minute != oTime.minute || nTime.hour != oTime.hour) {
  409.                 if (ClockDisp.bIconic) {
  410.                     DrawHand(hDC, oTime.minute, hpenBackground, MINUTESCALE, R2_COPYPEN);
  411.                     DrawHand(hDC, oTime.hour * 5 + (oTime.minute / 12), hpenBackground, HOURSCALE, R2_COPYPEN);
  412.                     DrawHand(hDC, nTime.minute, hpenForeground, MINUTESCALE, R2_COPYPEN);
  413.                     DrawHand(hDC, nTime.hour * 5 + (nTime.minute / 12), hpenForeground, HOURSCALE, R2_COPYPEN);
  414.                 }
  415.                 else {
  416.                     DrawFatHand(hDC, oTime.minute, hpenBackground, MHAND);
  417.                     DrawFatHand(hDC, oTime.hour*5+(oTime.minute/12), hpenBackground, HHAND);
  418.                    DrawFatHand(hDC, nTime.minute, hpenForeground, MHAND);
  419.                     DrawFatHand(hDC, (nTime.hour) * 5 + (nTime.minute / 12), hpenForeground, HHAND );
  420.                 }
  421.             }
  422.             if (!ClockDisp.bIconic && nTime.second != oTime.second) /* Draw new second hand */
  423.                 DrawHand(hDC, nTime.second, hpenBackground, SECONDSCALE, R2_NOT);
  424.         }
  425.     }
  426.     oTime = nTime;
  427. }
  428. /*
  429.  *  ClockTimer()
  430.  *
  431.  *  msg - timer ID
  432.  *
  433.  * Called by windows to tell CLOCK there has been a time change.
  434.  *
  435.  */
  436. void NEAR PASCAL ClockTimer(HWND hWnd, UINT msg)
  437. {
  438. HDC    hDC;
  439. TIME    nTime;
  440.     GetTime(&nTime);
  441.     /* It's possible to change any part of the system at any time
  442.      * through the Control Panel.  So we check everything.
  443.      */
  444.     if (((nTime.second == oTime.second) || ClockDisp.bIconic) &&
  445.         (nTime.minute == oTime.minute)          &&
  446.         (nTime.hour24 == oTime.hour24))
  447.         return;
  448.     hDC = GetDC(hWnd);
  449.     ClockPaint(hWnd, hDC, HANDPAINT);
  450.     ReleaseDC(hWnd, hDC);
  451.     DdePostAdvise(idInst, hszTime, hszNow);
  452.       UNREFERENCED_PARAMETER(msg);
  453. }
  454. /*
  455.  *  ClockCreate()
  456.  */
  457. void NEAR PASCAL ClockCreate(HWND hWnd)
  458. {
  459. INT        i;
  460. register HDC    hDC;
  461. INT        HorzSize;
  462. INT        VertSize;
  463.     hDC = GetDC(hWnd);
  464.     VertRes = GetDeviceCaps(hDC, VERTRES);
  465.     HorzRes = GetDeviceCaps(hDC, HORZRES);
  466.     VertSize= GetDeviceCaps(hDC, VERTSIZE);
  467.     HorzSize= GetDeviceCaps(hDC, HORZSIZE);
  468.     ReleaseDC(hWnd, hDC);
  469.     aspectN = ((LONG)VertRes * 100) / (LONG)VertSize;
  470.     aspectD = ((LONG)HorzRes * 100) / (LONG)HorzSize;
  471.     CreateTools();
  472.     /* Scale sines for aspect ratio if this is the first instance */
  473.     for (i=0; i < 60; i++) {
  474.         CirTab[i].sin = (SHORT)((CirTab[i].sin * aspectN) / aspectD);
  475.     }
  476. }
  477. /*
  478.  *  FormatInit() -  International initialization.
  479.  */
  480. void NEAR PASCAL FormatInit(register HANDLE hInstance, BOOL fModeChange)
  481. {
  482. WORD i, ii;
  483. CHAR szWinHeader[21], szKeyName[21], szRetVal[21];
  484.     for (i=0; i < 11; i++)
  485.         ClockDisp.szDigTime[i] = ' ';
  486.     LoadString(hInstance, IDS_INTL, (LPSTR)szWinHeader, 20);
  487.     LoadString(hInstance, IDS_ITIME, (LPSTR)szKeyName, 20);
  488.     ClockDisp.wTimeFormat = (WORD)GetProfileInt((LPSTR)szWinHeader, (LPSTR)szKeyName, 0);
  489.     LoadString(hInstance, IDS_S1159, (LPSTR)szKeyName, 20);
  490.     LoadString(hInstance, IDS_1159, (LPSTR)szRetVal, 20);
  491.     i = (WORD)GetProfileString((LPSTR)szWinHeader, (LPSTR)szKeyName, (LPSTR)szRetVal, (LPSTR)&ClockDisp.szAMPM[0][0], 7);
  492.     LoadString(hInstance, IDS_S2359, (LPSTR)szKeyName, 20);
  493.     LoadString(hInstance, IDS_2359, (LPSTR)szRetVal, 20);
  494.     ii = (WORD)GetProfileString((LPSTR)szWinHeader, (LPSTR)szKeyName, (LPSTR)szRetVal, (LPSTR)&ClockDisp.szAMPM[1][0], 7);
  495.     nLeadZero = GetProfileInt((LPSTR)szWinHeader, "iTLzero", 0);
  496.     LoadString(hInstance, IDS_STIME, (LPSTR)szKeyName, 20);
  497.     LoadString(hInstance, IDS_TIMESEP, (LPSTR)szRetVal, 20);
  498.     GetProfileString((LPSTR)szWinHeader, (LPSTR)szKeyName, (LPSTR)szRetVal, (LPSTR)szRetVal, 20);
  499.     ClockDisp.cTimeSep = szRetVal[0];
  500.     ClockDisp.szDigTime[2] = ClockDisp.cTimeSep;
  501.     ClockDisp.szDigTime[5] = ClockDisp.cTimeSep;
  502.     LoadString(hInstance, IDS_USNAME, (LPSTR)szWinHeader, 20);
  503.     LoadString(hInstance, IDS_CLKFORMAT, (LPSTR)szKeyName, 20);
  504.     /* We will read the new mode (DIGITAL/ANALOG) only during init time. */
  505.     if (fModeChange)
  506.     {
  507.         if (GetPrivateProfileInt((LPSTR)szWinHeader, (LPSTR)szKeyName, 1, (LPSTR)szIniFile))
  508.             ClockDisp.wFormat = IDM_ANALOG;
  509.         else
  510.             ClockDisp.wFormat = IDM_DIGITAL;
  511.     }
  512.     if (ClockDisp.wFormat == IDM_ANALOG)
  513.         hbrBackground = hbrColorWindow;
  514.     else
  515.         hbrBackground = hbrColorBlack;
  516.     ClockDisp.wDigTimeLen = 2+1+2+1+2+1;
  517.     if (!ClockDisp.wTimeFormat)
  518.         ClockDisp.wDigTimeLen += ((i > ii) ? (i) : (ii));
  519. }
  520. /*
  521.  *  ClockInit()
  522.  */
  523. BOOL NEAR PASCAL ClockInit(HANDLE hInstance)
  524. {
  525. HDC       hDC;
  526. WNDCLASS  ClockClass;
  527.     FormatInit(hInstance, TRUE);
  528.     ClockClass.style         = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
  529.     ClockClass.lpfnWndProc   = ClockWndProc;
  530.     ClockClass.cbClsExtra    = 0;
  531.     ClockClass.cbWndExtra    = 0;
  532.     ClockClass.hInstance     = hInstance;
  533.     ClockClass.hIcon         = NULL;
  534.     ClockClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  535.     ClockClass.hbrBackground = (HBRUSH) NULL;
  536.     ClockClass.lpszMenuName  = (LPSTR)"Clock";
  537.     ClockClass.lpszClassName = (LPSTR)"Clock";
  538.     if (!RegisterClass((LPWNDCLASS)&ClockClass))
  539.         return(FALSE);
  540.     LoadString(hInstance, IDS_FONTFILE, (LPSTR)szFontFile, 20);
  541.     AddFontResource(szFontFile);
  542.     /* Check the number of colors that the display is capable of. */
  543.     hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
  544.     ClockDisp.bColor = (GetDeviceCaps(hDC, NUMCOLORS) > 2);
  545.     ClockDisp.bColor = FALSE;
  546.     DeleteDC(hDC);
  547.     ClockDisp.bTmpHide = FALSE;
  548.     ClockDisp.bNewFont = FALSE;
  549.     ClockDisp.bColor   = TRUE;
  550.     ClockDisp.bNewFont = TRUE;
  551.     return(TRUE);
  552. }
  553. /*
  554.  *  SetMenuBar() - places or removes the menu bar, etc.
  555.  *
  556.  *  Based on the flag ClockDisp.bNoTitle (ie: do we want a menu/title
  557.  *  bar or not?), adds or removes the window title and menu bar:
  558.  *    Gets current style, toggles the bits, and re-sets the style.
  559.  *    Must then resize the window frame and show it.
  560.  */
  561. void NEAR PASCAL SetMenuBar( HWND hWnd )
  562. {
  563.     static DWORD wID;
  564.     DWORD   dwStyle;
  565.     dwStyle = GetWindowLong( hWnd, GWL_STYLE );
  566.     if( ClockDisp.bNoTitle ) {
  567.         /* remove caption & menu bar, etc. */
  568.         dwStyle &= ~(WS_DLGFRAME | WS_SYSMENU |
  569.                    WS_MINIMIZEBOX | WS_MAXIMIZEBOX );
  570.         wID = SetWindowLong( hWnd, GWL_ID, 0 );
  571.     }
  572.     else {
  573.         /* put menu bar & caption back in */
  574.         dwStyle = WS_TILEDWINDOW | dwStyle;
  575.         SetWindowLong( hWnd, GWL_ID, wID );
  576.     }
  577.     SetWindowLong( hWnd, GWL_STYLE, dwStyle );
  578.     SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
  579.         SWP_NOZORDER | SWP_FRAMECHANGED );
  580.     ShowWindow( hWnd, SW_SHOW );
  581. }
  582. /*
  583.  *  AboutDlgProc()
  584.  */
  585. BOOL APIENTRY AboutDlgProc ( hwnd, msg, wParam, lParam )
  586. HWND          hwnd;
  587. UINT msg;
  588. WPARAM wParam;
  589. LPARAM lParam;
  590. {
  591.     switch (msg) {
  592.         case WM_INITDIALOG:
  593.             /* nothing to initialize */
  594.             break;
  595.         case WM_COMMAND:
  596.             switch (LOWORD(wParam)) {
  597.                 case IDOK:
  598.                 case IDCANCEL:
  599.                     EndDialog(hwnd, 0);
  600.                     break;
  601.                 default:
  602.                     return FALSE;
  603.             }
  604.             break;
  605.         default:
  606.             return(FALSE);
  607.     }
  608.     return TRUE;
  609. }
  610. /*
  611.  *  ClockWndProc()
  612.  */
  613. LONG APIENTRY ClockWndProc(register HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  614. {
  615. HMENU       hMenu;
  616. static CHAR szAppName[12];  /* application name buffer */
  617. PAINTSTRUCT ps;
  618.     switch (message) {
  619.         case WM_COMMAND:
  620.         switch (wParam)  {
  621.             case IDM_ANALOG:
  622.             case IDM_DIGITAL:
  623.                 if ((WORD)wParam != ClockDisp.wFormat) {
  624.                     /* Switch flag to other choice */
  625.                     hMenu = GetMenu(hWnd);
  626.                     CheckMenuItem(hMenu, ClockDisp.wFormat, MF_BYCOMMAND | MF_UNCHECKED);
  627.                     CheckMenuItem(hMenu, ClockDisp.wFormat = (WORD) wParam, MF_BYCOMMAND | MF_CHECKED);
  628.                     InvalidateRect(hWnd, (LPRECT) NULL, TRUE);
  629.                 }
  630.             break;
  631.             case IDM_NOTITLE:
  632.                 goto toggle_title;
  633.             case IDM_ABOUT: {
  634.                 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUT), hWnd, (DLGPROC)AboutDlgProc);
  635.                 break;
  636.             }
  637.             default:
  638.                 goto defproc;
  639.         }
  640.         break;
  641.         case WM_SIZE:
  642.             ClockDisp.bNewFont = TRUE;
  643.             ClockSize(hWnd, LOWORD(lParam), HIWORD(lParam), (WORD)wParam);
  644.             UpdateWindow(hWnd);
  645.             break;
  646.         case WM_QUERYDRAGICON:
  647.             return (LONG)LoadIcon(hInst, "cckk");
  648.         case WM_CLOSE:
  649.         case WM_ENDSESSION:
  650.           DestroyWindow( hWnd );
  651.           break;
  652.         case WM_DESTROY: {
  653.             CHAR           szInt[10];
  654.             HCURSOR        hTempCursor;
  655.             KillTimer(hWnd, TimerID);
  656.             DeleteTools();
  657.             if (hFont)
  658.                 DeleteObject(hFont);
  659.             RemoveFontResource(szFontFile);
  660.             SetCapture(hWnd);
  661.             hTempCursor=SetCursor(LoadCursor(NULL, IDC_WAIT));
  662.             if (!(IsIconic(hWnd) || IsZoomed(hWnd)))
  663.                 GetWindowRect(hWnd, &rCoordRect);
  664.             /* Write new configuration to DDEMLCLK.INI */
  665.             LoadString(hInst, IDS_CLKFORMAT, (LPSTR)szBuffer, BUFLEN-1);
  666.             szInt[0] = (CHAR)('0' + (ClockDisp.wFormat == IDM_ANALOG));
  667.             szInt[1] = 0;
  668.             WritePrivateProfileString((LPSTR)szSection,
  669.                                       (LPSTR)szBuffer,
  670.                                       (LPSTR)szInt,
  671.                                       (LPSTR)szIniFile);
  672.             wsprintf((LPSTR)szInt, (LPSTR)"%i", (INT)IsIconic(hWnd));
  673.             WritePrivateProfileString((LPSTR)szSection,
  674.                                       (LPSTR)"Minimized",
  675.                                       (LPSTR)szInt,
  676.                                       (LPSTR)szIniFile);
  677.             wsprintf((LPSTR)szInt, (LPSTR)"%i", (INT)IsZoomed(hWnd));
  678.             WritePrivateProfileString((LPSTR)szSection,
  679.                                       (LPSTR)"Maximized",
  680.                                       (LPSTR)szInt,
  681.                                       (LPSTR)szIniFile);
  682.             wsprintf((LPSTR)szInt, (LPSTR)"%i", (INT)rCoordRect.left);
  683.             WritePrivateProfileString((LPSTR)szSection,
  684.                                       (LPSTR)"Left",
  685.                                       (LPSTR)szInt,
  686.                                       (LPSTR)szIniFile);
  687.             wsprintf((LPSTR)szInt, (LPSTR)"%i", (INT)rCoordRect.top);
  688.             WritePrivateProfileString((LPSTR)szSection,
  689.                                       (LPSTR)"Top",
  690.                                       (LPSTR)szInt,
  691.                                       (LPSTR)szIniFile);
  692.             wsprintf((LPSTR)szInt, (LPSTR)"%i", (INT)rCoordRect.right);
  693.             WritePrivateProfileString((LPSTR)szSection,
  694.                                       (LPSTR)"Right",
  695.                                       (LPSTR)szInt,
  696.                                       (LPSTR)szIniFile);
  697.             wsprintf((LPSTR)szInt, (LPSTR)"%i", (INT)rCoordRect.bottom);
  698.             WritePrivateProfileString((LPSTR)szSection,
  699.                                       (LPSTR)"Bottom",
  700.                                       (LPSTR)szInt,
  701.                                       (LPSTR)szIniFile);
  702.             wsprintf((LPSTR)szInt, (LPSTR)"%i", (INT)ClockDisp.bTopMost);
  703.             WritePrivateProfileString((LPSTR)szSection,
  704.                                       (LPSTR)"TopMost",
  705.                                       (LPSTR)szInt,
  706.                                       (LPSTR)szIniFile);
  707.             wsprintf((LPSTR)szInt, (LPSTR)"%i", (INT)ClockDisp.bNoTitle);
  708.             WritePrivateProfileString((LPSTR)szSection,
  709.                                       (LPSTR)"NoTitle",
  710.                                       (LPSTR)szInt,
  711.                                       (LPSTR)szIniFile);
  712.             PostQuitMessage(0);
  713.             break;
  714.         }
  715.         case WM_WININICHANGE:
  716.             /* FALSE indicates that we don't want to change the display format */
  717.             FormatInit(hInst, FALSE);
  718.             InvalidateRect(hWnd, (LPRECT)NULL, TRUE);
  719.             break;
  720.         case WM_PAINT:
  721.             /* Added to force total repaint to solve
  722.              * problem of garbage under second hand when hidden
  723.              * by menu or popup.
  724.              */
  725.             InvalidateRect(hWnd, (LPRECT)NULL, TRUE);
  726.             BeginPaint(hWnd, (LPPAINTSTRUCT)&ps);
  727.             if (ClockDisp.wFormat == IDM_DIGITAL) {
  728.                 hbrBackground = hbrColorBlack;
  729.                 FillRect(ps.hdc, (LPRECT)&clockRect, hbrBackground);
  730.             }
  731.             else
  732.                 hbrBackground=hbrColorWindow;
  733.             ClockPaint(hWnd, ps.hdc, REPAINT);
  734.             EndPaint(hWnd, (LPPAINTSTRUCT)&ps);
  735.             break;
  736.         case WM_TIMECHANGE:
  737.             /* Redraw. */
  738.             InvalidateRect(hWnd, (LPRECT)NULL, TRUE);
  739.         case WM_TIMER:
  740.             ClockTimer(hWnd, (WORD)wParam);
  741.             break;
  742.         case WM_SYSCOMMAND:
  743.             switch (wParam)  {
  744.                 case SC_MINIMIZE:
  745.                     if (!IsZoomed(hWnd))
  746.                         GetWindowRect(hWnd, (LPRECT)&rCoordRect);
  747.                     ClockDisp.bMinimized = TRUE;
  748.                     ClockDisp.bMaximized = FALSE;
  749.                     break;
  750.                 case SC_MAXIMIZE:
  751.                     if (!IsIconic(hWnd))
  752.                         GetWindowRect(hWnd, (LPRECT)&rCoordRect);
  753.                     ClockDisp.bMinimized = FALSE;
  754.                     ClockDisp.bMaximized = TRUE;
  755.                     break;
  756.                 case IDM_TOPMOST: {
  757.                     /* toggles topmost option
  758.                      */
  759.                     hMenu = GetSystemMenu(hWnd, FALSE);
  760.                     if( ClockDisp.bTopMost )  {
  761.                         CheckMenuItem( hMenu, IDM_TOPMOST, MF_BYCOMMAND | MF_UNCHECKED );
  762.                         SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
  763.                                        SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  764.                         ClockDisp.bTopMost = FALSE;
  765.                     }
  766.                     else {
  767.                         CheckMenuItem( hMenu, IDM_TOPMOST, MF_BYCOMMAND | MF_CHECKED );
  768.                         SetWindowPos( hWnd, HWND_TOPMOST, 0, 0, 0, 0,
  769.                                          SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  770.                         ClockDisp.bTopMost = TRUE;
  771.                     }
  772.                     break;
  773.                 }
  774.             }
  775.             return(DefWindowProc(hWnd, message, wParam, lParam));
  776.             break;
  777.         case WM_MOUSEACTIVATE:
  778.             /* right button temporarily hides the window if topmost is
  779.              * enabled (window re-appears when right button is released).
  780.              * When this happens, we don't want to activate the clock window
  781.              * just before hiding it (it would look really bad), so we
  782.              * intercept the activate message.
  783.              */
  784.             if( GetAsyncKeyState( VK_RBUTTON ) & 0x8000 )
  785.                 return( MA_NOACTIVATE );
  786.             else
  787.                 goto defproc;
  788.             break;
  789.         case WM_RBUTTONDOWN:
  790.         case WM_NCRBUTTONDOWN:
  791.             /* right button temporarily hides the window, if the window
  792.              * is topmost, and if no menu is currently "active"
  793.              */
  794.             if( !ClockDisp.bTmpHide && ClockDisp.bTopMost ) {
  795.                 ShowWindow( hWnd, SW_HIDE );
  796.                 SetCapture( hWnd );
  797.                 ClockDisp.bTmpHide = TRUE;
  798.             }
  799.             break;
  800.         case WM_RBUTTONUP:
  801.         case WM_NCRBUTTONUP:
  802.             /* if window is currently hidden, right button up brings it
  803.              * back. Must make sure we show it in its previous state - ie:
  804.              * minimized, maximized or normal.
  805.              */
  806.             if( ClockDisp.bTmpHide ) {
  807.                 ReleaseCapture();
  808.                 if( IsIconic(hWnd) )
  809.                     ShowWindow( hWnd, SW_SHOWMINNOACTIVE );
  810.                 else if( IsZoomed( hWnd ) )
  811.                     ShowWindow( hWnd, SW_SHOWMAXIMIZED );
  812.                 else
  813.                     ShowWindow( hWnd, SW_SHOWNOACTIVATE );
  814.                 ClockDisp.bTmpHide = FALSE;
  815.             }
  816.             break;
  817.         case WM_KEYDOWN:
  818.             /* ESC key toggles the menu/title bar (just like a double click
  819.              * on the client area of the window.
  820.              */
  821.             if( (wParam == VK_ESCAPE) && !(HIWORD( lParam ) & 0x4000) )
  822.                 goto toggle_title;
  823.             break;
  824.         case WM_NCLBUTTONDBLCLK:
  825.             if( !ClockDisp.bNoTitle )
  826.                 /* if we have title bars etc. let the normal stuff take place */
  827.                 goto defproc;
  828.             /* else: no title bars, then this is actually a request to bring
  829.              * the title bars back...
  830.              */
  831.             /* fall through */
  832.         case WM_LBUTTONDBLCLK:
  833. toggle_title:
  834.             ClockDisp.bNoTitle = (ClockDisp.bNoTitle ? FALSE : TRUE );
  835.             SetMenuBar( hWnd );
  836.            break;
  837.         case WM_NCHITTEST:
  838.             /* if we have no title/menu bar, clicking and dragging the client
  839.              * area moves the window. To do this, return HTCAPTION.
  840.              * Note dragging not allowed if window maximized, or if caption
  841.              * bar is present.
  842.              */
  843.             wParam = DefWindowProc(hWnd, message, wParam, lParam);
  844.             if( ClockDisp.bNoTitle && (wParam == HTCLIENT) && !IsZoomed(hWnd) )
  845.                 return HTCAPTION;
  846.             else
  847.               return wParam;
  848.         case WM_SYSCOLORCHANGE:
  849.             DeleteTools();
  850.             CreateTools();
  851.             break;
  852.         case WM_ERASEBKGND: {
  853.             RECT rect;
  854.             GetClientRect(hWnd, (LPRECT)&rect);
  855.             SelectObject((HDC)wParam, hbrBackground);
  856.             FillRect((HDC)wParam, (LPRECT)&rect, hbrBackground);
  857.             break;
  858.         }
  859.         default:
  860. defproc:
  861.         return(DefWindowProc(hWnd, message, wParam, lParam));
  862.     }
  863.     return(0L);
  864. }
  865. /*
  866.  *  WinMain()
  867.  */
  868. INT PASCAL WinMain(
  869. HINSTANCE hInstance,
  870. HINSTANCE hPrev,
  871. LPSTR lpszCmdLine,
  872. INT cmdShow)
  873. {
  874. register HWND hWnd;
  875. MSG           msg;
  876. TIME          nTime;
  877. PSTR          szTooMany;
  878. HMENU         hMenu;
  879. CHAR          szTopmost[80];
  880.     LoadString(hInstance, IDS_USNAME, (LPSTR)szBuffer, BUFLEN);
  881.     LoadString(hInstance, IDS_INIFILE, (LPSTR)szIniFile, 20);
  882.     LoadString(hInstance, IDS_USNAME, (LPSTR)szSection, 30);
  883.     if (!ClockInit(hInstance))
  884.         return(FALSE);
  885.     ClockCreate((HWND)NULL);
  886.     LoadString(hInstance, IDS_APPNAME, (LPSTR)szBuffer, BUFLEN);
  887.     rCoordRect.top=GetPrivateProfileInt((LPSTR)szSection,
  888.                                          (LPSTR)"Top",
  889.                                          (DWORD)-1, (LPSTR)szIniFile);
  890.     rCoordRect.left=GetPrivateProfileInt((LPSTR)szSection,
  891.                                          (LPSTR)"Left",
  892.                                          (DWORD)-1, (LPSTR)szIniFile);
  893.     rCoordRect.right=GetPrivateProfileInt((LPSTR)szSection,
  894.                                          (LPSTR)"Right",
  895.                                          (DWORD)-1, (LPSTR)szIniFile);
  896.     rCoordRect.bottom=GetPrivateProfileInt((LPSTR)szSection,
  897.                                          (LPSTR)"Bottom",
  898.                                          (DWORD)-1, (LPSTR)szIniFile);
  899.     hWnd = CreateWindow((LPSTR)"Clock",    /* The class name.           */
  900.             (LPSTR)szBuffer,               /* The window instance name. */
  901.             WS_TILEDWINDOW,
  902.             (rCoordRect.left < 0) ? CW_USEDEFAULT : rCoordRect.left,
  903.             (rCoordRect.top  < 0) ? CW_USEDEFAULT : rCoordRect.top,
  904.             (rCoordRect.left < 0) ? (INT)( (HorzRes/3) + GetSystemMetrics(SM_CXFRAME)*2 )
  905.                   : rCoordRect.right - rCoordRect.left,
  906.             (rCoordRect.left < 0) ? (INT)( (((HorzRes/3)*aspectN)/aspectD)+GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME)*2 )
  907.                   : rCoordRect.bottom - rCoordRect.top,
  908.             NULL,
  909.             NULL,
  910.             hInstance,
  911.             (LPSTR)NULL);
  912.     hWindow=hWnd;
  913.     // Loop if control panel time being changed.
  914.     GetTime((TIME *)&nTime);
  915.     do {
  916.         GetTime((TIME *)&oTime);
  917.     } while (nTime.second == oTime.second && nTime.minute == oTime.minute &&
  918.            nTime.hour24 == oTime.hour24);
  919.     if (!SetTimer(hWnd, TimerID, OPEN_TLEN, 0L) )  {
  920.         /* Windows only supports 16 public timers */
  921.         szTooMany = (PSTR)LocalAlloc(LPTR, 160);
  922.         LoadString(hInstance, IDS_TOOMANY, (LPSTR)szTooMany, 160);
  923.         MessageBox((HWND)NULL, (LPSTR)szTooMany, (LPSTR)szBuffer, MB_OK | MB_ICONHAND | MB_SYSTEMMODAL);
  924.         DeleteTools();
  925.         return(FALSE);
  926.     }
  927.     /* Add the topmost system menu item */
  928.     hMenu = GetSystemMenu( hWnd, FALSE );
  929.     AppendMenu( hMenu, MF_SEPARATOR, 0, NULL );
  930.     LoadString(hInstance, IDS_TOPMOST, szTopmost, 79);
  931.     /* Check the default setting to the clock as topmost or not */
  932.     ClockDisp.bTopMost=GetPrivateProfileInt((LPSTR)szSection,
  933.                                          (LPSTR)"TopMost",
  934.                                          0, (LPSTR)szIniFile);
  935.     if( ClockDisp.bTopMost ) {
  936.         AppendMenu( hMenu, MF_ENABLED | MF_CHECKED | MF_STRING, IDM_TOPMOST,
  937.                     szTopmost );
  938.         SetWindowPos( hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  939.     }
  940.     else
  941.         AppendMenu( hMenu, MF_ENABLED | MF_UNCHECKED | MF_STRING, IDM_TOPMOST,
  942.                     szTopmost );
  943.     /* Check the default menu item either analog or digital */
  944.     CheckMenuItem(GetMenu(hWnd), ClockDisp.wFormat, MF_BYCOMMAND | MF_CHECKED);
  945.     /* Check the default setting to show title bar or not */
  946.     ClockDisp.bNoTitle=GetPrivateProfileInt((LPSTR)szSection,
  947.                                          (LPSTR)"NoTitle",
  948.                                          0, (LPSTR)szIniFile);
  949.     if( ClockDisp.bNoTitle ) {
  950.         SetMenuBar( hWnd );
  951.     }
  952.     hInst = hInstance;
  953.     /* Check the default minimized state, minimized or not */
  954.     ClockDisp.bMinimized=GetPrivateProfileInt((LPSTR)szSection,
  955.                                          (LPSTR)"Minimized",
  956.                                          0, (LPSTR)szIniFile);
  957.     if (!ClockDisp.bMinimized) {
  958.         ClockDisp.bMaximized=GetPrivateProfileInt((LPSTR)szSection,
  959.                                          (LPSTR)"Maximized",
  960.                                          0, (LPSTR)szIniFile);
  961.         if (ClockDisp.bMaximized)
  962.             ShowWindow(hWnd, SW_MAXIMIZE);
  963.         else {
  964.             ShowWindow(hWnd, cmdShow);
  965.             GetWindowRect(hWnd, (LPRECT)&rCoordRect);
  966.         }
  967.     }
  968.     else
  969.         ShowWindow(hWnd, SW_MINIMIZE);
  970.     DdeInitialize(&idInst, (PFNCALLBACK)MakeProcInstance((FARPROC)DdeCallback, hInstance),
  971.             CBF_FAIL_EXECUTES | CBF_SKIP_ALLNOTIFICATIONS, 0L);
  972.     hszTime = DdeCreateStringHandle(idInst, "Time", 0);
  973.     hszNow = DdeCreateStringHandle(idInst, "Now", 0);
  974.     hszClock = DdeCreateStringHandle(idInst, "Clock", 0);
  975.     DdeNameService(idInst, hszClock, 0L, DNS_REGISTER);
  976.     while (GetMessage((LPMSG)&msg, NULL, 0, 0) ) {
  977.         TranslateMessage((LPMSG)&msg);
  978.         DispatchMessage((LPMSG)&msg);
  979.     }
  980.     DdeUninitialize(idInst);
  981.     return(msg.wParam);
  982. }
  983. /*
  984.  *  GetTime()
  985.  */
  986. VOID GetTime(
  987. TIME *ptime)
  988. {
  989.     time_t t;
  990.     struct tm *ptm;
  991.     time(&t);
  992.     ptm = localtime(&t);
  993.     ptime->second = ptm->tm_sec;
  994.     ptime->minute = ptm->tm_min;
  995.     ptime->hour12 =
  996.     ptime->hour = ptm->tm_hour > 12 ? ptm->tm_hour - 12 : ptm->tm_hour;
  997.     ptime->hour24 = ptm->tm_hour;
  998.     ptime->ampm = ptm->tm_hour > 12 ? 1 : 0;
  999. }
  1000. /*
  1001.  *  DdeCallback()
  1002.  */
  1003. HDDEDATA CALLBACK DdeCallback(
  1004. WORD usType,
  1005. WORD usFmt,
  1006. HCONV hConv,
  1007. HSZ hsz1,
  1008. HSZ hsz2,
  1009. HDDEDATA hData,
  1010. DWORD lData1,
  1011. DWORD lData2)
  1012. {
  1013. static HANDLE           hToken;
  1014. static TOKEN_PRIVILEGES tp;
  1015. static LUID             luid;
  1016.     if (usType == XTYP_CONNECT) {
  1017.         return((HDDEDATA)TRUE);
  1018.     }
  1019.     if (usType == XTYP_WILDCONNECT) {
  1020.         HDDEDATA hData;
  1021.         HSZPAIR FAR *phszp;
  1022.         DWORD cb;
  1023.         if ((!hsz1 || hsz1 == hszTime) && (!hsz2 || hsz2 == hszClock)) {
  1024.             if ((hData = DdeCreateDataHandle(idInst, NULL,
  1025.                     2 * sizeof(HSZPAIR), 0L, 0, 0, 0))) {
  1026.                 phszp = (HSZPAIR FAR *)DdeAccessData(hData, &cb);
  1027.                 phszp[0].hszSvc = hszClock;
  1028.                 phszp[0].hszTopic = hszTime;
  1029.                 phszp[1].hszSvc = phszp[1].hszTopic = 0;
  1030.                 DdeUnaccessData(hData);
  1031.                 return(hData);
  1032.             }
  1033.         }
  1034.         return(0);
  1035.     }
  1036.     if (usFmt == CF_TEXT) {
  1037.         CHAR sz[40];
  1038.         if (usType == XTYP_ADVSTART || usType == XTYP_ADVSTOP) {
  1039.             return((HDDEDATA)TRUE);
  1040.         }
  1041.         if (hsz1 == hszTime && hsz2 == hszNow) {
  1042.             if (usType == XTYP_REQUEST || usType == XTYP_ADVREQ) {
  1043.                 itoa(oTime.hour, sz, 10);
  1044.                 strcat(sz, ":");
  1045.                 itoa(oTime.minute, &sz[strlen(sz)], 10);
  1046.                 strcat(sz, ":");
  1047.                 itoa(oTime.second, &sz[strlen(sz)], 10);
  1048.                 return(DdeCreateDataHandle(idInst, (LPBYTE)sz, strlen(sz) + 1, 0L,
  1049.                         hszNow, CF_TEXT, 0));
  1050.             }
  1051.             if (usType == XTYP_POKE) {
  1052.                 SYSTEMTIME SysTime;
  1053.                 DdeGetData(hData, (LPBYTE)sz, 40L, 0L);
  1054.                 GetLocalTime(&SysTime);
  1055.                 sscanf(sz, "%2d:%2d:%2d", &SysTime.wHour, &SysTime.wMinute, &SysTime.wSecond);
  1056.                 /* enable system-time privilege, set time, disable privilege */
  1057.                 OpenProcessToken( GetCurrentProcess(),
  1058.                   TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ;
  1059.                 LookupPrivilegeValue( NULL, "SeSystemTimePrivilege", &luid );
  1060.                 tp.PrivilegeCount           = 1;
  1061.                 tp.Privileges[0].Luid       = luid;
  1062.                 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  1063.                 AdjustTokenPrivileges( hToken, FALSE, &tp,
  1064.                   sizeof(TOKEN_PRIVILEGES), NULL, NULL );
  1065.                 SetLocalTime(&SysTime);
  1066.                 AdjustTokenPrivileges( hToken, TRUE, &tp,
  1067.                   sizeof(TOKEN_PRIVILEGES), NULL, NULL );
  1068.                 DdePostAdvise(idInst, hszTime, hszNow);
  1069.                 return((HDDEDATA)DDE_FACK);
  1070.             }
  1071.         }
  1072.     }
  1073.     return(0);
  1074.     UNREFERENCED_PARAMETER(lData1);
  1075.     UNREFERENCED_PARAMETER(lData2);
  1076.     UNREFERENCED_PARAMETER(hConv);
  1077. }