处理 DateTimePicker 控件的 DTN_FORMAT 和 DTN_FORMATQUERY 消息以在 .NET 格式字符串中使用回调字段

发布于 2024-12-25 23:47:15 字数 19795 浏览 1 评论 0原文

我需要在 .NET 中使用 DateTimePicker 控件的回调字段功能,这在 C++ 中进行了描述:示例

但是在.NET中实现WmFormat方法有点痛苦。一切正常,回调字段捕获 WmKeyDown 消息并更改日期值,但控件不绘制回调字段。这是我的实现:

Private Sub WmFormat(ByRef m As Message)
    Dim nmdatetimeformat As FWEx.Win32API.NMDATETIMEFORMAT = m.GetLParam(GetType(FWEx.Win32API.NMDATETIMEFORMAT))
    Dim format As String = Marshal.PtrToStringAuto(nmdatetimeformat.pszFormat)
    Dim time As Date = SysTimeToDateTime(nmdatetimeformat.st)

    If format = "XX" Then
        Dim week As Integer = System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(time, Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday)
        ' Here is the problem. The week number does not shown in custom field.
        nmdatetimeformat.pszDisplay = Marshal.StringToHGlobalUni(week.ToString)

        ' I've tried more copy methods without luck
        ' nmdatetimeformat.pszDisplay = Marshal.StringToBSTR(week.ToString)
        ' Marshal.Copy(week.ToString.ToCharArray(), 0, nmdatetimeformat.pszDisplay, week.ToString.Length)

        Marshal.StructureToPtr(nmdatetimeformat, m.LParam, True)
    End If

    m.Result = IntPtr.Zero
End Sub

任何人都可以告诉我我的代码有什么问题吗? 谢谢。

这是完整的源代码:

Imports System
Imports System.ComponentModel
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports System.Globalization

