Author Topic: Foreign objects: is releasing the parent object enough?  (Read 7055 times)

0 Members and 1 Guest are viewing this topic.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Foreign objects: is releasing the parent object enough?
« on: March 19, 2013, 11:20:57 AM »
In the code below you can see that I am releasing all 'foreign' objects. But is this really required? Would only releasing the parent object (htmlfileObject) be enough?

Code - Auto/Visual Lisp: [Select]
  1. ; Str can be a string value or nil.
  2. ; If str is nil the clipboard will be cleared.
  3. ; Return value: string or nil.
  4. (defun clipboard-put-text (str / clipboarddataObject getStr htmlfileObject parentwindowObject)
  5.   (if
  6.     (and
  7.       (setq htmlfileObject (vlax-create-object "htmlfile"))
  8.       (setq parentwindowObject (vlax-get htmlfileObject 'parentwindow))
  9.       (setq clipboarddataObject (vlax-get parentwindowObject 'clipboarddata))
  10.     )
  11.     (progn
  12.       (vlax-invoke clipboarddataObject 'cleardata) ; Clears all data and not just text.
  13.       (if str (vlax-invoke clipboarddataObject 'setdata "text" str))
  14.       (setq getStr (vlax-invoke clipboarddataObject 'getdata "text"))
  15.     )
  16.   )
  17.   (if clipboarddataObject (vlax-release-object clipboarddataObject))
  18.   (if parentwindowObject (vlax-release-object parentwindowObject))
  19.   (if htmlfileObject (vlax-release-object htmlfileObject))
  20.   (if (and str (= str getStr)) str)
  21. )
  22.  
  23. ; Return value: string or nil.
  24. (defun clipboard-get-text ( / clipboarddataObject htmlfileObject parentwindowObject str)
  25.   (if
  26.     (and
  27.       (setq htmlfileObject (vlax-create-object "htmlfile"))
  28.       (setq parentwindowObject (vlax-get htmlfileObject 'parentwindow))
  29.       (setq clipboarddataObject (vlax-get parentwindowObject 'clipboarddata))
  30.     )
  31.     (setq str (vlax-invoke clipboarddataObject 'getdata "text"))
  32.   )
  33.   (if clipboarddataObject (vlax-release-object clipboarddataObject))
  34.   (if parentwindowObject (vlax-release-object parentwindowObject))
  35.   (if htmlfileObject (vlax-release-object htmlfileObject))
  36.   str
  37. )
  38.  

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Foreign objects: is releasing the parent object enough?
« Reply #1 on: March 20, 2013, 05:21:04 AM »
Situation 1:
    htmlfileObject not released
    parentwindowObject not released
!parentwindowObject => #<VLA-OBJECT DispHTMLWindow2 16908240>
parentwindowObject can be dumped.

Situation 2:
    htmlfileObject released
    parentwindowObject not released
!parentwindowObject => #<VLA-OBJECT IDispatch 16908240>
parentwindowObject cannot be dumped:
: error accessing 'TypeInfoCount' of IDispatch interface !

Situation 3:
    htmlfileObject released
    parentwindowObject released
!parentwindowObject => #<VLA-OBJECT *Unknown* 00000000>
parentwindowObject cannot be dumped:
; error : bad argument type <#<VLA-OBJECT *Unknown* 00000000>> ; expected VLA-OBJECT at [VLAX-DUMP-OBJECT]

Since there is a difference between the parentwindowObject objects in situation 2 and 3, releasing ALL foreign objects seems wiser.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Foreign objects: is releasing the parent object enough?
« Reply #2 on: March 20, 2013, 03:25:11 PM »
As opposed to Roy's empirical test, here's my take on the theoretical  ;)

If I did some form of vlax-create-object (or some similar) then it needs to be released. But if it is some sort of child object (e.g. Items collection) then no, it's not needed for those as releasing the parent would automatically release the child(ren) as well (hopefully  ::) - if the ActiveX lib has no bugs of its own).

Your code however, is not actually getting a contained object. You're creating a reference to the newly created object's parent. So I'd not expect a release of the original object to also "release" the parent - the parent isn't contained in the child. The lib "might"have been written to release the parent as soon as it notices there's no more children, but I wouldn't hold my breath. So to be safe it may need a release as well.

My rule of thumb with foreign objects: If in doubt, release them. It costs you a single extra line of code, which impacts on efficiency only negligibly, but ensures that handles and ram is released if at all necessary. In your case, my rule would cause me to release all 3 objects as you've done - with a possible exception of the clipboard data object (as that seems to be a child object of the parentwindow). Only releasing the parent window might break something: as it wasn't the original created object, so I'd definitely release both htmlfile and parent.
« Last Edit: March 20, 2013, 03:30:06 PM by irneb »
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

owenwengerd

  • Bull Frog
  • Posts: 451
Re: Foreign objects: is releasing the parent object enough?
« Reply #3 on: March 20, 2013, 05:32:48 PM »
Just a quick comment:

In COM, you don't release objects, you release interfaces. All interfaces that you obtain, you must release. Once all interfaces on an object are released, the object is free to be destroyed. The question you should be asking is *when* to release the interface(s). They will be released, either deterministically via explicit calls to (vlax-release-object) or opportunistically during garbage collection. In some cases an interface *must* be released deterministically if some succeeding code depends on the interface being released. For others, they can and should be left to garbage collection to be released opportunistically. In other cases, it's more efficient to "hand tune" the release of interfaces to effect the destruction of large objects quickly so that they release their memory.

At least, that is my opinion about the theoretical design of AutoLISP's COM functionality. In practice, I'm sure there are cases where this is not true, but I think it's useful to consider the theoretical perspective.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Foreign objects: is releasing the parent object enough?
« Reply #4 on: March 21, 2013, 01:14:49 AM »
You're absolutely correct Owen. Though as you've mentioned, there are situations where the opportunistic releases don't happen. E.g. if your code causes another program to start (e.g. linking to Excel) if you don't release it the program is still running - sometimes without even a tab on the taskbar (so the user can't "easily" close it manually).

I think in this case something similar is happening. The OP is creating a html file, which would probably open it in something like IE. Thus hopefully the opportunistic release does close IE after the html file is released ... at least some indeterminate time in the future.

BTW, I like VVA's take on this more - it's more direct about what's happening: http://www.theswamp.org/index.php?topic=21764.0

Not to mention, it explicitly opens IE. Can you be sure that opening/creating a html file will always open IE? What happens if it opens in FF due to some setting? On the other hand (as noted by some in that thread) if IE isn't installed ... what then? Is the program which opens the html still giving the same ActiveX connections to the clipboard data?
« Last Edit: March 21, 2013, 01:18:56 AM by irneb »
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

TheMaster

  • Guest
Re: Foreign objects: is releasing the parent object enough?
« Reply #5 on: March 21, 2013, 06:06:05 AM »
I think it's about time to clue some of you folk in on a secret.

The secret, is that consuming ActiveX from LISP is much harder
than it should be or could have been if the maker of the most-
widely-used dialect of the LISP programming language actually
knew something about it. The sad truth is that Autodesk knows
jack about LISP.

Below are your clipboard functions rewritten to use some of
the APIs from my 10+ year-old library of ActiveX utility and
helper functions, which I've relied for about that long to
make things easier than most seem to think they need be (an
abridged version with the required APIs is attached).

I still use LISP, but more-recently it's mostly for testing
code I write in other languages, namely managed and native
ObjectARX.

Two things you might want to make note of in the code below,
is that first, it contains no calls to vlax-release-object.
But, notice the trace messages output by the API.

Code - Auto/Visual Lisp: [Select]
  1.  
  2. ;; Requires VlxLite.lsp (attached)
  3.  
  4. ;; Helper for the following two functions.
  5. ;; Takes a function that takes a single
  6. ;; argument, which is the Clipboard object.
  7. ;; After the passed function is applied,
  8. ;; all objects that were traversed to reach
  9. ;; the invocation target are released.
  10.  
  11. (defun using-clipboard (func)
  12.    (vlx-invoke-using (vlax-create-object "htmlfile")
  13.       '(ParentWindow ClipboardData)
  14.       func
  15.    )
  16. )
  17.  
  18. ;; Set clipboard text
  19.  
  20. (defun SetClipboardText ( text )
  21.    (using-clipboard
  22.      '(lambda ( cbdata )
  23.          (if text
  24.             (vlax-invoke cbdata 'SetData "text" text)
  25.             (vlax-invoke cbdata 'ClearData)
  26.          )
  27.       )
  28.    )  
  29. )
  30.  
  31. ;; Get clipboard text:
  32.  
  33. (defun GetClipboardText ()
  34.    (using-clipboard
  35.      '(lambda ( cbdata )
  36.          (vlax-invoke cbdata 'GetData "text")
  37.       )
  38.    )
  39. )
  40.  
  41. ; Enable tracing of implicit ActiveX object release:
  42.  
  43. (setq *vlx-release-trace* T)
  44.  
  45.  


With the above code and VLXLite.lsp loaded:


Code - Text: [Select]
  1.  
  2. Command: (setq *vlx-release-trace* T)
  3. T
  4.  
  5. Command: (SetClipboardText "Hello VlxLite")
  6.  
  7. *** vlx-release: #<VLA-OBJECT IHTMLDataTransfer 000000002cd42c10> ***
  8. *** vlx-release: #<VLA-OBJECT DispHTMLWindow2 000000000304ac00> ***
  9. *** vlx-release: #<VLA-OBJECT DispHTMLDocument 000000000304a9d0> ***
  10. -1
  11.  
  12. Command: (GetClipboardText)
  13.  
  14. *** vlx-release: #<VLA-OBJECT IHTMLDataTransfer 000000000304ac50> ***
  15. *** vlx-release: #<VLA-OBJECT DispHTMLWindow2 000000002cd42670> ***
  16. *** vlx-release: #<VLA-OBJECT DispHTMLDocument 000000000304a9d0> ***
  17. "Hello VlxLite"
  18.  
  19. Command: (vlx-ThisDrawing '(Layers "0" Linetype))
  20.  
  21. *** vlx-release: #<VLA-OBJECT IAcadLayer 000000002eb32488> ***
  22. *** vlx-release: #<VLA-OBJECT IAcadLayers 000000002ea24798> ***
  23. "Continuous"
  24.  
  25. Command: (vlx-ThisApp '(Preferences Files MenuFile))
  26.  
  27. *** vlx-release: #<VLA-OBJECT IAcadPreferencesFiles 0000000028223aa0> ***
  28. *** vlx-release: #<VLA-OBJECT IAcadPreferences 0000000028223ad8> ***
  29. "C:\\Users\\TeklaTestAccount\\appdata\\roaming\\autodesk\\autocad 2012 -
  30. english\\r18.2\\enu\\support\\acad"
  31.  
  32.  
« Last Edit: March 21, 2013, 08:39:05 AM by TT »

Lee Mac

  • Seagull
  • Posts: 12905
  • London, England
Re: Foreign objects: is releasing the parent object enough?
« Reply #6 on: March 21, 2013, 08:18:59 AM »
Thank you for sharing your knowledge Tony.

TheMaster

  • Guest
Re: Foreign objects: is releasing the parent object enough?
« Reply #7 on: March 21, 2013, 08:25:04 AM »
Thank you for sharing your knowledge Tony.

You're welcome Lee.

Hopefully, the folks here will find it as helpful as it's been to me over the years.
« Last Edit: March 21, 2013, 08:36:37 AM by TT »

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1451
  • Marco
Re: Foreign objects: is releasing the parent object enough?
« Reply #8 on: March 22, 2013, 03:33:10 AM »
Hopefully, the folks here will find it as helpful as it's been to me over the years.
Thank you.

Marco

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Foreign objects: is releasing the parent object enough?
« Reply #9 on: March 22, 2013, 03:55:53 PM »
Many thanks everybody for your advice, information and inspiration...

But allow me to return to the topic:

Irneb is right: releasing htmlfileObject does not release the IE interface. This is obvious if you compare the delay when you first use one of the functions (several seconds) with the delay when you use them a second time (almost zero).

@ owenwengerd:
Is there a way to tell if and when the IE interface will be opportunistically released by garbage collection?

@ irneb:
BTW, I like VVA's take on this more - it's more direct about what's happening: http://www.theswamp.org/index.php?topic=21764.0
My code definitely starts an IE interface (even if FF is the default browser). And indeed the code will not work if IE is *completely* (if such a thing is possible) removed from Windows. With my IE security settings VVA's code triggers IE alerts and if not releasing the IE interface can be good 'opportunistic' practice I would prefer to use 'my' approach.


TheMaster

  • Guest
Re: Foreign objects: is releasing the parent object enough?
« Reply #10 on: March 22, 2013, 06:42:15 PM »

Irneb is right: releasing htmlfileObject does not release the IE interface. This is obvious if you compare the delay when you first use one of the functions (several seconds) with the delay when you use them a second time (almost zero).


IE is an OLE server. When you use it to copy plain text to the clipboard, it places more than just plain text on the clipboard. That includes OLE objects that have a dependence on the server, and which will keep the server running as long as what it placed on the clipboard remains there.

I would probably recommend finding another way to access the clipboard, if the user isn't otherwise using IE as their browser, since in that case, the unavoidable overhead isn't justifiable.

Insofar as the more generic question, A server will shut down when all its interfaces are released, provided there is no other outstanding dependence on it, which can include clipboard contents, open handles, mutexes, semaphores, and so forth.
« Last Edit: March 22, 2013, 06:46:44 PM by TT »

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Foreign objects: is releasing the parent object enough?
« Reply #11 on: March 25, 2013, 06:43:07 AM »
Code: [Select]
| I |                                     | C |
| E |  <-- ON -----------------------+    | A |
|   |                                |    | D |
| O |  <--->    htmlfileObject     <--->  |   |
| L |                 |                   | P |
| E |                 |                   | R |
|   |  <--->  parentwindowObject   <--->  | O |
| S |                 |                   | G |
| E |                 |                   | R |
| R |  <--->  clipboarddataObject  <--->  | A |
| V |                                     | M |
| E |
| R |  - - - > SHUT DOWN

... So step by step this happens (?):
  • When the htmlfileObject is created the CAD program creates what is in effect an interface with the IE OLE server. If the server is not already running it is switched on.
  • The other objects (parentwindowObject and clipboarddataObject) are each separate interfaces with the IE OLE server.
  • When the three interfaces are released the IE OLE server is not immediately shut down. It will shut down on its own. There is no way to influence this from Lisp.

TheMaster

  • Guest
Re: Foreign objects: is releasing the parent object enough?
« Reply #12 on: March 25, 2013, 06:03:11 PM »
The question of when a server shuts down can depend on a number of things.

The OLE object that gets placed on the clipboard has interfaces that must be released. From the perspective of the OLE Server, the windows clipboard is just another consumer that must call IUnknown::AddRef() and IUnknown::Release(), which is what happens when the OLE object is placed on the clipboard and removed, respectively.

If the server is loaded into the host process (an 'in-process' server) then even without putting anything on the clipboard, the server will not be unloaded immediately. That does not happen until some code in the host process makes a call to CoFreeUnusedLibraries(), or CoFreeUnusedLibrariesEx(), which will query each loaded COM server and ask it if it's ok to unload it (by calling the server's DllCanUnloadNow() method). If the call returns S_TRUE, then OLE unloads the server.

So, the point when an in-process server is actually unloaded from the host process depends on when the host process calls CoFreeUnusedLibraries(), which AutoCAD (at least) does periodically every few minutes. Those of us that have debugged in-process COM servers running in AutoCAD are more than vaguely familiar with this, since it prevents us from rebuilding our project because the project DLL cannot be overwritten while it is loaded into a host process. Usually, I will not wait for AutoCAD to call CoFreeUnusedLibraries() and will just terminate and restart it instead.

If the server is not running in-process then it depends on the server and cache policy, but from what I've observed, IE components, including the HTML component, are by-design, left running so that if the user repeatedly starts an instance of the IE browser with no other instances running, they do not have to wait as  long as they must the first time it is started in the Windows session. IOW, the delay you see the first time your code runs is that very problem. If the server was being unloaded when there are no longer any dependents, then each time a dependent is started, the server would have to be reloaded, and there would be a long delay. Microsoft knows that users don't savor that, so their solution is to keep some components running even when nothing is using them, so that they do not have be reloaded each and every time something that does need them is started.


irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Foreign objects: is releasing the parent object enough?
« Reply #13 on: March 26, 2013, 01:31:11 AM »
Good explanation!

But what the OP wanted to know is if it's necessary to release not only the htmlfileObject, but also the other 2 (i.e. the parent window and the clipboard). These variables are simply cleared when the defun completes, but is a ghost interface object perhaps still floating in the VL engine - like one would be for the htmlfileObject if no vlax-release-object was called on it?

AFAICT, it's probably not necessary. I just can't see any downside on being overly cautious in this case.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

TheMaster

  • Guest
Re: Foreign objects: is releasing the parent object enough?
« Reply #14 on: March 26, 2013, 03:01:02 AM »
Good explanation!

But what the OP wanted to know is if it's necessary to release not only the htmlfileObject, but also the other 2 (i.e. the parent window and the clipboard). These variables are simply cleared when the defun completes, but is a ghost interface object perhaps still floating in the VL engine - like one would be for the htmlfileObject if no vlax-release-object was called on it?

AFAICT, it's probably not necessary. I just can't see any downside on being overly cautious in this case.

As Owen already mentioned, it's really a moot question, since if you don't release the interfaces, VL's garbage collector will do it shortly thereafter, so not releasing them has little to do with the perception that the server isn't shutting down.

In case it wasn't already mentioned, the 'server' in the OP's case, is MSHTML.dll, which is already in use (AutoCAD uses it, and it is loaded when AutoCAD starts).  In other words, there is no way to unload that server, because AutoCAD uses it (can't say that's also the case for any other host process).