Ch 17 ¤å¦r

¤å¦rªº¤j¤p ( ÂI¼Æ )

¬Û«H¦U¦ìŪªÌ´¿¸g¨Ï¥Î¸ê·½´y­zÀɨӴy­z¹ï¸Ü²°ùتº±±¨î¤¸¥ó¦w±Æ¤è¦¡¡A¬Û«H¦U¦ìŪªÌ¤]¤w¸gª`·N¨ì¤F¡A¦b¹ï¸Ü²°ùتº¤å¦r¤j¤p¡A¨Ã¤£¬O¥H¹Ï¯À¬°³æ¦ì¡A¨º»ò¥¦»P¹Ï¯À¨s³º¦³¦óÃö«Y©O¡H¡C¨Æ¹ê¤W¤£¥u¬O¸ê·½´y­zÀÉùعï¸Ü²°ªº¦r§Î¤j¤p¡A¦b³\¦h¤å®Ñ³B²z³nÅé¡A¦p UltraEdit-32¡BWORD¡B°O¨Æ¥»µ¥³nÅ骺¦r§Î¤j¤p¡A¤]³£¤£¬O¥H¹Ï¯À¬°³æ¦ì¡C¨Ò¦p¤U¹Ï¬O¦b°O¨Æ¥»ùØ¡A¿ï¾Ü¡yCourier New¡z¦r«¬¡A¤j¤p¬°¡y10¡z¡A¦ý¬O¹ê»Ú¤W³o¨Ç¤å¦rªº¤j¤p¨Ã«D 10 ­Ó¹Ï¯Àªº¤j¤p ( ¦¹³Bªº¹Ï¯À¬O«ü pixel¡A¥Î¥H¥N´À¿Ã¹õ¤WªºÂI¡A¦Ó¤å¦rªº¤j¤p«h¥H¡yÂI¡zªí¥Ü¡A³o½g¤å³¹ùس£¿í¦u³o­Ó¬ù©w )¡C¥¦­Ì¦b¤p¤ì°¸ªº 19 ­^¤o²G´¹¿Ã¹õ¤W¤j¤p¬O 16¡Ñ16 ¹Ï¯À¤j¡A¤]¥i¥H»¡¡A§Ú¦pªG¿ï¾Ü¡y10¡zÂI¦r¡A¦ý¬O¦b¿Ã¹õ¤W«o¬O¥H 16 ­Ó¹Ï¯À¨Óªí¥Ü¡C

¦b Windows §@·~¨t²ÎùØ¡A¿Ã¹õ¤Wªº¤å®Ñ³B²zµ{¦¡¿ï¾Ü 10 ÂIªº¤å¦r¤j¤p®É¡A§Ú­Ì¤]·|§Æ±æ¦b¦C¦L®É¡A¦L¥Xªº¤å¦rÁÙ¬O 10 ÂIªí¥Ü¡C¦ý¬O§Ú­Ìª¾¹D¿Ã¹õªº¸ÑªR«×»P¦Lªí¾÷ªº¸ÑªR«×¬O¤£¦Pªº ( ¦¹³Bªº¸ÑªR«×¬O«ü¨C­^¤o¦³´X­Ó¹Ï¯À )¡A¤@¯ë²G´¹¿Ã¹õªº¸ÑªR«×¬O¨C­^¤o¬ù 86 ­Ó¹Ï¯À¡F¦ý¬O¹p®g¦Lªí¾÷¨C­^¤o«o¥i¹F 600 ¹Ï¯À¡A¨âªÌ¬Û®t¤F 7 ­¿¤§¦h( µù¤@ )¡A°²¦p Windows §@·~¨t²Îùتº¤å¦r¤j¤p 10 ÂI´N¬O¦b¿Ã¹õ¤Wªº 10 ­Ó¹Ï¯À¡A¤]¬O¦b¦Lªí¾÷¤Wªº 10 ­Ó¹Ï¯À¡A¨º»ò¦b¿Ã¹õ¤W¥i¥H«Ü²M·¡±o¿ëÃÑ 0.4 ¤½¤À°ª¡B0.4 ¤½¤À¼eªº¦r¡A¦b¦Lªí¾÷¦L¥X¨Óªº¦r¼e»P°ª«oÅܦ¨¤F 0.057 ¤½¤À ( 0.4¡Ò7¡Ü0.057 )¡A³o¼Ë¦L¥X¨Óªº¦r¤Ó¤p¤F¡A®Ú¥»¬Ý¤£²M·¡¡C

´«¥y¸Ü»¡¡A¦]¬°¹p®g¦Lªí¾÷ªº¸ÑªR«×¬O¨C­^¤o 600 ¹Ï¯À¡A¨ä¹Ï¯À«Ü¤p¡F¦Ó²G´¹¿Ã¹õ¸ÑªR«×¬O¨C­^¤o 86 ¹Ï¯À¡A¨ä¹Ï¯À¸û¤j¡C¤]´N¬O»¡¡A¹p®g¦Lªí¾÷ªº¨C­Ó¹Ï¯À¤j¤p¡A¤j¬ù¬O²G´¹¿Ã¹õªº¤C¤À¤§¤@¥ª¥k¡C¦pªG§@·~¨t²Î§â 10 ÂIªº¦r³£·í§@ 10 ­Ó¹Ï¯À¡A¦Ó¥B¦P®ÉÀ³¥Î¦b²G´¹¿Ã¹õ©Î¹p®g¦Lªí¾÷¤W¡A¨º»ò¦b¿Ã¹õ¤W¬Ý±o«Ü²M·¡ªº¦r¡A¦L¥X¨Ó´N·|¤p¨ìÁY¦¨¤@¹Î¦Ó¬Ý¤£²M·¡¡F©Î¬O¦Lªí¾÷¦L¥X¨Ó¾A·í¤j¤pªº¦r¡A¦b¿Ã¹õÅã¥Ü¤W«o¬O¤j¨ì¿Ã¹õ¤W¥u¯àÅã¥Ü´X­Ó¦r´N®e¯Ç¤£¤U¤F¡C

¥Ñ¥H¤Wªº»¡©ú¡A§Ú­ÌÀ³¸Ó¥i¥H©úÁA¡AÁöµM¦P¼Ë¬O 10 ÂI¦r¡A¦b¤£¦P¸ÑªR«×ªº©PÃä³]³Æ¤W©Ò¨Ï¥Îªº¹Ï¯À¦h¹è¬O¤£¦Pªº¡CµM¦Ó¡A¦b¤@¯ë¶Ç²Î¹]¦r¦L¨êùØ¡A¨C­^¤o¥i¥H®e¯Ç 72 ÂI¡A³o­Ó­È¬O¦b¹q¸£¡B¦Lªí¾÷µ¥¥¼µo©ú¤§«e´N¤w¸g¨Ï¥Î¤F¼Æ¦Ê¦~¡A¹q¸£µo©ú«á¡A§Ú­Ì¤]¿í¦u³o¶µ¶Ç²Î¡C©Ò¥H¦b¶Ç²Î¹]¦r¦L¨êùØ¡A10 ÂI¦rªº°ª«×¬O10/72­^¤o¡C§Ú­Ì¤]§Æ±æ¯à¦b¿Ã¹õ¤W¡A¯àÅã¥Ü 10 ÂI¦r¤]¬O10/72­^¤o¡A¬°¤F¹F¨ì³o­Ó¥Øªº¡A¦b Windows §@·~¨t²ÎùØ¡A§Ú­Ì¥i¥H¥Î GetDeviceCaps ¨Ó¨ú±o©PÃä¸Ë¸mªº¸ÑªR«×¡A¥Îªk¬O¡G

int GetDeviceCaps(
    HDC hdc,    // device-context handle 
    int nIndex  // index of capability to query  
   );

³o­Ó API ­º¥ý±o¨ú±o¸Ó©PÃä¸Ë¸mªº³]³Æ¤º®e ( device context )¡A¦pªG­n¨ú±o¤ô¥­¤è¦Vªº¸ÑªR«× ( ¦¹³Bªº¸ÑªR«×¬O¨C­^¤o¦³¦h¤Ö¹Ï¯À )¡AnIndex °Ñ¼Æ³]¬° LOGPIXELSX ¡F¦pªG­n¨ú±o««ª½¤è¦Vªº¸ÑªR«×¡A´N¨Ï nIndex ³]¬° LOGPIXELSY ¡A±µµÛ©I¥s GetDeviceCaps ´N¥i¥H¤F¡CnIndex °Ñ¼Æ¤£¥u³o¨â­Ó¡AÁÙ¥i¥H¥Î¨ä¥L°Ñ¼Æ¡A¨Ò¦p¥Î HORZRES¡BVERTRES ¥i¥H¨ú±o¤ô¥­¼e«×©M««ª½°ª«×¦³¦h¤Ö¹Ï¯À¡F¥Î HORZSIZE¡BVERTSIZE ¥i¥H¨ú±o¤ô¥­¼e«×©M««ª½°ª«×¦³¦h¤Ö²@¦Ìµ¥µ¥¡A¨ä¥LÁÙ¦³³\¦h¥Îªk¡A¥i¥H°Ñ¦Ò MSDN¡C

¦³¤F¥H¤WªºÆ[©À¤§«á¡A§Ú­Ì´N¥i¥Hºâ¥X¦b¤£¦P©PÃä¸Ë¸m¤¤¡A¤£¦P¤å¦rÂI­È©Ò¦û¥Îªº¹Ï¯À¤j¤p¡A³o­Ó­Èµ¥©ó¸Ó¤å¦r¦³¦h¤Ö­^¤o¡A¦A­¼¥H¸Ó©PÃä¸Ë¸mªº¸ÑªR«×¡F¦Ó¤å¦r¦³¦h¤Ö­^¤o´N¬O¸Ó¤å¦rªºÂI¼Æ°£¥H 72¡A¦pªG¥H¼Æ¾Ç¦¡ªí¥Ü¡A´N¬O¤U­±ªº¦¡¤l¡G

¤å¦r©Ò¦û¹Ï¯À¡×¨C­^¤o¹Ï¯À¡Ñ¤å¦r©Ò¦û­^¤o¼Æ¡×¨C­^¤o¹Ï¯À¡Ñ¤å¦rÂI¼Æ/72

¸U¦~¾äµ{¦¡

¤p¤ì°¸§Q¥Î¤W­±©Ò»¡ªº­ì²z¡A¼¶¼g¤@­Ó¸U¦~¾äµ{¦¡¡yperpetual calendar.asm¡z¡A¥¦¬O¤@­Ó¥H¹ï¸Ü²°¬°¥D­n¬É­±ªºµ{¦¡¡A¨Ï¥ÎªÌ¥i¥H«ö¥D¿ï³æùتº¡y©ñ¤j¡z©Î¡yÁY¤p¡z¿ï¶µ¨Ó©ñ¤j©ÎÁY¤p¦r§Î¡A¦Ó¦¹¹ï¸Ü²°¯à°÷¦Û°Ê­pºâ©Ò»Ýªº¤j¤p¡A½Õ¾ã¹ï¸Ü²°¤j¤p¡A¤£­P·|ºIÂ_«á­±ªº¤å¦r¡C

³o­Óµ{¦¡³B²z WM_INITDIALOG °T®§®É¡A¨ú±o¤F¤@¨Ç¸ê®Æ¡A¨Ò¦p¿Ã¹õ¼e«×¡B°ª«×¡B·í«e®É¶¡¡A¥H¤ÎÀRºA±±¨î¶µ¡B½s¿è®Ø¡B½Æ¦X®Ø¤Î¨â­Ó«ö¶sªº¥N½X¡A±µµÛ³Ì­«­nªº´N¬O©I¥s°Æµ{¦¡¡ACalcFont¡A¨Ó­pºâ¦r§Î¤j¤p¡C»P¨ú±o®É¶¡¦³Ãöªº API ¦³¨â­Ó¡A¤À§O¬O GetLocalTime ©M GetSystemTime¡A»¡©ú¦p¤U¡G

GetLocalTime ©M GetSystemTime API

¦b Win32 API ùØ¡A¥i¥H§Q¥Î GetSystemTime ¨ÓÀò±o¨t²Î®É¶¡¡A¦Ó³o­Ó¨t²Î®É¶¡´N¬O¨ó½Õ¥@¬É®É¶¡ ( Coordinated Universal Time¡AÁY¼g¦¨¡yUTC¡zµù¤G )¡F¦Ó GetLocalTime API ¬O¥Î¨ÓÀò±o·í¦aªº®É¶¡¡C§Ú­Ìªºµ{¦¡©I¥s³o¨â­Ó API ®É¡A±o§â SYSTEMTIME µ²ºcÅ骺¦ì§}¶Çµ¹¨t²Î¡A¦Ó¨t²Î·|§â SYSTEMTIME µ²ºcÅé¶ñ¦n¶Ç¦^¨Ó¡A¥¦­Ì³£¨S¦³¶Ç¦^­È¡A¨ä»yªk¬O¡G

VOID GetLocalTime(
    LPSYSTEMTIME lpSystemTime   // address of system time structure  
   );

SYSTEMTIME µ²ºcÅ骺¦UÄæ¦ì¤j¤p³£¬O¤@­Ó¦r²Õ¡A³o»P¨ä¥L Win32 ¨Ï¥ÎªºÅܼơB±`¼Æ¤j¤p¤£¦P¡A³o¥i¯à¬O¦]¬°ªí¥Ü®É¶¡¥H¦r²Õ¨Óªí¥Ü¡A´Nºïºï¦³¾l¤F ( ¦r²Õ¥i¥Hªí¥Ü 0¡ã65535 ªº½d³ò )¡C©³¤U¬O SYSTEMTIME µ²ºcÅ骺¦UÄæ¦ì·N¸q¡G

