Announcement

Collapse
No announcement yet.

3rd Party COM not working with PB9

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • 3rd Party COM not working with PB9

    Here where I work we use motion controllers to control our machines. Currently we are using Galil Motion Controllers (www.galilmc.com).

    Anyways I was talking to their tech guy the other day and he suggested I use the new API, because the stuff I am using is no longer updated.

    He told me it was now COM and not the typical DLL like their old stuff.

    I have never tried to use COM before, but it seemed pretty straight forward in PB9. So I generated the code with the PB COM Browser looked at some examples and tried to make a small sample program that would connect to the controller and message me back the value of a variable on the controller.

    I connected fine, but it seems any method with arguments does not work correctly.

    Below I have an example of me connecting to the controller (Galil.address = "" just brings up a list of available controllers). Then I attempt to get the value of a variable called CONFIG on the controller, but I receive nothing back even though I know I am connected because I can view active connections in GalilTools.

    I know most of you are not familiar with Galil, but I was wondering if someone would take a look my code and see if anything looks wrong or out of place.

    Include File for COM (I ended up trying Jose's TypeLib Browser 4.0.11, with same results):
    Code:
    ' ########################################################################################
    ' Library name: Galil
    ' Version: 0.1, Locale ID = 0
    ' Description: Galil
    ' Path: C:\Program Files\Galil\GalilTools-x86\lib\Galil.tlb
    ' Library GUID: {30A08063-D424-4206-9631-AE91CF80C678}
    ' Code generated by the TypeLib Browser 4.0.11 (c) 2008 by José Roca
    ' Date: 27 Oct 2008   Time: 08:59:44
    ' ########################################################################################
    
    ' ========================================================================================
    ' ClsIDs (Class identifiers)
    ' ========================================================================================
    
    $CLSID_Galil = GUID$("{D70CFDB0-E481-480C-A29C-6F60FC044B38}")
    
    ' ========================================================================================
    ' IIDs (Interface identifiers)
    ' ========================================================================================
    
    $IID_Events = GUID$("{67E9C73D-896A-440C-88DD-D0AC82AB7569}")
    $IID_IGalil = GUID$("{F1F88B2C-881A-4D82-9F99-60A84691387D}")
    
    ' ########################################################################################
    ' Interface name = IGalil
    ' IID = {F1F88B2C-881A-4D82-9F99-60A84691387D}
    ' Attributes = 4160 [&H1040] [Dual] [Dispatchable]
    ' Inherited interface = IDispatch
    ' ########################################################################################
    
    #IF NOT %DEF(%IGalil_INTERFACE_DEFINED)
        %IGalil_INTERFACE_DEFINED = 1
    
    INTERFACE IGalil $IID_IGalil
    
       INHERIT IDispatch
    
       ' =====================================================================================
       METHOD libraryVersion <1610743808> ( _               ' VTable offset = 28
       ) AS STRING                                          ' [retval][out] *retval VT_BSTR
       ' =====================================================================================
       PROPERTY SET address <1610743809> ( _                ' VTable offset = 32
         BYVAL STRING _                                     ' [in] VT_BSTR
       )                                                    ' void
       ' =====================================================================================
       METHOD connection <1610743810> ( _                   ' VTable offset = 36
       ) AS STRING                                          ' [retval][out] *retval VT_BSTR
       ' =====================================================================================
       PROPERTY SET timeout_ms <1610743811> ( _             ' VTable offset = 40
         BYVAL LONG _                                       ' [in] retval VT_INT <Long>
       )                                                    ' void
       ' =====================================================================================
       PROPERTY GET timeout_ms <1610743811> ( _             ' VTable offset = 44
       ) AS LONG                                            ' [retval][out] *retval VT_INT <Long>
       ' =====================================================================================
       METHOD command <1610743813> ( _                      ' VTable offset = 48
         OPTIONAL BYVAL STRING _                            ' [opt][in] command VT_BSTR [default value = "MG TIME"]
       , OPTIONAL BYVAL STRING _                            ' [opt][in] terminator VT_BSTR [default value = "$CR"]
       , OPTIONAL BYVAL STRING _                            ' [opt][in] ack VT_BSTR [default value = ":"]
       , OPTIONAL BYVAL INTEGER _                           ' [opt][in] trim VT_BOOL <Integer> [default value = -1]
       ) AS STRING                                          ' [retval][out] *retval VT_BSTR
       ' =====================================================================================
       METHOD commandValue <1610743814> ( _                 ' VTable offset = 52
         OPTIONAL BYVAL STRING _                            ' [opt][in] command VT_BSTR [default value = "MG TIME"]
       ) AS DOUBLE                                          ' [retval][out] *retval VT_R8 <Double>
       ' =====================================================================================
       METHOD programUpload <1610743815> ( _                ' VTable offset = 56
       ) AS STRING                                          ' [retval][out] *retval VT_BSTR
       ' =====================================================================================
       METHOD programDownload <1610743816> ( _              ' VTable offset = 60
         OPTIONAL BYVAL STRING _                            ' [opt][in] program VT_BSTR [default value = "MG TIME[$CR]EN"]
       )                                                    ' void
       ' =====================================================================================
       METHOD programUploadFile <1610743817> ( _            ' VTable offset = 64
         OPTIONAL BYVAL STRING _                            ' [opt][in] file VT_BSTR [default value = "program.dmc"]
       )                                                    ' void
       ' =====================================================================================
       METHOD programDownloadFile <1610743818> ( _          ' VTable offset = 68
         OPTIONAL BYVAL STRING _                            ' [opt][in] file VT_BSTR [default value = "program.dmc"]
       )                                                    ' void
       ' =====================================================================================
       METHOD arrayUpload <1610743819> ( _                  ' VTable offset = 72
         OPTIONAL BYVAL STRING _                            ' [opt][in] name VT_BSTR [default value = "array"]
       ) AS VARIANT                                         ' [retval][out] *retval VT_VARIANT <Variant>
       ' =====================================================================================
       METHOD arrayDownload <1610743820> ( _                ' VTable offset = 76
         BYVAL VARIANT _                                    ' [in] array VT_VARIANT <Variant>
       , OPTIONAL BYVAL STRING _                            ' [opt][in] name VT_BSTR [default value = "array"]
       )                                                    ' void
       ' =====================================================================================
       METHOD arrayUploadFile <1610743821> ( _              ' VTable offset = 80
         OPTIONAL BYVAL STRING _                            ' [opt][in] file VT_BSTR [default value = "arrays.csv"]
       , OPTIONAL BYVAL STRING _                            ' [opt][in] names VT_BSTR [default value = ""]
       )                                                    ' void
       ' =====================================================================================
       METHOD arrayDownloadFile <1610743822> ( _            ' VTable offset = 84
         OPTIONAL BYVAL STRING _                            ' [opt][in] file VT_BSTR [default value = "arrays.csv"]
       )                                                    ' void
       ' =====================================================================================
       METHOD firmwareDownloadFile <1610743823> ( _         ' VTable offset = 88
         OPTIONAL BYVAL STRING _                            ' [opt][in] file VT_BSTR [default value = "firmware.hex"]
       )                                                    ' void
       ' =====================================================================================
       METHOD write <1610743824> ( _                        ' VTable offset = 92
         OPTIONAL BYVAL STRING _                            ' [opt][in] bytes VT_BSTR [default value = "$CR"]
       ) AS LONG                                            ' [retval][out] *retval VT_INT <Long>
       ' =====================================================================================
       METHOD read <1610743825> ( _                         ' VTable offset = 96
       ) AS STRING                                          ' [retval][out] *retval VT_BSTR
       ' =====================================================================================
       METHOD sources <1610743826> ( _                      ' VTable offset = 100
       ) AS VARIANT                                         ' [retval][out] *retval VT_VARIANT <Variant>
       ' =====================================================================================
       METHOD recordsStart <1610743827> ( _                 ' VTable offset = 104
         OPTIONAL BYVAL DOUBLE _                            ' [opt][in] period_ms VT_R8 <Double> [default value = -1]
       )                                                    ' void
       ' =====================================================================================
       METHOD record <1610743828> ( _                       ' VTable offset = 108
         OPTIONAL BYVAL STRING _                            ' [opt][in] method VT_BSTR [default value = "QR"]
       ) AS VARIANT                                         ' [retval][out] *retval VT_VARIANT <Variant>
       ' =====================================================================================
       METHOD sourceValue <1610743829> ( _                  ' VTable offset = 112
         BYVAL VARIANT _                                    ' [in] record VT_VARIANT <Variant>
       , OPTIONAL BYVAL STRING _                            ' [opt][in] source VT_BSTR [default value = "TIME"]
       ) AS DOUBLE                                          ' [retval][out] *retval VT_R8 <Double>
       ' =====================================================================================
       METHOD sourceUnits <1610743830> ( _                  ' VTable offset = 116
         OPTIONAL BYVAL STRING _                            ' [opt][in] source VT_BSTR [default value = "TIME"]
       ) AS STRING                                          ' [retval][out] *retval VT_BSTR
       ' =====================================================================================
       METHOD sourceDescription <1610743831> ( _            ' VTable offset = 120
         OPTIONAL BYVAL STRING _                            ' [opt][in] source VT_BSTR [default value = "TIME"]
       ) AS STRING                                          ' [retval][out] *retval VT_BSTR
       ' =====================================================================================
    
    END INTERFACE
    
    #ENDIF   ' /* __IGalil_INTERFACE_DEFINED__ */
    My test code:
    Code:
    'Galil COMM Test
    
    #INCLUDE "Galil.inc"
    
    function PBMAIN()
    	static Galil as IGalil, GalilEvents as EventsImpl
    	
    	Galil = NEWCOM CLSID $CLSID_Galil
    	
    	IF isnothing(Galil) THEN
    			MSGBOX "Unable to create an object refrence to the Galil Interface."
    			exit function
    	end if
    	
    	GalilEvents = CLASS "CEvents"
    	
    	EVENTS FROM Galil CALL GalilEvents
    
    	Galil.address = ""
    
    	Galil.connection()
    	
    	sleep 500
    
    	msgbox Galil.command("CONFIG=?")
    
    end function
    
    ' ########################################################################################
    ' Class CEvents
    ' Interface name = Events
    ' IID = {67E9C73D-896A-440C-88DD-D0AC82AB7569}
    ' Attributes = 4096 [&H1000] [Dispatchable]
    ' Code generated by the TypeLib Browser 4.0.11 (c) 2008 by José Roca
    ' Date: 27 Oct 2008   Time: 09:03:04
    ' ########################################################################################
    
    CLASS CEvents GUID$("{3EC72A2F-5294-475D-B7CF-6590ACD7B250}") AS EVENT
    
    INTERFACE EventsImpl GUID$("{67E9C73D-896A-440C-88DD-D0AC82AB7569}") AS EVENT
    
      INHERIT IDispatch
    
       ' =====================================================================================
       METHOD onInterrupt <0> ( _
         BYVAL status AS LONG _                             ' [in] status VT_INT <Long>
       )                                                    ' VOID
    
         ' *** Insert your code here ***
    
       END METHOD
       ' =====================================================================================
    
       ' =====================================================================================
       METHOD onMessage <1> ( _
         BYVAL message AS STRING _                          ' [in] message VT_BSTR
       )                                                    ' VOID
    
         ' *** Insert your code here ***
    
       END METHOD
       ' =====================================================================================
    
       ' =====================================================================================
       METHOD onRecord <2> ( _
         BYVAL record AS VARIANT _                          ' [in] record VT_VARIANT <Variant>
       )                                                    ' VOID
    
         ' *** Insert your code here ***
    
       END METHOD
       ' =====================================================================================
    
    END INTERFACE
    
    END CLASS
    Thank you,
    Ryan M. Cross

  • #2
    Make sure all string parameters use unicode UCODE$()

    James

    Comment


    • #3
      As James said, you have to use Unicode strings:

      msgbox ACODE$(Galil.command(UCODE$("CONFIG=?")))
      Forum: http://www.jose.it-berater.org/smfforum/index.php

      Comment


      • #4
        Ryan,
        Having worked with Galil products before, and working with COM for my company's Motion Controllers I have to ask where the samples for Galil can be downloaded? If I can see their VB version, I think I put 2 and 2 together what the port to PB would be. (and it would go a LONNNNNNG way for me learning the ins and outs of COM itself as well)

        That aside, most likely the strings do need to be Unicode, or something not set to tell Galil to get ready to receive commands.
        Engineer's Motto: If it aint broke take it apart and fix it

        "If at 1st you don't succeed... call it version 1.0"

        "Half of Programming is coding"....."The other 90% is DEBUGGING"

        "Document my code????" .... "WHYYY??? do you think they call it CODE? "

        Comment


        • #5
          Excellent, works perfect.

          Thank you,
          Ryan M. Cross

          Comment


          • #6
            Originally posted by Cliff Nichols View Post
            Ryan,
            Having worked with Galil products before, and working with COM for my company's Motion Controllers I have to ask where the samples for Galil can be downloaded? If I can see their VB version, I think I put 2 and 2 together what the port to PB would be. (and it would go a LONNNNNNG way for me learning the ins and outs of COM itself as well)

            That aside, most likely the strings do need to be Unicode, or something not set to tell Galil to get ready to receive commands.
            Cliff they give you quite a few simple examples in different languages with their GalilTools utility (lite or regular[$]). If you install the latest GalilTools there are examples in the C:\Program Files\Galil\GalilTools-x86\lib\ directory. They also have documentation in the GalilTools help file.

            One thing I did find was that the .command method must be called with its defaults otherwise it seems to not work correctly.

            For example:

            DOES NOT WORK -
            msgbox acode$(Galil.command(ucode$("CONFIG=?")))

            WORKS -
            msgbox acode$(Galil.command(ucode$("CONFIG=?"), ucode$($CR), ucode$(":"), -1))
            Thank you,
            Ryan M. Cross

            Comment


            • #7
              So it appears that when an error is received its in the way of an "Object error (99)". For example is a send a bad command to the controller like this (EI is not valid on this controller):

              Code:
              Try
              msgbox acode$(Galil.command(ucode$("EI"), ucode$($CR), ucode$(":"), -1))
              Catch
              Msgbox ERROR$ & " (" & str$(Err) & ")"
              End Try
              Now in their Visual Basic 6 example all they do to display the actual error that the controller threw is:

              Code:
              On Error GoTo Catch1 
                      g.Command ("EI") 
              Catch1:
                      Text1.Text = Err.Description + vbNewLine
              In VB6 Err.Description is detailed error that the controller threw:
              2010 COMMAND ERROR. Galil::command("EI") got ? instead of : response. TC1 returned "1 Unrecognized command"

              How do I get that in PB9? Or is it not possible?
              Thank you,
              Ryan M. Cross

              Comment


              • #8
                The actual error code is returned by OBJRESULT, not ERR. The documentation of Galil should provide a list of error codes.
                Last edited by José Roca; 28 Oct 2008, 08:09 AM.
                Forum: http://www.jose.it-berater.org/smfforum/index.php

                Comment


                • #9
                  This is directly from the Galil documentation:

                  The exceptions thrown by the Galil class were designed to allow for easy debugging by providing human-readable information. No error-code table needs to be referenced by the programmer as the error information is included in the error. All thrown objects are strings. String search functions or error codes can be used to determine the nature of an error.
                  Example 1. Using string functions to programmatically handle thrown errors (below is a partial Try/Catch handler)
                  VB.NET Example
                  Code:
                  Catch exception As System.Runtime.InteropServices.COMException
                      Console.WriteLine(exception) 'print error message
                      If exception.Message.Contains("COMMAND ERROR") Then
                          Console.WriteLine("a command error occurred") 'special processing for command errors
                      End If
                  End Try
                  So since there is no error table, the question is. How do I get the string?
                  Last edited by RyanCross; 27 Oct 2008, 12:07 PM.
                  Thank you,
                  Ryan M. Cross

                  Comment


                  • #10
                    Give the IDISPINFO pseudo-object's IDISPINFO.DESC$ a try.
                    Dominic Mitchell
                    Phoenix Visual Designer
                    http://www.phnxthunder.com

                    Comment


                    • #11
                      Originally posted by Dominic Mitchell View Post
                      Give the IDISPINFO pseudo-object's IDISPINFO.DESC$ a try.
                      I thought so too, but OBJRESULT returns an %E_FAIL and not a %DISP_E_EXCEPTION.
                      Thank you,
                      Ryan M. Cross

                      Comment


                      • #12
                        In VB6 Err.Description is detailed error that the controller threw:
                        2010 COMMAND ERROR. Galil::command("EI") got ? instead of : response. TC1 returned "1 Unrecognized command"

                        How do I get that in PB9? Or is it not possible?
                        Do not use VTbl binding. Use ID binding(set the generate Dispatch interfaces flag in your COM browser).

                        For example, your code converted to use ID binding
                        Code:
                          LOCAL oGalil      AS GalilGalil
                          LOCAL sAddress    AS STRING
                          LOCAL sCommand    AS STRING
                          LOCAL sResult     AS STRING
                          LOCAL sParam1     AS STRING
                          LOCAL sParam2     AS STRING
                          LOCAL sParam3     AS STRING
                          LOCAL fTrim       AS LONG
                        
                          oGalil = NEWCOM clsid $CLSID_GALILGALIL
                        
                          IF ISNOTHING(oGalil) THEN
                              MSGBOX "Unable to create an object refrence to the Galil Interface."
                              EXIT FUNCTION
                          END IF
                        
                          OBJECT LET oGalil.address = sAddress
                        MSGBOX "IDISPINFO.DESC$:" + IDISPINFO.DESC$
                        
                          OBJECT CALL oGalil.connection() TO sResult
                          MSGBOX "connection:" + ACODE$(sResult)
                        MSGBOX "IDISPINFO.DESC$:" + IDISPINFO.DESC$
                        
                          SLEEP 500
                        
                          sParam1 = UCODE$("CONFIG=?")
                          sParam2 = UCODE$($CR)
                          sParam3 = UCODE$(":")
                          fTrim   = -1
                          OBJECT CALL oGalil.command(sParam1, sParam2, sParam3, fTrim) TO sResult
                        MSGBOX "IDISPINFO.DESC$:" + IDISPINFO.DESC$  
                          MSGBOX "command:" + ACODE$(sResult)
                        
                          MSGBOX "hresult:" + HEX$(OBJRESULT)
                        Produces the following output on my system using a utility I wrote. This matches the output of IDISPINFO.DESC$.
                        Notice in the output below an exception is thrown(DISP_E_EXCEPTION) and the error code reported
                        by the control is E_FAIL. The error code value can vary.
                        Code:
                        CoCreateInstance
                           rclsid       = {D70CFDB0-E481-480C-A29C-6F60FC044B38}
                           pUnkOuter    = 0x00000000
                           dwClsContext = (0x5)CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER
                           riid         = {00020400-0000-0000-C000-000000000046} IDISPATCH                   
                           ppv          = 0x00B04F08
                           hr           = 0x00000000: The operation completed successfully.
                        
                        
                        
                        IDispatch::Invoke
                           pThis        = 0x00928E50
                           dispIdMember = 0x60020001
                           riid         = {00000000-0000-0000-0000-000000000000}
                           lcid         = 2048
                           hr           = 0x80020009: Exception occurred.
                        
                        
                        
                        HRESULT - &H80020009: Exception occurred.
                        
                        Function: <&H60020001>
                        Argument: 
                        
                        ErrorCode - &H80004005: Unspecified error
                        
                        1011 TIMEOUT ERROR.  Galil::command("") took longer than 500 ms to read : response.
                        
                        
                        Source - Galil
                        
                        HelpFile: 
                        HelpContextId: 0
                        IDispatch::Invoke
                           pThis        = 0x00928E50
                           dispIdMember = 0x60020002
                           riid         = {00000000-0000-0000-0000-000000000000}
                           lcid         = 2048
                           hr           = 0x80020009: Exception occurred.
                        
                        
                        
                        HRESULT - &H80020009: Exception occurred.
                        
                        Function: <&H60020002>
                        Argument: 
                        
                        ErrorCode - &H80004005: Unspecified error
                        
                        9230 UNINITIALIZED OBJECT ERROR.  Galil::connection() called without Galil::address set
                        
                        
                        Source - Galil
                        
                        HelpFile: 
                        HelpContextId: 0
                        IDispatch::Invoke
                           pThis        = 0x00928E50
                           dispIdMember = 0x60020005
                           riid         = {00000000-0000-0000-0000-000000000000}
                           lcid         = 2048
                           hr           = 0x80020009: Exception occurred.
                        
                        
                        
                        HRESULT - &H80020009: Exception occurred.
                        
                        Function: <&H60020005>
                        Argument: 
                        
                        ErrorCode - &H80004005: Unspecified error
                        
                        9020 UNINITIALIZED OBJECT ERROR.  Galil::command() called without Galil::address set
                        
                        
                        Source - Galil
                        
                        HelpFile: 
                        HelpContextId: 0
                        IIDispatch_Release
                        Dominic Mitchell
                        Phoenix Visual Designer
                        http://www.phnxthunder.com

                        Comment


                        • #13
                          Wow Dominic you rock. I really owe you one for putting in the effort to help me. Thank you to everyone else who helped as well. This forum is awesome.
                          Thank you,
                          Ryan M. Cross

                          Comment

                          Working...
                          X