Re: ObjRegisterActive
Posted: 02 Feb 2015, 07:52
Public Domain, then I'd suppose
Hehe, the logic says yes, but when you don't specify terms of use, than default terms of use apply which are set by your state, which often set maximum protection by default (nobody is allowed to use your code in any way).Lexikos wrote:If use is allowed unconditionally, does that mean there are no terms of use?
Thank you sir.Lexikos wrote:WTFPL or equivalent
Code: Select all
NewAHKScript("ObjRegisterActive", "SomeCode", "Lexikos") ; no license/terms of use --> "Maximum protection (set by the state)" applies
NewAHKScript("ObjRegisterActive", "SomeCode", "Lexikos", "WTFPL") ; WTFPL --> "WTFPL" applies
return
NewAHKScript(Name, Code, Author, License="Maximum protection (set by the state)") {
; ...
}
Given the above, I'm finding it inconvenient to use this for communication between scripts. It seems as if I need to know the names of the object's keys in advance since I cannot use _NewEnum() or a for loop. The use of a hidden GUI to pass a variable value via text still look attractive. Perhaps I'm missing something.Relayer wrote:
The first Msgbox works but the for loop complains it cannot find a member.
Lexikos wrote:
There are actually two problems:
"Member not found" comes from requesting the member DISPID_NEWENUM instead of attempting to resolve the name "_NewEnum". This works well with COM objects (since some don't actually resolve the name "_NewEnum"), but AutoHotkey objects don't respond to that ID.
Even if you call _NewEnum() directly, you can't use an AutoHotkey enumerator object remotely because it expects variable references to put the items into. The for-loop passes a normal variable reference, not Variant reference (a ComObject with VT_BYREF|VT_VARIANT). You can pass a Variant reference, but the AutoHotkey object at the other end will just dereference it and pass a useless value to the enumerator.
You can't use _NewEnum() or a for loop with your hidden GUI method or any of the other methods either, so I'm really not seeing your point.Relayer wrote:It seems as if I need to know the names of the object's keys in advance since I cannot use _NewEnum() or a for loop. The use of a hidden GUI to pass a variable value via text still look attractive.
My rhetorical question was not about what happens when I don't specify a license, but about the semantics of asking for "terms of use". You asked for terms of use, but too bad, you can't have any.min wrote:Hehe, the logic says yes, but when you don't specify terms of use,
RelayerThe use of a hidden GUI to pass a variable value via text still look attractive.
lexikos wrote:If the script quits while running a method called by a remote script, the remote script will receive an error.
Any tips on how to implement this for a particular object? Given the following draft below, how would I use it for a particular object(active):lexikos wrote:A proper COM server might implement the IExternalConnection interface to detect when all external connections have been released, then exit.
Code: Select all
class IExternalConnection
{
__New(self)
{
if !ptr := IExternalConnection.GetAddress("vtable")
{
IExternalConnection.SetCapacity("vtable", 5 * A_PtrSize)
ptr := IExternalConnection.GetAddress("vtable")
count := [3, 1, 1, 3, 4]
for i, name in ["QueryInterface", "AddRef", "Release", "AddConnection", "ReleaseConnection"]
{
cb := RegisterCallback(IExternalConnection[name], "F", count[i], i-1)
NumPut(cb, ptr + (i-1) * A_PtrSize)
}
}
ObjSetCapacity(this, "_connect", 2 * A_PtrSize)
NumPut(&self, NumPut(ptr, this.__Ptr := ObjGetAddress(this, "_connect")))
}
QueryInterface(iid, ppvObject)
{
}
AddRef()
{
}
Release()
{
}
AddConnection(exconn, dwreserved)
{
}
ReleaseConnection(extconn, dwreserved, fLastReleaseCloses)
{
}
}
It's a normal COM error, which can be suppressed by ComObjError(0) or Try.Client-side, can I use try ActiveObject.Method() to suppress the above error?
What's __Delete, and how would it be called? The remote script just has a COM object which implements IDispatch. When the remote script no longer needs its reference to the object, it just calls IUnknown::Release(). If the server is no longer running, the real object no longer exists and so neither does the __Delete method.If an instance of the active object exists in the remote script and the host script quits, will __Delete be called?
The remote script gets a pointer to a proxy object. On each client, the proxy object has its own reference count. Server side, the COM libraries have at least one reference to the object, in the running object table. I do not think AddRef is called when a client connects.When a client retrieves an instance of an active object and that object has an AddRef method, does it get called?
I decided to choose this route. However, I wanted to trigger this via __Delete and I have a question regarding reference count w/ regards to registered object(s). Below is a demo code, when calling ObjRegisterActive the reference count is incremented by 2, so from 1 it becomes 3. Then after launching the client script, when a reference is retrieved(via ComObjActive), 3 becomes 6. Why is this??:lexikos wrote: I think it's more appropriate to just notify clients that the application is exiting
Code: Select all
#Persistent
DllCall("AllocConsole")
conout := FileOpen("CONOUT$", 1|4)
GUID := "{9359E8E4-3E3C-427F-81D8-5E1314B39E73}"
obj := {Test:Func("Test"), Status:1}
; REFCOUNT == 1
ObjAddRef(&obj)
conout.WriteLine("RefCount: " . ObjRelease(&obj)), conout.Read(0)
ObjRegisterActive(obj, GUID) ; register the object
; REFCOUNT == 3 ??
ObjAddRef(&obj)
conout.WriteLine("RefCount: " . ObjRelease(&obj)), conout.Read(0)
code := Format("
(
obj := ComObjActive({1}{2}{1})
obj.Status := 0
obj.Test()
return
)", Chr(34), GUID)
cmd := Format("{1}{2}{1} *", Chr(34), A_AhkPath)
exec := ComObjCreate("WScript.Shell").Exec(cmd)
exec.StdIn.Write(code), exec.StdIn.Close()
while obj.Status && (exec.Status == 0)
Sleep 10
; REFCOUNT == 6 ??
ObjAddRef(&obj)
conout.WriteLine("RefCount: " . ObjRelease(&obj)), conout.Read(0)
ObjRegisterActive(obj, "") ; revoke
conout.Write("`nPress 'Enter' to quit.`n>>> "), conout.Read(0)
KeyWait Enter, D
DllCall("FreeConsole")
ExitApp
Test(this)
{
ObjAddRef(&this)
FileOpen("CONOUT$", 1|4).WriteLine(A_ThisFunc . "->RefCount: " . ObjRelease(&this))
}
Thanks, very usefullexikos wrote:I've posted a function which might be useful in connection with ObjRegisterActive: GetActiveObjects().
ObjAddRef() / ObjRelease() wrote:This value should be used only for debugging purposes.
I see, so this is the unpredictable part. I guess I'd have to bind the RevokeActiveObject call to another object(one which actually gets __Deleted on exit). Thanks for the clarification.lexikos wrote:When a remote script retrieves a reference to the object (via proxy), it's all handled by the (OS-provided) COM libraries. If the reference count increases by 3, obviously AddRef was called 3 times, probably because the COM libraries store 3 additional references. I don't think that would be documented anywhere, so basically, don't rely on the reference count.
Code: Select all
RegisterIDs(CLSID,APPID){
RegWrite,REG_SZ,HKCU,Software\Classes\%APPID%,,%APPID%
RegWrite,REG_SZ,HKCU,Software\Classes\%APPID%\CLSID,,%CLSID%
RegWrite,REG_SZ,HKCU,Software\Classes\CLSID\%CLSID%,,%APPID%
}
nptmplinshi wrote:Thank you very much, maestrith. Works great!