NGWS SDK Documentation  

This is preliminary documentation and subject to change.
To comment on this topic, please send us email at ngwssdk@microsoft.com. Thanks!

Marshaling Method Calls

As described in section 4.1.4.5, all methods have a managed and an unmanaged method signature. The CCW is then responsible for marshaling method calls from the unmanaged signature to the managed signature. It’s the stub that acts as the facilitator between these two programming models. The stub performs 4 important tasks during marshaling:

  1. It manages the code transition
  2. It catches exceptions and returns HResults
  3. It packs the return values into an out-parameter
  4. It marshals data types from one format to another

Managing Code Transitions

Handling Managed Exceptions

COM interfaces return HResults to convey error information to the caller. NGWS runtime introduces the ability to throw exceptions across object interfaces but only from one managed object to another. When classic COM clients are using NGWS objects, the stub must to maintain HResult semantics that these clients are expecting. Therefore, exceptions that occur during calls made by COM clients must be mapped to the equivalent COM HResults and returned to the COM client.

For example, given the following description of the IFoo interface:

interface IFoo : IDispatch
{
   HRESULT StartWork();
   HRESULT GetCount([out, retval] long *lCount)
}

A NGWS developer may implement the interface as follows

class CFoo : public IFoo
{
   void StartWork()
   {
      if (…) throw RuntimeException
   }
   
   long GetCount()
   {
      if (…) throw RuntimeExceptions
   }
}

In the NGWS runtime, the methods that return HResults are replaced by methods that throw NGWS runtime exceptions. In this case, if a NGWS runtime client uses the CFoo class, it can catch the exceptions thrown in CFoo::StartWork and CFoo::GetCount in the usual way. But, when the same class is used by a classic COM client, the stub catches the exception thrown by the class and returns an HResult to the caller. If the method executes without throwing an exception, the stub returns S_OK.

In order to do this, the runtime needs a mapping between Exceptions and HResults. Each NGWS runtime exception class defined in the NGWS frameworks has a static member called ErrorCode for storing a classic COM HResult. The class library exception classes are automatically initialized with the proper HResult. Some NGWS runtime exceptions map to existing HResults. For example, OutOfMemoryException maps to the HResult COR_E_OUTOFMEMORY, which is equivalent to E_OUTOFMEMORY. Most NGWS runtime Exceptions map to new HResult values.

User defined classes that extend System.Exception must also set the static ErrorCode field during construction. The ErrorCode field of the base exception class called Exception is initialized to E_FAIL. If the HResult field is not reinitialized in the sub class then the E_FAIL HResult is used as the default.

New exception classes can be created as required by application developers. Recoverable exceptions that are application related should be derived from the ApplicationException class. New exception class can be mapped to an existing HRESULT by supplying the HRESULT value in the exception’s constructor. For example, a new exception class called NoAccessException can be created and mapped to the HRESULT E_ACCESSDENIED with the following code:

Class NoAccessException : public ApplicationException
{
   ErrorCode = E_ACCESSDENIED; 
}

CMyClass::MethodThatThrows
{
   NoAccessException *e;

   e = new NoAccessException();

   throw e;
}

Additional information about the exception is provided to the client through the IErrorInfo interface that it also exposed by the wrapper (See section 4.9.5 below).

Success Results - COM also supports the notion of success HResults that can be returned from any COM method to convey information to the caller rather than indicate and error condition. Examples include S_FALSE and DB_S_ENDOFROWSET. The mechanism described above (mapping exceptions to HResults) does not support success HResults mainly because the runtime does not advocate the use of exceptions for reporting non-exceptional situations (like a FalseException or EndOfRowsetException). None exceptional information should instead be reported to NGWS runtime client through a return value or an out parameter.

Converting Return Values

Return values from the NGWS runtime methods are handled through [out, retval] parameters added to the COM signature of the method. A NGWS runtime method that is defined with a void return simply has no [out, retval] parameter. A NGWS runtime method with an int return type would have an [out, retval] int * parameter added to the COM method signature.

Return values may also need to be converted from a NGWS runtime type to a COM type. For example, the following method returns a System.String that is converted to a BSTR in the COM Signature.

NGWS runtime signature:

System.String GetName();

COM signature:

HRESULT GetName([out, retval] BSTR *rv);

For information on type conversions see Error! Reference source not found. below.

Marshaling Data Types

As the SetDate example below shows, type conversion is also applied to method parameters. For the most part, integer and floating point data types are marshaled without conversion but other types like string, and date are converted to the NGWS classes that represent those types.

NGWS runtime signature:

void SetDate(System.DateTime d);

COM signature:

HRESULT SetDate(DATE d);

For complete information on type conversions see section Error! Reference source not found. below.