Public Class DateTimePickerEx
    Inherits DateTimePicker

    Private Const WM_REFLECT As Integer = &H2000

    Private Sub WmFormat(ByRef m As Message)
        Dim nmdatetimeformat As NMDATETIMEFORMAT = m.GetLParam(GetType(NMDATETIMEFORMAT))
        Dim format As String = Marshal.PtrToStringAuto(nmdatetimeformat.pszFormat)
        Dim time As Date = SysTimeToDateTime(nmdatetimeformat.st)

        If format = "XX" Then
            Dim week As Integer = System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(time, Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday)
            ' Here is the problem. The week number does not shown in custom field.

            nmdatetimeformat.pszDisplay = Marshal.StringToHGlobalUni(week.ToString)

            ' I've tried more copy methods without luck
            ' nmdatetimeformat.pszDisplay = Marshal.StringToBSTR(week.ToString)
            ' Marshal.Copy(week.ToString.ToCharArray(), 0, nmdatetimeformat.pszDisplay, week.ToString.Length)

            Marshal.StructureToPtr(nmdatetimeformat, m.LParam, True)
        End If

        m.Result = IntPtr.Zero
    End Sub

    Private Sub WmFormatQuery(ByRef m As Message)
        Dim nmdatetimeformatquery As NMDATETIMEFORMATQUERY = m.GetLParam(GetType(NMDATETIMEFORMATQUERY))
        Dim format As String = Marshal.PtrToStringAuto(nmdatetimeformatquery.pszFormat)
        Dim dst As IntPtr = (m.LParam.ToInt64() + Marshal.OffsetOf(GetType(NMDATETIMEFORMATQUERY), "szMax").ToInt64())
        'Dim dc As IntPtr = GetDC(Me.Handle)

        Dim textSize As Size = TextRenderer.MeasureText(Me.CreateGraphics, "52", Me.Font, New Size(20, 13), TextFormatFlags.NoPadding)
        nmdatetimeformatquery.szMax.cx = textSize.Width
        nmdatetimeformatquery.szMax.cy = textSize.Height

        Marshal.StructureToPtr(nmdatetimeformatquery, m.LParam, True)

        'Marshal.Copy(New Long() {nmdatetimeformatquery.szMax.cx, nmdatetimeformatquery.szMax.cy}, 0, dst, 2)
        m.Result = IntPtr.Zero
    End Sub

    Private Sub WmKeyDown(ByRef m As Message)
        Dim nmdatetimewmkeydown As NMDATETIMEWMKEYDOWN = m.GetLParam(GetType(NMDATETIMEWMKEYDOWN))
        Dim format As String = Marshal.PtrToStringAuto(nmdatetimewmkeydown.pszFormat)
        Dim curDat As Date = MyBase.Value

        Select Case format
            Case "XX"
                Select Case DirectCast(nmdatetimewmkeydown.nVirtKey, VirtualKeys)
                    Case VirtualKeys.VK_DOWN, VirtualKeys.VK_SUBTRACT
                        curDat = curDat.AddDays(-7)
                    Case VirtualKeys.VK_UP, VirtualKeys.VK_ADD
                        curDat = curDat.AddDays(7)
                    Case Else
                        Exit Sub
                End Select
            Case "X"

        End Select

        nmdatetimewmkeydown.st.Day = curDat.Day
        nmdatetimewmkeydown.st.Month = curDat.Month
        nmdatetimewmkeydown.st.Year = curDat.Year

        Marshal.StructureToPtr(nmdatetimewmkeydown, m.LParam, True)
        m.Result = IntPtr.Zero
    End Sub

    Private Sub WmDateTimeChange(ByRef m As Message)

    End Sub

    Private Sub WmNotifyDeltaPos(ByRef m As Message)
        Dim nmupdown As NMUPDOWN = m.GetLParam(GetType(NMUPDOWN))

        Dim vKey As VirtualKeys

        If nmupdown.iDelta < 0 Then
            vKey = VirtualKeys.VK_UP
            nmupdown.iDelta = Math.Abs(nmupdown.iDelta)
        ElseIf nmupdown.iDelta > 0 Then
            vKey = VirtualKeys.VK_DOWN
        Else
            Exit Sub
        End If

        For i As Integer = 0 To nmupdown.iDelta - 1
            PostMessage(IntPtr.Zero, WindowsMessages.WM_KEYDOWN, vKey, &H1)
            PostMessage(IntPtr.Zero, WindowsMessages.WM_KEYUP, vKey, &H10000001)
        Next
    End Sub

    Private Sub WmDropDown(ByRef m As Message)

    End Sub

    Private Function WmReflectCommand(ByRef m As Message) As Boolean
        If m.HWnd = Me.Handle Then
            Dim code As Long = NMHDR.FromMessage(m).code

            If DirectCast(m.Msg, WindowsMessages) And WM_REFLECT Then
                Select Case code
                    Case -756
                        Me.WmFormat(m)
                        Return True
                    Case DateTimePickerNotifications.DTN_FORMAT
                        Me.WmFormat(m)
                        Return True
                    Case DateTimePickerNotifications.DTN_FORMATQUERY
                        Me.WmFormatQuery(m)
                        Return True
                    Case DateTimePickerNotifications.DTN_WMKEYDOWN
                        Me.WmKeyDown(m)
                        Return True
                    Case -759 'DateTimePickerNotifications.DTN_DATETIMECHANGE
                        'Me.WmDateTimeChange(m)
                        'Return True
                    Case -754
                        'Me.WmDropDown(m)
                        '   Return True
                    Case Is < 0
                        Return False
                End Select
            Else
                Select Case code
                    Case UpDownNotifications.UDN_DELTAPOS
                        Me.WmNotifyDeltaPos(m)
                        Return True
                End Select
            End If

            Return False
        End If
    End Function

    Private Function SysTimeToDateTime(st As SYSTEMTIME) As Date
        Return New Date(st.Year, st.Month, st.Day, st.Hour, st.Minute, st.Second)
    End Function
    <System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")>
    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        If m.Msg <> 71 AndAlso m.Msg <> 513 Then
            Select Case DirectCast(m.Msg, WindowsMessages)
                Case WindowsMessages.WM_NOTIFY + WM_REFLECT, WindowsMessages.WM_NOTIFY
                    If Not Me.WmReflectCommand(m) Then
                        Exit Select
                    End If

                    Exit Sub
            End Select
        End If

        MyBase.WndProc(m)
    End Sub

 <StructLayout(LayoutKind.Sequential)>
        Public Structure NMDATETIMEFORMAT
            ''' <summary>
            ''' NMHDR structure that contains information about the message.
            ''' </summary>
            Public nmhdr As NMHDR
            ''' <summary>
            ''' Pointer to the null-terminated substring that defines a DTP control callback field. 
            ''' The substring comprises one or more X characters, followed by a NULL character.
            ''' </summary>
            Public pszFormat As IntPtr
            ''' <summary>
            ''' SYSTEMTIME structure that contains information about the current system date and time.
            ''' </summary>
            Public st As SYSTEMTIME
            ''' <summary>
            ''' Pointer to a null-terminated string. 
            ''' By default, this pointer is set to point at szDisplay by the DTP control.
            ''' It is legal to set this member to point at an existing string. 
            ''' If so, the application is not required to place a string into the szDisplay member.
            ''' </summary>
            Public pszDisplay As IntPtr
            ''' <summary>
            ''' Specifies the 64-character buffer that is to receive the null-terminated string that the DTP control will display.
            ''' It is not necessary that the application fill the entire buffer.
            ''' </summary>
            <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=64)>
            Public szDisplay As String
        End Structure

        ''' <summary>
        ''' This structure is used with the DTN_FORMATQUERY notification message.
        ''' </summary>
        ''' <remarks>
        ''' The NMDATETIMEFORMATQUERY structure contains information about a date and time picker (DTP) control callback field. 
        ''' It contains a substring (taken from the controls format string) that defines a callback field. 
        ''' The structure receives the maximum allowable size of the text that will be displayed in the callback field.
        ''' </remarks>
        <StructLayout(LayoutKind.Sequential)>
        Public Structure NMDATETIMEFORMATQUERY
            ''' <summary>
            ''' NMHDR structure that contains information about this notification message.
            ''' </summary>
            Public nmhdr As NMHDR
            ''' <summary>
            ''' Pointer to a null-terminated substring that defines a DTP control callback field. 
            ''' The substring is one or more X characters followed by a NULL.
            ''' </summary>
            Public pszFormat As IntPtr
            ''' <summary>
            ''' SIZE structure that must be filled with the maximum size of the text to be displayed in the callback field.
            ''' </summary>
            Public szMax As SIZE
        End Structure

        ''' <summary>
        ''' This structure carries information used to describe and handle a DTN_WMKEYDOWN notification message.
        ''' </summary>
        <StructLayout(LayoutKind.Sequential)>
        Public Structure NMDATETIMEWMKEYDOWN
            ''' <summary>
            ''' NMHDR structure that contains information about the notification message.
            ''' </summary>
            Public nmhdr As NMHDR
            ''' <summary>
            ''' Virtual key code that represents the key that the user pressed.
            ''' </summary>
            Public nVirtKey As Integer
            ''' <summary>
            ''' Pointer to a null-terminated substring, taken from the format string, that defines the callback field. 
            ''' The substring is one or more X characters, followed by a NULL.
            ''' </summary>
            Public pszFormat As IntPtr
            ''' <summary>
            ''' SYSTEMTIME structure containing the current date and time from the DTP control. 
            ''' The owner of the control must modify the time information based on the users keystroke.
            ''' </summary>
            Public st As SYSTEMTIME
        End Structure

''' <summary>
        ''' The SIZE structure specifies the width and height of a rectangle.
        ''' </summary>
        ''' <remarks>
        ''' The rectangle dimensions stored in this structure may correspond to viewport extents, 
        ''' window extents, text extents, bitmap dimensions, or the aspect-ratio filter for some extended functions.
        ''' </remarks>
        <StructLayout(LayoutKind.Sequential)>
        Public Structure SIZE
            ''' <summary>
            ''' Specifies the rectangle's width. The units depend on which function uses this.
            ''' </summary>
            Public cx As Long
            ''' <summary>
            ''' Specifies the rectangle's height. The units depend on which function uses this.
            ''' </summary>
            Public cy As Long
        End Structure

 ''' <summary>
        ''' This structure contains information about a message.
        ''' The pointer to this structure is specified as the lParam member of the WM_NOTIFY message.
        ''' </summary>
        <StructLayout(LayoutKind.Sequential)> _
        Public Structure NMHDR
            ''' <summary>
            ''' Window handle to the control sending a message.
            ''' </summary>
            Public hwndFrom As IntPtr

            ''' <summary>
            ''' Identifier of the control sending a message.
            ''' </summary>
            Public idFrom As IntPtr

            ''' <summary>
            ''' 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:
            ''' - NM_RCLICK
            ''' - NM_RDBCLICK
            ''' </summary>
            Public code As Integer

            Public Shared Function FromMessage(ByVal msg As System.Windows.Forms.Message) As NMHDR
                Return DirectCast(msg.GetLParam(GetType(NMHDR)), NMHDR)
            End Function
        End Structure

 ''' <summary>
        ''' Specifies a date and time, using individual members for the month, day, year, weekday, hour, minute, second, and millisecond. 
        ''' The time is either in coordinated universal time (UTC) or local time, depending on the function that is being called.
        ''' </summary>
        ''' <remarks>
        ''' It is not recommended that you add and subtract values from the SYSTEMTIME structure to obtain relative times.
        ''' </remarks>
        Public Structure SYSTEMTIME
            ''' <summary>
            ''' The year. The valid values for this member are 1601 through 30827.
            ''' </summary>
            Public Year As Short
            ''' <summary>
            ''' The month.
            ''' </summary>
            Public Month As Short
            ''' <summary>
            ''' The day of the week. Sunday = 0.
            ''' </summary>
            Public DayOfWeek As Short
            ''' <summary>
            ''' The day of the month. The valid values for this member are 1 through 31.
            ''' </summary>
            Public Day As Short
            ''' <summary>
            ''' The hour. The valid values for this member are 0 through 23.
            ''' </summary>
            Public Hour As Short
            ''' <summary>
            ''' The minute. The valid values for this member are 0 through 59.
            ''' </summary>
            Public Minute As Short
            ''' <summary>
            ''' The second. The valid values for this member are 0 through 59.
            ''' </summary>
            Public Second As Short
            ''' <summary>
            ''' The millisecond. The valid values for this member are 0 through 999.
            ''' </summary>
            Public Milliseconds As Short
        End Structure

