AutoIT: автоматизировать выбор даты в календаре в стороннем приложении .NET - PullRequest
0 голосов
/ 05 июля 2011

Я пытаюсь использовать AutoIt для автоматизации заполнения формы в стороннем приложении .NET.

У меня возникли проблемы с установкой даты в элементе управления календаря.

Элемент управления, который я сейчас пытаюсь заполнить, имеет тип класса WindowsForms10.SysDateTimePick32.app.0.378734a, в соответствии с AutoIt3 Window Info.Сначала я просто попытался установить текст элемента управления на желаемую дату, но это ничего не дало.

Затем я попытался использовать _GUICtrlMonthCal_SetCurSel, но, как и все остальные _GUI*функции, которые я пытался использовать, они тоже ничего не делали (был включен правильный заголовок, он просто ничего не делал, когда я его запускал).

У кого-нибудь есть идеи, как мне поступитьоб этом?

Спасибо, Рик

1 Ответ

1 голос
/ 06 июля 2011

Причина, по которой вы не можете использовать функции 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 делает то, что я сказал, что это будет ... Он конвертируетDateTime к тому, что они называют «системным» временем, используя DateTimeToSysTime ... Что хотя и не публично видно, вы можете примерно увидеть, что он делает в ILDasm ... Но проще предположить, что он использует стандартную структуру WinAPI SYSTEMTIME здесь.Это неплохое чтение, но вам нужно заполнить одну из этих структур.

Затем мы можем сделать довольно безопасное предположение, что lParam в сообщении, которое мы хотим, является указателем на структуру SYSTEMTIME ... IЯ опробую его и обновлю сообщение:)

Часть 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, поэтому, если естьлюбой код обработчика для этой программы в программе, которую вы пытаетесь автоматизировать, может работать не так, как если бы пользователь изменил значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...