TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: roy_043 on March 19, 2013, 11:20:57 AM

Title: Foreign objects: is releasing the parent object enough?
Post by: roy_043 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.  
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: roy_043 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.
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: irneb 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.
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: owenwengerd 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.
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: irneb 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 (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?
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: TheMaster 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.  
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: Lee Mac on March 21, 2013, 08:18:59 AM
Thank you for sharing your knowledge Tony.
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: TheMaster 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.
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: Marc'Antonio Alessi 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
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: roy_043 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 (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.

Title: Re: Foreign objects: is releasing the parent object enough?
Post by: TheMaster 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.
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: roy_043 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 (?):
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: TheMaster 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.

Title: Re: Foreign objects: is releasing the parent object enough?
Post by: irneb 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.
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: TheMaster 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).


Title: Re: Foreign objects: is releasing the parent object enough?
Post by: roy_043 on March 26, 2013, 02:58:06 PM
My conclusion (at this point):
Since the IE OLE server stays active it makes less sense to be very fussy about releasing the three 'foreign' objects. Opting for the opportunistic approach and leaving things in the hands of the garbage collector is a valid decision in this case.

Thanks for the additional explanation Tony.

Code - Auto/Visual Lisp: [Select]
  1. ; Return value: string, nil (clipboard empty) or error object.
  2. (defun new-clipboard-get-text ()
  3.   (vl-catch-all-apply
  4.     '(lambda ()
  5.       (vlax-invoke
  6.         (vlax-get
  7.           (vlax-get (vlax-create-object "htmlfile") 'parentwindow)
  8.           'clipboarddata
  9.         )
  10.         'getdata
  11.         "text"
  12.       )
  13.     )
  14.   )
  15. )
  16.  
  17. ; Return value: string (unmodified input) or error object.
  18. (defun new-clipboard-put-text (str / return)
  19.   (if
  20.       (setq return
  21.         (vl-catch-all-apply
  22.           '(lambda ()
  23.             (vlax-invoke
  24.               (vlax-get
  25.                 (vlax-get (vlax-create-object "htmlfile") 'parentwindow)
  26.                 'clipboarddata
  27.               )
  28.               'setdata
  29.               "text"
  30.               str
  31.             )
  32.           )
  33.         )
  34.       )
  35.     )
  36.     return
  37.     str
  38.   )
  39. )
  40.  
  41. ; Return value: T or error object.
  42. (defun new-clipboard-clear ( / return)
  43.   (if
  44.       (setq return
  45.         (vl-catch-all-apply
  46.           '(lambda ()
  47.             (vlax-invoke
  48.               (vlax-get
  49.                 (vlax-get (vlax-create-object "htmlfile") 'parentwindow)
  50.                 'clipboarddata
  51.               )
  52.               'cleardata
  53.             )
  54.           )
  55.         )
  56.       )
  57.     )
  58.     return
  59.     T
  60.   )
  61. )
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: TheMaster on March 26, 2013, 07:45:25 PM
My conclusion (at this point):
Since the IE OLE server stays active it makes less sense to be very fussy about releasing the three 'foreign' objects. Opting for the opportunistic approach and leaving things in the hands of the garbage collector is a valid decision in this case.

Thanks for the additional explanation Tony.



