`
isiqi
  • 浏览: 16483978 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

Variant类型在各语言中的参数传递

阅读更多

几年前我用VB开发了一个西门子PPI通信控件,由于VB开发的控件是标准的COM组件,所以想当然的认为VCC#Delphi等开发语言可以非常容易的使用。

前段时间由于该控件基于微软的MSCOMM控件,这个控件如果系统没有安装VB,单独注册好像很难成功,这害的一些没有装VB的用户,为了这个小控件必须安装一次VB,这实在是划算不来,所以直接用API串口函数进行了封装改进,这样不仅效率提高了,并且再也不需要MSCOMM控件了。

这一次,我不仅使该控件支持了浮点运算,并且在VCC#VB当然就不用多试了,以前就很好的支持)进行了兼容测试。

一试问题就来了,没有改进之前的控件,由于C#封装性能甚好,还能使用,唯一不足的是,控件方法中如果不要求返回的参数前面没有添加ByVal参数,在C#中就转换为 ref ***,害的你还得专门定义临时变量进行传参。

VC中直接就不行,ReadDataWriteData等几个主要方法根本在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控件各语言肯定都能很好的支持,它的接口参数是怎样的定义的。我在VBVCC#分别试了一下,VB中和inputOutput属性的类型就是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开发的,VBC#的包容性都很强,而VC却高高在上不肯屈就。

正一筹莫展准备放弃的时候,突然想到了以前用VC开发的OPC程序,上面有很多关于VARIANT的应用,一看就明白了,原来在VCVARIANT的用法是有讲究的。

下面我就详细说一下控件同样的接口在不同语言中如何使用。

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#中:

/// <summary>

/// 读数据

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

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";

}

}

/// <summary>

/// 写数据

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

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);

分享到:
评论

相关推荐

    Variant.rar

    5. **多用途**:`Variant`常用于数据交换、函数返回值和参数传递,尤其是在那些需要通用性或不确定数据类型的情况下。 6. **局限性**:尽管`Variant`提供了灵活性,但它也有一些缺点。比如,由于自动类型转换,可能...

    Example052-在DED中使用参数.rar

    3. **参数传递方式**:VB使用两种参数传递方式——按值(ByVal)和按引用(ByRef)。按值传递时,函数内部无法改变参数的实际值;按引用传递则可以。 4. **可选参数**:如果你希望函数或子过程能够接受可选参数,...

    Passing Binary Data in COM在COM中传递二进制数据

    在COM接口设计中,定义一个接受或返回`VARIANT`类型参数的方法是一种常见的传递二进制数据的方式。例如,可以定义一个名为`TransferBinaryData`的方法,其参数类型为`IN OUT VARIANT *pData`。这样,调用者既可以...

    ATL数组传递详细说明

    本文将详细介绍如何在 ATL/MFC DLL 中实现数组的有效传递,包括数组作为参数传入函数以及作为返回值从函数传出的情况。 #### 二、将数组打包到 VARIANT 在 COM 编程中,`VARIANT` 类型常用于封装多种数据类型,以...

    标准MFC WinSock ActiveX控件开发实例

    在控件的接口中,如`SendData()`和`GetData()`,VARIANT被用来作为参数传递不同类型的数据,这允许控件灵活地处理各种数据格式。 `SendData()`方法用于发送数据,它接受VARIANT类型的`Data`参数,表示要发送的数据...

    如何深入理解C语言中使用指针作为函数参数.pdf

    例如,如果一个函数的目的是交换两个整数变量的值,那么这两个变量的地址就需要作为参数传递给函数,然后在函数内部通过解引用指针来交换它们的值。 文档还强调了初始化指针作为函数参数的必要性。通常,当函数的...

    精彩编程与编程技巧-如何传递不固定个数的叁数...

    在VBScript或VBA等语言中,“ParamArray”关键字被用来定义一个可以接受任意数量参数的子程序或函数。“ParamArray”后的参数必须是最后一个参数,并且必须是变体型(Variant)数组。当调用这样的子程序或函数时,...

    COM特殊数据类型使用演示

    在COM中,有一些特殊的内置数据类型,它们被设计用来处理跨语言和跨平台的通信,这些类型包括BSTR、VARIANT和SAFEARRAY。本文将深入探讨这些数据类型的特性和使用方法,以及他们在实际应用中可能遇到的问题和注意...

    精彩编程与编程技巧-缺省值和可选参数...

    为了提高代码的灵活性和可读性,许多现代编程语言支持指定参数的缺省值,即在调用时如果没有传递该参数,则会使用预设的值。此外,还可以定义参数为可选参数,这样在调用时可以选择性地提供这些参数。 #### 缺省值...

    JAVA + JACOB调用c++COM组件

    本篇文章将详细探讨如何使用Java通过JACOB库来调用C++编写的COM(Component Object Model)组件,特别是涉及VARIANT*和BSTR*这两种数据类型的参数传递。 首先,让我们了解什么是COM组件。COM是一种微软开发的技术,...

    在delphi中实现任意类型的三元运算函数ThreeAsk

    此外,由于`Variant`类型的多态性质,还需要确保传递给`ThreeAsk`的参数类型能够兼容。 为了提高性能和安全性,可以考虑以下改进措施: - **类型检查**:在函数内部添加对`b`和`c`的类型检查,确保它们具有相同或...

    vb转c#程序

    3. **类型系统**:VB.NET中的`Object`和`Variant`在C#中对应的是`object`,VB.NET的`ByVal`和`ByRef`参数传递方式在C#中分别对应`value`和`ref`。 4. **集合和数组**:VB.NET的`ArrayList`在C#中通常被更现代的`...

    VC常用数据类型介绍,数据类型

    - `VARIANT`和`variant_t`、`COleVariant`:用于表示和操作复杂数据类型的结构体,如在COM接口中。 - `WNDPROC`:32位指针,指向窗口过程函数。 - `LANGID`和`LCID`:用于表示语言和区域设置的标识符。 在16位...

    标准MFC WinSock ActiveX控件开发实例(II)高级篇

    在ActiveX控件中,VARIANT作为参数传递,允许控件与宿主应用程序之间灵活的数据交换。理解VARIANT的构造和转换是关键,例如如何将VARIANT转换为特定数据类型,以及如何正确初始化和清理VARIANT变量。 **2. ...

    DB_ANY.pdf

    - 如果形参类型为Variant的FC/FB/指令在实参中填写了DB块,那么该DB必须基于UDT或系统数据类型建立,并且按照相应的类型进行处理。 #### 三、应用场景举例 为了更好地理解DB_ANY的实用价值,我们可以考虑一个具体...

    SafeArray使用.doc

    - 在Automation中,比如在VBA宏或脚本中调用OLE Automation对象,SafeArray用于传递数组参数。 - 自定义COM组件或ActiveX控件的开发,SafeArray可以帮助实现跨语言的数据交换。 总之,SafeArray是COM环境中高效且...

    ADOX字段类型参考

    这些类型提供额外的灵活性,尤其是在参数化查询中。 通过深入理解这些字段类型及其对应的值,开发人员可以更加精确地控制数据的存储和处理方式,从而提高应用程序的性能和可靠性。在使用ADOX进行数据库管理时,选择...

    变体和安全数组.pdf

    由于ActiveX在数据类型方面有严格的定义,变体的存在简化了AutoLISP与ActiveX对象之间参数传递的复杂性,因为变体可以自动地在AutoCAD内部类型与ActiveX所需的特定类型之间进行转换。 创建变体主要通过vlax-make-...

    c#调用ocx问题

    在OCX的接口定义中,数组通常通过`VARIANT*`类型进行传递。`VARIANT`是COM中的一种数据结构,可以容纳各种类型的值,包括数组。当C#项目引用OCX控件时,`VARIANT*`会被自动映射为`ref object`。然而,直接将C#的`...

    java语言使用.net的方法

    在这个例子中,`Your.Net.Class.Name`是.NET DLL中的类名,`YourMethodName`是你要调用的方法名,`参数1`和`参数2`是传递给方法的参数。 4. **注意事项** - 记得在使用完毕后释放COM资源,以避免内存泄漏,这通常...

Global site tag (gtag.js) - Google Analytics