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!

Consuming Selected interfaces

IUnknown

The RCW will hold a reference to the classic COM Server, and will release that reference when it is garbage collected. At that point the classic COM Server will be Released. When the NGWS runtime client requests a new interface the wrapper will handle the call through QueryInterface(). When a new interface is passed to a NGWS runtime client via any means the wrapper will be responsible for releasing the reference on that interface when the wrapper is garbage collected.

The NGWS runtime only maintains one RCW per object. It distinguishes between objects by comparing the values of the IUnknown pointers it receives. When an interface is being passed into the NGWS runtime, the Runtime queries on that interface for IUnknown, then checks that interface pointer against the ones already being wrapped.

ISupportErrorInfo

If the classic COM Server being wrapped returns an error HRESULT from a method call, the RCW will throw an exception to the NGWS runtime client. If the classic COM Server provides additional error information (via ISupportErrorInfo and GetLastError) the extended error information will also be propogated into the exception object.

The failure HRESULT returned from a call is converted to an exception and thrown by the RCW on return from the call. The NGWS runtime client can then catch the exception just like any other exception. The type of exception thrown depends on the HRESULT returned. The table below contains a complete list all NGWS runtime exceptions along with the HRESULTs return values that will cause those exceptions to be thrown. If a failure HRESULT that is not listed in the table is returned, the runtime throws an ApplicationException. The client can determine the HRESULT that caused the exception by examining the ErrorCode field of the Exception object.

HResult Returned Exception thrown by RCW
COR_E_ACCESS AccessException
COR_E_AMBIGUOUSMATCH AmbiguousMatchException
MSEE_E_APPDOMAINUNLOADED AppDomainUnloadedException
MSEE_E_APPDOMAINUNLOADINPROGRESS AppDomainUnloadInProgressException
COR_E_APPLICATION ApplicationException
COR_E_ARGUMENT ArgumentException
E_POINTER ArgumentNullException
COR_E_ARGUMENTOUTOFRANGE ArgumentOutOfRangeException
COR_E_ARITHMETIC ArithmeticException
COR_E_ARRAYTYPEMISMATCH ArrayTypeMismatchException
MSEE_E_CLASSUNLOADED ClassUnloadedException
COR_E_COMEMULATE_ERROR COMEmulateException
COR_E_CONTEXTMARSHAL ContextMarshalException
COR_E_CORE CoreException
NTE_FAIL CryptographicException
COR_E_DIRECTORYNOTFOUND DirectoryNotFoundException
COR_E_DIVIDEBYZERO DivideByZeroException
COR_E_DUPLICATEWAITOBJECT DuplicateWaitObjectException
COR_E_ENDOFSTREAM EndOfStreamException
COR_E_TYPELOAD EntryPointNotFoundException
COR_E_EXCEPTION Exception
COR_E_EXECUTIONENGINE ExecutionEngineException
COR_E_FIELDACCESS FieldAccessException
COR_E_FILENOTFOUND FileNotFoundException
COR_E_FORMAT FormatException
COR_E_INDEXOUTOFRANGE IndexOutOfRangeException
COR_E_INVALIDCAST InvalidCastException
COR_E_INVALIDCOMOBJECT InvalidComObjectException
COR_E_INVALIDFILTERCRITERIA InvalidFilterCriteriaException
COR_E_INVALIDOLEVARIANTTYPE InvalidOleVariantTypeException
COR_E_INVALIDOPERATION InvalidOperationException
COR_E_IO IOException
COR_E_METHODACCESS MethodAccessException
COR_E_MISSINGFIELD MissingFieldException
COR_E_MISSINGMANIFESTRESOURCE MissingManifestResourceException
COR_E_MISSINGMEMBER MissingMemberException
COR_E_MISSINGMETHOD MissingMethodException
COR_E_MULTICASTNOTSUPPORTED MulticastNotSupportedException
COR_E_NOTFINITENUMBER NotFiniteNumberException
E_NOTIMPL NotImplementedException
COR_E_NOTSUPPORTED NotSupportedException
COR_E_NULLREFERENCE NullReferenceException
E_OUTOFMEMORY OutOfMemoryException
COR_E_OVERFLOW OverflowException
COR_E_PATHTOOLONG PathTooLongException
COR_E_RANK RankException
COR_E_REFLECTIONTYPELOAD ReflectionTypeLoadException
COR_E_REMOTING RemotingException
COR_E_SAFEARRAYTYPEMISMATCH SafeArrayTypeMismatchException
COR_E_SECURITY SecurityException
COR_E_SERIALIZATION SerializationException
COR_E_STACKOVERFLOW StackOverflowException
COR_E_SINKHRONIZATIONLOCK SinkhronizationLockException
COR_E_SYSTEM SystemException
COR_E_TARGET TargetException
COR_E_TARGETINVOCATION TargetInvocationException
COR_E_TARGETPARAMCOUNT TargetParameterCountException
COR_E_THREADABORTED ThreadAbortException
COR_E_THREADINTERRUPTED ThreadInterruptedException
COR_E_THREADSTATE ThreadStateException
COR_E_THREADSTOP ThreadStopException
COR_E_TYPELOAD TypeLoadException
COR_E_TYPEINITIALIZATION TypeInitializationException
COR_E_VERIFIER VerifierException
COR_E_WEAKREFERENCE WeakReferenceException
All other HResults ComException

Only failure HRESULTs (those with the severity bit set) will cause exceptions to be thrown by the RCW. Success HRESULTs do not cause exceptions to be thrown.

