Reading and changing fields in SAP with RFC via VB .NET - 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.

Related

LINQ program NOT populating the database

I am quite new to LINQ but some help from a field has produced the following code that works OK; but does not write the data to the SQL Server database records.
Public Function Error_Log_Add(ServiceDateRec As VariantType, Seq As VariantType, RosterID As VariantType, ContactID As VariantType, MessageID As VariantType)
'
' Add Error Message to a Service
'
Error_Log_Add = False
Dim context As RosterMaster_Rostering = Me.RosterMaster_Rostering
Dim newErrorDataSet As RosterMaster_Rostering.ErrorLogDataTable = context.ErrorLog
Dim newErrorLogRow As RosterMaster_Rostering.ErrorLogRow
newErrorLogRow = newErrorDataSet.NewRow()
newErrorLogRow.ServiceDateID = ServiceDateRec
newErrorLogRow.Seq = Seq
newErrorLogRow.Roster_Required = RosterID
newErrorLogRow.PostID = ContactID
newErrorLogRow.Error_Message = MessageID
newErrorDataSet.Rows.Add(newErrorLogRow)
newErrorDataSet.AcceptChanges()
MsgBox("Inserted" + newErrorDataSet.Rows.Count.ToString())
End Function
Can someone point me in the right direction please.
You're so new to LINQ that you haven't even started with it apparently, because there is no LINQ at all in that code. You are using a typed DataSet, which is simply ADO.NET.
The problem is that you're not actually trying to save anything to the database. You need to call Update on a table adapter for that to happen, which is nowhere to be seen in that code. You seem to be under the impression that calling AcceptChanges will save something but it won't. The DataRows in your DataTable each track their own changes and AcceptChanges basically tells them to stop doing so because those changes have been saved. You haven't actually done the saving though. You need to call Update on the appropriate table adapter and it will save the changes and then implicitly call AcceptChanges.

In ETAS INCA, how can I extract specific calibration values by accessing the COM-API via 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

How do I pass ItemSpec into GetBranchHistory()?

I'm trying to get information about specific branches in TFS, so to start, I'm trying to create a variable to assign as a BranchHistoryTreeItem. However, when I pass in the ItemSpec, I'm getting an error on Spec (not the definition, but where it's passed into GetBranchHistory):
Value of type 'Microsoft.TeamFoundation.VersionControl.Client.ItemSpec' cannot be converted to '1-dimensional array of Microsoft.TeamFoundation.VersionControl.Client.ItemSpec'
I understand the error, but I'm not entirely sure why it throwing it. Isn't this data type exactly what it's looking for? I believe I have the ItemSpec declared correctly, but I'm a bit lost here. Can anyone offer some advice on why I'm getting this? Code:
Sub GetBranchInfo()
Dim tfs As New TfsTeamProjectCollection(Common.BuildServerURI)
Dim Version = tfs.GetService(Of VersionControlServer)()
Dim Spec As New ItemSpec("$/Project1", RecursionType.None)
Dim BranchHistory As New BranchHistoryTreeItem(Version.GetBranchHistory(Spec, VersionSpec.Latest))
End Sub
GetBranchHistory takes an array of ItemSpecs.
My VB is a little rusty, but I think you want something like:
Dim Spec As New ItemSpec("$/Project1", RecursionType.None)
Dim Specs(1) = new ItemSpec() {Spec}
Dim BranchHistory As New BranchHistoryTreeItem(Version.GetBranchHistory(Specs, VersionSpec.Latest))

Dynamic programming in VB

We develop applications for SAP using their SDK. SAP provides a SDK for changing and handling events occuring in the user interface.
For example, with this SDK we can catch a click on a button and do something on the click. This programming can be done either VB or C#.
This can also be used to create new fields on the pre-existing form. We have developed a specific application which allows users to store the definition required for new field in a database table and the fields are created at the run time.
So far, this is good. What we require now is that the user should be able to store the validation code for the field in the database and the same should be executed on the run time.
Following is an example of such an event:
Private Sub SBO_Application_ItemEvent(ByVal FormUID As String, ByRef pVal As SAPbouiCOM.ItemEvent, ByRef BubbleEvent As Boolean) Handles SBO_Application.ItemEvent
Dim oForm As SAPbouiCOM.Form
If pVal.FormTypeEx = "ACC_QPLAN" Then
If pVal.EventType = SAPbouiCOM.BoEventTypes.et_LOST_FOCUS And pVal.BeforeAction = False Then
oProdRec.ItemPressEvent(pVal)
End If
End If
End Sub
Public Sub ItemPressEvent(ByRef pVal As SAPbouiCOM.ItemEvent)
Dim oForm As SAPbouiCOM.Form
oForm = oSuyash.SBO_Application.Forms.GetForm(pVal.FormTypeEx, pVal.FormTypeCount)
If pVal.EventType = SAPbouiCOM.BoEventTypes.et_LOST_FOCUS And pVal.BeforeAction = False Then
If pVal.ItemUID = "AC_TXT5" Then
Dim CardCode, ItemCode As String
ItemCode = oForm.Items.Item("AC_TXT2").Specific.Value
CardCode = oForm.Items.Item("AC_TXT0").Specific.Value
UpdateQty(oForm, CardCode, ItemCode)
End If
End If
End Sub
So, what we need in this case is to store the code given in the ItemPressEvent in a database, and execute this in runtime.
I know this is not straight forward thing. But I presume there must be some ways of getting these kind of things done.
The SDK is made up of COM components.
Thanks & Regards,
Rahul Jain
I've not done this myself, but I think you're going to have to actually use the Systems.Runtime.CompilerServices functions to dynamically compile an assembly and then link it in. Another solution if you are using SQL Server might be to take advantage of the fact that you can write C# or VB.NET code in stored procedures. That might be a way.
Dim sqlstring1 As String = "Blah Blah Blah SQL here"
Dim Rs SAPbobsCOM.Recordset
Rs = GetDIConnection.GetBusinessObject(SAPbobsCOM.BoObjectTypes.BoRecordset)
rs.doquery(SqlString1)
You can create the code dynamically and compile it..
Have some simple interfaces to call the validation code and in all your dynamic code, implement the interface(s). This way, you can load assembly dynamically and get the class as an interface and use that interface directly..

