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
where HRESULT Function ([in] ISomething * pInterface)
The wizard generates the following Eiffel feature:
function (p_interface: ISOMETHING_INTERFACE)
where
Contracts
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
require
function_user_precondition: function_user_precondition
do
...
ensure
non_void_my_struct: Result /= Void
end
So the complete class hierarchy for an Eiffel client coclass is the following:
Exceptions
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:
note
description: "Eiffel coclass client example"
class
COCLASS_CLIENT
inherit
ECOM_EXCEPTION
export
{NONE} all
end
feature -- Basic Operations
coclass_feature_client
-- Example of a coclass feature caller
local
retried: BOOLEAN
coclass: EIFFEL_COCLASS_PROXY
do
if not retried then
create coclass.make
coclass.coclass_feature -- Actual call
end
rescue
if hresult = E_notimpl then
-- Process non implemented function error.
retried := True
retry
elseif hresult = E_invalidarg then
-- Process invalid argument error.
retried := True
retry
else
-- Forward exception to caller.
end
end
end -- class COCLASS_CLIENT