Building a COM Component

The EiffelCOM wizard enables the development of COM components in Eiffel. To build a COM component you can start either from an IDL file or from an Eiffel project. In the later case the wizard generates an IDL file for you.

Choosing an Eiffel Class

If you start building a COM component from an Eiffel system, you need to give an Eiffel class to the wizard. The wizard translates the Flat-Short form of the class into an IDL file, which is a formal specification of the COM component. Clients of the component are able to access only features specified in the IDL file. You need to supply the wizard with a Facade class that provides clients with a higher-level, single interface (do not confuse with COM interface) to the facilities of a system.

The Facade class should satisfy the following requirements:

In most Eiffel systems functionality is spread out throughout many classes. A system may not contain a class that can render all services of the system and can serve as a Facade to the outside world. If you cannot find such a class you should write one.

Using the Generated Code

If you start from an Eiffel project, the wizard produces a ready-to-use component, and you do not need to modify or to implement any generated code.

If you start from a COM definition file, you are able to design a more flexible component that has more than one interface and/or coclass and user defined types, but you have to implement features of the generated coclass. The generated Eiffel coclass features are empty. You should redefine them in heir to implement the intended behavior. Unlike client generated code, the server generated code will differ whether you have chosen to implement an in-process or an out-of-process component. The difference lies in the component activation code in the class ECOM_<Name_of_system>_REGISTRATION. If the component is in-process then this class includes the four functions that need to be exported from an in-process COM component (DllRegisterServer, DllUnregisterServer, DllGetClassObject, and DllCanUnloadNow). 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 generated code for the server is similar to the one for the client: the generated Eiffel coclass should be inherited from and the contract features redefined. The default feature implementation of the generated Eiffel coclass is empty. Features should be redefined to implement the intended behavior. These features will be called by the EiffelCOM runtime whenever a client accesses an interface.

The architecture remains the same as when accessing a component: the generated Eiffel coclass should be inherited from and the contract features redefined. The default implementation for features from the generated Eiffel coclass are empty. They should also be redefined to implement the intended behavior. These features will be called by the EiffelCOM runtime whenever a client access an interface.

Note: For this first release, the name of the user defined coclass has to be <Name_of_generated_coclass>_IMP. So if the generated coclass name is MY_COCLASS then the user defined coclass name must be MY_COCLASS_IMP.

Component's GUI

In the case of an out-of-process server, you might want to add a Graphical User Interface to your component. 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. The GUI should appear only in the former case, when the user has explicitly launched the application. The generated registration class for an out-of-process server includes the feature:

main_window: WEL_FRAME_WINDOW

This feature is a once function that can be redefined in a child class to return the class corresponding to the component window. This window is displayed only if COM does not start the component. When COM loads an out-of-process component, it appends the option "-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.

As a summary, when building a server from a COM definition you need to implement classes that inherit from coclasses and implement interface functions. The names of the children classes should be the names of the parent classes appended with _IMP. You will also have to inherit from the registration class in the case of an out-of-process component to provide the class that implements the component GUI.

Exceptions

The COM provides error status to the client by returning an HRESULT from the interface function. Such behavior is not acceptable in Eiffel and is replaced with exceptions. In the case of accessing an existing component, EiffelCOM runtime will raise exceptions with error code 24 (developer exception) and your code should catch them. When creating a component it will be your code that will raise exceptions and the EiffelCOM runtime that will catch them. Here is what the Eiffel code for a server should look like:

indexing
    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) is
            -- Example of a coclass feature
        do
            if not is_valid (an_argument) then
                trigger (E_invalidargument)
            else
                -- Normal processing
            end
        end

feature {NONE} -- Implspanentation
    is_valid (an_argument: ARGUMENT_TYPE): BOOLEAN is
            -- Is an_argument a valid argument?
        do
            -- Test of validity of an_argument
        end
end -- class ECOM_SERVER_COCLASS_IMP

This class inherits from the generated Eiffel coclass and from ECOM_EXCEPTION. It redefines the feature coclass_feature 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 trigger from ECOM_EXCEPTION to raise exceptions in case the feature cannot be executed normally (invalid argument e.g.). The EiffelCOM runtime catches the exception and maps it into an HRESULT that is sent back to the client.

Summary

Implementing EiffelCOM components consists in inheriting from the generated Eiffel coclasses and implementing their features. The only specific rules to follow relate to the redefinition of precondition features and the use of exceptions to return error status to the client. In the case of an out-of-process server, the registration class should be inherited from and the feature corresponding to the component window redefined to return the correct class.

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