Automatyzacja testów SAP z użyciem Windows API w Pythonie

Artur - AFINE cybersecurity team member profile photo
Michał Majchrowicz
February 13, 2026
13
min read

W poprzednim artykule „Ocena bezpieczeństwa kontrolek SAP GUI przy użyciu Windows API w Pythonie” opisano jak za pomocą prostych wywołań API analizować standardowe kontrolki SAP. W praktyce jednak takie podejście często przestaje działać przy bardziej złożonych lub niestandardowych elementach interfejsu. Do tego dochodzi fakt, że wiele firm nadal opiera automatyzację SAP na podstawowych skryptach, które wystarczają jedynie w najprostszych przypadkach. Gdy procesy stają się bardziej złożone, te narzędzia po prostu nie dają rady. Dlatego w tym artykule przedstawiono bardziej zaawansowane techniki —  wykorzystanie Windows API w Pythonie do sterowania SAP GUI na poziomie systemu operacyjnego. Dzięki temu możemy automatyzować nawet te elementy, do których SAP nie udostępnia żadnego API.
W artykule pokazano jak niskopoziomowe wywołania Windows API można wykorzystać do zarządzania fokusem okien, nawigowania po dynamicznych polach i symulowania naciśnięć klawiszy w celu stworzenia stabilnej i elastycznej automatyzacji testów.
Takie techniki zapewniają większą niezawodność i swobodę działania, szczególnie tam, gdzie standardowe skrypty SAP okazują się niewystarczające.

Czyszczenie pól wejściowych za pomocą Windows API

Jednym z najbardziej praktycznych przykładów kontroli SAP GUI jest możliwość czyszczenia zawartości aktywnego pola wejściowego bez korzystania z wbudowanego silnika skryptowego SAP. Funkcja clear_current_field() realizuje to poprzez symulowanie akcji klawiatury na poziomie systemu operacyjnego z wykorzystaniem Windows API. Zamiast wchodzić w interakcję z obiektami SAP GUI bezpośrednio, funkcja wysyła niskopoziomowe zdarzenia klawiatury (user32.keybd_event), które emulują fizyczne naciśnięcia klawiszy.

Działanie funkcji przebiega w dwóch etapach:

  1. Zaznaczenie całego tekstu – wysyłana jest kombinacja Ctrl+A, aby zaznaczyć całą zawartość bieżącego pola. Wciśnięcie i zwolnienie klawiszy Ctrl oraz A odbywa się w odpowiedniej kolejności, aby mieć pewność, że zaznaczenie zostało wykonane.
  2. Usunięcie zawartości – po krótkiej pauzie systemowej funkcja wysyła zdarzenie naciśnięcia klawisza Backspace, aby usunąć zaznaczony tekst.

Krótkie przerwy (time.sleep()) zapobiegają błędom czasowym i zwiększają niezawodność. To podejście jest szczególnie przydatne, gdy skrypty SAP GUI są wyłączone lub gdy interfejs zawiera dynamiczne pola o zmiennych identyfikatorach. Należy jednak uważać na potencjalne problemy, takie jak: utrata fokusu (czyszczenie niewłaściwego pola) lub zbyt szybkie działanie na wolniejszych systemach. Aby zminimalizować ryzyko, warto dodać obsługę błędów, dynamiczne opóźnienia oraz sprawdzenie aktywnego okna/kontrolki przed wykonaniem funkcji.

def clear_current_field():
    # Press Ctrl+A
    user32.keybd_event(VK_CONTROL, 0, 0, 0)   # Ctrl down
    user32.keybd_event(VK_A, 0, 0, 0)         # A down
    user32.keybd_event(VK_A, 0, KEYEVENTF_KEYUP, 0)   # A up
    user32.keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0)  # Ctrl up

    time.sleep(0.1)  # Allow system to process Ctrl+A

    # Press Backspace to delete
    user32.keybd_event(VK_BACK, 0, 0, 0)
    user32.keybd_event(VK_BACK, 0, KEYEVENTF_KEYUP, 0)
    time.sleep(0.1)

