用例項講解Variant型別在VB、C#、VC中的引數傳遞
前段時間由於該控制元件基於微軟的MSCOMM控制元件,這個控制元件如果系統沒有安裝VB,單獨註冊好像很難成功,這害的一些沒有裝VB的使用者,為了這個小控制元件必須安裝一次VB,這實在是划算不來,所以直接用API串列埠函式進行了封裝改進,這樣不僅效率提高了,並且再也不需要MSCOMM控制元件了。
這一次,我不僅使該控制元件支援了浮點運算,並且在VC、C#(VB當然就不用多試了,以前就很好的支援)進行了相容測試。
一試問題就來了,沒有改進之前的控制元件,由於C#封裝效能甚好,還能使用,唯一不足的是,控制元件方法中如果不要求返回的引數前面沒有新增ByVal引數,在C#中就轉換為 ref ***,害的你還得專門定義臨時變數進行傳參。
在VC中直接就不行,ReadData和WriteData等幾個主要方法根本在VC中無法轉換成對應函式,具體錯誤資訊如下:
// method 'ReadData' not emitted because of invalid return type or parameter type
// method 'WriteData' not emitted because of invalid return type or parameter type
// method 'PlcLogin' not emitted because of invalid return type or parameter type
// method 'PlcRun' not emitted because of invalid return type or parameter type
// method 'PlcStop' not emitted because of invalid return type or parameter type
經過測試,最後發現VB函式中的byte和陣列在VC中根本找不到合適的對應。
由於控制元件中又新新增了浮點數的支援,所以對引數介面又增加了一層複雜性。突然想到微軟的MSCOMM控制元件各語言肯定都能很好的支援,它的介面引數是怎樣的定義的。我在VB、VC、C#分別試了一下,VB中和input和Output屬性的型別就是Variant型別,在VC中是VARIANT,在C#中是Object。用Variant還有個好處,就是各種型別的資料都可以傳輸,沒有必要在另外新增介面函式了。
最後我定義的介面如下(主要介面):
Public Function ReadData(ByVal lngAddr As Long, vData As Variant, Optional ByVal lngNum As Long = 1, Optional ByVal bytLen As PPILEN = PPI_B, Optional ByVal bytType As PPITYPE = PPI_V, Optional ByVal Addr As Long = 0) As Long
Public Function WriteData(ByVal lngAddr As Long, ByVal vData As Variant, Optional ByVal lngNum As Long = 1, Optional ByVal bytLen As PPILEN = PPI_B, Optional ByVal bytType As PPITYPE = PPI_V, Optional ByVal Addr As Long = 0) As Long
在VC中對應的介面如下:
long ReadData(long lngAddr, VARIANT* vData, long lngNum, long bytLen, long bytType, long Addr);
long WriteData(long lngAddr, const VARIANT& vData, long lngNum, long bytLen, long bytType, long Addr);
在C#中的介面如下:
public virtual int ReadData(int lngAddr, ref object vData);
public virtual int ReadData(int lngAddr, ref object vData, int lngNum, PPILEN bytLen, PPITYPE bytType, int addr);
public virtual int WriteData(int lngAddr, object vData);
public virtual int WriteData(int lngAddr, object vData, int lngNum, PPILEN bytLen, PPITYPE bytType, int addr);
以為這樣定義就萬事大吉了,事後一試我又錯了,在C#中沒有任何問題(看了微軟還是在C#上下了很大的功夫),在VC簡單的定義一個VARIANT變數直接傳遞給控制元件,VB控制元件老是報錯,根本無法使用。後來想為什麼MSCOMM控制元件可以,我的控制元件不可以。天殺的MSCOMM肯定是VC開發的,而我的控制元件是VB開發的,VB和C#的包容性都很強,而VC卻高高在上不肯屈就。
正一籌莫展準備放棄的時候,突然想到了以前用VC開發的OPC程式,上面有很多關於VARIANT的應用,一看就明白了,原來在VC中VARIANT的用法是有講究的。
下面我就詳細說一下控制元件同樣的介面在不同語言中如何使用。
在VB中:
Private Sub cmdReadData_Click()
On Error GoTo ToExit '開啟錯誤陷阱
'------------------------------------------------
Dim i As Long
Dim bytType As Byte
Dim lngRet As Long
Dim lngData() As Long
Dim fData() As Single
Dim vData As Variant
Select Case cmbType.ListIndex
Case 0: bytType = PPI_I
Case 1: bytType = PPI_Q
Case 2: bytType = PPI_M
Case 3: bytType = PPI_V
Case 4: bytType = PPI_S
Case 5: bytType = PPI_SM
End Select
S7_PPI1.FixAddr = cmbNo.ListIndex + 1
lngRet = S7_PPI1.ReadData(Val(txtAddr), vData, Val(cmbNum.Text), Val(cmbLen.ListIndex), Val(bytType))
If lngRet = 0 Then
txtData = ""
If cmbLen.ListIndex = 3 Then
fData = vData
For i = 1 To Val(cmbNum.Text)
txtData = txtData & Format(fData(i - 1), "0.00") & " "
Next
Else
lngData = vData
For i = 1 To Val(cmbNum.Text)
txtData = txtData & Format(lngData(i - 1), "0") & " "
Next
End If
Else
txtData = "Error"
End If
'------------------------------------------------
Exit Sub
'----------------
ToExit:
MsgBox Err.Description
End Sub
Private Sub cmdWriteData_Click()
On Error GoTo ToExit '開啟錯誤陷阱
'------------------------------------------------
Dim bytType As Byte
Dim strData() As String
Dim lngRet As Long
Dim lngData(100) As Long
Dim fData(100) As Single
Dim i As Long
Select Case cmbType.ListIndex
Case 0: bytType = PPI_I
Case 1: bytType = PPI_Q
Case 2: bytType = PPI_M
Case 3: bytType = PPI_V
Case 4: bytType = PPI_S
Case 5: bytType = PPI_SM
End Select
If Len(txtData) > 0 Then
strData = Split(txtData, " ")
If cmbLen.ListIndex = 3 Then
For i = 0 To UBound(strData)
fData(i) = Val(strData(i))
Next
lngRet = S7_PPI1.WriteData(Val(txtAddr), fData, UBound(strData) + 1, Val(cmbLen.ListIndex), Val(bytType), cmbNo.ListIndex + 1)
Else
For i = 0 To UBound(strData)
lngData(i) = Val(strData(i))
Next
lngRet = S7_PPI1.WriteData(Val(txtAddr), lngData, UBound(strData) + 1, Val(cmbLen.ListIndex), Val(bytType), cmbNo.ListIndex + 1)
End If
If lngRet = 0 Then
'
Else
txtData = "Error"
End If
End If
'------------------------------------------------
Exit Sub
'----------------
ToExit:
MsgBox Err.Description
End Sub
在C#中:
///
/// 讀資料
///
///
///
private void btnRead_Click(object sender, EventArgs e)
{
int intAddr = int.Parse(txtFixAddr.Text);
object vData = new object();
/*
[PPI_I] = &H81
[PPI_Q] = &H82
[PPI_M] = &H83
[PPI_V] = &H84
[PPI_S] = 4
[PPI_SM] = 5
*/
PPIV2.PPITYPE DataType= PPIV2.PPITYPE.PPI_V;
switch (cmbDataType.SelectedIndex) //資料型別
{
case 0:
DataType = PPIV2.PPITYPE.PPI_I;
break;
case 1:
DataType = PPIV2.PPITYPE.PPI_Q;
break;
case 2:
DataType = PPIV2.PPITYPE.PPI_M;
break;
case 3:
DataType = PPIV2.PPITYPE.PPI_V;
break;
case 4:
DataType = PPIV2.PPITYPE.PPI_S;
break;
case 5:
DataType = PPIV2.PPITYPE.PPI_SM;
break;
}
if (axS7_PPI1.ReadData(int.Parse(txtDataAddr.Text), ref vData, cmbLen.SelectedIndex+1 , (PPIV2.PPILEN)cmbDataMode.SelectedIndex, DataType, intAddr) == 0)
{
if (cmbDataMode.SelectedIndex == 3)
{
float[] fData = (float[])vData;
txtData.Text = "";
for (int i = 0; i < fData.Length; i++)
{
txtData.Text += fData[i].ToString("0.00") + " ";
}
}
else
{
Int32[] intData = (Int32[])vData;
txtData.Text = "";
for (int i = 0; i < intData.Length; i++)
{
txtData.Text += intData[i].ToString() + " ";
}
}
}
else
{
txtData.Text = "ERROR";
}
}
///
/// 寫資料
///
///
///
private void btnWrite_Click(object sender, EventArgs e)
{
int intAddr = int.Parse(txtFixAddr.Text);
object vData = new object();
/*
[PPI_I] = &H81
[PPI_Q] = &H82
[PPI_M] = &H83
[PPI_V] = &H84
[PPI_S] = 4
[PPI_SM] = 5
*/
PPIV2.PPITYPE DataType = PPIV2.PPITYPE.PPI_V;
switch (cmbDataType.SelectedIndex) //資料型別
{
case 0:
DataType = PPIV2.PPITYPE.PPI_I;
break;
case 1:
DataType = PPIV2.PPITYPE.PPI_Q;
break;
case 2:
DataType = PPIV2.PPITYPE.PPI_M;
break;
case 3:
DataType = PPIV2.PPITYPE.PPI_V;
break;
case 4:
DataType = PPIV2.PPITYPE.PPI_S;
break;
case 5:
DataType = PPIV2.PPITYPE.PPI_SM;
break;
}
long lngRet = 0;
if (cmbDataMode.SelectedIndex == 3)
{
float[] fData = new float[100];
fData[0] = float.Parse(txtData.Text);
lngRet = axS7_PPI1.WriteData(int.Parse(txtDataAddr.Text), fData, 1, (PPIV2.PPILEN)cmbDataMode.SelectedIndex, DataType, intAddr);
}
else
{
Int32[] intData = new Int32[100];
intData[0] = Int32.Parse(txtData.Text);
lngRet = axS7_PPI1.WriteData(int.Parse(txtDataAddr.Text), intData, 1, (PPIV2.PPILEN)cmbDataMode.SelectedIndex, DataType, intAddr);
}
if (lngRet != 0)
{
txtData.Text = "ERROR";
}
}
在VC中:
//讀資料
void CPPI_TestDlg::OnReadData()
{
//pCombo->GetLBText (pCombo->GetCurSel (), strType);
long lngFixAddr=0,lngDataAddr=0;
char strAddr[255];
m_FixAddr.GetWindowText(strAddr,255);
sscanf(strAddr,"%ld",&lngFixAddr);
m_DataAddr.GetWindowText(strAddr,255);
sscanf(strAddr,"%ld",&lngDataAddr);
/*
[PPI_I] = &H81
[PPI_Q] = &H82
[PPI_M] = &H83
[PPI_V] = &H84
[PPI_S] = 4
[PPI_SM] = 5
*/
long DataType;
switch (m_DataType.GetCurSel()) //資料型別
{
case 0:
DataType=0x81;
break;
case 1:
DataType=0x82;
break;
case 2:
DataType=0x83;
break;
case 3:
DataType=0x84;
break;
case 4:
DataType=0x4;
break;
case 5:
DataType=0x5;
break;
}
long lngRet;
VARIANT vData;
VariantInit (&vData);
if(m_DataMode.GetCurSel()==3) //浮點數
{
vData.vt = VT_R4 | VT_ARRAY;
vData.parray=SafeArrayCreateVector(VT_R4, 0, 255 );
}
else
{
vData.vt = VT_I4 | VT_ARRAY;
vData.parray=SafeArrayCreateVector(VT_I4, 0, 255 ); //SAFEARRAY vd;
}
lngRet=m_PPI.ReadData(lngDataAddr,&vData,m_DataNum.GetCurSel()+1,m_DataMode.GetCurSel(),DataType,lngFixAddr);
if(lngRet==0)
{
CString strData;
if(m_DataMode.GetCurSel()==3) //浮點數
{
float *fData;
SafeArrayAccessData(vData.parray, (void**)&fData );
for(int i=0;i
{
CString cData;
cData.Format("%04.2f ",fData[i]);
strData+= cData;
}
SafeArrayUnaccessData(vData.parray);
}
else
{
long *lngData;
SafeArrayAccessData(vData.parray, (void**)&lngData );
for(int i=0;i
{
CString cData;
cData.Format("%ld ",lngData[i]);
strData+= cData;
}
SafeArrayUnaccessData(vData.parray);
}
m_Data.SetWindowText(strData);
}
else
{
m_Data.SetWindowText(_T("ERROR"));
}
SafeArrayUnaccessData(vData.parray);
SafeArrayDestroy(vData.parray);
VariantClear(&vData);
}
//寫資料
void CPPI_TestDlg::OnWrite()
{
long lngFixAddr=0,lngDataAddr=0;
char strAddr[255];
m_FixAddr.GetWindowText(strAddr,255);
sscanf(strAddr,"%ld",&lngFixAddr);
m_DataAddr.GetWindowText(strAddr,255);
sscanf(strAddr,"%ld",&lngDataAddr);
long DataType;
switch (m_DataType.GetCurSel())
{
case 0:
DataType=0x81;
break;
case 1:
DataType=0x82;
break;
case 2:
DataType=0x83;
break;
case 3:
DataType=0x84;
break;
case 4:
DataType=0x4;
break;
case 5:
DataType=0x5;
break;
}
long lngRet;
VARIANT vData;
VariantInit (&vData);
if(m_DataMode.GetCurSel()==3) //浮點數
{
vData.vt = VT_R4 | VT_ARRAY;
vData.parray=SafeArrayCreateVector(VT_R4, 0, 255 );
float *fDatas,fData;
SafeArrayAccessData(vData.parray, (void**)&fDatas );
m_Data.GetWindowText(strAddr,255);
sscanf(strAddr,"%f",&fData);
fDatas[0]=fData;
SafeArrayUnaccessData(vData.parray);
}
else
{
vData.vt = VT_I4 | VT_ARRAY;
vData.parray=SafeArrayCreateVector(VT_I4, 0, 255 ); //SAFEARRAY vd;
long *lngDatas,lngData;
SafeArrayAccessData(vData.parray, (void**)&lngDatas );
m_Data.GetWindowText(strAddr,255);
sscanf(strAddr,"%ld",&lngData);
lngDatas[0]=lngData;
SafeArrayUnaccessData(vData.parray);
}
lngRet=m_PPI.WriteData(lngDataAddr,(const VARIANT &)vData,1,m_DataMode.GetCurSel(),DataType,lngFixAddr);
if(lngRet!=0)
{
m_Data.SetWindowText(_T("ERROR"));
}
SafeArrayUnaccessData(vData.parray);
SafeArrayDestroy(vData.parray);
VariantClear(&vData);
}
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-557791/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- C#中的虛方法(virtual)例項講解C#
- Hellow C# unity學習記錄(7)值型別引用型別以及引數傳遞C#Unity型別
- 在例項中呼叫 Invoke 型別的類型別
- PHP弱型別引發的漏洞例項PHP型別
- C#程式設計引用型別和值型別 以及引用傳遞和值傳遞C#程式設計型別
- linux中main引數傳遞LinuxAI
- Java中建立泛型型別的例項Java泛型型別
- 在 `el-upload` 的事件中傳遞更多引數的方法事件
- python中函式的引數傳遞Python函式
- 引數傳遞
- String和StringBuffer型別資料進行引數傳遞問題型別
- 關於C99可變引數巨集的例項程式碼講解
- C#程式設計:ref【引數按引用傳遞】C#程式設計
- JS的方法引數傳遞(按值傳遞)JS
- 關於 Go 中 Map 型別和 Slice 型別的傳遞Go型別
- 引數的定義和引數的傳遞
- Mybatis引數傳遞MyBatis
- Mybatis引數傳遞&註解開發MyBatis
- 面試官問:Go 中的引數傳遞是值傳遞還是引用傳遞?面試Go
- 請求引數的傳遞
- 函式的引數傳遞函式
- 深入探討Spring Boot中的引數傳遞Spring Boot
- 獲取url中?後面傳遞的引數
- Flutter:學會在頁面間傳遞引數Flutter
- 路由元件傳遞引數路由元件
- React事件傳遞引數React事件
- C++引數的傳遞方式C++
- 可變引數例項
- SSM框架中Mybatis傳遞引數的幾種方法SSM框架MyBatis
- Java中的引數傳遞有哪些?通俗易懂Java
- 從request中傳遞過來的引數資訊
- 說說不知道的Golang中引數傳遞Golang
- Flask-sqlalchemy中 backref lazy的引數例項解釋和選擇FlaskSQL
- 如何計算PHP函式中傳遞的引數數量PHP函式
- PHP 用 Enum 限定引數型別PHP型別
- 鴻蒙程式設計江湖:ArkTS中Sendable資料在併發例項間的傳遞鴻蒙程式設計
- 引數傳遞方式必須是const引用傳遞
- 利用 Laravel Macroable 特性優化多型引數傳遞的技巧分享LaravelMac優化多型
- Python的函式引數傳遞:傳值?引用?Python函式