Jump to content

Recommended Posts

Hi,

I'm inviting all autoit forum members to contribute to a HTML parser udf. I going to attempt to replicate a python module called BeautifulSoup. It would be greatly appreciated if some senior Autoit programmers took interest in this topic. There is no template other than the module written in python located here and the documentation here.

I can't wait to see what this develops into. :robot:

Spoiler

censored.jpg

 

Link to post
Share on other sites
  • 4 months later...

Finally found a way to "mute" IE -- making it unable to load external resources except the already cached ones -- makes it load page faster. Other IE instances won't be affected, only the one we used as html parser.

This simple wrapper functions:

_HtmlParser_Startup

_HtmlParser_GetDocument ; the IHtmlDocument ref

_HtmlParser_LoadHtml ; load plain text, optionally remove all script tags

_HtmlParser_LoadUrl

_HtmlParser_LoadScript ; to use jquery, xpath, etc.

_HtmlParser_ClearScript

_HtmlParser_Exec ; execute js and get return value, see sample

Save as "HtmlParser.au3" and run, the sample code is included. Clear IE cache first for the best result. Hope it helps :)

#include-once
#include <WinAPI.au3>
#include <WindowsConstants.au3>
#include <GuiConstantsEx.au3>
#include <IE.au3>

; Opt("MustDeclareVars", 1)

Global $_HtmlParser_Debug = False
Global $_HtmlParser_Script = ""

Global Const $_HtmlParser_ScriptName = "HtmlParser.au3"
Global Const $tagINTERNET_PROXY_INFO = "dword dwAccessType; ptr lpszProxy; ptr lpszProxyBypass";
Global Const $tagCOPYDATA = _
  "ULONG_PTR;" & _  ; dwData, The data to be passed to the receiving application
  "DWORD;" & _    ; cbData, The size, in bytes, of the data pointed to by the lpData member
  "PTR"          ; lpData, The data to be passed to the receiving application. This member can be NULL.

Func _HtmlParser_Startup ($iPort=843)
    If IsDeclared("_HtmlParser_IE") AND IsObj($_HtmlParser_IE) Then Return 1

    Global $_HtmlParser_Port = $iPort
    __HtmlParser_ParseCmdLine()
    
    Global $_HtmlParser_HWND = WinWait($_HtmlParser_GUID, "", 5)
    If NOT $_HtmlParser_HWND Then Return SetError(1, 0, 0) ; Daemon failed to start
    WinSetTitle($_HtmlParser_HWND, "", "")
    
    ; Attach IE
    Global $_HtmlParser_IE = _IEAttach(WinGetHandle($_HtmlParser_GUID), "embedded")
    If NOT IsObj(_HtmlParser_GetDocument()) Then Return SetError(2, 0, 0)
    
    OnAutoItExitRegister("__HtmlParser_Shutdown")
    Return 1
EndFunc

Func _HtmlParser_GetDocument ()
    If IsObj($_HtmlParser_IE) Then Return _IEDocGetObj($_HtmlParser_IE)
    Return SetError(1, 0, 0)
EndFunc

Func _HtmlParser_LoadHtml ( $sHtml, $fRemoveScriptTags=0 )
    _IENavigate($_HtmlParser_IE, "about:blank")
    Local $doc = _HtmlParser_GetDocument()
    If $fRemoveScriptTags Then $sHtml = StringRegExpReplace($sHtml, "<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>", "")
    $doc.Write($sHtml & @CRLF & '<script language="javascript">' & @CRLF & $_HtmlParser_Script & @CRLF & 'Array.prototype.set=function(i,v){this[i]=v};Array.prototype.get=function(i){return this[i]};document.scripts[document.scripts.length-1].removeNode(false)</script>')
    Return $doc
EndFunc

Func _HtmlParser_LoadUrl ( $sUrl, $fRemoveScriptTags=0 )
    Local $http = ObjCreate("winhttp.winhttprequest.5.1")
    $http.Open("GET", $sUrl)
    $http.Send()
    Return _HtmlParser_LoadHtml($http.Responsetext, $fRemoveScriptTags)
EndFunc

Func _HtmlParser_LoadScript ( $sFilename )
    Local $script = ""
    If FileExists ($sFilename) Then
        $script = FileRead($sFilename)
    Else
        If StringInStr($sFilename, "http://") OR StringInStr($sFilename, "https://") OR StringInStr($sFilename, "ftp://") Then
            Local $http = ObjCreate("winhttp.winhttprequest.5.1")
            $http.Open("GET", $sFilename)
            $http.Send()
            $script = $http.Responsetext
        EndIf
    EndIf
    If $script Then
        $_HtmlParser_Script &= @CRLF & @CRLF & $script
        Return 1
    EndIf
    Return 0
EndFunc

Func _HtmlParser_ClearScript ( $sFilename )
    $_HtmlParser_Script = ""
EndFunc

Func _HtmlParser_Exec ( $sScript )
    Local $doc = _HtmlParser_GetDocument()
    If IsObj($doc) AND IsObj($doc.parentWindow) Then
        Local $window = $doc.parentWindow
        $window.execScript('window._HtmlParser_Result=(function(){' & $sScript & '})();', 'Javascript')
        If $window._HtmlParser_Result OR IsObj($window._HtmlParser_Result) Then
            Return $window._HtmlParser_Result
        Else
            Return SetError(2, 0, 0)
        EndIf
    EndIf
    Return SetError(1, 0, 0)
EndFunc

#region >> Internals

Func __HtmlParser_Shutdown ()
    Global $_HtmlParser_IE = 0
    If IsDeclared("_HtmlParser_HWND") Then WinClose($_HtmlParser_HWND)
    OnAutoItExitUnregister("__HtmlParser_Shutdown")
EndFunc

Func __HtmlParser_ParseCmdLine ()
    If @compiled Then
      Global Const $_HtmlParser_Exec = '"' & @ScriptFullPath & '"'
    Else
      Global Const $_HtmlParser_Exec = '"' & @AutoItExe & '" "' & @ScriptFullPath & '"'
    EndIf

    Local $cmd = StringInStr($CmdLineRaw, "/_HtmlParser_", 1), $val
    If $cmd > 0 Then
        #NoTrayIcon
        $cmd = StringRegExp(StringMid($CmdLineRaw, $cmd), '/(_HtmlParser_[a-zA-Z]+)\:"([^"]*)"', 3)
        For $i = 0 To UBound($cmd)-1 Step 2
            $val = $cmd[$i+1]
            If $val = ("" & Number($val)) Then $val = Number($val)
            Assign($cmd[$i], $val, 2)
        Next
        __HtmlParser_DaemonRun()
        Exit
    Else
        Global $_HtmlParser_GUID = __WinAPI_CreateGUID()
        __HtmlParser_Daemonstart()
    EndIf