Zarządzanie fokusem i nawigacja po kontrolkach SAP GUI

Skuteczne sterowanie SAP GUI wymaga nie tylko interakcji z widocznymi elementami, ale również precyzyjnego zarządzania fokusem i wejściem z klawiatury na poziomie systemowym. Poniższe funkcje prezentują zaawansowane techniki automatyzacji testów SAP przy użyciu Windows API.

1. Wysyłanie klawisza ENTER

Funkcja send_enter_key(hwnd) służy do wywołania akcji w określonym oknie SAP GUI poprzez symulację naciśnięcia klawisza ENTER.
Najpierw wywołuje SetForegroundWindow, aby przenieść okno na pierwszy plan, po czym po krótkim opóźnieniu wysyła komunikaty WM_KEYDOWN i WM_KEYUP dla klawisza VK_RETURN bezpośrednio do kolejki wiadomości aktywnego okna SAP. Takie podejście jest wydajne, ponieważ omija wyższe warstwy interfejsu wejścia, ale wymaga, by aplikacja poprawnie interpretowała te komunikaty jako prawdziwe naciśnięcia klawiszy.

2. Ustawianie fokusu

Funkcja set_focus(hwnd) uzupełnia poprzednią – służy do zarządzania fokusem okna.
Korzysta z metod SetForegroundWindow i SetFocus, aby mieć pewność, że kolejne akcje klawiatury zostaną wysłane do właściwej kontrolki. To szczególnie ważne w środowisku SAP, gdzie fokus może się niespodziewanie zmieniać podczas nawigacji lub odświeżania ekranu. Bez odpowiedniego zarządzania fokusem naciśnięcia klawiszy mogą trafić w złe miejsce i spowodować błędy w automatyzacji.

3. Nawigacja z użyciem SHIFT+TAB

Funkcja send_shift_tab(hwnd) symuluje kombinację klawiszy Shift+Tab, która przesuwa kursor do poprzedniego pola w kolejności tabulacji aplikacji. Realizuje to przez kolejne wywołania keybd_event dla klawiszy Shift i Tab – ich wciśnięcie i zwolnienie w odpowiedniej sekwencji. To przydatne narzędzie do dynamicznej nawigacji, zwłaszcza w złożonych ekranach SAP, gdzie pola mogą zmieniać swoje pozycje lub gdy potrzebny jest ruch „wstecz”.

def send_enter_key(hwnd):
    """Send an ENTER key to the specified window."""
    # Bring the window to the foreground
    user32.SetForegroundWindow(hwnd)
    time.sleep(0.1)  # Give time for the window to become active

    # Send WM_KEYDOWN and WM_KEYUP messages for the ENTER key
    user32.PostMessageW(hwnd, WM_KEYDOWN, VK_RETURN, 0)
    user32.PostMessageW(hwnd, WM_KEYUP, VK_RETURN, 0)

def set_focus(hwnd):
    """Send an ENTER key to the specified window."""
    # Bring the window to the foreground
    user32.SetForegroundWindow(hwnd)
    user32.SetFocus(hwnd)
    time.sleep(0.1)  # Give time for the window to become active
        
def send_shift_tab(hwnd):
    user32.keybd_event(VK_SHIFT, 0, 0, 0)
    user32.keybd_event(VK_TAB, 0, 0, 0)
    user32.keybd_event(VK_TAB, 0, KEYEVENTF_KEYUP, 0)
    user32.keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0)
    time.sleep(0.1)  

4. Dobre praktyki automatyzacji testów SAP

