TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: Kerry on November 02, 2005, 08:24:31 PM

Title: error: null interface pointer ..
Post by: Kerry on November 02, 2005, 08:24:31 PM
I've spent the last day or so trying to track down an intermittent error in an associates code.

I'll post more on this later, as time allows ; unless someone else fills in the gaps.

Long story short :

AutoDesk help files and some commentators recommend the following functionality ..
Code: [Select]
;;--------------------------------
(setq *acad-object* nil)                          ; Initialize global variable
(defun acad-object ()
  (cond (*acad-object*)                           ; Return the cached object
        (t (setq *acad-object* (vlax-get-acad-object)))
  )
)
;;--------------------------------
(setq *active-document* nil)                      ; Initialize global variable
(defun active-document ()
  (cond (*active-document*)                       ; Return the cached object
        (t (setq *active-document* (vla-get-activedocument (acad-object))))
  )
)
;;--------------------------------
(setq *model-space* nil)                          ; Initialize global variable
(defun model-space ()
  (cond (*model-space*)                           ; Return the cached object
        (t (setq *model-space* (vla-get-modelspace (active-document))))
  )
)
;;--------------------------------

 with the idea that it will be called like this ..

Code: [Select]
....
(setq myCircle (vla-addCircle (model-space)   (vlax-3d-point '(3.0 3.0 0.0)) 2.0))
....

If you are currently using code similar to that posted, it may be time to have another look at it .. and try something like this :
Code: [Select]
;;; ----- Release Bound Activex Objects --------------------------
;;;
(defun releaseObjects (ListOfQuotedVarnames / tmp)
  (foreach varname ListOfQuotedVarnames
    (if (= (type (setq tmp (vl-symbol-value varname))) 'vla-object)
      (if (not (vlax-object-released-p tmp))
        (vlax-release-object tmp)
      )
    )
    (set varname nil)
  )
)
;;--------------------------------
(releaseObjects (list '*model-space* '*active-document* '*acad-object*))

;;--------------------------------                     
(defun acad-object ()
  (cond ((and *acad-object* (not (vlax-object-released-p *acad-object*)))
         *acad-object*
        )
        (t (setq *acad-object* (vlax-get-acad-object)))
  )
)
;;--------------------------------                 
(defun active-document ()
  (cond ((and *active-document*
              (not (vlax-object-released-p *active-document*))
         )
         *active-document*
        )
        (t (setq *active-document* (vla-get-activedocument (acad-object))))
  )
)
;;--------------------------------                       
(defun model-space ()
  (cond ((and *model-space* (not (vlax-object-released-p *model-space*)))
         *model-space*
        )
        (t (setq *model-space* (vla-get-modelspace (active-document))))
  )
)
;;--------------------------------

The original code was causing an issue because he <sometimes> ran this sort of code :-
Code: [Select]
;; Global variables
 (setq thisDoc (active-document)
       mspace  (model-space)
 )
  ;;
  ;; bla, bla
  ;;
  (vlax-release-object mspace)
  (vlax-release-object thisDoc)
  ;;
  ;; bla, bla
  ;; 


Because his variable mspace  and the Global *model-space* pointed to the same object ;
 releasing that object using the mspace variable resulted in the *model-space* variable returning something invalid like this #<VLA-OBJECT 00000000>

.. So .. as well as testing that the variable exists, also check that it holds a legitimate value ie: hasn't been released.
.. hence the optional code.

kwb
Title: Re: error: null interface pointer ..
Post by: CAB on November 02, 2005, 09:02:40 PM
Forgive me for asking a dumb question but why wouldn't you use something like this?
Code: [Select]
(defun model-space ()
  (vla-get-modelspace (vla-get-activedocument (vlax-get-acad-object)))
)
Title: Re: error: null interface pointer ..
Post by: Kerry on November 02, 2005, 09:13:22 PM
From the Docs ..
Quote
Performance Considerations :

Repeated calls to access the AutoCAD Application, active Document, and ModelSpace objects should be avoided, as they negatively impact performance. You should design your applications to obtain these objects one time, and refer to the obtained object pointers throughout the application.


So theoretically, .. its better to assign it once and use the variable, rather than repeatedly burrow down into the Object Model.
Title: Re: error: null interface pointer ..
Post by: Kerry on November 02, 2005, 09:16:50 PM
There is an issue even if the variables are local ..

Try this ; alternatively using the AutoDesk code preloaded, then mine preloaded ..
Code: [Select]
(defun c:Test (/ mspace myCircle)
  (setq mspace (model-space))
  (setq myCircle (vla-addcircle mspace (vlax-3d-point '(3.0 3.0 0.0)) 2.0))
  (vlax-release-object mspace)
)
Title: Re: error: null interface pointer ..
Post by: Kerry on November 02, 2005, 09:25:34 PM
PS : I'm not going to suggest for a moment that this assignment be done any one particular way. ... Just that there is an issue if you blindly follow the code published by AutoDesk and some commentators.  ... as has been done in the code I was testing/debugging.
Title: Re: error: null interface pointer ..
Post by: CAB on November 02, 2005, 09:31:51 PM
Yes I get an error with the ACAD version.
Code: [Select]
Command: test
; error: null interface pointer: #<VLA-OBJECT 00000000>
; reset after error
Title: Re: error: null interface pointer ..
Post by: CAB on November 02, 2005, 09:33:36 PM
I'm off to add this to my library of 'Borrowed Code'

Thanks Kerry
Title: Re: error: null interface pointer ..
Post by: Kerry on November 02, 2005, 09:35:18 PM
heh, Test it first ...  :lmao:

no problems Alan.
Title: Re: error: null interface pointer ..
Post by: MP on November 02, 2005, 09:36:13 PM
Right or wrong here's my take Kerry  --

I dropped the use of wrapped globals for activedocument etc. long ago for a number of reasons, including the testing that the wrappers tend to do.

Instead I tend to write functions so they take the activedocument, modelspace, or layers collection etc. as an argument. The calling function is shouldered with the responsibility to pass a valid argument, and for any subsequent cleanup etc. Any overhead associated with repeated calls to create the object is avoided IF the caller takes care of setting aside a reference to said object before making the functions calls.

In it's simplest form.

Code: [Select]
(defun c:MtProggy ( / foo main )

    (defun foo ( object )
        ;;  foo takes an object, but doesn't
        ;;  care how it comes into existance
        ...
    )

    (defun main ( / object )

        ;;  create the object
   
        (setq object
            (SomeCallThatResultsInObject)
        )

        ;;  use the object ad nauseum
       
        (repeat (SomeCallThatReturnsIterationCount)
            (foo object)
        )

        ;;  dump it
       
        (vl-catch-all-apply
           '(lambda ( )
                (vlax-release-object object)
            )
        )
       
        (princ)
       
    )
   
    (main)

)

No worries of double references, things going out of scope etc. Perhaps I look at this too simplistically, but this works and performs well for me.

/2˘
Title: Re: error: null interface pointer ..
Post by: Kerry on November 02, 2005, 09:42:03 PM
Quote
... Perhaps I look at this too simplistically, but this works and performs well for me.

I concur .. About it working well.
Title: Re: error: null interface pointer ..
Post by: Kerry on November 02, 2005, 09:47:08 PM
User Beware :

The solution I was trying to demonstrate in this particular case suited the circumstances because the calling shown was used extensively. Reworking the wrapped stuff seemed the most expedient solution .. though not the best long term, perhaps.
Title: Re: error: null interface pointer ..
Post by: LE on November 02, 2005, 10:22:48 PM
I only use vlax-release-object on code like this:

Code: [Select]
  (setq vlaLock (vlax-create-object "xxxxxxx.xxxxxxxx"))
  (if (and vlaLock (= (type vlaLock) 'vla-object))
    (progn
      (vlax-put-property
vlaLock
'SoftwareName
dtt_softname)
      (vlax-put-property vlaLock 'LiberationKeyLength dtt_num)
...
      ;; release the activex control
      (vlax-release-object vlaLock)
      (gc))
Title: Re: error: null interface pointer ..
Post by: Sdoman on November 02, 2005, 10:36:11 PM
Interesting topic.

I've been using code for a few years now that is almost exactly as the AutoDesk sample code shown in the first post to this thread.  But I've never had a problem with a null pointer or anything like that (to my knowledge).
 
Title: Re: error: null interface pointer ..
Post by: LE on November 02, 2005, 10:45:48 PM
There is only few cases when a release is needed on visual lisp code.
Title: Re: error: null interface pointer ..
Post by: Kerry on November 02, 2005, 10:56:56 PM
This exact situation is one of the reasons why I attempt to use unique names for any global variables I use.
All it takes is for code in a VLX or FAS that the user has no control over to use code as demonstrated with the same variable names as you and the whole lot falls down.
Title: Re: error: null interface pointer ..
Post by: Sdoman on November 02, 2005, 11:00:42 PM
This exact situation is one of the reasons why I attempt to use unique names for any global variables I use.
All it takes is for code in a VLX or FAS that the user has no control over to use code as demonstrated with the same variable names as you and the whole lot falls down.


Agreed.  That's why I try to use unique names.  You never now when some (bozo) user might run some poorly written code that he/she downloaded from some forum some where. :)
Title: Re: error: null interface pointer ..
Post by: LE on November 02, 2005, 11:02:34 PM
How about using a protected namespace VLX.... there we don't have any problema.
Title: Re: error: null interface pointer ..
Post by: Kerry on November 02, 2005, 11:03:45 PM
There is only few cases when a release is needed on visual lisp code.

Agreed Luis. When referencing objects other than from the AutoCAD Object Model primarily.
Title: Re: error: null interface pointer ..
Post by: MP on November 02, 2005, 11:04:06 PM
There is only few cases when a release is needed on visual lisp code.

Yep, like when you use vla-GetInterfaceObject, vlax-get-object, vlax-create-object ...

(ot: good idea to obscure your team support control).

<nodding.gif>
Title: Re: error: null interface pointer ..
Post by: Kerry on November 02, 2005, 11:04:45 PM
How about using a protected namespace VLX.... there we don't have any problema.

Yep, just need to make sure the correct Document is referenced :)



Quote
(ot: good idea to obscure your team support control).
Yes, I noticed that too

Title: Re: error: null interface pointer ..
Post by: MP on November 02, 2005, 11:05:13 PM
Cool timing.

 :kewl:
Title: Re: error: null interface pointer ..
Post by: Sdoman on November 02, 2005, 11:07:56 PM
How about using a protected namespace VLX.... there we don't have any problema.

I never learned how to do the protected namespace thing.  But it's time I learned.  What's the best way to get started?  I read the help files and they just made my eyes glaze over.
Title: Re: error: null interface pointer ..
Post by: LE on November 02, 2005, 11:13:16 PM

(ot: good idea to obscure your team support control).

<nodding.gif>

Did not want it to show my bad manners....  :kewl:
Title: Re: error: null interface pointer ..
Post by: LE on November 02, 2005, 11:15:08 PM
I never learned how to do the protected namespace thing.  But it's time I learned.  What's the best way to get started?  I read the help files and they just made my eyes glaze over.

If you need help on that... let me know Steve.

I got the impression that ALL the help stuff from adesk was very clear......   :evil: [ahaaaaa]
Title: Re: error: null interface pointer ..
Post by: Sdoman on November 02, 2005, 11:19:07 PM

If you need help on that... let me know Steve.

I got the impression that ALL the help stuff from adesk was very clear......   :evil: [ahaaaaa]


HELP!
 
Title: Re: error: null interface pointer ..
Post by: LE on November 02, 2005, 11:24:24 PM
Don't know if can be good idea to post code about that here... or it will be better to send you a code sample via PM... or.....
Title: Re: error: null interface pointer ..
Post by: Kerry on November 02, 2005, 11:26:51 PM
Perhaps use a new topic in   Show your stuff Luis.
That way access is restricted to logged in members.
Title: Re: error: null interface pointer ..
Post by: CAB on November 02, 2005, 11:28:16 PM
As far as release is concerned, is it only when you create an object or also when you do this?
Code: [Select]
(setq obj (vlax-ename->vla-object ename))that you need to release the object.

I gather that this code need no release?
Title: Re: error: null interface pointer ..
Post by: Sdoman on November 02, 2005, 11:28:27 PM
Luis,

Thanks for the help.  Maybe we should start a new topic.  I'm sure others would be interested in knowing how to make protected name space files.
Title: Re: error: null interface pointer ..
Post by: Kerry on November 02, 2005, 11:28:54 PM
BTW. Thanks for the input guys. This turned into a really interesting thread.
Title: Re: error: null interface pointer ..
Post by: LE on November 02, 2005, 11:30:15 PM
As far as release is concerned, is it only when you create an object or also when you do this?
Code: [Select]
(setq obj (vlax-ename->vla-object ename))that you need to release the object.

I gather that this code need no release?

No.
Title: Re: error: null interface pointer ..
Post by: Sdoman on November 02, 2005, 11:31:30 PM
BTW. Thanks for the input guys. This turned into a really interesting thread.


As so to conclude, the answer was...
Title: Re: error: null interface pointer ..
Post by: Sdoman on November 02, 2005, 11:34:22 PM
To use code that validates whether an object is released before reassigning.
To use unique symbol names.
To use a protected namespace.
To do whatever MP suggested (it was over my head)
Title: Re: error: null interface pointer ..
Post by: Kerry on November 02, 2005, 11:38:19 PM
Something else that MAY be interesting

(setq xxDoc (vla-get-activedocument (vlax-get-acad-object)))
;->> #<VLA-OBJECT IAcadDocument 01270930>

(vlax-release-object xxDoc)
;->> 3   <- This is the current reference count on the Active document.


(repeat 100
   (setq xxDoc (vla-get-activedocument (vlax-get-acad-object)))
)

(vlax-release-object xxDoc)
;->> 102 <- This is the current reference count on the Active document.
;;  can be released with Garbage collection .. ? ?  ?
Title: Re: error: null interface pointer ..
Post by: Sdoman on November 02, 2005, 11:42:48 PM
Quote
hmmmm...... I tried there, but had no luck at-all.... I think it will be better if I just grab some of my PRJ projects and send it via PM.....

Ok Luis if you would rather, please PM me.  But It's getting late in the evening here.  So I may not be able to reply until tommorrow.
Title: Re: error: null interface pointer ..
Post by: Kerry on November 02, 2005, 11:43:34 PM
More Here :- http://www.theswamp.org/forum/index.php?topic=2005.0
Title: Re: error: null interface pointer ..
Post by: Sdoman on November 03, 2005, 12:15:01 AM
More Here :- http://www.theswamp.org/forum/index.php?topic=2005.0

A good read Kerry.  So to release or not release continues to puzzle.
Title: Re: error: null interface pointer ..
Post by: MP on November 03, 2005, 06:47:37 AM
A good read Kerry. So to release or not release continues to puzzle.

So it seems. That last post was a rather bleak conclusion.

:(
Title: Re: error: null interface pointer ..
Post by: LE on November 03, 2005, 10:03:39 AM
The following description is still basically the same as it was from Vital Lisp help.....

"No memory is necessarily freed when you issue vlax-release-object, but AutoCAD can reclaim the memory if needed, once all references to the object have been released."
Title: Re: error: null interface pointer ..
Post by: whdjr on November 03, 2005, 10:07:19 AM
Right or wrong here's my take Kerry  --

I dropped the use of wrapped globals for activedocument etc. long ago for a number of reasons, including the testing that the wrappers tend to do.

Instead I tend to write functions so they take the activedocument, modelspace, or layers collection etc. as an argument. The calling function is shouldered with the responsibility to pass a valid argument, and for any subsequent cleanup etc. Any overhead associated with repeated calls to create the object is avoided IF the caller takes care of setting aside a reference to said object before making the functions calls.

In it's simplest form.

Code: [Select]
(defun c:MtProggy ( / foo main )

    (defun foo ( object )
        ;;  foo takes an object, but doesn't
        ;;  care how it comes into existance
        ...
    )

    (defun main ( / object )

        ;;  create the object
   
        (setq object
            (SomeCallThatResultsInObject)
        )

        ;;  use the object ad nauseum
       
        (repeat (SomeCallThatReturnsIterationCount)
            (foo object)
        )

        ;;  dump it
       
        (vl-catch-all-apply
           '(lambda ( )
                (vlax-release-object object)
            )
        )
       
        (princ)
       
    )
   
    (main)

)

No worries of double references, things going out of scope etc. Perhaps I look at this too simplistically, but this works and performs well for me.

/2˘

I didn't realize you could name your defun's as arguments.  How exactly would that help you?  How come you don't get some kind of error?  That is kinda weird to think about. :lol:
Title: Re: error: null interface pointer ..
Post by: MP on November 03, 2005, 10:15:10 AM
Eh?

The defuns are locals, not arguments, though you can write functions that take functions as arguments (as demonstrated elsewhere).

:)
Title: Re: error: null interface pointer ..
Post by: CAB on November 03, 2005, 11:28:10 AM
Will,
Code: [Select]
;;=======================
(defun c:test1 ()
  (defun foo ()
    (print "Test1 - foo.")
  )
  (foo)
  (princ)
)
(c:test1)
(print (type foo))
(setq foo nil)


;;=======================
(defun c:test2 (/ foo)
  (defun foo ()
    (print "Test2 - foo.")
  )
  (foo)
  (princ)
)
(c:test2)
(print (type foo))
(print)
;;=======================

"Test1 - foo."
USUBR
"Test2 - foo."
nil
Title: Re: error: null interface pointer ..
Post by: whdjr on November 03, 2005, 11:38:04 AM
Sorry...I mis-typed earlier...I meant "I didn't realize you could have defun's as local variables?".

And I still don't see the importance in why you would do that.  I see CAB's explanation but I am still asking:
1.  Where would you use that set up?
2.  Why would you use that set up?
3.  How would you even think to use that set up? :|

I know I would not have thought to use defuns and locals.  I know it localizes your defun but what would you gain from doing that?
Title: Re: error: null interface pointer ..
Post by: whdjr on November 03, 2005, 11:39:40 AM
So does that mean any time I have a 'nested' defun I should also name it as a local (as good coding practice)?
Title: Re: error: null interface pointer ..
Post by: Sdoman on November 04, 2005, 08:43:04 AM
So does that mean any time I have a 'nested' defun I should also name it as a local (as good coding practice)?

Yes, that's right.  Let me see if I can explain without muffing it up....

If you have a c:function that requires some subfunctions that are designed to be used only for that c:function, then I personally prefer to embed them inside the c:function and declare them local.

The reasoning is that by embedding these particular dedicated subfunctions inside the c:function and delcaring them local, I know that they are used only for that c:function and I don't have to worry about them over writting, or being overwritten, by some other lisp routine that happens to be lurking out there, and happens to have a function with the same name.

Thus it is a good practice to declare local variables and local subs, so that when the routine ends, it leaves the lisp environment squeaky clean.

One downside however, to embedding local subfunctions inside c:functions is that every time the user invokes the c:function, those subs are reloaded.  That's sort of a waste of time to continually reload the subs, but with the fast PC's we all have now, the time usually isn't perceived by the user.  If on the other hand I had some huge subfunction that took a lot of time to load, then I might locate that fat sub outside of the c:function and just call it just like a toolbox function.

For those subfunctions that might be useable for other routines, then I always put them in a toolbox lisp file which I have setup to load automatically when the drawing is opened. These toolbox subs are not declared local.

Does that help?





Title: Re: error: null interface pointer ..
Post by: CAB on November 04, 2005, 08:47:12 AM
That was a good explanation. :-)
Title: Re: error: null interface pointer ..
Post by: MP on November 04, 2005, 08:56:43 AM
Good job Steve.

Here's a related thread started by ... Will DeLoach=> link (http://www.theswamp.org/forum/index.php?topic=3215.msg39894#msg39894).

:)
Title: Re: error: null interface pointer ..
Post by: MP on November 04, 2005, 09:01:26 AM
On nesting and performance here's one that may be interesing => link (http://www.theswamp.org/forum/index.php?topic=4064.msg48404#msg48404).

Or not.
Title: Re: error: null interface pointer ..
Post by: MP on November 04, 2005, 09:04:34 AM
As is this one => link (http://www.theswamp.org/forum/index.php?topic=4144.msg49441#msg49441).

Very interesting indeed.

:)
Title: Re: error: null interface pointer ..
Post by: whdjr on November 04, 2005, 10:11:08 AM
Excellent job on the explanation Steve.  However if my brain was worth a fart I might remember this discussion from earlier as MP pointed out.
Good job Steve.

Here's a related thread started by ... Will DeLoach=> link (http://www.theswamp.org/forum/index.php?topic=3215.msg39894#msg39894).

:)

Thanks for the reminder MP.  It seems most things go in one ear and out the other these days.  Just too much work to remember anything.
Title: Re: error: null interface pointer ..
Post by: Sdoman on November 04, 2005, 03:02:42 PM
Thanks for the kudos you all. 

I started to read the threads that MP referred to.  They look very interesting indeed, but I'm going to have to go back and read them later when I have more time.  Thanks!
Title: Re: error: null interface pointer ..
Post by: Kerry on November 09, 2005, 08:45:32 AM
Something else that MAY be interesting
>>>>>

(vlax-release-object xxDoc)
;->> 3   <- This is the current reference count on the Active document.


>>>>>

I've had second thought about the value returned from (vlax-release-object ...
It is undocumented in the help files, and despite my best guesses, I cant demonstrate with certainty what this number represents.



Title: Re: error: null interface pointer ..
Post by: Glenn R on January 21, 2006, 09:39:19 PM
Hmmm...interesting discussion (which I missed originally).

Here's my 2 bucks worth.

From my C++ COM development I learned a lot of things, in particular about the internal working of a COM object as far as the low level C++ side is concerned and a few more general concepts, but the most important is this:

1. C++ is difficult; COM is hard; GOOD COM is very hard.

Throughout this thread, there was much mention of 'pointers' to objects and the like, but I believe there are some misconceptions about those magic 'pointers'.
In a nutshell, a COM Class holds an internal reference to the object it is describing and for all intents and purposes it is static. Think of it like a global lisp variable, or a private internal variable (for the .NET people).

Now, the FIRST time some chunk of code asks for this 'object', the COM component spins up an instance of it's internal object, and here's the important bit, creates a NEW POINTER TO THE INTERFACE of the OBJECT (AddRef), NOT a pointer to the internal object itself. The internal OBJECT is created only ONCE - EVER.

The next thing it does, is increment it's INTERFACE reference counter by one and pass back the pointer. At this time the calling code can do what it likes.
Remember, this is a pointer to an INTERFACE, NOT THE INTERNAL OBJECT as such. This process is repeated again and again as required by the clients of this COM object.

Now, to release or not? One of the classic 'bad' things about COM is memory management (leaks) and this comes about through the reference counting that the COM Object implements (badly in this case) and calling code.

Setting a COM object reference to nil/nothing/null is SUPPOSED to inform the COM CLASS OBJECT to decrement it's internal reference count by one. This process repeats again and again, untill the internal counter reaches 0. When this happens, the COM Class object destroys it's internal object (the real one you're interested in) and frees the memory allocated by this object back to the pool.

As far as the release question goes, I would adopt the same pattern as in C++ - if you NEW'em, DELETE'em...pure and simple. And I suspect the reason releasing the acad object doesn't ever get the count to 0 is that AutoCAD itself is hanging onto some interface pointers for internal reasons (vlisp being one). Let's face it, you wouldn't want the reference count to the Acad Application itself to reach 0 whilst your code was running would you?

Just some ramblings that may or may not help.

Cheers,
Glenn.