EndFunc

Func __HtmlParser_Daemonstart ()
    Run ( $_HtmlParser_Exec & _
        ' /_HtmlParser_GUID:"' & $_HtmlParser_GUID & '"' & _
        ' /_HtmlParser_Debug:"' & (0 + $_HtmlParser_Debug) & '"' & _
        ' /_HtmlParser_Port:"' & $_HtmlParser_Port & '"' )
EndFunc

Func __HtmlParser_DaemonRun ()
    ; Initialize GUI
    Local $hGUI = GUICreate("", 500, 400, 10, 10, $WS_SIZEBOX, $WS_EX_TOOLWINDOW)
    Global $_HtmlParser_IE = _IECreateEmbedded()
    Local $hIE = GUICtrlCreateObj($_HtmlParser_IE, 0, 0, _WinAPI_GetClientWidth($hGUI), _WinAPI_GetClientHeight($hGUI))
    GUICtrlSetResizing($hIE, $GUI_DOCKAUTO)
    GUIRegisterMsg($WM_SYSCOMMAND, "__HtmlParser_SysCommand")
    If $_HtmlParser_Debug Then GUISetState()
    
    ; Initialize IE
    _IE_SetSessionProxy("127.0.0.1:" & $_HtmlParser_Port)
    _IENavigate($_HtmlParser_IE, "about:blank")
    _IEPropertySet($_HtmlParser_IE, "silent", True)
    WinSetTitle($hGUI, "", $_HtmlParser_GUID)
    
    Local $timeout = TimerInit()
    Do
        If TimerDiff($timeout) > 5000 Then Exit
    Until WinGetTitle($hGUI) <> $_HtmlParser_GUID
    If $_HtmlParser_Debug Then WinSetTitle($hGUI, "", "HtmlParser Debug Window")
    
    While 1
        Sleep(100)
    WEnd
EndFunc

Func __HtmlParser_SysCommand ($hWnd, $Msg, $wParam, $lParam)
    #forceref $Msg, $wParam, $lParam
    If BitAND($wParam, 0xFFF0) = 0xF060 Then Exit
    Return $GUI_RUNDEFMSG
EndFunc

#endregion << Internals

#region >> WinAPIEx

Func __WinAPI_CreateGUID()

    Local $tGUID, $Ret

    $tGUID = DllStructCreate($tagGUID)
    $Ret = DllCall('ole32.dll', 'uint', 'CoCreateGuid', 'ptr', DllStructGetPtr($tGUID))
    If @error Then
        Return SetError(1, 0, '')
    Else
        If $Ret[0] Then
            Return SetError(1, $Ret[0], 0)
        EndIf
    EndIf
    $Ret = DllCall('ole32.dll', 'int', 'StringFromGUID2', 'ptr', DllStructGetPtr($tGUID), 'wstr', '', 'int', 39)
    If (@error) Or (Not $Ret[0]) Then
        Return SetError(1, 0, '')
    EndIf
    Return $Ret[2]
EndFunc   ;==>__WinAPI_CreateGUID

Func _IE_SetSessionProxy ($sProxyAddress, $sBypassList="")
    Local $tProxyAddress = DllStructCreate("char[" & StringLen($sProxyAddress) + 1 & "]"), _
          $tBypassList = DllStructCreate("char[" & StringLen($sBypassList) + 1 & "]"), _
          $tINTERNET_PROXY_INFO = DllStructCreate($tagINTERNET_PROXY_INFO)
          
    DllStructSetData($tINTERNET_PROXY_INFO, "dwAccessType", 0x3)
    DllStructSetData($tProxyAddress, 1, $sProxyAddress)
    DllStructSetData($tINTERNET_PROXY_INFO, "lpszProxy", DllStructGetPtr($tProxyAddress))
    DllStructSetData($tBypassList, 1, $sBypassList)
    DllStructSetData($tINTERNET_PROXY_INFO, "lpszProxyBypass", DllStructGetPtr($tBypassList))
    
    Local $aRet = DllCall("urlmon.dll", "INT", "UrlMkSetSessionOption", _
                            "uint", 0x26, _
                            "ptr", DllStructGetPtr($tINTERNET_PROXY_INFO), _
                            "int", DllStructGetSize($tINTERNET_PROXY_INFO), _
                            "int", 0 )
    If @error OR $aRet[0] Then Return SetError(1, @error, 0)
    
    Return 1
EndFunc

#endregion << WinAPIEx

#region >> Debugging

Func _Alert ($msg, $fDialog=1)
  If $fDialog Then
    MsgBox(0, @ScriptName, $msg)
  Else
    TrayTip(@ScriptName, $msg, 5000)
  EndIf
EndFunc

Func _Critical ($ret, $rel=0, $msg="Fatal Error", $err=@error, $ext=@extended, $ln = @ScriptLineNumber)
  If $err Then
    $ln += $rel
    Local $LastError = _WinAPI_GetLastError(), _
          $LastErrorMsg = _WinAPI_GetLastErrorMessage(), _
          $LastErrorHex = Hex($LastError)
    $LastErrorHex = "0x" & StringMid($LastErrorHex, StringInStr($LastErrorHex, "0", 1, -1)+1)
    $msg &= @CRLF & "at line " & $ln & @CRLF & @CRLF & "AutoIt Error: " & $err & " (0x" & Hex($err)  & ") Extended: " & $ext
    If $LastError Then $msg &= @CRLF & "WinAPI Error: " & $LastError & " (" & $LastErrorHex & ")" & @CRLF & $LastErrorMsg
    ClipPut($msg)
    MsgBox(270352, "Fatal Error - " & @ScriptName, $msg)
    Exit
  EndIf
  Return $ret
EndFunc

#endregion << Debugging

; ==============================================================================