Choć opisane wcześniej funkcje zapewniają dużą kontrolę nad SAP GUI, działają one na różnych poziomach — od wysyłania komunikatów okienkowych, przez generowanie sztucznych naciśnięć klawiszy, aż po bezpośrednie zarządzanie fokusem. Ich umiejętne łączenie znacząco poprawia stabilność automatyzacji. Zalecana sekwencja działania:

  • Krok 1: Ustabilizowanie fokusu za pomocą set_focus().
  • Krok 2: Nawigacja do właściwego pola poprzez send_shift_tab().
  • Krok 3: Wywołanie akcji (np. zatwierdzenia formularza) przy użyciu send_enter_key().

Aby uniknąć typowych problemów, takich jak utrata fokusu czy niepoprawne przekazywanie klawiszy, warto stosować: adaptacyjne opóźnienia, weryfikację aktywnego okna przed wysyłaniem klawiszy oraz funkcję SendInput, jeśli PostMessage nie wywołuje oczekiwanego zachowania.

Wysyłanie tekstu jako sekwencji klawiszy w automatyzacji testów SAP

Funkcje get_vk_and_shift(char) oraz send_keys_via_keybd_event(text) współpracują ze sobą, aby przekształcić zwykły tekst na niskopoziomowe zdarzenia klawiatury obsługiwane przez Windows. Taka technika jest szczególnie przydatna tam, gdzie SAP GUI nie umożliwia bezpośredniego wstawiania tekstu.

1. Mapowanie znaków — get_vk_and_shift

Funkcja określa poprawny kod klawisza virtual-key (VK) oraz to, czy do jego wygenerowania potrzebny jest klawisz Shift. Obsługuje małe i wielkie litery, cyfry, podstawowe znaki interpunkcyjne (_, -, /, ?) oraz symbole wymagające kombinacji Shift + cyfra (np. ! @ # $ % ^ & * ( )). W przypadku nieobsługiwanego znaku zgłaszany jest wyjątek ValueError, co ułatwia debugowanie i utrzymanie automatyzacji.

2. Symulacja klawiszy — send_keys_via_keybd_event

Funkcja iteruje po podanym tekście i dla każdego znaku pobiera jego mapowanie z get_vk_and_shift, naciska i zwalnia odpowiednie klawisze. Opcjonalnie obsługuje klawisz Shift gdy zachodzi taka potrzeba oraz stosuje niewielką zwłokę czasową (0.01 s), aby uniknąć pominięcia znaków przez SAP GUI. To podejście jest szczególnie istotne w polach, które dynamicznie walidują dane lub wymagają surowych zdarzeń klawiatury.

3. Dlaczego ta metoda ma znaczenie

To podejście zapewnia precyzyjną, niskopoziomową kontrolę nad wprowadzaniem danych, omijając ograniczenia wyższych warstw automatyzacji. Gwarantuje dostarczenie dokładnie takich sekwencji klawiszy, jakich oczekuje interfejs użytkownika, dzięki czemu sprawdza się w polach przechwytujących raw keyboard events oraz wymuszających ścisłą walidację danych wejściowych. Dodatkowo konstrukcja funkcji upraszcza obsługę błędów — nieobsługiwane znaki są logowane, ale nie przerywają całej procedury wprowadzania.

def get_vk_and_shift(char):
    """Returns (vk_code, use_shift) tuple for a given character."""
    if 'A' <= char <= 'Z':
        return ord(char), True
    elif 'a' <= char <= 'z':
        return ord(char.upper()), False
    elif '0' <= char <= '9':
        return ord(char), False
    elif char == '_':
        return 0xBD, True  # Shift + '-' = '_'
    elif char == '-':
        return 0xBD, False  # VK_OEM_MINUS
    elif char == ' ':
        return 0x20, False  # Space
    elif char == '/':
        return 0xBF, False  # VK_OEM_2
    elif char == '?':
        return 0xBF, True   # Shift + '/' = '?'

    # Special characters that require Shift with number keys
    shift_symbols = {
        '!': ('1', True),
        '@': ('2', True),
        '#': ('3', True),
        '$': ('4', True),
        '%': ('5', True),
        '^': ('6', True),
        '&': ('7', True),
        '*': ('8', True),
        '(': ('9', True),
        ')': ('0', True),
    }

    if char in shift_symbols:
        digit_char, shift = shift_symbols[char]
        return ord(digit_char), shift

    raise ValueError(f"Unsupported character: {repr(char)}")

def send_keys_via_keybd_event(text):
    for char in text:
        try:
            vk_code, use_shift = get_vk_and_shift(char)

            if use_shift:
                ctypes.windll.user32.keybd_event(VK_SHIFT, 0, 0, 0)

            ctypes.windll.user32.keybd_event(vk_code, 0, 0, 0)       # key down
            ctypes.windll.user32.keybd_event(vk_code, 0, KEYEVENTF_KEYUP, 0)  # key up

            if use_shift:
                ctypes.windll.user32.keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0)

            time.sleep(0.01)

        except ValueError as e:
            print(e)

