Applied new documentation structure with limited number of books.

Fixed Eiffel syntax wiki page to be processed by the Eiffel wikiparser.


git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@1402 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
jfiat
2015-01-30 10:18:32 +00:00
parent f39fda37e6
commit 4513ee238e
585 changed files with 538 additions and 455 deletions

View File

@@ -0,0 +1,5 @@
[[Property:title|EiffelCOM Class Reference]]
[[Property:weight|0]]
[[Property:uuid|476f2bc7-9afa-125e-0b68-3e4fc30e97f4]]
==View the [[ref:libraries/com/reference/index|EiffelCOM Class Reference]] ==

View File

@@ -0,0 +1,17 @@
[[Property:title|EiffelCOM Interface Content]]
[[Property:weight|-2]]
[[Property:uuid|a6543000-6009-970e-8a68-a6f3b18c1fc6]]
The EiffelCOM library includes the following clusters:
* A [[ref:libraries/com/reference/index|Constants]] cluster provides standard COM constants and enumerations.
* A [[Interfaces|Interfaces]] cluster includes wrappers for standard interfaces that the EiffelCOM wizard does not generate and deferred classes: [[ref:libraries/com/reference/ecom_interface_chart|ECOM_INTERFACE]] , [[ref:libraries/com/reference/ecom_queriable_chart|ECOM_QUERIABLE]] , and [[ref:libraries/com/reference/ecom_stub_chart|ECOM_STUB]] .
* A [[Structures|Structures]] cluster includes wrappers for COM structures and additional data structures.
* A [[ref:libraries/com/reference/index|Support]] cluster provides access to helper classes.
{{seealso|<br/>
[[COM and Eiffel]] <br/>
[[EiffelCOM Wizard|EiffelCOM wizard]] }}

View File

