【问题标题】:How to automate calendar date selection in 3rd party .NET application?如何在 3rd 方 .NET 应用程序中自动选择日历日期?
【发布时间】:2011-07-05 16:05:34
【问题描述】:

我正在使用 AutoIt 在第 3 方 .NET 应用程序中自动填写表单。我无法在日历控件中设置日期。

根据 AutoIt3 Window Info Tool,该控件的类类型为 WindowsForms10.SysDateTimePick32.app.0.378734a。最初我只是尝试将控件的文本设置为我想要的日期,但这根本没有做任何事情。

然后我尝试使用_GUICtrlMonthCal_SetCurSel,但是(与我尝试的所有_GUI* 函数一样)这也没有做任何事情(包括正确的标题,当我运行它时它没有做任何事情)。

有没有人知道我该怎么做?

【问题讨论】:

    标签: .net autoit


    【解决方案1】:

    您不能使用 GUICtrlMonthCal* 函数的原因是因为您没有处理月份/日历控件。在 .NET 中确实有它们,但在这种情况下,它是 DateTimePicker。

    DateTimePickers 在下拉菜单中确实有一个 MonthCalender,但看起来这是在您单击下拉菜单时创建的,因此很难直接控制。相反,我通过设置一个小测试用例来查看程序设置值时会发生什么......这些是我发现的消息:

    <00001> 00090572 S WM_GETTEXTLENGTH
    <00002> 00090572 R WM_GETTEXTLENGTH cch:12
    <00003> 00090572 S WM_GETTEXT cchTextMax:26 lpszText:05E8D51C
    <00004> 00090572 R WM_GETTEXT cchCopied:12 lpszText:05E8D51C ("0")
    <00005> 00090572 S message:0x1002 [User-defined:WM_USER+3074] wParam:00000000 lParam:01F6A2A8
    <00006> 00090572 R message:0x1002 [User-defined:WM_USER+3074] lResult:00000001
    <00007> 00090572 S WM_GETTEXTLENGTH
    <00008> 00090572 R WM_GETTEXTLENGTH cch:12
    <00009> 00090572 S WM_GETTEXT cchTextMax:26 lpszText:05E8D51C
    <00010> 00090572 R WM_GETTEXT cchCopied:12 lpszText:05E8D51C ("0")
    <00011> 00090572 P WM_PAINT hdc:00000000
    <00012> 00090572 S WM_ERASEBKGND hdc:54010EE3
    <00013> 00090572 R WM_ERASEBKGND fErased:True
    

    最有趣的是用户定义的消息,这是控件通常如何获取它们独有的消息。如果我们假设我是正确的 0x1002 设置数据,那么唯一要做的就是看看 lParam 的含义。当您将值设置为 DateTime 对象时,这可能会很棘手。

    接下来我要做的是检查 ildasm 以查看 System.Windows.Forms.DateTimePicker::set_Value 因为我想这会告诉你很多关于 .NET 是如何做到的......我会做更多研究并更新这篇文章。

    第 2 部分:好的,所以 set_Value 的反汇编完成了我所说的...它使用 DateTimeToSysTime 将 DateTime 转换为他们所谓的“系统”时间...虽然不公开可见,但您可以大致看到什么它在 ILDasm 中运行......但更容易假设它使用标准的 WinAPI SYSTEMTIME 结构here。这是相当多的阅读,但您需要填写其中一个结构。

    然后我们可以做出相当安全的假设,即我们想要的消息中的 lParam 是指向 SYSTEMTIME 结构的指针...我将对其进行测试并更新帖子:)

    第 3 部分:现在是激动人心的部分……让它在实践中发挥作用。第一个问题是我们不能使用 SendMessage 在应用程序之间移动指针,因此我们需要一些额外的代码来在其他程序中创建缓冲区。除此之外,它的工作方式完全符合我的预期:

    #Include <GuiMonthCal.au3> ; $tagSYSTEMTIME is defined in here.
    
    Local $tSI = DllStructCreate($tagSYSTEMTIME)
    
    Local $hControl = ControlGetHandle("Date/Time Picker", "", "[NAME:ExampleDateTimePicker]")
    If @error Then Exit 0 * MsgBox(16, "Error", "Demo control not found.")
    
    ; Fill the structure to current date/time using GetLocalTime
    DllCall("kernel32.dll", "none", "GetLocalTime", "ptr", DllStructGetPtr($tSI))
    If @error Then Exit 0 * MsgBox(16, "Error", "GetLocalTime failed.")
    
    ; Change the year
    DllStructSetData($tSI, "Year", 2005)
    
    ; The struct needs to be in the process memory, so it's a bit of a workaround.
    Local $tMemMap
    Local $pMemory = _MemInit($hControl, DllStructGetSize($tSI), $tMemMap)
    _MemWrite($tMemMap, DllStructGetPtr($tSI))
    $iRet = _SendMessage($hControl, 0x1002, 0, $pMemory, 0, "wparam", "ptr")
    _MemFree($tMemMap)
    

    当您运行它时,日期部分应更改为 2005。唯一的问题是它不会触发 OnValueChanged 事件,因此如果您尝试自动化的程序中有任何处理程序代码,那么它可能不会与用户更改值时的工作方式完全相同。

    【讨论】:

      猜你喜欢
      • 2020-05-14
      • 2020-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-29
      • 1970-01-01
      • 2012-04-29
      • 2021-12-17
      相关资源
      最近更新 更多