Studium przypadku: Automatyzacja logowania SAP GUI

Poniższy przykład pokazuje, jak za pomocą biblioteki ctypes w Pythonie i Windows API można zautomatyzować proces logowania do SAP GUI — bez korzystania z natywnego mechanizmu SAP GUI Scripting. Takie podejście jest szczególnie użyteczne w środowiskach, w których skrypty SAP są wyłączone lub objęte surowymi ograniczeniami.

Kluczowe elementy automatyzacji

  1. Wykrywanie okien
    Skrypt rozpoczyna od wyszukania głównego okna SAP GUI po tytule. Jeżeli nie zostanie ono znalezione, próbuje wykryć okno SAP Logon i wysłać kliknięcie w przycisk „Log On”, wykorzystując funkcje: find_window_by_title i find_child_window, które enumerują okna systemowe i dopasowują je na podstawie podpisów.
  2. Zarządzanie fokusem
    Po znalezieniu właściwego okna funkcja set_focus przenosi okno na pierwszy plan i zapewnia, że kolejne zdarzenia klawiatury trafią we właściwe pole. Bez tego kroku automatyzacja mogłaby wpisywać dane w nieodpowiednie miejsce.
  3. Nawigacja i czyszczenie pól
    Do przełączania się między polami stosowane są funkcje send_shift_tab (do przechodzenia do poprzedniego pola) oraz  clear_current_field (do wyczyszczenia treści pola - Ctrl+A → Backspace). Zapewnia to spójne działanie nawet przy dynamicznych ekranach SAP.
  4. Wprowadzanie danych logowania
    Dane takie jak język, hasło, nazwa użytkownika czy numer klienta wprowadzane są za pomocą funkcji send_keys_via_keybd_event. Każdy znak jest tłumaczony na odpowiadający mu kod klawisza, dzięki czemu skrypt działa niezależnie od tego w jaki sposób SAP GUI obsługuje dane wejściowe.
  5. Finalizacja logowania
    Po uzupełnieniu wszystkich pól skrypt wykonuje funkcję send_enter_key, która wysyła klawisz Enter. Polecenie to symuluje rzeczywiste zatwierdzenie formularza.
import ctypes, sys
from ctypes import wintypes
import time, string

user32 = ctypes.windll.user32

WM_KEYDOWN = 0x0100
WM_KEYUP = 0x0101 
VK_RETURN = 0x0D
VK_TAB = 0x09
VK_SHIFT = 0x10
VK_CONTROL = 0x11
VK_A = 0x41
VK_BACK = 0x08
KEYEVENTF_KEYUP = 0x0002

EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, wintypes.HWND, wintypes.LPARAM)

def find_window_by_title(target_title):
    found_hwnd = []

    def callback(hwnd, lParam):
        length = user32.GetWindowTextLengthW(hwnd)
        if length > 0:
            buffer = ctypes.create_unicode_buffer(length + 1)
            user32.GetWindowTextW(hwnd, buffer, length + 1)
            if target_title in buffer.value:
                print(buffer.value)
                found_hwnd.append(hwnd)
                return False  
        return True 

    tmp=user32.EnumWindows(EnumWindowsProc(callback), 0)
    return found_hwnd[0] if found_hwnd else None

