Reusing a COM Component
When reusing an existing COM component, the wizard generates the necessary code to access it. The plumbing is already done so that instantiating an Eiffel class corresponding to one of the component's coclasses automatically calls the right COM initialization APIs.
Calling a feature on an Eiffel class corresponding to one of the component's coclasses forwards the call to the member on the corresponding interface. The data types of the function arguments are either Eiffel types defined in Eiffel data structure libraries, standard data types defined in the EiffelCOM library, or custom data types declared in the COM definition file. For example, from the following IDL line:
HRESULT Function ([in] int a, [out, retval] MyStruct * b)
The wizard generates the following feature:
function (a: INTEGER): MY_STRUCT_RECORD
HRESULT Function ([in] ISomething * pInterface)
The wizard generates the following Eiffel feature:
function (p_interface: ISOMETHING_INTERFACE)
All the Eiffel classes corresponding to the component's interfaces are generated in Common\Interfaces. These deferred classes include one deferred feature per function defined in the interface. They are equipped with automatically generated assertions. However, the wizard cannot generate fully specified contracts since it has no domain specific knowledge. It can only generate contracts that are domain independent. Such contracts, although useful, are not enough to describe entirely the behavior of the component. Generated contracts include checking for
null C pointers for wrappers. There might be a need for additional assertions. Invariants and postconditions can be added in an heir of the generated Eiffel coclass proxy. Preconditions, however, cannot be strengthened. A workaround provided by the wizard consists of generating a precondition function for each feature in the interface. The default implementation of these functions always returns
function (a: INTEGER): MY_STRUCT
-- Example of a generated Eiffel coclass feature
non_void_my_struct: Result /= Void
The COM standard requires that any interface function returns a status value (known as a
As a result, any feature in the client making calls to the Eiffel classes corresponding to the component's coclasses should include a
rescue clause. The processing done in this clause might depend on the nature of the exception. All the standard COM exceptions can be found in the library class
The following code snippet illustrates how a client can process exceptions raised by a call to an Eiffel class representing a component's coclass:
description: "Eiffel coclass client example"
feature -- Basic Operations
-- Example of a coclass feature caller
if not retried then
coclass.coclass_feature -- Actual call
if hresult = E_notimpl then
-- Process non implemented function error.
retried := True
elseif hresult = E_invalidarg then
-- Process invalid argument error.
retried := True
-- Forward exception to caller.
end -- class COCLASS_CLIENT