mirror of
https://github.com/EiffelSoftware/eiffel-org.git
synced 2026-02-16 15:34:31 +01:00
Author:halw
Date:2009-01-05T19:34:30.000000Z git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@152 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
@@ -19,7 +19,7 @@ The architecture of the generated code is similar to the one used by the code ge
|
||||
|
||||
In the case of an out-of-process server, the component might need a Graphical User Interface. There are two different scenarios in which the component can be activated: either its user launched it explicitly (e.g. by double clicking the executable icon) or it was launched by the COM runtime to satisfy a client request. In some cases it might be required for the component to have a different behavior in these two cases (for example the GUI could only be necessary when the component was launched explicitly by the user but should be hidden when launched by the COM runtime). The generated registration class for an out-of-process server includes the feature:
|
||||
<code>
|
||||
main_window: WEL_FRAME_WINDOW</code>
|
||||
main_window: WEL_FRAME_WINDOW</code>
|
||||
|
||||
This feature is a <code>once</code> function that can return the class corresponding to the component window. By default, this window is displayed only if COM does not start the component. When COM loads an out-of-process component, it appends the command line parameter "-embedding" to the executable. The generated registration class looks for this option and if it is part of the process argument list then it sets the default window appearance to hidden. Of course this default implementation may be modified if needed.
|
||||
|
||||
@@ -27,38 +27,38 @@ This feature is a <code>once</code> function that can return the class correspon
|
||||
|
||||
The COM standard specifies that each COM routine should return a status code to the client. The status code is encoded in a <eiffel>HRESULT</eiffel> value. Such behavior goes against the Command Query Separation Principle in Eiffel. The EiffelCOM generated system should use exceptions instead of returning <eiffel>HRESULT</eiffel> values to the client. By default the EiffelCOM runtime will always return <eiffel>S_OK</eiffel> meaning that the routine succeeded. To notify the client of a problem (e.g. invalid argument value), the EiffelCOM component should raise the corresponding exception from class <eiffel>ECOM_EXCEPTION</eiffel> using the feature <eiffel>trigger</eiffel> from the same class. The EiffelCOM runtime will catch the exception and send the corresponding <eiffel>HRESULT</eiffel> back to the client. Here is what the Eiffel code for a COM component should look like:
|
||||
<code>
|
||||
indexing
|
||||
description: "Eiffel coclass server example"
|
||||
note
|
||||
description: "Eiffel coclass server example"
|
||||
class
|
||||
ECOM_SERVER_COCLASS_IMP
|
||||
ECOM_SERVER_COCLASS_IMP
|
||||
|
||||
inherit
|
||||
ECOM_SERVER_COCLASS -- Generated by the wizard
|
||||
ECOM_SERVER_COCLASS -- Generated by the wizard
|
||||
|
||||
ECOM_EXCEPTION
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
ECOM_EXCEPTION
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
feature -- Basic Operations
|
||||
|
||||
coclass_feature (an_argument: ARGUMENT_TYPE) is
|
||||
-- Example of a coclass feature
|
||||
do
|
||||
if not is_valid (an_argument) then
|
||||
trigger (E_invalidargument)
|
||||
else
|
||||
-- Normal processing
|
||||
end
|
||||
end
|
||||
coclass_feature (an_argument: ARGUMENT_TYPE)
|
||||
-- Example of a coclass feature
|
||||
do
|
||||
if not is_valid (an_argument) then
|
||||
trigger (E_invalidargument)
|
||||
else
|
||||
-- Normal processing
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
is_valid (an_argument: ARGUMENT_TYPE): BOOLEAN is
|
||||
-- Is an_argument a valid argument?
|
||||
do
|
||||
-- Test of validity of an_argument
|
||||
end
|
||||
is_valid (an_argument: ARGUMENT_TYPE): BOOLEAN
|
||||
-- Is an_argument a valid argument?
|
||||
do
|
||||
-- Test of validity of an_argument
|
||||
end
|
||||
|
||||
end -- class ECOM_SERVER_COCLASS_IMP</code>
|
||||
|
||||
|
||||
@@ -27,63 +27,63 @@ where <eiffel>ISOMETHING_INTERFACE</eiffel> is a generated deferred class corres
|
||||
|
||||
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 on 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 <eiffel>Void</eiffel> Eiffel objects as well as <code>null</code> 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 <eiffel>True</eiffel>. They can be redefined to implement the correct behavior:
|
||||
<code>
|
||||
function (a: INTEGER): MY_STRUCT is
|
||||
-- Example of a generated Eiffel coclass feature
|
||||
require
|
||||
function_user_precondition: function_user_precondition
|
||||
do
|
||||
...
|
||||
ensure
|
||||
non_void_my_struct: Result /= Void
|
||||
end</code>
|
||||
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</code>
|
||||
|
||||
So the complete class hierarchy for an Eiffel client coclass is the following:
|
||||
[[Image:client-inheritance]]
|
||||
[[Image:client-inheritance]]
|
||||
==Exceptions==
|
||||
|
||||
The COM standard requires that any interface function returns a status value (known as a <eiffel>HRESULT</eiffel>). This means that any function which adheres to the COM standard actually corresponds to a side effect feature which the Eiffel methodology tries to avoid according to the ''Command Query Separation Principle''. The workaround used in EiffelCOM systems consists in mapping these return values to Eiffel exceptions. So if the component returns an <eiffel>HRESULT</eiffel> corresponding to an error code, the EiffelCOM runtime raises an Eiffel exception that needs to be caught by the client.
|
||||
[[Image:exception-raising]]
|
||||
[[Image:exception-raising]]
|
||||
As a result, any feature in the client making calls to the Eiffel classes corresponding to the component's coclasses should include a <code>rescue</code> 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 <eiffel>ECOM_EXCEPTION_CODES</eiffel>, which is inherited from by <eiffel>ECOM_EXCEPTION</eiffel>. The later also inherits from the kernel class <eiffel>EXCEPTIONS</eiffel> 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 by a call to an Eiffel class representing a component's coclass:
|
||||
<code>
|
||||
indexing
|
||||
description: "Eiffel coclass client example"
|
||||
note
|
||||
description: "Eiffel coclass client example"
|
||||
|
||||
class
|
||||
COCLASS_CLIENT
|
||||
COCLASS_CLIENT
|
||||
|
||||
inherit
|
||||
ECOM_EXCEPTION
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
ECOM_EXCEPTION
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
feature -- Basic Operations
|
||||
|
||||
coclass_feature_client is
|
||||
-- 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
|
||||
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</code>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user