This section shows how to create a project, specify the COM server characteristics, generate code for, and implement an example Fortran COM server project called Adder. It contains the following topics:
Specifying the Fortran COM Server as a Developer Studio Add-in
The Fortran COM Server Wizard is implemented as a Developer Studio Add-in. After you install Visual Fortran, you need to register and load the Fortran COM Server Wizard on your system. If you have not already done so, do the following:
...\Microsoft Visual Studio\Common\MSDev98\Addins\Df98\
directory.You only need to perform this procedure once on your system.
Creating a Fortran COM Server Project
The first step in creating a Fortran COM Server is to create a new project. Start Developer Studio. In File menu, click New.
In the New Projects dialog box, select (click) the Fortran COM Server project type, as shown below (if Microsoft Visual C++ is installed on your system, additional project types will appear):
The Fortran COM Server Wizard is implemented as a Developer Studio Add-in and must be registered and loaded on your system. If you receive a message that begins with "The Fortran COM Server Wizard Add-in is not loaded into Developer Studio ...", follow the instructions in Initializing the Fortran COM Server as a Developer Studio Add-in.
In this case:
To define the initial attributes of the Fortran COM server project being created, additional information is requested. The following screen shows the Fortran COM Server AppWizard. You use the project AppWizard once per project to create the project files and skeleton template (as with other project types). The Fortran COM Server AppWizard requests the type of server (DLL or EXE), the class name, interface name, and the class derived type name:
In this case:
A summary screen appears that summarizes the location and template information created for this project:
After you click OK, the project is created and the Fortran COM Server Wizard appears.
Using the Fortran COM Server Wizard to Define your COM Server
The Fortran COM Server Wizard lets you interactively define the attributes of your COM server. It lets you define and name classes, interfaces, methods, and so on. The user interface contains two panes:
The Fortran COM Server Wizard is automatically invoked by the Fortran COM Server AppWizard, so you can enter the initial definition of your server. You can, but you are not required to, fully define the server at this point. You can partially define your project and close your project workspace. Later, after you start Developer Studio and open the project workspace again, you can start the Fortran COM Server Wizard by clicking the Fortran COM Server Wizard menu item in the View menu.
With our example COM server, the initial screen of the Fortran COM Server Wizard now appears, displaying the type library GUID and the type library version:
In this case, you need to expand the hierarchy to select the IAdd interface name:
The screen appears as follows:
If the Dual Interface check box is checked, click the Dual Interface check box to uncheck it. The Adder sample only supports a COM server interface.
The hierarchy is as follows:
You can use the Fortran
COM Server Wizard's graphical user interface to add a class, interface, method, property,
or argument:
To delete an item:
For our example Adder COM server, add the methods to the IAdd interface:
The following screen appears:
The active buttons displayed depend on the selected (highlighted) item (COM server, class, interface, method, or argument) in the hierarchy. The active buttons represent the types that are valid in the current context. For example, the Argument button is inactive since an interface was selected and an Argument must be added to a method.
In this case:
Because the Clear method takes no arguments, you can now add a second method, named Add:
The Add method requires an argument, which we will name Operand. To add the Operand argument:
Before you click OK, the screen appears as follows:
After you click OK, the Fortran COM Server Wizard screen adds the Operand argument and displays its properties.
The default data type of an argument is INTEGER(4).
In our example:
We need to add the last method:
The GetValue method requires an argument, which we will name CurrentValue. To add the CurrentValue argument:
For the CurrentValue argument:
The screen appears as follows:
In our example, the server definition is now complete. Click the Save button to dismiss the Fortran COM Server Wizard. The project is now displayed, including the TODO.TXT file, allowing you to modify the generated code.
For detailed information about the property pages (right pane) for server, class, interface, method, argument, or instance properties, see Description of Property Pages.
To change the definition of your server later, select the Fortran COM Server Wizard menu item in the View menu.
In addition to methods, an interface can contain properties. Properties are method pairs that set or return information about the state of an object. Typically, a property corresponds to a field in the object's derived type. For example, in the AddingMachine example, we could have used a CurrentValue property rather than a GetValue (and SetValue) methods.
A property is primarily an Automation concept. In a COM interface, a property is implemented as one or two methods:
A property can be defined as read-only or write-only. In this case, there will be a single get_ or put_ method.
Defining an interface member as a property, rather than a method, can affect the syntax used by the client of your server. For example, Visual Basic uses a different syntax for getting or putting a property than for invoking a method. If the client language has a specific property syntax, it typically looks similar to setting a field in a record, rather than making a call.
To add a property
to your interface:
One or two methods are added to your interface. Two methods are added if you select both the get_ and put_ methods. One method is added if it is read-only or write-only. The properties methods and the argument that identifies the property value are fully defined and do not need to be modified.
A property method typically only has the single argument that represents the property value. You can add additional arguments if it makes sense. For example, additional arguments might be added if the property is an array of values, where an integer index argument is added to the property method.
When adding additional arguments to a property method, make sure that they are added before the property value argument. That is, the property value argument must always be the last argument to the property method. You can use drag-and-drop in the hierarchy pane to change the order of arguments. The order in the method is always the order that appears in the hierarchy pane.
Working with the Hierarchy Pane
As you have seen in the AddingMachine example, the hierarchy pane represents the definition of your server; that is, the classes, interfaces, methods, and so on. The hierarchy pane's user interface supports the following functionality:
Expand/contract an area | When the Fortran COM Server wizard is initially displayed, the hierarchy is fully contracted. Click the plus sign (+) next to an item to display its children. At this point, the + changes to a -. Click the - to hide the children. Double-clicking on an item also toggles its expand/contract state. |
Add a new entry | To add a new entry to the hierarchy, select the entry that will precede the new entry in the hierarchy. Then click the New... button or click the right mouse button to display the pop-up hierarchy pane context menu and select one of the New... entries in the context menu. |
Delete an entry | To delete an entry from the hierarchy, select the item to be deleted. Then click the Delete button or click the right mouse button to display the pop-up hierarchy pane context menu and select the Delete entry in the context menu. A confirmation dialog box is displayed to ensure that you do not accidentally delete items. All of an item's children are deleted when the item is deleted. |
Rename a member | To rename an entry in the hierarchy, select the item to be renamed. Wait a few seconds (to avoid double-clicking) and then click the item again. The item's name will enter editing mode allowing you to change the name. Press the Enter key when you have finished editing the name. |
Change the order of items | The order of some of the entries in the hierarchy is very
important. In particular:
|
The hierarchy pane supports drag-and-drop to allow you to change the order of items. To move an item, click and drag the item and drop it on the item that you want to precede it in the hierarchy.
Property pages appear in the right pane of the Fortran COM Server Wizard window. Different property pages apply to:
Type Library GUID | The unique identifier of the server's type library. There is usually no reason to change this from the default value generated by the Fortran COM Server Wizard. |
Type Library Version | The current version of the Type Library. |
ProgID | The version independent program ID (or text alias) for the class. The ProgID can be used in calls such as COMCreateObjectByProgID. |
Version | The current version of the class. It is appended to the ProgID to define the version-specific ProgID. |
Short name | A short name for the class. It is used in some of the generated file names. |
Description | A string used as the default value of the class' ProgID keys in the registry. This string is often used by tools, such as the OLE-COM Object Viewer, that display a list of the objects that are registered on the system. |
Help String | A string used to set the class' help string attribute in the IDL file. |
Threading model | The threading model of the class. The two choices are Apartment and Single. See Threading Models in Advanced COM Server Topics for information about the implications of this choice. |
CLSID | The unique identifier of the class. There is usually no reason to change this from the default value generated by the Wizard. |
Dual Interface | If checked, then the dual interface attribute is set in the IDL file. A dual interface supports both COM and Automation clients. |
Uses only Automation data types | If checked, then the interface uses only Automation-compatible data types as described in Method Data Types. |
Default interface | If checked, then the default interface attribute is set for this interface in the IDL file. The default attribute represents the default programmability interface of the object, and is intended for use by macro languages. |
Help String | A string used to set the interface's help string attribute in the IDL file. |
IID | The unique identifier of the interface. There is usually no reason to change this from the default value generated by the Wizard. |
ID | The identifier of the method used by Automation clients. |
Help string | A string used to set the method's help string attribute in the IDL file. |
Property Method | If checked, then the method is the get_ or put_ method of a property. |
Fortran data type | The Fortran data type of the argument. Select one of the data types from the list, or type in the data type. See Method Data Types for a discussion of the implications of your choice. |
Interface data type | The IDL data type. If you select one of the Fortran data types from the predefined list, then this field defaults to the corresponding IDL data type. Select one of the data types from the list, or type in the data type. See Method Data Types for a discussion of the implications of your choice |
Intent | The INTENT of the argument, one of the following list:
|
By Reference | Indicates that an argument is passed by reference rather than by value. Only valid with Intent In. Intent Out and Intent InOut are automatically passed by reference. |
Return Value | If checked, the argument represents the return value of the method. Only valid with Intent Out. |
Array argument | If checked, then the argument is an array rather than scalar argument. When checked, fill in the Array Description fields to describe the shape of the array. |
Optional argument | If checked, then the argument is optional. Optional arguments are passed using the Variant data type. |
Array Description fields | These fields describe the shape of an array argument. They are enabled when the Array argument field is checked. |
Module | The name used for the module defined in the UclassnameTY.f90 file. |
Constructor | The name used for the class constructor defined in the UclassnameTY.f90 file. |
Destructor | The name used for the class destructor defined in the UclassnameTY.f90 file. |
After you either click the Save button to dismiss the Fortran COM Server Wizard or open the project workspace, the project is displayed, including the TODO.TXT file.
The TODO.TXT file informs you of changes made to your project by the Wizard, and lets you know when you need to make changes. After the initial invocation of the Wizard, TODO.TXT lists the files that were added to the project. The source files are added to two folders in your FileView pane:
Click:
The project screen appears as follows:
The two files that you need to modify with a text editor are in the Source Files folder:
We will first modify the file UAddingMachineTY.f90. To edit the file UAddingMachineTY.f90, either double-click its file name in the FileView pane or use the Open menu item in the File menu. The original file UAddingMachineTY.f90 contains the following code:
A file named Uclass-nameTY.f90 is created for each class defined by the server. The file contains a module named AddingMachine_USE (in the form classname_USE). There are three places in this module where you may need to add code specific to your class:
real(4) CurrentValue
The module also contains two module procedures by the names AddingMachine_CONSTRUCTOR
and AddingMachine_DESTRUCTOR (referred to as classname_CONSTRUCTOR
and classname_DESTRUCTOR below). ObjectData%CurrentValue = 0
We will now modify the other source file UIAdd.f90. Either double-click its file name in the FileView pane or use the File menu, Open item. The original file UIAdd.f90 contains the following code:
A file by the name Uinterfacename.f90 (for example UIadd.f90) is created for each interface defined by the class. The file contains the methods of the class. Each method is named interfacename_methodname, for example: "IAdd_Clear". Each method is a function that is passed the class derived-type as the first argument. This gives the function access to the per-object data. Each function returns a 32-bit COM status code called an HRESULT. S_OK is a parameter that defines a success status. For additional information on COM status codes, see COM Status Codes: HRESULT.
You replace the "! TODO: Add implementation" line in each method with the code for the method. For the IAdd interface, below is the implementation of its three methods:
IAdd_Clear: ObjectData%CurrentValue = 0
IAdd_Add: ObjectData%CurrentValue = ObjectData%CurrentValue + Operand
IAdd_GetValue: CurrentValue = ObjectData%CurrentValue
Save the file and from the Build menu, click Build Adder.dll to build the server. The COM server is now complete.
The Developer Studio project created by the Fortran AppWizard performs two additional steps not done in a typical Fortran project:
The MIDL compiler uses the Visual C++ preprocessor by default during compilation. If the AppWizard determined that Visual C++ was not installed, it sets the MIDL options to use the Fortran preprocessor FPP instead. The options added are:
/cpp_cmdfpp /cpp_opt "/a /m/extend_source 132"
\Winnt\System32
directory. On Windows 9x systems, this is
typically the \Windows\System
directory. If the registration step fails,
do the following: For an EXE COM server, the COM server itself is run with the /REGSERVER command-line option.
If you also have Microsoft Visual C++ Version 6 installed on your system, you will notice that your server definition also appears in the Visual C++ ClassView pane. This occurs because the Visual C++ ClassView software can read and understand the IDL file created by the Fortran COM Server wizard.
The server is now ready to be called by any COM client. The completed Adder sample
is provided in the ...Df98\Samples\Advanced\COM\Adder
directory. This directory
also contains three clients written in Visual Fortran,
Visual Basic, and Visual C++.
To build the sample clients, first build the Adder sample. The GUIDs used by the sample COM clients work with the Adder Sample (not the GUIDs created in the example).
If you followed the example COM server AddingMachine in earlier sections (starting with Creating a Fortran COM Server Project), the AddingMachine server that you created is identical to the Adder sample except for the GUID's assigned to the AddingMachine object. The Fortran COM Server AppWizard always generates new GUIDs for a new project.
Each client displays a dialog box that provides the user interface to the Adding Machine. Below are notes on each of the clients:
The VFAdder client is created using the Fortran Windows Application AppWizard. VFAdder is a simple Dialog Based Application. The main dialog box is defined to have Clear and Add buttons, an edit box to enter the addend, and a static text field that displays the current value:
The Fortran Module Wizard creates the module (AddingMachine.f90) that defines the IAdd interface methods for use from Fortran. Code is added to the beginning of the WinMain routine to initialize COM and create an AddingMachine object:
call COMINITIALIZE(ret)
call COMCREATEOBJECTBYGUID (CLSID_AddingMachine, CLSCTX_ALL, IID_IAdd, &
& gAddingMachine, status)
call Check_Status(status, " Unable to create AddingMachine object")
The subroutine added as the handler of the Add button (VFAdderAdd) calls the $IAdd_Add routine and the $IAdd_GetValue routine:
! Call the AddingMachine Add method
lret = DlgGet(dlg, IDC_EDIT_ADDEND, text)
read(text, *) addend
status = $IAdd_Add(gAddingMachine, addend)
call Check_Status(status, " Add method returned failure status")
! Set the Current Value text field
status = $IAdd_GetValue(gAddingMachine, value)
write(text, *) value
call Check_Status(status, " GetValue method returned failure status")
lret = DlgSet(dlg, IDC_CURRENTVALUE, text)
The subroutine added as the handler of the Clear button (VFAdderClear) calls the $IAdd_Clear routine in a similar way. Code is added at the end of the WinMain routine to uninitialize COM and release the AddingMachine object:
if (gAddingMachine /= NULL) then
ret = COMReleaseObject(gAddingMachine)
endif
call COMUNINITIALIZE()
VBAdder is created from a new Standard EXE project. The form is modified to be similar to the VFAdder dialog box above. The first step in using the AddingMachine object from Visual Basic is to select the References menu item from the Project menu. Find AddingMachine 1.0 Type Library in the list and select it. Visual Basic reads the information from the type library and becomes aware of the AddingMachine object, the IAdd interface, and its methods. These will appear in the choices that the Visual Basic editor makes available to you as you enter code for the project.
The following code is added to the VBAdder project:
Dim Adder As New AddingMachine
Private Sub Add_Click()
Dim Value As Single
Adder.Add (Addend.Text)
CurrentValue.Caption = Adder.GetValue
Addend.Text = ""
End Sub
Private Sub Clear_Click()
Adder.Clear
CurrentValue.Caption = Adder.GetValue
End Sub
Private Sub Exit_Click()
End
End Sub
VCAdder is created using the MFC AppWizard (exe). The Dialog based option is selected in the wizard. The dialog box controls are copied from the VFAdder dialog box and pasted into the VCAdder dialog box.
The following statement is added to VCAdder.h in order to give the source files access to the AddingMachine object, the IAdd interface and its methods:
#import "..\Adder.dll"
A member variable is added to the CVCAdderApp application class to hold the pointer to the AddingMachine object:
AddingMachineLib::IAddPtr m_pIAdd;
Code is added to the beginning of the CVCAdderApp::InitInstance method to initialize COM and create an AddingMachine object:
CoInitialize(NULL);
m_pIAdd.CreateInstance(__uuidof(AddingMachineLib::AddingMachine));
The MFC Class Wizard is used to add:
OnAdd calls the Add method and the GetValue method.
void CVCAdderDlg::OnAdd()
{
HRESULT hr;
UpdateData();
double addend = atof(m_Addend);
hr = theApp.m_pIAdd->Add((float)addend);
float value = theApp.m_pIAdd->GetValue();
char buffer[32];
sprintf(buffer, "%10.10G", value);
m_CurrentValue = buffer;
m_Addend = "";
UpdateData(FALSE);
}
OnClear calls the Clear method and the GetValue method in a similar way.
Code is added at the end of the CVCAdderApp::InitInstance method to release the AddingMachine object and uninitialize COM:
m_pIAdd.Release();
CoUninitialize();
For design considerations and notes on using Visual Basic and Visual C++ clients, see Visual Basic and Visual C++ Client Notes.
You can modify the server to change the properties of any entry in the hierarchy, add new entries to the hierarchy, move entries in the hierarchy, or remove entries from the hierarchy.
You use the same user interface of the Fortran COM Server Wizard that you used to create the COM server, simplifying any additions, deletions, or changes to your COM server definition. However, you need to pay careful attention to the following files when you modify the COM server definition:
The Fortran COM Server Wizard regenerates the files in the Do Not Edit folder whenever the server definition changes.
To display the Fortran COM Server Wizard:
Once you have published an interface and clients are using it, COM rules state that you must not change the interface. Instead, you should create a new interface, in addition to the original one, and change the name. A common practice is to append a 2 to the name, for the second version of the interface. For example, IAdd would become IAdd2. The second version of your class should support both the original and new interfaces. Old clients continue to work using the original interface. New clients can use the new interface with the new functionality.
The new interface has a different interface ID (IID) than the original interface. The text name is for the convenience of programmers. The IID uniquely identifies the interface.
The Fortran COM Server Wizard adds messages to TODO.TXT anytime the Wizard makes a change to the project and anytime that you make a change to the server definition that requires you to manually edit one or more of the source files. For example, if you add a new method to the IAdd interface, SetValue, that sets the current value to a specific number, the Wizard generates new code to implement the new method in your server. Some of the new code is in the files in the Do Not Edit folder. The Wizard automatically changes these files.
However, a new method skeleton needs to be added to the UIADD.f90 file in the Source Files folder. The wizard never creates a new file with the same name as a file in the Source Files folder, because that would cause the edits that you have made to the files to be lost. Instead, the wizard generates a file with a plus sign (+) appended to the end of the name, for example: UIADD+.f90. The file UIADD+.f90 contains the skeleton of the new method, IAdd_SetValue. In this case, the following message is added to TODO.TXT, and TODO.TXT is opened in the Developer Studio text editor:
The file UIAdd+.f90 has been generated with the following changes.
You must merge these changes with the existing file UIAdd.f90.
The method IAdd_SetValue has been added.
You must use a text editor to copy the new method skeleton from the UIADD+.f90 file and paste it into the UIADD.f90 file.
Whenever a change is made to your server definition, "+" versions of the files in the Source Files folder are generated. You can ignore these files except when TODO.TXT informs you of an action you need to take.
Other changes that would require you to manually merge changes into your source files include: