Visible to Intel only — GUID: GUID-31F16608-58A7-4E79-A0B7-5F306F7741E8
Visible to Intel only — GUID: GUID-31F16608-58A7-4E79-A0B7-5F306F7741E8
Advanced COM Server Topics
Advanced topics about Fortran COM Servers described in this section include:
Choose Between DLL or EXE COM Servers
The basic tradeoff in choosing between a DLL (in-process) COM server and an EXE (out-of-process) COM server is one of performance vs. robustness:
A DLL server provides the advantage of performance over an EXE server. Since the DLL server is loaded into the client's address space, there is less overhead involved in method calls. If the client code and the server object live in the same COM apartment, method calls are as efficient as DLL routine calls.
An EXE server provides the advantage of robustness over a DLL server. Since the server object lives in a separate address space, the object cannot be affected by client memory handling bugs, and vice versa. If the server crashes, the client doesn't necessarily crash – as long as the client checks the results of all method calls and takes steps to recover from a "dead" object.
In addition to the tradeoff between performance and robustness, the following factors should also be considered:
With an EXE server, the object can run in a separate security context from the client. With a DLL server, the code of the object's methods executes using the client's access token.
An EXE server can be run on a remote machine using COM distributed object support.
You can load a DLL server into a surrogate to gain the benefits of an EXE server. This behavior is explained in the next section.
DLL Server Surrogates
An in-process DLL server can be run in a separate process with the help of a surrogate. A surrogate runs as a separate process, loads the DLL server, and provides all of the mechanism that allows the DLL server to act as a local server. Windows provides a standard surrogate named DLLHOST.EXE. The primary advantage of using a surrogate is fault isolation. That is, if the server crashes it does not crash the client, and vice versa. The disadvantage is performance. Significant performance overhead occurs in executing methods in a separate application, as opposed to in a DLL.
A DLL server is associated with a surrogate via entries in the system registry. This action is done by associating the DLL server with an AppID. An AppID is a GUID. When using the standard surrogate, you can use the CLSID of a class in the DLL as the AppID, or a newly generated GUID. To generate a new GUID, use GUIDGEN.EXE in the Developer Studio Tools subdirectory:
Under the HKEY_CLASSES_ROOT\CLSID\{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx} key of the class, add an AppID entry with the value of the CLSID. Using the AddingMachine class as an example, the registry key would be HKEY_CLASSES_ROOT\CLSID\{904245FC-DD6D-11D3-9835-0000F875E193} and the AppID value would be {904245FC-DD6D-11D3-9835-0000F875E193}.
Under the HKEY_CLASSES_ROOT\AppID key, add a key using the AppID. Using the AddingMachine class as an example, the registry key would be HKEY_CLASSES_ROOT\AppID\{904245FC-DD6D-11D3-9835-0000F875E193}. Use the class name for the default value of the key, for example, "AddingMachine Class". Add a "DllSurrogate" entry with an empty string for the value.
The client must request CLSCTX_LOCAL_SERVER rather than CLSCTX_INPROC_SERVER to use the surrogate rather than loading the DLL server in-process. Using a surrogate requires that the DLL server have a proxy/stub registered since the method invocations are between different processes. For information on proxies/stubs, see Marshalling, Proxies and Stubs.
You can also write a custom surrogate. See the Windows Platform SDK documentation for information.
Discussion of Wizard Code Generation
The COM Server Application Wizard generates the code for your project from the files in the subdirectory of your project named templates. The project-name.hie file contains the definition of your COM server in an undocumented text language. You should not manually edit the project-name.hie file; the Wizard will do that.
Most of the other files in the templates directory are templates of the source files generated for your project. These templates contain source code that is copied "as-is" to the generated sources, and embedded directives that guide the Wizard in generating the code specific to the COM server that you define. The directives use the information in the project-name.hie file. The directives are undocumented and subject to change.
When you create a new Fortran COM Server project, the AppWizard creates the templates directory and copies the templates from the Fortran COM Server templates directory, ...\Intel Fortran\Templates\COMServer.
The files in the templates directory may change with each release, but the templates in your templates directory are never automatically updated. For example, if you create a COM server using Intel® Fortran Version 18.0 and the next release of Intel® Fortran (such as Version 18.1) contains updated templates, the templates for your COM server are not automatically updated to the new 18.1 templates. If you modify the definition of your server, your project continues to use the templates that it was created with. This behavior has the advantage of not introducing different code into a project that you have developed and tested.
However, there are two cases where you may want to modify the templates that are used by your project:
A new release of Intel® Fortran may contain additional features that can be used in your COM server project. Some of the new features may depend upon the new templates. These features will not be available to a pre-existing project unless you update the templates in the templates directory. You do this action by copying all of the files in the Fortran COM Server templates directory ...\Intel Fortran\Templates\COMServer into the templates directory, replacing all files with the same name. Your project will then use the new templates the next time that the definition of your server is modified and the project sources are regenerated.
When you want to modify the code generated by the Wizard. You may edit a template in your templates directory. Editing code that is copied "as-is" is straightforward. Attempting to modify the embedded directives is unsupported and could cause the Wizard to fail when using the modified template. The embedded directives begin with an @ (at-sign) character. The next character determines the type of directive. The end of many directives is also delimited by an @ character followed by the matching end character for the type of directive. For example, @[ and @] are the delimiters for one type of directive.
The advantage of modifying a template is that you can customize the code generated by the Wizard. The disadvantages of modifying a template are:
You must be very careful not to modify a template in a manner that causes the Wizard to generate bad code or fail.
You will not be able to update the project templates with the templates from a new release of Intel® Fortran without having to re-apply your modifications to the new templates.
Threading Models
The Wizard supports two COM threading models for the classes that you create in a DLL COM server, Apartment and Single. The Wizard uses the Apartment threading model (also known as the Single Threaded Apartment model "STA") by default. The basic rules of the Apartment threading model are:
If two objects, A and B, are created in the same STA thread, and A is processing a method call, no other client can call either A or B until A completes.
If B is created in a different thread from A, B can accept a method call while A is still processing and vice versa.
This means that if the class shares any global data among its objects, the global data must be protected from simultaneous access using thread synchronization primitives. This is because two instances of the class could be running in different threads. However the per-object instance data, that is, the fields in the class derived-type, are protected from simultaneous access by COM mechanisms. This is true except in the case where an object calls out to another object that triggers a reentrant invocation of the first object.
A class using the Single threading model need not worry about simultaneous access to class global data, as well as per-object data. All objects of the class are created in a single thread and therefore only a single object of the class can be executing at any time.
An EXE COM server generated by the wizard is single threaded. All method invocations are serialized by the server's message queue. Therefore, with an EXE server, you need not worry about simultaneous access to class global data, as well as per-object data.
Explaining the COM threading models in detail is beyond the scope of this documentation. See the Windows Platform SDK documentation for additional information.
Marshalling, Proxies and Stubs
COM supports the use of objects in separate processes (as when using an EXE server or a DLL surrogate), and the threading models described above, by the use of marshalling, proxies and stubs. This section presents an overview of marshalling, proxies and stubs.
Marshalling is the process of reading the parameters for a method call and preparing them for transmission to another execution context (for example, thread, process, or machine). Marshalling is done by a proxy. From the client's perspective, a proxy has the same interface as the object itself. The proxy's job is to make the object look like an object in the same execution context as the client.
Proxies allow client code to be unconcerned about where the object actually lives. A proxy marshalls the method parameters and transmits them to a stub associated with the object in the server. The stub unmarshalls the parameters and invokes the method in the server. From the server's perspective, this behavior is no different from when it is called from a client in the same execution context. A server that is not an in-process DLL server always requires a proxy/stub pair. An in-process DLL server requires a proxy/stub pair when the client and object are in different apartments.
The following are the three ways to assign a proxy/stub pair to a server:
Type Library Marshalling: |
If you use only Automation-compatible data types in your methods and properties, COM can automatically use the "Universal Marshaller" as the proxy/stub for the server. The Universal Marshaller uses the description of the server in the type library to decide how to marshall the parameters. This behavior is known as type library marshalling. Using type library marshalling requires no effort on your part, other than restricting your server to Automation-compatible data types. |
MIDL-based Marshalling: |
Your project uses the MIDL compiler to compile the IDL description of the server into a type library. At the same time, the MIDL compiler also generates the C source code necessary to build a proxy/stub DLL for the server. You must have a C compiler to build a proxy/stub DLL from the MIDL generated code. The proxy/stub DLL is itself an in-process DLL server and needs to be registered with the system. You would need to use MIDL-based marshalling if your server uses non-Automation-compatible data types, and is used by a client in a different execution context. |
Custom Marshalling: |
Your server can implement its own marshalling by implementing the IMarshall interface. This approach typically involves a lot of work and is done for performance reasons. |
A Map of the Generated "Do Not Edit" Code
This section presents an overview of which parts of the COM server functionality are implemented as "Do Not Edit" source files generated by the application wizard:
File Name |
Description |
---|---|
server.idl |
Contains the IDL description of the server. It is compiled by the MIDL compiler to produce the server's type library. |
servernameglobal.f90 |
Contains the global data and functions for the server. |
dllmain.f90 (DLL server) |
Contains the exported functions that are required of all COM Server DLLs. These functions include DllMain, DLLRegisterServer, DLLUnregisterServer, DllGetClassObject, and DllCanUnloadNow. |
exemain.f90 (EXE server) |
Contains the main entry point of an EXE server. It also processes the command-line argument. |
serverhelper.f90 |
Contains helper functions for the server. |
clsfactty.f90 |
Contains definitions of the IClassFactory interface that is used to create instances of the classes defined by the server. |
clsfact.f90 |
Contains methods of the IClassFactory interface that is used to create instances of the classes defined by the server. |
classnameTY.f90 |
Defines a module that contains definitions of parameters and types used in the implementation of the class. It also contains the implementation of the IUnknown methods of the class. A separate instance of this file is generated for each class defined in the server. |
interfacename.f90 |
Defines a module that contains the Fortran interfaces of the methods in the interface. It also contains the implementation of the Fortran "wrappers" that are called directly from the class' VTBL and call the methods implemented by the user. A separate instance of this file is generated for each interface defined in the class. |