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

0 Members and 1 Guest are viewing this topic.

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Foreign objects: is releasing the parent object enough?
« Reply #15 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. )

TheMaster

  • Guest
Re: Foreign objects: is releasing the parent object enough?
« Reply #16 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.
« Last Edit: March 26, 2013, 11:21:07 PM by TT »

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Foreign objects: is releasing the parent object enough?
« Reply #17 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. )

TheMaster

  • Guest
Re: Foreign objects: is releasing the parent object enough?
« Reply #18 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.  


« Last Edit: March 27, 2013, 09:10:55 PM by TT »

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Foreign objects: is releasing the parent object enough?
« Reply #19 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.
« Last Edit: March 28, 2013, 07:18:03 AM by roy_043 »

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Foreign objects: is releasing the parent object enough?
« Reply #20 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. )

TheMaster

  • Guest
Re: Foreign objects: is releasing the parent object enough?
« Reply #21 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.

« Last Edit: March 28, 2013, 08:58:42 AM by TT »

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Foreign objects: is releasing the parent object enough?
« Reply #22 on: March 28, 2013, 04:06:49 PM »
It could be worse, so let's call the glass half full.

TheMaster

  • Guest
Re: Foreign objects: is releasing the parent object enough?
« Reply #23 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.