1

Тема: AHK: Как соединить простое GUI и окно программы Excel

Доброе утро. Приветствую всех форумчан.

Как соединить простое GUI и окно программы Excel ?
Я имею ввиду - не открыть эксель внутри GUI, а на созданное окно GUI наложить окно Эксель которое немного меньше по размеру и как бы
вписывается внутрь GUI.
И если сворачивается GUI, то и эксель тоже свернется.
Если закрывается GUI, то и эксель закрывается.

2 (изменено: svoboden, 2020-08-07 19:12:27)

Re: AHK: Как соединить простое GUI и окно программы Excel

Werwolf, На AHK вроде такое не сделать. Но может кто знает и на ahk способ.

3

Re: AHK: Как соединить простое GUI и окно программы Excel

Сделать-то можно, только зачем?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

4 (изменено: svoboden, 2020-08-07 21:28:12)

Re: AHK: Как соединить простое GUI и окно программы Excel

Такие встраиваемые меню обычно в играх делаются, только зачем для этого ahk.

5

Re: AHK: Как соединить простое GUI и окно программы Excel

svoboden пишет:

Такие встраиваемые меню

Нужно сделать не эксель встроенный в GUI, а пустое окно GUI.
И наложить на него окно программы Эксель.


Для чего это нужно ?
Там в экселе отсутствует привычная панель (где обычно titl располагается). А так - удобнее перетаскивать и вообще привычнее.

6

Re: AHK: Как соединить простое GUI и окно программы Excel

Привязка окон - попробуй копнуть здесь.

7

Re: AHK: Как соединить простое GUI и окно программы Excel

ypppu,
Ясно.
А как в этом коде - вот эту строку :

Gui, Work: Add, ActiveX, x0 y0 w280 h150 vWMP, WMPlayer.OCX.7

заменить на excel ?
Excel - это же вроде не  ActiveX, а программа.

8

Re: AHK: Как соединить простое GUI и окно программы Excel

Я другое имел в виду. Создаёте своё окно GUI с заголовком, за который будете перетаскивать. Поверх него помещаете окно Эксель. Далее каким-то образом отслеживаете позицию окна GUI (например с помощью таймера) и, если позиция изменилась, изменяете позицию окна Excel.

9 (изменено: teadrinker, 2020-08-08 23:13:25)

Re: AHK: Как соединить простое GUI и окно программы Excel

Попробуйте такой код:

#NoEnv
SetWinDelay, 0
SetBatchLines, -1

global Info := {}

CreateGui(1000, 800, "MainGui")
GetExcel()
AttachExcel()
Return

CreateGui(width, height, label) {
   Gui, New, +hwndhGui +Resize +Label%label%, 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() {
   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")
   }
}

Написано на скорую руку, не уверен, что каких-нибудь косяков не вылезет.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

10

Re: AHK: Как соединить простое GUI и окно программы Excel

teadrinker, спасибо.
Как раз то, что нужно.

Единственное что непонятно, как в код - вписать название файла xls, который должен там сразу открыться ?

11 (изменено: teadrinker, 2020-08-09 11:59:11)

Re: AHK: Как соединить простое GUI и окно программы Excel

#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")
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

12

Re: AHK: Как соединить простое GUI и окно программы Excel

Спасибо.
А можно сделать, чтобы это объединение из двух окон - отображалось поверх других окон ?
(Сейчас ведь неясно как это сделать - потому что это два окна, а не одно)

13

Re: AHK: Как соединить простое GUI и окно программы Excel

Окно экселя всегда над нашими окном, так что остаётся разобраться с последним.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

14

Re: AHK: Как соединить простое GUI и окно программы Excel

teadrinker пишет:

Окно экселя всегда над нашими окном, так что остаётся разобраться с последним.

Так в том-то и дело, что не получается.

под строчкой

CreateGui(1000, 800, "MainGui")

пишу

WinSet, AlwaysOnTop, on, MainGui

или под строчкой

Gui, New, +hwndhGui +Resize +Label%label%, Excel

пишу

WinSet, AlwaysOnTop, on, Excel

Ни в том ни в другом случае - "поверх всех окон" не срабатывает.

15

Re: AHK: Как соединить простое GUI и окно программы Excel

Добавьте в AttachExcel():

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)
   Gui, % Info.hGui . ": +AlwaysOnTop"
   WinActivate, % "ahk_id" Info.hExcel
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

16

Re: AHK: Как соединить простое GUI и окно программы Excel

teadrinker, спасибо.

17

Re: AHK: Как соединить простое GUI и окно программы Excel

teadrinker, посоветуйте как сделать, чтобы при закрытии GUI (кнопка с крестиком) - оба окна закрывались ?

Сейчас - на окне GUI - кнопка закрытия окна - почему-то не работает.
А если жать на кнопку закрытия встроенного экселевского окна -  то оно закрывается, а GUI - продолжает оставаться открытым.

18 (изменено: teadrinker, 2020-08-12 21:52:10)

Re: AHK: Как соединить простое GUI и окно программы Excel

Замените QuitExcel() на такое:

QuitExcel() {
   if WinExist("ahk_id" Info.hExcel) {
      try Info.Excel.Quit
      catch {
         Process, Close, % Info.PID
         Process, WaitClose, % Info.PID
      }
      WinWaitClose
      Gui, % Info.hGui . ": Cancel"
   }
   Process, Close, % Info.PID
   Process, WaitClose, % Info.PID
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

19

Re: AHK: Как соединить простое GUI и окно программы Excel

Заменил.
Но пока что-то не работает.
Нажимаю на крест закрытия GUI - и начинает мигать кнопка закрытия экселя.
Кнопка мигает, но эксель не закрывается.
То есть не предлагает сохранится перед закрытием, например (если документ не сохранен).

Щелкаю правой клавишей мыши на ярлык программы в панели задач - жму "закрыть".
Тоже ничего не происходит - только мигание экселевской кнопки закрытия.

20

Re: AHK: Как соединить простое GUI и окно программы Excel

Попробуйте пока закомментировать

Gui, % Info.hGui . ": +AlwaysOnTop"

Возможно, появляется окно с предложением сохранить документ, но GUI его перекрывает.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

21

Re: AHK: Как соединить простое GUI и окно программы Excel

Закомментировал.
Все то же самое - мигающая кнопка закрытия Экселя.

22

Re: AHK: Как соединить простое GUI и окно программы Excel

Ну не знаю тогда, у меня такого не происходит. Можно сразу убивать Эксель, без предложения сохранить:

QuitExcel() {
   if WinExist("ahk_id" Info.hExcel) {
      Process, Close, % Info.PID
      Process, WaitClose, % Info.PID
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

23

Re: AHK: Как соединить простое GUI и окно программы Excel

Спасибо - теперь все нормально закрывается.