WM_GETTEXT = 0x000D
WM_GETTEXTLENGTH = 0x000E

def get_window_caption(hwnd):
    text_length = user32.SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0)
    if text_length > 0:
        buffer = ctypes.create_unicode_buffer(text_length + 1)
        user32.SendMessageW(hwnd, WM_GETTEXT, text_length + 1, ctypes.byref(buffer))
        return buffer.value
    return "" 

def find_child_window(parent_hwnd, target_text):
    found_child_hwnd = []

    def callback(hwnd, lParam):
        length = user32.GetWindowTextLengthW(hwnd)
        window_caption=get_window_caption(hwnd)
        if length > 0:
            buffer = ctypes.create_unicode_buffer(length + 1)
            user32.GetWindowTextW(hwnd, buffer, length + 1)
            if target_text in buffer.value:
                found_child_hwnd.append(hwnd)
                return False  
        if window_caption and len(window_caption) > 0:
            if target_text in window_caption:
                    found_child_hwnd.append(hwnd)
                    return False
        return True  

    user32.EnumChildWindows(parent_hwnd, EnumWindowsProc(callback), 0)
    return found_child_hwnd[0] if found_child_hwnd else None


def set_focus(hwnd):
    """Send an ENTER key to the specified window."""
    user32.SetForegroundWindow(hwnd)
    user32.SetFocus(hwnd)
    time.sleep(0.1) 

def send_shift_tab(hwnd):
    user32.keybd_event(VK_SHIFT, 0, 0, 0)
    user32.keybd_event(VK_TAB, 0, 0, 0)
    user32.keybd_event(VK_TAB, 0, KEYEVENTF_KEYUP, 0)
    user32.keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0)
    time.sleep(0.1)  

def send_shift_enter(hwnd):
    user32.keybd_event(VK_SHIFT, 0, 0, 0)
    user32.keybd_event(VK_RETURN, 0, 0, 0)
    user32.keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0)
    user32.keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0)
    time.sleep(0.1)  

def get_vk_and_shift(char):
    """Returns (vk_code, use_shift) tuple for a given character."""
    if 'A' <= char <= 'Z':
        return ord(char), True
    elif 'a' <= char <= 'z':
        return ord(char.upper()), False
    elif '0' <= char <= '9':
        return ord(char), False
    elif char == '_':
        return 0xBD, True  # Shift + '-' = '_'
    elif char == '-':
        return 0xBD, False  # VK_OEM_MINUS
    elif char == ' ':
        return 0x20, False  # Space
    elif char == '/':
        return 0xBF, False  # VK_OEM_2
    elif char == '?':
        return 0xBF, True   # Shift + '/' = '?'

    # Special characters that require Shift with number keys
    shift_symbols = {
        '!': ('1', True),
        '@': ('2', True),
        '#': ('3', True),
        '$': ('4', True),
        '%': ('5', True),
        '^': ('6', True),
        '&': ('7', True),
        '*': ('8', True),
        '(': ('9', True),
        ')': ('0', True),
    }

    if char in shift_symbols:
        digit_char, shift = shift_symbols[char]
        return ord(digit_char), shift

    raise ValueError(f"Unsupported character: {repr(char)}")

def send_keys_via_keybd_event(text):
    for char in text:
        try:
            vk_code, use_shift = get_vk_and_shift(char)

            if use_shift:
                ctypes.windll.user32.keybd_event(VK_SHIFT, 0, 0, 0)

            ctypes.windll.user32.keybd_event(vk_code, 0, 0, 0)       # key down
            ctypes.windll.user32.keybd_event(vk_code, 0, KEYEVENTF_KEYUP, 0)  # key up

            if use_shift:
                ctypes.windll.user32.keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0)

            time.sleep(0.01)

        except ValueError as e:
            print(e)

