ComatePlus question.

Just starting out? Need help? Post your questions and find answers here.
User avatar
leonhardt
Enthusiast
Enthusiast
Posts: 220
Joined: Wed Dec 23, 2009 3:26 pm

ComatePlus question.

Post by leonhardt »

Hello Comate masters,I tried to link to OPC server but get some error,could you please point out where I am wrong?

Code: Select all

;xinclude comateplus.pbi; Varianthelper_include.pb

Procedure LE()
  Protected s.s=comate_getlasterrordescription()
  If s<>"Okay."
    Debug s
  EndIf
EndProcedure




*sa.SAFEARRAY=saCreateSafeArray(#TString,1,2)
SA_BSTR(*sa,1)=@"Applications.Application_1.CraneControl.i_WindSpeed.Value"
SA_BSTR(*sa,2)=@"Applications.Application_1.CraneControl.i_ElhouseTempAnalogInput.Value"

*sb.SAFEARRAY=saCreateSafeArray(#TLong,1,2)
SA_LONG(*sb,1)=1
SA_LONG(*sb,2)=2

*sc.SAFEARRAY=saCreateSafeArray(#TLong,1,2)
*sd.SAFEARRAY=saCreateSafeArray(#TLong,1,2)


V_ARRAY_STR(ItemAr.variant)=*sa
V_ARRAY_LONG(CHandleAr.variant)=*sb

V_ARRAY_LONG(SHandleAr.variant)=*sc
V_ARRAY_LONG(ErrorAr.variant)=*sd

opc.comateobject=comate_createobject("opc.automation.1")
opc\invoke("connect('abb.ac800mc_opcdaserver.3')")

gp.comateobject=opc\getobjectproperty("opcgroups\add")

items.comateobject=gp\getobjectproperty("opcitems")

items\invoke("additems(2,"+Str(ItemAr)+" as variant ,"+Str(CHandleAr)+" as variant ,"+
             Str(SHandleAr)+" as variant byref,"+Str(ErrorAr)+" as variant byref,#opt,#opt)")

le()

I always get the "Type mismatch in the method parameters." error, the AddItems method is like this:AddItems (Count As Long, ItemIDs() As String, ClientHandles() As Long, ByRef
ServerHandles() As Long, ByRef Errors() As Long, Optional RequestedDataTypes As Variant,
Optional AccessPaths As Variant)

and the same VB code runs well:

Code: Select all

Option Explicit
Dim opc As New OPCServer, gp As OPCGroup, items As OPCItems
Dim ItemAr(1 To 2) As String, CHandleAr(1 To 2) As Long, SHandleAr() As Long, ErrorAr() As Long
Dim a&, b&, va, vb, vc, vd

Private Sub Form_Load()
opc.Connect "abb.ac800mc_opcdaserver.3"
Set gp = opc.OPCGroups.Add
Set items = gp.OPCItems
ItemAr(1) = "Applications.Application_1.CraneControl.i_WindSpeed.Value"
ItemAr(2) = "Applications.Application_1.CraneControl.i_ElhouseTempAnalogInput.Value"
CHandleAr(1) = 1
CHandleAr(2) = 2

items.AddItems 2, ItemAr, CHandleAr, SHandleAr, ErrorAr

End Sub

I think maybe something wrong with my safe array handling. thanks for the help!
poor English...

PureBasic & Delphi & VBA
User avatar
mk-soft
Always Here
Always Here
Posts: 5409
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: ComatePlus question.

Post by mk-soft »

1.
SafeArray String are types BSTR

Code: Select all

*sa.SAFEARRAY=saCreateSafeArray(#TString,1,2)
SA_BSTR(*sa,1)=T_BSTR("Applications.Application_1.CraneControl.i_WindSpeed.Value")
SA_BSTR(*sa,2)=T_BSTR("Applications.Application_1.CraneControl.i_ElhouseTempAnalogInput.Value")
2.
COMatePlus don't support Variant with SafeArray ...

I don't know how to support this at time.

3.
VBA Dim String() as String is not a Variant. Is direct an SafeArray. But Dispatch.Invoke need DispParams for the Parameters ...

Link: http://vb.mvps.org/tips/vb5dll/
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
mk-soft
Always Here
Always Here
Posts: 5409
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: ComatePlus question.

Post by mk-soft »

I have started to call the OPC-Automation without COMate direct. Partly the parameters are direct, or Array (SafeArray) and partly Variant or Variant ByRef.
All this must be read from the documentation.

Project on my ONEDRIVE

The OPC-Automation-1.pbi is not completely corrected, because some methods have a return value and this value is still missing in the parameters.

Parameter as String is a BStr. Convert by PB (Interface p-bstr)
Parameter as Variant is ByVal. Copy by PB (Interface p-variant)
Parameter as Variant ByRef is a Pointer to Variant. Local variable of type variant
Parameter as Array is a variable with pointer to a SafeArray. Create by API

As you can see it is already very complex ...
Example

Code: Select all

;-TOP

IncludeFile "ComHelper.pb"
IncludeFile "OPC-Automation-1.pbi"
IncludeFile "VariantHelper_Include.pb"
;IncludeFile "VariantHelper.pb"

Global *OpcAutomation.IUnknown
Global *OpcServer.IOPCAutoServer
Global *OpcGroups.IOPCGroups
Global *OPCGroup.IOPCGroup
Global *OPCItems.OPCItems

Debug "*** CreateObject OPC Automation ***"
*OpcAutomation = CreateObject("OPC.Automation.1")
If Not *OpcAutomation
  Debug "Error CreateObject OPC Automation"
  End
EndIf

Debug "Query OPCAutoServer"
r1 = *OpcAutomation\QueryInterface(?IID_IOPCAutoServer, @*OpcServer)
If r1
  Debug FormatMessage(r1)
  End
EndIf

Debug "Connect to SPS"
Define Node.Variant
r1 = *OpcServer\Connect("INAT TCPIPH1 OPC Server", Node)
If r1
  Debug FormatMessage(r1)
  End
EndIf

Debug "Get OPCGroups"
r1 = *OpcServer\get_OPCGroups(@*OpcGroups)
If r1
  Debug FormatMessage(r1)
  End
EndIf

Debug "Add Group"
GroupName.variant
V_STR(GroupName) = T_BSTR("MyGroup")
r1 = *OpcGroups\Add(GroupName, @*OPCGroup)
If r1
  Debug FormatMessage(r1)
  End
EndIf

Debug "Get OPCItems"
r1 = *OpcGroup\get_OPCItems(@*OPCItems)
If r1
  Debug FormatMessage(r1)
  End
EndIf

Debug "Add Items"
Define.SAFEARRAY *Items, *ClientHandles, *ServerHandles, *Errors
*Items = saCreateSafeArray(#VT_BSTR, 1, 3)
SA_BSTR(*Items, 1) = T_BSTR("s7-test.mb4")
SA_BSTR(*items, 2) = T_BSTR("s7-test.mb5")
SA_BSTR(*items, 3) = T_BSTR("s7-test.mb6")
*ClientHandles = saCreateSafeArray(#VT_I4, 1, 3)
SA_LONG(*ClientHandles, 1) = 1
SA_LONG(*ClientHandles, 2) = 2
SA_LONG(*ClientHandles, 3) = 3


r1 = *OPCItems\AddItems(3, @*Items, @*ClientHandles , @*ServerHandles, @*Errors, type.variant, access.variant)
If r1
  Debug FormatMessage(r1)
EndIf

Debug "- ServerHandles"
For i = saLBound(*ServerHandles) To saUBound(*ServerHandles)
  Debug "" + i + ": " + SA_LONG(*ServerHandles, i)
Next

Debug "- Errors"
For i = saLBound(*Errors) To saUBound(*Errors)
  Debug "" + i + ": " + SA_LONG(*Errors, i)
Next

saFreeSafeArray(*Errors)

Debug "Group SyncRead"
Define.SAFEARRAY *Values, *Errors 
Define Qualities.Variant, Timestamps.Variant

; Die letzen beide Parameter sind bei ByRef und es muss ein leeren variant übergeben werden.
r1 = *OPCGroup\SyncRead(#OPCDevice, 3, @*ServerHandles, @*Values, @*Errors, @Qualities, @Timestamps)
If r1
  Debug FormatMessage(r1)
EndIf

Debug "- Errors"
vartype = saGetVartype(*Errors)
For i = saLBound(*Errors) To saUBound(*Errors)
  Select vartype
    Case #VT_I2
      Debug "" + i + ": " + SA_WORD(*Errors, i)
    Case #VT_I4
      Debug "" + i + ": " + SA_LONG(*Errors, i)
  EndSelect
Next

Debug "- Qualities"
Dim Qualities(1)

If Qualities\vt & #VT_ARRAY
  *psa.SAFEARRAY = Qualities\parray
  vartype = saGetVartype(*psa)
  For i = saLBound(*psa) To saUBound(*psa)
    Select vartype
      Case #VT_I2
        Debug "" + i + ": " + SA_WORD(*psa, i)
      Case #VT_I4
        Debug "" + i + ": " + SA_LONG(*psa, i)
    EndSelect
  Next
EndIf

saFreeSafeArray(*Errors)
saFreeSafeArray(*Values)

Debug "OPCItems Remove"
r1 = *OPCItems\Remove(3, @*ServerHandles, @*Errors)
If r1
  Debug FormatMessage(r1)
EndIf

saFreeSafeArray(*Errors)
saFreeSafeArray(*ServerHandles)

Debug "OPCGroups RemoveAll"
r1 = *OPCGroups\RemoveAll()
If r1
  Debug FormatMessage(r1)
EndIf

Debug "OPCServer Disconnect"
r1 = *OpcServer\Disconnect()
If r1
  Debug FormatMessage(r1)
EndIf

Debug "OPCServer Release"
r1 = *OpcServer\Release()
If r1 < 0
  Debug FormatMessage(r1)
EndIf

Debug "OPCAutomation Release"
r1 = *OpcAutomation\Release()
If r1 < 0
  Debug FormatMessage(r1)
EndIf
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
leonhardt
Enthusiast
Enthusiast
Posts: 220
Joined: Wed Dec 23, 2009 3:26 pm

Re: ComatePlus question.

Post by leonhardt »

mk-soft wrote:I have started to call the OPC-Automation without COMate direct. Partly the parameters are direct, or Array (SafeArray) and partly Variant or Variant ByRef.
All this must be read from the documentation.

Project on my ONEDRIVE

The OPC-Automation-1.pbi is not completely corrected, because some methods have a return value and this value is still missing in the parameters.

Parameter as String is a BStr. Convert by PB (Interface p-bstr)
Parameter as Variant is ByVal. Copy by PB (Interface p-variant)
Parameter as Variant ByRef is a Pointer to Variant. Local variable of type variant
Parameter as Array is a variable with pointer to a SafeArray. Create by API

As you can see it is already very complex ...
Example

Code: Select all

;-TOP

IncludeFile "ComHelper.pb"
IncludeFile "OPC-Automation-1.pbi"
IncludeFile "VariantHelper_Include.pb"
;IncludeFile "VariantHelper.pb"

Global *OpcAutomation.IUnknown
Global *OpcServer.IOPCAutoServer
Global *OpcGroups.IOPCGroups
Global *OPCGroup.IOPCGroup
Global *OPCItems.OPCItems

Debug "*** CreateObject OPC Automation ***"
*OpcAutomation = CreateObject("OPC.Automation.1")
If Not *OpcAutomation
  Debug "Error CreateObject OPC Automation"
  End
EndIf

Debug "Query OPCAutoServer"
r1 = *OpcAutomation\QueryInterface(?IID_IOPCAutoServer, @*OpcServer)
If r1
  Debug FormatMessage(r1)
  End
EndIf

Debug "Connect to SPS"
Define Node.Variant
r1 = *OpcServer\Connect("INAT TCPIPH1 OPC Server", Node)
If r1
  Debug FormatMessage(r1)
  End
EndIf

Debug "Get OPCGroups"
r1 = *OpcServer\get_OPCGroups(@*OpcGroups)
If r1
  Debug FormatMessage(r1)
  End
EndIf

Debug "Add Group"
GroupName.variant
V_STR(GroupName) = T_BSTR("MyGroup")
r1 = *OpcGroups\Add(GroupName, @*OPCGroup)
If r1
  Debug FormatMessage(r1)
  End
EndIf

Debug "Get OPCItems"
r1 = *OpcGroup\get_OPCItems(@*OPCItems)
If r1
  Debug FormatMessage(r1)
  End
EndIf

Debug "Add Items"
Define.SAFEARRAY *Items, *ClientHandles, *ServerHandles, *Errors
*Items = saCreateSafeArray(#VT_BSTR, 1, 3)
SA_BSTR(*Items, 1) = T_BSTR("s7-test.mb4")
SA_BSTR(*items, 2) = T_BSTR("s7-test.mb5")
SA_BSTR(*items, 3) = T_BSTR("s7-test.mb6")
*ClientHandles = saCreateSafeArray(#VT_I4, 1, 3)
SA_LONG(*ClientHandles, 1) = 1
SA_LONG(*ClientHandles, 2) = 2
SA_LONG(*ClientHandles, 3) = 3


r1 = *OPCItems\AddItems(3, @*Items, @*ClientHandles , @*ServerHandles, @*Errors, type.variant, access.variant)
If r1
  Debug FormatMessage(r1)
EndIf

Debug "- ServerHandles"
For i = saLBound(*ServerHandles) To saUBound(*ServerHandles)
  Debug "" + i + ": " + SA_LONG(*ServerHandles, i)
Next

Debug "- Errors"
For i = saLBound(*Errors) To saUBound(*Errors)
  Debug "" + i + ": " + SA_LONG(*Errors, i)
Next

saFreeSafeArray(*Errors)

Debug "Group SyncRead"
Define.SAFEARRAY *Values, *Errors 
Define Qualities.Variant, Timestamps.Variant

; Die letzen beide Parameter sind bei ByRef und es muss ein leeren variant übergeben werden.
r1 = *OPCGroup\SyncRead(#OPCDevice, 3, @*ServerHandles, @*Values, @*Errors, @Qualities, @Timestamps)
If r1
  Debug FormatMessage(r1)
EndIf

Debug "- Errors"
vartype = saGetVartype(*Errors)
For i = saLBound(*Errors) To saUBound(*Errors)
  Select vartype
    Case #VT_I2
      Debug "" + i + ": " + SA_WORD(*Errors, i)
    Case #VT_I4
      Debug "" + i + ": " + SA_LONG(*Errors, i)
  EndSelect
Next

Debug "- Qualities"
Dim Qualities(1)

If Qualities\vt & #VT_ARRAY
  *psa.SAFEARRAY = Qualities\parray
  vartype = saGetVartype(*psa)
  For i = saLBound(*psa) To saUBound(*psa)
    Select vartype
      Case #VT_I2
        Debug "" + i + ": " + SA_WORD(*psa, i)
      Case #VT_I4
        Debug "" + i + ": " + SA_LONG(*psa, i)
    EndSelect
  Next
EndIf

saFreeSafeArray(*Errors)
saFreeSafeArray(*Values)

Debug "OPCItems Remove"
r1 = *OPCItems\Remove(3, @*ServerHandles, @*Errors)
If r1
  Debug FormatMessage(r1)
EndIf

saFreeSafeArray(*Errors)
saFreeSafeArray(*ServerHandles)

Debug "OPCGroups RemoveAll"
r1 = *OPCGroups\RemoveAll()
If r1
  Debug FormatMessage(r1)
EndIf

Debug "OPCServer Disconnect"
r1 = *OpcServer\Disconnect()
If r1
  Debug FormatMessage(r1)
EndIf

Debug "OPCServer Release"
r1 = *OpcServer\Release()
If r1 < 0
  Debug FormatMessage(r1)
EndIf

Debug "OPCAutomation Release"
r1 = *OpcAutomation\Release()
If r1 < 0
  Debug FormatMessage(r1)
EndIf
@MK_Soft Thank you very much for your solution, I will try to learn it :D
poor English...

PureBasic & Delphi & VBA
User avatar
mk-soft
Always Here
Always Here
Posts: 5409
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: ComatePlus question.

Post by mk-soft »

Here one must work very precisely, otherwise the program will crash.
It is enough to pass an array with faulty ServerHandles which leads to a crash.

Online Update available
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
mk-soft
Always Here
Always Here
Posts: 5409
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: ComatePlus question.

Post by mk-soft »

A new update.

I have updated the interface OPCDAAUTO, because the existing one is not error-free. File OPCAutomationV202.pbi.
I have created this file with Pelles-C COM Load Type Library and translated it from 'C' to PB.

Tool: viewtopic.php?f=27&t=75790
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
leonhardt
Enthusiast
Enthusiast
Posts: 220
Joined: Wed Dec 23, 2009 3:26 pm

Re: ComatePlus question.

Post by leonhardt »

@mk-soft
yeah I have downloaded all the source files and been playing with them :D , just for curious, it seems that pb is far more difficult and complex to do the opc stuff than vb,what dev tools are you using for develop opc like apps? :mrgreen:
poor English...

PureBasic & Delphi & VBA
User avatar
mk-soft
Always Here
Always Here
Posts: 5409
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: ComatePlus question.

Post by mk-soft »

This is the difference between object oriented programming (Purebasic) and object oriented programming language (VB)

What VB does for you in the background is creating the variables in the right format and creating pulls for GetObject or 'CreateObject -> ReleaseObject', that you have to do in Purebasic by yourself (Like in 'C').

Example:
VB: "Set gp = opc.OPCGroups.Add("MyGroup")"
In the background VB fetches the object with r1 = *OPCServer\get_OPCGroups -> *OPCGroups, creates the variable MyGroup.Variant as BSTR, calls the method r1 = *OPCGroups\Add(Name) -> *OPCGroup.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
leonhardt
Enthusiast
Enthusiast
Posts: 220
Joined: Wed Dec 23, 2009 3:26 pm

Re: ComatePlus question.

Post by leonhardt »

mk-soft wrote:This is the difference between object oriented programming (Purebasic) and object oriented programming language (VB)

What VB does for you in the background is creating the variables in the right format and creating pulls for GetObject or 'CreateObject -> ReleaseObject', that you have to do in Purebasic by yourself (Like in 'C').

Example:
VB: "Set gp = opc.OPCGroups.Add("MyGroup")"
In the background VB fetches the object with r1 = *OPCServer\get_OPCGroups -> *OPCGroups, creates the variable MyGroup.Variant as BSTR, calls the method r1 = *OPCGroups\Add(Name) -> *OPCGroup.
Well I 've already knew something different between PB and VB,so I tried to use COMateplus which should not be more complex than vb,everything was as expected until this topic , when I invoked the AddItems method.
poor English...

PureBasic & Delphi & VBA
Post Reply