SYSTEMTIME      STRUC
wYear           WORD    ?       ;¦è¤¸¦~¥÷ 
wMonth          WORD    ?       ;¤ë¡A1 ¬°¤@¤ë¡B2 ¬°¤G¤ë¡B3 ¬°¤T¤ë¡K¡K
wDayOfWeek      WORD    ?       ;¬P´Á´X¡A0 ¬°¬P´Á¤é¡B1 ¬°¬P´Á¤@¡B2 ¬°¬P´Á¤G¡K¡K
wDay            WORD    ?       ;¤é
wHour           WORD    ?       ;®É¡A±Ä¥Î 24 ®É¨î¡A¥Ñ 0¡ã23
wMinute         WORD    ?       ;¤À
wSecond         WORD    ?       ;’
wMilliseconds   WORD    ?       ;²@¬í¡A±q 0¡ã999
SYSTEMTIME      ENDS

±µ¤U¨Ó¡A¦b WM_INITDIALOG °T®§ùØ©I¥s CalcFont °Æµ{¦¡¡A³o­Ó°Æµ{¦¡°µ¤F¥|¥ó¨Æ¡C²Ä¤@¬O¨Ì¾Ú¦r§Îªº¤j¤p¡AdwDlgFontSize¡Aºâ¥X¦rÅ骺°ª«×¦û¦³´X­Ó¹Ï¯À¡A¦s¤J dwFontHigh¡AµM«á¨Ì¾Ú dwFontHigh ©I¥s CreateFont «Ø¥ßÅÞ¿è¦r§Î¡A¦A¥Î GetTextMetrics ¨ú±o¦r§Î¼e«×¦û¦³´X­Ó¹Ï¯À¡A¦s¤J dwFontWidth ÅܼơC³o¼Ë¡Aµ{¦¡´N¤w¸g¨ú±o¦r§Îªº°ª«×»P¼e«×¦³¦h¤Ö¹Ï¯À¡C°²¦p¨Ï¥ÎªÌ§ó°Ê¤F¦r§Î¤j¤p¡A¨º»ò´N·|¼vÅT¾ã­Óµøµ¡ª©­±¡A¥]§t¦U±±¨î¶µªº¤j¤p¤Î¦U±±¨î¶µ¦b¹ï¸Ü²°ªº¦ì¸m³£·|§ïÅÜ¡A³o¥ó¨Æ¥Ñ©I¥s CalcCtlPosi °Æµ{¦¡§¹¦¨¡A³o¬O CalcFont °Æµ{¦¡ªº²Ä¤G¶µ¤u§@¡CCalcFont °µªº²Ä¤T¥ó¨Æ¬O¨Ì¾Ú¦r§Î¤j¤p¡A­pºâ¹ï¸Ü²°ªº¤j¤p¤Î§â¹ï¸Ü²°²¾¨ì¿Ã¹õ¤¤¥¡¡CCalcFont °Æµ{¦¡ªº³Ì«á¤@¶µ¤u§@«K¬O§â·s«Ø¥ß§¹¦¨ªºÅÞ¿è¦r§Î¿ï¤J¦U±±¨î¶µùØ¡C

WM_SETFONT

¦¹³B­È±o¤@´£ªº¬O¡A­n§ïÅܹï¸Ü²°ùتº¦r§Î¡A¥i¥H¥Î SelectObject¡F¦ý³o¤@©Û¦ü¥G¹ï±±¨î¶µµL®Ä¡A§Y¨Ï¤p¤ì°¸´¿¸g¨ú±o±±¨î¶µªº¸Ë¸m¤º®e¥N½X¡A¦A¥H SelectObject §ïÅܨä¦r§Î¤]µLªk¦¨¥\¡C¤£¹L§Ú­ÌÁÙ¬O¥i¥HÂÇ¥Ñ SendMessage µo°e WM_SETFONT °T®§µ¹¬Y­Ó±±¨î¶µ¡A¨Ï¨äÅܧó¦r§Î¡A¦¹®É wParam ¬O¦r§Î¥N½X¡AlParam ¬O¥Î¨Ó«ü¥Ü±±¨î¶µ¦b§ïÅܦr§Î«á¬O§_¥ß§Y­«Ã¸¦r§Î¡ATRUE ªí¥Ü¥ß§Y­«Ã¸¡AFALSE ªí¥Ü§_¡C¨ì¦¹ºâ¬O¤w³B²z§¹ WM_INITDIALOG °T®§¡C

·í¨Ï¥ÎªÌ«ö¤U¥D¿ï³æ¤¤ªº¡yÁY¤p¡z©Î¡y©ñ¤j¡z¿ï¶µ®É¡AdwDlgFontSize ·|¦b 8 ¨ì 24 ªº½d³ò¤ºÀH¤§´î¤@©Î¼W¤@¡A±µµÛ©Ò°µªº¨Æ«K¬O©I¥s CalcFont °Æµ{¦¡­«­«·s­pºâ¦rÅé°ª«×¡B­pºâ¦U±±¨î¶µ¤j¤p¤Î¦ì¸m¡B­pºâ¹ï¸Ü²°¤j¤p¨Ã²¾¦Ü¿Ã¹õ¤¤¥¡¡B¹ï¹ï¸Ü²°¿ï¤J·sªºÅÞ¿è¦r§Î³o¥|¥ó¨Æ¡A³Ì«á¬O©I¥s InvalidateRect ³]©w¹ï¸Ü²°»Ý­n­«·sø¹Ï¡C

µM«á¦b WM_PAINT °T®§ùØ¡A©I¥s DrawCalendarTbl °Æµ{¦¡¡A³B²zø¥X¸Ó¤ë¥÷ªº¤ë¾ä¡C¦b¦¹¤ë¾äªº²Ä¤@¦C ( ¥Ñ¥ª¦Ó¥kºÙ¬°¦C ) ¬O¬P´Á¡y¤é¡B¤@¡B¤G¡K¡K¡zµ¥¤å¦r¡A³o¨Ç¤å¦r¥H­I´º¬°¶À¦â¡A·í°µÄæ¦ì¡C¦p¤U¹Ï©Ò¥Ü¡A¨C­Ó¤å¦r³£¬O¥H DrawText ¿é¥X¦Ü³]³Æ¤º®e¡G

¸U¦~¾ä¤ë¾äªí®æ»¡©ú¤å¦r®Ø¡B¶¡¹j¶ZÂ÷

¥Ñ¤W¹Ï¤¤¯à°÷¬Ý±o¥X¨Ó¡A¨C­Ó°Åµô¯x§Î¥ª¤W¨¤¤ô¥­¤è¦V¬Û¶Z¨â­Ó¦r¤¸ªº¼e«× ( ¹Ï¤¤ w ªí¥Ü¤@­Ó¦r¤¸¼e )¡A¦Ó¤W¤U¤è¦V«h¬O¬Û¶Z¤@­Ó¥b¦r¤¸¼e«× ( ¹Ï¤¤ h ªí¥Ü¤@­Ó¦r¤¸°ª )¡A

DrawText API

DrawText ¬O¥Î¨Ó§â¦r¦ê¥H«ü©wªº¤è¦¡Åã¥Ü¦b¬Y­Óªº°Ï°ì¤º¡A¨ä­ì«¬¬°¡G

int DrawText(
    HDC     hDC,        // handle to device context
    LPCTSTR lpString,   // pointer to string to draw
    int     nCount,     // string length, in characters
    LPRECT  lpRect,     // pointer to structure with formatting dimensions
    UINT    uFormat     // text-drawing flags
   );

DrawText ·|§â¦r¦êÅã¥Ü¦b°Åµô¯x§Îªº²Ä¤@¦æ¡A¦pªG¦r¦ê§t¦³´«¦æ¦r¤¸ ( linefeed ) ¤ÎÂk¦ì¦r¤¸ ( carriage return )¡A¨º»ò´N·|´«¨ì¤U¤@¦æÄ~ÄòÅã¥Ü¡A§Ú­Ì¥i¥H¥Î DT_LEFT¡BDT_RIGHT¡BDT_CENTER «ü©w¦V¥ª¡B¥k¡B¤¤¶¡¹ï»ô¡A·í DrawText ´«¦æ®É¡A¨C¦æ°ª«×¬O tmHeight¡A¦æ¶Z¤£¥]§t tmExternalLeading ( °Ñ¦Ò TEXTMETRIC µ²ºcÅé )¡A¦pªG­n¦æ¶Z¥]§t¥~³¡¶¡¶Z¡A¥i¥H¨Ï¥Î DT_EXTERNALLEADING¡C

uFormat °Ñ¼Æ¥i¥H¥Î DT_SINGLELINE Åã¥Ü¤@¦æ¦r¦ê¡A§Y¨Ï¦r¦ê¥]§t´«¦æ©ÎÂk¦ì¦r¤¸¡ADrawText ¤]·|§â³o¨â­Ó¦r¤¸·í°µ¤@¯ë¤å¦rÅã¥Ü¦b¿Ã¹õ¤W¡C¦b¦³ DT_SINGLELINE ªº±¡§Î¤U¡A¤]¥i¥H·f°t DT_TOP¡BDT_BOTTOM¡BDT_VCENTER ¨Ó¨Ï¦r¦ê¦ì©ó°Åµô¯x§Îªº³»ºÝ¡B©³ºÝ©Î««ª½ªº¤¤¶¡¡A¤º©w­È¬O DT_TOP¡C¤p¤ì°¸³o­Ó¸U¦~¾äµ{¦¡§â¬P´Á¡y¤é¡B¤@¡B¤G¡K¡K¡zµ¥¤å¦r¤À¤C¦¸©I¥s DrawText¡A¨C­Ó°Åµô¯x§Î¼e«×¬O¤@­Ó¥b¦r¤¸¼e ( ¹Ï¤¤¥H w ªí¥Ü¤@­Ó¦r¤¸¼e¡A¥H h ªí¥Ü¤@­Ó¦r¤¸°ª¡A¹Ï¤¤¤]¥HÂŦâ¯x§Î¼Ð¥Ü°Åµô¯x§Î¡A¦Ó°Åµô¯x§ÎùØ­±ªººñ¦â¯x§Î¬O¤å¦r®Ø )¡A¦Ó¤å¦r«h¬OÅã¥Ü¦b°Åµô¯x§Î¤¤¥¡ ( ¨Ï¥Î¤F DT_CENTER )¡A©Ò¥H¦b¤å¦r¨âÃä¦U¯d¦³¥|¤À¤§¤@¼e¦r¤¸¡C