def clear_current_field():
    # Press Ctrl+A
    user32.keybd_event(VK_CONTROL, 0, 0, 0)   # Ctrl down
    user32.keybd_event(VK_A, 0, 0, 0)         # A down
    user32.keybd_event(VK_A, 0, KEYEVENTF_KEYUP, 0)   # A up
    user32.keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0)  # Ctrl up

    time.sleep(0.1)  # Allow system to process Ctrl+A

    # Press Backspace to delete
    user32.keybd_event(VK_BACK, 0, 0, 0)
    user32.keybd_event(VK_BACK, 0, KEYEVENTF_KEYUP, 0)
    time.sleep(0.1)

def send_enter_key():
    # Press Enter
    ctypes.windll.user32.keybd_event(VK_RETURN, 0, 0, 0)
    # Release Enter
    ctypes.windll.user32.keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0)

# Main logic
if __name__ == "__main__":
    print("\nSAP GUI Login Tool v0.2.1 by Michał Majchrowicz AFINE Team\n")
    
    if len(sys.argv) < 2:
        print(f"{sys.argv[0]} <login_nubmer> [<PL>]\n");
        exit(-1)
    
    sap_login_number=1
    sap_language="EN"
    if len(sys.argv) > 1:
        sap_login_number=int(sys.argv[1])

    if len(sys.argv) > 2 and sys.argv[2].lower() == "pl":
        sap_language="PL"
    print(f"SAP login number: {sap_login_number}")
    sap_login_str="USER"+str(sap_login_number)
    main_window_title = "/000 SAP"
    mainHwnd = find_window_by_title(main_window_title)
    if not mainHwnd:
        print(f"Main Window not found!!!")
        sapLogonHwnd = find_window_by_title("SAP Logon")
        print(f"SAP Logon found: {hex(sapLogonHwnd)}")
        log_on_button_hwnd = find_child_window(sapLogonHwnd, "Log On")
        if log_on_button_hwnd:
            print(f"Log on button found: {hex(log_on_button_hwnd)}")
            set_focus(log_on_button_hwnd)
            send_shift_tab(sapLogonHwnd)
            send_shift_enter(sapLogonHwnd)
            time.sleep(3)
        else:
            print("Log on button not found!!!")
    
    mainHwnd = find_window_by_title(main_window_title)
    if not mainHwnd:
        print(f"Main Window not found!!!")
        exit(-1)
    print(f"Main Window found: {hex(mainHwnd)}")
       
    footer_window_hwnd = find_child_window(mainHwnd, "Footer")
    if footer_window_hwnd:
        print(f"Footer found: {hex(footer_window_hwnd)}")
        set_focus(footer_window_hwnd)
        send_shift_tab(mainHwnd)
        clear_current_field()
        send_keys_via_keybd_event(sap_language)
        send_shift_tab(mainHwnd)
        clear_current_field()
        send_keys_via_keybd_event("Password")
        if sap_login_number < 12 or sap_login_number > 20:
            send_keys_via_keybd_event("?")
        send_shift_tab(mainHwnd)
        clear_current_field()
        send_keys_via_keybd_event(sap_login_str)
        send_shift_tab(mainHwnd)
        clear_current_field()
        if sap_login_number > 21:
            send_keys_via_keybd_event("100")
        else:
            send_keys_via_keybd_event("110")
        send_enter_key()

    print("")

Przykładowy wynik działania

Po uruchomieniu skryptu można zobaczyć następujący output:

PS C:\> python.exe .\sap_login.py 31

SAP GUI Login Tool v0.2.1 by Michał Majchrowicz AFINE Team

SAP login number: 31
Main Window not found!!!
SAP Logon 800
SAP Logon found: 0x103c4
Log on button found: 0x103ce
AFINE/000 SAP
Main Window found: 0x5e029c
Footer found: 0xd0816