''' <summary>
        ''' Contains information specific to up-down control notification messages.
        ''' It is identical to and replaces the NM_UPDOWN structure. 
        ''' </summary>
        ''' <remarks></remarks>
        Public Structure NMUPDOWN
            ''' <summary>
            ''' NMHDR structure that contains additional information about the notification. 
            ''' </summary>
            Public hdr As NMHDR
            ''' <summary>
            ''' Signed integer value that represents the up-down control's current position. 
            ''' </summary>
            Public iPos As Integer
            ''' <summary>
            ''' Signed integer value that represents the proposed change in the up-down control's position. 
            ''' </summary>
            Public iDelta As Integer
        End Structure

Public Enum DateTimePickerMessages
            DTM_FIRST = &H1000
            DTM_GETSYSTEMTIME = DTM_FIRST + 1
            DTM_SETSYSTEMTIME = DTM_FIRST + 2
            DTM_GETRANGE = DTM_FIRST + 3
            DTM_SETRANGE = DTM_FIRST + 4
            DTM_SETFORMAT = DTM_FIRST + 5
            DTM_SETMCCOLOR = DTM_FIRST + 6
            DTM_GETMCCOLOR = DTM_FIRST + 7
            DTM_GETMONTHCAL = DTM_FIRST + 8
            DTM_SETMCFONT = DTM_FIRST + 9
            DTM_GETMCFONT = DTM_FIRST + 10
            DTM_SETMCSTYLE = DTM_FIRST + 11
            DTM_GETMCSTYLE = DTM_FIRST + 12
            DTM_CLOSEMONTHCAL = DTM_FIRST + 13
            DTM_GETDATETIMEPICKERINFO = DTM_FIRST + 14
            DTM_GETIDEALSIZE = DTM_FIRST + 15
        End Enum

        Public Enum DateTimePickerNotifications
            DTN_FIRST = -740
            DTN_LAST = -745
            DTN_FIRST2 = -753
            DTN_LAST2 = -799
            DTN_DATETIMECHANGE = DTN_FIRST - 6
            DTN_USERSTRING = DTN_FIRST - 5
            DTN_WMKEYDOWN = DTN_FIRST - 4
            DTN_FORMAT = DTN_FIRST - 3
            DTN_FORMATQUERY = DTN_FIRST - 2
            DTN_DROPDOWN = DTN_FIRST - 1
            DTN_CLOSEUP = DTN_FIRST
        End Enum