¤£ºÞ¬O¦h¦æ©Î³æ¦æ¦r¦ê¡A¦pªG°Åµô¯x§Îªº¼e«×¤Ó¤p©Î¦r¦ê¤Óªø¡A³£·|¨Ï¦r¦ê¥kÃä³QºI±¼¡A³o®É uFormat ¥i¨Ï¥Î DT_NOCLIP¡A¨Ï¦r¦ê¤£¨ü°Åµô¯x§Îªº­­¨î¦Ó¶W¥X°Åµô¯x§Î¡F¦]¬° DT_NOCLIP ¤£¶·­pºâ°Åµô¯x§Îªº½d³ò¡A©Ò¥HÅã¥Ü³t«×·íµM·|¥[§Ö¡C¦ý¦pªG·Q­n¦b°Åµô¯x§Îªº½d³ò¤º¡A§â¶W¥Xªº³¡¥÷¤@¨ì¤U¤@¦æÅã¥Ü¡A¥i¥H¨Ï¥Î DT_WORDBREAK¡C

DrawText ÁÙ·|§â¡y&¡z¦r¤¸µø¬°«e¸m¦r¤¸¡A¦b¦¹¦r¤¸¤§«áªº¦r¥[¤W©³½u¡A¦Ó¤£·|Åã¥Ü¡y&¡z¡F¦pªG­nÅã¥Ü¡y&¡z¦r¤¸±o¨Ï¥Î¡y&&¡z¡C©ó¬O¦³©³¤U¤TºØ¥Îªk¡G

  1. DT_NOPREFIX¡G©¿²¤«e¸m¦r¤¸¡A§â¡y&¡z¦r¤¸·í¦¨´¶³q¦r¤¸¬Ý«Ý¡C¨Ò¦p¦³¤@­Ó¦r¦ê¬O¡yA&BC&&D¡z¡ADrawText ·|Åã¥Ü¬°¡yABC&D¡z¡F¦ý¬O¦pªG¥[¤W DT_NOPREFIX¡A¨º»ò DrawText ·|Åã¥Ü¬°¡yA&BC&&D¡z¡C
  2. DT_HIDEPREFIX¡GÁôÂëe¸m¦r¤¸¡A·|§â¡yA&BC&&D¡zÅã¥Ü¬°¡yABC&D¡z¡C
  3. DT_PREFIXONLY¡G¥u·|¦b±µµÛ¡y&¡z«áªº¦r¤¸µe¥X©³½u¡A¦Ó¤£·|Åã¥Ü¥X¨ä¥L¦r¤¸¡A¨Ò¦p·|§â¡yA&BC&&D¡zÅã¥Ü¬°¡y    ¡z¡C

¦pªG uFormat ¨Ï¥Î¤F DT_CALCRECT¡A¨º»ò DrawText ¨Ã¤£·|§â¦r¦êµe¥X¨Ó¡A¦Ó¬O­pºâ©Ò»Ý­nªº°Åµô¯x§Î³Ì¤pªº¤j¤p¡AµM«á¶ñ¤J lpRect ©Ò«üªº RECT µ²ºcÅ餺¡A³o­Ó¥\¯à¥i¥H¦b¤£ª¾°Åµô¯x§Îªº¤j¤p®É¨Ï¥Î¡A¥ý¨Ï¥Î DT_CALCRECT ¬°°Ñ¼Æ©I¥s DrawText ­pºâ¦n°Åµô¯x§Î¤§«á¡A¦A©I¥s¤@¦¸ DrawText ¯u¥¿ªºÃ¸¥X¤å¦r¨Ó¡Aºâ«Ü±`¥Îªº¥\¯à¡C°²¦p³o­Ó¦r¦ê¬O¤@¦æªº¤å¦r¡A¨º»òµ{¦¡³]­p®vÀ³¥ý³]©w¦n°Åµô¯x§Îªº¥ª¤W¨¤®y¼Ð¡A¥ç§Y­n¥ý¶ñ¦n top ©M left Äæ¦ì¡AµM«á¥H DT_CALCRECT or DT_SINGLELINE ©I¥s DrawText¡ADrawText ªð¦^®É·|§â°Åµô¯x§Îªº bottom ©M right ¶ñ¦n¡C°²¦p³o­Ó¦r¦ê¬O¦h¦æ¤å¦r¡A¨º»òµ{¦¡³]­p®v°£¤F top ©M left ­n¥ý¶ñ¦n¥~¡AÁÙ±o«ü©w right¡A§@¬°¨C¤@¦Cªº¼e«×¡A³o¼Ë DrawText ¤~¯à¨M©w¦¹¦r¦ê¦û¦³´X¦C¤å¦r¡A¶i¦Ó¨M©w°Åµô¯x§Îªº°ª«×¡A¦Ó¶Ç¦^ªº bottom ¼Æ­È¬O°Åµô¯x§Î°ª«×¥[¤W­ì¥ý³]©wªº top¡C

DrawText Áö¥i¥H³B²z³\¦hºØª¬ªpªº¦r¦ê¡A¦ý¬O¤´µMµLªk§ïÅܤå¦rÃC¦â¥H¤Î¤å¦r®Øªº­I´ºÃC¦â¡C¦b Windows ¨t²ÎùØ¡A­n§ïÅܤå¦rÃC¦â¶·¨Ï¥Î SetTextColor ¡A­n§ïÅܤå¦r®Øªº­I´ºÃC¦â¡A¥i¥H¥Î SetBkColor¡C½Ð°Ñ¦Ò¤W¹Ï¡ASetBkColor ¥u¯à§ïÅܤå¦r®Ø ( ¥Hºñ¦â¯x§Î®Ø¦íªº³¡¥÷ ) ªº­I´ºÃC¦â¡A¦Ü©ó¤å¦r®Ø¥~ªº³¡¥÷¥²¶·¥t¥~³]ªk¡C¦b¸U¦~¾ä³o­Óµ{¦¡ùØ¡A¤p¤ì°¸¨Ï¬P´Á¡y¤é¡B¤@¡B¤G¡K¡K¡zµ¥¤å¦r­I´º³]¬°¶À¦â¡A¥H¥YÅ㥦­Ì¬OÄæ¦ì¡A³oùؤp¤ì°¸¬Oµe¥X¤@­Ó¶ñº¡¶À¦âªº¯x§Î¡AµM«á¦A¥H SetBkColor ³]©w¤å¦r®Ø­I´º¬°¶À¦â¡C¶¶±a¤@´£¡A­n¨ú±o¤å¦r®Øªº­I´ºÃC¦â¡A¥i¥H¥Î GetBkColor¡C

±ýµe¥X¤@­Ó¶ñº¡ªº¶À¦â¯x§Î¡A¥i¥H¥Î FillRect API¡A¦b¦¹¤§«e¡A±o¥ý¥Î CreateSolidBrush «Ø¥ß¤@­Ó¶À¦âªºµ§¨ê¡ACreateSolidBrush ·|¶Ç·|¤@­Óµ§¨ê¥N½X¡F±µµÛ¦A¥Î SelectObject ¿ï¾Ü¦¹µ§¨ê¡AFillRect ´N·|¥H³o­Óµ§¨ê¶ñº¡¯x§Î¡C

SetBkMode

°²¦p¤w¸g¦b¬P´Á¡y¤é¡B¤@¡B¤G¡K¡K¡zµ¥Äæ¦ì¤Wµe¤W¶îº¡ÃC¦âªº¶À¦â¯x§Î¡A§Ú­Ì¤]¥i¥H³]©w­I´º¼Ò¦¡¬°³z©úªº¡A³o¼Ë¨t²Î´N¤£·|§â¤å¦r®Øªº­I´º¶îº¡ÃC¦â¡C¨Æ¹ê¤W­I´º¼Ò¦¡¥u¦³¨âºØ¥i¥H¿ï¾Ü¡GTRANSPARENT¡BOPAQUE¡A«eªÌ¬O³z©ú¼Ò¦¡¡A«áªÌ¬O¥H²{¦bªº­I´ºÃC¦â§â¤å¦r®Ø¶îº¡¡CSetBkMode »yªk¬O¡G

SetBkMode(
    HDC hdc,            // handle of device context
    int iBkMode         // flag specifying background mode
   );

·í Windows ¦b³]³Æ¤º®eø¥X¤å¦r®É¡A¬O¥H¤º©wªºµeµ§Ã¸¥X¤å¦rªº«e´ºÃC¦â¡A¤]¥Î¤º©wªºµ§¨êø¥X­I´ºÃC¦â¡C¦p¤W¹Ï©Ò¥Ü¡A¬O¤ë¾äªº²Ä¤@¦C¬P´Á¡y¤é¡B¤@¡B¤G¡K¡K¡zªº©ñ¤j¹Ï¡C¤å¦rªº«e´ºÃC¦â¬O¥Î³]©w¡A­n¦Ó¥t¥~ÁÙ¦³¤@­Ó¤èªk¡A¥i¥H³]©w¤å¦r®Øªº­I´º¬°³z©ú¼Ò¦¡¡A³o¼Ë¤å¦r®ØªºÃC¦â¤£·|Åã¥Ü¥X¨Ó¡A´N¥u·|Åã¥Ü¥X¹ï¸Ü²°ªºÃC¦â¡C©³¤Uªº SetBkMode ´N¬O¥Î¨Ó³]©w­I´º¼Ò¦¡¡C

­ì©l½X

©³¤U¬O perpetual_calendar.asm ªº­ì©l½X¡G

;perpetual calendar¸U¦~¾ä¡G¦¹µ{¦¡§Q¥Î¼Ò¦¡¹ï¸Ü²°¬°¬É­±ªºÀ³¥Îµ{¦¡
;¡@¡@¡@¡@¡@¡@¡@¡@¡@¡@¡@¡@¡@¿é¤J¦è¤¸´X¦~´X¤ë¡A·|§â¸Ó¤ëªº¤ë¾ä¦L¦b¤u§@°Ï
        .586
        .model  flat,stdcall
        option  casemap:none

include         windows.inc
include         user32.inc
include         kernel32.inc
include         gdi32.inc
includelib      user32.lib
includelib      kernel32.lib
includelib      gdi32.lib

IDC_EDIT        equ     100
IDC_COMBOBOX    equ     101
IDC_STATIC0     equ     102
IDC_STATIC1     equ     103
IDC_STATIC2     equ     104
IDC_BUTTON0     equ     105
IDC_BUTTON1     equ     106
IDM_EXIT        equ     107
IDM_LARGE       equ     108
IDM_SMALL       equ     109
IDM_CLEAR       equ     110
IDM_HELP        equ     111

DLGFONTSIZE     equ     12
FIELDBKCOLOR    equ     0ffffh  ;Äæ¦ì­I´ºÃC¦â¶À¦â
TODAYBKCOLOR    equ     0ff00h  ;¤µ¤éªº­I´º¥Hºñ¦âªí¥Ü

;*******************************************************************************
.const
dwHalf          DWORD   0.5
wTen            WORD    10
w72             WORD    72
szDlgName       BYTE    'CalendarDlg',0
szFontFace      BYTE    '·s²Ó©úÅé',0
szMonth         BYTE    '¤@',0,'¤G',0,'¤T',0,'¥|',0,'¤­',0,'¤»',0
                BYTE    '¤C',0,'¤K',0,'¤E',0,'¤Q',0,'¤Q¤@',0,'¤Q¤G',0
szWeek          BYTE    '¤é',0,'¤@',0,'¤G',0,'¤T',0,'¥|',0,'¤­',0,'¤»',0
szFmt0          BYTE    '%04d',0
szFmt1          BYTE    '%2d',0
szFmt2          BYTE    '²{¦b±z¿ï¥Îªº¦r§Î¤j¤p¬° %2d ÂI¡C',0
nDayOfMonth     BYTE    31,28,31,30,31,30,31,31,30,31,30,31
szIcon          BYTE    'CalendarIcon',0
szTitle         BYTE    '²{¦b¦r§Î¤j¤p',0

;*******************************************************************************
.data
hInstance       HINSTANCE       ?
hDialog         HANDLE          ?
hEdit           HANDLE          ?
hComboBox       HANDLE          ?
hBtn0           HANDLE          ?               ;¡y¬d¸ß¡z«ö¶sªº¥N½X
hBtn1           HANDLE          ?               ;¡yÂ÷¶}¡z«ö¶sªº¥N½X
hStatic0        HANDLE          ?               ;ÀRºA±±¨î¶µ¡y¦è¤¸¡zªº¥N½X
hStatic1        HANDLE          ?               ;ÀRºA±±¨î¶µ¡y¦~¡zªº¥N½X
hStatic2        HANDLE          ?               ;ÀRºA±±¨î¶µ¡y¤ë¡zªº¥N½X
hNewFont        HFONT           ?
dwDlgFontSize   DWORD           DLGFONTSIZE     ;²Ä´X¸¹¦rÅé¡A¬Û·í©óOFFICEùتº¦r«¬¤j¤p
dwFontHigh      DWORD           ?               ;¦rÅé°ª«×¡A¥H¹Ï¯À¬°³æ¦ì
dwFontWidth     DWORD           ?               ;¦rÅé¼e«×¡A¥H¹Ï¯À¬°³æ¦ì
dwScrWidth      DWORD           ?               ;¿Ã¹õ¼e«×¡A¥H¹Ï¯À¬°³æ¦ì
dwScrHigh       DWORD           ?               ;¿Ã¹õ°ª«×¡A¥H¹Ï¯À¬°³æ¦ì
ptCalendarTbl   POINT           
rectText        RECT            
stLocTime       SYSTEMTIME      
ps              PAINTSTRUCT     
tm              TEXTMETRIC      
szBuffer        BYTE    40 dup (0)
;*******************************************************************************
.code
;-------------------------------------------------------------------------------
;¨D¦è¤¸EAX¦~ECX¤ë¤@¤é¬O¬P´Á´X
;ªð¦^®ÉEAX=¬P´Á´X
CalculateDate   PROC    USES ebx esi
                LOCAL   m:DWORD
                mov     esi,eax ;«O¦s¦~©óESIùØ
                mov     eax,14
                sub     eax,ecx
                sub     edx,edx
                mov     ebx,12
                div     ebx     ;EAX=a=int((14-month)/12)
                sub     esi,eax
                mul     ebx
                sub     eax,2
                add     eax,ecx
                mov     ebx,100
                mov     m,eax   ;EAX=month+12a-2
                mov     eax,esi
                div     ebx
                mov     esi,eax ;C=¥@¬ö=(year-a)ªº¤d¦ì¼Æ»P¦Ê¦ì¼Æ
                shr     esi,2
                shl     eax,1
                sub     esi,eax
                add     esi,edx
                shr     edx,2
                inc     esi
                add     esi,edx ;ESI=C/4-2C+Y+Y/4+D
                mov     eax,m
                mov     ecx,m
                shl     ecx,2
                add     eax,ecx
                mov     ebx,5
                shl     ecx,1
                sub     edx,edx
                add     eax,ecx
                dec     eax     ;EAX=13m-1
                div     ebx
                mov     ecx,7
                xor     edx,edx
                add     eax,esi ;EAX=C/4-2C+Y+Y/4+D+int((13m-1)/5)
@@:             cmp     eax,0
                jge     positive
                add     eax,ecx
                jmp     @b
positive:       div     ecx
                xchg    eax,edx
                ret
CalculateDate   ENDP
;-------------------------------------------------------------------------------
;³]©w¦n¤å¦rÃC¦â»P°Åµô¯x§Î¡A¨C­Ó¤¤¤å¦rªº°Åµô¯x§Î¬O¤@­Ó¥b¦r¤¸¼e¡B¤@­Ó¦r¤¸°ª
CalcTextRect    PROC    hdc:HDC,dwWeek:DWORD
    .IF dwWeek==0
                invoke  SetTextColor,hdc,0ffh           ;¬P´Á¤é¤å¦r¬õ¦â
    .ELSEIF dwWeek==6
                invoke  SetTextColor,hdc,0ff0000h       ;¬P´Á¤»¤å¦rÂŦâ
    .ELSE
                invoke  SetTextColor,hdc,0              ;¶Â¦â
    .ENDIF
                mov     ecx,dwFontWidth
                shl     ecx,1
                mov     eax,dwWeek
                mul     ecx
                add     eax,ptCalendarTbl.x
                mov     rectText.left,eax
                add     ecx,dwFontWidth         ;ECX=¤@­Ó¥b¦r²Õ¼e
                mov     rectText.right,eax
                shr     ecx,1
                add     rectText.right,ecx
                ret
CalcTextRect    ENDP
;-------------------------------------------------------------------------------
DrawCalendarTbl PROC    hdc:HDC
                LOCAL   dwWeek:DWORD            ;¬P´Á¤é¡G0¡A¬P´Á¤@¡G1¡A¬P´Á¤G¡G2¡A¡K¡K¬P´Á¤»¡G6
                LOCAL   dwYear:DWORD,dwMonth:DWORD,dwDay:DWORD
                LOCAL   nMaxDay:DWORD           ;¸Ó¤ë¦³´X¤Ñ
                LOCAL   colorTextBk:DWORD

;³]©w¶ñº¡¶À¦âªº¯x§Î¤j¤p¡A¦s¤JrectTextùØ¡A¦¹¯x§Î¥ª¤W¨¤¦bptCalendarTbl³B¡A¼e13­Ó¥b¦r¤¸¡A¤@­Ó¦r¤¸°ª
                mov     edx,dwFontWidth
                mov     eax,edx
                mov     ecx,edx
                shl     edx,3
                shl     eax,2
                add     edx,ecx
                add     edx,eax
                shr     ecx,1
                add     edx,ecx                 ;EDX=13­Ó¥b¦r¤¸¼e
                mov     eax,ptCalendarTbl.x
                mov     rectText.left,eax
                add     edx,eax
                mov     rectText.right,edx
                mov     ecx,ptCalendarTbl.y
                mov     rectText.top,ecx
                add     ecx,dwFontHigh
                mov     rectText.bottom,ecx

;µe¥X¬P´Á¡y¤é¡z¡B¡y¤@¡z¡ã¡y¤»¡zªºÄæ¦ìªº­I´ºÃC¦â¡A§Y¶ñº¡¶À¦âªº¯x§Î
                invoke  CreateSolidBrush,FIELDBKCOLOR
                push    eax
                invoke  SelectObject,hdc,eax
                invoke  DeleteObject,eax
                pop     edx
                invoke  FillRect,hdc,OFFSET rectText,edx

;µe¥X¬P´Á¡y¤é¡z¡B¡y¤@¡z¡ã¡y¤»¡zªºÄæ¦ì¦W
                invoke  SelectObject,hdc,hNewFont
                invoke  DeleteObject,eax
                invoke  SetBkColor,hdc,FIELDBKCOLOR
                mov     dwWeek,0
                mov     edx,ptCalendarTbl.y
                mov     rectText.top,edx
                add     edx,dwFontHigh
                mov     rectText.bottom,edx
@@:             invoke  CalcTextRect,hdc,dwWeek
                mov     ecx,dwWeek
                shl     ecx,1
                add     ecx,dwWeek
                add     ecx,OFFSET szWeek
                invoke  DrawText,hdc,ecx,-1,OFFSET rectText,DT_CENTER or DT_VCENTER or DT_SINGLELINE
                mov     ecx,dwFontWidth
                inc     dwWeek
                shl     ecx,2
                add     rectText.left,ecx
                cmp     dwWeek,7
                jb      @b

;³]©w¤å¦r­I´ºÃC¦â»P¹ï¸Ü²°­I´º¦P¦â
                invoke  GetSysColor,COLOR_BTNFACE       ;¨ú±o¹ï¸Ü²°­I´º¦â
                mov     colorTextBk,eax
                invoke  SetBkColor,hdc,eax

;¥Ñ½s¿è®Ø¡B½Æ¦X®Ø¤À§O¨ú±o¦è¤¸´X¦~´X¤ë¡A¨Ã­pºâ¸Ó¤ëªº¤@¤é¬O¬P´Á´X
                invoke  GetDlgItemInt,hDialog,IDC_EDIT,NULL,FALSE
                mov     dwYear,eax
                invoke  SendMessage,hComboBox,CB_GETCURSEL,0,0
                mov     dwMonth,eax
                mov     ecx,eax
                inc     ecx
                mov     eax,dwYear
                call    CalculateDate   ;­pºâ¬P´Á´X¡A¶Ç¦^©óEAX
                mov     dwWeek,eax      ;¬P´Á¤é¡G0¡A¬P´Á¤@¡G1¡A¡K¡K

;­pºâ¸Ó¤ë¦³´X¤Ñ¡A¨Ã¦s©ónMaxDay
                mov     ecx,dwMonth
                movzx   edx,nDayOfMonth[ecx]
                mov     nMaxDay,edx
    .IF ecx==1                          ;Àˬd¤G¤ë¥÷ªº¤Ñ¼Æ
                mov     eax,dwYear      ;­Y¬°¶|¦~«h¤G¤ë¦³29¤Ñ¡AnMaxDay=29
                and     eax,011b        ;§_«h¬°¥­¦~¡A¤G¤ë¦³28¤Ñ¡AnMaxDay=28
                jnz     ok
                xor     edx,edx
                mov     ecx,100
                mov     eax,dwYear
                div     ecx
        .IF edx==0
                mov     eax,dwYear
                mov     ecx,400
                div     ecx
                or      edx,edx
                jz      leap_year
        .ELSE
leap_year:      inc     nMaxDay
        .ENDIF
    .ENDIF

;µe¥X¤ë¾äªí®æ
ok:             mov     dwDay,1         ;¨C­Ó¤ë¥Ñ¤@¤é¶}©l¨ìnMaxDay¤î
                mov     ecx,ptCalendarTbl.y
                mov     rectText.top,ecx
next_week:      mov     eax,dwFontHigh ;¨C¤@¦C(¥Ñ¥ª¦Ó¥k)¥Nªí¤@­Ó¬P´Á
                shl     eax,1          ;¨C¦C¤§¶¡¬Û¹j¥b­Ó¦r¤¸°ª¡A¦A¥[¤W¨C¦C¤@­Ó¦r¤¸°ª
                add     eax,dwFontHigh ;¡A¬G¨C¦C¤å¦r¯x§Î¥ª¤W¨¤­n¥[¤W¤@­Ó¥b¦r¤¸°ª¡A¤~
                shr     eax,1          ;¬O¤U¤@¦C¤å¦r¯x§Î¥ª¤W¨¤ªº¦ì¸m©Ò¦b
                add     eax,ecx
                mov     rectText.top,eax
                add     eax,dwFontHigh
                mov     rectText.bottom,eax
next_day:       mov     eax,dwDay
                cmp     eax,nMaxDay
                ja      finish
                invoke  wsprintf,OFFSET szBuffer,OFFSET szFmt1,eax
                invoke  CalcTextRect,hdc,dwWeek
                mov     ecx,dwDay
    .IF cx==stLocTime.wDay              ;­Y¬°¤µ¤é¡A«h¥Hºñ¦â­I´ºªí¥Ü
                mov     eax,TODAYBKCOLOR
    .ELSE
                mov     eax,colorTextBk
    .ENDIF
                invoke  SetBkColor,hdc,eax
                invoke  DrawText,hdc,OFFSET szBuffer,-1,ADDR rectText,DT_CENTER or DT_VCENTER or DT_SINGLELINE
                inc     dwDay
                inc     dwWeek
                cmp     dwWeek,7
                jb      next_day
                mov     dwWeek,0
                mov     ecx,rectText.top
                jmp     next_week
finish:         ret
DrawCalendarTbl ENDP
;-------------------------------------------------------------------------------
;¨Ì¾ÚdwFontWidth¡BdwFontHigh­pºâ¦U±±¨î¶µªº¤j¤p¡A¨Ã§â¦U±±¨î¶µ²¾°Ê¨ì¹ï¸Ü²°¾A·íªº¦ì¸m
;¶Ç¦^­È¡GEDX¬°¤u§@°Ï¼e«×¡AEAX¬°¤u§@°Ï°ª«×
CalcCtlPosi     PROC
                LOCAL   dwHalfFntWidth:DWORD,ptCtl:POINT
                LOCAL   dwBtnWidth:DWORD,dwBtnHigh:DWORD
                LOCAL   dwClientWidth:DWORD,dwClientHigh:DWORD  ;¤u§@°Ïªº¼e«×»P°ª«×

;¨Ì¾ÚdwFontWidth¡BdwFontHigh­pºâ«ö¶sªº¼e«×»P°ª«×¡A¼e¤K­Ó¦r¤¸¡A°ª7/4¦r¤¸
                mov     edx,dwFontWidth
                shl     edx,3
                mov     dwBtnWidth,edx
                mov     ecx,dwFontHigh
                shl     ecx,3
                sub     ecx,dwFontHigh
                shr     ecx,2
                mov     dwBtnHigh,ecx

;¨Ì¾ÚdwFontWidth¡BdwFontHigh¨M©w¨C­Ó±±¨î¶µ¦ì¸m¡A¤è¦¡¦p¤U¡G
;¡@¡@1.¡y¦è¤¸¡z¦b¤u§@°Ï¥ª¤W¨¤¥k¤è¤T­Ó¦r¤¸¡B¤U¤è¨â­Ó¦r¤¸³B¡A¼e¨â­Ó¦r¤¸¡A°ª¤@­Ó¦r¤¸
;¡@¡@2.½s¿è®Ø¦b¡y¦è¤¸¡z¥k¤è¥b­Ó¦r¤¸³B¡A¼e¥|­Ó¦r¤¸¡A°ª¤@­Ó¦r¤¸¦A¥[¤»ÂI
;¡@¡@3.¡y¦~¡z¦b½s¿è®Ø¥k¤è¥b­Ó¦r¤¸³B¡A¼e¤@­Ó¦r¤¸¡A°ª¤@­Ó¦r¤¸
;¡@¡@4.½Æ¦X®Ø¦b¡y¦~¡z¥k¤è¥b­Ó¦r¤¸³B¡A¼e¥|­Ó¦r¤¸¡A°ª
;¡@¡@5.¡y¤ë¡z¦b½Æ¦X®Ø¥b­Ó¦r¤¸³B¡A
;¡@¡@6¡y¬d¸ß¡z¡B¡yÂ÷¶}¡z«ö¶s¦b¡y¦è¤¸¡z¤U¤è¤@­Ó¦r¤¸³B
;ªð¦^®É¡AEAX¶Ç¦^·sªºµøµ¡¤j¤p¡A§C¦r²Õ¬°µøµ¡¼e«×¡A°ª¦r²Õ¬°µøµ¡°ª«×
                mov     ecx,dwFontHigh
                mov     eax,dwFontWidth
                shl     ecx,1
                mov     dwHalfFntWidth,eax
                mov     ptCtl.y,ecx
                shr     dwHalfFntWidth,1
                mov     ptCtl.x,eax
                shl     eax,1
                add     ptCtl.x,eax
                invoke  MoveWindow,hStatic0,ptCtl.x,ptCtl.y,ecx,dwFontHigh,TRUE
                mov     eax,dwFontWidth
                shl     eax,1
                mov     ecx,eax
                add     eax,dwHalfFntWidth
                shl     ecx,1
                add     ptCtl.x,eax
                mov     edx,ptCtl.y
                mov     eax,dwFontHigh
                push    ecx
                sub     edx,3
                add     eax,6
                invoke  MoveWindow,hEdit,ptCtl.x,edx,ecx,eax,TRUE
                pop     ecx
                mov     eax,dwHalfFntWidth
                add     ptCtl.x,ecx
                add     ptCtl.x,eax
                invoke  MoveWindow,hStatic1,ptCtl.x,ptCtl.y,dwFontWidth,dwFontWidth,TRUE
                mov     ecx,dwFontWidth
                mov     eax,dwHalfFntWidth
                add     ptCtl.x,ecx
                add     ptCtl.x,eax
                shl     ecx,2
                mov     edx,ptCtl.y
                mov     eax,dwFontHigh
                sub     edx,3
                add     eax,6
                invoke  MoveWindow,hComboBox,ptCtl.x,edx,ecx,eax,TRUE
                mov     edx,dwHalfFntWidth
                mov     ecx,dwFontWidth
                add     ptCtl.x,edx
                shl     ecx,2
                add     ptCtl.x,ecx
                invoke  MoveWindow,hStatic2,ptCtl.x,ptCtl.y,dwFontWidth,dwFontWidth,TRUE
                mov     eax,ptCtl.x
                mov     edx,dwFontWidth
                shl     edx,2
                add     eax,edx         ;EAX=¤u§@°Ï¼e«×=¦è¤¸¨ì¤ëªº¼e«×¦A¥[¤W¥ª¥k¦U¤T¦r¤¸¼e
                mov     ecx,dwFontHigh
                mov     dwClientWidth,eax
                shl     ecx,1
                add     ptCtl.y,ecx
                mov     edx,dwBtnWidth
                mov     ecx,3
                shl     edx,1           ;¨â­Ó«ö¶s
                sub     eax,edx
                cwd
                div     cx
                mov     ptCtl.x,eax
                push    eax             ;EAX=¨â«ö¶s¤§¶¡¹j=¡y¬d¸ß¡zÂ÷¥ªÃä®Ø¤§¶¡¹j
                invoke  MoveWindow,hBtn0,eax,ptCtl.y,dwBtnWidth,dwBtnHigh,TRUE
                mov     edx,dwBtnWidth
                pop     eax
                add     ptCtl.x,edx
                add     eax,ptCtl.x
                invoke  MoveWindow,hBtn1,eax,ptCtl.y,dwBtnWidth,dwBtnHigh,TRUE

;­pºâªí®æ¦ì¸m¡A¨Ã¦s©óptCalendarTblµ²ºcÅéùØ¡C¦¹ªí®æ¬O¥Î¨ÓÅã¥Ü¬Y­Ó¤ëªº¤ë¾ä¡A
;¨C¤@¦æ¼e¤@­Ó¥b¦r¤¸¡A¥t¥~¦æ»P¦æ¤§¶¡¬Û¹j¤@­Ó¦r¤¸¡A¨C¦C¤§¶¡¬Û¹j¥b­Ó¦r¤¸¡C
                mov     ecx,dwFontHigh
                mov     eax,dwBtnHigh
                shl     ecx,1
                add     ptCtl.y,eax
                add     ecx,ptCtl.y
                mov     dwClientHigh,ecx
                mov     ptCalendarTbl.y,ecx     ;¶Ç¦^¤ë¾äªí®æªºY¦ì¸m¡A¦b«ö¶s©³½t¤U¨â­Ó¦r¤¸°ª
                mov     edx,dwFontWidth
                mov     eax,edx
                mov     ecx,edx
                shl     edx,3
                shl     eax,2
                add     edx,ecx
                add     edx,eax
                shr     ecx,1
                add     edx,ecx                 ;EDX=13­Ó¥b¦r¤¸¼e
                mov     eax,dwClientWidth
                sub     eax,edx
                shr     eax,1
                mov     ptCalendarTbl.x,eax     ;¶Ç¦^¤ë¾äªí®æªºX¦ì¸m
                mov     ecx,dwFontHigh
                mov     eax,ecx
                shr     eax,1
                add     eax,ecx
                mov     ecx,eax
                shl     eax,2
                shl     ecx,1
                add     eax,ecx                 ;EAX=1.5­Ó¦r¤¸°ª­¼¥H6
                add     eax,dwFontHigh          ;EAX=³Ì«á¤@¦C©³½t
                add     eax,dwFontHigh
                add     eax,dwFontHigh
                add     dwClientHigh,eax
                mov     eax,dwClientHigh
                mov     edx,dwClientWidth
                ret
CalcCtlPosi     ENDP
;-------------------------------------------------------------------------------
CalcFont        PROC    hdc:HDC,hWin:HWND
                LOCAL   dwTemp:DWORD
                LOCAL   dwWinWidth:DWORD,dwWinHigh:DWORD        ;µøµ¡ªº¼e«×»P°ª«×
                invoke  DeleteObject,hNewFont   ;§R°£Âªº¦r§Î
;¨Ì¾ÚdwDlgFontSize¤j¤p¡A«Ø¥ßÅÞ¿è¦rÅé¡A¨ä°ª«×¬°
;int(fabs(FontSize*GetDeviceCaps(hdc,LOGPIXELSY)/72)/10.0+0.5)
;¨Ã§â¦rÅé°ª«×¤Î¼e«×¤À§O¦s©ódwFontHigh¡BdwFontWidthÅܼÆùØ
                invoke  GetDeviceCaps,hdc,LOGPIXELSY ;¨ú±oªuY¶b¤è¦Vªº¨CÅÞ¿è­^¦TªºÂI¼Æ
                mov     dwTemp,eax      ;--st0--
                fild    dwTemp          ;T=¨CÅÞ¿è­^¦TªºÂI¼Æ
                fimul   dwDlgFontSize   ;TF
                fimul   wTen            ;10TF
                fidiv   w72             ;10TF/72
                fidiv   wTen            ;TF/72
                fadd    dwHalf          ;TF/72+0.5
                fabs                    ;|TF/72+0.5|
                fistp   dwFontHigh
                invoke  CreateFont,dwFontHigh,0,0,0,500,0,0,0,0,0,0,0,0,OFFSET szFontFace
                mov     hNewFont,eax
                invoke  SelectObject,hdc,eax
                invoke  DeleteObject,eax
                invoke  GetTextMetrics,hdc,OFFSET tm
                mov     eax,tm.tmMaxCharWidth
                mov     dwFontWidth,eax
;¥ÎCalcCtlPosi­pºâ¦U±±¨î¶µ¦ì¸m¤Î§ïÅܤj¤p¡A¨Ã²¾°Ê¦U±±¨î¶µ¨ì¹ï¸Ü²°ùتº¾A·í¦ì¸m
                call    CalcCtlPosi
;­×§ï¹ï¸Ü²°¤j¤p¡A¨Ã§â¹ï¸Ü²°²¾¨ì¿Ã¹õ¤¤¥¡
                mov     dwWinWidth,edx  ;EDX¬°¹ï¸Ü²°ªº¤u§@°Ï¼e«×
                mov     dwWinHigh,eax   ;EAX¬°¹ï¸Ü²°ªº¤u§@°Ï°ª«×¡A¥H¹Ï¯À¬°³æ¦ì
                invoke  GetSystemMetrics,SM_CYMENU
                add     dwWinHigh,eax
                invoke  GetSystemMetrics,SM_CYCAPTION
                add     dwWinHigh,eax
                invoke  GetSystemMetrics,SM_CYFIXEDFRAME
                shl     eax,1           ;¹ï¸Ü²°°ª«×¡×¤u§@°Ï°ª«×¡Ï¥D¿ï³æ°ª«×¡Ï
                add     dwWinHigh,eax   ;¡@¡@¡@¡@¡@¡@¼ÐÃDÄæ°ª«×¡Ï2¡Ñ¥~®Ø°ª«×
                invoke  GetSystemMetrics,SM_CXFIXEDFRAME
                shl     eax,1
                add     dwWinWidth,eax  ;¹ï¸Ü²°¼e«×¡×¤u§@°Ï¼e«×¡Ï2¡Ñ¥~®Ø¼e«×
                mov     edx,dwScrWidth
                sub     edx,dwWinWidth
                mov     ecx,dwScrHigh
                sub     ecx,dwWinHigh
                shr     edx,1           ;EDX¡×¹ï¸Ü²°X®y¼Ð¡×(¿Ã¹õ¼e«×¡Ð¹ï¸Ü²°¼e«×)/2
                shr     ecx,1           ;ECX¡×¹ï¸Ü²°Y®y¼Ð¡×(¿Ã¹õ°ª«×¡Ð¹ï¸Ü²°°ª«×)/2
                invoke  MoveWindow,hWin,edx,ecx,dwWinWidth,dwWinHigh,TRUE
;§Q¥Î§â¤w«Ø¥ß¦nªº¦r§Î¿ï¤J¦U±±¨î¶µùØ
                invoke  SendMessage,hStatic0,WM_SETFONT,hNewFont,TRUE
                invoke  SendMessage,hEdit,WM_SETFONT,hNewFont,TRUE
                invoke  SendMessage,hStatic1,WM_SETFONT,hNewFont,TRUE
                invoke  SendMessage,hComboBox,WM_SETFONT,hNewFont,TRUE
                invoke  SendMessage,hStatic2,WM_SETFONT,hNewFont,TRUE
                invoke  SendMessage,hBtn0,WM_SETFONT,hNewFont,TRUE
                invoke  SendMessage,hBtn1,WM_SETFONT,hNewFont,TRUE
                ret
CalcFont        ENDP
;-------------------------------------------------------------------------------
DlgProc         PROC    hDlg:HANDLE,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
                LOCAL   dwTemp:DWORD
.IF uMsg==WM_PAINT
                invoke  BeginPaint,hDlg,OFFSET ps
                invoke  DrawCalendarTbl,ps.hdc
                invoke  EndPaint,hDlg,OFFSET ps

.ELSEIF uMsg==WM_COMMAND
                mov     eax,wParam
    .IF lParam==0
    ;­YlParam=0¡Aªí¥Ü¿ï©w¬Y¿ï³æ¿ï¶µ
        .IF ax==IDM_EXIT
                invoke  EndDialog,hDlg,NULL
        .ELSEIF ax==IDM_HELP
                invoke  wsprintf,OFFSET szBuffer,OFFSET szFmt2,dwDlgFontSize
                invoke  MessageBox,hDlg,OFFSET szBuffer,OFFSET szTitle,MB_OK or MB_ICONQUESTION
        .ELSEIF ax==IDM_CLEAR
                invoke  SetDlgItemText,hDlg,IDC_EDIT,NULL
        .ELSEIF ax==IDM_LARGE
                inc     dwDlgFontSize
            .IF dwDlgFontSize>24
                mov     dwDlgFontSize,24
                jmp     no_change
            .ENDIF
                jmp     @f
        .ELSEIF ax==IDM_SMALL
                dec     dwDlgFontSize
            .IF dwDlgFontSize<8
                mov     dwDlgFontSize,8
                jmp     no_change
            .ENDIF
@@:             invoke  GetDC,hDlg
                mov     dwTemp,eax
                invoke  CalcFont,eax,hDlg
                invoke  ReleaseDC,hDlg,dwTemp
                invoke  InvalidateRect,hDlg,NULL,TRUE
        .ENDIF
    .ELSE
    ;­YlParam¤£¬°0¡Aªí¥Ü¿ï©w¬Y¤l±±¨î¤¸¥ó
                mov     edx,wParam
                shr     edx,16
        .IF dx==BN_CLICKED
            .IF ax==IDC_BUTTON1         ;ªí¥Ü«ö¤U¡yÂ÷¶}¡z«ö¶s
                invoke  SendMessage,hDlg,WM_COMMAND,IDM_EXIT,0
            .ELSEIF ax==IDC_BUTTON0     ;ªí¥Ü«ö¤U¡y¬d¸ß¡z«ö¶s
                jmp     look_up
            .ENDIF
        .ELSEIF dx==CBN_SELCHANGE       ;ªí¥Ü¨Ï¥ÎªÌ¤w¿ï©w¤ë¥÷¤F
            .IF ax==IDC_COMBOBOX
look_up:        invoke  InvalidateRect,hDlg,NULL,TRUE
            .ENDIF
        .ENDIF
    .ENDIF
no_change:

.ELSEIF uMsg==WM_INITDIALOG
                invoke  LoadIcon,hInstance,OFFSET szIcon
                invoke  SendMessage,hDlg,WM_SETICON,ICON_BIG,eax
                mov     eax,hDlg
                mov     hDialog,eax
;¨ú±o¿Ã¹õªº¼e«×¤Î°ª«×¡A¤À§O¦s©ódwScrWidth¡BdwScrHigh
                invoke  GetSystemMetrics,SM_CXSCREEN
                mov     dwScrWidth,eax
                invoke  GetSystemMetrics,SM_CYSCREEN
                mov     dwScrHigh,eax
;¨ú±oÀRºA±±¨î¶µ¡B½s¿è®Ø¡B½Æ¦X®Ø¤Î¨â­Ó«ö¶sªº¥N½X
                invoke  GetDlgItem,hDlg,IDC_EDIT
                mov     hEdit,eax
                invoke  SetFocus,eax    ;§â¿é¤JµJÂI³]¦b½s¿è®Ø
                invoke  GetDlgItem,hDlg,IDC_COMBOBOX
                mov     hComboBox,eax
                invoke  GetDlgItem,hDlg,IDC_BUTTON0
                mov     hBtn0,eax
                invoke  GetDlgItem,hDlg,IDC_BUTTON1
                mov     hBtn1,eax
                invoke  GetDlgItem,hDlg,IDC_STATIC0
                mov     hStatic0,eax
                invoke  GetDlgItem,hDlg,IDC_STATIC1
                mov     hStatic1,eax
                invoke  GetDlgItem,hDlg,IDC_STATIC2
                mov     hStatic2,eax
;©³¤Uªºµ{¦¡¤ù¬q¬O¥Î¨Ó§â¡y¤@¡z¡B¡y¤G¡z¡K¥[¤J½Æ¦X®ØùØ
                mov     dwTemp,0
@@:             mov     ecx,dwTemp
                mov     edx,ecx
                shl     ecx,1
                add     ecx,edx
        .IF dl==11
                add     ecx,2
        .ENDIF
                add     ecx,OFFSET szMonth
                invoke  SendMessage,hComboBox,CB_ADDSTRING,NULL,ecx
                inc     dwTemp
                cmp     dwTemp,12
                jb      @b
;¨Ï·í«eªº¦è¤¸¦~¡B¤ëÅܦ¨½Æ¦X®Øªº¤º©w¿ï¶µ
                invoke  GetLocalTime,OFFSET stLocTime
                movzx   ecx,stLocTime.wMonth
                dec     ecx
                invoke  SendMessage,hComboBox,CB_SETCURSEL,ecx,0
                movzx   ecx,stLocTime.wYear
                invoke  wsprintf,OFFSET szBuffer,OFFSET szFmt0,ecx
                invoke  SetWindowText,hEdit,OFFSET szBuffer
;¥Î°Æµ{¦¡¡ACalcFont¡A­pºâ¦rÅé¤j¤p¡F¨Ã¥Î°Æµ{¦¡¡ASetCtlPosition¡A³]¸m±±¨î¶µ¦ì¸m
                invoke  GetDC,hDlg
                mov     dwTemp,eax
                invoke  CalcFont,eax,hDlg
                invoke  ReleaseDC,hDlg,dwTemp

.ELSEIF uMsg==WM_CLOSE
                invoke  SendMessage,hDlg,WM_COMMAND,IDM_EXIT,0

.ELSE
                mov     eax,FALSE
                ret
.ENDIF
                mov     eax,TRUE
                ret
DlgProc         ENDP
;-------------------------------------------------------------------------------
start:          invoke  GetModuleHandle,NULL
                mov     hInstance,eax
                invoke  DialogBoxParam,hInstance,offset szDlgName,NULL,offset DlgProc,NULL
                invoke  ExitProcess,eax
;*******************************************************************************
                end     start

©³¤U¬O perpetual_calendar.rc ­ì©l½X¡G

#include "c:\masm32\include\resource.h"

#define IDC_EDIT        100     //¦è¤¸¦~¥÷½s¿è®Ø
#define IDC_COMBOBOX    101     //¤ë¥÷½Æ¦X®Ø
#define IDC_STATIC0     102
#define IDC_STATIC1     103
#define IDC_STATIC2     104
#define IDC_BUTTON0     105     //¬d¸ß«ö¶s
#define IDC_BUTTON1     106     //Â÷¶}«ö¶s
#define IDM_EXIT        107
#define IDM_LARGE       108
#define IDM_SMALL       109
#define IDM_CLEAR       110
#define IDM_HELP        111

#define DLGFONTSIZE     12

CalendarMenu    MENU
BEGIN
  MENUITEM      "Â÷¶}",IDM_EXIT
  MENUITEM      "©ñ¤j",IDM_LARGE
  MENUITEM      "ÁY¤p",IDM_SMALL
  MENUITEM      "²M°£",IDM_CLEAR
  MENUITEM      "»¡©ú",IDM_HELP
END

CalendarIcon    ICON    Moon.ico

CalendarDlg     DIALOG MOVEABLE PURE LOADONCALL DISCARDABLE 100,0,200,300
STYLE           DS_FIXEDSYS|DS_SETFONT|WS_POPUP|WS_VISIBLE|WS_SYSMENU|
                WS_MAXIMIZEBOX|WS_MINIMIZEBOX|WS_CAPTION 
CAPTION         "¸U¦~¾ä"
FONT            DLGFONTSIZE,"²Ó©úÅé"
MENU            CalendarMenu
BEGIN
  CONTROL "¦è¤¸",IDC_STATIC0, "STATIC",  WS_CHILD|SS_LEFT|WS_GROUP|WS_VISIBLE,5,13,33,11
  CONTROL "",    IDC_EDIT,    "EDIT",    WS_CHILD|ES_LEFT|WS_BORDER|WS_TABSTOP|WS_VISIBLE|ES_NUMBER,40,10,47,12
  CONTROL "¦~",  IDC_STATIC1, "STATIC",  WS_CHILD|SS_LEFT|WS_GROUP |WS_VISIBLE,90,13,35,11
  CONTROL "",    IDC_COMBOBOX,"COMBOBOX",WS_CHILD|WS_TABSTOP|WS_VISIBLE|CBS_DROPDOWNLIST|WS_VSCROLL,120,10,48,90
  CONTROL "¤ë",  IDC_STATIC2, "STATIC",  WS_CHILD|SS_LEFT|WS_GROUP |WS_VISIBLE,170,13,25,11
  CONTROL "¬d¸ß",IDC_BUTTON0, "BUTTON",  WS_CHILD|BS_PUSHBUTTON|WS_TABSTOP,40,28,40,12
  CONTROL "Â÷¶}",IDC_BUTTON1, "BUTTON",  WS_CHILD|BS_PUSHBUTTON|WS_TABSTOP,120,28,40,12
END

©³¤U¬O perpetual_calendar.mak Àɪº¤º®e¡G

# ²£¥Í perpetual_calendar.EXE
ALL : perpetual_calendar.EXE

# ²ÕĶ¾¹¤Î³sµ²¾¹
perpetual_calendar.EXE : perpetual_calendar.ASM perpetual_calendar.RES
# ²ÕĶ¾¹·|¦Û°Ê¶Ç perpetual_calendar.OBJ µ¹³sµ²¾¹¡A¬G /link ¤§«á¤£¥Î¦A¥[¤W perpetual_calendar.OBJ
    ml /coff perpetual_calendar.ASM /link /SUBSYSTEM:WINDOWS perpetual_calendar.RES 

# ¸ê·½½sĶ¾¹
perpetual_calendar.RES : perpetual_calendar.RC Moon.ico
    rc perpetual_calendar.RC

¹Ï¥ÜÀÉ¡AMoon.ico ¦b³oùؤU¸ü¡C


µù¤@¡G¤p¤ì°¸¨Ï¥Î ViewSonic VA916 19 ­^¤o²G´¹¿Ã¹õ¡A¥iµø°Ï°ì¬O 37.6¡Ñ30.1 cm2¡A¤]´N¬O 14.8¡Ñ11.85 ¥­¤è­^¤o¡A¥H¼e 1280 ¹Ï¯À¡B°ª 1024 ¹Ï¯ÀÅã¥Ü®É¡AªuµÛ¤ô¥­¤è¦Vªº¸ÑªR«×¬O¨C­^¤o 86.5 ­Ó¹Ï¯À¡AªuµÛ««ª½¤è¦Vªº¸ÑªR«×¬O 86.4 ­Ó¹Ï¯À ( 1280¡Ò14.8¡Ü86.5¡A1024¡Ò11.85¡Ü86.4¡A600/86¡Ü6.98 )¡C

µù¤G¡G¦]¬°¦a²y¬O¶ê§Îªº¡A¦b¤Ó¶§ª½®gªº¦a°Ï¥u¦³¤@¤p¶ô°Ï°ì¡A¦b³o¶ô°Ï°ì¬O¥¿¤È 12 ®É¡F¦Ó¦b³o¶ô°Ï°ìªºªF¤è¦­¤w¹L¤F¥¿¤È 12 ®É¡F¦Ó¦b³o¶ô°Ï°ìªº¦è¤è¡A«o©|¥¼¨ì¥¿¤È¡C§Ú­Ì§â¦a²y¤À¦¨ 24 ­Ó®É°Ï¡A¨Ã¥H­^°ê­Û´°ªº®æªL«Âªv¤Ñ¤å¥x·í°µ¼Ð·Ç®É¶¡¡AºÙ¬°®æªL«Âªv¼Ð·Ç®É¶¡ ( Greenwich Mean Time¡AÁY¼g¬°¡yGMT¡z)¡A·í¤Ó¶§¦b®æªL«Âªv¤Ñ¤å¥xªº³Ì°ªÂI®É¡A§Y¬°®æªL«Âªv¼Ð·Ç®É¶¡¥¿¤È 12¡G00¡A¦Ó¤¤µØ¥Á°ê¦b¤ñ®æªL«Âªv¼Ð·Ç®É¶¡§Ö 8 ­Ó¤p®Éªº¦a°Ï¡A´N¥H GMT¡Ï8 ªí¥Ü¡F®L«Â¦iªº®É¶¡¬O¤ñ®æªL«Âªv¼Ð·Ç®É¶¡®É¶¡ºC 10 ¤p®É¡A¥H GMT¡Ð10 ªí¥Ü¡C

¦ý¬O¦]¬°¦a²y¨Ã«D¥¿²yÅé¡A¨C¤Ñªº¦ÛÂà¬O¦³¨Ç¤£³W«hªº¡A¦Ó¥B¥¿¦b½wºC´î³t¤¤¡A©Ò¥H¡A®æªL«Âªv¼Ð·Ç®É¶¡¤w¸g¤£¦A³Q§@¬°¼Ð·Ç®É¶¡¨Ï¥Î¡A²{¦bªº¼Ð·Ç®É¶¡¡A¬O¥Ñ䣭ì¤lÄÁ³ø®Éªº¨ó½Õ¥@¬É®É¶¡ ( UTC )¡C©Ò¥H¦b¤¤µØ¥Á°ê¡A¥Î GetSystemTime ©Ò±o¨ìªº¬O¨ó½Õ¥@¬É®É¶¡¬O²M±á¨âÂI¾ã¡F¦Ó¥Î GetLocalTime ¨ú±oªº®É¶¡¬O¬O¤W¤È¤QÂI¾ã¡C


¦^¨ì­º­¶¡A ¨ì²Ä¤Q¤»³¹¡A ¨ì²Ä¤Q¤K³¹