Jump to content

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

[AHK_L] ComDispatch v1.0 - replacement for DispatchObj()


  • This topic is locked This topic is locked
4 replies to this topic
fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007
ComDispatch v1.0

Notice: This library requires AutoHotkey_L

I've made a replacement for Lexikos' DispatchObj() function. The main problem with it was that it wasn't updated to keep up with the times, that is, it still relies on the old COM library for AHK_Basic. I used the following tricks whilst programming it:[*:yt642r73]The script uses the native SafeArray support to get the parameters out of the VARIANT array.
[*:yt642r73]The script uses Lexikos' ComVar() function to convert the return value back to VARIANT.Download (with documentation)

Interesting stuff:
The second example shows how to expose COM objects so that they can be retrieved back using ComObjActive() or similar in other processes/scripts, akin to what Office does.
I'm going to add a COM automation feature to SciTE4AutoHotkey by using this.

Example:
sc := [color=#107095]ComObjCreate[/color]([color=#666666]"ScriptControl"[/color])
sc.Language := [color=#666666]"VBScript"[/color]

code =
(
Sub example1()
	[color=#107095]MsgBox[/color] [color=#666666]"AHK returned: "[/color] & ahk.Message([color=#666666]"Hello World!"[/color])
End Sub
)
sc.AddCode(code)

; In this case, we don't need ComDispatch()'s this parameter.
sc.AddObject([color=#666666]"ahk"[/color], ComDispatch([color=#666666]""[/color], [color=#666666]"Message = example1"[/color]))
sc.Run([color=#666666]"example1"[/color])

example1(this, text)
{
	[color=#107095]MsgBox[/color], 0, myFunc(), % text
	[color=#107095]return[/color] [color=#666666]"Thanks for calling AHK!"[/color]
}

EDIT: found a documentation typo, ComObjParameter should be ComObjValue.

Sean
  • Members
  • 2462 posts
  • Last active: Feb 07 2012 04:00 AM
  • Joined: 12 Feb 2007
I suppose that it's not that hard to extend and expose ComEvent class to be used for this purpose, if it's really useful.

tinku99
  • Members
  • 560 posts
  • Last active: Feb 08 2015 12:54 AM
  • Joined: 03 Aug 2007
ahk and python interop

Requires comdispatch library and comremote.ahk by fincs.
Requires pywin32 by Mark Hammond
Requires ipython

To run example:
1. run the ahkside.ahk script
2. run the pythonside.py script using the following command line in msysgit:
python /c/Python26/Scripts/ipython.py -wthread -i pythonside.py

pythonside.py
import win32com.client
from win32com.server.util import wrap, unwrap
from win32com.server.dispatcher import DefaultDebugDispatcher
from ctypes import *
import commands
import pythoncom
import winerror
from win32com.server.exception import Exception

clsid = "{55C2F76F-5136-4614-A397-12214CC011E5}"
iid = pythoncom.MakeIID(clsid)
appid = "ahkdemo.python"

class VeryPermissive:
    def __init__(self):
        self.data = []
        self.handle = 0
        self.dobjects = {}        
    def __del__(self):
        pythoncom.RevokeActiveObject(self.handle)
    def _dynamic_(self, name, lcid, wFlags, args):
        if wFlags & pythoncom.DISPATCH_METHOD:
            return getattr(self,name)(*args)
        if wFlags & pythoncom.DISPATCH_PROPERTYGET:
            try:
                # to avoid problems with byref param handling, tuple results are converted to lists.
                ret = self.__dict__[name]
                if type(ret)==type(()):
                    ret = list(ret)
                return ret
            except KeyError: # Probably a method request.
                raise Exception(scode=winerror.DISP_E_MEMBERNOTFOUND)
        if wFlags & (pythoncom.DISPATCH_PROPERTYPUT | pythoncom.DISPATCH_PROPERTYPUTREF):
            setattr(self, name, args[0])
            return
        raise Exception(scode=winerror.E_INVALIDARG, desc="invalid wFlags")
    def write(self, x):
        print x
        return 0
import win32com.server.util, win32com.server.policy
child = VeryPermissive()
ob = win32com.server.util.wrap(child, usePolicy=win32com.server.policy.DynamicPolicy)
try:
    handle = pythoncom.RegisterActiveObject(ob, iid, 0)
except pythoncom.com_error, details:
    print "Warning - could not register the object in the ROT:", details
    handle = None    
child.handle = handle  
          
ahk = win32com.client.Dispatch("ahkdemo.ahk")
ahk.aRegisterIDs(clsid, appid)
# autohotkey.exe ahkside.ahk
# python /c/Python26/Scripts/ipython.py -wthread -i pythonside.py
# must use -wthread otherwise calling com client hangs
ahkside.ahk
#Persistent
CLSID_ThisScript := "{38A3EB13-D0C4-478b-9720-4D0B2D361DB9}"
APPID_ThisScript := "ahkdemo.ahk"
funcs := ["aRegisterIDs", "aGetObject", "aCallFunc"]
server := ahkComServer(CLSID_ThisScript, APPID_ThisScript, funcs)	
return

   
aRegisterIDs(this, CLSID, APPID){
RegisterIDs(CLSID, APPID)
}

aGetObject(this, name){
global
return %name%
}

aCallFunc(this, func, args){
return %func%(args)
}


F2::
py := ComObjActive("ahkdemo.python")
py.write("hello")
return


;; ahkcomserver()
ahkComServer(CLSID_ThisScript, APPID_ThisScript, funcs)
{
global serverReady
server := object()
  
  RegisterIDs(CLSID_ThisScript, APPID_ThisScript)
for i, func in funcs
{
str .= func . ", "
}
str := SubStr(str, 1, strlen(str) - 2)

  myObj := ComDispatch("", str)
; Expose it
  if !(hRemote := ComRemote(myObj, CLSID_ThisScript))
  {
    MsgBox, 16, %A_ScriptName%, Can't remote the object!
    ExitApp
  }
server.CLSID := CLSID_ThisScript
server.APPID := APPID_ThisScript
server.hRemote := hRemote
serverReady := 1
  return server
}

#Include ComRemote.ahk
#include lib\ComDispTable.ahk
#include lib\ComDispatch.ahk
#include lib\ComVar.ahk

Edit (7/13/2011): removed AutoHotkey.dll dependency on the python side.

tinku99
  • Members
  • 560 posts
  • Last active: Feb 08 2015 12:54 AM
  • Joined: 03 Aug 2007
Do you think its possible to implement IConnectionPoint within your comdispatch object ?
Can do it in python: examples:
http://bit.ly/oksyrv,
http://bit.ly/pb0KT9
Would be a nicer way to do asynchronous communication between ahk scripts than using postmessage...

rbrtryn
  • Members
  • 1177 posts
  • Last active: Sep 11 2013 08:04 PM
  • Joined: 22 Jun 2011
Re-posted without all the annoying color tags.
 

ComDispatch v1.0

Notice: This library requires AutoHotkey_L

I've made a replacement for Lexikos' DispatchObj() function. The main problem with it was that it wasn't updated to keep up with the times, that is, it still relies on the old COM library for AHK_Basic. I used the following tricks whilst programming it:[*:yt642r73]The script uses the native SafeArray support to get the parameters out of the VARIANT array.

  • The script uses Lexikos' ComVar() function to convert the return value back to VARIANT. Download (with documentation)
Interesting stuff:
The second example shows how to expose COM objects so that they can be retrieved back using ComObjActive() or similar in other processes/scripts, akin to what Office does.
I'm going to add a COM automation feature to SciTE4AutoHotkey by using this.

Example:
sc := ComObjCreate("ScriptControl")
sc.Language := "VBScript"

code =
(
Sub example1()
	MsgBox "AHK returned: " & ahk.Message("Hello World!")
End Sub
)
sc.AddCode(code)

; In this case, we don't need ComDispatch()'s this parameter.
sc.AddObject("ahk", ComDispatch("", "Message = example1"))
sc.Run("example1")

example1(this, text)
{
	MsgBox, 0, myFunc(), % text
	return "Thanks for calling AHK!"
}


My Scripts are written for the latest released version of AutoHotkey.

Need a secure, accessible place to backup your stuff? Use Dropbox!