Passing values between extensions and the PBVM

PBNI uses two interfaces, IPB_Value and IPB_Arguments, to pass PowerBuilder values between the PBVM and extension PBXs. The PBNICallInfo structure holds the data.

PBCallInfo structure

The PBCallInfo structure is used to hold data and return type information for calls between extensions and the PBVM. It has three public members:

IPB_Arguments*   pArgs;
IPB_Value*           returnValue;
pbclass                   returnClass;

The following code initializes a PBCallInfo structure using the IPB_Session InitCallInfo method. After allocating a PBCallInfo structure called ci, the IPB_Session GetClass and GetMethodID methods are used to get the class and method ID of the current method. Then, these parameters are used to initialize the ci structure:

pbclass cls;
pbmethodID mid;
PBCallInfo* ci = new PBCallInfo;

cls = Session -> GetClass(myobj);
mid = Session -> GetMethodID(cls, "myfunc",
   PBRT_FUNCTION, "II");

Session -> InitCallInfo(cls, mid, ci);

When you have finished using a PBCallInfo structure, you must call FreeCallInfo to release the allocated memory:

Session -> FreeCallInfo(ci);
delete ci;

The IPB_Arguments and IPB_Value interfaces have methods that enable you to pass values between the PBVM and PowerBuilder extension modules using PBCallInfo to hold the data.

IPB_Arguments interface

The IPB_Arguments interface has two methods:

  • GetCount obtains the number of arguments in a method call.

  • GetAt obtains the value at a specific index of the pArgs member of the PBCallInfo structure. For each argument, GetAt returns a pointer to the IPB_Value interface.

The following code fragment uses GetCount and GetAt in a FOR loop to process different argument types. The ci-> pArgs -> GetCount()statement gets the number of arguments, and ci -> pArgs -> GetAt(i) gets the value at the index i. This value is a pointer to the IPB_Value interface on which IPB_Value methods, such as IsArray and GetArray, can be called (see IPB_Value interface):

int i;
for (i=0; i < ci-> pArgs -> GetCount();i++)
{
   pbuint ArgsType;
   if( ci -> pArgs -> GetAt(i) -> IsArray())
         pArguments[i].array_val = 
         ci -> pArgs -> GetAt(i) -> GetArray();
      continue;
   }

   if( ci -> pArgs -> GetAt(i) -> IsObject()) 
   {
      if (ci -> pArgs -> GetAt(i) -> IsNull()) 
         pArguments[i].obj_val=0;
      else
         pArguments[i].obj_val = 
            ci -> pArgs -> GetAt(i) -> GetObject();
      continue;
   }
   ...

IPB_Value interface

IPB_Value has three sets of methods: helper methods, set methods, and get methods.

Helper methods

The IPB_Value interface helper methods provide access to information about variables and arguments, including the value's class and type, whether it is an array or simple type, whether it is set by reference, and whether the null flag is set. There is also a method that sets the value to null:

virtual pbclass          GetClass() const = 0;
virtual pbint              GetType() const = 0;
virtual pbboolean     IsArray() const = 0;
virtual pbboolean     IsObject() const = 0;
virtual pbboolean     IsByRef() const = 0;
virtual pbboolean     IsNull() const = 0;
virtual PBXRESULT   SetToNull() = 0;

The example shown in the previous section, IPB_Arguments interface, shows how you can use three of these methods: IsArray, IsObject, and IsNull.

This example shows how you can use the SetToNull method to set the returnValue member of the PBCallInfo structure to null:

if ( ci->pArgs->GetAt(0)->IsNull() ||
   ci->pArgs->GetAt(1)->IsNull() )
   {
// if either of the passed arguments is null, 
// return the null value
ci->returnValue->SetToNull();

Set methods

The IPB_Value set methods set values in the PBCallInfo structure. There is a set method for each PowerBuilder datatype: SetInt, SetUint, SetLong, SetUlong, and so on. These methods automatically set the value represented by IPB_Value to not null. The syntax is:

virtual PBXRESULT Set<type>(<pbtype> arg);

For example, the SetLong method takes an argument of type pblong.

In this example, the method has two integer arguments, set to int_val1 and int_val2:

ci-> pArgs -> GetAt(0) -> SetInt(int_val1);
ci-> pArgs -> GetAt(1) -> SetInt(int_val2);

The IPB_Value set methods set the datatype of the value represented by IPB_Value to a specific type. If the original type of the value is any, you can set it to any other type. Then, because the value now has a specific type, setting it to another type later returns the error PBX_E_MISMATCHED_DATA_TYPE. If the argument is readonly, the error PBX_E_READONLY_ARGS is returned.

Get methods

The IPB_Value get methods obtain values from the PBCallInfo structure. There is a get method for each PowerBuilder datatype: GetInt, GetUint, GetLong, GetUlong, and so on.The syntax is:

virtual <pbtype> Get<type>( ); 

For example, the GetString method returns a value of type pbstring.

The following example uses the IPB_Value GetAt method to assign the value at the first index of the pArgs member of the PBCallInfo structure to a variable of type IPB_Value* called pArg. If pArg is not null, the GetLong method sets the variable longval to the value in pArg:

PBCallInfo   *ci
...
pblong longval = NULL;
IPB_Value* pArg = ci-> pArgs-> GetAt(0);
   if (!pArg->IsNull())
   longval = pArg -> GetLong();

If the value is null, or if you use a get method that is expected to return one datatype when the value is a different datatype (such as using GetLong when the datatype is pbarray), the result returned is undetermined.

The get methods can also be used with the returnValue member of PBCallInfo:

ret_val = ci.returnValue->GetInt();
return ret_val;