#NoEnv
SetWinDelay, 0
SetBatchLines, -1
global Info := {}
filePath := "D:\MyExcelFile.xlsm"
CreateGui(1000, 800, "MainGui")
GetExcel(filePath)
AttachExcel()
Return
CreateGui(width, height, label) {
Gui, New, +hwndhGui +Resize +Label%label% -DPIScale, Excel
Gui, Show, w%width% h%height%
VarSetCapacity(WINDOWINFO, 60, 0)
NumPut(60, WINDOWINFO)
DllCall("GetWindowInfo", "Ptr", hGui, "Ptr", &WINDOWINFO)
for k, v in ["left", "top", "right", "bottom"] {
Info[v] := NumGet(WINDOWINFO, 16 + A_Index*4, "UInt")
Info[v . "Offset"] := Info[v] - NumGet(WINDOWINFO, A_Index*4, "UInt")
}
Info.hGui := hGui
}
GetExcel(filePath := "") {
if filePath {
Excel := ComObjCreate("Excel.Application")
Book := Excel.Workbooks.Open(filePath)
Excel.Visible := true
WinWait, ahk_class XLMAIN
}
else if WinExist("ahk_class XLMAIN")
Excel := Excel_Get()
else {
Excel := ComObjCreate("Excel.Application")
Book := Excel.Workbooks.Add
Excel.Visible := true
WinWait, ahk_class XLMAIN
}
hExcel := Excel.hwnd
WinGet, PID, PID, ahk_id %hExcel%
for k, v in ["Excel", "hExcel", "PID"]
Info[v] := %v%
OnExit(Func("QuitExcel").Bind(Info))
}
AttachExcel() {
static GWLP_HWNDPARENT := -8, eolc := EVENT_OBJECT_LOCATIONCHANGE := 0x800B
DllCall("SetWindowLong" . (A_PtrSize = 4 ? "" : "Ptr"), "Ptr", Info.hExcel, "UInt", GWLP_HWNDPARENT, "Ptr", Info.hGui)
WinMove, % "ahk_id" Info.hExcel,, Info.left, Info.top, Info.right - Info.left, Info.bottom - Info.top
OnMessage(0x3, "WM_MOVE")
Info.Hook := new WinEventHook(eolc, eolc, "OnExcelMove",, Info.PID)
WinActivate, % "ahk_id" Info.hExcel
}
MainGuiClose() {
ExitApp
}
MainGuiSize(hGui, eventInfo, width, height) {
WinMove, % "ahk_id" Info.hExcel,,,, width, height
}
WM_MOVE(wp, lp, msg, hwnd) {
static timer := Func("ClearTimout")
if !(Info.hGui = hwnd)
Return
Info.timeout := true
x := lp & 0xFFFF, (x > 0x7FFF && x -= 0xFFFF)
y := lp >> 16 , (y > 0x7FFF && y -= 0xFFFF)
WinMove, % "ahk_id" Info.hExcel,, x, y
SetTimer, % timer, -20
}
ClearTimout() {
Info.timeout := false
}
OnExcelMove(hWinEventHook, event, hwnd, idObject) {
if (hwnd != Info.hExcel) || Info.timeout
Return
WinGetPos, X, Y, W, H, % "ahk_id" . Info.hExcel
WinMove, % "ahk_id" . Info.hGui,, X - Info.leftOffset, Y - Info.topOffset
, W + Info.leftOffset - Info.rightOffset
, H + Info.topOffset - Info.bottomOffset
}
QuitExcel() {
if WinExist("ahk_id" Info.hExcel) {
Info.Excel.Quit
WinWaitClose
Gui, % Info.hGui . ": Cancel"
Sleep, 1000
}
Process, Close, % Info.PID
Process, WaitClose, % Info.PID
}
Excel_Get(WinTitle := "ahk_class XLMAIN") {
ControlGet, hwnd, hwnd,, Excel71, %WinTitle%
if !hwnd
return
Window := AccObjectFromWindow(hwnd, -16)
Loop {
try Application := Window.Application
catch
ControlSend, Excel71, {esc}, %WinTitle%
} until !!Application
return Application
}
AccObjectFromWindow(hWnd, idObject = 0)
{
static IID_IDispatch := "{00020400-0000-0000-C000-000000000046}"
, IID_IAccessible := "{618736E0-3C3D-11CF-810C-00AA00389B71}"
, OBJID_NATIVEOM := 0xFFFFFFF0, VT_DISPATCH := 9, F_OWNVALUE := 1
, h := DllCall("LoadLibrary", Str, "oleacc", Ptr)
VarSetCapacity(IID, 16), idObject &= 0xFFFFFFFF
DllCall("ole32\CLSIDFromString", Str, idObject = OBJID_NATIVEOM ? IID_IDispatch : IID_IAccessible, Ptr, &IID)
if DllCall("oleacc\AccessibleObjectFromWindow", Ptr, hWnd, UInt, idObject, Ptr, &IID, PtrP, pAcc) = 0
Return ComObjEnwrap(VT_DISPATCH, pAcc, F_OWNVALUE)
}
class WinEventHook
{
__New(eventMin, eventMax, hookProc, eventInfo := 0, idProcess := 0, idThread := 0, dwFlags := 0) {
this.pCallback := RegisterCallback(hookProc, "F",, eventInfo)
this.hHook := DllCall("SetWinEventHook", "UInt", eventMin, "UInt", eventMax, "Ptr", 0, "Ptr", this.pCallback
, "UInt", idProcess, "UInt", idThread, "UInt", dwFlags, "Ptr")
}
__Delete() {
DllCall("UnhookWinEvent", "Ptr", this.hHook)
DllCall("GlobalFree", "Ptr", this.pCallback, "Ptr")
}
}