Christoph Jüngling
Christoph Jüngling

Reputation: 1100

Robotframework, AutoIt: Error message "No keyword with name 'Send' found"

I'm trying to get familiar with the robotframework using autoitlibrary to test Windows applications. I found some examples which use the Send command to type text into a notpad window.

That's what I've done so far:

*** Settings ***
Library           AutoItLibrary

*** Variables ***
${app}            C:/Program Files/Notepad++/notepad++.exe

*** Test Cases ***
Enter text
    Run    ${app}
    Win Wait Active    new 1 - Notepad++
    Send    This is just a test.

So, the Notepad++ window is opened, but then it failed with the No keyword with name 'Send' found. message. I suppose there is no Send command in the AutoItLibrary, but I also cannot find any other command which may do this job.

AutoIt is installed, and so is the wrapper by pip install robotframework-autoitlibrary.

There really exists a Send keyword in AutoIt, but supposedly not in the wrapper for robotframework.

And ideas to fix this?

UPDATE: Windows 10 (64bit in a VirtualBox), Python v3.7.6 (32bit), RF v3.1.2, RF-AutoItLibrary v1.2.4, AutoIt v3.3.14.5

The "Search Keywords" dialog in RIDE provides AutoItLibrary as a Source, but then list only a few commands. So I suppose the library is accessible, but incomplete. enter image description here

Upvotes: 1

Views: 4706

Answers (2)

PDHide
PDHide

Reputation: 19949

Fix:

Check your python architecture ( is it 32 or 64 bit)

For 32:

  1. Open cmd in "Run as administrator" mode
  2. run the command pip install robotframework-autoitlibrary
  3. Now clone the autoit library source code: https://github.com/nokia/robotframework-autoitlibrary
  4. in the root directory run the below command: python setup.py install using cmd in admin mode

to navigate to root directory use the command pushd <filepath>' instead ofcd ` if cd doesn't work in cmd opened in admin mode.

For 64:

  1. Open cmd in "Run as administrator" mode
  2. Now clone the autoit library source code: https://github.com/nokia/robotframework-autoitlibrary
  3. in the root directory run the below command: python setup.py install using cmd in admin mode

to navigate to root directory use the command pushd <filepath>' instead ofcd ` if cd doesn't work in cmd opened in admin mode.

Upvotes: 0

michael_heath
michael_heath

Reputation: 5372

import os, re, subprocess, sys

# Set path to Python directories.
programfiles = os.environ['programfiles']
if not programfiles:
    exit('Failed to get programfiles')

python_dirs = [os.path.join(programfiles, 'Python35'),
               os.path.join(programfiles, 'Python36'),
               os.path.join(programfiles, 'Python37'),
               os.path.join(programfiles, 'Python38')]

# Process each python directory.
for python_dir in python_dirs:
    print('---')

    # Set path to AutoItX3.dll.
    autoitx_dll = os.path.join(python_dir, r'Lib\site-packages\AutoItLibrary\lib\AutoItX3.dll')
    if not os.path.isfile(autoitx_dll):
        print('File not found: "' + autoitx_dll + '"')
        continue

    # Set path to the makepy module.
    makepy = os.path.join(python_dir, r'Lib\site-packages\win32com\client\makepy.py')
    if not os.path.isfile(makepy):
        print('File not found: "' + makepy + '"')
        continue

    # Generate cache using make.py.
    command = [os.path.join(python_dir, 'python.exe'), makepy, autoitx_dll]

    with subprocess.Popen(command, stderr=subprocess.PIPE, cwd=python_dir, universal_newlines=True) as p:
        stderr = p.communicate()[1]
        print(stderr.rstrip())

        parameters = re.findall(r'^Generating to .+\\([A-F0-9\-]+)x(\d+)x(\d+)x(\d+)\.py$', stderr, re.M)

        if len(parameters) == 1:
            parameters = parameters[0]

            print('Insert the next line into AutoItLibrary.__init__.py if not exist.\n'
                  '  win32com.client.gencache.EnsureModule("{{{guid}}}", {major}, {minor}, {lcid})'
                  .format(guid=parameters[0],
                          major=parameters[1],
                          minor=parameters[2],
                          lcid=parameters[3]))

# Pause so the user can view the subprocess output.
input('Press the return key to continue...')

The generated cache done by win32com\client\makepy.py for AutoItLibrary from the setup.py is saved in the %temp%\gen_py folder. This is done only when setup.py is executed. If the %temp% directory is cleaned later, which removes the cache, then I notice keywords like Send may fail to be recognized by the robotframework.

One solution appears to be regenerating the cache. The code above will generate the cache by use of makepy.py. It may also print a message about inserting win32com.client.gencache.EnsureModule(...) into AutoItLibrary\__init__.py for any of the Python versions as needed. This will ensure the cache is available when AutoItLibrary is imported.

Change paths in the code to suit your environment.


With further research:

  • AutoItLibrary currently has AutoItX 3.3.6.1 and latest AutoIt has AutoItX 3.3.14.5. Important to know as one version registered can overwrite the registration of the previous registration.
  • AutoItLibrary currently registers AutoIt3X.dll without the _x64 suffix on the name on x64 systems. I may reference AutoIt3_x64.dll to define difference between x86 and x64.
  • Any version of AutoIt3X.dll and AutoIt3_x64.dll uses the same ID codes and the last registered wins (based on bitness as both x86 and x64 registrations can co-exist).
    The TypeLib class key registered ID is {F8937E53-D444-4E71-9275-35B64210CC3B} and is where win32com may search.
  • If AutoIt3X.dll and AutoIt3_x64.dll are registered, unregister any 1 of those 2 will remove the AutoItX3.Control class key. Without this key, AutoIt3X will fail as AutoItLibrary needs this key. To fix, register again e.g. regsvr32.exe AutoIt3X.dll as admin in the working directory of AutoIt3X.dll.
  • The methods of any same version of AutoItX will match i.e. AutoIt3X.dll and AutoIt3X_x64.dll only changes in bitness, not methods.

Inserting win32com.client.gencache.EnsureModule("{F8937E53-D444-4E71-9275-35B64210CC3B}", 0, 1, 0) into AutoItLibrary\__init__.py should ensure the cache is always available for any AutoItX version. The initial code can be used to generate the cache, though the suggested change in AutoItLibrary\__init__.py makes it obsolete as the cache is generated on import of AutoItLibrary. If the ID was not constant, then the initial code may inform you of the ID to use.

The cache is important as it has generated .py files with methods like e.g.:

       def Send(self, strSendText=defaultNamedNotOptArg, nMode=0):
           'method Send'
           # etc...

which if missing, makes Send and many others, an invalid keyword in AutoItLibrary.

If AutoItX 3.3.14.5 is registered, the - leading methods are removed and the + leading methods are added as compared to AutoItX 3.3.6.1:

-BlockInput
-CDTray
-IniDelete
-IniRead
-IniWrite
-RegDeleteKey
-RegDeleteVal
-RegEnumKey
-RegEnumVal
-RegRead
-RegWrite
-RunAsSet
+RunAs
+RunAsWait

So if any of those methods causes error, then you may want AutoItX 3.3.6.1 registered instead. In the AutoItX history, 3.3.10.0 release is when those method changes happened.

Upvotes: 2

Related Questions