; ======================================================================================================================
; 함수: ActivateAndWait(WinTitle, WinText := "", Timeout := 5, ExcludeTitle := "", ExcludeText := "")
; 설명: 특정 창을 활성화하고, 실제로 활성화될 때까지 지정된 시간(초)만큼 기다립니다.
; 파라미터:
; - WinTitle: 대상 창의 제목 (SetTitleMatchMode의 영향을 받음)
; - WinText (선택사항): 대상 창의 텍스트
; - Timeout (선택사항): 최대 대기 시간 (초). 기본값 5초.
; - ExcludeTitle (선택사항): 제외할 창의 제목
; - ExcludeText (선택사항): 제외할 창의 텍스트
; 반환값:
; - 성공 시 1, 실패(타임아웃) 시 0을 반환합니다.
; ======================================================================================================================
ActivateAndWait(WinTitle, WinText := "", Timeout := 5, ExcludeTitle := "", ExcludeText := "")
{
; 1. 창 활성화를 시도합니다.
WinActivate, %WinTitle%, %WinText%, %ExcludeTitle%, %ExcludeText%
; 2. 지정된 Timeout 시간 동안 창이 활성화될 때까지 기다립니다.
; A_TickCount는 시스템이 부팅된 후 경과된 시간을 밀리초 단위로 나타냅니다.
; 이를 사용하여 시간 제한을 설정합니다.
StartTime := A_TickCount
Loop
{
; 2-1. 현재 활성화된 창이 목표 창인지 확인합니다.
if WinActive(WinTitle, WinText, ExcludeTitle, ExcludeText)
{
; 2-2. 목표 창이 활성화되었으면 성공(1)을 반환하고 함수를 종료합니다.
return 1
}
; 2-3. Timeout을 초과했는지 확인합니다.
; (현재 시간 - 시작 시간)이 Timeout(밀리초)보다 크면 루프를 빠져나갑니다.
if (A_TickCount - StartTime > Timeout * 1000)
{
break
}
; 2-4. CPU 부담을 줄이기 위해 짧은 대기 시간을 줍니다.
Sleep, 100
}
; 3. Timeout 시간 내에 창이 활성화되지 않았으면 실패(0)를 반환합니다.
return 0
}
#NoEnv
#SingleInstance Force
SetBatchLines, -1
; 현재 마우스 위치 가져오기
CoordMode, Mouse, Screen
MouseGetPos, mx, my
; 모니터 개수 가져오기
SysGet, MonitorCount, MonitorCount
currentMonitor := 0
; 각 모니터 좌표 확인
Loop, %MonitorCount%
{
SysGet, Mon, Monitor, %A_Index%
if (mx >= MonLeft && mx <= MonRight && my >= MonTop && my <= MonBottom)
{
currentMonitor := A_Index
break
}
}
if (currentMonitor > 0)
{
ToolTip, 현재 모니터 번호: %currentMonitor%, %mx%, %my%
Sleep, 2000
ToolTip ; 툴팁 제거
}
else
{
MsgBox, 16, 에러, 현재 위치가 어떤 모니터에도 속하지 않습니다.
}#NoEnv
#SingleInstance Force
SetBatchLines, -1
SetWorkingDir, %A_ScriptDir%
CoordMode, Pixel, Screen ; 픽셀/이미지서치 좌표를 화면 기준으로
; 모니터 개수 확인
SysGet, MonitorCount, MonitorCount
if (MonitorCount < 3) {
MsgBox, 16, Error, 현재 모니터 개수: %MonitorCount%`n3번 모니터가 없습니다.
ExitApp
}
; 3번 모니터의 경계 좌표 가져오기
SysGet, Mon3, Monitor, 3
; 디버그용으로 좌표 확인
; MsgBox, 3번 모니터:`nLeft=%Mon3Left%`nTop=%Mon3Top%`nRight=%Mon3Right%`nBottom=%Mon3Bottom%
; 이미지 경로
imagePath := A_ScriptDir . "\img\test001.png"
if !FileExist(imagePath) {
MsgBox, 16, Error, 이미지 파일이 없습니다:`n%imagePath%
ExitApp
}
; 3번 모니터 영역에서 이미지 검색
; ※ AHK v1의 명령식 파라미터에서는 변수에 %를 붙여서 넘겨야 함!
ImageSearch, FoundX, FoundY, %Mon3Left%, %Mon3Top%, %Mon3Right%, %Mon3Bottom%, %imagePath%
if (ErrorLevel = 0) {
MsgBox, 64, 성공, 이미지 찾음! 좌표: %FoundX%, %FoundY%
} else if (ErrorLevel = 1) {
MsgBox, 48, 못 찾음, 3번 모니터에서 이미지를 찾지 못했습니다.
} else {
MsgBox, 16, 에러, ImageSearch 에러(좌표/경로/옵션 확인).
}#Include Gdip.ahk ; Gdip 라이브러리 필요 (같은 폴더에 두면 됨)
F1::
; 캡처할 영역 지정 (x, y, w, h)
x := 100
y := 100
w := 300
h := 200
; GDI+ 시작
if !pToken := Gdip_Startup()
{
MsgBox, GDI+ 실행 실패
ExitApp
}
; 전체화면 DC 가져오기
hdc := GetDC(0)
; 비트맵 생성
hbm := CreateDIBSection(w, h)
hdc2 := CreateCompatibleDC(hdc)
obm := SelectObject(hdc2, hbm)
; 원하는 영역 복사
BitBlt(hdc2, 0, 0, w, h, hdc, x, y, 0x00CC0020)
; GDI+ 비트맵으로 변환
pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
; 저장 (파일명, 확장자에 따라 PNG/JPG 등 가능)
Gdip_SaveBitmapToFile(pBitmap, "screenshot.png")
; 리소스 정리
SelectObject(hdc2, obm), DeleteObject(hbm), DeleteDC(hdc2), ReleaseDC(0, hdc)
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
MsgBox, 스크린샷 저장 완료!
return
; SAP 연결
sap := ComObjGet("SAPGUI").GetScriptingEngine.Children(0).Children(0)
; SAP 트랜잭션 실행
sap.findById("wnd[0]/tbar[0]/okcd").text := "SE16N"
sap.findById("wnd[0]").sendVKey(0)
; 상태바 메시지 확인 후 조건 캡쳐
if (sap.findById("wnd[0]/sbar").Text != "No entries found") {
; SAP 창 활성화
WinActivate, ahk_exe saplogon.exe
WinGet, hwnd, ID, A
; 캡쳐 저장 (GDI 방식)
FilePath := "C:\Temp\sap_" A_Now ".png"
pToken := Gdip_Startup()
pBitmap := Gdip_BitmapFromHWND(hwnd)
Gdip_SaveBitmapToFile(pBitmap, FilePath)
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
MsgBox, Saved to %FilePath%
}
#Persistent
#SingleInstance, Force
SetTitleMatchMode, 2 ; 창 이름 부분 일치 허용
; SAP 연결 (COM 객체)
sap := ComObjGet("SAPGUI").GetScriptingEngine.Children(0).Children(0)
; ==============================
; 1. 트랜잭션 실행
; ==============================
sap.findById("wnd[0]/tbar[0]/okcd").text := "SE16N"
sap.findById("wnd[0]").sendVKey(0)
; ==============================
; 2. 검색어 입력
; ==============================
sap.findById("wnd[0]/usr/ctxtGD-TAB").text := "MARA"
sap.findById("wnd[0]").sendVKey(0)
; ==============================
; 3. 조건부 캡쳐
; ==============================
status := sap.findById("wnd[0]/sbar").Text
if (status != "No entries found") {
FormatTime, now, , yyyyMMdd_HHmmss
filePath := "C:\Temp\sap_capture_" . now . ".png"
CaptureSAPWindow(filePath)
MsgBox, 64, SAP Capture, Screenshot saved:`n%filePath%
} else {
MsgBox, 48, SAP Capture, No result found. Screenshot skipped.
}
'------------------------------
' VBA / VBScript 예제 (SAP GUI Recorder)
'------------------------------
If Not IsObject(application) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(connection) Then
Set connection = application.Children(0)
End If
If Not IsObject(session) Then
Set session = connection.Children(0)
End If
' SE16N 실행
session.findById("wnd[0]/tbar[0]/okcd").text = "SE16N"
session.findById("wnd[0]").sendVKey 0
' 테이블명 입력
session.findById("wnd[0]/usr/ctxtGD-TAB").text = "MARA"
session.findById("wnd[0]").sendVKey 0
' 결과 확인 후 캡쳐 (PowerShell/Paint 사용)
If session.findById("wnd[0]/sbar").Text <> "No entries found" Then
' PowerShell로 화면 캡쳐
CreateObject("WScript.Shell").Run _
"powershell -command " & _
"""Add-Type -AssemblyName System.Windows.Forms; " & _
"$bmp = New-Object Drawing.Bitmap (800,600); " & _
"$graphics=[Drawing.Graphics]::FromImage($bmp); " & _
"$graphics.CopyFromScreen(100,100,[Drawing.Point]::Empty,(800,600)); " & _
"$bmp.Save('C:\Temp\sap_capture_vba.png')""", 0, True
End If
'
Dim tableName
tableName = WScript.Arguments(0) ' AHK에서 전달받는 인자
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
Set connection = application.Children(0)
Set session = connection.Children(0)
session.findById("wnd[0]/tbar[0]/okcd").text = "SE16N"
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]/usr/ctxtGD-TAB").text = tableName
session.findById("wnd[0]").sendVKey 0
tableName := "MARA"
Run, wscript.exe "C:\Path\recorded.vbs" "%tableName%", , , pid
'------------------------------
' 2개 이상의 인자를 AHK에서 전달받는 예시
'------------------------------
Dim tableName, filePath
tableName = WScript.Arguments(0) ' 첫 번째 인자
filePath = WScript.Arguments(1) ' 두 번째 인자
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
Set connection = application.Children(0)
Set session = connection.Children(0)
' 트랜잭션 실행
session.findById("wnd[0]/tbar[0]/okcd").text = "SE16N"
session.findById("wnd[0]").sendVKey 0
' 테이블명 입력
session.findById("wnd[0]/usr/ctxtGD-TAB").text = tableName
session.findById("wnd[0]").sendVKey 0
' 상태 확인 후 캡쳐 (예시)
If session.findById("wnd[0]/sbar").Text <> "No entries found" Then
' PowerShell 캡쳐
CreateObject("WScript.Shell").Run _
"powershell -command " & _
"""Add-Type -AssemblyName System.Windows.Forms; " & _
"$bmp = New-Object Drawing.Bitmap (800,600); " & _
"$graphics=[Drawing.Graphics]::FromImage($bmp); " & _
"$graphics.CopyFromScreen(100,100,[Drawing.Point]::Empty,(800,600)); " & _
"$bmp.Save('" & filePath & "')""", 0, True
End If
#Persistent
#SingleInstance, Force
; -----------------------
; 1. 반복할 테이블 목록
; -----------------------
tables := ["MARA", "MVKE", "VBAK"]
Loop, % tables.MaxIndex() {
tableName := tables[A_Index]
; 캡쳐 파일명 생성
FormatTime, now, , yyyyMMdd_HHmmss
filePath := "C:\Temp\sap_capture_" . tableName . "_" . now . ".png"
; VBA 호출 (2개 인자 전달)
RunWait, wscript.exe "C:\Path\recorded.vbs" "%tableName%" "%filePath%", , , pid
; Optional: 각 반복 후 1초 대기
Sleep, 1000
}
MsgBox, 64, SAP Automation, All tables processed.
#Persistent
#SingleInstance, Force
#Include Gdip.ahk ; GDI+ 라이브러리 포함 (같은 폴더에 두세요)
; 캡쳐 함수 (창 단위)
ScreenCapture(filePath) {
WinActivate, SAP Easy Access
Sleep, 500
WinGetPos, X, Y, W, H, SAP Easy Access
; 창 단위 캡쳐
pToken := Gdip_Startup()
pBitmap := Gdip_BitmapFromScreen(X "|" Y "|" W "|" H)
Gdip_SaveBitmapToFile(pBitmap, filePath, 100)
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
}
; -----------------------
; 1. 반복할 테이블 목록
; -----------------------
tables := ["MARA", "MVKE", "VBAK"]
Loop, % tables.MaxIndex() {
tableName := tables[A_Index]
; 파일명
FormatTime, now, , yyyyMMdd_HHmmss
filePath := "C:\Temp\sap_capture_" . tableName . "_" . now . ".png"
; VBA 호출 (조회만 담당)
RunWait, wscript.exe "C:\Path\recorded.vbs" "%tableName%", , , pid
; AHK에서 캡쳐 실행
ScreenCapture(filePath)
Sleep, 1000
}
MsgBox, 64, SAP Automation, All tables processed.
; 엑셀 열기
xlApp := ComObjActive("Excel.Application")
if !xlApp
xlApp := ComObjCreate("Excel.Application")
wb := xlApp.ActiveWorkbook
sheet := wb.Sheets(1)
; 실행 범위 설정
startRow := 50
endRow := 55 ; 테스트용 55까지
Loop, % (endRow - startRow + 1)
{
row := A_Index + startRow - 1
param1 := sheet.Cells(row, 1).Value
param2 := sheet.Cells(row, 2).Value
; 1. VBS 실행 (SAP 자동화)
RunWait, % "wscript.exe ""C:\Scripts\SAP_Record.vbs"" """ param1 """ """ param2 """"
; 2. VBS 끝나면 → AHK가 스크린샷 캡쳐
FormatTime, timestamp,, yyyyMMdd_HHmmss
captureFile := "C:\Screenshots\row" row "_" timestamp ".png"
; 전체 화면 캡쳐
CaptureScreen(captureFile)
; 3. (다음 루프에서 다시 VBS 호출됨)
}
MsgBox 완료! %startRow%~%endRow% 실행 끝
; =========================
; 화면 캡쳐 함수
; =========================
CaptureScreen(saveFile)
{
pToken := Gdip_Startup()
; 화면 크기 가져오기
SysGet, Mon, MonitorWorkArea
pBitmap := Gdip_BitmapFromScreen(MonLeft "|" MonTop "|" MonRight "|" MonBottom)
Gdip_SaveBitmapToFile(pBitmap, saveFile)
Gdip_DisposeImage(pBitmap)
Gdip_Shutdown(pToken)
}
;#####################################################################################
; Gdip standard library for AHK v1
; 원본 출처: tic (AHK Forum), LGPL License
; 캡쳐 기능만 필요한 최소 버전
;#####################################################################################
Gdip_Startup()
{
if !DllCall("GetModuleHandle", "str", "gdiplus.dll")
hModule := DllCall("LoadLibrary", "str", "gdiplus.dll")
VarSetCapacity(si, 16, 0)
NumPut(1, si, 0, "UInt")
DllCall("gdiplus\GdiplusStartup", "UIntP", pToken, "UIntP", &si, "UInt", 0)
return pToken
}
Gdip_Shutdown(pToken)
{
DllCall("gdiplus\GdiplusShutdown", "UInt", pToken)
}
Gdip_BitmapFromScreen(Screen)
{
StringSplit, S, Screen, |
if (S0 = 1)
{
SysGet, SM_CXSCREEN, 0
SysGet, SM_CYSCREEN, 1
x := 0, y := 0, w := SM_CXSCREEN, h := SM_CYSCREEN
}
else
x := S1, y := S2, w := S3, h := S4
hdc := DllCall("GetDC", "UInt", 0)
hcdc := DllCall("CreateCompatibleDC", "UInt", hdc)
hbm := DllCall("CreateCompatibleBitmap", "UInt", hdc, "Int", w, "Int", h)
obm := DllCall("SelectObject", "UInt", hcdc, "UInt", hbm)
DllCall("BitBlt", "UInt", hcdc, "Int", 0, "Int", 0, "Int", w, "Int", h
, "UInt", hdc, "Int", x, "Int", y, "UInt", 0x00CC0020)
DllCall("SelectObject", "UInt", hcdc, "UInt", obm)
DllCall("DeleteDC", "UInt", hcdc)
DllCall("ReleaseDC", "UInt", 0, "UInt", hdc)
DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", "UInt", hbm, "UInt", 0, "UIntP", pBitmap)
DllCall("DeleteObject", "UInt", hbm)
return pBitmap
}
Gdip_SaveBitmapToFile(pBitmap, sOutput, Quality=75)
{
CLSID := "{557CF406-1A04-11D3-9A73-0000F81EF32E}" ; PNG encoder
VarSetCapacity(pCodec, 16)
StringReplace, CLSID, CLSID, {,, All
StringReplace, CLSID, CLSID, },, All
StringSplit, c, CLSID, -
loop, 11
NumPut("0x" c%A_Index%, pCodec, (A_Index-1)*4, "UInt")
DllCall("gdiplus\GdipSaveImageToFile", "UInt", pBitmap, "WStr", sOutput, "UInt", &pCodec, "UInt", 0)
}
' SAP GUI 조작 중간에 F1 호출
Set WshShell = CreateObject("WScript.Shell")
' SAP GUI 작업 코드 ...
WshShell.SendKeys "{F1}" ' 이 시점에서 AHK가 캡쳐 실행
' SAP GUI 작업 계속 ...
#NoEnv
#SingleInstance Force
SetBatchLines, -1
; 현재 마우스 위치 가져오기
CoordMode, Mouse, Screen
MouseGetPos, mx, my
; 모니터 개수 가져오기
SysGet, MonitorCount, MonitorCount
currentMonitor := 0
; 각 모니터 좌표 확인
Loop, %MonitorCount%
{
SysGet, Mon, Monitor, %A_Index%
if (mx >= MonLeft && mx <= MonRight && my >= MonTop && my <= MonBottom)
{
currentMonitor := A_Index
break
}
}
if (currentMonitor > 0)
{
ToolTip, 현재 모니터 번호: %currentMonitor%, %mx%, %my%
Sleep, 2000
ToolTip ; 툴팁 제거
}
else
{
MsgBox, 16, 에러, 현재 위치가 어떤 모니터에도 속하지 않습니다.
}
Loop, Files, %A_ScriptDir%\img\*.png
{
imagePath := A_LoopFileFullPath
ImageSearch, FoundX, FoundY, %Mon3Left%, %Mon3Top%, %Mon3Right%, %Mon3Bottom%, %imagePath%
if (ErrorLevel = 0) {
MsgBox, 64, 성공, 발견: %imagePath%`n좌표: %FoundX%, %FoundY%
break ; 루프만 종료
}
else if (ErrorLevel = 2) {
MsgBox, 16, 에러, 이미지 파일 문제:`n%imagePath%
}
}
MsgBox, 루프가 끝났습니다. (이미지 발견 시에는 중간에 탈출)
#NoEnv
#SingleInstance Force
SetBatchLines, -1
SetWorkingDir, %A_ScriptDir%
CoordMode, Pixel, Screen
; DllCall("SetProcessDPIAware") ; DPI 스케일링 문제시 사용
; 3번 모니터 좌표 얻기
SysGet, MonitorCount, MonitorCount
if (MonitorCount < 3) {
MsgBox, 16, Error, 현재 모니터 개수: %MonitorCount%`n3번 모니터가 없습니다.
ExitApp
}
SysGet, Mon3, Monitor, 3
; img 폴더의 모든 PNG 파일 가져오기
imageList := [] ; 배열 생성
Loop, Files, %A_ScriptDir%\img\*.png
{
imageList.Push(A_LoopFileFullPath)
}
; 이미지 검색 루프
found := false
for index, imagePath in imageList
{
ImageSearch, FoundX, FoundY, %Mon3Left%, %Mon3Top%, %Mon3Right%, %Mon3Bottom%, %imagePath%
if (ErrorLevel = 0) {
MsgBox, 64, 성공, % "발견: " . imagePath . "`n좌표: " . FoundX . "," . FoundY
found := true
break ; 발견 시 즉시 종료
}
; ErrorLevel = 1 → 못찾음 → 그냥 다음 루프로 넘어감
; ErrorLevel = 2 → 이미지 파일 문제 → 로그 남기고 넘어감
else if (ErrorLevel = 2) {
MsgBox, 16, 에러, 이미지 파일 문제:`n%imagePath%
}
}
if (!found) {
MsgBox, 48, 결과, 어떤 이미지도 3번 모니터에서 발견되지 않았습니다.
}