1. Uruchomienie polecenia i przetwarzanie danych wejściowych

Skrypt został uruchomiony w Pythonie z argumentem 31, który reprezentuje numer użytkownika SAP. Skrypt poprawnie przetworzył dane wejściowe i rozpoznał, że użytkownik chce zalogować się jako SAP user o numerze 31. Wartość ta określa nazwę użytkownika (USER31) oraz wpływa na dodatkową logikę, taką jak wybór klienta.

2. Sprawdzenie głównego okna

Początkowo skrypt nie był w stanie odnaleźć głównego okna SAP GUI ponieważ sesja SAP nie była jeszcze otwarta - co jest zgodne z oczekiwanym zachowaniem. Spowodowało to uruchomienie mechanizmu awaryjnego, który inicjuje nową sesję poprzez interakcję z oknem SAP Logon.

3. Przejście do SAP Logon

Skrypt wykrył okno SAP Logon i poprawnie zlokalizował przycisk „Log On”. Wyświetlone zostały również wartości uchwytów okien (w formacie szesnastkowym), co potwierdza, że skrypt jest w stanie komunikować się z interfejsem SAP Logon w celu uruchomienia sesji.

4. Inicjalizacja sesji

Po wywołaniu akcji Log On skrypt z powodzeniem otworzył sesję SAP. Odnalazł główne okno SAP o tytule AFINE/000 SAP,  jego uchwyt oraz uchwyt kontrolki stopki. Stopka zazwyczaj zawiera pola wprowadzania m.in. dla języka, nazwy użytkownika, hasła i klienta, co oznacza, że skrypt jest gotowy do wprowadzania danych logowania.

Wnioski

Automatyzacja logowania do SAP GUI przy użyciu Windows API i Pythona stanowi efektywną alternatywę dla tradycyjnego skryptowania SAP, szczególnie w środowiskach, w których skrypty są wyłączone lub ograniczone. Takie podejście pozwala na interakcję z interfejsem SAP na poziomie systemu operacyjnego, zapewniając precyzyjną kontrolę nad fokusem okna, nawigacją i symulacją klawiszy. Dzięki funkcjom takim jak find_window_by_title, set_focus czy send_keys_via_keybd_event, skrypt może w niezawodny sposób lokalizować okna SAP, czyścić pola oraz wpisywać dane logowania bez polegania na kruchych identyfikatorach elementów UI.

Analiza przykładowego rezultatu działania skryptu pokazuje jego odporność na różne scenariusze: potrafi poradzić sobie z sytuacją, w której główne okno SAP nie jest jeszcze dostępne, przełączając się automatycznie na interfejs SAP Logon, inicjując sesję, a następnie kontynuując proces logowania. Taka odporność czyni rozwiązanie praktycznym w zastosowaniach produkcyjnych, w których środowiska SAP bywają dynamiczne lub podatne na opóźnienia.

Podsumowując, zaawansowane metody sterowania tego typu nie tylko zwiększają niezawodność automatyzacji, lecz także umożliwiają integrację SAP GUI z bardziej złożonymi procesami automatyzacji. Przy odpowiedniej obsłudze błędów i dostosowaniu czasów oczekiwania technika ta może znacząco usprawnić zadania powtarzalne, zmniejszyć nakład pracy manualnej i podnieść efektywność operacyjną w systemach korporacyjnych.

FAQ

Questions enterprise security teams ask before partnering with AFINE for security assessments.

No items found.

Miesięczny Raport Ofensywny

Dołącz do naszego newslettera! Co miesiąc ujawniamy nowe zagrożenia w oprogramowaniu biznesowym, wskazujemy kluczowe luki wymagające uwagi oraz analizujemy trendy w cyberbezpieczeństwie na podstawie naszych testów ofensywnych.

Klikając "Subskrybuj", potwierdzasz, że zgadzasz się z naszymi Zasadami i Warunkami.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Gradient glow background for call-to-action section