单位一应用软件,在一台电脑上运行某功能时提示“为MinDate属性指定了一个大于MaxDate当前值的值”,在其它电脑使用都正常。
经查询发现“为MinDate属性指定了一个大于MaxDate当前值的值” 提示是微软DTPicker控件的提示。表示为该控件MinDate属性设置值时大于了该控件MaxDate设置的值。
观察正常电脑上的情况,该控件MinDate会设置为从数据库中取出的一个值,MaxDate会设置为当前时间。
为啥就这台电脑会出错呢?没有思路直接重装机器,我晕,还是同样故障。
根据 https://support.microsoft.com/zh-cn/kb/198880内容发现设置这两个属性时会调用SendMessage给该控件发送消息。
/*
当试图设置 MinDate 或 MaxDate 属性时,SendMessage API 的调用会将"DTM_SETRANGE"消息发送到该控件以通知其新的日期范围设置。
此消息有三种设置方式(wParam):
只设置最小日期,不设置最大日期。
只设置最大日期,不设置最小日期。
同时设置最小日期和最大日期。
lParam
必须设置为指向一个两元素数组,数组元素为SYSTEMTIME 结构。
第一个元素用于指定最小日期信息,第二个元素用于指定最大日期信息。
创建一个新的标准 EXE 项目。默认情况下创建 Form1。
从 项目 菜单中选择 引用 选择"Microsoft Windows 公共控件-2 6.0",然后单击确定。
向 Form1 中添加一个 DTPicker 控件。
向 Form1 中添加五个命令按钮。
从 项目 菜单中选择 添加模块 并添加到项目的标准模块。
将以下代码粘贴到模块:
*/
Option Explicit
Public Type SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type
Public Declare Function SendMessage Lib "user32" Alias _
"SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long
Public Const DTM_SETRANGE = &H1004&
Public Const GDTR_MIN = 1
Public Const GDTR_MAX = 2
'将以下代码粘贴到 Form1 的代码窗口:
Option Explicit
Private Sub Command1_Click()
' Set DTPicker MinDate through normal means.
Me.DTPicker1.MinDate = "1/10/99"
End Sub
Private Sub Command2_Click()
'Set DTPicker MaxDate through normal means.
Me.DTPicker1.MaxDate = "1/17/99"
End Sub
Private Sub Command3_Click()
Dim TimeArray(1) As SYSTEMTIME
Dim result As Long
' Define first element of SYSTEMTIME Array to be minimum date.
TimeArray(0).wDay = 10
TimeArray(0).wMonth = 1
TimeArray(0).wYear = 1999
' Call API to send message to control to set MinDate.
result = SendMessage(Me.DTPicker1.hwnd, DTM_SETRANGE, _
GDTR_MIN, TimeArray(0))
End Sub
Private Sub Command4_Click()
Dim TimeArray(1) As SYSTEMTIME
Dim result As Long
' Define second element of SYSTEMTIME Array to be maximum date.
TimeArray(1).wDay = 17
TimeArray(1).wMonth = 1
TimeArray(1).wYear = 1999
' Call API to send message to control to set MaxDate.
result = SendMessage(Me.DTPicker1.hwnd, DTM_SETRANGE, _
GDTR_MAX, TimeArray(0))
End Sub
Private Sub Command5_Click()
Dim TimeArray(1) As SYSTEMTIME
Dim result As Long
' Define first element of SYSTEMTIME Array to be minimum date.
TimeArray(0).wDay = 10
TimeArray(0).wMonth = 1
TimeArray(0).wYear = 1999
' Define second element of SYSTEMTIME Array to be maximum date.
TimeArray(1).wDay = 17
TimeArray(1).wMonth = 1
TimeArray(1).wYear = 1999
' Call API to send message to control to set MinDate and MaxDate.
result = SendMessage(Me.DTPicker1.hwnd, DTM_SETRANGE, _
GDTR_MIN + GDTR_MAX, TimeArray(0))
End Sub
Private Sub Form_Load()
Me.Command1.Caption = "Set DTPicker MinDate Normally"
Me.Command2.Caption = "Set DTPicker MaxDate Normally"
Me.Command3.Caption = "Set DTPicker MinDate Via API"
Me.Command4.Caption = "Set DTPicker MaxDate Via API"
Me.Command5.Caption = "Set DTPicker Min and MaxDate Via API"
End Sub
上windbg调试器,设置断点:
bp User32!SendMessageA ".if(poi(esp+8) == 0x00001004) {} .else {gc}"
表示当调用SendMessageA函数并且第二个参数(消息类型)是0x00001004(DTM_SETRANGE消息)时中断,否则继续执行。
跟踪到一个结果如下:
0:000> g
eax=0012d700 ebx=03e93744 ecx=00120024 edx=00000006 esi=03e93780 edi=0012d710
eip=77d2f3c2 esp=0012d6e0 ebp=0012d720 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
USER32!SendMessageA:
77d2f3c2 8bff mov edi,edi
0:000> dd esp
0012d6e0 277d48d8 00050a50 00001004 00000003
0012d6f0 0012d700 00000000 0012d97c 277ca680
0012d700 00010641 00010001 00000000 00000000
0012d710 000707df 000d0001 0006000f 00000024
0012d720 0012d740 77105cd9 03e93744 258bf259
0012d730 00000001 0012d774 0ffaa4dc 0012d734
0012d740 0012d7d0 771062e8 03e93744 00000094
0012d750 00000004 0000000a 00000001 002097d4
可以看到第一个参数00050a50表示控件的hwnd,第二个参数00001004表示消息,第三个参数00000003表示同时设置mindate和maxdate,第四个参数0012d700是SYSTEMTIME结构数组地址。
0012d700地址行正好是mindate所有参数,00010641表示年月(interger类型为16位),0641表示1601年,0001表示1月,
0012d710地址行正好是maxdate所有参数,000707df表示年月(interger类型为16位),07df 表示2015年,0007表示7月,000d0001中的000d表示日13号。
等等,不对呀,今天应该是23号的。
在看系统时间,完了,果然是2015年7月13日。这就对了,前面说过“该控件MinDate会设置为从数据库中取出的一个值,MaxDate会设置为当前时间",
数据库中记录的值一定小于当前时间。系统时间设置过小了直接导致小于数据库中的时间。因此出错了。
本来以为当前时间会从数据库中取的,结果是这样。