sap_gui_scripting
True Multi-threaded SAP GUI Automation for Dart & Flutter (Windows).
A high-performance bridge between Dart and the SAP GUI Scripting API. Built on a native C++/COM core with STA (Single-Threaded Apartment) architecture, enabling parallel execution of multiple scripts across different SAP sessions — without blocking the main thread.
Why sap_gui_scripting?
Traditional SAP GUI Scripting (VBScript, PowerShell, Python) runs on a single thread via COM, meaning you can only automate one session at a time. This package breaks that limitation:
| Traditional SAP Scripting | sap_gui_scripting | |
|---|---|---|
| Parallel sessions | No (single-threaded COM) | Yes (6+ sessions in parallel) |
| Language | VBScript / PowerShell / Python | Dart & Flutter |
| Session pooling | Manual | Automatic via SapOrchestrator |
| Type safety | Late-binding, runtime errors | Static types, compile-time checks |
| Isolates | N/A | Each script runs in a Dart isolate |
| Mockable | No | Yes (ISapApi / ISapObject interfaces) |
| Use cases | Simple macros | Bulk extraction, RPA, Flutter desktop apps |
Architecture
┌─────────────────────────────────────────────────────────────┐
│ DART LAYER │
│ ┌─────────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Orchestrator │──▶│ Isolate 1│──▶│ Script A │ (Session 1) │
│ │ (Session │ ├──────────┤ ├──────────┤ │
│ │ Pool) │──▶│ Isolate 2│──▶│ Script B │ (Session 2) │
│ │ │ ├──────────┤ ├──────────┤ │
│ │ acquire() │──▶│ Isolate N│──▶│ Script N │ (Session N) │
│ │ release() │ └──────────┘ └──────────┘ │
│ └──────┬───────┘ │
│ │ FFI (dart:ffi) │
├─────────┼───────────────────────────────────────────────────┤
│ ▼ C++ / COM LAYER (v4.dll) │
│ ┌──────────────────────────────────────┐ │
│ │ static ComStaDispatcher │ │
│ │ ┌────────────────────────────────┐ │ │
│ │ │ STA Thread (single instance) │ │ │
│ │ │ g_objects map (shared) │ │ │
│ │ │ COM marshaling (CoInitialize) │ │ │
│ │ └────────────────────────────────┘ │ │
│ └──────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ SAP GUI Scripting API │
│ (SAP GUI for Windows process) │
└─────────────────────────────────────────────────────────────┘
Three-layer isolation model:
- Dart Layer —
SapOrchestratormanages a session pool and spawns isolates per script viaIsolate.spawn(). - Isolation Layer — Each script runs in its own isolate, reusing a pre-connected COM root handle.
- Native Layer — A single shared
ComStaDispatcherinv4.dllprovides one STA thread for the entire process, enabling true parallel access to SAP sessions.
Features
- True Multi-threading — Run scripts in parallel using Dart Isolates (not async/await on a single thread).
- Session Pooling —
SapOrchestratorautomatically creates and reuses SAP sessions (configurable up to 12+). - Intuitive API — Familiar
find*()pattern for SAP developers:findCTextField(),findButton(),startTransaction(), etc. - 71 Typed Components —
GuiButton,GuiTextField,GuiTableControl,GuiGridView(ALV),GuiTree,GuiToolbar,GuiMenu,GuiCalendar,GuiChart, and many more — all with compile-time type safety. - Robust Memory Management — C++ core safely manages COM lifecycle; Dart
Finalizerhandles garbage collection. - Mockable Architecture —
ISapApiandISapObjectinterfaces enable unit testing without a live SAP connection. - 360+ Unit Tests — Comprehensive test coverage for the FFI bridge and all GUI component wrappers.
Prerequisites
| Requirement | Details |
|---|---|
| Windows OS | SAP GUI Scripting is Windows-only |
| SAP GUI installed | SAP Logon application on the machine |
| Scripting enabled (server) | RZ11 → sapgui/user_scripting = TRUE |
| Scripting enabled (client) | SAP GUI Options → Accessibility & Scripting → Scripting → Enable Scripting |
| MSVC (Visual Studio) | Required to compile v4.dll |
| Dart SDK | >=3.10.3 |
Installation
1. Add the dependency
dependencies:
sap_gui_scripting: ^1.0.0
2. Compile the native DLL
Compile the C++ bridge with MSVC:
cl /LD v4.cpp /EHsc /std:c++17 ole32.lib oleaut32.lib /out:v4.dll
The source files are located in lib/cpp_implementations/.
3. Place the DLL
Ensure v4.dll is either:
- In the same directory as your Dart/Flutter executable, or
- Added to your system
PATHenvironment variable
For Flutter Windows apps, place it in build\windows\x64\runner\Release\ alongside your .exe.
Quick Start
Script (Worker)
Define your automation logic as a top-level function:
import 'package:sap_gui_scripting/sap_orchestrator/script_runner.dart';
void getCustomerName(Map<String, dynamic> msg) async {
await runScriptSafely<String>(msg, (session, args) async {
session.startTransaction('XD03');
// Find text field and set value
session.findCTextField('wnd[0]/usr/ctxtRF02D-KUNNR')?.text = args.toString();
// Press the search button
session.findButton('wnd[0]/tbar[0]/btn[0]')?.press();
// Read the customer name
String? name = session
.findTextField('wnd[0]/usr/subSUBTAB:SAPLXD04:0101/txtKNA1-NAME1')
?.text;
session.endTransaction();
return name ?? 'Not found';
});
}
Tip: Always return to the main menu with
session.endTransaction()so the session can be reused.
Orchestrator (Main)
import 'package:sap_gui_scripting/sap_gui_scripting.dart';
void main() async {
final orchestrator = SapOrchestrator();
await orchestrator.initialize(maxSessions: 6);
// Run multiple scripts in parallel
final f1 = orchestrator.runScript<String>(getCustomerName, '10025');
final f2 = orchestrator.runScript<String>(getCustomerName, '10026');
final f3 = orchestrator.runScript<String>(getCustomerName, '10027');
final results = await Future.wait([f1, f2, f3]);
print('Results: $results'); // ['ACME Corp', 'Globex Inc', 'Initech']
}
Usage Patterns
Flutter Desktop App
class SapService {
final orchestrator = SapOrchestrator();
bool _ready = false;
Future<void> init() async {
_ready = await orchestrator.initialize(maxSessions: 12);
}
Future<String> readCustomer(String number) {
return orchestrator.runScript<String>(_readCustomerScript, number);
}
}
// Must be a top-level or static method
void _readCustomerScript(Map<String, dynamic> msg) async {
await runScriptSafely<String>(msg, (session, args) async {
session.startTransaction('XD03');
session.findCTextField('wnd[0]/usr/ctxtRF02D-KUNNR')?.text = args.toString();
session.findButton('wnd[0]/tbar[0]/btn[0]')?.press();
final name = session.findTextField('wnd[0]/usr/subSUBTAB:SAPLXD04:0101/txtKNA1-NAME1')?.text;
session.endTransaction();
return name ?? 'Not found';
});
}
Bulk Data Extraction (RPA)
void main() async {
final orchestrator = SapOrchestrator();
await orchestrator.initialize(maxSessions: 6);
final customers = ['10001', '10002', '10003', ...]; // 100+ customers
// Process in batches of 6 (your pool size)
for (final batch in _chunk(customers, 6)) {
final futures = batch.map((id) =>
orchestrator.runScript<String>(extractCustomerData, id));
final results = await Future.wait(futures);
_saveToDatabase(results);
}
}
Table / Grid Extraction
void extractTableData(Map<String, dynamic> msg) async {
await runScriptSafely<List<Map<String, String>>>(msg, (session, args) async {
session.startTransaction('SE16N');
session.findCTextField('wnd[0]/usr/ctxtGD-TABLECLASS')?.text = 'KNA1';
session.findButton('wnd[0]/tbar[1]/btn[8]')?.press();
final grid = session.findGridView('wnd[0]/usr/cntlGRID1/shellcont/shell');
if (grid == null) return [];
final data = <Map<String, String>>[];
for (int row = 0; row < grid.rowCount; row++) {
data.add({
'kunnr': grid.getCellValue(row, 'KUNNR') ?? '',
'name1': grid.getCellValue(row, 'NAME1') ?? '',
'ort01': grid.getCellValue(row, 'ORT01') ?? '',
});
}
session.endTransaction();
return data;
});
}
Fire-and-Forget (No Result Needed)
void saveChanges(Map<String, dynamic> msg) async {
await runScriptSafely<void>(msg, (session, args) async {
session.findButton('wnd[0]/tbar[0]/btn[11]')?.press(); // Save
// No return value needed
});
}
API Reference
SapOrchestrator
The central session pool and script dispatcher.
| Member | Description |
|---|---|
SapOrchestrator() |
Singleton factory |
initialize({int maxSessions = 6}) |
Connect to SAP, create session pool. Returns Future<bool> |
runScript<T>(entryPoint, args) |
Spawn a script in an isolate. Returns Future<T> |
isInitialized |
Whether the pool is ready |
isInitializing |
Whether initialization is in progress |
freeSessionCount |
Number of free sessions available |
lastError |
Last error message |
maxSessions |
Configured pool size |
maxWaiting |
Max callers allowed to wait (default 20) |
runScriptSafely & useSapSession
Helper functions for writing scripts that run inside isolates.
// Always wrap your script logic:
Future<void> myScript(Map<String, dynamic> msg) async {
await runScriptSafely<T>(msg, (session, args) async {
// session = GuiSession (your SAP session)
// args = user-provided argument (dynamic)
return /* T */;
});
}
GuiSession (Core Session API)
| Method | Description |
|---|---|
startTransaction(String tcode) |
Start a transaction code |
endTransaction() |
Return to SAP main menu |
sendCommand(String cmd) |
Send an OK code |
createSession() |
Create a new SAP session |
findById(String id) |
Find any element by SAP ID |
findById<T>(String id) |
Find and type-check any element |
findButton(String id) |
Find a button |
findCTextField(String id) |
Find a CText field |
findTextField(String id) |
Find a text field |
findGridView(String id) |
Find an ALV Grid |
findTableControl(String id) |
Find a table control |
findTree(String id) |
Find a tree control |
findComboBox(String id) |
Find a combo box |
findCheckBox(String id) |
Find a checkbox |
findToolbar(String id) |
Find a toolbar |
findStatusbar(String id) |
Find a status bar |
findMenu(String id) |
Find a menu |
... |
40+ find*() methods available |
GuiComponent Type Hierarchy
GuiComponent (id, name, type, typeAsNumber, parent)
├── GuiVComponent (+ setFocus, visualize, text, tooltip, dimensions)
│ ├── GuiButton (press, emphasized)
│ ├── GuiTextField (caretPosition, displayedText, maxLength, etc.)
│ ├── GuiCTextField
│ ├── GuiPasswordField
│ ├── GuiOkCodeField
│ ├── GuiLabel
│ ├── GuiCheckBox
│ ├── GuiRadioButton
│ ├── GuiStatusPane
│ ├── GuiComboBox / GuiComboBoxControl / GuiComboBoxEntry
│ └── GuiVContainer → see below
│
├── GuiContainer (+ children, 40+ find*() methods)
│ ├── GuiApplication (connections, versions, openConnection)
│ ├── GuiConnection (sessions, closeConnection)
│ ├── GuiSession (info, activeWindow, start/endTransaction, sendCommand)
│ ├── GuiMainWindow (resizeWorkingPane, bar visibility)
│ ├── GuiFrameWindow
│ ├── GuiModalWindow
│ ├── GuiMessageWindow
│ ├── GuiBox / GuiContainerShell / GuiCustomControl
│ ├── GuiSimpleContainer / GuiScrollContainer / GuiSplitterContainer
│ ├── GuiUserArea
│ ├── GuiTab / GuiTabStrip
│ ├── GuiScrollbar / GuiToolbar / GuiTitlebar / GuiStatusbar
│ ├── GuiMenu / GuiMenubar
│ ├── GuiSessionInfo / GuiStatusBarLink
│ ├── GuiVHViewSwitch / GuiInputFieldControl
│ └── GuiVContainer → extends both GuiContainer & GuiVComponent
│ ├── GuiShell (has context menu support)
│ │ ├── GuiTree (node navigation, checkboxes)
│ │ ├── GuiGridView (ALV Grid — rows, columns, cell values)
│ │ ├── GuiCalendar
│ │ ├── GuiChart / GuiBarChart / GuiSapChart
│ │ ├── GuiNetChart
│ │ ├── GuiHTMLViewer
│ │ ├── GuiEAIViewer2D / GuiEAIViewer3D
│ │ ├── GuiPicture
│ │ ├── GuiOfficeIntegration
│ │ ├── GuiToolbarControl
│ │ ├── GuiGOSShell
│ │ └── GuiSplit (SplitterShell)
│ ├── GuiTableControl / GuiTableRow / GuiTableColumn
│ ├── GuiTextedit / GuiStage
│ ├── GuiDialogShell / GuiDockShell
│ ├── GuiGraphAdapt
│ └── GuiColorSelector
Mocking & Testing
The package exposes ISapApi and ISapObject interfaces, enabling unit tests without a live SAP connection:
import 'package:mocktail/mocktail.dart';
import 'package:sap_gui_scripting/sap_gui_scripting.dart';
class MockSapObject extends Mock implements ISapObject {}
void main() {
test('GuiButton press calls obj.press()', () {
final mock = MockSapObject();
final button = GuiButton(mock);
when(() => mock.press()).thenReturn(null);
button.press();
verify(() => mock.press()).called(1);
});
}
Troubleshooting
| Problem | Solution |
|---|---|
| DLL not found | Ensure v4.dll is in the same folder as your .exe or in PATH |
Sap_Connect returns 0 |
Check SAP GUI is running and scripting is enabled |
No SAP connections available |
Log into at least one SAP system in SAP Logon |
| Script hangs/timeout | Check maxWaiting is not exceeded; reduce concurrent scripts |
| Type mismatch errors | Verify SAP element IDs match expected component types |
| Session creation fails | Check server-side scripting is enabled (RZ11) |
| Isolate communication error | Ensure your entry point is a top-level or static function |
Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Development Setup
# Install dependencies
dart pub get
# Run tests
dart test
# Run coverage
dart run test_cov_console
Running the Example
cd example
flutter run -d windows
License
MIT — See the LICENSE file for details.
Disclaimer
This package is not affiliated, associated, authorized, or officially endorsed by SAP SE.
ESPAÑOL
sap_gui_scripting
Automatización SAP GUI Multi-hilo real para Dart & Flutter (Windows).
Un puente de alto rendimiento entre Dart y la API de SAP GUI Scripting. Construido sobre un núcleo nativo C++/COM con arquitectura STA (Single-Threaded Apartment), permitiendo la ejecución en paralelo de múltiples scripts en diferentes sesiones de SAP, sin bloquear el hilo principal.
¿Por qué sap_gui_scripting?
El scripting tradicional de SAP GUI (VBScript, PowerShell, Python) se ejecuta en un solo hilo a través de COM, lo que significa que solo puedes automatizar una sesión a la vez. Este paquete rompe esa limitación:
| SAP Scripting Tradicional | sap_gui_scripting | |
|---|---|---|
| Sesiones en paralelo | No (COM single-threaded) | Sí (6+ sesiones en paralelo) |
| Lenguaje | VBScript / PowerShell / Python | Dart & Flutter |
| Pool de sesiones | Manual | Automático con SapOrchestrator |
| Seguridad de tipos | Late-binding, errores en runtime | Tipos estáticos, verificaciones en compilación |
| Isolates | N/A | Cada script se ejecuta en un isolate Dart |
| Mockeable | No | Sí (interfaces ISapApi / ISapObject) |
| Casos de uso | Macros simples | Extracción masiva, RPA, apps Flutter de escritorio |
Arquitectura
┌─────────────────────────────────────────────────────────────┐
│ CAPA DART │
│ ┌─────────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Orchestrator │──▶│ Isolate 1│──▶│ Script A │ (Sesión 1) │
│ │ (Pool de │ ├──────────┤ ├──────────┤ │
│ │ sesiones) │──▶│ Isolate 2│──▶│ Script B │ (Sesión 2) │
│ │ │ ├──────────┤ ├──────────┤ │
│ │ acquire() │──▶│ Isolate N│──▶│ Script N │ (Sesión N) │
│ │ release() │ └──────────┘ └──────────┘ │
│ └──────┬───────┘ │
│ │ FFI (dart:ffi) │
├─────────┼───────────────────────────────────────────────────┤
│ ▼ CAPA C++ / COM (v4.dll) │
│ ┌──────────────────────────────────────┐ │
│ │ static ComStaDispatcher │ │
│ │ ┌────────────────────────────────┐ │ │
│ │ │ STA Thread (instancia única) │ │ │
│ │ │ g_objects map (compartido) │ │ │
│ │ │ COM marshaling (CoInitialize) │ │ │
│ │ └────────────────────────────────┘ │ │
│ └──────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ SAP GUI Scripting API │
│ (proceso SAP GUI for Windows) │
└─────────────────────────────────────────────────────────────┘
Modelo de tres capas de aislamiento:
- Capa Dart —
SapOrchestratorgestiona un pool de sesiones y lanza isolates por script víaIsolate.spawn(). - Capa de Aislamiento — Cada script corre en su propio isolate, reutilizando un handle COM raíz pre-conectado.
- Capa Nativa — Un único
ComStaDispatchercompartido env4.dllprovee un hilo STA para todo el proceso, permitiendo acceso paralelo real a sesiones SAP.
Características
- Multi-hilo Real — Ejecuta scripts en paralelo usando Isolates de Dart (no solo async/await en un hilo).
- Pool de Sesiones —
SapOrchestratorcrea y reutiliza sesiones SAP automáticamente (configurable hasta 12+). - API Intuitiva — Patrón familiar
find*()para desarrolladores SAP:findCTextField(),findButton(),startTransaction(), etc. - 71 Componentes Tipados —
GuiButton,GuiTextField,GuiTableControl,GuiGridView(ALV),GuiTree,GuiToolbar,GuiMenu,GuiCalendar,GuiChart, y muchos más — todos con seguridad de tipos en compilación. - Gestión de Memoria Robusta — El núcleo C++ gestiona el ciclo de vida de COM de forma segura;
Finalizerde Dart maneja la recolección de basura. - Arquitectura Mockeable — Interfaces
ISapApieISapObjectpermiten pruebas unitarias sin conexión SAP real. - 360+ Tests Unitarios — Cobertura de pruebas completa para el puente FFI y todos los wrappers de componentes.
Requisitos Previos
| Requisito | Detalles |
|---|---|
| Windows OS | SAP GUI Scripting solo está disponible en Windows |
| SAP GUI instalado | SAP Logon instalado en la máquina |
| Scripting habilitado (servidor) | RZ11 → sapgui/user_scripting = TRUE |
| Scripting habilitado (cliente) | SAP GUI → Opciones → Accesibilidad y Scripting → Scripting → Habilitar Scripting |
| MSVC (Visual Studio) | Necesario para compilar v4.dll |
| Dart SDK | >=3.10.3 |
Instalación
1. Añade la dependencia
dependencies:
sap_gui_scripting: ^1.0.0
2. Compila la DLL nativa
Compila el puente C++ con MSVC:
cl /LD v4.cpp /EHsc /std:c++17 ole32.lib oleaut32.lib /out:v4.dll
Los archivos fuente están en lib/cpp_implementations/.
3. Ubica la DLL
Asegúrate de que v4.dll esté:
- En el mismo directorio que tu ejecutable Dart/Flutter, o
- Añadida a la variable de entorno
PATHdel sistema
Para apps Flutter Windows, colócala en build\windows\x64\runner\Release\ junto a tu .exe.
Inicio Rápido
Script (Worker)
Define tu lógica de automatización como una función de nivel superior:
import 'package:sap_gui_scripting/sap_orchestrator/script_runner.dart';
void obtenerNombreCliente(Map<String, dynamic> msg) async {
await runScriptSafely<String>(msg, (session, args) async {
session.startTransaction('XD03');
// Buscar campo de texto y establecer valor
session.findCTextField('wnd[0]/usr/ctxtRF02D-KUNNR')?.text = args.toString();
// Presionar el botón de búsqueda
session.findButton('wnd[0]/tbar[0]/btn[0]')?.press();
// Leer el nombre del cliente
String? nombre = session
.findTextField('wnd[0]/usr/subSUBTAB:SAPLXD04:0101/txtKNA1-NAME1')
?.text;
session.endTransaction();
return nombre ?? 'No encontrado';
});
}
Consejo: Vuelve siempre al menú principal con
session.endTransaction()para que la sesión pueda ser reutilizada.
Orquestador (Main)
import 'package:sap_gui_scripting/sap_gui_scripting.dart';
void main() async {
final orchestrator = SapOrchestrator();
await orchestrator.initialize(maxSessions: 6);
// Ejecutar múltiples scripts en paralelo
final f1 = orchestrator.runScript<String>(obtenerNombreCliente, '10025');
final f2 = orchestrator.runScript<String>(obtenerNombreCliente, '10026');
final f3 = orchestrator.runScript<String>(obtenerNombreCliente, '10027');
final resultados = await Future.wait([f1, f2, f3]);
print('Resultados: $resultados'); // ['ACME Corp', 'Globex Inc', 'Initech']
}
Patrones de Uso
App Flutter de Escritorio
class SapService {
final orchestrator = SapOrchestrator();
bool _listo = false;
Future<void> init() async {
_listo = await orchestrator.initialize(maxSessions: 12);
}
Future<String> leerCliente(String numero) {
return orchestrator.runScript<String>(_scriptLeerCliente, numero);
}
}
// Debe ser una función top-level o static
void _scriptLeerCliente(Map<String, dynamic> msg) async {
await runScriptSafely<String>(msg, (session, args) async {
session.startTransaction('XD03');
session.findCTextField('wnd[0]/usr/ctxtRF02D-KUNNR')?.text = args.toString();
session.findButton('wnd[0]/tbar[0]/btn[0]')?.press();
final nombre = session.findTextField('wnd[0]/usr/subSUBTAB:SAPLXD04:0101/txtKNA1-NAME1')?.text;
session.endTransaction();
return nombre ?? 'No encontrado';
});
}
Extracción Masiva de Datos (RPA)
void main() async {
final orchestrator = SapOrchestrator();
await orchestrator.initialize(maxSessions: 6);
final clientes = ['10001', '10002', '10003', ...]; // 100+ clientes
// Procesar en lotes de 6 (tamaño del pool)
for (final lote in _agrupar(clientes, 6)) {
final futures = lote.map((id) =>
orchestrator.runScript<String>(extraerDatosCliente, id));
final resultados = await Future.wait(futures);
_guardarEnBaseDeDatos(resultados);
}
}
Extracción de Tablas / Grids
void extraerDatosTabla(Map<String, dynamic> msg) async {
await runScriptSafely<List<Map<String, String>>>(msg, (session, args) async {
session.startTransaction('SE16N');
session.findCTextField('wnd[0]/usr/ctxtGD-TABLECLASS')?.text = 'KNA1';
session.findButton('wnd[0]/tbar[1]/btn[8]')?.press();
final grid = session.findGridView('wnd[0]/usr/cntlGRID1/shellcont/shell');
if (grid == null) return [];
final datos = <Map<String, String>>[];
for (int row = 0; row < grid.rowCount; row++) {
datos.add({
'kunnr': grid.getCellValue(row, 'KUNNR') ?? '',
'name1': grid.getCellValue(row, 'NAME1') ?? '',
'ort01': grid.getCellValue(row, 'ORT01') ?? '',
});
}
session.endTransaction();
return datos;
});
}
Fire-and-Forget (Sin Resultado)
void guardarCambios(Map<String, dynamic> msg) async {
await runScriptSafely<void>(msg, (session, args) async {
session.findButton('wnd[0]/tbar[0]/btn[11]')?.press(); // Guardar
// No se necesita devolver un valor
});
}
Referencia de API
SapOrchestrator
El pool central de sesiones y despachador de scripts.
| Miembro | Descripción |
|---|---|
SapOrchestrator() |
Singleton |
initialize({int maxSessions = 6}) |
Conecta a SAP y crea el pool de sesiones. Retorna Future<bool> |
runScript<T>(entryPoint, args) |
Lanza un script en un isolate. Retorna Future<T> |
isInitialized |
Si el pool está listo |
isInitializing |
Si la inicialización está en progreso |
freeSessionCount |
Número de sesiones libres disponibles |
lastError |
Último mensaje de error |
maxSessions |
Tamaño configurado del pool |
maxWaiting |
Máximo de llamadas en espera (por defecto 20) |
runScriptSafely & useSapSession
Funciones auxiliares para escribir scripts que se ejecutan dentro de isolates.
// Siempre envuelve tu lógica de script:
Future<void> miScript(Map<String, dynamic> msg) async {
await runScriptSafely<T>(msg, (session, args) async {
// session = GuiSession (tu sesión SAP)
// args = argumento proporcionado por el usuario (dynamic)
return /* T */;
});
}
GuiSession (API Principal de Sesión)
| Método | Descripción |
|---|---|
startTransaction(String tcode) |
Inicia una transacción |
endTransaction() |
Vuelve al menú principal de SAP |
sendCommand(String cmd) |
Envía un comando OK |
createSession() |
Crea una nueva sesión SAP |
findById(String id) |
Busca cualquier elemento por ID SAP |
findById<T>(String id) |
Busca y verifica el tipo de cualquier elemento |
findButton(String id) |
Busca un botón |
findCTextField(String id) |
Busca un campo CText |
findTextField(String id) |
Busca un campo de texto |
findGridView(String id) |
Busca una ALV Grid |
findTableControl(String id) |
Busca un table control |
findTree(String id) |
Busca un tree control |
findComboBox(String id) |
Busca un combo box |
findCheckBox(String id) |
Busca un checkbox |
findToolbar(String id) |
Busca una barra de herramientas |
findStatusbar(String id) |
Busca una barra de estado |
findMenu(String id) |
Busca un menú |
... |
40+ métodos find*() disponibles |
Jerarquía de Tipos GuiComponent
GuiComponent (id, name, type, typeAsNumber, parent)
├── GuiVComponent (+ setFocus, visualize, text, tooltip, dimensions)
│ ├── GuiButton (press, emphasized)
│ ├── GuiTextField (caretPosition, displayedText, maxLength, etc.)
│ ├── GuiCTextField
│ ├── GuiPasswordField
│ ├── GuiOkCodeField
│ ├── GuiLabel
│ ├── GuiCheckBox
│ ├── GuiRadioButton
│ ├── GuiStatusPane
│ ├── GuiComboBox / GuiComboBoxControl / GuiComboBoxEntry
│ └── GuiVContainer → ver abajo
│
├── GuiContainer (+ children, 40+ métodos find*())
│ ├── GuiApplication (connections, versions, openConnection)
│ ├── GuiConnection (sessions, closeConnection)
│ ├── GuiSession (info, activeWindow, start/endTransaction, sendCommand)
│ ├── GuiMainWindow (resizeWorkingPane, visibilidad de barras)
│ ├── GuiFrameWindow
│ ├── GuiModalWindow
│ ├── GuiMessageWindow
│ ├── GuiBox / GuiContainerShell / GuiCustomControl
│ ├── GuiSimpleContainer / GuiScrollContainer / GuiSplitterContainer
│ ├── GuiUserArea
│ ├── GuiTab / GuiTabStrip
│ ├── GuiScrollbar / GuiToolbar / GuiTitlebar / GuiStatusbar
│ ├── GuiMenu / GuiMenubar
│ ├── GuiSessionInfo / GuiStatusBarLink
│ ├── GuiVHViewSwitch / GuiInputFieldControl
│ └── GuiVContainer → extiende ambos GuiContainer y GuiVComponent
│ ├── GuiShell (soporte de menú contextual)
│ │ ├── GuiTree (navegación de nodos, checkboxes)
│ │ ├── GuiGridView (ALV Grid — filas, columnas, valores de celda)
│ │ ├── GuiCalendar
│ │ ├── GuiChart / GuiBarChart / GuiSapChart
│ │ ├── GuiNetChart
│ │ ├── GuiHTMLViewer
│ │ ├── GuiEAIViewer2D / GuiEAIViewer3D
│ │ ├── GuiPicture
│ │ ├── GuiOfficeIntegration
│ │ ├── GuiToolbarControl
│ │ ├── GuiGOSShell
│ │ └── GuiSplit (SplitterShell)
│ ├── GuiTableControl / GuiTableRow / GuiTableColumn
│ ├── GuiTextedit / GuiStage
│ ├── GuiDialogShell / GuiDockShell
│ ├── GuiGraphAdapt
│ └── GuiColorSelector
Mocking y Testing
El paquete expone las interfaces ISapApi e ISapObject, permitiendo pruebas unitarias sin conexión SAP real:
import 'package:mocktail/mocktail.dart';
import 'package:sap_gui_scripting/sap_gui_scripting.dart';
class MockSapObject extends Mock implements ISapObject {}
void main() {
test('GuiButton.press llama a obj.press()', () {
final mock = MockSapObject();
final button = GuiButton(mock);
when(() => mock.press()).thenReturn(null);
button.press();
verify(() => mock.press()).called(1);
});
}
Solución de Problemas
| Problema | Solución |
|---|---|
| DLL no encontrada | Asegúrate de que v4.dll esté en la misma carpeta que tu .exe o en el PATH |
Sap_Connect devuelve 0 |
Verifica que SAP GUI esté en ejecución y el scripting habilitado |
No SAP connections available |
Inicia sesión en al menos un sistema SAP en SAP Logon |
| El script se bloquea | Verifica que maxWaiting no sea excedido; reduce scripts concurrentes |
| Errores de tipo (type mismatch) | Verifica que los IDs de elementos SAP coincidan con los tipos de componente esperados |
| Fallo al crear sesiones | Verifica que el scripting esté habilitado en el servidor (RZ11) |
| Error de comunicación entre isolates | Asegúrate de que el entry point sea una función top-level o static |
Contribuciones
Las pull requests son bienvenidas. Para cambios mayores, por favor abre un issue primero para discutir lo que te gustaría cambiar.
Configuración de Desarrollo
# Instalar dependencias
dart pub get
# Ejecutar tests
dart test
# Ejecutar cobertura
dart run test_cov_console
Ejecutar el Ejemplo
cd example
flutter run -d windows
Licencia
MIT — Ver el archivo LICENSE para más detalles.
Aviso Legal
Este paquete no está afiliado, asociado, autorizado ni respaldado oficialmente por SAP SE.
Libraries
- enums/enum_gui_component_type_number
- gui_classes/gui_application
- gui_classes/gui_bar_chart
- gui_classes/gui_box
- gui_classes/gui_c_text_field
- gui_classes/gui_calendar
- gui_classes/gui_chart
- gui_classes/gui_checkbox
- gui_classes/gui_collection
- gui_classes/gui_color_selector
- gui_classes/gui_combo_box
- gui_classes/gui_combo_box_control
- gui_classes/gui_combo_box_entry
- gui_classes/gui_component
- gui_classes/gui_component_collection
- gui_classes/gui_connection
- gui_classes/gui_container
- gui_classes/gui_container_shell
- gui_classes/gui_custom_control
- gui_classes/gui_dialog_shell
- gui_classes/gui_dock_shell
- gui_classes/gui_eai_viewer_2d
- gui_classes/gui_eai_viewer_3d
- gui_classes/gui_frame_window
- gui_classes/gui_gos_shell
- gui_classes/gui_graph_adapt
- gui_classes/gui_grid_view
- gui_classes/gui_html_viewer
- gui_classes/gui_input_field_control
- gui_classes/gui_label
- gui_classes/gui_main_window
- gui_classes/gui_map
- gui_classes/gui_message_window
- gui_classes/gui_modal_window
- gui_classes/gui_net_chart
- gui_classes/gui_office_integration
- gui_classes/gui_ok_code_field
- gui_classes/gui_password_field
- gui_classes/gui_picture
- gui_classes/gui_sap_chart
- gui_classes/gui_scroll_bar
- gui_classes/gui_scroll_container
- gui_classes/gui_session
- gui_classes/gui_session_info
- gui_classes/gui_shell
- gui_classes/gui_simple_container
- gui_classes/gui_split
- gui_classes/gui_splitter_container
- gui_classes/gui_stage
- gui_classes/gui_status_bar_link
- gui_classes/gui_status_pane
- gui_classes/gui_statusbar
- gui_classes/gui_tab
- gui_classes/gui_tab_strip
- gui_classes/gui_table_column
- gui_classes/gui_table_control
- gui_classes/gui_table_row
- gui_classes/gui_text_field
- gui_classes/gui_textedit
- gui_classes/gui_titlebar
- gui_classes/gui_toolbar
- gui_classes/gui_toolbar_control
- gui_classes/gui_tree
- gui_classes/gui_user_area
- gui_classes/gui_utils
- gui_classes/gui_v_component
- gui_classes/gui_v_container
- gui_classes/gui_vh_view_switch
- interfaces/i_sap_api
- interfaces/i_sap_object
- methods/dart_and_c_typedefs
- methods/load_dll_helper
- methods/sap_api
- methods/sap_object
- sap_gui_scripting
- True Multi-threaded SAP GUI Automation for Dart & Flutter (Windows only).
- sap_orchestrator/sap_orchestrator
- sap_orchestrator/script_runner
- sap_orchestrator/scripts
- sap_orchestrator/worker