In ETAS INCA, how can I extract specific calibration values by accessing the COM-API via VBA? - vba

I'm trying to construct a VBA script that opens INCA and extracts specific calibration values.
To start, I found a Youtube video by ETAS (https://www.youtube.com/watch?v=OQAvE0UT5xk), and I copied the code from there:
Private Function inca_com_api() As Variant
Dim Inca As Object
Dim DB As Object
Dim DBname As String
Dim devices() As Variant
Dim calValue As Variant
Set Inca = CreateObject("inca.inca")
Set DB = Inca.GetCurrentDataBase
DBname = DB.GetName
inca_com_api = DBname
Inca.DisconnectFromTool
End Function
The code opens INCA and runs as intended, returning the database name, but what I want is not the database name, but specific calibration values.
I was under the impression that I could just use the API functions listed in the User's Guide for INCA-MIP (https://www.etas.com/en/downloadcenter/18008.php), which is the INCA COM-API interface package for Matlab.
I don't have INCA-MIP, I just thought I could call those functions through VBA, by using the same function name or similar function names.
But when I try code like:
devices() = DB.IncaGetDevices
or
devices() = DB.GetDevices
or
devices() = Inca.IncaGetDevices
or
devices() = Inca.GetDevices
or the same variations of GetCalibrationValue, IncaGetCalibrationValue, I get:
Run-time error '438': Object doesn't support this property or method
I was planning to use IncaGetDevices to show me a device name, which I could then use as an input argument for IncaGetCalibrationValue, for each of my specific calibration names that I want returned.
Again, I don't have INCA-MIP, but I am wondering how I can return these calibration values using the VBA and the COM-API for INCA?
Also, I tried looking through the following posts for answers:
In ETAS INCA, is there a way to quickly retrieve an item from an arbitrary path in an ASAP2Project?
In ETAS INCA, what classes correspond to each type of database item?
but I don't really know what they're talking about.
Any help would be appreciated, thanks

Related

SolidWorks VBA - Translating API Help into useable code

I'd like to do what feels like a fairly simple task, and I've found the specific API Help pages which should make it clear, but, I can't actually make things work.
The Key steps that I would like to achieve are:
Rename the active document
Update References to this document to accommodate new name
Save active document.
This help page shows the Usage for renaming the doc, and under the "Remarks" heading, includes links to the next two steps, mentioning them off hand as if implementing them would be easy.
https://help.solidworks.com/2020/English/api/sldworksapi/SolidWorks.Interop.sldworks~SolidWorks.Interop.sldworks.IModelDocExtension~RenameDocument.html?verRedirect=1
The trouble is, I'm a bit of a VBA beginner - usually I get by with the 'record' function, and then tidying things up from there - but undertaking the steps above manually doesn't result in anything being recorded at all for one reason or another.
Assuming I am able to pass in the item to be renamed (I'll define a variable at the start of the Sub for this e.g. swModel = swApp.ActiveDoc), and the new name (NewName = "NEW NAME HERE"), How would I translate the Help API into a Sub that I can actually run?
Two of them suggest declaring as a Function, and one as a Public Interface - I've never used these before - do these just run in a standard Module? Do I need to write a 'master Sub' to call the different functions sequentially, or could these be included directly in the sub, if they're only to be used once?
[Feeling a little lost - it's demoralizing when the help files aren't all that helpful]
Let me know if there's any more information missing that I can add to improve my question - as I said, I'm fairly new to this coding thing...
The "record" function is sometimes a good point to start but there are a lot of functions it can't recognize while you execute them manually.
The API Help is then useful to find out how to use a specific function.
In almost every example the use of a specific method (e.g. RenameDocument) is only shown abstract. There is always a instance variable which shows you the object-type needed to call this method. So you can use these in every sub you want, but beforehand need access to the specific instance objects.
For your example the RenameDocument method is called with an object of the type IModelDocExtension. First thing for you to do is to get this object and then you can call the method as described in the help article.
Under Remarks in the article you find additional information for what you maybe have to do before or after calling a method.
For your example it is mentioned that the renaming takes permanently place after saving the document.
And finally here is what you want to do with some VBA code:
Dim swApp As SldWorks.SldWorks
Dim swModel As ModelDoc2
Sub main()
' get the solidworks application object
Set swApp = Application.SldWorks
'get the current opened document object
Set swModel = swApp.ActiveDoc
' get the modeldocextension object
Dim swModelExtension As ModelDocExtension
Set swModelExtension = swModel.Extension
Dim lRet As Long
lRet = swModelExtension.RenameDocument("NEW NAME")
If lRet = swRenameDocumentError_e.swRenameDocumentError_None Then
MsgBox "success renaming"
Else
MsgBox "failed with error: " & lRet
End If
End Sub
Afterwars you have to process the return value to check for errors described in this article: https://help.solidworks.com/2020/English/api/swconst/SolidWorks.Interop.swconst~SolidWorks.Interop.swconst.swRenameDocumentError_e.html

VBA How to programmatically set objects name?

In FactoryTalk View SE I’m trying to set an objects name in VBA based on another value.
This works:
Dim PumpSP As Object
Set PumpSP = ThisDisplay.PumpSetpoint1
PumpSP.Vaule = 10
This doesn’t work:
Dim PumpSP As Object
Set PumpSP = "ThisDisplay.PumpSetpoint" & "1"
PumpSP.Vaule = 10
How do I get it to take a concatenated string?
Thanks.
How do I get it to take a concatenated string?
You don't, and you can't. PumpSP is an Object, not a String. The only thing you can ever Set it to, is an object reference.
This is very similar to, say, how you would access the controls on a UserForm:
Set box = Me.TextBox1
The reason you can get that object with a string, is because a form has a Controls collection that lets you provide a string, works out which control has that name, and returns the Control object for it:
Set box = Me.Controls("TextBox" & i)
So in your case to go from this:
Set PumpSP = ThisDisplay.PumpSetpoint1
I don't know what ThisDisplay is, but maybe it has a similar collection:
Set PumpSP = ThisDisplay.Controls("PimpSetpoint" & i)
If there's no collection that lets you retrieve items by name with a string literal, you're out of luck.
That is the hard part as we have paid support with Rockwell but they will not help with any VBA questions. Ok fine but there VBA commands and class are not like 90% of the Excel or MS Office VBA you find online. Anyway I was able to find the correct class member.
So this work for me:
Set PumpSP = ThisDisplay.FindElement("PumpSetpoint" & “1”) Thanks for all the help.

VB6 map string to integer for headers

I'm trying to parse a CSV File into a VB6 application in order to update multiple records on a table on SQL with existing single record updating code already in the form. The CSV Files will have a header row whixh can be used to validate the information going into the correct place in the ADODB recordset. In C++ you can use a map to say like
map<String s, int x> column
column<"First Name", -1>
column<"Last Name",-1>
Then create a counter across the comma delimited values where if the third value is Last Name then the code could be written to change
column<"Last Name",-1> to column<"Last Name",3> and if x != -1 in any of the maps the file is valid for use, I would then loop through the remaining records and parse into a container using something similar to
strLastName = Array<column[3]>
to assign the record values to the correct variables. I am still very new to VB6, how can I accomplish something similar in VB6 and what containers should be used? So far I have
Public Sub GetImportValues()
On Error GoTo GetImportValues_Error:
Dim intFileNum As Integer
Open Path For Input As #intFileNum
Do Until EOF(intFileNum)
Line Input #intFileNum, vbCrLf
FunctionThatSavesInformationToSQL
Loop
Close #intFileNum
GetImportValues_Exit:
Exit Sub
GetImportValues_Error:
Err.Source = "frmMemberAdd.GetImportValues" & " | " & Err.Source
Err.Raise Err.Number, Err.Source, Err.Description
End Sub
with a dialog box returning the path as a string using App.path in a separate Function
*****************************************************Slight change to answer
The collection was on track for what I had asked but I did have to change it to dictionary because you cannot return items on a collection which kept me from comparing the items and changing the keys but dictionary can. Make sure if you use dictionary you switch the item and key.
If I understand your question correctly, you're trying to create a map (Dictionary<string, int> in C#). In VB6, you can use Collection for this purpose - it's roughly equivalent to C#'s Dictionary<string, object>. It uses String keys and stores all values as Variant. For example:
Dim oColl As Collection
Set oColl = New Collection
oColl.Add -1, "ColumnName"
Dim nColumnIndex As Long
'Get column index for column name.
nColumnIndex = oColl.Item("ColumnName")
If nColumnIndex = -1 Then
nColumnIndex = ...
'When you want to update a column index in the collection, you
'first have to remove the item and then add it back with the right
'index.
oColl.Remove "ColumnName"
oColl.Add nColumnIndex, "ColumnName"
End If
Edit 1:
One word of warning regarding VB6: you'll see many samples doing this:
Dim oObj As New SomeClass
It's ok to do this in VB.Net but don't ever do this in VB6. Declare and instantiate the object on separate statements because the single-statement form generates code where oObj is checked for Nothing and set to an instance before each use. This slows down your code (unnecessary checks) and creates hard-to-find bugs if you're using an instance that's supposed to be gone.
Always do this instead:
Dim oObj As SomeClass
Set oObj = New SomeClass
...
'Clean up the object when you're done with it. Remember, there's
'no garbage collection in COM / VB6, you have to manage object
'lifetimes.
Set oObj = Nothing
Also, use Long instead of Integer as much as you can - Long is a 32-bit integer, while Integer is only 16-bits. VB6 type names can be misleading frequently. Here's an old answer of mine with a bit more detail (not strictly related to your question but useful).
Alternatively, you can create a simplified wrapper around the .NET Dictionary class and expose it as a COM object: this would allow you to call it from VB6. This would likely be (somewhat) slower than Collection and it'd require the .NET Framework for your VB6 project to run.
Edit 2:
As #CMaster commented, Dictionary is available from the Microsoft Scripting Runtime library - you need to add a reference to it to use it (this is why I prefer Collection - it has no dependency). This answer has details about how to use it.

Reading and changing fields in SAP with RFC via VB .NET

I'm currently trying to figure out the basics of remote function calls via vb .NET. I feel pretty helpless however, because their just isn't any useful documentation for the most simple of tasks.
What I'm trying to do atm is starting the transaction CO13, write the confirmation number in the appropriate field and cancel the order. Even this simple tasks turned out to be a pain in the ass. I'm still not sure how to access and modify the contents of a specific field. There are some examples with tables for excel in the net, but hat's about it. What I have so far is this (login is working and in another function):
Public Function stornieren() As Boolean
Dim ordernr As String
Dim confirmationnr
Dim confirmation As Object
Dim R3 As Object
Dim CO13 As Object
Dim result
R3 = CreateObject("SAP.Functions")
ordernr = TextBox3.Text
confirmationnr = TextBox4.Text
CO13 = R3.Add("RFC_CALL_TRANSACTION_USING")
CO13.exports("TCODE") = "CO13"
CO13.exports("MODE") = "S"
confirmation = CO13.exports("RUECK")
confirmation.value = confirmationnr
result = CO13.call
End Function
RUECK is the Field Name. I want to write the value of "confirmationnr" into the field RUECK. "confirmation.value = confirmationnr" throws the error message "the object variable could not be determined" and "NullReferenceException" was not handled. Sounds to me like the object is empty.
Thanks in advance.
EDIT: Now trying via BAPIs and particularly BAPI_PRODORDCONF_CANCEL. I have no idea about the syntax though. Any help would be appreciated.

Determine Object Type

Is there a way to determine the Object type, when passing a reference to a function?
I'm using a security permissions function, which determines if the user has permission to view/edit the Form passed to it by reference. I'd like to expand this to include reports as well.
To keep the function generic, I'd like to pass a ref for either a Form or a Report as an Object, eg:
function gfSecurity_Permission(obj as Object)
However, I'd need to determine the type of the object within the function.
Does anyone know of a way to do that?
MTIA
Take a look at
typeOf and typeName
Generic object variables (that is, variables you declare as Object)
can hold objects from any class. When using variables of type Object,
you may need to take different actions based on the class of the
object; for example, some objects might not support a particular
property or method. Visual Basic provides two means of determining
which type of object is stored in an object variable: the TypeName
function and the TypeOf...Is operator.
TypeName and TypeOf…Is
The
TypeName function returns a string and is the best choice when you
need to store or display the class name of an object, as shown in the
following code fragment:
Dim Ctrl As Control = New TextBox
MsgBox(TypeName(Ctrl))
The TypeOf...Is operator is the best choice for testing an object's
type, because it is much faster than an equivalent string comparison
using TypeName. The following code fragment uses TypeOf...Is within an
If...Then...Else statement:
If TypeOf Ctrl Is Button Then
MsgBox("The control is a button.")
End If
Simplest way to determine the access type in access is to do an object lookup within the Access' system tables.
Here would be the lookup:
DLookup("Type","MSysObjects","NAME = '" & strObject & "'")
strObject is the name of the object within Access
The result is one of the number below OR NULL if the object does not exist in Access
1 = Access Table
4 = OBDB-Linked Table / View
5 = Access Query
6 = Attached (Linked) File (such as Excel, another Access Table or query, text file, etc.)
-32768 = Access Form
-32764 = Access Report
-32761 = Access Module
so, the dlookup would provide "-32768" for a Form or "-32764" for a Report
Hope that helps