Letting the garbage collector clean up is fine in this case, except that I would let exceptions take their natural course (e.g., act on the result of vl-catch-all-apply or, don't use it), because I don't know what may have caused them.

After looking at system activity using Spy++, I'll retract the above, and not agree with you here, because the DispHTMLWindow2 is actually a hidden window that is registered as a clipboard viewer, and allowing it to persist until the next GC (which could be when ?) is a needless waste of resources, only to avoid slightly-more complex code (e.g., assign the object to a variable and  call (vlax-release-object)).

With regards to COM and IUnknown, there is only one rule, which is that when you are finished using an Interface, you should release it. Relying on garbage collection to release a COM object is something that I would do, only if I knew for sure that whatever I was allowing the GC to clean up for me, is not consuming significant resources (e.g., memory and/or CPU cycles).  What any given COM object does when you release it, is a private implementation detail that we shouldn't be dependent on.
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: roy_043 on March 27, 2013, 02:51:46 PM
... there is only one rule, which is that when you are finished using an Interface, you should release it.
Point taken. Thanks again.

Code - Auto/Visual Lisp: [Select]
  1. ; Return value: string (empty string if the clipboard does not contain text) or nil.
  2. (defun newer-clipboard-get-text ( / clipboard html parent return)
  3.   (vl-catch-all-apply
  4.     (function
  5.       (lambda ()
  6.         (setq html (vlax-create-object "htmlfile"))
  7.         (setq parent (vlax-get html 'parentwindow))
  8.         (setq clipboard (vlax-get parent 'clipboarddata))
  9.         (setq return
  10.           (cond
  11.             ((vlax-invoke clipboard 'getdata "text"))
  12.             ("")
  13.           )
  14.         )
  15.       )
  16.     )
  17.   )
  18.   (if clipboard (vlax-release-object clipboard))
  19.   (if parent (vlax-release-object parent))
  20.   (if html (vlax-release-object html))
  21.   return
  22. )
  23.  
  24. ; Return value: string (read back from the clipboard) or nil.
  25. (defun newer-clipboard-put-text (str / clipboard html parent return)
  26.   (vl-catch-all-apply
  27.     (function
  28.       (lambda ()
  29.         (setq html (vlax-create-object "htmlfile"))
  30.         (setq parent (vlax-get html 'parentwindow))
  31.         (setq clipboard (vlax-get parent 'clipboarddata))
  32.         (vlax-invoke clipboard 'setdata "text" str)
  33.         (setq return (vlax-invoke clipboard 'getdata "text"))
  34.       )
  35.     )
  36.   )
  37.   (if clipboard (vlax-release-object clipboard))
  38.   (if parent (vlax-release-object parent))
  39.   (if html (vlax-release-object html))
  40.   return
  41. )
  42.  
  43. ; Return value: T or nil.
  44. (defun newer-clipboard-clear ( / clipboard html parent return)
  45.   (vl-catch-all-apply
  46.     (function
  47.       (lambda ()
  48.         (setq html (vlax-create-object "htmlfile"))
  49.         (setq parent (vlax-get html 'parentwindow))
  50.         (setq clipboard (vlax-get parent 'clipboarddata))
  51.         (vlax-invoke clipboard 'cleardata)
  52.         (setq return (not (vlax-invoke clipboard 'getdata "text")))
  53.       )
  54.     )
  55.   )
  56.   (if clipboard (vlax-release-object clipboard))
  57.   (if parent (vlax-release-object parent))
  58.   (if html (vlax-release-object html))
  59.   return
  60. )
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: TheMaster on March 27, 2013, 09:05:30 PM
... there is only one rule, which is that when you are finished using an Interface, you should release it.
Point taken. Thanks again.

You might want to also have a look at this:

Code - Text: [Select]
  1.  
  2. Command: MEM
  3.  
  4. Current memory use:    271,593,472 bytes
  5. Initial memory use     265,109,504 bytes
  6. Memory use net change:   6,483,968 bytes
  7.  
  8. Command: MEM
  9. Current memory use:    271,028,224 bytes
  10. Initial memory use     265,109,504 bytes
  11. Memory use net change:   5,918,720 bytes
  12.  
  13. Command: MEM
  14. Current memory use:    271,024,128 bytes
  15. Initial memory use     265,109,504 bytes
  16. Memory use net change:   5,914,624 bytes
  17.  
  18. Command: (SetClipboardText "FUBAR")
  19. -1
  20.  
  21. Command: MEM
  22. Current memory use:    275,255,296 bytes
  23. Initial memory use     265,109,504 bytes
  24. Memory use net change:  10,145,792 bytes   <----- LOOK
  25.  
  26. Command: MEM
  27. Current memory use:    275,255,296 bytes
  28. Initial memory use     265,109,504 bytes
  29. Memory use net change:  10,145,792 bytes
  30.  
  31. Command
  32.  
  33.  

MEM Command (C#):

Code - C#: [Select]
  1.  
  2.    [CommandMethod( "MEM" )]
  3.    public static void MemCommand()
  4.    {
  5.       Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  6.       GC.Collect( GC.MaxGeneration );
  7.       GC.WaitForPendingFinalizers();
  8.       System.Threading.Thread.Sleep( 1000 );
  9.       Process acad = Process.GetCurrentProcess();
  10.       long current = acad.WorkingSet64;
  11.  
  12.       ed.WriteMessage(
  13.             "\nCurrent memory use:    {0,11:#,###0} bytes",
  14.             current );
  15.  
  16.       if( initWorkingSet64 != 0L )
  17.       {
  18.          ed.WriteMessage(
  19.             "\nInitial memory use     {0,11:#,###0} bytes",
  20.             initWorkingSet64 );
  21.            
  22.          ed.WriteMessage(
  23.             "\nMemory use net change: {0,11:#,###0} bytes",
  24.             current - initWorkingSet64 );
  25.       }
  26.       else
  27.       {
  28.          initWorkingSet64 = current;
  29.       }
  30.    }
  31.  
  32.    static long initWorkingSet64 = 0L;
  33.  
  34.  


Title: Re: Foreign objects: is releasing the parent object enough?
Post by: roy_043 on March 28, 2013, 07:13:42 AM
Ah, so running the functions gobbles up a lot of memory. Does the mem consumption increase when the functions are used multiple times?

FWIW:
My guess is that this will never become an ideal solution. I am actually hoping that these functions will be added to the BricsCAD vle-* function set. My code, or similar code, would then only be used to emulate the functions for other CAD platforms. For compatibility reasons all vle-* functions have to be emulatable.
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: roy_043 on March 28, 2013, 07:59:14 AM
FWIW:
Code - Auto/Visual Lisp: [Select]
  1. ; newest-clipboard-helper
  2. ; Helper function used by other newest-clipboard-* functions.
  3. ; Possible values for option: "C" (clear), "R" (read) or "W" (write).
  4. ; For options "C" and "R" the str (string) argument in a dummy argument.
  5. ; Note: if option is "W" the clipboard is cleared first.
  6. ; Return value:
  7. ;   Option "C": T (success) or nil.
  8. ;   Option "R": string (empty string if the clipboard does not contain text) or nil.
  9. ;   Option "W": string (read back from the clipboard) or nil.
  10. (defun newest-clipboard-helper (str option / clipboard html parent return)
  11.   (vl-catch-all-apply
  12.     (function
  13.       (lambda ()
  14.         (setq html (vlax-create-object "htmlfile"))
  15.         (setq parent (vlax-get html 'parentwindow))
  16.         (setq clipboard (vlax-get parent 'clipboarddata))
  17.         (setq return
  18.           (cond
  19.             ((= (strcase option) "C")
  20.               (vlax-invoke clipboard 'cleardata)
  21.               (not (vlax-invoke clipboard 'getdata "text"))
  22.             )
  23.             ((= (strcase option) "R")
  24.               (cond
  25.                 ((vlax-invoke clipboard 'getdata "text"))
  26.                 ("")
  27.               )
  28.             )
  29.             ((= (strcase option) "W")
  30.               (vlax-invoke clipboard 'cleardata)
  31.               (vlax-invoke clipboard 'setdata "text" str)
  32.               (vlax-invoke clipboard 'getdata "text")
  33.             )
  34.           )
  35.         )
  36.       )
  37.     )
  38.   )
  39.   (if clipboard (vlax-release-object clipboard))
  40.   (if parent (vlax-release-object parent))
  41.   (if html (vlax-release-object html))
  42.   return
  43. )
  44.  
  45. ; newest-clipboard-clear
  46. ; Return value: T (success) or nil.
  47. (defun newest-clipboard-clear ()
  48.   (newest-clipboard-helper nil "C")
  49. )
  50.  
  51. ; newest-clipboard-get-text
  52. ; Return value: string (empty string if the clipboard does not contain text) or nil.
  53. (defun newest-clipboard-get-text ()
  54.   (newest-clipboard-helper nil "R")
  55. )
  56.  
  57. ; newest-clipboard-put-text
  58. ; Note: the clipboard is cleared first.
  59. ; Return value: string (read back from the clipboard) or nil.
  60. (defun newest-clipboard-put-text (str)
  61.   (newest-clipboard-helper str "W")
  62. )
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: TheMaster on March 28, 2013, 08:54:32 AM
Ah, so running the functions gobbles up a lot of memory. Does the mem consumption increase when the functions are used multiple times?


No, the increase happens on the first use of the interfaces, and remains constant after that. The memory isn't being used up by any clipboard-related data and clearing the clipboard doesn't release the memory, unfortunately.

Title: Re: Foreign objects: is releasing the parent object enough?
Post by: roy_043 on March 28, 2013, 04:06:49 PM
It could be worse, so let's call the glass half full.
Title: Re: Foreign objects: is releasing the parent object enough?
Post by: TheMaster on March 28, 2013, 05:05:18 PM
It could be worse, so let's call the glass half full.

To each his own, but this means of using the clipoboard isn't something that I could recommend in good conscience.

To further that, here's some C# code that can be compiled into a tiny DLL that takes care of the fly without the sledge hammer.

Code - C#: [Select]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows.Forms;
  6. using Autodesk.AutoCAD.DatabaseServices;
  7.  
  8. namespace Autodesk.AutoCAD.Runtime
  9. {
  10.    public static class VLClipboardHelper
  11.    {
  12.       /// <summary>
  13.       /// Returns the text contents of the
  14.       /// clipboard if it contains text, or
  15.       /// nil otherwise.
  16.       ///
  17.       /// Usage: (clipboard-get-text)
  18.       ///
  19.       /// </summary>
  20.  
  21.       [LispFunction( "CLIPBOARD-GET-TEXT" )]
  22.       public static string VLCBGetText( ResultBuffer unused )
  23.       {
  24.          if( Clipboard.ContainsText() )
  25.             return Clipboard.GetText();
  26.          else
  27.             return null;
  28.       }
  29.  
  30.       /// <summary>
  31.       /// Returns non-nil if the clipboard
  32.       /// contains text, or nil otherwise.
  33.       ///
  34.       /// Usage: (clipboard-contains-text)
  35.       ///
  36.       /// </summary>
  37.  
  38.       [LispFunction( "CLIPBOARD-CONTAINS-TEXT" )]
  39.       public static bool VLCBHasText( ResultBuffer unused )
  40.       {
  41.          return Clipboard.ContainsText();
  42.       }
  43.  
  44.       /// <summary>
  45.       /// Clears the clipboard of all contents.
  46.       ///
  47.       /// Usage: (clipboard-clear)
  48.       ///
  49.       /// </summary>
  50.  
  51.       [LispFunction( "CLIPBOARD-CLEAR" )]
  52.       public static void ClipboardClear( ResultBuffer unused )
  53.       {
  54.          Clipboard.Clear();
  55.       }
  56.  
  57.       /// <summary>
  58.       /// Places the given text on the clipboard.
  59.       ///
  60.       /// Usage: (clipboard-set-text <string>...)
  61.       ///
  62.       /// If multiple strings are provided, all but the
  63.       /// first argument are concatenated into a single
  64.       /// string using the first argument as a delimiter.
  65.       ///
  66.       /// Hence:
  67.       ///  
  68.       ///   (clipboard-set-text "," "Moe" "Larry" "Curly")
  69.       ///  
  70.       /// sets the clipboard text to "Moe,Larry,Curly"
  71.       ///
  72.       /// </summary>
  73.  
  74.       [LispFunction( "CLIPBOARD-SET-TEXT" )]
  75.       public static void VLCBSetText( ResultBuffer rb )
  76.       {
  77.          const int RTSTR = (int) LispDataType.Text;
  78.          const string errmsg = "Requires one or more strings";
  79.          if( rb == null )
  80.             throw new ArgumentException( errmsg );
  81.          TypedValue[] items = rb.AsArray();
  82.          if( items.Length == 0 )
  83.             throw new ArgumentException( errmsg );
  84.          TypedValue first = items[0];
  85.          if( first.TypeCode != RTSTR )
  86.             throw new ArgumentException( errmsg );
  87.          string text = (string) first.Value;
  88.          if( items.Length > 1 )
  89.          {
  90.             if( !items.All( tv => tv.TypeCode == RTSTR ) )
  91.                throw new ArgumentException( errmsg );
  92.             var rest = items.Skip( 1 ).Select( tv => (string) tv.Value );
  93.             text = string.Join( text, rest );
  94.          }
  95.          Clipboard.SetText( text );
  96.       }
  97.    }
  98. }
  99.  
  100.  

If anyone that wants to use this doesn't have VS Express installed or can't for some other reason compile this, I'm sure someone here can do that and post the NETLOADable DLL.