Public Enum UpDownNotifications
            UDN_FIRST = -721
            UDN_LAST = -729
            UDN_DELTAPOS = UDN_FIRST - 1
        End Enum

Public Enum WindowsMessages
''' <summary>
            '''Sent by a common control to its parent window when an event has occurred or the control requires some information.
            ''' </summary>
            WM_NOTIFY = &H4E

''' <summary>
            '''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.
            ''' </summary>
            WM_KEYDOWN = &H100

''' <summary>
            '''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.
            ''' </summary>
            WM_KEYUP = &H101
End Enum

''' <summary>
        ''' The VirtualKeys enumeration is also managed as System.Windows.Forms.Keys.
        ''' The bracketed [keynames] are from that managed Forms.Keys enumeration.
        ''' </summary>
        ''' <remarks></remarks>
        Public Enum VirtualKeys As Integer
VK_UP = &H26        ' // [Up] = 038
VK_DOWN = &H28          ' // [Down] = 040
VK_ADD = &H6B           ' // [Add] = 107
VK_SUBTRACT = &H6D      ' // [Subtract] = 109
End Enum

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

I need to use the callback fileds capability of the DateTimePicker control in .NET, what is described here in C++:example.

But this is a little pain to implement the WmFormat method in .NET. Everything works fine, the callback field capturing the WmKeyDown message and changing the date value, but the control doesn't paint the callback field. Here is my implementation:

