Author Topic: why the param can not return the value?  (Read 2836 times)

0 Members and 1 Guest are viewing this topic.

guohq

  • Newt
  • Posts: 84
why the param can not return the value?
« on: August 31, 2014, 09:07:20 AM »
I create a project in vs2010 and the com interop is checked.
here is the code:

Public Class PointEx
        Public Function GetPointZCoord(ByVal Pt As Object, ByRef ZCoord As Double) As Boolean
            Try
                If Pt Is Nothing OrElse Pt.ObjectName <> "AcDbPoint" Then
                    Return False
                End If

                Dim Coord() As Double = Pt.Coordinates()
                ZCoord = Coord(2)
                Return True
            Catch ex As Exception
                Return False
            End Try
        End Function
    End Class

 Then,I call the function with lisp in autocad:

(setq ptTool (vlax-create-object "VLispEx.PointEx"))
(setq Z 0)
(vlax-invoke ptTool 'GetPointZCoord (vlax-ename->vla-object (car (entsel))) Z)
(vlax-release-object ptTool)


At last,the value of param Z is still 0,it dosen't has any change.Can you tell me why?

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: why the param can not return the value?
« Reply #1 on: September 01, 2014, 04:10:57 AM »
Lisp (well AutoLisp) works the other way round. Instead of telling the function that its parameter is referencing something from outside, you tell the place where you call the function that the argument you're sending it needs to be "by reference". In Lisp this is rather referred to as sending the symbol name instead of the symbol's value. Also the function needs to work on the assumption (or test for) that the parameter is a symbol name instead of a value.

So when writing something like this in Lisp, you'd have done something like:
Code - Auto/Visual Lisp: [Select]
  1. (defun GetPointZCoord(Pt ZCoord / Coord)
  2.   (and Pt ;Check if point object
  3.        (= (type Pt) 'vla-Object) ;Check if VLA object
  4.        (eq (vla-get-ObjectName Pt) "AcDbPoint") ;Check if point object
  5.        (setq Coord (vlax-get Pt 'Coordinates)) ;And get coordinates
  6.        (= (type ZCoord) 'Sym) ;Check if ZCoord is passed in as a symbol name
  7.        (set ZCoord (nth 2 Coord)) ;Check if Z can be set into symbol parameter
  8.   )
  9. )

Note when setting the value to the ZCoord parameter it's first checked to see if it is just a symbol name. Then it uses SET instead of SETQ, i.e. use the symbol name inside the variable instead of quoting the variable's name and then setting that. Now when calling that function, you need to quote the "variable" passed in as the ZCoord argument - i.e. you're quoting it outside the function which is going to set it.

Here's a sample from ACad's command-line:
Code: [Select]
Command: (GetPointZCoord (vlax-ename->vla-object (car (entsel))) 'Z)
Select object: T
Command: !Z
2000.0
Notice the ' prefix to Z - short hand for writing (quote Z).

Now, you're working from the DotNet side. If what you're after is to set the argument in Lisp from within DotNet - that's a whole new ballgame. Unfortunately ADesk's interaction between DotNet and Lisp do not cater for these things - all arguments passed in to DotNet is converted to a ResultBuffer list and is always only passed in as ByValue. Not to mention, DotNet doesn't accept vla-objects as arguments to its LispFunction methods - you'd simply need to send it the ename as obtained from (car (ensel)) instead.

To get around this issue though you can "simulate" something like a ByRef parameter, by expecting a string naming the symbol in the ZCoord parameter's place. This you do using the document object's SetLispSymbol method - see an example use here: http://adndevblog.typepad.com/autocad/2014/08/set-or-get-lisp-symbol-in-net.html

Edit: Sorry I see you're making Com-interop. Well perhaps this works, just call that function in the same way you'd call it if it was written in Lisp as above - i.e. prefix the Z value with a quote. E.g. that's how you'd call the standard ActiveX GetBoundingBox method:
Code - Auto/Visual Lisp: [Select]
  1. (vla-GetBoundingBox obj 'MinCoord ' MaxCoord)
After which MinCoord would contain the "bottom left 3d point as a safearray of variants, as would the MaxCoord contain that of the top-right.

If the same happens for your custom Com exported function I've never really tested. Perhaps you've found a better way to get this working than that convoluted SetLispSymbol idea.
« Last Edit: September 01, 2014, 04:53:09 AM by irneb »
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

guohq

  • Newt
  • Posts: 84
Re: why the param can not return the value?
« Reply #2 on: September 01, 2014, 08:24:59 PM »
Although the problem is not resolved,thank you all the same.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: why the param can not return the value?
« Reply #3 on: September 02, 2014, 05:28:36 AM »
Although the problem is not resolved,thank you all the same.
So you mean it doesn't work if you do this:
Code - Auto/Visual Lisp: [Select]
  1. (vlax-invoke ptTool 'GetPointZCoord (vlax-ename->vla-object (car (entsel))) 'Z)

What if you go with the vlax-invoke-method call instead:
Code - Auto/Visual Lisp: [Select]
  1. (vlax-invoke-method ptTool 'GetPointZCoord (vlax-ename->vla-object (car (entsel))) 'Z)

I've seen some strange stuff happen due to weird differences between those two.

Unfortunately if this simply "will not work" you're stuck with rather exporting the function as a LispFunction from the DotNet side instead of going through ActiveX.

Also you haven't mentioned how you made the VB code you have COM visible. Did you follow the steps in section 1 of this tut?
https://www.simple-talk.com/dotnet/visual-studio/build-and-deploy-a-.net-com-assembly/

Most important you have to make a Com-Visible Interface, which your class then needs to implement. And also you'd need to register it with proper GUIDs.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

guohq

  • Newt
  • Posts: 84
Re: why the param can not return the value?
« Reply #4 on: September 02, 2014, 07:31:28 AM »
This function 'vlax-invoke-method‘ achieve  my goals! Thank you! :evil:

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: why the param can not return the value?
« Reply #5 on: September 02, 2014, 08:23:29 AM »
This function 'vlax-invoke-method‘ achieve  my goals! Thank you! :evil:
Awesome, glad you got it sorted!
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.