Func _HtmlParser_Test ()
    $_HtmlParser_Debug = True
    
    _Critical( _HtmlParser_Startup() )
    
    ; warming up
    Local $doc = _HtmlParser_GetDocument()
    $doc.write("Hello AutoIt World")
    _Alert("now for real")
    
    _HtmlParser_LoadScript("https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js")
    ; Or:
    ; _HtmlParser_LoadScript(@ScriptDir & "\jquery.min.js")
    Local $doc = _HtmlParser_LoadUrl("http://www.autoitscript.com", True)
    Local $pages = _Critical( _HtmlParser_Exec('var p=[];$("p").each(function(index) { p.push("[" + (index+1) + "] " + $(this).text());});return p') )
    Local $s = ""
    For $i = 0 To $pages.length-1
        $s &= $pages.get($i) & @CRLF
    Next
    _Alert($s)
    
    Local $saved = $doc.body.parentElement.outerHTML
    Local $divs = _HtmlParser_Exec('return $(".featitem.clearfix")')
    Local $div, $features = ""
    For $i = 0 To $divs.length-1
        $div = $divs.get($i)
        $features &= $div.outerHTML
    Next
    $doc.body.innerHTML = $features
    _Alert("A lot faster parsing in javascript though")
    
    _HtmlParser_LoadHtml($saved, True)
    Local $features = _HtmlParser_Exec('var s=""; $(".featitem.clearfix").each(function(){ s += this.outerHTML }); document.body.innerHTML=s; return s')  
    _Alert($features)
    
EndFunc
If @ScriptName = $_HtmlParser_ScriptName Then _HtmlParser_Test()

Edit: added $fRemoveScriptTags option for _HtmlParser_LoadUrl and _HtmlParser_LoadHtml

Edited by eimhym
Link to post
Share on other sites

Heres another, IE-less, example. Needs libtidy (attached) to clean pages and pass the well-formed html into MSXML ActiveX control (see MSDN documentation here).

pros: 1) lightweight, lighting fast. 2) XPath available by default. 3) Script tags won't executed, css or images won't loaded. 4) No problem in deleting SCRIPT tag.

cons: 1) does fail with some pages, always check @error after calling _HXmlParser_LoadUrl or _HXmlParser_LoadHtml. 2) libtidy crash on HTML5 pages, you have to reload the dll. 3) Doesn't handle html tags within textarea correctly, suggestion for workaround expected. 4) Can't use JS framework.

The sample code do the same as HtmlParser, for comparison.

#include-once
#include "libtidy.au3"

; Opt("MustDeclareVars", 1)

Global Const $_HXmlParser_ScriptName = "HXmlParser.au3"
Global $_HXmlParser_DOM = 0

Func _HXmlParser_Startup ( $sConfFilename="tidy-xml-settings.cfg" )
    _LibTidy_Startup()
    If @error Then Return SetError(@error, @extended, 0)
    _LibTidy_LoadConfig($sConfFilename)
    If @error Then
        _LibTidy_Shutdown()
        Return SetError(@error, @extended, 0)
    EndIf
    $_HXmlParser_DOM = ObjCreate("MSXML2.DOMDocument")
    OnAutoItExitRegister("__HXmlParser_Shutdown")
    $_HXmlParser_DOM.validateOnParse = False;
    $_HXmlParser_DOM.resolveExternals = False;
    Return 1
EndFunc

Func __HXmlParser_Shutdown ()
    $_HXmlParser_DOM = 0
    OnAutoItExitUnRegister("__HXmlParser_Shutdown")
EndFunc

Func _HXmlParser_GetErrorString ()
    If IsObj($_HXmlParser_DOM.parseError) AND $_HXmlParser_DOM.parseError.errorCode Then
        Return "Error loading page " & _
                " (" & Hex($_HXmlParser_DOM.parseError.errorCode) & _
                ") at line: " & $_HXmlParser_DOM.parseError.line & _
                ", position: " & $_HXmlParser_DOM.parseError.linepos & _
                ", reason: " & $_HXmlParser_DOM.parseError.reason
    EndIf
    Return 0
EndFunc

Func _HXmlParser_LoadHtml ( $sHtml )
    If NOT $sHtml Then Return SetError(4, 0, 0)
    _LibTidy_LoadString( $sHtml )
    If @error Then Return SetError(@error, @extended, 0)
    $sHtml = _LibTidy_CleanAndRepair()
    If @error OR NOT $sHtml Then Return SetError(5, @error, 0)
    
    $sHtml = StringRegExp(StringMid($sHtml, StringInStr($sHtml, "<html")), "(?s)^<html[^>]*>[^<]*(<.*)", 1)
    If @error Then Return SetError(6, @error, 0)

    $sHtml = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" [' _
        & '<!ENTITY nbsp " "><!ENTITY iexcl "¡"><!ENTITY cent "¢"><!ENTITY pound "£"><!ENTITY curren "¤"><!ENTITY yen "¥"><!ENTITY brvbar "¦"><!ENTITY sect "§"><!ENTITY uml "¨"><!ENTITY copy "©"><!ENTITY ordf "ª"><!ENTITY laquo "«"><!ENTITY not "¬"><!ENTITY shy "­"><!ENTITY reg "®"><!ENTITY macr "¯"><!ENTITY deg "°"><!ENTITY plusmn "±"><!ENTITY sup2 "²"><!ENTITY sup3 "³"><!ENTITY acute "´"><!ENTITY micro "µ"><!ENTITY para "¶"><!ENTITY middot "·"><!ENTITY cedil "¸"><!ENTITY sup1 "¹"><!ENTITY ordm "º"><!ENTITY raquo "»"><!ENTITY frac14 "¼"><!ENTITY frac12 "½"><!ENTITY frac34 "¾"><!ENTITY iquest "¿"><!ENTITY times "×"><!ENTITY divide "÷">' _
        & '<!ENTITY Agrave "À"><!ENTITY Aacute "Á"><!ENTITY Acirc "Â"><!ENTITY Atilde "Ã"><!ENTITY Auml "Ä"><!ENTITY Aring "Å"><!ENTITY AElig "Æ"><!ENTITY Ccedil "Ç"><!ENTITY Egrave "È"><!ENTITY Eacute "É"><!ENTITY Ecirc "Ê"><!ENTITY Euml "Ë"><!ENTITY Igrave "Ì"><!ENTITY Iacute "Í"><!ENTITY Icirc "Î"><!ENTITY Iuml "Ï"><!ENTITY ETH "Ð"><!ENTITY Ntilde "Ñ"><!ENTITY Ograve "Ò"><!ENTITY Oacute "Ó"><!ENTITY Ocirc "Ô"><!ENTITY Otilde "Õ"><!ENTITY Ouml "Ö"><!ENTITY Oslash "Ø"><!ENTITY Ugrave "Ù"><!ENTITY Uacute "Ú"><!ENTITY Ucirc "Û"><!ENTITY Uuml "Ü"><!ENTITY Yacute "Ý"><!ENTITY THORN "Þ"><!ENTITY szlig "ß"><!ENTITY agrave "à"><!ENTITY aacute "á"><!ENTITY acirc "â"><!ENTITY atilde "ã"><!ENTITY auml "ä"><!ENTITY aring "å"><!ENTITY aelig "æ"><!ENTITY ccedil "ç"><!ENTITY egrave "è"><!ENTITY eacute "é"><!ENTITY ecirc "ê"><!ENTITY euml "ë"><!ENTITY igrave "ì"><!ENTITY iacute "í"><!ENTITY icirc "î"><!ENTITY iuml "ï"><!ENTITY eth "ð"><!ENTITY ntilde "ñ"><!ENTITY ograve "ò"><!ENTITY oacute "ó"><!ENTITY ocirc "ô"><!ENTITY otilde "õ"><!ENTITY ouml "ö"><!ENTITY oslash "ø"><!ENTITY ugrave "ù"><!ENTITY uacute "ú"><!ENTITY ucirc "û"><!ENTITY uuml "ü"><!ENTITY yacute "ý"><!ENTITY thorn "þ"><!ENTITY yuml "ÿ">' _
        & ']>' & @CRLF _
        & '<html>' & @CRLF _
        & $sHtml[0]

    $_HXmlParser_DOM.loadXML($sHtml);
    If IsObj($_HXmlParser_DOM.parseError) AND $_HXmlParser_DOM.parseError.errorCode Then
        SetError(7, $_HXmlParser_DOM.parseError.errorCode, 0)
    EndIf
    
    $_HXmlParser_DOM.setProperty("SelectionLanguage", "XPath");
    
    Return $_HXmlParser_DOM
