事前準備,先建立好兩個要測試的 RFC
第一個是 Z_HELLO_WORLD,傳入一個 NAME,然後回傳訊息 Hello NAME,主要是進行參數的 Import 與 Export 練習
第二個 RFC Z_HELLO_TABLE,傳入一個 TABLE,裡面分別放加數與被加數,系統將兩個值算完後回傳 Table,進行練習傳入 Table 與輸出 Table
接下來進行 VB.NET 與 C# 的程式測試呼叫上面兩個 RFC
使用 VB 連線 SAP RFC,需要 Import 下面三個 COM 元件
SAP Logon Unicode Control : 登入 SAP 使用
SAP Remote Function Call Unicode Control : 呼叫 RFC 使用
SAP Table Factory Unicode : 傳 Table 參數使用
Unicode 與非 Unicode 的差別在當傳入像是 "彣" 這類非 BIG5 編碼的文字時,是否能正常被 SAP 處理,所以當 SAP 是 Unicode 編碼時,建議使用 Unicode 的參考
拉一個 GUI 如下畫面
一、與SAP 進行連線
在 Form 的最上方需要 Import 上面三個參考
Imports SAPLogonCtrl
Imports SAPTableFactoryCtrl
Imports SAPFunctionsOCX
連線 SAP 需要兩個物件,分別是 SAPLogonCtrl.SAPLogonControl 與 SAPLogonCtrl.Connection,前者設定登入資訊,後者建立 Connection 並進行登入回傳是否成功,將下面 Code 放置在任一個 Button 物件的 On_Clock 事件
Dim login As New SAPLogonCtrl.SAPLogonControl
Dim conn As SAPLogonCtrl.Connection
login.ApplicationServer = "XX.XX.XX.XX" //SAP IP
login.Client = "XXX" //SAP CLIENT
login.Language = "EN" //SAP LOGON LANGUAGE
login.User = "XXXXX" //USER ID
login.Password = "********" //USER PASSWORD
login.SystemNumber = 0 //SAP SYSTEM NUMBER
conn = CType(login.NewConnection(), SAPLogonCtrl.Connection)
If conn.Logon(0, True) Then
MsgBox("Connected")
Else
MsgBox("Failed")
Exit Sub
End If
要斷線則下
conn.Logoff()
此時執行時會發生下面錯誤
接下來執行成功就會看到 Connected 的訊息
連線成功時,再 conn.Logoff() 前下中斷點可在 SAP SM04 看到登入的資訊
Dim login As New SAPLogonCtrl.SAPLogonControl
Dim conn As SAPLogonCtrl.Connection
login.ApplicationServer = "XX.XX.XX.XX" //SAP IP
login.Client = "XXX" //SAP CLIENT
login.Language = "EN" //SAP LOGON LANGUAGE
login.User = "XXXXX" //USER ID
login.Password = "********" //USER PASSWORD
login.SystemNumber = 0 //SAP SYSTEM NUMBER
conn = CType(login.NewConnection(), SAPLogonCtrl.Connection)
If conn.Logon(0, True) Then
MsgBox("Connected")
Else
MsgBox("Failed")
Exit Sub
End If
Dim SAP_RFC As New SAPFunctionsOCX.SAPFunctions
SAP_RFC.Connection = conn
Dim ifunc As SAPFunctionsOCX.Function = CType(SAP_RFC.Add("Z_HELLO_WORLD"), SAPFunctionsOCX.Function)
Dim parameter1 As Parameter
parameter1 = CType(ifunc.Exports("I_NAME"), Parameter)
parameter1.Value = "彣"
ifunc.Call()
Dim parameter2 As Parameter = CType(ifunc.Imports("E_MSG"), Parameter)
MsgBox(CType(parameter2.Value, String))
SAP_RFC.RemoveAll()
conn.Logoff()
Dim login As New SAPLogonCtrl.SAPLogonControl
Dim conn As SAPLogonCtrl.Connection
login.ApplicationServer = "XX.XX.XX.XX" //SAP IP
login.Client = "XXX" //SAP CLIENT
login.Language = "EN" //SAP LOGON LANGUAGE
login.User = "XXXXX" //USER ID
login.Password = "********" //USER PASSWORD
login.SystemNumber = 0 //SAP SYSTEM NUMBER
conn = CType(login.NewConnection(), SAPLogonCtrl.Connection)
If conn.Logon(0, True) Then
MsgBox("Connected")
Else
MsgBox("Failed")
Exit Sub
End If
Dim SAP_RFC As New SAPFunctionsOCX.SAPFunctionsClass
SAP_RFC.Connection = conn
Dim ifunc As SAPFunctionsOCX.Function
ifunc = CType(SAP_RFC.Add("Z_HELLO_TABLE"), SAPFunctionsOCX.Function)
Dim Tables1_data As Object
Tables1_data = CType(ifunc.Tables("O_TABLE"), SAPTableFactoryCtrl.Table)
Tables1_data.Rows.Add()
Tables1_data(1, "NUM1") = "6"
Tables1_data(1, "NUM2") = "3"
Tables1_data.Rows.Add()
Tables1_data(2, "NUM1") = "8"
Tables1_data(2, "NUM2") = "0"
If ifunc.Call = True Then
Dim dt As New DataTable
dt.Columns.Add("NUM1")
dt.Columns.Add("NUM2")
dt.Columns.Add("RESULT")
dt.Columns.Add("MSG")
Dim dr As DataRow
dr = dt.NewRow
Dim Tables1_show As SAPTableFactoryCtrl.Table
Tables1_show = CType(ifunc.Tables("O_TABLE"), SAPTableFactoryCtrl.Table)
dr("NUM1") = CType(Tables1_data(1, "NUM1"), String)
dr("NUM2") = CType(Tables1_data(1, "NUM2"), String)
dr("RESULT") = CType(Tables1_data(1, "RESULT"), String)
dr("MSG") = CType(Tables1_data(1, "MSG"), String)
dt.Rows.Add(dr)
dr = dt.NewRow
dr("NUM1") = CType(Tables1_data(2, "NUM1"), String)
dr("NUM2") = CType(Tables1_data(2, "NUM2"), String)
dr("RESULT") = CType(Tables1_data(2, "RESULT"), String)
dr("MSG") = CType(Tables1_data(2, "MSG"), String)
dt.Rows.Add(dr)
DataGridView1.DataSource = dt
Else
MsgBox("Error")
Exit Sub
End If
Tables1_data.FreeTable()
SAP_RFC.RemoveAll()
conn.Logoff()
C# :
與 VB.NET 拉一樣的 GUI 畫面
C# 同樣要 Import 三個 COM 元件
SAP Logon Unicode Control : 登入 SAP 使用
SAP Remote Function Call Unicode Control : 呼叫 RFC 使用
SAP Table Factory Unicode : 傳 Table 參數使用
(圖片請參考上面 VB.NET)
C# 在最上方引用使用的是
using SAPLogonCtrl;
using SAPFunctionsOCX;
using SAPTableFactoryCtrl;
C# 在最上方引用使用的是
using SAPLogonCtrl;
using SAPFunctionsOCX;
using SAPTableFactoryCtrl;
CALL RFC BY PARAMETER CODE 如下
SAPLogonCtrl.SAPLogonControlClass logon = new SAPLogonCtrl.SAPLogonControlClass();
SAPLogonCtrl.Connection Conn;
logon.ApplicationServer = "XXX.XXX.XXX.XXX"; //SAP系统IP
logon.Client = "XXX"; //SAP客户端号
logon.Language = "EN"; //SAP登陆语言
logon.User = "XXXXXX"; //用户帐号
logon.Password = "******"; //用户密码
logon.SystemNumber = 0; //SAP系统编号
Conn = (SAPLogonCtrl.Connection)logon.NewConnection();
if (Conn.Logon(0, true))
{
MessageBox.Show("good job");
}
SAPFunctionsOCX.SAPFunctionsClass SAP_RFC = new SAPFunctionsOCX.SAPFunctionsClass();
SAP_RFC.Connection = Conn;
SAPFunctionsOCX.Function ifunc = (SAPFunctionsOCX.Function)SAP_RFC.Add("Z_HELLO_WORLD");
Parameter parameter1 = (Parameter)ifunc.get_Exports("I_NAME");
parameter1.Value = "Eric";
if (ifunc.Call())
{
Parameter parameter2 = (Parameter)ifunc.get_Imports("E_MSG");
MessageBox.Show((String)parameter2.Value);
}
SAP_RFC.RemoveAll();
Conn.Logoff();
基本上只是在宣告與部份語法的差別,大致上無太多差異
SAPLogonCtrl.SAPLogonControlClass logon = new SAPLogonCtrl.SAPLogonControlClass();
SAPLogonCtrl.Connection Conn;
logon.ApplicationServer = "XXX.XXX.XXX.XXX"; //SAP IP
logon.Client = "XXX"; //SAP CLIENT
logon.Language = "EN"; //SAP LOGON LANGUAGE
logon.User = "XXXXXX"; //USER ID
logon.Password = "******"; //USER PASSWORD
logon.SystemNumber = 0; //SAP SYSTEM NUMBER
Conn = (SAPLogonCtrl.Connection)logon.NewConnection();
if (Conn.Logon(0, true))
{
MessageBox.Show("Connected");
}
SAPFunctionsOCX.SAPFunctionsClass SAP_RFC = new SAPFunctionsOCX.SAPFunctionsClass();
SAP_RFC.Connection = Conn;
SAPFunctionsOCX.Function ifunc = (SAPFunctionsOCX.Function)SAP_RFC.Add("Z_HELLO_TABLE");
SAPTableFactoryCtrl.Tables Tables1 = (SAPTableFactoryCtrl.Tables)ifunc.Tables;
SAPTableFactoryCtrl.Table Tables1_data = (SAPTableFactoryCtrl.Table)Tables1.get_Item("O_TABLE");
//這邊會出現題,變成寫入 Table 中的第一個參數放 1,就新增一筆,其最後 Table 只有第一欄有值
Tables1_data.AppendGridData(1, 1, 1, 1);
Tables1_data.AppendGridData(1, 1, 1, 2);
if (ifunc.Call())
{
DataTable dt = new DataTable();
dt.Columns.Add("NUM1", typeof(string));
dt.Columns.Add("NUM2", typeof(string));
dt.Columns.Add("RESULT", typeof(string));
dt.Columns.Add("MSG", typeof(string));
Tables1 = (Tables)ifunc.Tables;
Table Talbe1_show = (Table)Tables1.get_Item("O_TABLE");
dt.Rows.Add(Talbe1_show.get_Cell(1, 1).ToString(),
Talbe1_show.get_Cell(1, 2).ToString(),
Talbe1_show.get_Cell(1, 3).ToString(),
Talbe1_show.get_Cell(1, 4).ToString());
dt.Rows.Add(Talbe1_show.get_Cell(2, 1).ToString(),
Talbe1_show.get_Cell(2, 2).ToString(),
Talbe1_show.get_Cell(2, 3).ToString(),
Talbe1_show.get_Cell(2, 4).ToString());
Tables1_data.FreeTable();
dataGridView1.DataSource = dt;
}
Conn.Logoff();
產生的結果變成只能傳入第一個參數,被加數都會是 0,在筆者寫到此時並未看到 C# 有什麼方法可直接傳入 Table 參數
使用預設的命名規則
再加入以下 Code 於程式中 (直接全部取代即可),此 VB.NET 程式仍要 imports 之前加入的 SAP 相關 dll
下面的程式其實同之前 VB.NET 從 Connection 的建立,到產生 RFC 和 Table 相關物建,到取回資料到 DataTable,最後 Disconnection 的程式,之後 C# 只是傳入登入資訊以及要加回資料的 DataTable
Imports SAPFunctionsOCX
Imports SAPLogonCtrl
Imports SAPTableFactoryCtrl
Public Class Class1
Function CALL_RFC(ByVal strIP As String, ByVal strClient As String, ByVal strLanguage As String,
ByVal strID As String, ByVal strPassword As String, ByVal strSystemnumber As String,
ByRef dt As DataTable) As Boolean
CALL_RFC = True
Dim conn As SAPLogonCtrl.Connection
Dim login As New SAPLogonCtrl.SAPLogonControlClass()
login.ApplicationServer = strIP
login.Client = strClient
login.Language = strLanguage
login.User = strID
login.Password = strPassword
login.SystemNumber = strSystemnumber
conn = CType(login.NewConnection(), SAPLogonCtrl.Connection)
If conn.Logon(0, True) Then
Else
CALL_RFC = False
Exit Function
End If
Dim SAP_RFC As New SAPFunctionsOCX.SAPFunctionsClass
SAP_RFC.Connection = conn
Dim ifunc As SAPFunctionsOCX.Function
ifunc = CType(SAP_RFC.Add("Z_HELLO_TABLE"), SAPFunctionsOCX.Function)
Dim Tables1_data As Object
Tables1_data = CType(ifunc.Tables("O_TABLE"), SAPTableFactoryCtrl.Table)
Tables1_data.Rows.Add()
Tables1_data(1, "NUM1") = "6"
Tables1_data(1, "NUM2") = "3"
Tables1_data.Rows.Add()
Tables1_data(2, "NUM1") = "8"
Tables1_data(2, "NUM2") = "1"
If ifunc.Call = True Then
dt.Columns.Add("NUM1")
dt.Columns.Add("NUM2")
dt.Columns.Add("RESULT")
dt.Columns.Add("MSG")
Dim dr As DataRow
dr = dt.NewRow
Dim Tables1_show As SAPTableFactoryCtrl.Table
Tables1_show = CType(ifunc.Tables("O_TABLE"), SAPTableFactoryCtrl.Table)
dr("NUM1") = CType(Tables1_data(1, "NUM1"), String)
dr("NUM2") = CType(Tables1_data(1, "NUM2"), String)
dr("RESULT") = CType(Tables1_data(1, "RESULT"), String)
dr("MSG") = CType(Tables1_data(1, "MSG"), String)
dt.Rows.Add(dr)
dr = dt.NewRow
dr("NUM1") = CType(Tables1_data(2, "NUM1"), String)
dr("NUM2") = CType(Tables1_data(2, "NUM2"), String)
dr("RESULT") = CType(Tables1_data(2, "RESULT"), String)
dr("MSG") = CType(Tables1_data(2, "MSG"), String)
dt.Rows.Add(dr)
Tables1_show.FreeTable()
Else
CALL_RFC = False
Exit Function
End If
Tables1_data.FreeTable()
SAP_RFC.RemoveAll()
conn.Logoff()
End Function
End Class
在該 Project 下即可找到該建置後的 dll 檔,其中 ClassLibrary1.dll 要放置到之後 C# 要引用 VB.NET 的 Project 下,其他的 dll 則要放在,而其他 VB.NET 引用的 SAP dll 檔則要放在 C# 建置後執行檔的 bin\debug 目錄下
VB.NET 的 dll 要放在 c# 的 Project 目錄之後提供 C# 參考加入此 dll |
而 VB.NET class 產生的 SAP dll 要放在bin\debug 下,因為 C# 基
本上是透過 VB.NET 來呼叫 SAP,並沒有引用SAP 的 dll,不會產 生在 bin\debug 目錄,沒放會造成 VB.NET dll 呼叫時失敗 |
接下來回到 C# Project 中,引用該 VB.NET 的 dll,在 Project 的參考加入 dll
使用瀏覽加入之前建置的 dll,並在 C# using 之前 VB.NET 產生的 ClassLibrary1;
將前面 C# CALL RFC BY TABLE CODE Code 變動如下
P.S. 因為傳入的參數是寫死在上方 VB.NET 裡,基本上可以考慮使用 C# 透過 DataTable 傳入 VB.NET 建立的 dll,即可達成依需要的參數透過 VB.NET call SAP RFC
private void button2_Click(object sender, EventArgs e)
{
Class1 VB_RFC_CONNECT = new Class1();
DataTable dt1 = new DataTable();
Boolean result =
VB_RFC_CONNECT.CALL_RFC("SAP IP", "SAP Client", "Language", "SAP ID", "SAP PASSWORD", "SAP SYSTEM ID", ref dt1);
GridView1.DataSource = dt1;
GridView1.Visible = true;
}
最後即可透過 C# 透過 VB.NET dll 進行 Call SAP RFC 並 import Table 參數
後記 : 雖然 VB.NET 就可以達成,但有時公司限制使用 C# 開發 Project 時,C# 呼叫 SAP 的元件會發生 Table 無法 import 的問題時,則只好退而求其次使用 C# call VB.NET dll 來進行
哇~你好棒棒~會好多工具~這些非sap的工具都是你自己study的嗎? 還是本身就用了~
回覆刪除公司完全禁用~你們好free
從完全不會~要進入到這樣的開發~這門檻....
排版很舒服~偶爾來看貼文~心情都會變好^^
公司有要求使用專門的工具啦,只是私下喜歡嘗試其他工具,這都是在 IDES Server 上嘗試,就比較不受限制 ... XD
刪除好強大丫~ 什麼都難不倒喔~
回覆刪除公司很窮~啥都沒升級~也不想花錢~IDES環境也沒有~
寫了一陣子abap 都沒摸其他的~突然要再來學原本不會的的工具和其他語言~ 覺得困難重重~完全跟不上丫~
有看到你有篇python 文章的分享也很棒~ 實例說的很清楚 ~雖然也還不會..XD~ 但有時間也想來study~
希望有機會可以看到你更多 none-sap tool 或與sap介接的學習經驗的分享~^^