Private Sub WmFormat(ByRef m As Message)
    Dim nmdatetimeformat As FWEx.Win32API.NMDATETIMEFORMAT = m.GetLParam(GetType(FWEx.Win32API.NMDATETIMEFORMAT))
    Dim format As String = Marshal.PtrToStringAuto(nmdatetimeformat.pszFormat)
    Dim time As Date = SysTimeToDateTime(nmdatetimeformat.st)

    If format = "XX" Then
        Dim week As Integer = System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(time, Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday)
        ' Here is the problem. The week number does not shown in custom field.
        nmdatetimeformat.pszDisplay = Marshal.StringToHGlobalUni(week.ToString)

        ' I've tried more copy methods without luck
        ' nmdatetimeformat.pszDisplay = Marshal.StringToBSTR(week.ToString)
        ' Marshal.Copy(week.ToString.ToCharArray(), 0, nmdatetimeformat.pszDisplay, week.ToString.Length)

        Marshal.StructureToPtr(nmdatetimeformat, m.LParam, True)
    End If

    m.Result = IntPtr.Zero
End Sub

Can anybody tell me what's wrong on my code?
Thank you.

Here is the full source code:

Imports System
Imports System.ComponentModel
Imports System.Drawing
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports System.Globalization

Public Class DateTimePickerEx
    Inherits DateTimePicker

    Private Const WM_REFLECT As Integer = &H2000

    Private Sub WmFormat(ByRef m As Message)
        Dim nmdatetimeformat As NMDATETIMEFORMAT = m.GetLParam(GetType(NMDATETIMEFORMAT))
        Dim format As String = Marshal.PtrToStringAuto(nmdatetimeformat.pszFormat)
        Dim time As Date = SysTimeToDateTime(nmdatetimeformat.st)

        If format = "XX" Then
            Dim week As Integer = System.Globalization.CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(time, Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday)
            ' Here is the problem. The week number does not shown in custom field.

            nmdatetimeformat.pszDisplay = Marshal.StringToHGlobalUni(week.ToString)

            ' I've tried more copy methods without luck
            ' nmdatetimeformat.pszDisplay = Marshal.StringToBSTR(week.ToString)
            ' Marshal.Copy(week.ToString.ToCharArray(), 0, nmdatetimeformat.pszDisplay, week.ToString.Length)

            Marshal.StructureToPtr(nmdatetimeformat, m.LParam, True)
        End If

        m.Result = IntPtr.Zero
    End Sub

    Private Sub WmFormatQuery(ByRef m As Message)
        Dim nmdatetimeformatquery As NMDATETIMEFORMATQUERY = m.GetLParam(GetType(NMDATETIMEFORMATQUERY))
        Dim format As String = Marshal.PtrToStringAuto(nmdatetimeformatquery.pszFormat)
        Dim dst As IntPtr = (m.LParam.ToInt64() + Marshal.OffsetOf(GetType(NMDATETIMEFORMATQUERY), "szMax").ToInt64())
        'Dim dc As IntPtr = GetDC(Me.Handle)

        Dim textSize As Size = TextRenderer.MeasureText(Me.CreateGraphics, "52", Me.Font, New Size(20, 13), TextFormatFlags.NoPadding)
        nmdatetimeformatquery.szMax.cx = textSize.Width
        nmdatetimeformatquery.szMax.cy = textSize.Height

        Marshal.StructureToPtr(nmdatetimeformatquery, m.LParam, True)

        'Marshal.Copy(New Long() {nmdatetimeformatquery.szMax.cx, nmdatetimeformatquery.szMax.cy}, 0, dst, 2)
        m.Result = IntPtr.Zero
    End Sub

    Private Sub WmKeyDown(ByRef m As Message)
        Dim nmdatetimewmkeydown As NMDATETIMEWMKEYDOWN = m.GetLParam(GetType(NMDATETIMEWMKEYDOWN))
        Dim format As String = Marshal.PtrToStringAuto(nmdatetimewmkeydown.pszFormat)
        Dim curDat As Date = MyBase.Value

        Select Case format
            Case "XX"
                Select Case DirectCast(nmdatetimewmkeydown.nVirtKey, VirtualKeys)
                    Case VirtualKeys.VK_DOWN, VirtualKeys.VK_SUBTRACT
                        curDat = curDat.AddDays(-7)
                    Case VirtualKeys.VK_UP, VirtualKeys.VK_ADD
                        curDat = curDat.AddDays(7)
                    Case Else
                        Exit Sub
                End Select
            Case "X"

        End Select

        nmdatetimewmkeydown.st.Day = curDat.Day
        nmdatetimewmkeydown.st.Month = curDat.Month
        nmdatetimewmkeydown.st.Year = curDat.Year

        Marshal.StructureToPtr(nmdatetimewmkeydown, m.LParam, True)
        m.Result = IntPtr.Zero
    End Sub

    Private Sub WmDateTimeChange(ByRef m As Message)

    End Sub

    Private Sub WmNotifyDeltaPos(ByRef m As Message)
        Dim nmupdown As NMUPDOWN = m.GetLParam(GetType(NMUPDOWN))

        Dim vKey As VirtualKeys

        If nmupdown.iDelta < 0 Then
            vKey = VirtualKeys.VK_UP
            nmupdown.iDelta = Math.Abs(nmupdown.iDelta)
        ElseIf nmupdown.iDelta > 0 Then
            vKey = VirtualKeys.VK_DOWN
        Else
            Exit Sub
        End If

        For i As Integer = 0 To nmupdown.iDelta - 1
            PostMessage(IntPtr.Zero, WindowsMessages.WM_KEYDOWN, vKey, &H1)
            PostMessage(IntPtr.Zero, WindowsMessages.WM_KEYUP, vKey, &H10000001)
        Next
    End Sub

    Private Sub WmDropDown(ByRef m As Message)

    End Sub

    Private Function WmReflectCommand(ByRef m As Message) As Boolean
        If m.HWnd = Me.Handle Then
            Dim code As Long = NMHDR.FromMessage(m).code

            If DirectCast(m.Msg, WindowsMessages) And WM_REFLECT Then
                Select Case code
                    Case -756
                        Me.WmFormat(m)
                        Return True
                    Case DateTimePickerNotifications.DTN_FORMAT
                        Me.WmFormat(m)
                        Return True
                    Case DateTimePickerNotifications.DTN_FORMATQUERY
                        Me.WmFormatQuery(m)
                        Return True
                    Case DateTimePickerNotifications.DTN_WMKEYDOWN
                        Me.WmKeyDown(m)
                        Return True
                    Case -759 'DateTimePickerNotifications.DTN_DATETIMECHANGE
                        'Me.WmDateTimeChange(m)
                        'Return True
                    Case -754
                        'Me.WmDropDown(m)
                        '   Return True
                    Case Is < 0
                        Return False
                End Select
            Else
                Select Case code
                    Case UpDownNotifications.UDN_DELTAPOS
                        Me.WmNotifyDeltaPos(m)
                        Return True
                End Select
            End If

            Return False
        End If
    End Function

    Private Function SysTimeToDateTime(st As SYSTEMTIME) As Date
        Return New Date(st.Year, st.Month, st.Day, st.Hour, st.Minute, st.Second)
    End Function
    <System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")>
    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        If m.Msg <> 71 AndAlso m.Msg <> 513 Then
            Select Case DirectCast(m.Msg, WindowsMessages)
                Case WindowsMessages.WM_NOTIFY + WM_REFLECT, WindowsMessages.WM_NOTIFY
                    If Not Me.WmReflectCommand(m) Then
                        Exit Select
                    End If

                    Exit Sub
            End Select
        End If

        MyBase.WndProc(m)
    End Sub

 <StructLayout(LayoutKind.Sequential)>
        Public Structure NMDATETIMEFORMAT
            ''' <summary>
            ''' NMHDR structure that contains information about the message.
            ''' </summary>
            Public nmhdr As NMHDR
            ''' <summary>
            ''' Pointer to the null-terminated substring that defines a DTP control callback field. 
            ''' The substring comprises one or more X characters, followed by a NULL character.
            ''' </summary>
            Public pszFormat As IntPtr
            ''' <summary>
            ''' SYSTEMTIME structure that contains information about the current system date and time.
            ''' </summary>
            Public st As SYSTEMTIME
            ''' <summary>
            ''' Pointer to a null-terminated string. 
            ''' By default, this pointer is set to point at szDisplay by the DTP control.
            ''' It is legal to set this member to point at an existing string. 
            ''' If so, the application is not required to place a string into the szDisplay member.
            ''' </summary>
            Public pszDisplay As IntPtr
            ''' <summary>
            ''' Specifies the 64-character buffer that is to receive the null-terminated string that the DTP control will display.
            ''' It is not necessary that the application fill the entire buffer.
            ''' </summary>
            <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=64)>
            Public szDisplay As String
        End Structure

        ''' <summary>
        ''' This structure is used with the DTN_FORMATQUERY notification message.
        ''' </summary>
        ''' <remarks>
        ''' The NMDATETIMEFORMATQUERY structure contains information about a date and time picker (DTP) control callback field. 
        ''' It contains a substring (taken from the controls format string) that defines a callback field. 
        ''' The structure receives the maximum allowable size of the text that will be displayed in the callback field.
        ''' </remarks>
        <StructLayout(LayoutKind.Sequential)>
        Public Structure NMDATETIMEFORMATQUERY
            ''' <summary>
            ''' NMHDR structure that contains information about this notification message.
            ''' </summary>
            Public nmhdr As NMHDR
            ''' <summary>
            ''' Pointer to a null-terminated substring that defines a DTP control callback field. 
            ''' The substring is one or more X characters followed by a NULL.
            ''' </summary>
            Public pszFormat As IntPtr
            ''' <summary>
            ''' SIZE structure that must be filled with the maximum size of the text to be displayed in the callback field.
            ''' </summary>
            Public szMax As SIZE
        End Structure

        ''' <summary>
        ''' This structure carries information used to describe and handle a DTN_WMKEYDOWN notification message.
        ''' </summary>
        <StructLayout(LayoutKind.Sequential)>
        Public Structure NMDATETIMEWMKEYDOWN
            ''' <summary>
            ''' NMHDR structure that contains information about the notification message.
            ''' </summary>
            Public nmhdr As NMHDR
            ''' <summary>
            ''' Virtual key code that represents the key that the user pressed.
            ''' </summary>
            Public nVirtKey As Integer
            ''' <summary>
            ''' Pointer to a null-terminated substring, taken from the format string, that defines the callback field. 
            ''' The substring is one or more X characters, followed by a NULL.
            ''' </summary>
            Public pszFormat As IntPtr
            ''' <summary>
            ''' SYSTEMTIME structure containing the current date and time from the DTP control. 
            ''' The owner of the control must modify the time information based on the users keystroke.
            ''' </summary>
            Public st As SYSTEMTIME
        End Structure

''' <summary>
        ''' The SIZE structure specifies the width and height of a rectangle.
        ''' </summary>
        ''' <remarks>
        ''' The rectangle dimensions stored in this structure may correspond to viewport extents, 
        ''' window extents, text extents, bitmap dimensions, or the aspect-ratio filter for some extended functions.
        ''' </remarks>
        <StructLayout(LayoutKind.Sequential)>
        Public Structure SIZE
            ''' <summary>
            ''' Specifies the rectangle's width. The units depend on which function uses this.
            ''' </summary>
            Public cx As Long
            ''' <summary>
            ''' Specifies the rectangle's height. The units depend on which function uses this.
            ''' </summary>
            Public cy As Long
        End Structure

 ''' <summary>
        ''' This structure contains information about a message.
        ''' The pointer to this structure is specified as the lParam member of the WM_NOTIFY message.
        ''' </summary>
        <StructLayout(LayoutKind.Sequential)> _
        Public Structure NMHDR
            ''' <summary>
            ''' Window handle to the control sending a message.
            ''' </summary>
            Public hwndFrom As IntPtr

            ''' <summary>
            ''' Identifier of the control sending a message.
            ''' </summary>
            Public idFrom As IntPtr

            ''' <summary>
            ''' 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:
            ''' - NM_RCLICK
            ''' - NM_RDBCLICK
            ''' </summary>
            Public code As Integer

            Public Shared Function FromMessage(ByVal msg As System.Windows.Forms.Message) As NMHDR
                Return DirectCast(msg.GetLParam(GetType(NMHDR)), NMHDR)
            End Function
        End Structure

 ''' <summary>
        ''' Specifies a date and time, using individual members for the month, day, year, weekday, hour, minute, second, and millisecond. 
        ''' The time is either in coordinated universal time (UTC) or local time, depending on the function that is being called.
        ''' </summary>
        ''' <remarks>
        ''' It is not recommended that you add and subtract values from the SYSTEMTIME structure to obtain relative times.
        ''' </remarks>
        Public Structure SYSTEMTIME
            ''' <summary>
            ''' The year. The valid values for this member are 1601 through 30827.
            ''' </summary>
            Public Year As Short
            ''' <summary>
            ''' The month.
            ''' </summary>
            Public Month As Short
            ''' <summary>
            ''' The day of the week. Sunday = 0.
            ''' </summary>
            Public DayOfWeek As Short
            ''' <summary>
            ''' The day of the month. The valid values for this member are 1 through 31.
            ''' </summary>
            Public Day As Short
            ''' <summary>
            ''' The hour. The valid values for this member are 0 through 23.
            ''' </summary>
            Public Hour As Short
            ''' <summary>
            ''' The minute. The valid values for this member are 0 through 59.
            ''' </summary>
            Public Minute As Short
            ''' <summary>
            ''' The second. The valid values for this member are 0 through 59.
            ''' </summary>
            Public Second As Short
            ''' <summary>
            ''' The millisecond. The valid values for this member are 0 through 999.
            ''' </summary>
            Public Milliseconds As Short
        End Structure