EndFunc

Func _HXmlParser_LoadUrl ( $sUrl )
    Local $http = ObjCreate("winhttp.winhttprequest.5.1")
    $http.Open("GET", $sUrl)
    $http.Send()
    Local $ret = _HXmlParser_LoadHtml($http.Responsetext)
    If @error Then Return SetError(@error, @extended, $ret)
    Return $ret
EndFunc


#region >> Debugging

Func _Alert ($msg, $fDialog=1, $err=@error, $ext=@extended, $ln = @ScriptLineNumber)
  If $fDialog Then
    MsgBox(0, @ScriptName, $msg)
  Else
    TrayTip(@ScriptName, $msg, 5000)
  EndIf
  If $err Then Return SetError($err, $ext, $ln)
  Return 0
EndFunc

Func _Critical ($ret, $rel=0, $msg="Fatal Error", $err=@error, $ext=@extended, $ln = @ScriptLineNumber)
  If $err Then
    $ln += $rel
    Local $LastError = _WinAPI_GetLastError(), _
          $LastErrorMsg = _WinAPI_GetLastErrorMessage(), _
          $LastErrorHex = Hex($LastError)
    $LastErrorHex = "0x" & StringMid($LastErrorHex, StringInStr($LastErrorHex, "0", 1, -1)+1)
    $msg &= @CRLF & "at line " & $ln & @CRLF & @CRLF & "AutoIt Error: " & $err & " (0x" & Hex($err)  & ") Extended: " & $ext
    If $LastError Then $msg &= @CRLF & "WinAPI Error: " & $LastError & " (" & $LastErrorHex & ")" & @CRLF & $LastErrorMsg
    $msg &= @CRLF & @CRLF & _HXmlParser_GetErrorString()
    ClipPut($msg)
    MsgBox(270352, "Fatal Error - " & @ScriptName, $msg)
    Exit
  EndIf
  Return $ret
EndFunc

#endregion << Debugging

Func _HXmlParser_Test ()
    
    _Critical( _HXmlParser_Startup() )
    Local $dom = _Critical( _HXmlParser_LoadUrl("http://www.AutoItScript.com") )
   
    _Alert("Removing all SCRIPT tags")
    Local $begin = TimerInit()
    Local $nodes = $dom.selectNodes("//script")
    If $nodes.length Then
        For $i = 0 To $nodes.length - 1
            Local $node = $nodes.item($i)
            $node.parentNode.removeChild($node)
        Next
    EndIf
    _Alert("Done in " & TimerDiff($begin) & " ms")
    
    _Alert("Collecting all P tags")
    Local $count = 1, $s = ""
    $begin = TimerInit()
    $nodes = $dom.selectNodes("//p")
    If $nodes.length Then
        For $i = 0 To $nodes.length - 1
            Local $node = $nodes.item($i)
            $s &= "[" & $count & "] " & $node.text & @CRLF
            $count += 1
        Next
    EndIf
    _Alert("Done in " & TimerDiff($begin) & " ms")
    _Alert($s)

    $s = ""
    _Alert("Collecting all feature DIVs")
    $begin = TimerInit()
    $nodes = $dom.selectNodes("//div[contains(@class, 'featitem')]")
    If $nodes.length Then
        For $i = 0 To $nodes.length - 1
            Local $node = $nodes.item($i)
            $s &= $node.xml & @CRLF
        Next
    EndIf
    _Alert("Done in " & TimerDiff($begin) & " ms")
    _Alert($s)
    
    ClipPut($dom.xml)
    _Alert("HTML content is in clipboard")
    
EndFunc
If @ScriptName = $_HXmlParser_ScriptName Then _HXmlParser_Test()

libtidy.7z

