1

Тема: AHK: получение текста из меню

Добрый вечер.
Столкнулся с такой задачей:
В программе 1С 7.7 в журнале в зависимости от того помечен документ или свойство в карточке на удаление или нет меняется текст в меню. Т.е. там либо "Пометить на удаление", либо "снять пометку на удаление". Вопрос состоит в том как этот текст оттуда получить, для последующего использования в AHK.

2

Re: AHK: получение текста из меню

http://forum.script-coding.com/viewtopi … 749#p97749

3 (изменено: Ivan_vrn89, 2017-01-11 12:50:57)

Re: AHK: получение текста из меню

Malcev

Если вы имели ввиду вот это:


NumberOfMenuItem := ""   ; если оставить пустое значение, выдаст информацию о пунктах последнего подменю оконного меню
                         ; если присвоить номер — выдаст информацию о пунктах подменю с этим номером
                         
MIIM_FTYPE := 0x100, MIIM_STRING := 0x40, oType := {0: "MFT_STRING", 0x800: "MFT_SEPARATOR", 0x4: "MFT_BITMAP"}

F11::
   InfoString := ""
   if !hMenu := DllCall("GetMenu", Ptr, WinExist("A"), Ptr)  {
      MsgBox, Окно использует нестандартное меню
      Return
   }
   count := DllCall("GetMenuItemCount", Ptr, hMenu)
   if !hMenu := DllCall("GetSubMenu", Ptr, hMenu, Int, NumberOfMenuItem = "" ? count - 1 : NumberOfMenuItem - 1)  {
      MsgBox, Подменю не найдено
      Return
   }
   count := DllCall("GetMenuItemCount", Ptr, hMenu)
   Loop % count  {
      Gosub, IniMII
      NumPut(MIIM_FTYPE, &MENUITEMINFO + 4)
      DllCall("GetMenuItemInfo", Ptr, hMenu, UInt, A_Index - 1, UInt, true, Ptr, &MENUITEMINFO)
      type := oType[NumGet(&MENUITEMINFO + 8, "UInt")]
      InfoString .= (InfoString = "" ? "" : "`n")
      if (type != "MFT_STRING")
         InfoString .= type
      else  {
         Gosub, IniMII
         NumPut(MIIM_STRING, &MENUITEMINFO + 4)
         DllCall("GetMenuItemInfo", Ptr, hMenu, UInt, A_Index - 1, UInt, true, Ptr, &MENUITEMINFO)
         TextLength := NumGet(&MENUITEMINFO + 4*4 + A_PtrSize*6, "UInt")
         VarSetCapacity(TextBuff, TextLength * (A_IsUnicode ? 2 : 1), 0)
         NumPut(&TextBuff, &MENUITEMINFO + 4*4 + A_PtrSize*5)
         NumPut(++TextLength, &MENUITEMINFO + 4*4 + A_PtrSize*6)
         DllCall("GetMenuItemInfo", Ptr, hMenu, UInt, A_Index - 1, UInt, true, Ptr, &MENUITEMINFO)
         InfoString .= StrGet(&TextBuff)
      }
   }
   MsgBox, % InfoString
   Return
      
IniMII:
   VarSetCapacity(MENUITEMINFO, size := 4*4 + A_PtrSize*8, 0)
   NumPut(size, MENUITEMINFO)
   Return

То в этом случае у меня AHK выдает ошибку в 4й строчке и не запускает этот скрипт.

Если вообще тему, то нормально работают оба скрипта от сюда https://autohotkey.com/board/topic/1975 … text-menu/. Но они не помогли. Название и номер пункта меню они выводят, но по своему, т.е. вне зависимости от состояния документа(помечен или нет на удаление), отображает не то что в меню написано("Пометить на удаление" или "Снять пометку на удаление"), а просто "Удалить".

4

Re: AHK: получение текста из меню

Ivan_vrn89, отредактируйте последнее сообщение, расставьте ХОТЯ БЫ заглавные буквы и точки.

5 (изменено: Malcev, 2017-01-11 14:08:13)

Re: AHK: получение текста из меню

Ivan_vrn89, имел в виду именно этот скрипт, который у вас выдаёт ошибку.
Скачайте актуальную версию автохотки.
https://autohotkey.com/download/ahk-install.exe

6

Re: AHK: получение текста из меню

Malcev
Спасибо. Обновление помогло. Скрипт заработал. Но не помог. В отчёт попадают только разделители (MFT_SEPARATOR) и пустые строчки. Попробовал в блокноте - все нормально, текст из меню считывает, а в 1С не хочет.

7

Re: AHK: получение текста из меню

А если так?

NumberOfMenuItem := ""   ; если оставить пустое значение, выдаст информацию о пунктах последнего подменю оконного меню
                        ; если присвоить номер — выдаст информацию о пунктах подменю с этим номером

MIIM_FTYPE := 0x100, MIIM_STRING := 0x40, oType := {0: "MFT_STRING", 0x800: "MFT_SEPARATOR", 0x4: "MFT_BITMAP"}

F11::
   InfoString := ""
   if !hMenu := DllCall("GetMenu", Ptr, WinExist("A"), Ptr)  {
      MsgBox, Окно использует нестандартное меню
      Return
   }
   count := DllCall("GetMenuItemCount", Ptr, hMenu)
   if !hMenu := DllCall("GetSubMenu", Ptr, hMenu, Int, NumberOfMenuItem = "" ? count - 1 : NumberOfMenuItem - 1)  {
      MsgBox, Подменю не найдено
      Return
   }
   count := DllCall("GetMenuItemCount", Ptr, hMenu)
   Loop % count  {
         Gosub, IniMII
         NumPut(MIIM_STRING, &MENUITEMINFO + 4)
         DllCall("GetMenuItemInfo", Ptr, hMenu, UInt, A_Index - 1, UInt, true, Ptr, &MENUITEMINFO)
         TextLength := NumGet(&MENUITEMINFO + 4*4 + A_PtrSize*6, "UInt")
         VarSetCapacity(TextBuff, TextLength * (A_IsUnicode ? 2 : 1), 0)
         NumPut(&TextBuff, &MENUITEMINFO + 4*4 + A_PtrSize*5)
         NumPut(++TextLength, &MENUITEMINFO + 4*4 + A_PtrSize*6)
         DllCall("GetMenuItemInfo", Ptr, hMenu, UInt, A_Index - 1, UInt, true, Ptr, &MENUITEMINFO)
         InfoString .= StrGet(&TextBuff)
   }
   MsgBox, % InfoString
   Return

IniMII:
   VarSetCapacity(MENUITEMINFO, size := 4*4 + A_PtrSize*8, 0)
   NumPut(size, MENUITEMINFO)
   Return

8

Re: AHK: получение текста из меню

Malcev
Сделал как вы написали. Теперь текст в отчёт попадает, но вне зависимости от состояния документа и того, что отображается в меню в отчёт попадает строчка "&Удалить".

Post's attachments

скрин1.png 65.21 kb, file has never been downloaded. 

You don't have the permssions to download the attachments of this post.

9

Re: AHK: получение текста из меню

Malcev
И ещё второй скрин.

Post's attachments

скрин2.png 66.3 kb, file has never been downloaded. 

You don't have the permssions to download the attachments of this post.

10

Re: AHK: получение текста из меню

Не знаю как можно отловить меню, которое окно рисует само.
Можете так попробовать.
ahk_class Notepad замените на класс вашего окна.

f11::
Acc_Get("DoDefaultAction", "3.2", 0, "ahk_class Notepad")
WinWait, ahk_class #32768
msgbox % Acc_Get("Name", 1, 6, "ahk_class #32768")
return



;------------------------------------------------------------------------------
; Acc.ahk Standard Library
; by Sean
; Updated by jethrow:
; 	Modified ComObjEnwrap params from (9,pacc) --> (9,pacc,1)
; 	Changed ComObjUnwrap to ComObjValue in order to avoid AddRef (thanks fincs)
; 	Added Acc_GetRoleText & Acc_GetStateText
; 	Added additional functions - commented below
; 	Removed original Acc_Children function
;	Added Acc_Error, Acc_ChildrenByRole, & Acc_Get functions
; last updated 10/25/2012
;------------------------------------------------------------------------------

Acc_Init()
{
	Static	h
	If Not	h
		h:=DllCall("LoadLibrary","Str","oleacc","Ptr")
}
Acc_ObjectFromEvent(ByRef _idChild_, hWnd, idObject, idChild)
{
	Acc_Init()
	If	DllCall("oleacc\AccessibleObjectFromEvent", "Ptr", hWnd, "UInt", idObject, "UInt", idChild, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0
	Return	ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt")
}

Acc_ObjectFromPoint(ByRef _idChild_ = "", x = "", y = "")
{
	Acc_Init()
	If	DllCall("oleacc\AccessibleObjectFromPoint", "Int64", x==""||y==""?0*DllCall("GetCursorPos","Int64*",pt)+pt:x&0xFFFFFFFF|y<<32, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0
	Return	ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt")
}

Acc_ObjectFromWindow(hWnd, idObject = 0)
{
	Acc_Init()
	If	DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0
	Return	ComObjEnwrap(9,pacc,1)
}

Acc_WindowFromObject(pacc)
{
	If	DllCall("oleacc\WindowFromAccessibleObject", "Ptr", IsObject(pacc)?ComObjValue(pacc):pacc, "Ptr*", hWnd)=0
	Return	hWnd
}

Acc_GetRoleText(nRole)
{
	nSize := DllCall("oleacc\GetRoleText", "Uint", nRole, "Ptr", 0, "Uint", 0)
	VarSetCapacity(sRole, (A_IsUnicode?2:1)*nSize)
	DllCall("oleacc\GetRoleText", "Uint", nRole, "str", sRole, "Uint", nSize+1)
	Return	sRole
}

Acc_GetStateText(nState)
{
	nSize := DllCall("oleacc\GetStateText", "Uint", nState, "Ptr", 0, "Uint", 0)
	VarSetCapacity(sState, (A_IsUnicode?2:1)*nSize)
	DllCall("oleacc\GetStateText", "Uint", nState, "str", sState, "Uint", nSize+1)
	Return	sState
}

Acc_SetWinEventHook(eventMin, eventMax, pCallback)
{
	Return	DllCall("SetWinEventHook", "Uint", eventMin, "Uint", eventMax, "Uint", 0, "Ptr", pCallback, "Uint", 0, "Uint", 0, "Uint", 0)
}

Acc_UnhookWinEvent(hHook)
{
	Return	DllCall("UnhookWinEvent", "Ptr", hHook)
}
/*	Win Events:

	pCallback := RegisterCallback("WinEventProc")
	WinEventProc(hHook, event, hWnd, idObject, idChild, eventThread, eventTime)
	{
		Critical
		Acc := Acc_ObjectFromEvent(_idChild_, hWnd, idObject, idChild)
		; Code Here:

	}
*/

; Written by jethrow
Acc_Role(Acc, ChildId=0) {
	try return ComObjType(Acc,"Name")="IAccessible"?Acc_GetRoleText(Acc.accRole(ChildId)):"invalid object"
}
Acc_State(Acc, ChildId=0) {
	try return ComObjType(Acc,"Name")="IAccessible"?Acc_GetStateText(Acc.accState(ChildId)):"invalid object"
}
Acc_Location(Acc, ChildId=0, byref Position="") { ; adapted from Sean's code
	try Acc.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
	catch
		return
	Position := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")
	return	{x:NumGet(x,0,"int"), y:NumGet(y,0,"int"), w:NumGet(w,0,"int"), h:NumGet(h,0,"int")}
}
Acc_Parent(Acc) { 
	try parent:=Acc.accParent
	return parent?Acc_Query(parent):
}
Acc_Child(Acc, ChildId=0) {
	try child:=Acc.accChild(ChildId)
	return child?Acc_Query(child):
}
Acc_Query(Acc) { ; thanks Lexikos - www.autohotkey.com/forum/viewtopic.php?t=81731&p=509530#509530
	try return ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
Acc_Error(p="") {
	static setting:=0
	return p=""?setting:setting:=p
}
Acc_Children(Acc) {
	if ComObjType(Acc,"Name") != "IAccessible"
		ErrorLevel := "Invalid IAccessible Object"
	else {
		Acc_Init(), cChildren:=Acc.accChildCount, Children:=[]
		if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
			Loop %cChildren%
				i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i), Children.Insert(NumGet(varChildren,i-8)=9?Acc_Query(child):child), NumGet(varChildren,i-8)=9?ObjRelease(child):
			return Children.MaxIndex()?Children:
		} else
			ErrorLevel := "AccessibleChildren DllCall Failed"
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}
Acc_ChildrenByRole(Acc, Role) {
	if ComObjType(Acc,"Name")!="IAccessible"
		ErrorLevel := "Invalid IAccessible Object"
	else {
		Acc_Init(), cChildren:=Acc.accChildCount, Children:=[]
		if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
			Loop %cChildren% {
				i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i)
				if NumGet(varChildren,i-8)=9
					AccChild:=Acc_Query(child), ObjRelease(child), Acc_Role(AccChild)=Role?Children.Insert(AccChild):
				else
					Acc_Role(Acc, child)=Role?Children.Insert(child):
			}
			return Children.MaxIndex()?Children:, ErrorLevel:=0
		} else
			ErrorLevel := "AccessibleChildren DllCall Failed"
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}
Acc_Get(Cmd, ChildPath="", ChildID=0, WinTitle="", WinText="", ExcludeTitle="", ExcludeText="") {
	static properties := {Action:"DefaultAction", DoAction:"DoDefaultAction", Keyboard:"KeyboardShortcut"}
	AccObj :=   IsObject(WinTitle)? WinTitle
			:   Acc_ObjectFromWindow( WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText), 0 )
	if ComObjType(AccObj, "Name") != "IAccessible"
		ErrorLevel := "Could not access an IAccessible Object"
	else {
		StringReplace, ChildPath, ChildPath, _, %A_Space%, All
		AccError:=Acc_Error(), Acc_Error(true)
		Loop Parse, ChildPath, ., %A_Space%
			try {
				if A_LoopField is digit
					Children:=Acc_Children(AccObj), m2:=A_LoopField ; mimic "m2" output in else-statement
				else
					RegExMatch(A_LoopField, "(\D*)(\d*)", m), Children:=Acc_ChildrenByRole(AccObj, m1), m2:=(m2?m2:1)
				if Not Children.HasKey(m2)
					throw
				AccObj := Children[m2]
			} catch {
				ErrorLevel:="Cannot access ChildPath Item #" A_Index " -> " A_LoopField, Acc_Error(AccError)
				if Acc_Error()
					throw Exception("Cannot access ChildPath Item", -1, "Item #" A_Index " -> " A_LoopField)
				return
			}
		Acc_Error(AccError)
		StringReplace, Cmd, Cmd, %A_Space%, , All
		properties.HasKey(Cmd)? Cmd:=properties[Cmd]:
		try {
			if (Cmd = "Location")
				AccObj.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
			  , ret_val := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")
			else if (Cmd = "Object")
				ret_val := AccObj
			else if Cmd in Role,State
				ret_val := Acc_%Cmd%(AccObj, ChildID+0)
			else if Cmd in ChildCount,Selection,Focus
				ret_val := AccObj["acc" Cmd]
			else
				ret_val := AccObj["acc" Cmd](ChildID+0)
		} catch {
			ErrorLevel := """" Cmd """ Cmd Not Implemented"
			if Acc_Error()
				throw Exception("Cmd Not Implemented", -1, Cmd)
			return
		}
		return ret_val, ErrorLevel:=0
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}