''' <summary>
        ''' Contains information specific to up-down control notification messages.
        ''' It is identical to and replaces the NM_UPDOWN structure. 
        ''' </summary>
        ''' <remarks></remarks>
        Public Structure NMUPDOWN
            ''' <summary>
            ''' NMHDR structure that contains additional information about the notification. 
            ''' </summary>
            Public hdr As NMHDR
            ''' <summary>
            ''' Signed integer value that represents the up-down control's current position. 
            ''' </summary>
            Public iPos As Integer
            ''' <summary>
            ''' Signed integer value that represents the proposed change in the up-down control's position. 
            ''' </summary>
            Public iDelta As Integer
        End Structure

Public Enum DateTimePickerMessages
            DTM_FIRST = &H1000
            DTM_GETSYSTEMTIME = DTM_FIRST + 1
            DTM_SETSYSTEMTIME = DTM_FIRST + 2
            DTM_GETRANGE = DTM_FIRST + 3
            DTM_SETRANGE = DTM_FIRST + 4
            DTM_SETFORMAT = DTM_FIRST + 5
            DTM_SETMCCOLOR = DTM_FIRST + 6
            DTM_GETMCCOLOR = DTM_FIRST + 7
            DTM_GETMONTHCAL = DTM_FIRST + 8
            DTM_SETMCFONT = DTM_FIRST + 9
            DTM_GETMCFONT = DTM_FIRST + 10
            DTM_SETMCSTYLE = DTM_FIRST + 11
            DTM_GETMCSTYLE = DTM_FIRST + 12
            DTM_CLOSEMONTHCAL = DTM_FIRST + 13
            DTM_GETDATETIMEPICKERINFO = DTM_FIRST + 14
            DTM_GETIDEALSIZE = DTM_FIRST + 15
        End Enum

        Public Enum DateTimePickerNotifications
            DTN_FIRST = -740
            DTN_LAST = -745
            DTN_FIRST2 = -753
            DTN_LAST2 = -799
            DTN_DATETIMECHANGE = DTN_FIRST - 6
            DTN_USERSTRING = DTN_FIRST - 5
            DTN_WMKEYDOWN = DTN_FIRST - 4
            DTN_FORMAT = DTN_FIRST - 3
            DTN_FORMATQUERY = DTN_FIRST - 2
            DTN_DROPDOWN = DTN_FIRST - 1
            DTN_CLOSEUP = DTN_FIRST
        End Enum

Public Enum UpDownNotifications
            UDN_FIRST = -721
            UDN_LAST = -729
            UDN_DELTAPOS = UDN_FIRST - 1
        End Enum

Public Enum WindowsMessages
''' <summary>
            '''Sent by a common control to its parent window when an event has occurred or the control requires some information.
            ''' </summary>
            WM_NOTIFY = &H4E

''' <summary>
            '''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.
            ''' </summary>
            WM_KEYDOWN = &H100

''' <summary>
            '''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.
            ''' </summary>
            WM_KEYUP = &H101
End Enum

''' <summary>
        ''' The VirtualKeys enumeration is also managed as System.Windows.Forms.Keys.
        ''' The bracketed [keynames] are from that managed Forms.Keys enumeration.
        ''' </summary>
        ''' <remarks></remarks>
        Public Enum VirtualKeys As Integer
VK_UP = &H26        ' // [Up] = 038
VK_DOWN = &H28          ' // [Down] = 040
VK_ADD = &H6B           ' // [Add] = 107
VK_SUBTRACT = &H6D      ' // [Subtract] = 109
End Enum

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文