Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

COM Object Reference [AutoHotkey v1.1+]


  • Please log in to reply
233 replies to this topic
jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009

Will it be OK? BTW, my preference is Acc_ObjectFromWindow.

Sure. Are there any plans to officially release ComUtils.zip soon?

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007

Sure. Are there any plans to officially release ComUtils.zip soon?

It does not depend on me, but on Lexikos. He so easily broke the exsisting functions but took indefinitely to restore them, and I'm tired of that. Currently I don't have any intention to maintain scripts for AHK_L, but, I won't mind that you alter and distribute the scripts for AHK_L.

BTW, here is the code for MODI/OCR (:not tested) to be used with AHK_L. There was a question about it, but, I didn't post the code since there was no Atl.ahk to be used with AHK_L. It requires Microsoft Office 2003/2007, and I suppose it'll work only with 32bit AHK_L.
sImage := "path_to_real_image" ; Replace it!

Gui, +Resize +LastFound
Gui, Show, w1024 h768 Center, OCR
odi := ComObjCreate("MODI.Document")
odi.Create(sImage)
ovw := Atl_AxCreateControl(WinExist(),"MiDocViewer.MiDocView")
ovw.Document := odi
; odi.OCR
; sText := odi.Images(0).Layout.Text
; odi.Close
; MsgBox % sText
Return

GuiClose:
ExitApp


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

He so easily broke the exsisting functions but took indefinitely to restore them, and I'm tired of that.

What are you referring to, specifically?

Learning one
  • Members
  • 1483 posts
  • Last active: Jan 02 2016 02:30 PM
  • Joined: 04 Apr 2009
this example script shows how to work with
safe arrays and range object in MS Excel.
Thanks: jethrow
Hotkeys: F1 - set values to Range("A1:B3") via SafeArray, F2 - get values from Range("A1:B3") via SafeArray
#IfWinActive, ahk_class XLMAIN
;===================================================================================
F1::	; set values to Range("A1:B3") via SafeArray
SafeArray := ComObjArray(12, 3, 2)	; create a safe array. "12" means VT_VARIANT, "3" means 3 rows (1. dimension), "2" means 2 columns (2. dimension)

; Note: when building a SafeArray to assign to an Excel Range Value, it will be 0-based
Loop, 3	; 3 rows
{
    RowNum := A_Index-1
    Loop, 2	;  2 columns
	{
        ColNum := A_Index-1
        SafeArray[RowNum, ColNum] := "Row" RowNum +1  " Col" ColNum + 1
    }
}

oExcel := ComObjActive("Excel.Application")
oExcel.Range("A1:B3").value := SafeArray 	; set safe array to range object
return


;===================================================================================
F2::	; get values from Range("A1:B3") via SafeArray
oExcel := ComObjActive("Excel.Application")

SafeArray := oExcel.Range("A1:B3").value	; get safe array

;MsgBox % SafeArray.MaxIndex(1)   ; get total rows (1. dimension)
;MsgBox % SafeArray.MaxIndex(2)   ; get total columns (2. dimension)

; Note: when extracting the SafeArray, it will be 1-based
Loop % SafeArray.MaxIndex(1) ; loop through every row
{
	CurRowNum := A_Index
	Loop % SafeArray.MaxIndex(2)  ; loop through every column
	MsgBox,,, % SafeArray[CurRowNum, A_Index], 1    ; get cell's value
}
return
#IfWinActive

EDIT: or in functions - better
DemoString =
(
Jack%A_Tab%Gates%A_Tab%Driver%A_Tab%
Mark%A_Tab%Weber%A_Tab%Student%A_Tab%His father is a driver.
Jim%A_Tab%Tucker%A_Tab%Driver%A_Tab%
Jill%A_Tab%Lochte%A_Tab%Artist%A_Tab%Jack's sister.
)


#IfWinActive, ahk_class XLMAIN
F1::	; set 2 dimensional object to Range("A1:D4") via SafeArray
oExcel := ComObjActive("Excel.Application")
SafeArray(oExcel.Range("A1:D4"), String2Table(DemoString))
return

F2::	; get 2 dimensional object from Selection or any other range object via SafeArray, and convert it to string
oExcel := ComObjActive("Excel.Application")
MsgBox % Table2String(SafeArray(oExcel.Selection))
return
#IfWinActive





;===Functions===========================================================================
SafeArray(oRange, oTable="") {	; Sets or gets SafeArray. By Learning one.
	/*
	Parameters:
		oRange		MS Excel range object
		oTable		2 dimensional array object
	
	Operation:
		if oTable is empty		function gets SafeArray from specified oRange and returns it as oTable
		else					function converts oTable to SafeArray, and sets it to specified oRange
	*/
	
	if (oTable = "")	; get SafeArray
	{
		oTable := Object()
		SafeArray := oRange.value
		if  (SafeArray.MaxIndex(1) = "")	; just one cell range
		return SafeArray	; return as var not object
		
		Loop % SafeArray.MaxIndex(1) ; loop through every row
		{
			RowNum := A_Index
			%RowNum% := Object()
			Loop % SafeArray.MaxIndex(2)  ; loop through every column
			%RowNum%.Insert(SafeArray[RowNum, A_Index])
			oTable.Insert(%RowNum%)
		}
		return oTable
	}
	else	; set SafeArray
	{
		if !IsObject(oTable)
		{
			oRange.value := oTable
			return
		}
		For k,v in oTable
		{
			Dimension1 ++	; rows
			CurMaxCol := oTable[k].MaxIndex()
			if (CurMaxCol > Dimension2)
			Dimension2 := CurMaxCol
		}
		SafeArray := ComObjArray(12, Dimension1, Dimension2)
		Loop, % Dimension1	; rows
		{
			RowNum := A_Index-1
			Loop, % Dimension2	;  columns
			{
				ColNum := A_Index-1
				SafeArray[RowNum, ColNum] := oTable[RowNum+1][ColNum+1]
			}
		}
		oRange.value := SafeArray 
	}
}

String2Table(String, ColumnsDelimiter="`t", RowsDelimiter= "`n") {		; converts string to table object (2 dimensional). By Learning one.
	oTable := Object()
	Loop, parse, String, %RowsDelimiter%
	{
		CurRow := A_LoopField, RowNum := A_index
		%RowNum% := Object()
		Loop, parse, CurRow, %ColumnsDelimiter%
		%RowNum%.Insert(A_LoopField)
		oTable.Insert(%RowNum%)
	}
	return oTable
}

Table2String(oTable, ColumnsDelimiter="`t", RowsDelimiter= "`n") {		; converts table object (2 dimensional) to string. By Learning one.
	if !IsObject(oTable)	; var passed as obj
	return oTable
	For k,v in oTable
	{
		For k2,v2 in oTable[k]
		RowString .= v2 ColumnsDelimiter
		RowString := RTrim(RowString, ColumnsDelimiter)
		TableString .= RowString RowsDelimiter
		RowString =
	}
	return RTrim(TableString, RowsDelimiter)
}


sinkfaze
  • Moderators
  • 6367 posts
  • Last active:
  • Joined: 18 Mar 2008
Okay jethrow (or anyone else who's willing), I already know how to open a Windows Explorer window to a folder, but how would I pass a search string to that window using COM?

jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009

COM Object: Shell.Application [Folder Object]

Purpose: Access/Manipulate Folders

System Requirements: General

Documentation Link: Shell Object, Folder Object

Code Example: Rename Folders/Files without using FileCopy(Dir)

;// Create an example directory
dir := A_Desktop "\Example_Dir"
FileCreateDir, %dir%\Temp
Loop 9
   FileAppend, , %dir%\_%A_Index%.txt
Run %dir%
MsgBox, 262144, , Press OK to add Prefix to files...

;// Loop through the folder items. Add a Prefix to the files.
objFolder := ComObjCreate("Shell.Application").NameSpace(dir)
for item in objFolder.items
   if Not item.isFolder
      item.name := "File" item.name

;// Delete example directory
MsgBox Deleting Directory...
FileRemoveDir, %dir%, 1


tank
  • Administrators
  • 4345 posts
  • AutoHotkey Foundation
  • Last active: Oct 13 2016 01:04 AM
  • Joined: 21 Dec 2007

COM Object: Shell.Explorer [Embedded Browser]
Purpose: Embed a Trident Browser (IE) in a Gui
System Requirements: General
Documentation Link: Shell.Explorer, iWebBrowser2
Basic Code Example: Embed a browser navigate to a web site and wait for it to loadEvery one asks why ctrl+key comboes and enter do not work in theier implementation of this. Please see how this is solved in this example

/*
 written by tank updated by Jethrow
 
 AHK_L version 1.0.90.00 ansii 32 bit or higher
  
 Date : 10/18/2011
 */
 main:
{
   Gosub,init

   url:="http://www.google.com"
   WB.Navigate(url)
   loop
      If !WB.busy
         break

   return
}

init:
{
   ;// housekeeping routines
   ;// set the tear down procedure
   OnExit,terminate
   
   ;// Create a gui
   Gui, +LastFound +Resize +OwnDialogs
   
   ;// create an instance of Internet Explorer_Server
   ;// store the iwebbrowser2 interface pointer as *WB* & the hwnd as *ATLWinHWND*
   Gui, Add, ActiveX, w510 h600 x0 y0 vWB hwndATLWinHWND, Shell.Explorer
   
   ;// disable annoying script errors from the page
   WB.silent := true
   
   ;// necesary to accept enter and accelorator keys
   ;http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.ole.interop.ioleinplaceactiveobject(VS.80).aspx
   IOleInPlaceActiveObject_Interface:="{00000117-0000-0000-C000-000000000046}"
   
   ;// necesary to accept enter and accelorator keys
   ;// get the in place interface pointer
   pipa := ComObjQuery(WB, IOleInPlaceActiveObject_Interface)
   
   ;// necesary to accept enter and accelorator keys
   ;// capture key messages
   OnMessage(WM_KEYDOWN:=0x0100, "WM_KEYDOWN")
   OnMessage(WM_KEYUP:=0x0101, "WM_KEYDOWN")
   
   ;//Display the GUI
   gui,show, w510 h600 ,Gui Browser
   
   ;// return and allow the program
   return
}

;// capture the gui resize event
GuiSize:
{
   ;// if there is a resize event lets resize the browser
   WinMove, % "ahk_id " . ATLWinHWND, , 0,0, A_GuiWidth, A_GuiHeight
   return
}

GuiClose:
terminate:
{
   ;// housekeeping
   ;// destroy the gui
   Gui, Destroy
   ;// release the in place interface pointer
   ObjRelease(pipa)
   ExitApp
}



WM_KEYDOWN(wParam, lParam, nMsg, hWnd)
{
   global pipa
   static keys:={9:"tab", 13:"enter", 46:"delete", 38:"up", 40:"down"}
   if keys.HasKey(wParam)
   {
      WinGetClass, ClassName, ahk_id %hWnd%
      if  (ClassName = "Internet Explorer_Server")
      {
      ;// Build MSG Structure
         VarSetCapacity(Msg, 48)
         for i,val in [hWnd, nMsg, wParam, lParam, A_EventInfo, A_GuiX, A_GuiY]
            NumPut(val, Msg, (i-1)*A_PtrSize)
      ;// Call Translate Accelerator Method
         TranslateAccelerator := NumGet(NumGet(1*pipa)+5*A_PtrSize)
         DllCall(TranslateAccelerator, "Ptr",pipa, "Ptr",&Msg)
         return, 0
      }
   }
}

EDIT - from jethrow - here is another version of the WM_KEYDOWN function, which I modeled after code written by Lexikos:

WM_KEYDOWN(wParam, lParam, nMsg, hWnd)
{
   global wb
   static fields := "hWnd,nMsg,wParam,lParam,A_EventInfo,A_GuiX,A_GuiY"
   WinGetClass, ClassName, ahk_id %hWnd%
   if  (ClassName = "Internet Explorer_Server")
   {
   ;// Get the in place interface pointer
      pipa := ComObjQuery(wb.document, "{00000117-0000-0000-C000-000000000046}")
   ;// Build MSG Structure
      VarSetCapacity(Msg, 48)
      Loop Parse, fields, `,             ;`
         NumPut(%A_LoopField%, Msg, (A_Index-1)*A_PtrSize)
   ;// Call Translate Accelerator Method
      TranslateAccelerator := NumGet(NumGet(1*pipa)+5*A_PtrSize)
      Loop 2 ;// only necessary for Shell.Explorer Object
         r := DllCall(TranslateAccelerator, "Ptr",pipa, "Ptr",&Msg)
      until wParam != 9 || wb.document.activeElement != ""
   ;// Release the in place interface pointer
      ObjRelease(pipa)
		
      if r = 0 ;// S_OK: the message was translated to an accelerator.
         return 0
   }
}

Never lose.
WIN or LEARN.

shajul
  • Members
  • 571 posts
  • Last active: Aug 01 2015 03:45 PM
  • Joined: 15 Sep 2006

COM Object: Shell.Explorer [Embedded Browser


Fabulous. Hats off to you (and Sean).
If i've seen further it is by standing on the shoulders of giants

my site | ~shajul | WYSIWYG BBCode Editor

jballi
  • Members
  • 1029 posts
  • Last active:
  • Joined: 01 Oct 2005

[*:2kl8akrm]COM Object: Shell.Explorer [Embedded Browser]
...[*:2kl8akrm]Documentation Link: Shell.Explorer, iWebBrowser2

I'm fairly certain that the documentation link for the Shell.Explorer is not the one you intended to use. This one points to a the Shell.Explore Method -- something that opens a specified folder in a Windows Explorer window. I would like to be helpful and provide the correctly link but I have no idea which link you were thinking of. Sorry...

tank
  • Administrators
  • 4345 posts
  • AutoHotkey Foundation
  • Last active: Oct 13 2016 01:04 AM
  • Joined: 21 Dec 2007

I'm fairly certain

Ha ha you are correct thanks i didnt pay any attention
I have updated the link Thanks for pointing out the error

@shajul YW i actually got tired of the requests for this showing up in the forum. I just hope the code doesnt get broken by future updates
Never lose.
WIN or LEARN.

ruespe
  • Members
  • 567 posts
  • Last active: Dec 01 2014 07:59 PM
  • Joined: 17 Jun 2008
Very helpfull tank, thanks.

I need the IE-Control only in a part of the GUI. So I added
Gui,Add,Picture,w510 h500 hwndGuiHWND  
This works very well, but now there aren't any scrollbars shown. I can scroll with the cursor keys.

The horizontal scrollbar appears only, when I resize the GUI, so that it becomes less high than the IE-Control, the vertical scrollbar, when I resize the width of the GUI, so that it becomes smaler than the IE-control.

I presume, that the scrollbars are existing because they don't appear at once but slowly while dragging the GUI-borders. It looks as If the IE-Control isn't interested at the size of the picture-Control but only at the size of the Gui.

Any idea how to get the scrollbars shown?

tank
  • Administrators
  • 4345 posts
  • AutoHotkey Foundation
  • Last active: Oct 13 2016 01:04 AM
  • Joined: 21 Dec 2007
you may better post this in ask for help and post your entire modified code. your question is about your lack of understanding of control positioning and has actually nothing to do with the specifics of COM... Jethrow may b**ch slap me for this statement but i bet not
Never lose.
WIN or LEARN.

a4u
  • Guests
  • Last active:
  • Joined: --

you may better post this in ask for help and post your entire modified code.

Agreed

... Jethrow may b**ch slap me for this statement but i bet not

:lol: - who hasn't wanted to b**ch slap tank at one point or another? :p

occasional ahker
  • Guests
  • Last active:
  • Joined: --
I was hoping someone could clarify the correct syntax for creating a new book with names other than the default book1,book2 as well as creating new sheets in that workbook with names other than the default sheet1,sheet2 etc

I have tried looking up the documenation and the eample in VB is as follows.

AddNew()
Set NewBook = Workbooks.Add
With NewBook
.Title = "All Sales"
.Subject = "Sales"
.SaveAs Filename:="Allsales.xls"
End With
End Sub

The issue apparently is that when I create a new workbook I can't figure out how to set the object(workbook) to a var for later reference like in the example and I've tried different combonations of syntax but I'm not making much progress.

I have figured out how to add sheets using the sheets object but again can't figure out how to rename them or give them a name at creation.

Just for reference this is the script I am using currently.
FileSelectFile, File, 1, X:\Leaktest Data
If Not File 
	Return	
	
SplitPath, File, OutFileName, OutDir, OutExt, OutNameNoExt, OutDrive
FileName =%OutDir%\[%OutFileName%]%OutNameNoExt%

oExcel := ComObjCreate("Excel.Application")    		; create Excel Application object
oExcel.Workbooks.Add					; create a new workbook
;oExcel.Sheets.Add									;; create a new sheet

oExcel.Range("A1").Value := "Full Path of Data File Being Examined"    
oExcel.Range("A1").Font.Bold := 1      ; set bold font for cell A3
oExcel.Range("A2").Value := File
oExcel.Range("AA1:AA10000").Formula := "='X:\LeakTest Data\LT2 Data Collection\[LT2_DATA110124.xls]LT2_DATA110124'!B1"   ; set formula for cell A3 to SUM(A1:A2)
oExcel.Range("AB1:AB10000").Formula := "='X:\LeakTest Data\LT2 Data Collection\[LT2_DATA110124.xls]LT2_DATA110124'!C1"   ; set formula for cell A3 to SUM(A1:A2)H
oExcel.Range("AC1:AC10000").Formula := "='X:\LeakTest Data\LT2 Data Collection\[LT2_DATA110124.xls]LT2_DATA110124'!D1"   ; set formula for cell A3 to SUM(A1:A2)
oExcel.Range("AD1:AD10000").Formula := "='X:\LeakTest Data\LT2 Data Collection\[LT2_DATA110124.xls]LT2_DATA110124'!E1"   ; set formula for cell A3 to SUM(A1:A2)


Index:=0
Loop, 
{
	Cell:= oExcel.Range("AA" . A_Index).Value
	
	If Cell = 0.000000
		Continue
	If Cell = 
		Break
	
	Index ++
	oExcel.Range("D" . Index).Value := oExcel.Range("AA" . A_Index).Value
	oExcel.Range("E" . Index).Value := oExcel.Range("AB" . A_Index).Value
	oExcel.Range("F" . Index).Value := oExcel.Range("AC" . A_Index).Value
	
}

oExcel.Visible := 1   ; make Excel Application visible
ExitApp

Any help would be much appreciated.

a4u
  • Guests
  • Last active:
  • Joined: --

I was hoping someone could clarify the correct syntax for creating a new book with names other than the default book1,book2 as well as creating new sheets in that workbook with names other than the default sheet1,sheet2 etc

My understanding is you don't change the Book Name until you save the book - but you can change the window title (though it can easily change back). Changing the sheet name is simple:
[color=#107095]DetectHiddenWindows[/color], On
[color=#107095]SetTitleMatchMode[/color], 2

xlApp := [color=#107095]ComObjCreate[/color]([color=#666666]"Excel.Application"[/color])
xlBook := xlApp.Workbooks.Add
[color=#107095]for[/color] sheet in xlBook.Sheets
	sheet.name := [color=#666666]"Some Sheet #"[/color] [color=brown]A_Index[/color]

[color=#107095]WinGetTitle[/color], title, % xlBook.name [color=#666666]" ahk_class XLMAIN"[/color] 
[color=#107095]StringReplace[/color], title, title, % xlBook.name, Some Book Name
[color=#107095]WinSetTitle[/color], % xlBook.name [color=#666666]" ahk_class XLMAIN"[/color], , %title%

xlApp.Visible := true