Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on May 9th, 2012  |  syntax: None  |  size: 18.51 KB  |  hits: 23  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. Handling DTN_FORMAT and DTN_FORMATQUERY messages of the DateTimePicker control to use callback fields in format string in .NET
  2. Private Sub WmFormat(ByRef m As Message)
  3.     Dim nmdatetimeformat As FWEx.Win32API.NMDATETIMEFORMAT = m.GetLParam(GetType(FWEx.Win32API.NMDATETIMEFORMAT))
  4.     Dim format As String = Marshal.PtrToStringAuto(nmdatetimeformat.pszFormat)
  5.     Dim time As Date = SysTimeToDateTime(nmdatetimeformat.st)
  6.  
  7.     If format = "XX" Then
  8.         Dim week As Integer = System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(time, Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday)
  9.         ' Here is the problem. The week number does not shown in custom field.
  10.         nmdatetimeformat.pszDisplay = Marshal.StringToHGlobalUni(week.ToString)
  11.  
  12.         ' I've tried more copy methods without luck
  13.         ' nmdatetimeformat.pszDisplay = Marshal.StringToBSTR(week.ToString)
  14.         ' Marshal.Copy(week.ToString.ToCharArray(), 0, nmdatetimeformat.pszDisplay, week.ToString.Length)
  15.  
  16.         Marshal.StructureToPtr(nmdatetimeformat, m.LParam, True)
  17.     End If
  18.  
  19.     m.Result = IntPtr.Zero
  20. End Sub
  21.        
  22. Imports System
  23. Imports System.ComponentModel
  24. Imports System.Drawing
  25. Imports System.Runtime.InteropServices
  26. Imports System.Windows.Forms
  27. Imports System.Globalization
  28.  
  29. Public Class DateTimePickerEx
  30.     Inherits DateTimePicker
  31.  
  32.     Private Const WM_REFLECT As Integer = &H2000
  33.  
  34.     Private Sub WmFormat(ByRef m As Message)
  35.         Dim nmdatetimeformat As NMDATETIMEFORMAT = m.GetLParam(GetType(NMDATETIMEFORMAT))
  36.         Dim format As String = Marshal.PtrToStringAuto(nmdatetimeformat.pszFormat)
  37.         Dim time As Date = SysTimeToDateTime(nmdatetimeformat.st)
  38.  
  39.         If format = "XX" Then
  40.             Dim week As Integer = System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(time, Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday)
  41.             ' Here is the problem. The week number does not shown in custom field.
  42.  
  43.             nmdatetimeformat.pszDisplay = Marshal.StringToHGlobalUni(week.ToString)
  44.  
  45.             ' I've tried more copy methods without luck
  46.             ' nmdatetimeformat.pszDisplay = Marshal.StringToBSTR(week.ToString)
  47.             ' Marshal.Copy(week.ToString.ToCharArray(), 0, nmdatetimeformat.pszDisplay, week.ToString.Length)
  48.  
  49.             Marshal.StructureToPtr(nmdatetimeformat, m.LParam, True)
  50.         End If
  51.  
  52.         m.Result = IntPtr.Zero
  53.     End Sub
  54.  
  55.     Private Sub WmFormatQuery(ByRef m As Message)
  56.         Dim nmdatetimeformatquery As NMDATETIMEFORMATQUERY = m.GetLParam(GetType(NMDATETIMEFORMATQUERY))
  57.         Dim format As String = Marshal.PtrToStringAuto(nmdatetimeformatquery.pszFormat)
  58.         Dim dst As IntPtr = (m.LParam.ToInt64() + Marshal.OffsetOf(GetType(NMDATETIMEFORMATQUERY), "szMax").ToInt64())
  59.         'Dim dc As IntPtr = GetDC(Me.Handle)
  60.  
  61.         Dim textSize As Size = TextRenderer.MeasureText(Me.CreateGraphics, "52", Me.Font, New Size(20, 13), TextFormatFlags.NoPadding)
  62.         nmdatetimeformatquery.szMax.cx = textSize.Width
  63.         nmdatetimeformatquery.szMax.cy = textSize.Height
  64.  
  65.         Marshal.StructureToPtr(nmdatetimeformatquery, m.LParam, True)
  66.  
  67.         'Marshal.Copy(New Long() {nmdatetimeformatquery.szMax.cx, nmdatetimeformatquery.szMax.cy}, 0, dst, 2)
  68.         m.Result = IntPtr.Zero
  69.     End Sub
  70.  
  71.     Private Sub WmKeyDown(ByRef m As Message)
  72.         Dim nmdatetimewmkeydown As NMDATETIMEWMKEYDOWN = m.GetLParam(GetType(NMDATETIMEWMKEYDOWN))
  73.         Dim format As String = Marshal.PtrToStringAuto(nmdatetimewmkeydown.pszFormat)
  74.         Dim curDat As Date = MyBase.Value
  75.  
  76.         Select Case format
  77.             Case "XX"
  78.                 Select Case DirectCast(nmdatetimewmkeydown.nVirtKey, VirtualKeys)
  79.                     Case VirtualKeys.VK_DOWN, VirtualKeys.VK_SUBTRACT
  80.                         curDat = curDat.AddDays(-7)
  81.                     Case VirtualKeys.VK_UP, VirtualKeys.VK_ADD
  82.                         curDat = curDat.AddDays(7)
  83.                     Case Else
  84.                         Exit Sub
  85.                 End Select
  86.             Case "X"
  87.  
  88.         End Select
  89.  
  90.         nmdatetimewmkeydown.st.Day = curDat.Day
  91.         nmdatetimewmkeydown.st.Month = curDat.Month
  92.         nmdatetimewmkeydown.st.Year = curDat.Year
  93.  
  94.         Marshal.StructureToPtr(nmdatetimewmkeydown, m.LParam, True)
  95.         m.Result = IntPtr.Zero
  96.     End Sub
  97.  
  98.     Private Sub WmDateTimeChange(ByRef m As Message)
  99.  
  100.     End Sub
  101.  
  102.     Private Sub WmNotifyDeltaPos(ByRef m As Message)
  103.         Dim nmupdown As NMUPDOWN = m.GetLParam(GetType(NMUPDOWN))
  104.  
  105.         Dim vKey As VirtualKeys
  106.  
  107.         If nmupdown.iDelta < 0 Then
  108.             vKey = VirtualKeys.VK_UP
  109.             nmupdown.iDelta = Math.Abs(nmupdown.iDelta)
  110.         ElseIf nmupdown.iDelta > 0 Then
  111.             vKey = VirtualKeys.VK_DOWN
  112.         Else
  113.             Exit Sub
  114.         End If
  115.  
  116.         For i As Integer = 0 To nmupdown.iDelta - 1
  117.             PostMessage(IntPtr.Zero, WindowsMessages.WM_KEYDOWN, vKey, &H1)
  118.             PostMessage(IntPtr.Zero, WindowsMessages.WM_KEYUP, vKey, &H10000001)
  119.         Next
  120.     End Sub
  121.  
  122.     Private Sub WmDropDown(ByRef m As Message)
  123.  
  124.     End Sub
  125.  
  126.     Private Function WmReflectCommand(ByRef m As Message) As Boolean
  127.         If m.HWnd = Me.Handle Then
  128.             Dim code As Long = NMHDR.FromMessage(m).code
  129.  
  130.             If DirectCast(m.Msg, WindowsMessages) And WM_REFLECT Then
  131.                 Select Case code
  132.                     Case -756
  133.                         Me.WmFormat(m)
  134.                         Return True
  135.                     Case DateTimePickerNotifications.DTN_FORMAT
  136.                         Me.WmFormat(m)
  137.                         Return True
  138.                     Case DateTimePickerNotifications.DTN_FORMATQUERY
  139.                         Me.WmFormatQuery(m)
  140.                         Return True
  141.                     Case DateTimePickerNotifications.DTN_WMKEYDOWN
  142.                         Me.WmKeyDown(m)
  143.                         Return True
  144.                     Case -759 'DateTimePickerNotifications.DTN_DATETIMECHANGE
  145.                         'Me.WmDateTimeChange(m)
  146.                         'Return True
  147.                     Case -754
  148.                         'Me.WmDropDown(m)
  149.                         '   Return True
  150.                     Case Is < 0
  151.                         Return False
  152.                 End Select
  153.             Else
  154.                 Select Case code
  155.                     Case UpDownNotifications.UDN_DELTAPOS
  156.                         Me.WmNotifyDeltaPos(m)
  157.                         Return True
  158.                 End Select
  159.             End If
  160.  
  161.             Return False
  162.         End If
  163.     End Function
  164.  
  165.     Private Function SysTimeToDateTime(st As SYSTEMTIME) As Date
  166.         Return New Date(st.Year, st.Month, st.Day, st.Hour, st.Minute, st.Second)
  167.     End Function
  168.     <System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")>
  169.     Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
  170.         If m.Msg <> 71 AndAlso m.Msg <> 513 Then
  171.             Select Case DirectCast(m.Msg, WindowsMessages)
  172.                 Case WindowsMessages.WM_NOTIFY + WM_REFLECT, WindowsMessages.WM_NOTIFY
  173.                     If Not Me.WmReflectCommand(m) Then
  174.                         Exit Select
  175.                     End If
  176.  
  177.                     Exit Sub
  178.             End Select
  179.         End If
  180.  
  181.         MyBase.WndProc(m)
  182.     End Sub
  183.  
  184.  <StructLayout(LayoutKind.Sequential)>
  185.         Public Structure NMDATETIMEFORMAT
  186.             ''' <summary>
  187.             ''' NMHDR structure that contains information about the message.
  188.             ''' </summary>
  189.             Public nmhdr As NMHDR
  190.             ''' <summary>
  191.             ''' Pointer to the null-terminated substring that defines a DTP control callback field.
  192.             ''' The substring comprises one or more X characters, followed by a NULL character.
  193.             ''' </summary>
  194.             Public pszFormat As IntPtr
  195.             ''' <summary>
  196.             ''' SYSTEMTIME structure that contains information about the current system date and time.
  197.             ''' </summary>
  198.             Public st As SYSTEMTIME
  199.             ''' <summary>
  200.             ''' Pointer to a null-terminated string.
  201.             ''' By default, this pointer is set to point at szDisplay by the DTP control.
  202.             ''' It is legal to set this member to point at an existing string.
  203.             ''' If so, the application is not required to place a string into the szDisplay member.
  204.             ''' </summary>
  205.             Public pszDisplay As IntPtr
  206.             ''' <summary>
  207.             ''' Specifies the 64-character buffer that is to receive the null-terminated string that the DTP control will display.
  208.             ''' It is not necessary that the application fill the entire buffer.
  209.             ''' </summary>
  210.             <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=64)>
  211.             Public szDisplay As String
  212.         End Structure
  213.  
  214.         ''' <summary>
  215.         ''' This structure is used with the DTN_FORMATQUERY notification message.
  216.         ''' </summary>
  217.         ''' <remarks>
  218.         ''' The NMDATETIMEFORMATQUERY structure contains information about a date and time picker (DTP) control callback field.
  219.         ''' It contains a substring (taken from the controls format string) that defines a callback field.
  220.         ''' The structure receives the maximum allowable size of the text that will be displayed in the callback field.
  221.         ''' </remarks>
  222.         <StructLayout(LayoutKind.Sequential)>
  223.         Public Structure NMDATETIMEFORMATQUERY
  224.             ''' <summary>
  225.             ''' NMHDR structure that contains information about this notification message.
  226.             ''' </summary>
  227.             Public nmhdr As NMHDR
  228.             ''' <summary>
  229.             ''' Pointer to a null-terminated substring that defines a DTP control callback field.
  230.             ''' The substring is one or more X characters followed by a NULL.
  231.             ''' </summary>
  232.             Public pszFormat As IntPtr
  233.             ''' <summary>
  234.             ''' SIZE structure that must be filled with the maximum size of the text to be displayed in the callback field.
  235.             ''' </summary>
  236.             Public szMax As SIZE
  237.         End Structure
  238.  
  239.         ''' <summary>
  240.         ''' This structure carries information used to describe and handle a DTN_WMKEYDOWN notification message.
  241.         ''' </summary>
  242.         <StructLayout(LayoutKind.Sequential)>
  243.         Public Structure NMDATETIMEWMKEYDOWN
  244.             ''' <summary>
  245.             ''' NMHDR structure that contains information about the notification message.
  246.             ''' </summary>
  247.             Public nmhdr As NMHDR
  248.             ''' <summary>
  249.             ''' Virtual key code that represents the key that the user pressed.
  250.             ''' </summary>
  251.             Public nVirtKey As Integer
  252.             ''' <summary>
  253.             ''' Pointer to a null-terminated substring, taken from the format string, that defines the callback field.
  254.             ''' The substring is one or more X characters, followed by a NULL.
  255.             ''' </summary>
  256.             Public pszFormat As IntPtr
  257.             ''' <summary>
  258.             ''' SYSTEMTIME structure containing the current date and time from the DTP control.
  259.             ''' The owner of the control must modify the time information based on the users keystroke.
  260.             ''' </summary>
  261.             Public st As SYSTEMTIME
  262.         End Structure
  263.  
  264. ''' <summary>
  265.         ''' The SIZE structure specifies the width and height of a rectangle.
  266.         ''' </summary>
  267.         ''' <remarks>
  268.         ''' The rectangle dimensions stored in this structure may correspond to viewport extents,
  269.         ''' window extents, text extents, bitmap dimensions, or the aspect-ratio filter for some extended functions.
  270.         ''' </remarks>
  271.         <StructLayout(LayoutKind.Sequential)>
  272.         Public Structure SIZE
  273.             ''' <summary>
  274.             ''' Specifies the rectangle's width. The units depend on which function uses this.
  275.             ''' </summary>
  276.             Public cx As Long
  277.             ''' <summary>
  278.             ''' Specifies the rectangle's height. The units depend on which function uses this.
  279.             ''' </summary>
  280.             Public cy As Long
  281.         End Structure
  282.  
  283.  ''' <summary>
  284.         ''' This structure contains information about a message.
  285.         ''' The pointer to this structure is specified as the lParam member of the WM_NOTIFY message.
  286.         ''' </summary>
  287.         <StructLayout(LayoutKind.Sequential)> _
  288.         Public Structure NMHDR
  289.             ''' <summary>
  290.             ''' Window handle to the control sending a message.
  291.             ''' </summary>
  292.             Public hwndFrom As IntPtr
  293.  
  294.             ''' <summary>
  295.             ''' Identifier of the control sending a message.
  296.             ''' </summary>
  297.             Public idFrom As IntPtr
  298.  
  299.             ''' <summary>
  300.             ''' Notification code. This member can be a control-specific notification code or it can be one of the common notification codes. The following values are supported if you include mouse support in your device platform:
  301.             ''' - NM_RCLICK
  302.             ''' - NM_RDBCLICK
  303.             ''' </summary>
  304.             Public code As Integer
  305.  
  306.             Public Shared Function FromMessage(ByVal msg As System.Windows.Forms.Message) As NMHDR
  307.                 Return DirectCast(msg.GetLParam(GetType(NMHDR)), NMHDR)
  308.             End Function
  309.         End Structure
  310.  
  311.  ''' <summary>
  312.         ''' Specifies a date and time, using individual members for the month, day, year, weekday, hour, minute, second, and millisecond.
  313.         ''' The time is either in coordinated universal time (UTC) or local time, depending on the function that is being called.
  314.         ''' </summary>
  315.         ''' <remarks>
  316.         ''' It is not recommended that you add and subtract values from the SYSTEMTIME structure to obtain relative times.
  317.         ''' </remarks>
  318.         Public Structure SYSTEMTIME
  319.             ''' <summary>
  320.             ''' The year. The valid values for this member are 1601 through 30827.
  321.             ''' </summary>
  322.             Public Year As Short
  323.             ''' <summary>
  324.             ''' The month.
  325.             ''' </summary>
  326.             Public Month As Short
  327.             ''' <summary>
  328.             ''' The day of the week. Sunday = 0.
  329.             ''' </summary>
  330.             Public DayOfWeek As Short
  331.             ''' <summary>
  332.             ''' The day of the month. The valid values for this member are 1 through 31.
  333.             ''' </summary>
  334.             Public Day As Short
  335.             ''' <summary>
  336.             ''' The hour. The valid values for this member are 0 through 23.
  337.             ''' </summary>
  338.             Public Hour As Short
  339.             ''' <summary>
  340.             ''' The minute. The valid values for this member are 0 through 59.
  341.             ''' </summary>
  342.             Public Minute As Short
  343.             ''' <summary>
  344.             ''' The second. The valid values for this member are 0 through 59.
  345.             ''' </summary>
  346.             Public Second As Short
  347.             ''' <summary>
  348.             ''' The millisecond. The valid values for this member are 0 through 999.
  349.             ''' </summary>
  350.             Public Milliseconds As Short
  351.         End Structure
  352.  
  353. ''' <summary>
  354.         ''' Contains information specific to up-down control notification messages.
  355.         ''' It is identical to and replaces the NM_UPDOWN structure.
  356.         ''' </summary>
  357.         ''' <remarks></remarks>
  358.         Public Structure NMUPDOWN
  359.             ''' <summary>
  360.             ''' NMHDR structure that contains additional information about the notification.
  361.             ''' </summary>
  362.             Public hdr As NMHDR
  363.             ''' <summary>
  364.             ''' Signed integer value that represents the up-down control's current position.
  365.             ''' </summary>
  366.             Public iPos As Integer
  367.             ''' <summary>
  368.             ''' Signed integer value that represents the proposed change in the up-down control's position.
  369.             ''' </summary>
  370.             Public iDelta As Integer
  371.         End Structure
  372.  
  373. Public Enum DateTimePickerMessages
  374.             DTM_FIRST = &H1000
  375.             DTM_GETSYSTEMTIME = DTM_FIRST + 1
  376.             DTM_SETSYSTEMTIME = DTM_FIRST + 2
  377.             DTM_GETRANGE = DTM_FIRST + 3
  378.             DTM_SETRANGE = DTM_FIRST + 4
  379.             DTM_SETFORMAT = DTM_FIRST + 5
  380.             DTM_SETMCCOLOR = DTM_FIRST + 6
  381.             DTM_GETMCCOLOR = DTM_FIRST + 7
  382.             DTM_GETMONTHCAL = DTM_FIRST + 8
  383.             DTM_SETMCFONT = DTM_FIRST + 9
  384.             DTM_GETMCFONT = DTM_FIRST + 10
  385.             DTM_SETMCSTYLE = DTM_FIRST + 11
  386.             DTM_GETMCSTYLE = DTM_FIRST + 12
  387.             DTM_CLOSEMONTHCAL = DTM_FIRST + 13
  388.             DTM_GETDATETIMEPICKERINFO = DTM_FIRST + 14
  389.             DTM_GETIDEALSIZE = DTM_FIRST + 15
  390.         End Enum
  391.  
  392.         Public Enum DateTimePickerNotifications
  393.             DTN_FIRST = -740
  394.             DTN_LAST = -745
  395.             DTN_FIRST2 = -753
  396.             DTN_LAST2 = -799
  397.             DTN_DATETIMECHANGE = DTN_FIRST - 6
  398.             DTN_USERSTRING = DTN_FIRST - 5
  399.             DTN_WMKEYDOWN = DTN_FIRST - 4
  400.             DTN_FORMAT = DTN_FIRST - 3
  401.             DTN_FORMATQUERY = DTN_FIRST - 2
  402.             DTN_DROPDOWN = DTN_FIRST - 1
  403.             DTN_CLOSEUP = DTN_FIRST
  404.         End Enum
  405.  
  406. Public Enum UpDownNotifications
  407.             UDN_FIRST = -721
  408.             UDN_LAST = -729
  409.             UDN_DELTAPOS = UDN_FIRST - 1
  410.         End Enum
  411.  
  412. Public Enum WindowsMessages
  413. ''' <summary>
  414.             '''Sent by a common control to its parent window when an event has occurred or the control requires some information.
  415.             ''' </summary>
  416.             WM_NOTIFY = &H4E
  417.  
  418. ''' <summary>
  419.             '''The WM_KEYDOWN message is posted to the window with the keyboard focus when a nonsystem key is pressed. A nonsystem key is a key that is pressed when the ALT key is not pressed.
  420.             ''' </summary>
  421.             WM_KEYDOWN = &H100
  422.  
  423. ''' <summary>
  424.             '''The WM_KEYUP message is posted to the window with the keyboard focus when a nonsystem key is released. A nonsystem key is a key that is pressed when the ALT key is not pressed or a keyboard key that is pressed when a window has the keyboard focus.
  425.             ''' </summary>
  426.             WM_KEYUP = &H101
  427. End Enum
  428.  
  429. ''' <summary>
  430.         ''' The VirtualKeys enumeration is also managed as System.Windows.Forms.Keys.
  431.         ''' The bracketed [keynames] are from that managed Forms.Keys enumeration.
  432.         ''' </summary>
  433.         ''' <remarks></remarks>
  434.         Public Enum VirtualKeys As Integer
  435. VK_UP = &H26        ' // [Up] = 038
  436. VK_DOWN = &H28          ' // [Down] = 040
  437. VK_ADD = &H6B           ' // [Add] = 107
  438. VK_SUBTRACT = &H6D      ' // [Subtract] = 109
  439. End Enum
  440.  
  441. Public Declare Auto Function PostMessage Lib "user32" (ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean