 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
majkinetor
Joined: 24 May 2006 Posts: 3626 Location: Belgrade
|
Posted: Tue Dec 04, 2007 10:14 am Post subject: |
|
|
2 Sean
What about IContextMenu ? Can it be LocalServer too or must be InProc (I don't recall ever seing it local). If dll is only option, then I guess Lex's dotNet caller can creeate it dynamicaly  _________________
 |
|
| Back to top |
|
 |
AHKnow
Joined: 03 Jul 2004 Posts: 118
|
Posted: Tue Dec 04, 2007 10:49 am Post subject: |
|
|
| Sean wrote: | | lexikos wrote: | | Very interesting. |
It may be more interesting to create IDispatch AutoHotkey COM Server, I suppose. |
The whole COM server idea is indeed very interesting. It opens up even more capabilities for AutoHotkey and COM. |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 1338
|
Posted: Tue Dec 04, 2007 3:02 pm Post subject: |
|
|
| majkinetor wrote: | | I don't recall ever seing it local. |
Neither do I. I suspect it's not allowed.
| Quote: | If dll is only option, then I guess Lex's dotNet caller can creeate it dynamicaly  |
I became very interested in .NET through the great work of lexikos. I'm wondering how well the explorer shell goes along with .NET. |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 1338
|
Posted: Tue Dec 04, 2007 3:03 pm Post subject: |
|
|
| AHKnow wrote: | | The whole COM server idea is indeed very interesting. It opens up even more capabilities for AutoHotkey and COM. |
Agreed. BTW AHK is really amazing. |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 3626 Location: Belgrade
|
Posted: Tue Dec 04, 2007 3:09 pm Post subject: |
|
|
You got great deal of sophistication when COM is in question.
I have read DropTarget and its very funny that in your work COM is easier to implement then in some higher languages . At least it seems to me so. Particualary nice thing is that you use the same function for entire VTable (I used the same method to subclas N controls with the same function, in ComboX).
Thx for everything. _________________
 |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 3626 Location: Belgrade
|
Posted: Tue Dec 04, 2007 3:56 pm Post subject: |
|
|
The bellow script merges everything above into single script that can be used to register, unregister and see behavior of entire process. This has nothing to do with DDE anymore.
To register shell context menu entery, open cmd and run script with /reg parameter. Run it with /unreg to unregister.
After you register it with shell, "AHK VERB TEST" will appear in menu. Select multiple files or folders and select mentioned menu entery to make the Explorer call the script.
U need COM.ahk to run this.
| Code: | #persistent
OnExit, DropTargetClose
if 1 = /unreg
{
Shell_Unregister()
MsgBox Shell verb unregistred
ExitApp
} else if 1=/reg
{
Shell_Register()
MsgBox Shell verb registred
ExitApp
}
Shell_Init()
Return
Shell_Register() {
RegWrite, REG_SZ, HKCR, *\shell\AHK VERB TEST\DropTarget, CLSID, {83E7233E-4624-488F-9CBC-DFA2521AF2FA}
RegWrite, REG_SZ, HKCR, Folder\shell\AHK VERB TEST\DropTarget, CLSID, {83E7233E-4624-488F-9CBC-DFA2521AF2FA}
RegWrite, REG_SZ, HKCR, CLSID\{83E7233E-4624-488F-9CBC-DFA2521AF2FA}\LocalServer32,, "%A_AhkPath%" "%A_ScriptFullPath%"
}
Shell_UnRegister() {
RegDelete, HKCR, *\shell\AHK VERB TEST
RegDelete, HKCR, Folder\shell\AHK VERB TEST
RegDelete, HKCR, CLSID\{83E7233E-4624-488F-9CBC-DFA2521AF2FA}
}
Shell_Init() {
global
If not Shell_nRegister := DropTargetOpen() {
msgbox Shell init failed
ExitApp
}
}
GetData:
msgbox % GetData(Shell_data)
COM_Release(Shell_data), Shell_data := ""
Return
DropTargetClose:
DropTargetClose(Shell_nRegister)
ExitApp
DropTargetOpen(){
static IDropTarget, IClassFactory
If not VarSetCapacity(IDropTarget)
{
VarSetCapacity(IDropTarget,36,0), NumPut(&IDropTarget+4,IDropTarget), nParams=3116516
Loop, Parse, nParams
NumPut(RegisterCallback("IDropTarget","",A_LoopField,A_Index-1),IDropTarget,4*A_Index)
}
If not VarSetCapacity(IClassFactory)
{
VarSetCapacity(IClassFactory,28,0), NumPut(&IClassFactory+4,IClassFactory), nParams=31142
Loop, Parse, nParams
NumPut(RegisterCallback("IClassFactory","",A_LoopField,A_Index-1), IClassFactory,4*A_Index)
}
NumPut(&IClassFactory,IDropTarget,32), NumPut(&IDropTarget,IClassFactory,24)
COM_Init()
DllCall("ole32\CoRegisterClassObject", "Uint", COM_GUID4String(CLSID,"{83E7233E-4624-488F-9CBC-DFA2521AF2FA}"), "Uint", &IDropTarget, "Uint", 4, "Uint", 1, "UintP", Shell_nRegister)
Return Shell_nRegister
}
DropTargetClose(Shell_nRegister)
{
DllCall("ole32\CoRevokeClassObject", "Uint", Shell_nRegister)
COM_Term()
}
GetData(this)
{
VarSetCapacity(FormatEtc,20,0), VarSetCapacity(StgMedium,12,0)
NumPut(DllCall("RegisterClipboardFormat", "str", "Shell IDList Array"),FormatEtc,0), NumPut(0,FormatEtc,4), NumPut(1,FormatEtc,8), NumPut(-1,FormatEtc,12), NumPut(1,FormatEtc,16)
DllCall(NumGet(NumGet(1*this)+12), "Uint", this, "Uint", &FormatEtc, "Uint", &StgMedium) ; GetData
hData:= NumGet(StgMedium,4)
pData:= DllCall("GlobalLock", "Uint", hData)
pidlP:= pData+NumGet(pData+4), VarSetCapacity(sPath, 259)
Loop, % NumGet(pData+0)
pidl:=DllCall("shell32\ILCombine", "Uint", pidlP, "Uint", pData+NumGet(pData+4+4*A_Index)), DllCall("shell32\SHGetPathFromIDListA", "Uint", pidl, "str", sPath), COM_CoTaskMemFree(pidl), sData .= sPath . "`n"
DllCall("GlobalUnlock", "Uint", hData)
DllCall("ole32\ReleaseStgMedium", "Uint", &StgMedium)
Return sData
}
IClassFactory(this, punk="", riid="", ppobj="")
{
hResult := 0
If A_EventInfo = 3
NumPut(NumGet(this+24),ppobj+0)
Else If A_EventInfo = 0
hResult := DllCall(NumGet(NumGet(this+24)+4), "Uint", NumGet(this+24), "Uint", punk, "Uint", riid)
Return hResult
}
IDropTarget(this, pdata="", key="", x="", y="", peffect="")
{
hResult := 0
If A_EventInfo = 6
{
NumPut(NumGet(peffect+0)&5,peffect+0)
Global Shell_data := pdata
COM_AddRef(Shell_data)
SetTimer, GetData, -100
}
Else If A_EventInfo = 3
NumPut(NumGet(peffect+0)&5,peffect+0)
Else If A_EventInfo = 0
InStr("{00000122-0000-0000-C000-000000000046}{00000000-0000-0000-C000-000000000046}",IID:=COM_String4GUID(pdata)) ? NumPut(this,key+0) : IID="{00000001-0000-0000-C000-000000000046}" ? NumPut(NumGet(this+32),key+0) : hResult:=0x80004002
Return hResult
}
|
After some testing it seems that all above problems are fixed ("file not found", speed) _________________
 |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2558 Location: Australia, Qld
|
Posted: Tue Dec 04, 2007 5:03 pm Post subject: |
|
|
| majkinetor wrote: | If dll is only option, then I guess Lex's dotNet caller can creeate it dynamicaly  | Honestly, if you were going to program a shell extension in .NET, why mix it with AutoHotkey at all? To provide a convenient installer.ahk...?
| Sean wrote: | | I'm wondering how well the explorer shell goes along with .NET. | I used QtTabBar (which uses .Net Framework 2.0) for a while on XP. It works well, but there's a bit of a delay opening the first Explorer window, as the CLR loads...
Actually, would it not be possible to write a DLL (in C++ or .Net) to act as an intermediary (class factory) for an AutoHotkey local server? The DLL itself should be small, and would allow the main implementation to be in AutoHotkey.
Now I ask myself "Why would you want to implement an in-proc COM server with AutoHotkey?"  |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 3626 Location: Belgrade
|
Posted: Tue Dec 04, 2007 5:05 pm Post subject: |
|
|
| Quote: | | Honestly, if you were going to program a shell extension in .NET, why mix it with AutoHotkey at all? To provide a convenient installer.ahk...? |
I like to have possibilities, thats all. I didn't say I will do the things you mention above.
| Quote: | | Now I ask myself "Why would you want to implement an in-proc COM server with AutoHotkey?" |
How about, just for fun  _________________
 |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 1338
|
Posted: Wed Dec 05, 2007 12:22 am Post subject: |
|
|
| lexikos wrote: | | I used QtTabBar (which uses .Net Framework 2.0) for a while on XP. It works well, but there's a bit of a delay opening the first Explorer window, as the CLR loads... |
That's good to know. Thanks.
| Quote: | | Actually, would it not be possible to write a DLL (in C++ or .Net) to act as an intermediary (class factory) for an AutoHotkey local server? The DLL itself should be small, and would allow the main implementation to be in AutoHotkey. |
Looks like you're talking about the in-process handler. As a matter of fact, the first thing hit me was Windows Media Player's deskband when you said about deskband, which I suspected might use it. But, it turned out in-process server which is the only one allowed for deskband. BTW, from the programming point of view, I believe there is not much difference between in-process server and handler. So: why not just write a full fledged in-process server and open an IPC channel with AHK, which could be COM again. |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2558 Location: Australia, Qld
|
Posted: Wed Dec 05, 2007 12:55 am Post subject: |
|
|
| Sean wrote: | | So: why not just write a full fledged in-process server and open an IPC channel with AHK, which could be COM again. | I'd thought of that, but if the main implementation is in another language, I see no reason to use AutoHotkey at all. (A while back I started a C++ project implementing a desk band, but kind of lost interest...) |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 1338
|
Posted: Wed Dec 05, 2007 11:26 am Post subject: |
|
|
I added Dispatch.ahk for Dispatch COM Server to AutoHotkeyVerb.ahk. Please rerun RegisterVerb.ahk to register the Server. Currently it implements only one function, AppExit.
Example:
| Code: | COM_Init()
pahk := COM_CreateObject("AutoHotkey.Application")
MsgBox, % COM_Invoke(pahk, "Exit")
MsgBox, % COM_Invoke(pahk, "AppExit")
COM_Term()
|
|
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2558 Location: Australia, Qld
|
Posted: Sun Jan 13, 2008 3:31 am Post subject: |
|
|
Any clue how to get Dispatch.ahk to work with VBscript?
| Code: | COM_Init()
ahk := COM_CreateObject("AutoHotkey.Application")
COM_Invoke(ahk, "SomeFunc", "testing", 1, 2)
COM_Invoke(ahk, "AppExit")
COM_Release(ahk)
| works, but | Code: | Set ahk = CreateObject("AutoHotkey.Application")
ahk.SomeFunc "testing", 1, 2
ahk.AppExit | just gives me
| Quote: | | Error: ActiveX component can't create object: 'AutoHotkey.Application' |
Edit: Seems it might've been a Vista registry virtualization issue. I guess RegisterVerb.ahk and my test.ahk both were accessing a virtualized key, while the VBscript wasn't. I went looking for the AutoHotkey.Application subkey under HKEY_CLASSES_ROOT in regedit, but couldn't find it.
Now when I try to create the object, I get: | Quote: | Script: Z:\test.vbs
Line: 1
Char: 1
Error: Invalid access to memory location.
Code: 800703E6
Source: (null) |
|
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 1338
|
Posted: Sun Jan 13, 2008 4:41 am Post subject: |
|
|
| lexikos wrote: | Now when I try to create the object, I get: | Quote: | Script: Z:\test.vbs
Line: 1
Char: 1
Error: Invalid access to memory location.
Code: 800703E6
Source: (null) |
|
For the moment, use WScript.CreateObject instead of VBS's CreateObject, it seems to work.
IDispatch and IClassFactory were implemented to the minimum necessary as I had in mind only AutoHotkey.exe to use AutoHotkey.Application. To use it with other scripting engines, I think the interfaces should be fully implemented like COM_DispInterface(). And, should also assign separate DispIDs for the custom functions as some scripting engines cache DispIDs for the performance.
PS. Is there no way to disable the notification mails for whole (already notification-enabled) threads instead of one-by-one? |
|
| Back to top |
|
 |
Lexikos
Joined: 17 Oct 2006 Posts: 2558 Location: Australia, Qld
|
Posted: Sun Jan 13, 2008 5:48 am Post subject: |
|
|
| Sean wrote: | | For the moment, use WScript.CreateObject instead of VBS's CreateObject, it seems to work. | Thanks.
| Quote: | | To use it with other scripting engines, I think the interfaces should be fully implemented like COM_DispInterface(). And, should also assign separate DispIDs for the custom functions as some scripting engines cache DispIDs for the performance. | That certainly wasn't the issue in this case. I logged the calls to interface members; basically it was:
- IClassFactory.AddRef()
- IClassFactory.QueryInterface(IID_IClassFactory)
- IClassFactory.Release()
- IClassFactory.AddRef()
- IClassFactory.Release()
- IClassFactory.QueryInterface(IID_IMarshal)
- IClassFactory.Release()
...repeated eleven times, then an Access Violation would occur in ole.dll (iirc), attempting to read address 0x0.
| Quote: | | PS. Is there no way to disable the notification mails for whole (already notification-enabled) threads instead of one-by-one? | Other than changing the e-mail address associated with your profile, I'm not sure. |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 1338
|
Posted: Sun Jan 13, 2008 7:59 am Post subject: |
|
|
| lexikos wrote: | then an Access Violation would occur in ole.dll (iirc), attempting to read address 0x0.  |
I updated Dispatch.ahk. And I changed the name AppExit to Quit to accord with other well-known local servers.
It's still not rigorous implementation, so can go wrong with other scripting engines, then please post here. I'll leave this thread as notification-on. |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|