Sign In

Autohotkey

윈도우 활성화 확인 함수
; ====================================================================================================================== ; 함수: 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
VBA 레코딩 > Autohotkey 변환 예제 (화면캡쳐) 1
; 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% }
VBA 레코딩 > Autohotkey 변환 예제 (화면캡쳐) 2
#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 Only 화면캡쳐
'------------------------------ ' 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
Autohotkey 에서 파라미터 넘기기 > VBA 스크립트
recorded.vbs
' 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
Autohotkey
tableName := "MARA" Run, wscript.exe "C:\Path\recorded.vbs" "%tableName%", , , pid
응용 코드 반복문 + 2개 이상의 파라미터 Autohotkey > VBA 파라미터로 호출
1️⃣ VBA 스크립트 (recorded.vbs)
'------------------------------ ' 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
2️⃣ AutoHotkey v1 코드 (반복 + 다중 파라미터)
#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.
AutoHotkey v1 예시 (엑셀 읽기 + 반복 + 다중 파라미터 + 캡쳐)
; 엑셀 열기 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.ahk 저장
;##################################################################################### ; 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) }
🔹 VBS 중간에 F1 이벤트 넣기
' 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 탈출
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, 루프가 끝났습니다. (이미지 발견 시에는 중간에 탈출)
For문 없음
#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번 모니터에서 발견되지 않았습니다. }