The wizard generates all the necessary code to access the existing component. The plumbing is already done, so instantiating an Eiffel coclass actually initializes COM internals.
To access the component, you need to call features of the coclass. The data types of function arguments are either Eiffel types defined in Eiffel data structure libraries (EiffelBase), standard COM data types defined in the EiffelCOM library, or component COM data types specified in the definition file. For example, from the following IDL line
HRESULT InterfaceFunction ([in] int a, [out, retval] MyStruct * b)
The wizard generates the following feature in the Eiffel coclass:
interface_function (a: INTEGER): MY_STRUCT_RECORD
where MY_STRUCT_RECORD is a generated Eiffel class wrapping MyStruct.Here is a more difficult example:
HRESULT a_function ([in] IsomeInterface * p_interface)
The wizard generates the following Eiffel feature:
a_function (p_interface: ISOME_INTERFACE_INTERFACE)
where ISOME_INTERFACE_INTERFACE is a generated deferred class. Where can you obtain an instance of the class? First, you may receive from other function. Second, you can create an implemented server interface ISOME_INTERFACE_IMPL_STUB. In the later case you should provide your own implementation.
The wizard cannot generate fully specified contracts. Indeed, the tool has no domain specific knowledge and 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 void Eiffel objects as well as C pointer validity (for wrappers) checking. There might be other conditions to allow calls to an Eiffel coclass feature. Invariants and postconditions can be enforced in an heir of the generated Eiffel coclass. Preconditions, however, cannot be strengthened. A workaround provided by the wizard is to generate a precondition function for each feature in the interface. The default implementation of these functions always returns True. They should be redefined to implement the correct behavior:
interface_function (a: INTEGER): MY_STRUCT
is
-- Example of a generated Eiffel coclass feature
require
interface_function_user_precondition: interface_function_user_precondition
do
...
ensure
non_void_my_struct:
Result
/=
Void
end
Another advantage of the previous hierarchy is that it adds incrementality to the EiffelCOM system. Indeed, should the definition file be modified and the wizard run once more against it, your code would not be changed. Only the generated Eiffel coclass would be, and it would suffice to adapt your heir accordingly.
COM standard requires that any interface function returns a status value (known as a HRESULT). This corresponds to side effect features which the Eiffel methodology tends to avoid. The workaround used in EiffelCOM systems is to map these return values into Eiffel exceptions. If the server returns an error code, the EiffelCOM runtime raises an Eiffel exception that your code should catch.
As a result, any feature in the coclass client making calls to the user defined Eiffel coclass 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 ECOM_EXCEPTION_CODES, which is inherited from by ECOM_EXCEPTION. The later also inherits from the kernel class EXCEPTIONS and can consequently be used by the coclass client to catch the exceptions.
The following code snippet illustrates how a client can process exceptions raised in the Eiffel coclass:
indexing
description: "Eiffel coclass client example"
class
COCLASS_CLIENT
inherit
ECOM_EXCEPTION
export
{NONE} all
end
create
make
feature
{NONE}
-- Initialization
make
is
-- Initialize Eiffel coclass.
do
create
coclass.make
end
feature
-- Basic Operations
coclass_feature_client
is
-- Example of a coclass feature caller
local
retried: BOOLEAN
coclass: EIFFEL_COCLASS_PROXY
do
create
coclass.make
if
not retried
then
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
There are a few rules to follow when building an Eiffel coclass client, but they are straightforward and do not add any constraints. First, inherit from the generated Eiffel coclass to implement the preconditions. Second, any feature call to the Eiffel coclass should include a rescue clause.
See Also:
Introduction Dialog and Main Window,
Generated Code Type Dialog,
Definition
File Dialog,
Eiffel
Project File Dialog,
Destination
Folder Dialog,
IDL
Marshaling Definition Dialog,
Type
Library Marshaling Definition Dialog,
Final
Dialog,
COM
Definition File Processing,
Eiffel
Project Processing,
Generated
Files,
Class
Hierarchy,
Accessing
a Component,
Building
a Component