无SAP GUI DLL时,C#实现SAP GUI自动化的替代方案
在无SAP GUI DLL引用的情况下用C#实现SAP GUI自动化
我已经用Python和Visual Basic成功实现了SAP GUI自动化,但在C#中一直找不到可行方案。我知道C#的实现逻辑应该和VB类似,但开发机上没有SAP GUI DLL,无法直接添加引用。
以下是可正常运行的代码:
Python实现
#-Begin----------------------------------------------------------------- #-Includes-------------------------------------------------------------- import sys, win32com.client #-Sub Main-------------------------------------------------------------- def Main(): SapGuiAuto = win32com.client.GetObject("SAPGUI") if not type(SapGuiAuto) == win32com.client.CDispatch: return application = SapGuiAuto.GetScriptingEngine if not type(application) == win32com.client.CDispatch: SapGuiAuto = None return connection = application.Children(0) if not type(connection) == win32com.client.CDispatch: application = None SapGuiAuto = None return session = connection.Children(1) if not type(session) == win32com.client.CDispatch: connection = None application = None SapGuiAuto = None return #session.findById("wnd[0]").resizeWorkingPane 173, 36, 0 session.findById("wnd[0]").resizeWorkingPane(173, 36, 0)
Visual Basic实现
方式一:连接已有SAP会话
Sub Main Set SapGuiAuto = GetObject("SAPGUI") Set Application = SapGuiAuto.GetScriptingEngine Set Connection = Application.openConnection("EQ2") Set Session = Connection.Children(0) Session.ActiveWindow.Iconify() Session.findById("wnd[0]/usr/txtRSYST-MANDT").Text = "410" Session.findById("wnd[0]/usr/txtRSYST-BNAME").Text = "XYZ" Session.findById("wnd[0]/usr/pwdRSYST-BCODE").Text = "Pwd1" Session.findById("wnd[0]/usr/txtRSYST-LANGU").Text = "EN" Session.findById("wnd[0]").SendVKey 0 End Sub
方式二:启动SAP并建立连接
Sub SAP_OpenSessionFromLogon() Dim SapGui Dim Applic Dim connection Dim session Shell ("C:\Program Files (x86)\SAP\FrontEnd\SAPgui\sapfewcp.exe") Set SapGui = GetObject("SAPGUI") Set Applic = SapGui.GetScriptingEngine Set connection = Applic.OpenConnection("QLA - ECC Project One Quality System", True) '<=== 这里需要填写你的连接描述 End Sub
请问:如何在不添加SAP GUI COM DLL引用的情况下,用C#实现上述相同功能?甚至是否可以直接打开相关exe、将窗口置于前台并进行GUI自动化?
解决方案
一、使用COM Late Binding(无需添加DLL引用)
C#中可以通过dynamic类型实现COM对象的延迟绑定,和VB的GetObject逻辑一致,无需提前引用SAP的DLL。
1. 连接已有SAP会话的代码
using System; using System.Runtime.InteropServices; class SapGuiAutomation { static void Main() { try { // 获取已运行的SAPGUI对象 dynamic sapGuiAuto = Marshal.GetActiveObject("SAPGUI"); if (sapGuiAuto == null) return; // 获取脚本引擎 dynamic application = sapGuiAuto.GetScriptingEngine(); if (application == null) { Marshal.ReleaseComObject(sapGuiAuto); return; } // 获取第一个连接(可根据实际情况调整索引) dynamic connection = application.Children(0); if (connection == null) { Marshal.ReleaseComObject(application); Marshal.ReleaseComObject(sapGuiAuto); return; } // 获取会话(索引根据实际情况调整) dynamic session = connection.Children(1); if (session == null) { Marshal.ReleaseComObject(connection); Marshal.ReleaseComObject(application); Marshal.ReleaseComObject(sapGuiAuto); return; } // 执行自动化操作,例如调整工作区大小 session.findById("wnd[0]").resizeWorkingPane(173, 36, 0); // 释放COM对象(避免内存泄漏) Marshal.ReleaseComObject(session); Marshal.ReleaseComObject(connection); Marshal.ReleaseComObject(application); Marshal.ReleaseComObject(sapGuiAuto); } catch (Exception ex) { Console.WriteLine($"操作失败:{ex.Message}"); } } }
2. 启动SAP并建立新连接的代码
using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; class SapGuiAutomation { static void Main() { try { // 启动SAP GUI客户端 Process.Start(@"C:\Program Files (x86)\SAP\FrontEnd\SAPgui\sapfewcp.exe"); // 等待SAP启动完成(时间根据实际情况调整) Thread.Sleep(5000); // 获取SAPGUI对象 dynamic sapGuiAuto = Marshal.GetActiveObject("SAPGUI"); if (sapGuiAuto == null) return; dynamic application = sapGuiAuto.GetScriptingEngine(); if (application == null) { Marshal.ReleaseComObject(sapGuiAuto); return; } // 打开指定连接(第二个参数True表示显示登录窗口) dynamic connection = application.OpenConnection("QLA - ECC Project One Quality System", true); if (connection == null) { Marshal.ReleaseComObject(application); Marshal.ReleaseComObject(sapGuiAuto); return; } // 获取会话并执行登录操作 dynamic session = connection.Children(0); if (session != null) { session.findById("wnd[0]/usr/txtRSYST-MANDT").Text = "410"; session.findById("wnd[0]/usr/txtRSYST-BNAME").Text = "XYZ"; session.findById("wnd[0]/usr/pwdRSYST-BCODE").Text = "Pwd1"; session.findById("wnd[0]/usr/txtRSYST-LANGU").Text = "EN"; session.findById("wnd[0]").SendVKey(0); // 发送回车登录 Marshal.ReleaseComObject(session); } // 释放COM对象 Marshal.ReleaseComObject(connection); Marshal.ReleaseComObject(application); Marshal.ReleaseComObject(sapGuiAuto); } catch (Exception ex) { Console.WriteLine($"操作失败:{ex.Message}"); } } }
二、直接操作窗口的GUI自动化方案
如果不想依赖SAP的COM接口,也可以用Windows API或自动化库实现窗口激活、模拟键鼠操作,但这种方式稳定性较差,容易受窗口布局变化影响:
1. 激活SAP窗口的示例(用Windows API)
using System; using System.Diagnostics; using System.Runtime.InteropServices; class WindowAutomation { [DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); private const int SW_RESTORE = 9; static void Main() { // 查找SAP窗口进程 Process[] sapProcesses = Process.GetProcessesByName("saplogon"); if (sapProcesses.Length > 0) { IntPtr hWnd = sapProcesses[0].MainWindowHandle; // 如果窗口最小化,先还原 ShowWindow(hWnd, SW_RESTORE); // 激活窗口 SetForegroundWindow(hWnd); } } }
注意事项
- 使用COM延迟绑定时,要确保SAP GUI的脚本功能已开启(在SAP GUI选项中启用脚本支持)。
Marshal.ReleaseComObject要正确调用,避免COM对象内存泄漏。- 直接模拟键鼠的方式仅适用于简单场景,复杂操作建议优先使用SAP的COM脚本接口。
内容的提问来源于stack exchange,提问作者10101
相关产品推荐
相关产品推荐

