Автор Тема: НЕофициальный FAQ AutoIt  (Прочитано 85076 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
НЕофициальный FAQ AutoIt
« Создано: Февраль 05, 2011, 00:47:49 »
Этот FAQ будет постепенно расти, по мере появления частых вопросов на форуме.

По любым предложениям/улучшениям/поправкам смело пишите мне в ЛС.



GUI и его элементы
1. Как избежать мерцание элементов GUI при их частом обновлений?
2. Как показать прокрутку только после того, когда текст выходит за рамки edit-поля?
3. Как сменить иконку у ListView Item?
4. Как правильно создавать дочерние окна?
5. Как правильно “запоминать” позицию GUI для последующих запусков?
6. Почему лучше использовать GUICtrl* вместо Control*?

Графика
1. Как получить размер изображения?

Автоматизация
1. Как учётной записи пользователя назначить административные права?
2. Как создать учётную запись пользователя с правами администратора?

Имитирование нажатия клавиш, Send, HotKeys
1. Почему не работает HotKeySet, или как обойти проблему с раскладкой клавиатуры при отправке сочетаний клавиш?

Общие принципы написания скриптов
1. Как эффективнее организовать операторы сравнения?
2. Почему лучше использовать BitOR для добавления значении констант (например в стилях GUI)?
3. Как предотвратить критические ошибки скрипта?
4. Как отловить критические ошибки скрипта?
5. Как сопоставить номер строки из ошибки скомпилированного скрипта с исходником?

Системный Tray
1. Как создать GUI по двойному нажатию на иконку в трее?

Разное
1. Как установить пароль на запуск скрипта?
2. Как запустить скрипт вместе с Windows?
3. Как передать данные из скрипта в скрипт (интеракция)?

Интернет и сеть
1. Как включить/выключить локальное сетевое подключение?
2. Как отправить GET-запрос?
3. Как отправить POST-запрос?
4. Как отправить имя и пароль для HTTP-аутентификации?
5. Как выполнить перенаправление по ссылке, и получить перенаправленную ссылку?

Файловая система
1. Как разделить/соединить файл?

Процессы, сервисы и работа с памятью
1. Как “заморозить/разморозить” процесс?

AutoIt-специфичное
1. Как заставить FileInstall работать с каталогами?
2. Как позволить запуск только одной копии программы?
« Последнее редактирование: Сентябрь 21, 2015, 02:39:12 от CreatoR »


Правила, Поиск, Супер тема


AutoIt is simple, subtle, elegant.


«Не оказываю тех. поддержку через ПМ/ICQ, и по электронной почте - для этого есть форум. (C)»
«Законы Мэрфи неоспоримы!»


Мои работы

Русское сообщество AutoIt

НЕофициальный FAQ AutoIt
« Ответ #15 Отправлен: Февраль 05, 2011, 00:47:49 »

Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814

  • Автор темы
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
Re: НЕофициальный FAQ AutoIt
« Ответ #15, Отправлен: Июль 08, 2011, 17:39:30 »
Вопрос:
Почему не работает HotKeySet, или как обойти проблему с раскладкой клавиатуры при отправке сочетаний клавиш?

Ответ:
Обход проблемы с HotKeySet/Accelerators при разных раскладках клавиатуры


Правила, Поиск, Супер тема


AutoIt is simple, subtle, elegant.


«Не оказываю тех. поддержку через ПМ/ICQ, и по электронной почте - для этого есть форум. (C)»
«Законы Мэрфи неоспоримы!»


Мои работы

Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814

  • Автор темы
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
Re: НЕофициальный FAQ AutoIt
« Ответ #16, Отправлен: Август 03, 2011, 04:49:37 »
Вопрос:
Как отправить GET-запрос?

Ответ:
  • С помощью InetGet/InetRead
    (нажмите для показа/скрытия)
  • С помощью WinHTTP через COM-интерфейс (http://msdn.microsoft.com/en-us/library/aa384106%28v=VS.85%29.aspx)
    (нажмите для показа/скрытия)
  • С помощью WinHttp.au3 (WinHTTP через DllCalls) (http://www.autoitscript.com/forum/topic/84133-winhttp-functions/)
    (нажмите для показа/скрытия)
  • С помощью TCP-функций AutoIt
    (нажмите для показа/скрытия)

Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814

  • Автор темы
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
Re: НЕофициальный FAQ AutoIt
« Ответ #17, Отправлен: Август 03, 2011, 04:52:15 »
Вопрос:
Как отправить POST-запрос?

Ответ:
  • С помощью WinHTTP через COM-интерфейс (http://msdn.microsoft.com/en-us/library/aa384106%28v=VS.85%29.aspx)
    (нажмите для показа/скрытия)
  • С помощью WinHttp.au3 (WinHTTP через DllCalls) (http://www.autoitscript.com/forum/topic/84133-winhttp-functions/)
    (нажмите для показа/скрытия)
  • С помощью TCP-функций AutoIt
    (нажмите для показа/скрытия)
« Последнее редактирование: Февраль 02, 2015, 12:11:36 от CreatoR »

Русское сообщество AutoIt

Re: НЕофициальный FAQ AutoIt
« Ответ #17 Отправлен: Август 03, 2011, 04:52:15 »

Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814

  • Автор темы
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
Re: НЕофициальный FAQ AutoIt
« Ответ #18, Отправлен: Август 04, 2011, 01:41:07 »
Вопрос:
Как отправить имя и пароль для HTTP-аутентификации?

Ответ:
  • С помощью InetGet/InetRead
    (нажмите для показа/скрытия)
  • С помощью WinHTTP через COM-интерфейс (http://msdn.microsoft.com/en-us/library/aa384106%28v=VS.85%29.aspx)
    (нажмите для показа/скрытия)
  • С помощью WinHttp.au3 (WinHTTP через DllCalls) (http://www.autoitscript.com/forum/topic/84133-winhttp-functions/)
    (нажмите для показа/скрытия)
  • С помощью TCP-функций AutoIt
    (нажмите для показа/скрытия)
« Последнее редактирование: Январь 30, 2012, 07:04:53 от CreatoR »

Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814

  • Автор темы
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
Re: НЕофициальный FAQ AutoIt
« Ответ #19, Отправлен: Февраль 01, 2012, 15:55:49 »
Вопрос:
Как заставить FileInstall работать с каталогами?

Ответ:
FileInstall предназначен строго для файлов.

Однако можно использовать следующий код, который в не скомпилированный скрипт добавит список FileInstall'ов с файлами указанного каталога:

Код: AutoIt [Выделить]
_FileDirInstall(@ScriptDir & '\Resources', @TempDir)

;===== YOUR SCRIPT CONTENT GOES HERE =====



;===== YOUR SCRIPT CONTENT GOES HERE =====


Func _FileDirInstall($sDirPath, $sDest, $nFlag = 0, $sMask = '*', $iSubDirs = 0, $sIncludeName = -1)
    Local $aList, $aMacros, $sMacros, $sData, $sReadScript, $hFile
   
    If @Compiled Then
        Return SetError(-1)
    EndIf
   
    If StringStripWS($sIncludeName, 8) = '' Then
        $sIncludeName = 'InstalledDir'
    ElseIf $sIncludeName = -1 Then
        $sIncludeName = 'InstalledDir_' & StringRegExpReplace($sDirPath, '^.*\\', '')
    EndIf
   
    $sIncludeName &= '.fdi'
   
    $aList = __FileSearch($sDirPath, $sMask, 1, $iSubDirs, 0)
   
    If @error Then
        Return SetError(1)
    EndIf
   
    $aMacros = _
        StringSplit( _
            'AppDataCommonDir|DesktopCommonDir|DocumentsCommonDir|FavoritesCommonDir|ProgramsCommonDir|StartMenuCommonDir|' & _
            'StartupCommonDir|AppDataDir|DesktopDir|MyDocumentsDir|FavoritesDir|ProgramsDir|StartMenuDir|StartupDir|UserProfileDir|' & _
            'HomeDrive|HomePath|HomeShare|ProgramFilesDir|CommonFilesDir|WindowsDir|SystemDir|TempDir', _
        '|')
   
    For $i = 1 To $aMacros[0]
        $sMacros = Execute('@' & $aMacros[$i])
       
        If $sDest = $sMacros Then
            $sDest = StringReplace($sDest, $sMacros, '@' & $aMacros[$i])
        EndIf
    Next
   
    For $i = 1 To $aList[0]
        If $iSubDirs = 1 Then
            $sData &= 'FileInstall("' & $aList[$i] & '", ' & $sDest & ' & "\' & StringRegExpReplace($aList[$i], '^.*\\', '') & '", ' & $nFlag & ')' & @CRLF
        Else
            $sData &= 'FileInstall("' & $sDirPath & '\' & $aList[$i] & '", ' & $sDest & ' & "\' & $aList[$i] & '", ' & $nFlag & ')' & @CRLF
        EndIf
    Next
   
    If $sData = '' Then
        Return SetError(2)
    EndIf
   
    $hFile = FileOpen(@ScriptDir & '\' & $sIncludeName, 2)
    FileWrite($hFile, '#include-once' & @CRLF & @CRLF & $sData)
    FileClose($hFile)
   
    $sReadScript = FileRead(@ScriptFullPath)
   
    If Not StringInStr($sReadScript, '#include "' & $sIncludeName & '"' & @CRLF) Then
        $hFile = FileOpen(@ScriptFullPath, 2)
        FileWrite($hFile, '#include "' & $sIncludeName & '"' & @CRLF & $sReadScript)
        FileClose($hFile)
    EndIf
   
    Return 1
EndFunc

Func __FileSearch($sPath, $sFileMask = "*", $iFlag = 0, $iSubDir = 1, $iSort = 0)
    Local $sOutBin, $sOut, $aOut, $sRead, $hDir, $sAttrib, $sFiles
   
    If Not StringInStr(FileGetAttrib($sPath), "D") Then
        Return SetError(1, 0, 0)
    EndIf
   
    If $iSubDir = 1 Then
        $sAttrib &= ' /S'
    EndIf
   
    If $iSort = 1 Then
        $sAttrib &= ' /O:N'
    EndIf
   
    Switch $iFlag
        Case 1
            $sAttrib &= ' /A-D'
        Case 2
            $sAttrib &= ' /AD'
        Case Else
            $sAttrib &= ' /A'
    EndSwitch
   
    $sOut = StringToBinary('0' & @CRLF, 2)
    $sPath = StringRegExpReplace($sPath, '\\+$', '')
    $sFileMask = StringRegExpReplace($sFileMask, '^;+|;+$', '')
    $sFileMask = StringRegExpReplace($sFileMask, ';{2,}', ';')
    $aMasks = StringSplit($sFileMask, ';')
   
    For $i = 1 To $aMasks[0]
        If StringStripWS($aMasks[$i], 8) = "" Then
            ContinueLoop
        EndIf
       
        $sFiles &= '"' & $sPath & '\' & $aMasks[$i] & '"'
       
        If $i < $aMasks[0] Then
            $sFiles &= ';'
        EndIf
    Next
   
    $hDir = Run(@ComSpec & ' /U /C DIR ' & $sFiles & ' /B' & $sAttrib, @SystemDir, @SW_HIDE, 6)
   
    While 1
        $sRead = StdoutRead($hDir, False, True)
       
        If @error Then
            ExitLoop
        EndIf
       
        If $sRead <> "" Then
            $sOut &= $sRead
        EndIf
    Wend
   
    $aOut = StringRegExp(BinaryToString($sOut, 2), '[^\r\n]+', 3)
   
    If @error Or UBound($aOut) < 2 Then
        Return SetError(2, 0, 0)
    EndIf
   
    $aOut[0] = UBound($aOut)-1
    Return $aOut
EndFunc


Запустите данный скрипт до компиляции.
Рядом с вашим скриптом появится файл «InstalledDir_ИмяУказаннойПапки.fdi», а в сам скрипт будет прописана строчка #include "InstalledDir_ИмяУказаннойПапки.fdi".


Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814

  • Автор темы
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
Re: НЕофициальный FAQ AutoIt
« Ответ #20, Отправлен: Апрель 24, 2012, 14:33:38 »
Вопрос:
Почему лучше использовать BitOR для добавления значении констант (например в стилях GUI)?

Ответ:
При обычном сложении значении констант, мы получаем кашу из чисел. А при использовании BitOR, существующее значение в добавляемом числе, повторяться не будет (т.е не будет добавляться содержащееся число). Вот пример сравнения:

Код: AutoIt [Выделить]
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

$bUseBitOR = True ;Поставьте на False и увидите ошибку в стилизации GUI

$iStyles = $GUI_SS_DEFAULT_GUI + $WS_SIZEBOX

;Вторично пытаемся добавить стиль $WS_SIZEBOX (иногда это происходит если стили берутся к примеру из файла конфигурации)
If $bUseBitOR Then
    $iStyles = BitOR($iStyles, $WS_SIZEBOX)
Else
    $iStyles += $WS_SIZEBOX
EndIf

$hGUI = GUICreate("Test Script", 300, 200, -1, -1, $iStyles)
GUISetState(@SW_SHOW, $hGUI)

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd


Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814

  • Автор темы
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
Re: НЕофициальный FAQ AutoIt
« Ответ #21, Отправлен: Май 28, 2012, 09:59:26 »
Вопрос:
Как правильно “запоминать” позицию GUI для последующих запусков?

Ответ:
Многие пытаются реализовать возможность сохранения позиции и размера GUI для последующих запусков программы.
Однако очень часто делают невольные ошибки, и даже не подозревая этого.

Например, знаете ли вы, что... если закрыть свёрнутое окно из панели задач, то размер окна будет сохранён неверно, будет что-то типа «-32000 x -32000».

Вот пример показывающий как предотвратить эту проблему, и другие, связанные с сохранением и восстановлением позиции GUI, а также как это делается оптимальнее всего (на мой взгляд):

Код: AutoIt [Выделить]
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

;Отключаем обработку событии $GUI_EVENT_MINIMIZE, $GUI_EVENT_RESTORE и $GUI_EVENT_MAXIMIZE
;Это нам придётся делать самим, т.к нам нужно получать размеры окна ДО его сворачивания
Opt('GUIEventOptions', 1)
OnAutoItExitRegister('_OnExit')

Global $sConfig_File                = @ScriptDir & '\' & StringTrimRight(@ScriptName, 4) & '_Config.ini'

Global $aGUI_Last_Pos

Global $iDef_GUILeft                = -1
Global $iDef_GUITop                 = -1
Global $iDef_GUIWidth               = 700
Global $iDef_GUIHeight              = 550

Global $iGUI_Left                   = IniRead($sConfig_File, 'Window Settings', 'Left', $iDef_GUILeft)
Global $iGUI_Top                    = IniRead($sConfig_File, 'Window Settings', 'Top', $iDef_GUITop)
Global $iGUI_Width                  = IniRead($sConfig_File, 'Window Settings', 'Width', $iDef_GUIWidth)
Global $iGUI_Height                 = IniRead($sConfig_File, 'Window Settings', 'Height', $iDef_GUIHeight)

_GUIFixPos()

$hMain_GUI = GUICreate('Remember GUI Size Demo', $iGUI_Width, $iGUI_Height, $iGUI_Left, $iGUI_Top, BitOR($GUI_SS_DEFAULT_GUI, $WS_SIZEBOX))
GUISetState(@SW_SHOW, $hMain_GUI)

While 1
    $nMsg = GUIGetMsg()
   
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $GUI_EVENT_MINIMIZE
            ;Получаем размеры окна ДО его сворачивания
            $aGUI_Last_Pos = _WinGetPos($hMain_GUI)
           
            ;Теперь можно и свернуть окно :), делаем вручную, т.к в начале мы отключили обработку этого события
            GUISetState(@SW_MINIMIZE, $hMain_GUI)
        Case $GUI_EVENT_RESTORE
            ;Восстанавливаем окно
            GUISetState(@SW_RESTORE, $hMain_GUI)
        Case $GUI_EVENT_MAXIMIZE
            ;Разворачиваем окно
            GUISetState(@SW_MAXIMIZE, $hMain_GUI)
    EndSwitch
WEnd

Func _GUIFixPos()
    If $iGUI_Left = -1 Or $iGUI_Left = '' Or $iGUI_Left < -$iGUI_Width Or $iGUI_Left > (@DesktopWidth - 50) Then
        $iGUI_Left = $iDef_GUILeft
    EndIf
   
    If $iGUI_Top = -1 Or $iGUI_Top = '' Or $iGUI_Top < -$iGUI_Height Or $iGUI_Top > (@DesktopHeight - 50) Then
        $iGUI_Top = $iDef_GUITop
    EndIf
   
    If $iGUI_Width > (@DesktopWidth - 50) Then
        $iGUI_Width = $iDef_GUIWidth
    EndIf
   
    If $iGUI_Height > (@DesktopHeight - 50) Then
        $iGUI_Height = $iDef_GUIHeight
    EndIf
EndFunc

Func _WinGetPos($hWin)
    Local $aWin_Pos = WinGetPos($hWin)
    If @error Then Return SetError(1)
   
    Local $aClient_Size = WinGetClientSize($hWin)
    If @error Then Return SetError(2)
   
    $aWin_Pos[2] = $aClient_Size[0]
    $aWin_Pos[3] = $aClient_Size[1]
   
    Return $aWin_Pos
EndFunc

Func _OnExit()
    If Not IsArray($aGUI_Last_Pos) Then
        $aGUI_Last_Pos = _WinGetPos($hMain_GUI)
    EndIf
   
    If UBound($aGUI_Last_Pos) = 4 Then
        IniWrite($sConfig_File, 'Window Settings', 'Left', $aGUI_Last_Pos[0])
        IniWrite($sConfig_File, 'Window Settings', 'Top', $aGUI_Last_Pos[1])
        IniWrite($sConfig_File, 'Window Settings', 'Width', $aGUI_Last_Pos[2])
        IniWrite($sConfig_File, 'Window Settings', 'Height', $aGUI_Last_Pos[3])
    EndIf
EndFunc

« Последнее редактирование: Май 30, 2013, 06:47:51 от CreatoR »

Русское сообщество AutoIt

Re: НЕофициальный FAQ AutoIt
« Ответ #21 Отправлен: Май 28, 2012, 09:59:26 »

Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814

  • Автор темы
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
Re: НЕофициальный FAQ AutoIt
« Ответ #22, Отправлен: Май 30, 2012, 14:08:50 »
Вопрос:
Как выполнить перенаправление по ссылке, и получить перенаправленную ссылку?

Ответ:
Метод используя объект WinHttp:

Нужно разрешить перенаправление и проверять Location:
Код: AutoIt [Выделить]
$oHTTP = ObjCreate("WinHttp.WinHttpRequest.5.1")
$oHTTP.Option(6) = False ;WinHttpRequestOption_EnableRedirects
$oHTTP.Open("GET", "http://creator-lab.ucoz.ru/load/0-0-1-52-20")
$oHTTP.Send()
$oHTTP.WaitForResponse
$sNewLocation = $oHTTP.GetResponseHeader("Location")
ConsoleWrite($sNewLocation & @LF)


Метод используя функции TCP*:

Код: AutoIt [Выделить]
$sHead = _HTTPGetResponse("creator-lab.ucoz.ru", "/load/0-0-1-52-20", "HEAD")

If StringRegExp($sHead, "(?i)Content-Type:(.*?)html") Then
    $sHead = _HTTPGetResponse("creator-lab.ucoz.ru", "/load/0-0-1-52-20", "GET")
EndIf

$sNewLocation = StringRegExpReplace($sHead, '(?s).*\r?\nLocation:\h*([^\r\n]+)\r?\n.*', '\1')
MsgBox(64, 'Title', 'Location: ' & @CRLF & $sNewLocation)

Func _HTTPGetResponse($sHost, $sPage, $sRequest = "HEAD")
    TCPStartup()
   
    Local $sName_To_IP = TCPNameToIP($sHost)
    Local $iSocket = TCPConnect($sName_To_IP, 80)
   
    If $iSocket = -1 Then
        TCPShutdown()
        Return SetError(1, 0, "")
    EndIf
   
    Local $sCommand = $sRequest & " " & $sPage & " HTTP/1.1" & @CRLF
    $sCommand &= "Host: " & $sHost & @CRLF
    $sCommand &= "User-Agent: AutoIt/" & @AutoItVersion & " (Windows; U; Windows NT 5.1; en-US; rv:1.8.1)" & @CRLF
    $sCommand &= "Referer: " & $sHost & @CRLF
    $sCommand &= "Connection: close" & @CRLF & @CRLF
   
    Local $BytesSent = TCPSend($iSocket, $sCommand)
   
    If $BytesSent = 0 Then
        TCPShutdown()
        Return SetError(2, @error, 0)
    EndIf
   
    Local $sRecv = "", $sCurrentRecv
   
    While 1
        $sCurrentRecv = TCPRecv($iSocket, 16)
        If @error <> 0 Then ExitLoop
        If $sCurrentRecv <> "" Then $sRecv &= $sCurrentRecv
    WEnd
   
    TCPCloseSocket($iSocket)
    TCPShutdown()
   
    Return $sRecv
EndFunc


Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814

  • Автор темы
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
Re: НЕофициальный FAQ AutoIt
« Ответ #23, Отправлен: Июнь 15, 2012, 15:13:28 »
Вопрос:
Почему лучше использовать GUICtrl* вместо Control*?

Ответ:
Все Control* функции сначала ищут родительское окно, затем перечисляют все его элементы для определения необходимого ID, и только затем посылают соответствующее сообщение. В случае работы с текстом, например ControlGetText, все ещё намного сложнее, т.к. необходимо перенаправить поток ввода из чужого процесса в свой.
GUICtrl* функции работают напрямую и только в своём процессе, что намного проще и быстрее.

Control* функции нужно использовать только для окон, созданных не AutoIt средствами.

Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814

  • Автор темы
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
Re: НЕофициальный FAQ AutoIt
« Ответ #24, Отправлен: Август 28, 2012, 20:10:43 »
Вопрос:
Как позволить запуск только одной копии программы?

Ответ:
Поместите следующий блок кода в начало вашего скрипта:
Код: AutoIt [Выделить]
If WinExists('[CLASS:AutoIt v3;TITLE:' & @ScriptName & ']') Then
    MsgBox(48, @ScriptName, 'Позволено запускать только одну копию программы!' & @CRLF & @CRLF & 'ОК ==> ВЫХОД')
   
    ;Раскоментируйте следующую строчку если нужно активировать окно вашей программы при повторном её запуске
    ;WinActivate('Имя вашей программы')
   
    Exit
EndIf

AutoItWinSetTitle(@ScriptName)


Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814

  • Автор темы
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
Re: НЕофициальный FAQ AutoIt
« Ответ #25, Отправлен: Ноябрь 25, 2012, 23:41:06 »
Вопрос:
Как предотвратить критические ошибки скрипта?

Ответ:
Таких ошибок есть несколько, рассмотрим наиболее “популярную”...
Ошибка при использовании массива, наверное самая распространённая ошибка среди новичков:

В большинстве случаев скрипт работает без сбоев, но происходит некое условие (которое скриптер не предусмотрел), и скрипт “вылетает” с ошибкой, например:
Цитировать
Subscript used with non-Array variable
такое происходит если выполняется попытка обратиться к переменной, которая не является массивом, как к таковому.
В данном случае, перед использованием переменной будет достаточно проверять её функцией IsArray, и если возвращает 1, значит можно обращаться к переменной как к массиву (хотя есть и некоторые нюансы, см. далее).

Следующая ошибка проявляется если обратиться к несуществующему индексу или ячейке массива:
Цитировать
Array variable has incorrect number of subscripts or subscript dimension range exceeded
это также касается обращения к массиву как к двумерному (к примеру), в то время когда он является одномерным, ну и наоборот.
С размерностью обычно проблем нет, скриптер должен точно знать какая размерность у используемого массива.
А вот с обращением к несуществующему индексу, часто бывают проблемы.
Решаются они также довольно просто, перед обращением к массиву, нужно всего лишь проверять его размер, делается при помощи функции Ubound.

IsArray и Ubound можно проверять в связке (последовательно), хотя на самом деле достаточно проверять только через Ubound, т.к он в любом случае вернёт 0 если переменная не является массивом.

Примеры правильного использования и обращения к массивам:

Первая проверка на массивность, и вторая на размер массива:
Код: AutoIt [Выделить]
Dim $vArray = StringSplit('1,2,3,4,5', ',')

;Если переменная $vArray является массивом, то...
If IsArray($vArray) Then
    ;Выводим первый (нулевой) элемент массива, т.к мы уже точно знаем что эта переменная является массивом,
    ;а это значит что она имеет как минимум один элемент
    MsgBox(64, '$vArray[0]', $vArray[0])
   
    ;Проверяем что массив имеет более чем 4 элемента (как известно, нумерация начинается с нуля)
    If UBound($vArray) > 4 Then
        MsgBox(64, '$vArray[4]', $vArray[4])
    EndIf
EndIf


Проверка двумерного массива:
Код: AutoIt [Выделить]
$iCols = 2 ;Число колонок
Dim $vArray[6][$iCols] = [[5], [1, 'Data1'], [2, 'Data2'], [3, 'Data3'], [4, 'Data4'], [5, 'Data5']]

;Если массив двумерный (его размерность равна 2-ум), то...
If UBound($vArray, 0) = 2 Then
    ;Выводим первый (нулевой) элемент двумерного массива, т.к мы уже точно знаем что эта переменная является массивом,
    ;а это значит что она имеет как минимум один элемент в каждой колонке
    MsgBox(64, '$vArray[0][0]', $vArray[0][0])
EndIf

;Проверяем размер первой и второй колонки, если первая больше чем 3 а вторая больше чем 1, то...
If UBound($vArray, 1) > 3 And UBound($vArray, 2) > 1 Then
    ;Выводим на экран значение 4-ой ячейки во второй колонке
    ;(не забываем что нумерация начинается с 0-ля, см. справку)
    MsgBox(64, '$vArray[3][1]', $vArray[3][1])
EndIf




Неправильный пример:
Код: AutoIt [Выделить]
Dim $vArray = StringSplit('1,2,3,4,5', ',')

If IsArray($vArray) Then
    MsgBox(64, '$vArray[0][0]', $vArray[0][0])
EndIf


в данном случае мы обращаемся к одномерному массиву как к двумерному, не проверив заранее его размерность, а только его тип (массив или нет).

Исправленный пример:
Код: AutoIt [Выделить]
Dim $vArray = StringSplit('1,2,3,4,5', ',')

If IsArray($vArray) And Ubound($vArray, 0) = 2 Then
    MsgBox(64, '$vArray[0][0]', $vArray[0][0])
EndIf


в данном случае естественно вывода на экран не будет, т.к переменная $vArray является одномерным массивом.



На втором месте среди распространённых ошибок, наверное являются ошибки, связанные с объектами.
Как и в случае с массивами, перед использованием свойств объекта, следует проверять, является ли используемый объект таковым, или нет.

Неправильный пример:
Код: AutoIt [Выделить]
$oDict = ObjCreate('Scripting.Dictionary')

$oDict.Add('Key', 'Item')
MsgBox(0, @ScriptName, $oDict.Item('Key'))


Исправленный пример:
Код: AutoIt [Выделить]
$oDict = ObjCreate('Scripting.Dictionary')

If IsObj($oDict) Then
    $oDict.Add('Key', 'Item')
    MsgBox(0, @ScriptName, $oDict.Item('Key'))
EndIf


Также смотрите справку к функции ObjEvent, с помощью которой можно контролировать события и ошибки вызванные использованием объектов.
« Последнее редактирование: Декабрь 01, 2015, 23:32:54 от CreatoR »

Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814

  • Автор темы
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
Re: НЕофициальный FAQ AutoIt
« Ответ #26, Отправлен: Май 06, 2015, 19:53:59 »
Вопрос:
Как передать данные из скрипта в скрипт (интеракция)?

Ответ:
Для решения данного вопроса, имеется несколько вариаций...

Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814

  • Автор темы
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
Re: НЕофициальный FAQ AutoIt
« Ответ #27, Отправлен: Август 10, 2015, 20:10:31 »
Вопрос:
Как отловить критические ошибки скрипта?

Ответ:
Два основные варианта:
1) OnAutoItErrorRegister / AutoItErrorHandler - Обработчик критических ошибок - Обработка критических ошибок AutoIt
2) _AutoItErrorTrap.au3 (UDF) - Error detection in AutoIt scripts! (используется хук процесса)

Упрощённый пример второго варианта:
Код: AutoIt [Выделить]
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>

If Not @Compiled Then
    MsgBox(48, @ScriptName, 'Please compile.')
    Exit
EndIf

; Call Back variables
Global $hAET_CBTPROC_CALLBKERROR, $hAET_CBTPROC_HOOKERROR

_AutoItErrorTrap()

$Form1 = GUICreate("Form1", 262, 113, 192, 124)
$Button1 = GUICtrlCreateButton("Вызвать критическую ошибку", 8, 8, 243, 97)
GUISetState(@SW_SHOW)

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
        Case $Button1
            Dim $array[10]
            MsgBox(0, "Это ошибка", $array[15])
    EndSwitch
WEnd

Func _ErrHandler($data)
    MsgBox(16, "Ошибка", "Обнаружена неустранимая ошибка: " & $data)
   
    Local $sRelaunchLine = @AutoItExe & ' "' & @ScriptFullPath & '"'
    If @Compiled Then $sRelaunchLine = @ScriptFullPath
    Run($sRelaunchLine, @ScriptDir)
EndFunc

Func _AutoItErrorTrap()
    Local $iAET_THREADID
   
    $iAET_THREADID = _WinAPI_GetCurrentThreadId()
    $hAET_CBTPROC_CALLBKERROR = DllCallbackRegister("__CBTProc_ErrorTrap", "int", "int;int;int") ; регистрируем коллбэк, который будет перехватывать сообщения об ошибках
   
    If Not $hAET_CBTPROC_CALLBKERROR Then
        Return 0
    EndIf
   
    $hAET_CBTPROC_HOOKERROR = _WinAPI_SetWindowsHookEx($WH_CBT, DllCallbackGetPtr($hAET_CBTPROC_CALLBKERROR), 0, $iAET_THREADID) ; и вешаем его на перехват окон
   
    If Not $hAET_CBTPROC_HOOKERROR Then
        DllCallbackFree($hAET_CBTPROC_CALLBKERROR)
        Return 0
    EndIf
   
    Return 1
EndFunc

Func __CBTProc_ErrorTrap($nCode, $wParam, $lParam)
    If $nCode <> 5 Then
        Return _WinAPI_CallNextHookEx($hAET_CBTPROC_HOOKERROR, $nCode, $wParam, $lParam)
    EndIf
   
    If Not _WinAPI_FindWindow("#32770", "AutoIt Error") Then
        Return _WinAPI_CallNextHookEx($hAET_CBTPROC_HOOKERROR, $nCode, $wParam, $lParam)
    EndIf
   
    Local $hAET_ERROR_HWND = HWnd($wParam)
    $hAET_GETERROR = ControlGetText($hAET_ERROR_HWND, "", "Static2")
   
    If IsDeclared("__iLineNumber") Then
        $hAET_GETERROR = StringRegExpReplace($hAET_GETERROR, "\d+[0-9]", Eval("__iLineNumber") & @CRLF)
        $hAET_GETERROR = StringReplace($hAET_GETERROR, "Х", @CRLF & "Module: Main/", 1)
    EndIf
   
    $hAET_GETERROR = StringReplace($hAET_GETERROR, @LF, @CRLF)
   
    $Data = StringSplit($hAET_GETERROR, @CRLF)
    $Line = StringSplit($Data[1], " ")
   
    _WinAPI_UnhookWindowsHookEx($hAET_CBTPROC_HOOKERROR)
    _WinAPI_DestroyWindow($hAET_ERROR_HWND)
   
    ;->>>>> ********** Здесь место для вставки пользовательских функций!
   
    _ErrHandler("Line " & $Line[2] & "; " & $Data[$Data[0]])
   
    ;<<<<<- **********
   
    Return _WinAPI_CallNextHookEx($hAET_CBTPROC_HOOKERROR, $nCode, $wParam, $lParam)
EndFunc

(скрипт должен быть скомпилирован)

OffTopicЗа идею вопроса спасибо veretragna
« Последнее редактирование: Сентябрь 21, 2015, 02:21:16 от CreatoR »

Оффлайн CreatoR [?]

  • Администратор
  • *
  • Сообщений: 7814

  • Автор темы
  • Репутация: 2282
  • Пол: Мужской
  • AutoIt is simple, subtle, elegant
    • CreatoR's Lab
    • Награды
  • Версия AutoIt: 3.3.10.2
Re: НЕофициальный FAQ AutoIt
« Ответ #28, Отправлен: Сентябрь 21, 2015, 02:38:28 »
Вопрос:
Как сопоставить номер строки из ошибки скомпилированного скрипта с исходником?

Ответ:
Применить следующий скрипт к исходнику скомпилированного скрипта:

Код: AutoIt [Выделить]
#include <WinAPIFiles.au3>

Global $sAutoItExe = @AutoItExe ;Should be 3.3.12.0 / 3.3.9.4 / 3.3.8.X / 3.3.6.X
;Global $sAutoItExe = 'D:\AutoIt_Versions\AutoIt_3.3.12.0\AutoIt3.exe'

$sFile = FileOpenDialog('Select script file (source from your compiled script)...', @ScriptDir, 'AutoIt v3 Script (*.au3)')
If @error Then Exit

$iLine = InputBox('Get error code line', 'Please enter error line number from compiled script:' & @CRLF & @CRLF & '(the AutoIt version of selected source file should match the version that used to compile the script)', '')
If @error Then Exit

SplashTextOn('Generating error code line', 'Please wait...', 200, 50, -1, -1, BitOR(16, 32), '', 12, 800)
$sCodeLine = _AU3_GetErrLineCode($sFile, $iLine)
SplashOff()

MsgBox(64, 'Result', StringFormat('Error code line (#%i) for <%s>:\r\n%s', $iLine, StringRegExpReplace($sFile, '^.*\\', ''), $sCodeLine))

Func _AU3_GetErrLineCode($sScript_File, $iLine)
    Local $sSrc_Raw, $iPos1, $iPos2, $iLen
   
    $sSrc_Raw = _AU3_StripToRaw($sScript_File)
   
    If @error Then
        Return SetError(1, 0, '')
    EndIf
   
    $sSrc_Raw = StringStripWS($sSrc_Raw, 3)
    $iPos1 = StringInStr($sSrc_Raw, @LF, 2, $iLine - 1)
    $iPos2 = StringInStr($sSrc_Raw, @LF, 2, $iLine)
    $iLen = ($iPos2 > 0 ? $iPos2 - $iPos1 : -1)
   
    Return StringStripWS(StringMid($sSrc_Raw, $iPos1, $iLen), 3)
EndFunc

Func _AU3_StripToRaw($sSrcFile, $bReset = False)
    If $sSrcFile = '' Or Not FileExists($sSrcFile) Then
        Return SetError(1, 0, 0)
    EndIf
   
    Local Static $sSrcRaw = ''
    Local Static $sInclds = '|'
   
    If $bReset Then
        $sSrcRaw = ''
        $sInclds = '|'
    EndIf
   
    Local $sInclude = '', $sLine = '', $iPos = 0, $sFName = '', $sFnc = '', $aFnc, $aVars
    Local $sScriptDir = StringRegExpReplace($sSrcFile, '\\[^\\]+$', '')
    Local $sRead = FileRead($sSrcFile)
   
    ;!!! Strip comment block here (before checking #include-once)...
    _AU3_StringStripCommentBlocks($sRead)
   
    If StringRegExp($sRead, '(?mi)^\h*#include-once') Then
        If StringInStr($sInclds, '|' & $sSrcFile & '|', 2) Then
            $sRead = StringRegExpReplace($sRead, '(?msi)\R?^\h*#include-once.*', '')
        Else
            $sInclds &= $sSrcFile & '|'
        EndIf
    EndIf
   
    $sRead = StringStripCR($sRead)
    Local $aRead = StringSplit($sRead, @LF)
   
    For $i = 1 To $aRead[0]
        If StringStripWS($aRead[$i], 8) = '' Then
            ContinueLoop
        EndIf
       
        If StringRegExp($aRead[$i], '(?i)^\h*(;|#include-once|#pragma\h+compile\()') Then
            ContinueLoop
        EndIf
       
        _AU3_StringStripComments($aRead[$i])
       
        If Not StringRegExp($aRead[$i], '(?i)^\h*#include\h*[<"'']') Then
            $sLine = $aRead[$i]
           
            ;Merge broken (with _) lines
            If StringRegExp($aRead[$i], '_\h*$') Then
                $sLine = StringRegExpReplace($aRead[$i], '^\h+|[_\h]+$', '')
               
                While 1
                    $i += 1
                   
                    If $i >= $aRead[0] Then
                        ExitLoop
                    EndIf
                   
                    _AU3_StringStripComments($aRead[$i])
                    $aRead[$i] = StringRegExpReplace($aRead[$i], '[_\h]+$', '')
                   
                    If @extended = 0 Then
                        $sLine &= ' ' & StringStripWS($aRead[$i], 1)
                        ExitLoop
                    EndIf
                   
                    $sLine &= ' ' & StringStripWS($aRead[$i], 1)
                WEnd
            EndIf
           
            $sSrcRaw &= StringStripWS($sLine, 1) & @CRLF
           
            ContinueLoop
        EndIf
       
        ;Get include path
        $sInclude = _AU3_IncludeToPath($aRead[$i], $sScriptDir)
       
        If Not @error Then
            ;Recursive call for include
            $sSrcRaw = _AU3_StripToRaw($sInclude)
        EndIf
    Next
   
    Return $sSrcRaw
EndFunc

Func _AU3_IncludeToPath($sInclude, $sScriptDir = @ScriptDir)
    Local $aRegExp, $aRet, $sSYS, $sAU3, $sWorkDir
    Local $iError = 0, $sRet = ''
   
    $aRegExp = StringRegExp($sInclude, '(?i)^\h*#include\h+(<|"|'')([^>"'']+)(?:>|"|'')\h*(;.*?)?$', 3)
   
    If UBound($aRegExp) < 2 Then
        Return SetError(1, 0, '')
    EndIf
   
    $sInclude = $aRegExp[1]
   
    ;Get AutoIt Include folder
    Local Static $sAutoIt_Incl_Dir = StringRegExpReplace($sAutoItExe, '\\[^\\]+$', '') & '\Include'
   
    ;Get User Include folders
    Local Static $aUDL = StringRegExp(RegRead('HKCU\Software\AutoIt v3\AutoIt', 'Include'), '([^;]+)(?:;|$)', 3)
   
    While 1
        ;Check include type 4 (include with full path)
        If Not _WinAPI_PathIsRelative($sInclude) Then
            If FileExists($sInclude) Then
                $sRet = $sInclude
            Else
                $iError = 2
            EndIf
           
            ExitLoop
        EndIf
       
        ;Set Current & AutoIt Include file
        $sAU3 = $sScriptDir & '\' & $sInclude
        $sSYS = $sAutoIt_Incl_Dir & '\' & $sInclude
       
        ;Check include type 1 and 2 (before user includes check)
        If $aRegExp[0] == '<' Then
            If FileExists($sSYS) Then
                $sRet = $sSYS
                ExitLoop
            EndIf
        ElseIf $aRegExp[0] == '"' Or $aRegExp[0] == "'" Then
            If FileExists($sAU3) Then
                $sRet = $sAU3
                ExitLoop
            EndIf
        EndIf
       
        ;Check include type 3 (search in user includes)
        For $i = 0 To UBound($aUDL) - 1
            $aUDL[$i] &= '\' & $sInclude
           
            If FileExists($aUDL[$i]) Then
                $sRet = $aUDL[$i]
                ExitLoop 2
            EndIf
        Next
       
        ;Check include type 1 and 2 (after user includes check)
        If $aRegExp[0] == '<' Then
            If FileExists($sAU3) Then
                $sRet = $sAU3
                ExitLoop
            EndIf
        ElseIf $aRegExp[0] == '"' Or $aRegExp[0] == "'" Then
            If FileExists($sSYS) Then
                $sRet = $sSYS
                ExitLoop
            EndIf
        EndIf
       
        ;Include file not found
        $iError = 3
        ExitLoop
    WEnd
   
    If Not $iError Then
        $sWorkDir = @WorkingDir
       
        If $sWorkDir <> $sScriptDir Then
            FileChangeDir($sScriptDir)
        EndIf
       
        $sRet = _WinAPI_GetFullPathName($sRet)
       
        If @error Or $sRet = '' Then
            $iError = 4
        EndIf
       
        If $sWorkDir <> $sScriptDir Then
            FileChangeDir($sWorkDir)
        EndIf
    Else
        $sRet = ''
    EndIf
   
    Return SetError($iError, 0, $sRet)
EndFunc

Func _AU3_StringStripCommentBlocks(ByRef $sString)
    Local $aSplit = StringSplit(StringStripCR($sString), @LF)
    Local $iCmntsStart_Count
   
    $sString = ''
   
    For $i = 1 To $aSplit[0]
        If StringRegExp($aSplit[$i], '(?i)^\h*#(cs|comments-start)([\h;].*)?$') Then
            $iCmntsStart_Count = 1
           
            While 1
                If $i + 1 >= $aSplit[0] Then
                    ExitLoop
                EndIf
               
                $i += 1
               
                If StringRegExp($aSplit[$i], '(?i)^\h*#(cs|comments-start)([\h;].*)?') Then
                    $iCmntsStart_Count += 1
                    ContinueLoop
                EndIf
               
                If StringRegExp($aSplit[$i], '(?i)^\h*#(ce|comments-end)([\h;].*)?') Then
                    $iCmntsStart_Count -= 1
                   
                    If $iCmntsStart_Count <= 0 Then
                        ExitLoop
                    EndIf
                EndIf
            WEnd
           
            ContinueLoop
        EndIf
       
        $sString &= $aSplit[$i] & @CRLF
    Next
EndFunc

Func _AU3_StringStripComments(ByRef $sString)
    Local $aStrs = StringRegExp($sString, '("[^"]*"|''[^'']*'')', 3)
    Local $sStrs = StringRegExpReplace($sString, '("[^"]*"|''[^'']*'')', '#[email protected]~_~#')
    Local $iInStr = StringInStr($sStrs, ';', 2)
   
    If $iInStr = 0 Then
        Return
    EndIf
   
    $sString = StringStripWS(StringLeft($sStrs, $iInStr - 1), 2)
   
    For $i = 0 To UBound($aStrs) - 1
        $sString = StringReplace($sString, '#[email protected]~_~#', $aStrs[$i], 1, 2)
    Next
EndFunc


также см. предыдущие вопросы.

Русское сообщество AutoIt

Re: НЕофициальный FAQ AutoIt
« Ответ #28 Отправлен: Сентябрь 21, 2015, 02:38:28 »

 

Похожие темы

  Тема / Автор Ответов Последний ответ
16 Ответов
64187 Просмотров
Последний ответ Сентябрь 15, 2009, 15:41:00
от El Panda
4 Ответов
7751 Просмотров
Последний ответ Июнь 13, 2010, 23:47:03
от aizi
3 Ответов
3608 Просмотров
Последний ответ Сентябрь 09, 2010, 21:22:34
от CreatoR
13 Ответов
76754 Просмотров
Последний ответ Октябрь 17, 2010, 14:27:34
от Yashied
83 Ответов
41488 Просмотров
Последний ответ Февраль 25, 2013, 10:41:42
от Astel064
0 Ответов
3150 Просмотров
Последний ответ Октябрь 14, 2010, 11:47:43
от Garrett
0 Ответов
2039 Просмотров
Последний ответ Февраль 19, 2011, 00:08:13
от `p r o x y
1 Ответов
1930 Просмотров
Последний ответ Май 27, 2012, 12:24:28
от Garrett
0 Ответов
1307 Просмотров
Последний ответ Май 28, 2012, 22:36:03
от CreatoR
8 Ответов
2880 Просмотров
Последний ответ Ноябрь 29, 2012, 18:31:28
от AlexxxRu