To get additional information about the exception, the NGWS runtime client would typically examine the fields of the Exception object that’s thrown. In order for the runtime to provide meaningful information about the error, the COM server must implement the IErrorInfo interface. If the COM server supports IErrorInfo, the runtime will use the information provided through IErrorInfo to initialize the Exception object. If the classic COM server does not support IErrorInfo, the Exception object is initialized with default values.

Exception Field COM Source of information
ErrorCode HResult returned from call
HelpLink If IErrorInfo->HelpContext() is non-zero, the String formed by concatenating IErrorInfo->GetHelpFile() and “#” and IErrorInfo->GetHelpContext(). Otherwise the string returned from IErrorInfo->GetHelpFile().
InnerException Always Null
Message String returned from IErrorInfo->GetDescription()
Source String returned from IErrorInfo->GetSource()
StackTrace The stack trace
TargetSite The name of the method that returned the failing HResult.

IProvideClassInfo

If the classic COM Server being wrapped implements IProvideClassInfo, the RCW will use this type information to provide support for Reflection as well as interrogating the type information for it’s own purposes. Type information may also be obtained from the Registry, or from an IDispatch implementation. As mentioned in Section 2, Class information is required before an object can be wrapped.

IDispatch

Dispinterfaces exposed by COM servers can only be accessed from the NGWS runtime through reflection. Reflection is the mechanism for doing object inspection and dynamic invocation. You cannot make a direct method call on an RCW if the RCW is only wrapping a dispinterface.

Properties

A dual interface or dispinterface may declare properties as well as methods. All properties have corresponding accessor methods for setting or getting the property values. When converting a type library description of an interface with properties to metadata, a property as well as one or more accessor methods for that property is created. The type library conversion process applies the following transformations to property accessor methods.

For example:

In a Type Library:

interface ISample : IDispatch {
   [propget,    HRESULT prop1([out, retval] short *pVal);
   [propput,    HRESULT prop1([in] short newVal);

   [propget,    HRESULT prop2([out, retval] IFoo **pVal);
   [propputref, HRESULT prop2([in] IFoo *newVal);

   [propget,    HRESULT prop3([out, retval] IFoo **ppIFoo);
   [propput,    HRESULT prop3([in] BSTR *text);
   [propputref, HRESULT prop3([in] IFoo *pIFoo);
}

In Managed C++:

interface ISample {
   __property short prop1 {get {}; set {};};   // propget, propset
   __property IFoo prop2 {get {}; set {};};    // propget, propset
   __property IFoo prop3 {get {}; set()};   // propget, propputref
   Letprop3(String text);               // propput 

}

In Visual Basic:

Public Property Get Prop1() As Integer … End Property
Public Property Let Prop1(val as Integer) … End Property

Public Property Get Prop2() As IFoo … End Property
Public Property Let Prop2(val as IFoo) … End Property

Public Property Get Prop3() As IFoo … End Property
Public Property Let Prop3(val as IFoo) … End Property
Public Setprop3Value(String as Text) … End Property

Methods

Events

IDispatchEx

ITypeInfo

The runtime also provides a custom marshaler for marshaling the ITypeInfo interface to the System.Type class. Any unmanaged method that uses the ITypeInfo interface will automatically use the marshaler when the method is exposed to the NGWS runtime. The TlbImp utility will convert all references to ITypeInfo to System.Type on import.

For example, the following unmanaged type:

interface TypeProvider {
   HRESULT SetType([in] ITypeInfo *t);
   HRESULT SetTypeRef([in, out] ITypeInfo **t);
   HRESULT GetType([out, retval] ITypeInfo **t);
}

Is converted to:

interface TypeProvider {
   void SetType(System.Type t);
   void SetTypeRef(ref System.Type t);
   System.Type GetType();
}

IConnectionPointContainer

IPersistFile, IPersistStream

IEnumVariant

A custom marshaler is provided by the runtime that provides a bridge between the COM interface IEnumVariant and the the NGWS frameworks interface IEnumerator. The custom marshaler causes method parameters and properties of type IEnumVariant to be exposed to the NGWS runtime as the IEnumerator interface. So for example, a COM collection object with a property of type IEnumVariant whose unmanaged signature is:

HResult _NewEnum(IEnumVariant *pEnum);

Would have the following signature when exported to a COM type library.

IEnumerator _NewEnum ();

The marshaler automatically delegates the calls from the NGWS runtime interface to the COM interface in the following way:

bool IEnumerator.MoveNext()

Calls IEnumVariant.Next(1, …) and caches the Variant returned as an Object. If Next returns S_FALSE, the method returns False otherwise the method returns true.

Object IEnumerator.Current()

Returns the object cached when MoveNext was called.

For additional details on custom marshaling see the Custom Marshaling spec.

Identifying Enumerators

In the NGWS frameworks, enumerators are provided by the System.Collections.IEnumerable interface.

public interface IEnumerable 
{
   IEnumerator GetEnumerator();
}

The interface has a method called GetEnumerator that returns an enumerator. When imported by typelib importer, any COM coclass that provides an enumerator will also appear to implement the IEnumerable interface. For example, the Fields interface defined in a typelib as follows:

interface Fields : {
   …
   [id(0xfffffffc)] HRESULT _NewEnum([out, retval] IUnknown** ppvObj);
   …
};

Would be imported by the typelib importer as:

interface Fields : implements IEnumerable
{
   Object _NewEnum();
   IEnumerator GetEnumerator();
}

Notice that the GetEnumerator method is automatically added to the interface and that the interface implements IEnumerable. The proper way of obtaining the enumerator for any managed type (including RCW’s) is to cast the type to IEnumerable and then call IEnumerable.GetEnumerator.