|
|
If you are the author of a COM component that is going to be used by .NET
Interfaces
Avoid manually redefining COM interfaces in managed code. This task consumes time and rarely produces a managed interface compatible with the existing COM interface. Instead, use TlbImp.exe to maintain definition compatibility.
Avoid defining
Provide ways to explicitly release resources. Many COM components release resources when their reference count
Avoid optional parameters in methods because C# cannot treat them as optional.
Use dual interfaces whenever possible because this allows early or late binding from .NET clients.
Data
Use Automation-compatible types where possible. Avoid Variants, asking yourself why you arent using a more specific type.
Avoid using void* pointers to refer to interfaces. If an interface method can return a pointer to any interface, it is very common to use a void* pointer to accomplish this:
HRESULTGetAnInterfacePointer([in]REFIIDtheInterfaceId,
[out,iid_is(theInterfaceId)]void**pTheInterface);
The second parameter will be marshaled as an IntPtr , which is not descriptive or easy to use. It would be better to amend the IDL to use IUnknown* instead and to specify [retval] :
HRESULTGetAnInterfacePointer([in]REFIIDtheInterfaceId, [out,retval,iid_is(theInterfaceId)]IUnknown**pTheInter face);
Now the second parameter will be marshaled as a Guid , which can then be cast to the appropriate interface type by the client.
Use blittable types (which have direct managed equivalents) where possible. Nonblittable types will require conversion during marshaling, and therefore will not perform as well as blittable types.
Avoid ANSI strings if possible because it is much more efficient to marshal Unicode string data.
Use
SAFEARRAY
s instead of variable-length arrays because of the problems with marshaling IDL arrays explained earlier. Also, wherever possible, use
Dont define structs with SAFEARRAY fields because the importer doesnt support them.
Error reporting
Avoid returning failure
HRESULT
s for informational purposes.
HRESULT
s are mapped to exceptions so that when an interop assembly receives a failure
HRESULT
from a component, it throws a corresponding
HRESULT
. There is an overhead associated with processing exceptions, but almost no overhead is incurred by the exception handling code when no exception occurs. For this reason, use
HRESULT
s only to signal errors. In addition,
HRESULT
s are
Always use rich error reporting from COM components, using the ISupportErrorInfo and IErrorInfo interfaces. Components written in C++ using ATL should have the ISupportErrorInfo check box checked on the Options page of the ATL Object Wizard, and should use the ATL CComModule::Error method to return error information using IErrorInfo . In Visual Basic 6 code, use the Error.Raise method with the optional Source , Description , HelpFile , and HelpContext fields:
'Raiseerror1000,withthesource "TheComponent"
'andthespecifiederrormessage.
'Thelasttwoparametersspecifyahelpfile
'andhelpcontextID
Err.Raise1000,"TheComponent", "Therehasbeenanerror",_
helpfile.hlp,100
Type Libraries
Provide and register type libraries, so that .NET programmers can use TlbImp to generate interop assemblies. Provide version and locale information in type libraries because this is propagated through to the interop assembly.
Avoid defining functions in IDL modules, since these are not imported when creating the interop assembly.
Other Considerations
Implement
IProvideClassInfo
. Methods often contain interface pointers as arguments. The type library importer
Make as few transitions across the managed/unmanaged boundary as possible because of the cost involved in this transition. This might mean
|
|