@@ -0,0 +1,23 @@
[[Property:title|Interfaces]]
[[Property:weight|0]]
[[Property:uuid|7f65c561-cac3-6870-5d1c-6f73beeed872]]
COM interfaces have several facets. First, an interface is a deferred class ("abstract class" in C++ terms). This means that an interface is a specification of a type. Second, an interface pointer represents a COM object, which is callable by a client application. An object can expose several interfaces, or represent several types.
<!--break-->
==ECOM_INTERFACE==
For each interface listed in a type library, the EiffelCOM wizard generates a deferred class and two effective classes: a proxy of an interface pointer, or a client side class, and a stub of an interface pointer, or a server side class. The deferred interface class inherits from [[ref:libraries/com/reference/ecom_interface_chart|<eiffel>ECOM_INTERFACE</eiffel>]] and has one deferred feature for each interface function. Both effective classes, or implemented interfaces, inherit from the deferred class and implement its functions. The functions of the interface proxy calls the underlying C layer, which in turn calls the COM component while the functions of the interface stub implement the component functionality.
[[ref:libraries/com/reference/ecom_interface_chart|ECOM_INTERFACE]] holds a pointer to the underlying COM interface.
==ECOM_QUERIABLE==
Different languages handle type coercion or type narrowing in different ways. C uses type cast; C++ introduces several type casting mechanisms; Eiffel uses [[ET: Inheritance#Object test|object test]], etc. Every COM interface exposes the <eiffel>QueryInterface</eiffel> function which allows clients to query the COM component for a pointer to another interface. Querying a component for an interface pointer is analogous to using an object test in Eiffel. To accomplish this, EiffelCOM introduces a library class [[ref:libraries/com/reference/ecom_queriable_chart|ECOM_QUERIABLE]], which has the creation routine
<code>
make_from_other (other: ECOM_INTERFACE)</code>
which queries a COM component internally. Every interface proxy class inherits from [[ref:libraries/com/reference/ecom_queriable_chart|ECOM_QUERIABLE]]. An important difference between this mechanism and using an object test is that if the creation routine fails to initialize a new [[ref:libraries/com/reference/ecom_queriable_chart|ECOM_QUERIABLE]] object, an exception will be raised, whereas, the <eiffel>attached</eiffel> syntax of the object test will merely produce a <code>False</code> result in the case in which no object of the desired type is available.
==ECOM_STUB==
[[ref:libraries/com/reference/ecom_stub_chart|ECOM_STUB]] inherits from [[ref:libraries/com/reference/ecom_interface_chart|ECOM_INTERFACE]], and exposes the feature [[ref:libraries/com/reference/ecom_stub_chart|<code>create_item</code>]] which allows creating the underlying COM object.

View File

@@ -0,0 +1,116 @@
[[Property:title|Structures]]
[[Property:weight|1]]
[[Property:uuid|fc2071f0-213c-cc88-4914-833b598ceb83]]
The [[ref:libraries/com/reference/index|Structures]] cluster includes wrappers for data structures useful when using the COM technology.
==ECOM_ARRAY==
ECOM_ARRAY is a multidimensional, resizable array. It is converted to SAFEARRAY at the COM runtime level. Most languages only support SAFEARRAYs of OLE automation types.
==ECOM_EXCEPTION==
ECOM_EXCEPTION provides support for triggering and catching exceptions. According to the COM specification, every feature of a COM interface should return a status code of type HRESULT. HRESULT is a 32 bit integer. The COM specification defines possible exception codes and corresponding human-readable descriptions.
The status code is mapped by the EiffelCOM runtime to Eiffel exceptions. To raise COM-specific exceptions, the class ECOM_EXCEPTION provides the feature <eiffel>trigger</eiffel>:
<code>
trigger (code: INTEGER)
-- Raise exception with code `code'.
-- See class ECOM_EXCEPTION_CODES for possible values.
</code>
The class also has several features that help analyzing exceptions and error codes received from the COM runtime.
<code>
hresult: INTEGER
-- Original HRESULT.
require
applicable: is_developer_exception
hresult_code: INTEGER
-- Status code.
require
applicable: is_developer_exception
hresult_facility: INTEGER
-- Facility code.
require
applicable: is_developer_exception
hresult_message: STRING
-- Error message.
require
applicable: is_developer_exception
</code>
Every call to COM should be wrapped into a <code> rescue </code> clause as follows:
<code>
some_feature
local
retried: BOOLEAN
...
do
if not retried then
-- Call to COM.
end
rescue
if is_developer_exception then
-- Compare `hresult' to some predefined value
-- and handle various cases,
-- or display a dialog box with an error message
-- `hresult_message'.
end
retried := True
retry
end
</code>
==ECOM_STRUCTURE==
ECOM_STRUCTURE is a deferred class which inherits from WEL_STRUCTURE. All wrappers of COM structures inherit from ECOM_STRUCTURE.
==ECOM_VARIANT==
ECOM_VARIANT is a wrapper of the VARIANT structure. VARIANT is the Visual Basic equivalent to Eiffel's <eiffel>ANY</eiffel>. In Visual Basic all variable types conform to VARIANT. Since the semantics and runtime architecture of Visual Basic are different from those of Eiffel, there is no simple way to map VARIANT to ANY. Instead, EiffelCOM provides an Eiffel wrapper around the VARIANT structure.
This wrapper exposes the feature
<code>
variable_type: INTEGER
-- Variable type. See class ECOM_VAR_TYPE for possible values.
</code>
which specifies the actual type of the variant. The class has multiple features for typed access and setting of variables.
==ECOM_VARIANT_ACCESS==
<eiffel>ECOM_VARIANT_ACCESS</eiffel> provides the feature:
<code>
missing: ECOM_VARIANT
-- Value representing the default value of a COM optional argument.
-- Equivalent to an omitted VB argument, or C++ vtMissing, or .NET System.Reflection.Missing.
</code>
Many COM Automation servers have routines that take arguments with default values. This is very common, for example, in Microsoft Office applications such as Excel and Word. In Visual Basic, such arguments are optional and, when omitted, the server uses the default value. In languages that cannot omit arguments, a special VARIANT value representing the omitted argument must be passed. EiffelCOM applications can pass missing for this purpose.
For example, the following adds a new workbook to Excel. The default argument tells Excel to decide for itself how many worksheets to put in the new workbook:
<code>
class
MY_EXCEL_APPLICATION
inherit
APPLICATION_PROXY
ECOM_VARIANT_ACCESS
feature
add_workbook
local
workbook: WORKBOOK_PROXY
do
workbook := workbooks.add (missing, 0)
end
</code>

View File

@@ -0,0 +1,15 @@
[[Property:title|EiffelCOM Library]]
[[Property:weight|8]]
[[Property:uuid|b5c66d71-515f-3c73-9c67-c50e4a8d6685]]
Type: Library <br/>
Platform: Windows <br/>
==EiffelCOM Library==
The EiffelCOM library provides support classes for the code generated by the EiffelCOM wizard. It has wrappings for standard COM data types such as VARIANT, SAFEARRAY, CURRENCY, DECIMAL, IUnknown, IDispatch, etc.
{{seealso|<br/>
[[EiffelCOM Wizard|EiffelCOM wizard]] }}

View File

@@ -0,0 +1,241 @@
[[Property:title|Access Type]]
[[Property:weight|5]]
[[Property:uuid|0d049617-9737-7cc8-810a-9f6f9ca603ec]]
Regardless of its location, a COM components can be accessed either through OLE '''Automation''' or '''directly''' through the interface's virtual table.
==Automation==
Accessing a COM component through Automation means using a well-known interface called '''IDispatch''' to access to a group of methods and properties. This interface includes the method <eiffel>invoke</eiffel> that allows calling a method, setting or getting a property on the Automation server.
One advantage of this approach is that the interface has a known virtual table layout. As a result, Windows can include a built-in marshaler for that interface (See [[Deeper into COM]] for information on marshalers). The supported types (known as Automation types) and their Eiffel equivalents are listed in the following table:
{|
|-
|
COM Type
|
Eiffel equivalent
|
Description
|-
|
VARIANT_BOOL
|
BOOLEAN
|
Standard boolean
|-
|
unsigned char
|
CHARACTER
|
Standard character
|-
|
double
|
DOUBLE
|
Standard double
|-
|
float
|
REAL
|
4-byte real value
|-
|
int
|
INTEGER
|
Standard integer
|-
|
long
|
INTEGER
|
Standard integer
|-
|
short
|
INTEGER
|
2-byte integer
|-
|
BSTR
|
STRING
|
Standard string
|-
|
CURRENCY
|
ECOM_CURRENCY
|
Currency value
|-
|
DATE
|
DATE_TIME
|
Standard date
|-
|
SCODE
|
INTEGER
|
Return status
|-
|
Interface IDispatch *
|
ECOM_INTERFACE
|
Automation interface
|-
|
Interface IUnknown *
|
ECOM_INTERFACE
|
Generic interface
|-
|
dispinterface
|
ECOM_INTERFACE
|
Automation interface
|-
|
Coclass Typename
|
TYPE_NAME
|
Component main class
|-
|
SAFEARRAY(TypeName)
|
ECOM_ARRAY [TypeName]
|
Array
|-
|
TypeName*
|
CELL [TypeName]
|
Pointer to type
|-
| VARIANT
| ECOM_VARIANT
| Variant value
|-
| enum
| INTEGER
| Enumeration
|-
|
Decimal
|
ECOM_DECIMAL
|
Decimal value
|}
Another advantage is a more dynamic discovery of the methods and properties of a component at runtime. Indeed the IDispatch interface also includes methods to determine whether or not a method or property is available and, in the case that it is available, get its identifier. This process is called late binding and allows component to discover at runtime the availability of functionality on other components.
This approach has also a lot of drawbacks. First, late binding is not an efficient way of calling a function on an interface. This is because first its identifier must be requested, and then the function called. That's two round trips which can be expensive in a distributed environment. Second, since the marshaler is built-in, it has to know in advance all the possible types that a function can accept to be able to marshal the corresponding data. Consequently, there is a limitation on the number of types that one can use in signatures of functions on an Automation compatible interface. The set of available types is called '''Variant''' and cover most of the standard types. It does not allow however the passing of complex user defined data types.
For these reasons Automation is mostly used in scripting environments (where speed is not an important factor) to accomplish simple tasks.
==Direct Access==
Direct interface access is the preferred way to access remote servers where speed becomes a concern and data types are specific to the application. The first interface pointer on the component is obtained through the class object (see [[Coclass|Class Object]] ). Other interfaces on the component are obtained by calling the '''QueryInterface''' function.
Because information on any interface cannot be accessed dynamically, the description of the interfaces must be provided to tools that need to handle the components such as the EiffelCOM wizard. The official way of describing components and interfaces is through Interface Definition Language (IDL). Once an IDL file has been written to describe a component it can be compiled with MIDL (the Microsoft IDL compiler) to generate both a type library and the code for the marshaler specific to that interface.
==EiffelCOM==
One idea behind EiffelCOM is that the details of how a component is accessed should be of no concern to an EiffelCOM programmer. Of course the programmer should be able to choose which kind of access he or she wants to use, but this choice should have no impact on the design of the Eiffel system itself. For that reason, the Eiffel code generated by the wizard follows the same architecture independently of the choice made for interface access and marshaling. The differences in access are handled in the EiffelCOM runtime library where the actual calls to the components are implemented.
{{seealso|<br/>
[[EiffelCOM Library|EiffelCOM library]] <br/>
[[EiffelCOM: Introduction|Introduction]] <br/>
[[COM Concepts|COM Concepts]] <br/>
[[COM Interfaces|COM Interfaces]] <br/>
[[Coclass|Coclasses]] <br/>
[[The Component Location|Component Location]] <br/>
[[Deeper into COM|Deeper into COM]] }}

View File

@@ -0,0 +1,28 @@
[[Property:title|Coclass]]
[[Property:weight|3]]
[[Property:uuid|7f91f9ce-e042-1d48-9d01-f9b794269ec4]]
We saw earlier that [[COM Interfaces]] can be perceived as views of a component. This conceptual representation actually maps the implementation of an EiffelCOM component. This is because the coclass inherits from the interfaces and implements their [[uuid:b8c10baa-4f50-adfe-a6f8-9cb56a8f1917#Deferred feature|deferred features]]. Indeed, interfaces are [[uuid:b8c10baa-4f50-adfe-a6f8-9cb56a8f1917#Deferred class|deferred classes]] with all features deferred that are accessible by [[uuid:b8c10baa-4f50-adfe-a6f8-9cb56a8f1917#Client|clients]]. The coclass is an Eiffel class that inherits from these interfaces and implements all the features. This design is not specific to Eiffel though, and can be found in other languages as well. The coclass defines the behavior of the interface functions.<br/>
==Class Object==
Also, we have seen that interfaces are accessed through interface pointers. But how does a client obtain one of these?
The answer lies in the class object. The name of this module should really be coclass factory since its goal is to spawn instances of the coclass on request. Class objects are accessed by COM whenever a client requests a new instance of the associated component. COM loads the class object and asks it to provide the interface pointer requested by the client.
The way a class object is loaded in memory (this process is called activation) depends on the location of the component (See [[The Component Location|Location]] for a description of the possible locations of a component). If the component is an in-process server, then the class object is called directly through the functions exported from the DLL. If the component is an out-of-process server, then it provides COM with a pointer to the class object. In both cases, once the component is loaded, COM has access to the class object and can call it, should a client request a new instance of a component.
[[Image:com-1|Component Creation]]
The code for the class object is generated by the EiffelCOM wizard so that Eiffel programmers will not have to worry about it.
{{seealso|
[[EiffelCOM Wizard|EiffelCOM wizard]] <br/>
[[EiffelCOM Library|EiffelCOM library]] <br/>
[[EiffelCOM: Introduction|Introduction]] <br/>
[[COM Concepts|COM Concepts]] <br/>
[[COM Interfaces|COM Interfaces]] <br/>
[[The Component Location|Component Location]] <br/>
[[Access Type|Access Type]] <br/>
[[Deeper into COM|Deeper into COM]] }}

View File

@@ -0,0 +1,29 @@
[[Property:title|COM Concepts]]
[[Property:weight|1]]
[[Property:uuid|9cb19fc1-3d26-5752-6232-ea23f2668c32]]
This page defines some concepts that are fundamental to the entire technology of COM.
<!--break-->
==The COM Standard==
COM is a standard that describes how a binary component can communicate with the outside world.
==Interfaces==
The component communicates through well-defined interfaces. Each interface is a specification of a group of properties and methods. It is important that the interface does not contain the implementation of the properties and methods, only their specifications (signatures).
==Coclasses==
The actual implementation lies in the [[Coclass|'''coclass''']]. There can be different implementations of the same interface in different coclasses.
==Class Objects or Class Factories==
Finally, each coclass can be instantiated using a class object or class factory.
These notions will be discussed further in the upcoming sections.
{{seealso|<br/>
[[EiffelCOM Library| EiffelCOM library]] <br/>
[[EiffelCOM: Introduction|Introduction]] <br/>
[[COM Interfaces|COM Interfaces]] <br/>
[[Coclass|Coclasses]] <br/>
[[The Component Location| Component Location]] <br/>
[[Access Type|Access Type]] <br/>
[[Deeper into COM|Deeper into COM]] }}

View File

@@ -0,0 +1,22 @@
[[Property:title|COM Interfaces]]
[[Property:weight|2]]
[[Property:uuid|1dbc3fb2-cf0b-b129-1102-ba01e26d8f74]]
Interfaces are at the heart of any COM component. Interfaces are described in the definition file of a component. They consist of a group of semantically related functions that can be accessed by the clients of the component. Although they are a specification, they also have a physical representation. A client can request a pointer on an interface and access the component functions through that pointer. Interfaces are the only possible way to access functions from a component. They enforce information hiding by ensuring that clients can access only the component's public functions.
Interfaces also define the type of a component. Each interface corresponds to a specific view of the component. In a way, this can be compared to polymorphism in the object-oriented world. Whenever an interface from a component is requested, only the functions defined on that interface are accessible, as if the component were polymorphically cast into an object of that type.
The COM specification requires that any interface provide access to all interfaces on the same component. All interfaces should include a specific function called '''QueryInterface''' that will provide a pointer on any other interface of the component. Interfaces are identified with a globally unique identifier (GUID) guaranteed to be unique in time and space. Since this function has to be on every interface, it has been abstracted into a specific interface called '''IUnknown''' from which all other interfaces must inherit.
The two other functions exposed by '''IUnknown''' are '''AddRef''' and '''Release'''. These functions should be called when a client gets a reference to an interface and when it discards that reference, respectively. These two functions define the life-cycle of a component at runtime by implementing reference counting—a common way of determining when a component can be removed from memory: when the reference count reaches zero, this signifies that there are no more clients are using that component. You might worry that this business of reference counting will the source of problems such as memory leaks. You would be right, should you choose a low-level language in which to implement your components, since it requires strict discipline on the part of the programmers. Fortunately, you will never have to implement or use these functions in Eiffel: all the processing related to IUnknown is provided by the EiffelCOM runtime. Calls to '''QueryInterface''' are done "behind the scene" and only when needed. The component life-cycle (i.e. calls to '''AddRef''' and '''Release''') is also taken care of by the EiffelCOM runtime.
{{seealso|<br/>
[[EiffelCOM Library|EiffelCOM library]] <br/>
[[EiffelCOM: Introduction|Introduction]] <br/>
[[COM Concepts|COM Concepts]] <br/>
[[Coclass|Coclasses]] <br/>
[[The Component Location|Component Location]] <br/>
[[Access Type|Access Type]] <br/>
[[Deeper into COM|Deeper into COM]] }}

View File

@@ -0,0 +1,28 @@
[[Property:title|The Component Location]]
[[Property:weight|4]]
[[Property:uuid|083c0120-2eda-9353-ceae-f63e7f407341]]
<div>
==Types of Components==
Certainly you've heard of ActiveX, DirectX, OCX, COM+, ADO+, ASP, and other Microsoft technologies. These are all technologies that use the COM standard. This section focuses on categorizing COM components according to their properties as well as the context in which they are used. The categorization will define how the EiffelCOM wizard should be used to wrap or create a component. The first criterion that defines the type of component is its location at run time: will the component be loaded in the client process (in-process) or will the component be a remote server for a distributed application (out-of-process)? In the former case, the component is compiled as a Dynamic Link Libraries (DLL) while in the latter case it is a standard executable.
==In-process Components==
Typical instances of DLL components are found in technologies such as OCX, ActiveX, or ASP. These are small, downloadable binaries that will be loaded and executed in a container. The container acts as a client of the component. The EiffelCOM wizard provides the ability to wrap such a component by providing access to its interface to any Eiffel container. It is also possible to create a new In-process component in Eiffel.
One main difference with out-of-process components (other than the nature of the module, DLL versus executable) is the way in-process components are activated. In the case of out-of-process components, the component will specify COM when it is ready to receive calls from client. In the case of an in-process server the call is coming directly from COM: COM first loads the DLL into the client process and then calls the exported function DllGetClassObject to access the component class object. The other three exported functions of an in-process component are DllRegister to register the component in the Windows registry, DllUnregister to unregister the component from the registry and finally DllCanUnloadNow which gets called by COM whenever it tries to unload the component from memory. These four functions must be accessible from outside the DLL for the in-process component to work properly.
==Out-of-process Components==
These components are standard executable acting as servers that can be accessed locally or over a network. Typically used in a three tier client server architecture, the major difference with in-process servers (other than the module type - executable instead of DLL) is their lifetime. In-process components are typically loaded to achieve a specific task and unloaded just after the task is complete. Out-of-process components are servers, intended to run continuously. The EiffelCOM wizard allows to build clients for such servers in Eiffel. It also provides the ability to create such servers.
{{seealso|<br/>
[[EiffelCOM Library|EiffelCOM library]] <br/>
[[EiffelCOM: Introduction|Introduction]] <br/>
[[COM Concepts|COM Concepts]] <br/>
[[COM Interfaces|COM Interfaces]] <br/>
[[Coclass|Coclasses]] <br/>
[[Access Type|Access Type]] <br/>
[[Deeper into COM|Deeper into COM]] }}

View File

@@ -0,0 +1,48 @@
[[Property:title|Deeper into COM]]
[[Property:weight|6]]
[[Property:uuid|f28ee911-1b15-260c-a290-540b9531113a]]
'''Apartment models''' and '''Marshalling''' are two more interesting areas of COM internals. It is not necessary to understand these details to use the EiffelCOM wizard, but the knowledge could improve decision making when designing new EiffelCOM components.
==Apartment models==
The first interesting subject that warrants more in-depth coverage is the execution context of a component. Components can run in the same process as the client, but can also run in a separate process, even on a different machine. But this only takes processes into account. What happens if a component uses multithreading to achieve it tasks? In the case of remote servers, this is a very real possibility. The problem is that a server does not (and should not) know in advance the nature of its clients. It cannot assume that the client will be able to take advantage of its multithreading capabilities. Conversely a multithreaded client should not rely on the server's ability to handle concurrent access.
The solution chosen in the COM specification is to define an additional execution context called an '''apartment'''. When COM loads a component it creates the apartment in which the component will run. Multiple instances of a multithreaded component will coexist in the same apartment since asynchronous calls will be handled correctly and there is no need to add any synchronization layer. On the other hand, single threaded components will be alone in their apartments and any concurrent calls coming from clients will be first synchronized before entering the apartment. These two behaviors define two different kinds of apartments: '''Multi Threaded Apartments''' (MTA) and '''Single Threaded Apartments''' (STA).
[[Image:com-2|Apartments]]
Apartments solve the problem of concurrency by removing the necessity of knowing the multithreaded capability of a component and its clients. Multithreaded clients can always make asynchronous calls and depending on whether the component handles concurrent access or not, they will be forwarded directly or synchronized first. There can be multiple instances of an STA running in one process, while there can be at most one MTA.
==Marshalling==
COM calls can "cross" apartment boundaries. Components from an STA can make calls to components running in an MTA and vice versa. These apartments might be running in different processes or even on different machines. The approach chosen in the COM specification for cross-apartment calls involves a pattern of '''proxies''' and '''stubs'''.
The idea is to "trick" the client of an interface by providing an interface proxy in its apartment. The proxy includes exactly the same functions as the interface itself but the implementations will merely forward the call to the actual interface. The client's behavior is the same whether it is dealing the actual interface or just a proxy. A point of interest in this approach is that the client implementation is independent from the location of the component.
But this is not quite the whole story. The call that goes to a proxy will not be forwarded to the actual interface but to its stub. The stub is the counterpart of the proxy—it represents the client for the interface. The interface's behavior is the same whether it is communicating with the actual client or a stub. Although it is not totally true that the component implementation is independent from the location of the client, the stub pattern still helps keep code identical for the implementation of the interface themselves. The implementation of a component will still be different between an in-process or out-of-process component, since it will have to be a DLL in one case and a executable in the other. The design of the interfaces might also differ since out-of-process servers will tend to avoid too many round trips.
[[Image:com-3|Cross Apartment Calls]]
There is one proxy/stub pair per interface. The proxy or the stub is loaded dynamically only when needed. This proxy/stub pair constitute the '''marshaller'''. The reason for having a single name for two different things comes from how MIDL generates its code. MIDL will produce files for one DLL in which both the proxy and the stub will be included. This DLL is the marshaller.
==Summary==
This brief introduction to the Component Object Model should be enough to get started with the EiffelCOM wizard. It specifies the main characteristics that define the type of a component and that need to be given to the wizard along with the definition file.
{{seealso| <br/>
[[EiffelCOM Library|EiffelCOM library]] <br/>
[[COM Concepts|COM Concepts]] <br/>
[[Deeper into COM|Deeper into COM]] <br/>
[[COM Interfaces|COM Interfaces]] <br/>
[[Coclass|Coclasses]] <br/>
[[The Component Location|Component Location]] <br/>
[[Access Type|Access Type]] }}

View File

@@ -0,0 +1,22 @@
[[Property:title|EiffelCOM: Introduction]]
[[Property:weight|0]]
[[Property:uuid|adadc51d-3dec-320a-9405-0842eacca4f7]]
This chapter attempts to cover enough information about COM for Eiffel developers to use the EiffelCOM wizard in an effective way. It does not cover all of COM ... that would (and does) require volumes. Still, this chapter presents the main concepts needed to understand how to build an EiffelCOM system.
Briefly stated, the Component Object Model is a Microsoft binary standard that establishes how two binary units can access each other at runtime. Such binary units can run in the same process, in different processes on the same machine, or even on different machines. Components can be implemented in any language as long as the compiler produces binaries compliant with the COM standard.
The advantages of such an approach include an increased reusability (binary reuse), a better version management (COM standard implies that new component versions are compatible with the older ones), and a built-in runtime environment. The binary reuse aspect of COM, augmented with the software quality of Eiffel, offers the developer a platform for increased productivity.
{{seealso|<br/>
[[EiffelCOM Library| EiffelCOM library]] <br/>
[[COM Concepts|COM Concepts]] <br/>
[[COM Interfaces| COM Interfaces]] <br/>
[[Coclass| Coclasses]] <br/>
[[The Component Location|Component Location]] <br/>
[[Access Type|Access Type]] <br/>
[[Deeper into COM|Deeper into COM]] }}

View File

@@ -0,0 +1,9 @@
[[Property:title|COM and Eiffel]]
[[Property:weight|-15]]
[[Property:uuid|32e79152-1e8f-43cd-e014-a83aab18e440]]
==About COM and Eiffel==
{{seealso|[[EiffelCOM Library| EiffelCOM library]] }}

View File

@@ -0,0 +1,58 @@
[[Property:title|Accessing a COM Component]]
[[Property:weight|2]]
[[Property:uuid|d27be959-8f8e-a6f0-cd20-12f6ce71307f]]
This third tutorial describes how to access a COM component. It will build a client of the <eiffel>StringManipulator</eiffel> component built in the first tutorial.
==Step by step instructions==
# Launch the EiffelCOM Wizard. Note: if you are running Windows 7, you will need to right-click "EiffelCOM Wizard" in the start menu and select "Run as administrator".
# In '''Project''', in the '''Current project''' input field, type in ''string_manipulator_client'' and press '''Enter'''.
# In '''Project Type''', choose ''Access an existing COM component''.
# In '''Component Information''', click the browse button (the button with '''...''') and open the file ''$ISE_EIFFEL\examples\com\wizard\string_manipulator\string_manipulator.idl'' where ''$ISE_EIFFEL'' represents the path to the EiffelStudio installation directory.
# Click '''Next'''.
# In '''Component Type''', choose ''In-process (*.dll)''.
# In '''Generation Options''', click the browse button and select the directory where the project should be created (which we will later refer to as the ''destination folder''). Choose ''$ISE_EIFFEL\examples\com\wizard\string_manipulator\generated\client'' where ''$ISE_EIFFEL'' represents the path to the EiffelStudio directory.
# Make sure both '''Compile C code''' and '''Compile Eiffel code''' are checked.
# Select '''Overwrite existing files'''.
# Click '''Generate'''.
# Wait until the wizard is done.
==Temporary Work-Around==
Note that because Eiffel as a language has evolved somewhat since the '''EiffelCOM Wizard''' was last released, the compile will fail on the last (Eiffel) portion of the compile. However, in this case, it is not sufficient to simply launch EiffelStudio, change the configuration, and finish the compile. The reason is that the EiffelCOM Wizard WOULD HAVE built a pre-compiled library from the C and Eiffel files just generated, and this is important because later steps in this Guided Tour depend upon that library to be there. Thus, to navigate this, you will need to execute the steps below.
# Let the EiffelCOM Wizard compilation proceed until it fails due to a Eiffel syntax error. Leave the EiffelCOM Wizard running. We will need it below.
# Click the EiffelStudio button to launch EiffelStudio on the project file that was generated above.
# The first window presented is the "Choose Your Directory" dialog box. UNCHECK the "Compile project" checkbox. Then click '''OK'''.
# Once EiffelStudio is open, click the ''Change Project Settings'' toolbar button, and navigate to ''Target: default'' in the navigation pane.
# Set the "Void safety" setting to "No", and set the "Syntax" setting to "Transitional syntax".
# Click '''OK''' in the Project Settings dialog box.
# DO NOT COMPILE, but exit EiffelStudio.
# Copy the .ECF file just modified to a safe location. In Windows Explorer, navigate to the ...\string_manipulator\generated\client\Client\ folder. Copy the .ECF file (string_manipulator_idl_client.ecf) outside the project directory temporarily (for example, to the ...\string_manipulator\generated\client\ folder. This .ECF file has the settings that will permit the EiffelCOM Wizard compilation to succeed.
# Place this safe copy of the modified .ECF file on the clipboard, ready to copy. Navigate to the folder where you made a copy of the above .ECF file, and in Windows Explorer, while the .ECF file is selected, from the Edit menu, select ''Copy'' (or hit Ctrl-C on the keyboard to make a copy of the file on the Windows clipboard).
# In Windows Explorer, navigate back to the ...\string_manipulator\generated\client\Client\ folder, but don't do anything yet.
# Quickly execute the following 2 steps: A) in the EiffelCOM Wizard, click the '''Generate''' button. B) After about 2 seconds, after the files have been generated and the C/C++ compilations have started, return to the Windows Explorer window in the ...\string_manipulator\generated\client\Client\ folder, and hit Ctrl-V on the keyboard to PASTE the saved .ECF file into the folder. Confirm when it prompts you whether to replace the .ECF file that was just generated (in Windows 7, this will be a "Copy and Replace" choice).
# Watch the EiffelCOM Wizard Output window as it completes successfully this time.
# With Windows Explorer, navigate to the ...\string_manipulator\generated\client\Client\EIFGENs\default\W_code\msc\ folder and confirm there is a file there named <code>precomp.lib</code> .
Now you are ready to continue with the Guided Tour.
==First Look at the Generated Code==
At the end of the processing the '''EiffelStudio''' button becomes enabled. Click on it. This will automatically start EiffelStudio with the generated project so you can more easily navigate through the created Eiffel classes.
{{note|When accessing a COM component the EiffelCOM Wizard will generate a precompiled library which includes all the generated classes. This allows for easy browsing of the generated classes, however a precompilation project is read-only, so you need to start another EiffelStudio to reuse the generated classes. The interesting classes are all related to the coclass proxy <eiffel>STRING_MANIPULATOR_PROXY</eiffel>. The proxy is the Eiffel class that gives access to the component. Each feature on the proxy calls the corresponding interface function on the component. You can use the EiffelStudio opened by the wizard to browse through the generated classes and study the class hierarchy.}}
==Implementing a Client==
To implement a client of the <eiffel>StringManipulator</eiffel> component open a new EiffelStudio. Create the project in ''$ISE_EIFFEL\examples\com\wizard\string_manipulator\client'' using the ecf file found in that directory. Freeze and run the project. You are now accessing the previously built component and calling functions on its interfaces! The class <eiffel>MY_STRING_MANIPULATOR</eiffel> inherits from the generated <eiffel>STRING_MANIPULATOR_PROXY</eiffel> and redefines the feature ''replace_substring_user_precondition''. The generated interfaces include contracts for each exposed function. You can redefine the ''user_precondition'' features to implement your own preconditions.
{{note|If a COM component should be added to an existing client, the generated ecf file can be added as a library. }}
==Contracts==
Contracts can be broken directly on the proxy in which case you will get a standard contract violation in the client. If contracts are broken on the server then the exception will be forwarded by the EiffelCOM runtime to the client. The feature replace_substring_user_precondition in <eiffel>MY_STRING_MANIPULATOR</eiffel> includes has some assertions. Comment them out. Now the contract of the [[ref:libraries/base/reference/string_8_chart|<code>replace_substring </code>]] feature is wrong and erroneous calls can be made. Quick melt the changes and run the client. Enter some invalid numbers in the fields used to call this feature. After you click '''Replace''' you will see an error message box warning you that a precondition was violated on the server side. This demonstrates contracts `over the wire'. The precondition was violated in the server; this exception was caught by the EiffelCOM runtime and sent back to the client.
{{seealso|<br/>
[[Creating a New COM Component|Creating a New COM Component]] <br/>
[[Creating a new component from an Eiffel project|Creating a new component from an Eiffel Project]] }}

View File

@@ -0,0 +1,52 @@
[[Property:title|Creating a New COM Component]]
[[Property:weight|0]]
[[Property:uuid|f8298b7d-c1a4-c8cc-1821-066f90e7e6e0]]
This first tutorial describes creating a COM component from a COM definition file that is either an IDL file or a Type Library. The tutorial focuses on creating an in-process (DLL) component, called <eiffel>StringManipulator</eiffel>. The component exposes one interface <eiffel>IString</eiffel> that includes the functions <eiffel>ReplaceSubstring</eiffel> and <eiffel>PruneAll</eiffel> corresponding respectively to the features [[ref:libraries/base/reference/string_8_chart|<eiffel>replace_substring</eiffel>]] and [[ref:libraries/base/reference/string_8_chart|<eiffel>prune_all</eiffel>]] of the class [[ref:libraries/base/reference/string_8_chart|<eiffel>STRING</eiffel>]] from the EiffelBase library. <eiffel>IString</eiffel> also exposes the property <eiffel>String</eiffel> which represents the manipulated string. The property can be set or read.
==Step by Step Instructions==
# Launch EiffelCOM Wizard. Note: if you are running Windows 7, you will need to right-click "EiffelCOM Wizard" in the start menu and select "Run as administrator".
# In the '''Current project''' input field, type in ''string_manipulator_server'' and press '''enter'''.
# In '''Project Type''', choose ''Create a new COM component''.
# In '''Component Information''', click the browse button (the button with '''...''') and open the file ''$ISE_EIFFEL\examples\com\wizard\string_manipulator\string_manipulator.idl'' where ''$ISE_EIFFEL'' represents the path to the EiffelStudio installation directory.
# Make sure '''Generate and use marshaller DLL''' is not checked.
# Click '''Next'''.
# In '''Component Type''', choose ''In-process (*.dll)''.
# In '''Generation Options''', click the browse button and select the directory where the project should be created (which we will later refer to as the ''destination folder''). Choose ''$ISE_EIFFEL\examples\com\wizard\string_manipulator\generated\component'' where ''$ISE_EIFFEL'' represents the path to the EiffelStudio installation directory.
# Make sure both '''Compile C code''' and '''Compile Eiffel code''' are checked.
# Make sure '''Clean destination folder prior to generation''' is selected.
# Click '''Generate'''.
# Wait until the wizard is done.
{{note|Because Eiffel as a language has evolved somewhat since the '''EiffelCOM Wizard''' was last released, you will need to go into the project file under the "Server" subdirectory (string_manipulator_idl.ecf, preferrably from within EiffelStudio) and change the following settings for this example to compile: Select "Target" in the navigator pane, then change the "Void safety" setting to "No", and "Syntax" to "Transitional syntax". Click '''OK''' in the Project Settings dialog box. Now you can finish the compile from within EiffelStudio. Note that there will be a few warnings about obsolete calls. These can be ignored for now.}}
==First Look at the Generated Code==
At the end of the processing the '''EiffelStudio''' button becomes enabled. Click on it. This will automatically start EiffelStudio with the generated project so you can navigate more easily through the created Eiffel classes. You can save the processing output by clicking the '''Save''' button.
The deferred class <eiffel>STRING_MANIPULATOR_COCLASS</eiffel> represents the component and exposes all its functionality. It inherits from <eiffel>ISTRING_INTERFACE</eiffel> which corresponds to the '''IString''' interface and has one heir <eiffel>STRING_MANIPULATOR_COCLASS_IMP</eiffel> which implements all the deferred features. The default implementation in the heir is empty.
==Implementing the Component==
To do something more interesting than merely returning an error to the client, edit the implementation of the <eiffel>STRING_MANIPULATOR_COCLASS_IMP</eiffel> class. There is an implementation of the class in ''$ISE_EIFFEL\examples\com\wizard\string_manipulator\server''\. Copy this file over to ''$ISE_EIFFEL\examples\com\wizard\string_manipulator\generated\component\server\component'' and freeze the project. Voila! You have your first EiffelCOM component up and running.
==Running the Component==
The component needs to be registered prior to being loaded. Register an out-of-process component using the following syntax:
<code>
system_name.exe -Regserver</code>
where ''system_name'' is the name of the component executable file. Register an in-process component using the ''regsvr32'' utility using the following syntax:
<code>
regsvr32 system_name.dll</code>
where ''system_name'' is the name of the dll (e.g. string_manipulator). So to register the <eiffel> StringManipulator</eiffel> component, run:
<code>
cd $ISE_EIFFEL\examples\com\wizard\string_manipulator\generated\component\server\EIFGENs\default\W_code
regsvr32 string_manipulator_idl.dll</code>
Once registered, follow the steps described in [[Accessing a COM Component|Accessing a COM Component]] to build the component's client.
{{seealso|<br/>
[[Creating a new component from an Eiffel project|Creating a new component from an Eiffel Project]] <br/>
[[Accessing a COM Component|Accessing a COM Component.]] }}

View File

@@ -0,0 +1,46 @@
[[Property:title|Creating a new component from an Eiffel project]]
[[Property:weight|1]]
[[Property:uuid|f1f6711a-989b-f182-377d-89dd827401d5]]
The second tutorial describes creating a COM component from an Eiffel system. The tutorial example <eiffel>String</eiffel> is almost identical to <eiffel>StringManipulator</eiffel> of the previous tutorial. In the <eiffel>StringManipulator</eiffel> example the wizard starts from an IDL file and builds an Eiffel System; in contrast, the <eiffel>String</eiffel> example takes an Eiffel system and generates an IDL file and the required plumbing code to make the Eiffel project accessible to COM.
==Step by step instructions==
# Create a new Eiffel project in the directory ''$ISE_EIFFEL\examples\com\wizard\e2idl\eproject'' where $ISE_EIFFEL represents the path to the EiffelStudio installation directory.
# Select the ECF file located in the same directory and compile.
# Start the EiffelCOM Wizard
# In '''Project''', in the '''Current project''' input field, type in ''string'' and press '''enter'''.
# In '''Project Type''', choose ''Add a COM interface to an existing Eiffel project''.
# In the field under '''Path to Eiffel project location''' enter ''$ISE_EIFFEL\examples\com\wizard\e2idl\eproject''.
# Click the browse button under '''Path to system's configuration file (*.ecf)''' and open the file ''$ISE_EIFFEL\examples\com\wizard\e2idl\eproject\string.ecf''.
# In the text field under '''Target to use''', enter: ''string''.
# In the text field under '''Name of Eiffel facade class''', enter: <eiffel>string_manipulator</eiffel>.
# In the text field under '''Name of Eiffel facade class cluster''', enter: <eiffel>root_cluster</eiffel>.
# Click '''Next'''.
# In '''Component Type''', choose ''In-process (*.dll)''.
# In '''Generation Options''', click the browse button and select the directory where the project should be created. Choose ''$ISE_EIFFEL\examples\com\wizard\e2idl\generated''.
# Make sure both '''Compile C code''' and '''Compile Eiffel code''' are checked.
# Make sure '''Clean destination folder prior to generation''' is selected.
# Click '''Generate'''.
# Wait until the wizard is done.
==First look at the generated code==
The generated Eiffel classes include:
* <eiffel>ISTRING_MANIPULATOR_INTERFACE</eiffel>: This class represents the only interface exposed by the COM component.
* <eiffel>STRING_MANIPULATOR_PROXY_IMP</eiffel>: This class implements the coclass, it inherits from the interface and implements its members.
* <eiffel>ECOM_STRING_REGISTRATION</eiffel>: This class contains the code required to register the component.
You do not need to modify or implement any classes. The wizard produces a ready-to-use component.
{{tip|<br/>
In most Eiffel systems functionality is spread out throughout the system. No single class exposes the full functionality of the system and can serve as a Facade to the outside world. Running the wizard on any such class would not be practical. Before starting the wizard write an Eiffel class that acts as a Facade and forwards client calls to the appropriate subsystems. Enter the Facade class name into '''Name of Eiffel facade class''' field. The wizard generates an IDL file from this class. }}
{{seealso|<br/>
[[Creating a New COM Component|Creating a New COM Component]] <br/>
[[Accessing a COM Component|Accessing a COM Component.]] }}

View File

@@ -0,0 +1,21 @@
[[Property:title|EiffelCOM Wizard Guided Tour]]
[[Property:weight|-13]]
[[Property:uuid|b0973926-aaac-0131-ae60-d1db6ecf6f38]]
This section provides a working example of how to use the EiffelCOM wizard to create COM components and to access existing COM components. <br/>
* [[Creating a New COM Component|Creating a New COM Component]] .
* [[Creating a new component from an Eiffel project|Creating a new component from an Eiffel Project.]]
* [[Accessing a COM Component|Accessing a COM Component.]]
{{Caution|EiffelCOM currently requires the use of the Microsoft C compiler (available with Visual Studio or the Microsoft Windows SDK). EiffelCOM will not work at this time with the MinGW C compiler.}}
{{seealso| '''See Also''' <br/>
[[EiffelCOM Wizard Introduction|Introduction]] <br/>
[[EiffelCOM Wizard Reference|EiffelCOM wizard reference]] }}

View File

@@ -0,0 +1,31 @@
[[Property:title|EiffelCOM Wizard Introduction]]
[[Property:weight|-14]]
[[Property:uuid|b73bc137-55ce-5404-e178-d88565cb6b62]]
The COM standard allows software components written in different languages to communicate with each other. However, building COM compliant applications requires the development of a large amount of "plumbing" code dedicated to supporting the technology. The EiffelCOM wizard was designed to free Eiffel developers from having to write the plumbing code.
The '''EiffelCOM Wizard''' is a powerful tool that enables both the rapid development of COM components in Eiffel and the access of COM components from Eiffel systems. The wizard consists of a series of input fields, in which you describe the component's characteristics. The wizard uses data you enter to produce:
# An Eiffel system skeleton
# The code to access or create a component
# The component-specific runtime libraries.
The wizard allows Eiffel developers with little COM knowledge to develop and reuse COM components. The design of the generated code follows the Eiffel standards and will look familiar to experienced Eiffel users. The only prerequisite to use the EiffelCOM wizard is an understanding of the '''Interface Definition Language'''. '''IDL''' describes a component's interface(s). Compilers can generate '''Type Libraries''' from IDL files. Tools that need information about a given component, such as the EiffelCOM wizard, Visual Basic, etc. will analyze the Type Libraries. The IDL syntax is very close to C so should be easy to learn for developers that are familiar with this language.
The wizard generates code from a Type Library and additional information given by the user. The generated code consists of Eiffel classes, C/C++ files, and library files. The wizard automatically produces library files from generated C and C++ code. You do not need to modify generated C/C++ code to build your EiffelCOM system.
{{note|The '''EiffelCOM Wizard''' is delivered with EiffelStudio, but it is a '''standalone tool''' (i. e., not part of the EiffelStudio IDE). You can find the wizard by following the directory path: ''$ISE_EIFFEL\wizards\com''. The executable file ''com_wizard_launcher.exe'' will launch the GUI version of the wizard. The executable file ''com_wizard.exe'' is a command-line version of the wizard described [[Wizards: Command Line Options|here]].}}
==Code Generation Process==
[[Image:introduction]]
The wizard can automatically compile the generated C and Eiffel code. To produce a Type Library corresponding to a given IDL file the wizard relies on '''MIDL''', the Microsoft IDL compiler (installed with the Windows Platform SDK). You may also provide the wizard with a Type Library directly. The wizard can also be used to add a COM interface to an existing Eiffel project. For the rest of the manual a '''COM Definition File''' will refer to the input file given to the wizard (either an IDL file, a Type Library or an Eiffel project file).
{{seealso|[[EiffelCOM Wizard Guided Tour|Guided Tour]] , [[EiffelCOM Wizard Reference|EiffelCOM wizard reference]] }}

View File

@@ -0,0 +1,73 @@
[[Property:title|Building a COM Component]]
[[Property:weight|5]]
[[Property:uuid|eb299741-4570-c2f1-011a-69da3043c6eb]]
When building a COM component, the EiffelCOM wizard allows for the development of both in-process (DLLs) and out-of-process (EXEs) COM components in Eiffel.
<!--break-->
==Using the Generated Code==
If the project consists of adding a COM interface to an existing Eiffel project then the wizard will generate (and optionally compile) everything required to implement the COM component. No extra work is required.
If the project uses a COM definition file (either an IDL file or a type library), the EiffelCOM Wizard generates empty features in the classes corresponding to the component's coclasses. The implementation can then be added into these empty features.
{{warning|Depending on the project settings, the EiffelCOM Wizard may overwrite the files containing the classes corresponding to the component's colasses if the project is re-generated thereby replacing the implemented features with empty ones. Make sure the destination folder is different from the folder where the classes have been implemented prior to re-generating the project. }}
Unlike the code generated to access an existing component, the code generated to implement a new COM component will differ for an in-process or an out-of-process component. The difference lies in the component activation code in the class <eiffel>ECOM_<Name_of_system>_REGISTRATION</eiffel>. If the component is in-process then this class includes the four functions that need to be exported from an in-process COM component ( <eiffel>DllRegisterServer</eiffel>, <eiffel>DllUnregisterServer</eiffel>, <eiffel>DllGetClassObject</eiffel>, and <eiffel>DllCanUnloadNow</eiffel>). If the component is out-of-process then the registration class includes a feature initializing the component and its graphical user interface.
The architecture of the generated code is similar to the one used by the code generated to access an existing component: classes corresponding to the component's coclasses inherit from classes corresponding to the component's interfaces and implement all the deferred features. There is however a major difference: the classes corresponding to the component's coclasses should '''not''' be inherited from. Instead their implementation should be completed. Putting the implementation in a heir class would cause a runtime failure since the EiffelCOM generated code will instantiate the class corresponding to the component's coclass when being called rather than any descendant that would actually contain the implementation. The classes corresponding to the component's coclasses are all suffixed with <eiffel>_COCLASS_IMP</eiffel>.
==Component's GUI==
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>
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.
==Exceptions==
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>
note
description: "Eiffel coclass server example"
class
ECOM_SERVER_COCLASS_IMP
inherit
ECOM_SERVER_COCLASS -- Generated by the wizard
ECOM_EXCEPTION
export
{NONE} all
end
feature -- Basic Operations
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 an_argument a valid argument?
do
-- Test of validity of an_argument
end
end -- class ECOM_SERVER_COCLASS_IMP</code>
This class inherits from the generated Eiffel coclass and from <eiffel>ECOM_EXCEPTION</eiffel>. It implements the deferred feature <eiffel>coclass_feature</eiffel> from the generated coclass. This feature is part of the interface functions that can be called by clients of the component. Its implementation uses the feature <eiffel>trigger</eiffel> from <eiffel>ECOM_EXCEPTION</eiffel> to raise exceptions in case the feature cannot be executed normally (invalid argument). The EiffelCOM runtime catches the exception and maps it into an <eiffel>HRESULT</eiffel> that is sent back to the client.
{{seealso|[[How the EiffelCOM Wizard works|How the EiffelCOM Wizard Works]] , [[Generated Files|Generated Files]] , [[Class Hierarchy|Class Hierarchy]] , [[Eiffel Project Processing|Adding a COM Interface to an Eiffel Project]] , [[Reusing a COM Component|Accessing a COM Component]] , [[Wizards: Command Line Options|Command Line Options]] }}

View File

@@ -0,0 +1,34 @@
[[Property:title|Class Hierarchy]]
[[Property:weight|2]]
[[Property:uuid|3f78176c-179f-78a4-cf32-47ec548bbb16]]
The generated Eiffel code reflects the architecture of the component described in the definition file. Each interface corresponds to a deferred Eiffel class that includes one deferred feature per interface function. The deferred features are implemented in heirs of the interface class. Classes inheriting from these interfaces implement either a coclass or an implemented interface (that is an interface whose instance might be used as an argument on one of the component interfaces functions).
==Projects Accessing Existing COM Components==
In a project accessing an existing component, the Eiffel classes corresponding to component coclasses inherit from the class [[ref:libraries/com/reference/ecom_queriable_chart| <eiffel>ECOM_QUERIABLE</eiffel> ]] , which is part of the EiffelCOM library. This class includes the feature <eiffel>make_from_other</eiffel> which allows initializing the component from another instance of [[ref:libraries/com/reference/ecom_interface_chart| <eiffel>ECOM_INTERFACE</eiffel> ]] .
[[Image:interface-inheritance]]
==Projects Implementing New COM Components==
In a project implementing a new component, the Eiffel classes corresponding to component coclasses inherit from the class [[ref:libraries/com/reference/ecom_stub_chart|<eiffel>ECOM_STUB</eiffel>]], which is part of the EiffelCOM library. This class includes the feature [[ref:libraries/com/reference/ecom_stub_chart|<eiffel>create_item</eiffel>]] which allows initializing the component.
[[Image:interface-inheritance-server]]
The '''Interface_proxy''' folder includes Eiffel classes wrapping interfaces that may be returned by functions on other interfaces. These classes inherit from both the deferred interface class located in '''Common\Interfaces''' and [[ref:libraries/com/reference/ecom_queriable_chart| <eiffel>ECOM_QUERIABLE</eiffel> ]] .
[[Image:implemented-interface]]
The '''Interface_stub''' folder includes Eiffel classes implementing interfaces that may be given to the component as an argument. These classes inherit from both the deferred interface class and [[ref:libraries/com/reference/ecom_stub_chart| <eiffel>ECOM_STUB</eiffel> ]] .
[[Image:implemented-interface-server]]
{{seealso|[[How the EiffelCOM Wizard works|How the EiffelCOM Wizard Works]] , [[Generated Files|Generated Files]] , [[Eiffel Project Processing|Adding a COM Interface to an Eiffel Project]] , [[Reusing a COM Component|Accessing a COM Component]] , [[Building a COM Component|Building a COM Component]] , [[Wizards: Command Line Options|Command Line Options]] }}

View File

@@ -0,0 +1,25 @@
[[Property:title|Eiffel Project Processing]]
[[Property:weight|3]]
[[Property:uuid|d94c4060-af70-930b-5023-1c2b2d069633]]
The EiffelCOM Wizard can be used to add a COM interface to an existing Eiffel project. The advantage of that approach is that it doesn't require any knowledge about IDL. The EiffelCOM Wizard will take care of generating the IDL from the Eiffel facade class. The generated IDL will define one coclass containing one interface that corresponds to the contract view of the facade class.
==Designing the Facade Class==
The facade class should be designed so that it exposes the functionality of the Eiffel system that needs to be accessed from clients of the component. Only the public routines will be exported to the IDL and thus to clients (the class should not have any public attributes, see the list of requirements below).
There are some rules that the facade class must follow for the COM wizard to be able to generate correct IDL:
* The facade class must have a creation procedure called <eiffel>make</eiffel> that does not take any argument. This is the procedure that will be called by the EiffelCOM runtime to initialize the Eiffel object when a COM call arrives from a client.
* The arguments and objects returned by the public routines of the facade class must be of one of the following types: [[ref:libraries/base/reference/character_8_chart| <eiffel>CHARACTER_8</eiffel> ]] , [[ref:libraries/base/reference/integer_32_chart| <eiffel>INTEGER_32</eiffel> ]] , [[ref:libraries/base/reference/real_32_chart| <eiffel>REAL_32</eiffel> ]] , [[ref:libraries/base/reference/real_64_chart| <eiffel>REAL_64</eiffel> ]] , [[ref:libraries/base/reference/boolean_chart| <eiffel>BOOLEAN</eiffel> ]] , [[ref:libraries/base/reference/integer_32_ref_chart| <eiffel>INTEGER_32_REF</eiffel> ]] , [[ref:libraries/base/reference/boolean_ref_chart| <eiffel>BOOLEAN_REF</eiffel> ]] , [[ref:libraries/base/reference/real_32_ref_chart| <eiffel>REAL_32_REF</eiffel> ]] , [[ref:libraries/base/reference/character_8_ref_chart| <eiffel>CHARACTER_8_REF</eiffel> ]] , [[ref:libraries/base/reference/real_64_ref_chart| <eiffel>REAL_64_REF</eiffel> ]] , [[ref:libraries/base/reference/string_8_chart| <eiffel>STRING_8</eiffel> ]] , [[ref:libraries/com/reference/ecom_currency_chart| <eiffel>ECOM_CURRENCY</eiffel> ]] , [[ref:libraries/com/reference/ecom_decimal_chart| <eiffel>ECOM_DECIMAL</eiffel> ]] , [[ref:libraries/com/reference/ecom_interface_chart| <eiffel>ECOM_INTERFACE</eiffel>]] , or [[ref:libraries/com/reference/ecom_array_chart| <eiffel>ECOM_ARRAY</eiffel>]] . Features with arguments or return objects that are of a type not in this list are excluded from the generated IDL file and are not accessible to clients.
* The facade class should not contain any public attribute, only routines can be exported to COM clients.
* The facade class must belong to a successfully compiled Eiffel project.
{{seealso|[[How the EiffelCOM Wizard works|How the EiffelCOM Wizard Works]] , [[Generated Files|Generated Files]] , [[Class Hierarchy|Class Hierarchy]] , [[Eiffel Project Processing|Adding a COM Interface to an Eiffel Project]] , [[Accessing a COM Component|Accessing a COM Component]] , [[Reusing a COM Component|Reusing a COM Component]] , [[Wizards: Command Line Options|Command Line Options]] }}

View File

@@ -0,0 +1,17 @@
[[Property:title|Generated Files]]
[[Property:weight|1]]
[[Property:uuid|808d49ba-132d-f847-2d8c-f49fe8c499b1]]
The EiffelCOM Wizard generates code into the specified destination folder. The file hierarchy is the following:
[[Image:folders]]
* The '''Client''' folder includes all the files used to access a COM component. The subfolders '''Clib''' and '''Include''' contain respectively the C++ source files and header files. If a COM Client was generated (as opposed to a COM Server), the subfolder '''Component''' contains the Eiffel class used to provide an interface to the component. Finally, if a COM Server was generated, the subfolder '''Interface_proxy''' contains classes wrapping interfaces that may be returned by functions of the component. These classes may be of interest for systems implementing a new COM component as well. The '''Client''' folder also contains an ECF file that can be used to precompile the generated Eiffel classes if the project consists of accessing an existing component. It is also possible to directly use the ECF file as a library in an existing project.
* The '''Common''' folder includes classes that are useful both when accessing and implementing a COM component. It includes the usual C++ folders as well as the '''Interfaces''' and '''Structures''' folders. The '''Interfaces''' folder contains Eiffel classes corresponding to COM interfaces. These are deferred classes that only define the signature of the COM interfaces members. The '''Structures''' folder contains Eiffel classes wrapping any structure defined in the COM definition file (IDL or type library).
* Optionally, the EiffelCOM Wizard may generate a '''idl''' folder which contains the IDL file generated from the Eiffel facade class if the project consists of adding a COM interface to an existing Eiffel project.
* The '''Server''' folder includes files used to implement a COM component. Apart from the usual C++ folders, it also includes a '''Component''' folder which contains Eiffel classes corresponding to the component's coclasses and a '''Interface_stub''' folder which contains Eiffel classes wrapping interfaces that may be given as an argument to the component. This last folder may also be useful when accessing a COM component. The '''Server''' folder also includes a ECF file which can be used to compile the generated system if the project consists of creating a new component.
{{seealso|[[How the EiffelCOM Wizard works|How the EiffelCOM Wizard Works]] , [[Class Hierarchy|Class Hierarchy]] , [[Eiffel Project Processing|Adding a COM Interface to an Eiffel Project]] , [[Reusing a COM Component|Accessing a COM Component]] , [[Building a COM Component|Building a COM Component]] , [[Wizards: Command Line Options|Command Line Options]] }}

View File

@@ -0,0 +1,21 @@
[[Property:title|How the EiffelCOM Wizard works]]
[[Property:weight|0]]
[[Property:uuid|2cbfb8ef-d163-fb01-ab8f-5ab156ea36fd]]
Depending on the project settings there are between 2 and 6 major steps involved when generating the Eiffel system:
* '''IDL Generation''': If the project consists of adding a COM interface to an existing Eiffel project, the first step accomplished by the EiffelCOM Wizard consists of generating an IDL file from the specified facade class (see [[Eiffel Project Processing|Adding a COM interface to an Eiffel project]] for additional details).
* '''IDL Compilation''': If the project uses an IDL file (whether it was specified or the result of processing a facade class from an existing Eiffel project), the EiffelCOM Wizard then compiles it into a type library.
* '''Type Library Parsing''': The EiffelCOM Wizard then analyzes the type library (whether it was specified in the settings or is the result of an IDL file compilation) and stores the information it needs to generate the code into an internal representation.
* '''Code Generation''': The EiffelCOM wizard generates both the Eiffel and C/C++ code from the information gathered during the previous step (see [[Generated Files|Generated Files]] for a list of generated files)
* '''C/C++ Compilation''': If specified in the project settings, the EiffelCOM Wizard then compiles the generated C and C++ code into object files and libraries that will be linked into the Eiffel system.
* '''Eiffel Compilation''': If the project consists of accessing an existing component then the EiffelCOM Wizard compiles the generated Eiffel code into a precompiled library that contains all the generated classes. If the project consists of creating a new component then the EiffelCOM Wizard compiles the generated Eiffel code into a standard project using the registration class as the root class.
Optionally, EiffelStudio can be opened on the generated system by clicking the corresponding button after the system has been compiled.
{{note|The EiffelStudio button will only be enabled if the Eiffel code was compiled. }}
{{seealso|[[Generated Files|Generated Files]] , [[Class Hierarchy|Class Hierarchy]] , [[Eiffel Project Processing|Adding a COM Interface to an Eiffel Project]] , [[Reusing a COM Component|Accessing a COM Component]] , [[Building a COM Component|Building a COM Component]] , [[Wizards: Command Line Options|Command Line Options]] }}

View File

@@ -0,0 +1,20 @@
[[Property:title|EiffelCOM Wizard Reference]]
[[Property:weight|-12]]
[[Property:uuid|d3564eb8-ef56-4ec1-599f-430b023fa7e8]]
The '''EiffelCOM Wizard''' is delivered with EiffelStudio, but it is a '''standalone tool''' (i. e., not part of the EiffelStudio IDE). You can find the wizard by following the directory path: <code lang="text">$ISE_EIFFEL\wizards\com</code>. The executable file <code lang="text">com_wizard_launcher.exe</code> will launch the GUI version of the wizard. The executable file <code lang="text">com_wizard.exe</code> is a command line version of the wizard described [[Wizards: Command Line Options|here]].
The EiffelCOM Wizard facilitates the creation of Eiffel projects implementing or reusing COM components.
* [[How the EiffelCOM Wizard works|How the EiffelCOM Wizard works]] describes the steps followed by the wizard when creating the Eiffel project.
* [[Generated Files|Generated Files]] describes the list of generated files and their usage.
* [[Class Hierarchy|Class Hierarchy]] describes the class hierarchy of the generated Eiffel project.
* [[Eiffel Project Processing|Eiffel Project Processing]] covers how to add a COM interface to an existing EiffelStudio project.
* [[Reusing a COM Component|Accessing a COM Component]] describes how to reuse an existing COM component.
* [[Building a COM Component|Building a COM Component]] describes how to build a new COM component.
* [[Wizards: Command Line Options|Command Line Options]] describes using the wizard from the command line.
{{seealso|<br/>
[[EiffelCOM Wizard Introduction|Introduction]] <br/>
[[EiffelCOM Wizard Guided Tour|Guided Tour]] }}

View File

@@ -0,0 +1,96 @@
[[Property:title|Reusing a COM Component]]
[[Property:weight|4]]
[[Property:uuid|ae910c51-2264-4b65-2567-9dfc1873beca]]
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.
<!--break-->
==Using the Generated Code==
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:
<code>
HRESULT Function ([in] int a, [out, retval] MyStruct * b)</code>
The wizard generates the following feature:
<code>
function (a: INTEGER): MY_STRUCT_RECORD</code>
where <eiffel>MY_STRUCT_RECORD</eiffel> is a generated Eiffel wrapper around the IDL defined structure <eiffel>MyStruct</eiffel>. Structures represent one case of custom data types, interfaces represent another. So for the following IDL:
<code>
HRESULT Function ([in] ISomething * pInterface)</code>
The wizard generates the following Eiffel feature:
<code>
function (p_interface: ISOMETHING_INTERFACE)</code>
where <eiffel>ISOMETHING_INTERFACE</eiffel> is a generated deferred class corresponding to the <eiffel>ISomething</eiffel> interface. Calling <eiffel>function</eiffel> requires passing an instance of a type that implements <eiffel>ISOMETHING_INTERFACE</eiffel>. The '''stubs''' implementing such interfaces can be found in '''Server\Interfaces_stub'''. In our example the Eiffel class would be named <eiffel>ISOMETHING_IMPL_STUB</eiffel>. The default implementation of the stub is empty and should be completed to implement the wanted behavior. This is how callbacks can be implemented using EiffelCOM.
==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 <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
-- 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]]
==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]]
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>
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</code>
{{seealso|[[How the EiffelCOM Wizard works|How the EiffelCOM Wizard Works]] , [[Generated Files|Generated Files]] , [[Class Hierarchy|Class Hierarchy]] , [[Eiffel Project Processing|Adding a COM Interface to an Eiffel Project]] , [[Building a COM Component|Reusing a COM Component]] , [[Wizards: Command Line Options|Command Line Options]] }}

View File

@@ -0,0 +1,34 @@
[[Property:title|Wizards: Command Line Options]]
[[Property:weight|6]]
[[Property:uuid|ca417e46-ad46-2d3f-e13e-a88366dc06b3]]
The EiffelCOM Wizard can be used from the command line for example in batch scripts. The command line utility is <code>com_wizard.exe</code> and is located in <code>$ISE_EIFFEL\wizards\com</code>. Each command line option has both a long and a short name. The long names are all prefixed with <code>--</code> while the short names are all prefixed with <code>-</code>. Options that take an argument should have the argument directly following the option with a space or a <code>=</code> sign in between the option name and the argument as in:
<code lang="text">
--ace="mysystem.ecf"</code>
this option is equivalent to:
<code lang="text">
-a "mysystem.ecf"</code>
The list of options is the following:
* '''--client, -c''' <DEFINITION_FILE>: Build client to access COM component described by <DEFINITION_FILE>.
* '''--server, -s''' <DEFINITION_FILE>: Build new COM component as described by <DEFINITION_FILE>.
* '''--eiffel, -e''' <PROJECT_FILE>: Add COM interface to Eiffel project with project file (*.epr) <PROJECT_FILE>.
* '''--ace, -a''' <ECF_FILE>: Path to ecf file of Eiffel project to be added a COM interface. Use together with <code>'--eiffel'</code>.
* '''--facade, -f''' <FACADE_CLASS>: Name of facade class to generate IDL from. Use together with <code>'--eiffel'</code>.
* '''--cluster, -u''' <CLUSTER>: Name of facade class cluster. Use together with <code>'--eiffel'</code>.
* '''--outofprocess, -o''': Access or build out of process component. By default access or build in-process component (DLL).
* '''--compilec, -i''': Compile generated C code.
* '''--compileeiffel, -l''': Compile generated Eiffel code. Implies '--compilec'.
* '''--marshaller, -m''': Build marshaller DLL, can only be used with '--server' and if definition file is an IDL file.
* '''--destination, -d''' <DESTINATION>: Generate files in <DESTINATION> folder. By default files are generated in current folder.
* '''--cleanup, -p''': Cleanup destination folder prior to generation. This option cannot be used together with <code>'--backup'</code>.
* '''--backup, -b''': Backup overriden files by adding extension '.bac'. This option cannot be used together with <code>'--cleanup'</code>.
* '''--graphical, -g''': Launch GUI, all other options are ignored.
* '''--nologo, -n''': Do not display copyright information.
* '''--version, -v''': Print version information.
* '''--help, -h''': Display help on how to use the EiffelCOM Wizard command line utility.
{{seealso|[[How the EiffelCOM Wizard works|How the EiffelCOM Wizard Works]] , [[Generated Files|Generated Files]] , [[Class Hierarchy|Class Hierarchy]] , [[Eiffel Project Processing|Adding a COM Interface to an Eiffel Project]] , [[Reusing a COM Component|Accessing a COM Component]] , [[Building a COM Component|Building a COM Component]] }}

View File

@@ -0,0 +1,12 @@
[[Property:title|EiffelCOM Wizard]]
[[Property:weight|4]]
[[Property:uuid|49d5c1b9-14f8-5bea-6641-50e9cf6715cf]]
Type: Wizard <br/>
Platform: Windows
{{seealso|<br/>
[[EiffelCOM Library|EiffelCOM library]] }}

View File

@@ -0,0 +1,16 @@
[[Property:title|COM]]
[[Property:weight|0]]
[[Property:uuid|993f5778-97c1-e113-31d7-61ae81c559fb]]
Microsoft COM (Component Object Model) is a platform-independent, distributed, system for creating binary software components that can interact. COM is the foundation technology for Microsoft's OLE (compound documents) and ActiveX (Internet-enabled components) technologies.
<!--break-->
{{definition|Automation|Automation is a Microsoft Windows Platform term that means, when an application provides it, that that application exposes its unique features to scripting tools and other applications. Automation uses the Component Object Model (COM).}}
:See also [http://msdn.microsoft.com/en-us/library/windows/desktop/ms221375%28v=vs.85%29.aspx Automation].
There is a host of technologies and capabilities that are available to your Eiffel applications on the Microsoft Windows platform through COM interfaces. For instance, a number of Microsoft products (e.g. Microsoft Word, Excel, Visio, Outlook, etc.) can be enhanced or controlled by other software through Automation via a COM interface. It is not complicated to, for example, have your Eiffel application open Excel, open a worksheet, evaluate its contents, and make extensive changes, or in-depth queries into its contents, either on the screen or invisibly. At this writing, all Microsoft Office products offer extensive COM interfaces for such purposes.
In addition, Eiffel supports the capability of making Eiffel applications into COM-compliant COM objects, thus exposing callable COM interfaces to other software for similar purposes.
The EiffelCOM Wizard, EiffelCOM Runtime, and EiffelCOM Library are there to make this job easier.