Edited by eimhym
Link to post
Share on other sites
  • 9 months later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By SkysLastChance
      I am having trouble finding a good way to click these "button" below. 

      I only need to be able to click them when they have both yes/no. Otherwise I don't have to worry about them. For instance if they looked like this I would NOT have worry about clicking them and can just ignore them all togheter.(Below Picture)

      The problem is as mentioned in the title, all of the ID's  are dynamic. (Classes too)

      Here is what it looks like if yes is already selected.

      This is what I was using to select the the button. However, I need to know if the button has already been clicked/selected or not.
      _WD_LoadWait($sSession) $sElement = _WD_FindElement($sSession, $_WD_LOCATOR_ByXPath, "//span[text() = 'Offered access to electronic health information?']") Sleep(1000) _WD_ElementAction($sSession, $sElement, 'click') Sleep(500) _WD_Action($sSession, "actions", $sActionTab) Sleep(500) _WD_Action($sSession, "actions", $sActionEnter) Is there a way I can get the count of spans in the span class-"s_636" by tabbing over to the button? I am hoping someone might have some ideas on what I can try.
      Unfortunally, The site is for work so giving the site wont do any good. 
    • By kurtykurtyboy
      GuiFlatButton is a UDF to easily create regular buttons with different colors for background, foreground, border, hover, focus, etc..
      This started as an effort to change the background color of a button and eventually grew into a full UDF.
      If you've looked around forums for changing button background colors, you have probably noticed that each proposed workaround has its own set of issues/side-effects. The answers usually circle back to 'use ownerdrawn buttons' and 'not worth it'. Well, now it is possible for anyone to easily create ownerdrawn buttons - totally worth it!
      Some issues with other workarounds such as drawing with GDI+ or using a colored label as a 'button':
      Not 'real' buttons so you lose built-in functionality that windows gives to buttons Messy / inefficient code in the main while loop to check for mouse position Slow to respond to click, paint, etc... Having to deal with GUIRegisterMsg messages Not straight-forward to implement GuiFlatButton is not a workaround; it is a technique to respond to Windows' built-in owner-drawn button events.
      With minimal effort, we can now create true simple colored buttons.
      The idea is to create an owner-drawn button using GUICtrlCreateButton then subclass the GUI and controls to handle the button-specific events to paint it however we want.
      This UDF magically does all of this for us! No need to worry about event handling or main while loop logic.
       
      How to use
      It couldn't be any easier! Simply create a new button using the familiar syntax. This creates an ownerdrawn button with default colors.
      $mybutton1 = GuiFlatButton_Create("Button 1", 78, 20, 120, 40) If you want to change the background and text colors:
      GuiFlatButton_SetBkColor(-1, 0x5555FF) GuiFlatButton_SetColor(-1, 0xFFFFFF) Advanced Usage
      Set background/text/border all at once
      GuiFlatButton_SetColors(-1, 0x0000FF, 0xFFFFFF, 0x9999FF) Set ALL colors for ALL button states! (normal, focus, hover, selected)
      Local $aColorsEx = [0x0000FF, 0xFFFFFF, -2, 0x4444FF, 0xFFFFFF, 0xAAAAFF, 0x6666FF, 0xFFFFFF, 0xCCCCFF, 0x0000EE, 0xFFFFFF, 0x7777EE] GuiFlatButton_SetColorsEx(-1, $aColorsEx) Set default colors to apply to any future buttons
      ;set colors GuiFlatButton_SetDefaultColors(0x0000FF, 0xFFFFFF, 0x9999FF) ;create buttons $mybutton1 = GuiFlatButton_Create("Button 1", 12, 20, 120, 40) $mybutton2 = GuiFlatButton_Create("Button 2", 143, 20, 120, 40) Set ALL color defaults
      ;set colors Local $aColorsEx = [0x0000FF, 0xFFFFFF, -2, 0x4444FF, 0xFFFFFF, 0xAAAAFF, 0x6666FF, 0xFFFFFF, 0xCCCCFF, 0x0000EE, 0xFFFFFF, 0x7777EE] GuiFlatButton_SetDefaultColorsEx($aColorsEx) ;create buttons $mybutton1 = GuiFlatButton_Create("Button 1", 12, 20, 120, 40) $mybutton2 = GuiFlatButton_Create("Button 2", 143, 20, 120, 40)  
      Available Functions
       
      Simple Example

      #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> #include "GuiFlatButton.au3" Example() ;GUI with one button Func Example() Local $hGUI, $mybutton1 $hGUI = GUICreate("GuiFlatButton Ex0", 275, 120) GUISetBkColor(0x333333) Local $idLabel = GUICtrlCreateLabel("Click the button", 10, 100, 150, 30) GUICtrlSetColor(-1, 0xFFFFFF) ;create new button then set the background and foreground colors $mybutton1 = GuiFlatButton_Create("Button 1" & @CRLF & "Line 2", 78, 20, 120, 40, $BS_MULTILINE) GuiFlatButton_SetBkColor(-1, 0x5555FF) GuiFlatButton_SetColor(-1, 0xFFFFFF) GUISetState(@SW_SHOW, $hGUI) Local $i = 0 Local $iMsg While 1 $iMsg = GUIGetMsg() Switch $iMsg Case $GUI_EVENT_CLOSE ExitLoop Case $mybutton1 $i += 1 GUICtrlSetData($idLabel, $i) ConsoleWrite($i & @CRLF) EndSwitch Sleep(10) WEnd GUIDelete() EndFunc ;==>Example
      Menu/Toolbar Example

      #include <GUIConstantsEx.au3> #include <MsgBoxConstants.au3> #include "GuiFlatButton.au3" Example() ;Example GUI with toolbar Func Example() Local $hGUI, $idLabel, $aButtons, $iTbSize $hGUI = GUICreate("GuiFlatButton Ex2", 300, 200) GUISetBkColor(0x444444) $idLabel = GUICtrlCreateLabel("Click a button", 10, 180, 150, 30) GUICtrlSetColor(-1, 0xFFFFFF) $aButtons = createToolbar() $iTbSize = UBound($aButtons) GUISetState(@SW_SHOW, $hGUI) Local $i = 0 Local $iMsg While 1 $iMsg = GUIGetMsg() Switch $iMsg Case $GUI_EVENT_CLOSE ExitLoop Case $aButtons[0] To $aButtons[$iTbSize - 1] ConsoleWrite("1") GUICtrlSetData($idLabel, GuiFlatButton_Read($iMsg)) EndSwitch Sleep(10) WEnd GUIDelete() EndFunc ;==>Example Func createToolbar() Local $aButtons[6] Local $bkColor = 0x777777 Local $textColor = 0xFFFFFF Local $borderColor = 0x999999 Local $aBtnClrs[12] = [0x777777, 0xFFFFFF, $GUI_BKCOLOR_TRANSPARENT, 0x888888, 0xFFFFFF, $GUI_BKCOLOR_TRANSPARENT, 0x999999, 0xFFFFFF, $GUI_BKCOLOR_TRANSPARENT, 0x666666, 0xFFFFFF, $GUI_BKCOLOR_TRANSPARENT] For $i = 0 To UBound($aButtons) - 1 $aButtons[$i] = GuiFlatButton_Create("B" & $i, $i * 50, 0, 50, 17) GuiFlatButton_SetColorsEx($aButtons[$i], $aBtnClrs) Next Return $aButtons EndFunc ;==>createToolbar  
      Icon Example
      You can even easily add icons to your buttons -- just create a new button and send it an icon!

      #include <GDIPlus.au3> #include "GuiFlatButton.au3" Example() ;buttons with Icon images Func Example() ;get images for demonstration _GDIPlus_Startup() ;initialize GDI+ Local $hIcon = _WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 258, 24, 24) ;extract the 'Save' icon Local $hBitmap = _GDIPlus_BitmapCreateFromHICON($hIcon) ;Create Bitmap from Icon (for demonstration) Local $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) ;Create HBitmap from Bitmap _GDIPlus_BitmapDispose($hBitmap) ;dispose the bitmap _GDIPlus_Shutdown() ;done with GDI+ Local $hGUI = GUICreate("GuiFlatButton Ex5", 255, 400) GUISetBkColor(0xEEEEEE) ;set default colors of future buttons Local $aColorsEx = _ [0xE2E5E8, 0X000000, 0x888888, _ ; normal : Background, Text, Border 0xE2E5E8, 0X000000, 0x333333, _ ; focus : Background, Text, Border 0xE8E8E8, 0X000000, 0x666666, _ ; hover : Background, Text, Border 0xDDDDDD, 0X000000, 0xAAAAAA] ; selected : Background, Text, Border GuiFlatButton_SetDefaultColorsEx($aColorsEx) ;normal button with icon $label1 = GUICtrlCreateLabel( "$BS_TOOLBUTTON -->", 5, 10) GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT) Local $mybutton1 = GuiFlatButton_Create("Save", 130, 5, 50, 48, $BS_TOOLBUTTON) _WinAPI_DeleteObject(_SendMessage(GUICtrlGetHandle($mybutton1), $BM_SETIMAGE, $IMAGE_ICON, $hIcon)) ;align top Local $mybuttonT = GuiFlatButton_Create("Top", 5, 65, 120, 55, $BS_TOP) _WinAPI_DeleteObject(_SendMessage(GUICtrlGetHandle($mybuttonT), $BM_SETIMAGE, $IMAGE_ICON, $hIcon)) ;align top-left Local $mybuttonTL = GuiFlatButton_Create("Top-Left", 5, 125, 120, 55, BITOR($BS_TOP, $BS_LEFT)) _WinAPI_DeleteObject(_SendMessage(GUICtrlGetHandle($mybuttonTL), $BM_SETIMAGE, $IMAGE_ICON, $hIcon)) ;align top-right Local $mybuttonTR = GuiFlatButton_Create("Top-Right", 5, 185, 120, 55, BITOR($BS_TOP, $BS_RIGHT)) _WinAPI_DeleteObject(_SendMessage(GUICtrlGetHandle($mybuttonTR), $BM_SETIMAGE, $IMAGE_ICON, $hIcon)) ;align left Local $mybuttonL = GuiFlatButton_Create("Left", 5, 245, 120, 55, $BS_LEFT) _WinAPI_DeleteObject(_SendMessage(GUICtrlGetHandle($mybuttonL), $BM_SETIMAGE, $IMAGE_ICON, $hIcon)) ;align bottom Local $mybuttonB = GuiFlatButton_Create("Bottom", 130, 65, 120, 55, $BS_BOTTOM) _WinAPI_DeleteObject(_SendMessage(GUICtrlGetHandle($mybuttonB), $BM_SETIMAGE, $IMAGE_ICON, $hIcon)) ;align bottom-left Local $mybuttonBL = GuiFlatButton_Create("Bottom-Left", 130, 125, 120, 55, BITOR($BS_BOTTOM, $BS_LEFT)) _WinAPI_DeleteObject(_SendMessage(GUICtrlGetHandle($mybuttonBL), $BM_SETIMAGE, $IMAGE_ICON, $hIcon)) ;align bottom-right Local $mybuttonBR = GuiFlatButton_Create("Bottom-Right", 130, 185, 120, 55, BITOR($BS_BOTTOM, $BS_RIGHT)) _WinAPI_DeleteObject(_SendMessage(GUICtrlGetHandle($mybuttonBR), $BM_SETIMAGE, $IMAGE_ICON, $hIcon)) ;align right Local $mybuttonR = GuiFlatButton_Create("Right", 130, 245, 120, 55, $BS_RIGHT) _WinAPI_DeleteObject(_SendMessage(GUICtrlGetHandle($mybuttonR), $BM_SETIMAGE, $IMAGE_ICON, $hIcon)) GuiFlatButton_SetState($mybuttonR, $GUI_DISABLE ) ;disabled Local $mybuttonDisable = GuiFlatButton_Create("Disabled", 130, 310, 120, 55, $BS_TOOLBUTTON) _WinAPI_DeleteObject(_SendMessage(GUICtrlGetHandle($mybuttonDisable), $BM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap)) GuiFlatButton_SetState($mybuttonDisable, $GUI_DISABLE ) ;clean up! _WinAPI_DestroyIcon( $hIcon ) _WinAPI_DeleteObject( $hHBitmap ) GUISetState(@SW_SHOW, $hGUI) Local $iMsg While 1 $iMsg = GUIGetMsg() Switch $iMsg Case $GUI_EVENT_CLOSE ExitLoop EndSwitch Sleep(10) WEnd GUIDelete() EndFunc ;==>Example  
      I'm sure there are some use-cases I've forgotten, so feedback is welcome!
       
      Download the latest UDF and several more examples:
      GuiFlatButton_20220919.zip (1,121)
      Update 2022-09-19
      Added update from 05/25 back in after it was accidentally removed
      Update 2022-09-01
      Added $BS_MULTILINE button style
      Added ellipses when text is longer than the button
      Fixed compatibility with Opt("MustDeclareVars", 1)
      Update 2022-05-25
      Fixed issue, buttons disappear when a GUI containing a child window with WS_EX_MDICHILD extended style is moved
      Update 2022-05-24
      Fixed issue releasing subclassing when GUI is deleted but program is not closed
      Fixed occasional white background flicker
      Added function GuiFlatButton_GetPos
      Update 2021-01-02
      Fixed bug, not drawing correctly after deleting GUI with GUIDelete()
      Fixed bug, changing default colors changed all buttons, even previously created buttons
      Made some internal functions more efficient
      Update 2019-04-14
      Fixed bug, not showing pressed down state when clicking rapidly
      Added Icon/Bitmap support!
      Added function GuiFlatButton_SetPos to change the position and/or size of a button
      Update 2019-02-09
      Added 2 new functions to set the button colors globally for all future buttons.
      GuiFlatButton_SetDefaultColors 
      GuiFlatButton_SetDefaultColorsEx

      Credits to:
      Melba23 (UDF template)
      LarsJ (general subclassing code)
      4ggr35510n (TrackMouseEvent example)
      binhnx (disable dragging with $WS_EX_CONTROLPARENT)
      GUIRegisterMsg in AutoIt Help (owner-draw button example)
      funkey (_WinAPI_DrawState example)
       
       
       
       
    • By t0nZ
      Always searching for the "final" solution to my zipping/unzipping needs, I started years ago using WinRar with AutoIT (don't ask me why...) and for the last 10 years I worked well with the _zip.UDF , a good solution using the embedded windows zipfldr.dll.
      But often I work with a lot of data (both multi gigabytes and/or 100K+ files) and I noticed the performance of the windows zip DLL are not so good, the problem is maybe worsened by the mono thread operation using AutoIT +  zipfldr.dll.
      SO my choice is 7zip (7ZA.exe)  also for licence (freeware also for business) reasons, and I wrote a small and simple UDF:
      ; #INDEX# ======================================================================================================================= ; Title .........: _7za ; AutoIt Version : 3.3.16.0 ; Language ......: English ; Description ...: Functions for using 7za.exe archive manipulation app ; Author(s) .....: NSC ; Version .......: 1.2 ; Date ..........: 2022/06/28 ; =============================================================================================================================== ; ------------------------------------------------------------------------------ ; This software is provided 'as-is', without any express or ; implied warranty. In no event will the authors be held liable for any ; damages arising from the use of this software. ; #INCLUDES# =================================================================================================================== ; #include-once #include <AutoItConstants.au3> ; =============================================================================================================================== ; #VARIABLES# =================================================================================================================== ; Global Global $7za_exe = @ScriptDir & "\" & "7za.exe" ; =============================================================================================================================== ; #CURRENT# ===================================================================================================================== ; _EXEC7za ;_UNcompress_7za ;_COMpress_7za_7z ;_COMpress_7za_zip ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name ..........: _EXEC7za ; Description ...: launch 7Za.exe with params and returns exit codes ; Syntax ........: EXEC7za($7zCommands, $archive, $folder[, $show]) ; Parameters ....: $7zCommands - 7zip command line params ; $archive - complete path to the archive ; $folder - the source/destination folder ; $show - optional set the state of 7za console visibility, default @SW_HIDE, ; other values as ShellExecuteWait() ; Return values .: 1 - Success ; 0 - and set @error = 1 ; and ; @extended = 1 (Warning (Non fatal error(s)) ; @extended = 2 (Fatal error) ; @extended = 7 (Command line error) ; @extended = 8 (Not enough memory for operation) ; @extended = 255 (User stopped the process) ; @extended values set by 7za.exe exit codes ; Author ........: NSC ; Modified ......: 2022/05/13 ; Remarks .......: requires 7za.exe in @scriptdir, 7za.exe (7-Zip Extra: standalone console version) ; Thanks to 7-zip.org ; Related .......: ; Link ..........: ; Examples .......: compress a folder recursive with subfolders ; EXEC7za("u -mx4 -bt", c:\folder1\archive.7z", c:\folder1\folderTOcompress\ ) ; uncompress the same folder recursive ; EXEC7za("x -aoa -bt -r", "c:\folder1\archive.7z", "-oc:\folder2\") ; =============================================================================================================================== Func _EXEC_7za($7zCommands, $archive, $folder, $show = @SW_HIDE) Local $return7za = ShellExecuteWait($7za_exe, $7zCommands & ' "' & $archive & '" "' & $folder & '"', '', $SHEX_OPEN, $show) Select Case $return7za = 0 Return 1 Case Else Return SetError(1, $return7za, 0) EndSelect EndFunc ;==>_EXEC_7za ; #FUNCTION# ==================================================================================================================== ; Name ..........: _UNcompress_7za ; Description ...: launch 7Za.exe with preset params to uncompress an archive (.7z or .zip recursively) and returns exit codes ; Syntax ........: _UNcompress_7za($archive, $folder[, $show]) ; Parameters ....: $archive - complete path to the archive ; $folder - the source/destination folder ; $show - optional set the state of 7za console visibility, default @SW_HIDE, ; other values as ShellExecuteWait() ; Return values .: 1 - Success ; 0 - and set @error = 1 ; and ; @extended = 1 (Warning (Non fatal error(s)) ; @extended = 2 (Fatal error) ; @extended = 7 (Command line error) ; @extended = 8 (Not enough memory for operation) ; @extended = 255 (User stopped the process) ; @extended values set by 7za.exe exit codes ; Author ........: NSC ; Modified ......: 2022/05/19 ; Remarks .......: requires 7za.exe in @scriptdir, 7za.exe (7-Zip Extra: standalone console version) ; Thanks to 7-zip.org ; Related .......: ; Link ..........: ; =============================================================================================================================== Func _UNcompress_7za($archive, $folder, $show = @SW_HIDE) Local $return7za = ShellExecuteWait($7za_exe, "x -aoa -bt -r" & ' "' & $archive & '" -o"' & $folder & '"', '', $SHEX_OPEN, $show) Select Case $return7za = 0 Return 1 Case Else Return SetError(1, $return7za, 0) EndSelect EndFunc ;==>_UNcompress_Folder_7za ; #FUNCTION# ==================================================================================================================== ; Name ..........: _COMpress_7za_7z ; Description ...: launch 7Za.exe with precompiled params to compress in .7z format ;a single file, a filtered (*.pdf) bunch of files or a folder (recursively) and returns exit codes ; Syntax ........: _COMpress_7za_7z($archive, $folder[, $show [, $compLvl]] ) ; Parameters ....: $archive - complete path to the archive ; $folder - the source file(s) / folder ; $show - optional set the state of 7za console visibility, default @SW_HIDE, ; other values as ShellExecuteWait() ; $CompLvl - optional compression level (1-9) default 4 ; Return values .: 1 - Success ; 0 - and set @error = 1 ; and ; @extended = 1 (Warning (Non fatal error(s)) ; @extended = 2 (Fatal error) ; @extended = 7 (Command line error) ; @extended = 8 (Not enough memory for operation) ; @extended = 255 (User stopped the process) ; @extended values set by 7za.exe exit codes ; Author ........: NSC ; Modified ......: 2022/06/22 ; Remarks .......: requires 7za.exe in @scriptdir, 7za.exe (7-Zip Extra: standalone console version) ; avoids re-compress of popular archives. ; Thanks to 7-zip.org ; Related .......: ; Link ..........: ; =============================================================================================================================== Func _COMpress_7za_7z($archive, $folder, $show = @SW_HIDE, $CompLvl = 4) If StringRight($folder, 4) = ".zip" Or StringRight($folder, 3) = ".7z" Or StringRight($folder, 4) = ".rar" Or StringRight($folder, 4) = ".lha" Or StringRight($folder, 3) = ".gz" Or StringRight($folder, 7) = ".tar.gz" Or StringRight($folder, 4) = ".iso" Then $CompLvl = 0 EndIf Local $return7za = ShellExecuteWait($7za_exe, 'u -mx' & $CompLvl & ' -mmt -bt' & ' "' & $archive & '" "' & $folder & '"', '', $SHEX_OPEN, $show) Select Case $return7za = 0 Return 1 Case Else Return SetError(1, $return7za, 0) EndSelect EndFunc ;==>_COMpress_7za_7z ; #FUNCTION# ==================================================================================================================== ; Name ..........: _COMpress_7za_zip ; Description ...: launch 7Za.exe with precompiled params to compress in zip format ; a single file, a filtered (*.pdf) bunch of files or a folder (recursively) and returns exit codes ; Syntax ........: _COMpress_7za_zip($archive, $folder[, $show [, $compLvl]] ) ; Parameters ....: $archive - complete path to the archive ; $folder - the source file(s) / folder ; $show - optional set the state of 7za console visibility, default @SW_HIDE, ; other values as ShellExecuteWait() ; $CompLvl - optional compression level (1-9) default 4 ; Return values .: 1 - Success ; 0 - and set @error = 1 ; and ; @extended = 1 (Warning (Non fatal error(s)) ; @extended = 2 (Fatal error) ; @extended = 7 (Command line error) ; @extended = 8 (Not enough memory for operation) ; @extended = 255 (User stopped the process) ; @extended values set by 7za.exe exit codes ; Author ........: NSC ; Modified ......: 2022/06/22 ; Remarks .......: requires 7za.exe in @scriptdir, 7za.exe (7-Zip Extra: standalone console version), ; avoids re-compress of popular archives. ; Thanks to 7-zip.org ; Related .......: ; Link ..........: ; =============================================================================================================================== Func _COMpress_7za_zip($archive, $folder, $show = @SW_HIDE, $CompLvl = 9) If StringRight($folder, 4) = ".zip" Or StringRight($folder, 3) = ".7z" Or StringRight($folder, 4) = ".rar" Or StringRight($folder, 4) = ".lha" Or StringRight($folder, 3) = ".gz" Or StringRight($folder, 7) = ".tar.gz" Or StringRight($folder, 4) = ".iso" Then $CompLvl = 0 EndIf Local $return7za = ShellExecuteWait($7za_exe, 'u -tzip -mx' & $CompLvl & ' -mmt -bt' & ' "' & $archive & '" "' & $folder & '"', '', $SHEX_OPEN, $show) Select Case $return7za = 0 Return 1 Case Else Return SetError(1, $return7za, 0) EndSelect EndFunc ;==>_COMpress_7za_zip You have to provide 7za.exe, in scriptdir in some way, maybe with a fileinstall or embedding in some way. 
      Daily I use most of the time:
      _UNcompress_7za
      _COMpress_7za_7z
      so I'am almost done with these funcs....
      Also I made a quick and dirty benchmark on some real world data (for me at least) , comparing the windows DLL, the zip ULTRA by 7zip and the various 7zip levels.

      My choice is level 4 (time/size) but your mileage may vary...
      Also, extracting many thousands of little files from a 7z archive with 7zip is waaaay fast in respect to other solutions.
    • By Kanashius
      This UDF can be used to draw at the Desktop Wallpaper (Windows 8+) with GDI+ without using files.
      The example runs with 60-120fps at my machine, so the speed is acceptable.
      When the script exits, the original wallpaper is restored.
      Have fun :).
      PS: The UDF uses the window between the background and the icons, so it could be used to add an own child window at the desktop. Just look at the begin of __Wallpaper_Startup ($hWorkerW).
       
      Example:
       
      WallpaperUDF.au3 WallpaperUDF Example.au3
    • By sandgre
      Wondering if you can help a teacher out.  For the last few years of remote, hybrid, and in-person teaching I've been using an AutoHotKey script that creates an inking toolbar to be used during a PowerPoint presentation.  (https://www.autohotkey.com/boards/viewtopic.php?t=79163) The annotation tools available through Ppt are woefully inadequate, and, on my machine at least, jump around all over the place - sometimes on the bottom, sometimes on the left, sometimes on the right.  It's a scavenger hunt every single time.  The inking tool is always available, and recent updates allowed for the addition of lots more colors, which I used for modeling phenomena with students. One tragic day I arrived to school to find that my district IT dep't took away access to AutoHotKey.  No more tool bar. 
      I've been trying to resurrect some programming skills from a past life. I'm working through various tutorials and help files, with the goal of recreating the toolbar in AutoIt.  I'm really needing some help to move things along though.  I've been going through your PowerPoint UDF and all of your functions seem to just relate to editing the slides. Can you point me in the direction of how to create a toolbar that accesses the annotation tools that are available during the slideshow itself? 
       
×
×
  • Create New...