This document covers the following topics:
Every generated object has a set of standard properties. If there are any group definitions in the IDL file, additional properties exist to set and get attributes inside groups and to access groups. See also Properties and Groups.
Note:
The notation of property names is case-sensitive.
/* Initialize C O M */ ... /* Get pointer to instance -> pDspObj */ ... /* Get DispId of property -> DispId_Property */ ... VARIANT presult; HRESULT res = 0; DISPID mydispid = DISPID_PROPERTYPUT; VARIANTARG args[1]; VariantInit(args); /* Next two lines depends on type of corresponding property */ V_R4(args) = <Value> V_VT(args) = VT_R4; DISPPARAMS params; params.rgvarg = args; params.cArgs = 1; params.cNamedArgs = 1; params.rgdispidNamedArgs = &mydispid; EXCEPINFO ExcpInfo; unsigned int pargerr; res = pDspObj->Invoke( DispId_Property, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, &presult, &ExcpInfo, &pargerr ); if ( FAILED( res ) ) { /* Exception handling */ ... }
Dim obj As Object Dim propValue As <Property Type> ... Set obj = CreateObject("<Object Name>") ... obj.<Property Name>=<Value> ...
/* Initialize C O M */ ... /* Get pointer to instance -> pDspObj */ ... /* Get DispId of property -> DispId_Property */ void* psret; HRESULT res; DISPPARAMS params = { NULL, NULL, 0, 0 }; VARIANT result; EXCEPINFO except; unsigned int argerr; res = pDspObj->Invoke( DispId_Property, IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, &result, &except, &argerr ); if ( SUCCEEDED( res ) ) { /* prepare psret */ ... if ( psret != NULL ) { switch ( V_VT(&result) ) { case VT_BSTR: psret = (BSTR)(V_BSTR(&result)); break; case VT_I4: psret = (long*)&(V_I4(&result)); break; case VT_R4: psret = (float*)&(V_R4(&result)); break; case VT_DISPATCH: psret = V_DISPATCH(&result); break; /* cases of other variant types*/ ... default: /* error : unsupported variant type */ } } } else { /* Error Handling */ ... }
Dim obj As Object Dim propValue As <Property Type> ... Set obj = CreateObject("<Object Name>") ... propValue = obj.<Property Name> ...
Additional properties are defined for group handling. There are properties to set or get values of group members (similar to set/get on standard properties) and to get a handle for an interface representing a (sub)group or a pointer to a dispatch object representing a (sub)group.
Notes:
<Group Attribute> ::= <ObjectName>.<Qualifier> <Qualifier> ::= <TopLevel>.<Levels>.<Attribute> | <TopLevel>.<Attribute> | <Attribute> <TopLevel> ::= <program name (uppercase)>_<Level> | <program alias name> <Levels> ::= <Level>.<Levels> | <Level> <Level> ::= <group name(lowercase)> <Index> <Attribute> ::= "attribute name (lowercase)" <Index> ::= "" | "(Index_1)" | "(Index_1, Index_2)" | "(Index_1, Index_2, Index_3)"
Note:
Every index starts with 0.
Library 'MyObject' Is Program 'TEST' Is Define Data Parameter 1 Group_1 2 Attribute_2 (I4) 2 Group_2 3 Attribute_3 (I4) End-Define
IDISPATCH *pDspObj, *pDspTest_group_1, *pDspTest_group_2; /* Initialize C O M */ ... /* Get pointer to instance -> pDspObj */ ... /* some declarations and initializations*/ ... { OLECHAR *Names[] = { L"TEST_group_1" }; DISPID id[1]; res = pDspObj->GetIDsOfNames( IID_NULL; Names, 1, 0, id ); DISPPARAMS params = { NULL, NULL, 0, 0 }; VARIANT presult; res = pDspObj->Invoke( id[0], IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, &presult, NULL, 0); if ( V_VT( &result ) == VT_DISPATCH ) { pDspTest_group_1 = V_DISPATCH(&result); } else { /* error handling */ } } { OLECHAR *Names[] = { L"attribute_2", L"group_2" }; DISPID id[2]; res = pDspTest_group_1->GetIDsOfNames( IID_NULL, Names, 2, 0, id ); DISPPARAMS params = { NULL, NULL, 0, 0 }; VARIANT presult; res = pDspTest_group_1->Invoke( id[0], IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, &presult, NULL, 0); if ( V_VT( &result ) == VT_I4 ) { /* plong2 = pointer to a long */ plong2 = (long*)&(V_I4(&result)); } else { /* error handling */ } res = pDspTest_group_1->Invoke( id[1], IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, &presult, NULL, 0); if ( V_VT( &result ) == VT_DISPATCH ) { pDspTest_group_2 = V_DISPATCH(&result); } else { /* error handling */ } } { OLECHAR *Names[] = { L"attribute_3" }; DISPID id[1]; res = pDspObj->GetIDsOfNames( IID_NULL, Names, 1, 0, id ); DISPPARAMS params = { NULL, NULL, 0, 0 }; VARIANT presult; res = pDspTest_group_2->Invoke( id[0], IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, &presult, NULL, 0); if ( V_VT( &result ) == VT_I4 ) { /* plong3 = pointer to a long */ plong3 = (long*)&(V_I4(&result)); } else { /* error handling */ } }
Dim obj As Object Dim lValue As Long ... Set obj = CreateObject("<Object Name>") ... ' Set value from attribute inside a group obj.TEST_group_1.attribute_2 = lValue obj.TEST_group_1.group_2.attribute_3 = lValue ... ' Get value from attribute inside a group lValue = obj.TEST_group_1.attribute_2 lValue = obj.TEST_group_1.group_2.attribute_3 ...
Program 'TEST' Is Define Data Parameter 1 Group_1A 2 Attribute_2 (I4) 2 Group_2A 3 Attribute_3 (I4) 2 Group_2B (/3,4) 3 Attribute_4 (I4) 1 Group_1B (/5) 2 Group_2C (/3,4) 3 Attribute_5 (I4) 2 Group_2D 3 Attribute_6 (I4) 3 Group_3 4 Attribute_7 (I4) End-Define
/* Example: access to group_1b(2).group_2c(3 , 4).attribute5 */ Idispatch *pdspObj, *pdspPTEST_group_1b, *pdspPTEST_group_1b_group_2c; /* get dispatch pointer to object -> pdspObj */ ... /* get_TEST_group_1b(2) */ { OLECHAR *Names[] = { L"TEST_group_1b" }; DISPID id[1]; res = pdspObj->GetIDsOfNames( IID_NULL, Names, 1, 0, id ); VARIANTARG args[1]; VariantInit(args); V_I4(args) = 1; V_VT(args) = VT_I4; DISPPARAMS params; params.rgvarg = args; params.cArgs = 1; params.cNamedArgs = 0; VARIANT presult; res = pdspObj->Invoke( id[0], IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, &presult, NULL, 0); if ( V_VT( &result ) == VT_DISPATCH ) { pdspTest_group_1b = V_DISPATCH(&result); } else { /* error handling */ } } /* get_group_2c(2,3) */ { OLECHAR *Names[] = { L"group_2c" }; DISPID id[1]; res = pdspTest_group_1b ->GetIDsOfNames( IID_NULL, Names, 1, 0, id ); VARIANTARG args[2]; VariantInit(args); VariantInit(args+1); V_I4(args+1) = 1; V_VT(args+1) = VT_I4; V_I4(args) = 2; V_VT(args) = VT_I4; DISPPARAMS params; params.rgvarg = args; params.cArgs = 2; params.cNamedArgs = 0; VARIANT presult; res = pdspTest_group_1b ->Invoke( id[0], IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, &presult, NULL, 0); if ( V_VT( &result ) == VT_DISPATCH ) { pdspTest_group_1b_group_2c = V_DISPATCH(&result); } else { /* error handling */ } } /* get attribute5 */ long ltemp; { OLECHAR *Names[] = { L"attribute5" }; DISPID id[1]; res = pdspTest_group_1b_group_2c ->GetIDsOfNames( IID_NULL, Names, 1, 0, id ); DISPPARAMS params = { NULL, NULL, 0, 0 }; VARIANT presult; res = pdspTest_group_1b_group_2c ->Invoke( id[0], IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, &presult, NULL, 0); if ( V_VT( &result ) == VT_I4) { ltemp = V_I4(&result); } else { /* error handling */ } }
Dim obj As Object Dim lValue As Long Dim l0, l1, l2 As Long ... Set obj = CreateObject("<Object Name>") ... ' Set value from attribute inside a group obj.TEST_group_1a.attribute_2 = lValue obj.TEST_group_1a.group_2a.attribute_3 = lValue obj.TEST_group_1a.group_2b( i1 , i2 ).attribute_4 = lValue ... obj.TEST_group_1b( i0 ).group_2c( i1 , i2 ).attribute_5 = lValue obj.TEST_group_1b( i0 ).group_2d.attribute_6 = lValue obj.TEST_group_1b( i0 ).group_2d.group_3.attribute_7 = lValue ... ' Get value from attribute inside a group ... lValue = obj.TEST_group_1a.attribute_2 lValue = obj.TEST_group_1a.group_2a.attribute_3 lValue = obj.TEST_group_1a.group_2b( i1 , i2 ).attribute_4 lValue = obj.TEST_group_1b( i0 ).group_2c( i1 , i2 ).attribute_5 lValue = obj.TEST_group_1b( i0 ).group_2d.attribute_6 lValue = obj.TEST_group_1b( i0 ).group_2d.group_3.attribute_7 ...
The IDL syntax allows you to define (remote) procedures only. This is similar to Natural, which knows only procedures (referred to in Natural as subprograms). Neither IDL nor Natural have the concept of a function. A function is a procedure which, in addition to the parameters, returns some value.
It is possible to treat the OUT parameter of a procedure as the return value of a function. Using this technique, a procedure can be used as a function. The DCOM Wrapper generates a function rather than a procedure when the following two conditions are met:
the last parameter of the procedure definition is of type OUT
this last parameter of the procedure definition has the name
Function_Result
Example:
Program 'Calc' Is Define Data Parameter 1 Operator_ (A1) In 1 Operand_1 (I4) In 1 Operand_2 (I4) In 1 Function_Result (I4) Out End-Define
From the above specification, the DCOM Wrapper generates an object that can be called from Visual Basic as follows:
Dim result As Long . . . result = CALCOLEObj.calc ('+', 1234, 1234)
If the last parameter had a name other than
Function_Result
in the IDL file, the call in Visual
Basic would look as follows:
CALCOLEObj.calc '+', 1234, 1234, result
ActiveX automation technology supports only a restricted set of data types (see supported data types).
The DCOM Wrapper supports the use of arrays with up to three dimensions. For all base types, the DCOM Wrapper uses the so-called SAFEARRAY data type for mapping arrays to ActiveX data types.
Note:
When using a SAFEARRAY it is expected that the array has the right
size. It is not recommended to leave any member of an array undefined.
Program 'CPROG'; is Define data parameter 1 IVALUE (I4) IN 1 IARRAY (A80/1:9) IN End-define
... dim arr( ) redim arr(8) ... for n = 0 to 8 arr(n) = "ONLY IN " & (n+1) document.write arr(n) next WrapperObject.CPROG 123, arr
... long i4_single = 12345678; SAFEARRAY *iarray; SAFEARRAYBOUND rgsabound_dim1[] = {9, 0}; char temp [32]; OLECHAR wtemp[32]; iarray = SafeArrayCreate(VT_BSTR, 1, rgsabound_1 ); for (i = 0; i <9; i++) { sprintf (temp,"I%d",(i+1)*1); mbstowcs(wtemp, temp, 80); iarray[i] = SysAllocString(wtemp); } VARIANTARG args[2]; VariantInit(args); VariantInit(args+1); DISPPARAMS params; V_ARRAYREF(args+1) = & iarray; V_VT(args+1) = VT_ARRAY|VT_BSTR|VT_BYREF; V_I4REF(args) = &i4_single; V_VT(args) = VT_I4|VT_BYREF; params.rgvarg = args; params.rgdispidNamedArgs = cNames > 1 ? id+1 : 0; params.cArgs = 2; params.cNamedArgs = cNames-1 ; EXCEPINFO pExcpInfo; res = pDspObj->Invoke( id[0], IID_NULL, 0, DISPATCH_METHOD, ¶ms, NULL, &pExcpInfo, 0 ); ...
... Program 'APROG'; is Define data parameter 1 IVALUE (I4) IN 1 IOARRAY (A80/1:10) IN OUT End-define
... Dim arr( ) ReDim arr(9) ... for n = 0 to 9 arr(n) = "IN OUT" & (n+1) document.write arr(n) next WrapperObject.APROG 123, arr For each strval in arr Document.write strval Next
... long i4_single = 12345678; SAFEARRAY *ioarray; SAFEARRAYBOUND rgsabound_dim1[] = {10, 0}; char temp [32]; OLECHAR wtemp[32]; ioarray = SafeArrayCreate(VT_BSTR, 1, rgsabound_1 ); for (i = 0; i <10; i++) { sprintf (temp,"I%d",(i+1)*1); mbstowcs(wtemp, temp, 80); ioarray[i] = SysAllocString(wtemp); } VARIANTARG args[2]; VariantInit(args); VariantInit(args+1); DISPPARAMS params; V_ARRAYREF(args+1) = &ioarray; V_VT(args+1) = VT_ARRAY|VT_BSTR|VT_BYREF; V_I4REF(args) = &i4_single; V_VT(args) = VT_I4|VT_BYREF; params.rgvarg = args; params.rgdispidNamedArgs = cNames < 1 ? id+1 : 0; params.cArgs = 2; params.cNamedArgs = cNames-1 ; EXCEPINFO pExcpInfo; res = pDspObj->Invoke( id[0], IID_NULL, 0, DISPATCH_METHOD, ¶ms, NULL, &pExcpInfo, 0 ); ...
Program 'BPROG'; is Define data parameter 1 IVALUE (I4) IN 1 OARRAY (A80/1:10) OUT End-define
... Dim OARRAY() ReDim OARRAY(10) 'see Notes on Visual Basic ... WrapperObject.BPROG 123, arr For each strval in arr Document.write strval Next
In C/C++ INOUT and OUT parameters are handled in same way. See the example for INOUT parameters.
Visual Basic arrays start with index 0. VBScript does not support the "dim myarray(... to ...)" notation. Because array sizes are checked you have to dimension your array N-1 when it contains N elements. INOUT arrays have to be defined like OUT arrays and be redimensioned to the required size.
Note:
The DCOM Wrapper can create objects that support VARIANT
references. Scripting languages such as VBScript pass output parameters by
VARIANT references and not via an exactly defined type. For example, when a
method of a COM interface has an out parameter of type String, Visual Basic
passes a reference to a VARIANT to get the out parameter.
DCOM Wrapper objects try to convert these references into the
required reference type.
Referencing attribute values in groups is demonstrated in Properties and Groups. After you have set the attribute values, the method call must be prepared.
The argument list of the method call consists of all attributes and groups at level 1 (that is, attributes in lines beginning with 1 in the IDL file). The group is represented by a dispatch pointer (C/C++) or interface (Visual Basic) that must be passed as an argument. A special property has been introduced to get this group argument (see Properties and Groups).
Program 'EXAMPLE1' Is Define Data Parameter 1 MyStruct 2 MyStruct1 3 MyLong(I4) 3 MyFloat (F4) 2 MyLong (I4) 2 MyFloat (F4) 1 MyStructAsString (A253) 1 Function_Result (I4) Out End-Define
// // initialize structure values // IDispatch *pDspObj, *pDspEXAMPLE1_mystruct, *pDspEXAMPLE1_mystruct_mystruct1; DISPID functionID; ... /* get pointer to group mystruct in program Example1 */ { /* get ID of group mystruct and program Example1 */ OLECHAR *Names[] = { L"EXAMPLE1_mystruct", L"EXAMPLE1" }; DISPID id[2]; res = pDspObj->GetIDsOfNames( IID_NULL, Names, 2, 0, id ); /* store function id */ functionID = id[1]; DISPPARAMS params = { NULL, NULL, 0, 0 }; VARIANT presult; res = pDspObj->Invoke( id[0], IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, &presult, NULL, 0); if ( V_VT( &result ) == VT_DISPATCH ) { pDspEXAMPLE1_mystruct = V_DISPATCH(&result); } else { /* error handling */ } } { OLECHAR *Names[] = { L"mystruct_1" }; DISPID id[1]; res = pDspEXAMPLE1_mystruct ->GetIDsOfNames( IID_NULL, Names, 1, 0, id ); DISPPARAMS params = { NULL, NULL, 0, 0 }; VARIANT presult; res = pDspEXAMPLE1_mystruct ->Invoke( id[0], IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, &presult, NULL, 0); if ( V_VT( &result ) == VT_DISPATCH ) { pDspEXAMPLE1_mystruct_mystruct1 = V_DISPATCH(&result); } else { /* error handling */ } } ... /* call the function EXAMPLE1 */ { BSTR MyString = SysAllocString(L""); VARIANTARG args[2]; VariantInit(args); VariantInit(args+1); V_DISPATCH(args+1) = pDspEXAMPLE1_mystruct; V_VT(args+1) = VT_DISPATCH; V_BSTRREF(args) = &MyString; V_VT(args) = VT_BSTR|VT_BYREF; DISPPARAMS params; params.rgvarg = args; params.cArgs = 2; params.cNamedArgs = 0; EXCEPINFO ExcpInfo; unsigned int uArgErr; /* call procedure EXAMPLE1 */ res = pDspObj->Invoke( functionID, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, ¶ms, &presult, &ExcpInfo, &uArgErr ); if (FAILED(res)) { /* error handling */ } if ( V_VT(&result) == VT_I4 ) { ltemp = V_I4(&result); } else { /* Wrong data type */ } }
Dim obj As Object ... Set obj = CreateObject("<object name>") ... Dim retString As String Dim retCode As Long retString = " " obj.EXAMPLE1_mystruct.mystruct1.mylong = ... obj.EXAMPLE1_mystruct.mystruct1.myfloat = ... obj.EXAMPLE1_mystruct.mylong = ... obj.EXAMPLE1_mystruct.myfloat = ... obj.EXAMPLE1obj.EXAMPLE1_mystruct, retString ' get value in structure myVar1 = obj.EXAMPLE1_mystruct.mystruct1.mylong myVar2 = obj.EXAMPLE1_mystruct.mylong
Referencing attribute values in periodic groups is demonstrated in Properties and Groups. The argument list of the method call consists of all attributes and (periodic) groups at level 1 (that is, attributes in lines beginning with 1 in the IDL file). The group is represented by a dispatch pointer (C/C++) or interface (Visual Basic) that must be passed as an argument. If a periodic group at level 1 exists, it is passed as an array of dispatch pointers (C/C++) or interfaces (Visual Basic) in the argument list (see Handling Arrays). A special property (<PROGRAM NAME>_<group name>_all) has been introduced to get this array of group arguments.
Program 'PGROUP' Is Define Data Parameter 1 TABLE (/5,4) 2 CELL (F8) 1 RESULTH (F8/4) 1 RESULTV (F8/5) End-Define
HRESULT res, hr; VARIANT result; long lindex[2]; /* safearray init */ SAFEARRAY* psaDsp; SAFEARRAYBOUND boundaries[2]; boundaries[0].lLbound=0; boundaries[0].cElements= 5; boundaries[1].lLbound=0; boundaries[1].cElements= 4; SAFEARRAY* psaResH; SAFEARRAYBOUND boundariesH[1]; boundariesH[0].lLbound=0; boundariesH[0].cElements= 4; SAFEARRAY* psaResV; SAFEARRAYBOUND boundariesV[1]; boundariesV[0].lLbound=0; boundariesV[0].cElements= 5; psaDsp = SafeArrayCreate(VT_DISPATCH, 2, boundaries); psaResH = SafeArrayCreate(VT_R8, 1, boundariesH); psaResV = SafeArrayCreate(VT_R8, 1, boundariesV); ... OLECHAR *Names[] = { L"PGROUP", L"PGROUP_table" }; DISPID id[2]; pDspObj -> GetIDsOfNames( IID_NULL, Names, 2, 0, id ); DISPID FuncId_PGROUP = id[0]; DISPID StructId_PGROUP_table = id[1]; IDispatch* dspTemp2; /* get each dispatch pointer to elements of periodic group */ for ( lindex[0] = 0; lindex[0] < 5; lindex[0]++) { for ( lindex[1] = 0; lindex[1] < 4; lindex[1]++) { VARIANTARG args[2]; VariantInit(args); VariantInit(args+1); V_I4(args+1) = lindex[0]; V_VT(args+1) = VT_I4; V_I4(args) = lindex[1]; V_VT(args) = VT_I4; DISPPARAMS params; params.rgvarg = args; params.cArgs = 2; params.cNamedArgs = 0; res = pDspObj->Invoke( StructId_PGROUP_table, IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, &result, NULL, NULL ); if ( SUCCEEDED( res ) || ( V_VT(&result) == VT_DISPATCH )) { IDispatch* dspTemp = V_DISPATCH(&result); dspTemp2 = dspTemp; SafeArrayPutElement(psaDsp, (long*) lindex, dspTemp) } } } /* get dispid for setting values */ OLECHAR *Names[] = { L"cell" }; DISPID id[1]; pDspObj -> GetIDsOfNames( IID_NULL, Names, 1, 0, id ); DISPID dispidTableCell = id[0]; /* set values */ DISPID mydispid = DISPID_PROPERTYPUT; for ( lindex[0] = 0; lindex[0] <5; lindex[0]++) { for ( lindex[1] = 0; lindex[1] < 4; lindex[1]++) { hr = SafeArrayGetElement(psaDsp, (long*) lindex, &dspTemp2) VARIANTARG args[1]; VariantInit(args); V_R8(args) = <double value>; V_VT(args) = VT_R8; DISPPARAMS params; params.rgvarg = args; params.cArgs = 1; params.cNamedArgs = 1; params.rgdispidNamedArgs = &mydispid; res = dspTemp2->Invoke( dispidTableCell, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, &result, NULL, NULL ); } } /* call function */ VARIANTARG args[3]; VariantInit(args+2); VariantInit(args+1); VariantInit(args); V_ARRAYREF(args) = &psaResV; V_VT(args) = VT_R8|VT_ARRAY|VT_BYREF; V_ARRAYREF(args+1) = &psaResH; V_VT(args+1) = VT_R8|VT_ARRAY|VT_BYREF; V_ARRAYREF(args+2) = &psaDsp; V_VT(args+2) = VT_DISPATCH|VT_ARRAY|VT_BYREF; DISPPARAMS params; params.rgvarg = args; params.cArgs = 3; params.cNamedArgs = 0; res = pDspObj->Invoke( FuncId_PGROUP, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, ¶ms, &result, NULL, NULL ); ...
' declare array of interface pointer for structures access Dim i1, i2 As Long ' define as dynamic arrays Dim dblhres() As Double Dim dblvres() As Double ' set safearray bounds ReDim dblhres(0 To 3) ReDim dblvres(0 To 4) ' Initialize values ... ' set values in structure For i1 = 0 To 4 For i2 = 0 To 3 obj.PGROUP_table(i1, i2).cell = ... Next i2 Next i1 ' method call obj.PGROUP obj.PGROUP_table_all, dblhres, dblvres ... End Sub