Outlook Redemption : GetNamesFromIDs

I'm trying to get all property names / values from an Outlook item. I have custom properties in addition to the default outlook item properties. I'm using redemption to get around the Outlook warnings but I'm having some problems with the GetNamesFromIDs method on a Redemption.RDOMail Item....
I'm using my redemption session to get the message and trying to use the message to get the names of all the properties.
Dim rMessage as Redemption.RDOMail = _RDOSession.GetMessageFromID(EntryID, getPublicStoreID())
Dim propertyList As Redemption.PropList = someMessage.GetPropList(Nothing)
For i As Integer = 1 To propertyList.Count + 1
Console.WriteLine(propertyList(i).ToString())
Console.WriteLine(someMessage.GetNamesFromIDs(________, propertyList(i)))
Next
I'm not totally sure what to pass in as the first parameter to getNamesFromIDs. The definition of GetNamesFromIDs is as follows:
GetNamesFromIDs(MAPIProp as Object, PropTag as Integer) As Redemption.NamedProperty
I'm not totally sure what should be passed in as the MAPIProp object. I don't see this property referenced in the documentation. http://www.dimastr.com/redemption/rdo/MAPIProp.htm#properties
Any help or insight would be greatly appreciated.
I think I figured it out. I have used VBA only, so you need to "think around" it's limitations, it will follow the same scheme in VB.NET.
The function signature is this:
Function GetNamesFromIDs(MAPIProp As Unknown, PropTag As Long) As NamedProperty
As the first parameter it requires an object which supports the IUnknown interface. Looking at the Redemption docs it became clear that there is an interface named _MAPIProp, from which many other RDO objects are derived (IRDOMail is among them). So this must be the very RDOMail you are trying to get data out of.
Knowing that, it needed only one other subtle hint from the docs to get it working:
Given a prop tag (>= 0x80000000),
returns the GUID and id of the named
property.
So property tag must be >= 0x80000000, this means it wont work for all properties, but just for the custom ones (I guess that is the distinction in this case, correct me if I'm wrong.) Passing in property tags not fulfilling this condition raises an error message (0x8000ffff "unexpected results").
Here is my code. It is VBA, so forgive me the Hex() blunder, as VBAs long integer overflows for numbers that big. I am sure you will get the picture.
Sub GetNamesFromIds()
Dim rSession As New Redemption.RDOSession
Dim rMessage As Redemption.RDOMail
Dim PropertyList As Redemption.PropList
Dim PropTag As Long
Dim EntryId As String
Dim i As Integer
rSession.MAPIOBJECT = Application.Session.MAPIOBJECT
' retrieve first random mail for this example '
EntryId = ActiveExplorer.CurrentFolder.Items(1).EntryId
Set rMessage = rSession.GetMessageFromID(EntryId)
Set PropertyList = rMessage.GetPropList(0)
For i = 1 To PropertyList.Count
PropTag = PropertyList(i)
If "0x" & Right("00000000" & Hex(PropTag), 8) > "0x80000000" Then
Debug.Print
If IsArray(rMessage.Fields(PropTag)) Then
Debug.Print Hex(PropTag), "(Array:", UBound(rMessage.Fields(PropTag)), "items)"
Else
Debug.Print Hex(PropTag), "(", rMessage.Fields(PropTag), ")"
End If
Debug.Print " GUID:", rMessage.GetNamesFromIds(rMessage, PropTag).GUID
Debug.Print " ID:", rMessage.GetNamesFromIds(rMessage, PropTag).ID
End If
Next
End Sub
First snippet from the output:
8041001E ( urn:content-classes:message )
GUID: {00020386-0000-0000-C000-000000000046}
ID: content-class
Well, for background info, the author suggests using something like OutlookSpy to see how Outlook stores the properties.
Looking at this exchange (make sure to read through all the follow-up responses), there isn't much more (in fact, I think at one point the Outlook MVP types GetNamesFromIDs when he means GetIDsFromNames).
What you might try is using GetIDsFromNames to see what that returns, and then use that to pass to GetNamesFromIDs.
I've used Redemption before, but not in this particular manner, so that's all I've got for you ...