Advertisment

Porting MFC applications to Linux

author-image
CIOL Bureau
Updated On
New Update

By Markus Neifer

Advertisment

Porting Windows applications to Linux doesn't have to involve a retraining nightmare. Markus Neifer shows how to port MFC using wxWindows, giving a user's guide to this open source GUI toolkit and providing a complete, step-by-step porting example.

With the help of wxWindows, a portable GUI toolkit for C++ and Python, I'll show you how to port a Windows-only MFC application to Linux using a Multiple Document Interface (MDI) text editor as an example. A small application like this helps focus the discussion on the nuts and bolts of porting the framework and prevents us from getting lost in a sea of code.

Document/view overview





The application I'll illustrate uses the well-known document/view architecture, since it deals with documents as most applications do. Even if your application does not use the document/view architecture, I recommend you read on. You might want to add this feature as long as you're already switching the framework. In my previous article about wxWindows, I pointed out some similarities between MFC and wxWindows. The string classes CString and wxString and the event system are very close to each other. But the similarities do not end here.

Advertisment

The wxWindows toolkit also provides MFC-like support for the document/view



architecture. I'll start with a comparison of the core classes. The following table lists the classes involved in the document/view architecture for both frameworks.

Except for the edit view class, each MFC class has its wxWindows counterpart. (The last item is empty for MFC, because MFC does not have a separate document manager class. The documents are handled internally by the application class CWinApp.) The following UML diagrams show the relationships bet ween the classes:

Advertisment

The application



Each framework provides a class that represents the application itself. The MFC application class declares a constructor, a method for initialization, a method for event handling, and a message map. You need the message map declaration and the event handling

method, because the about dialog of the application will be handled by this class.

Advertisment

Application class: MFC

Note: I used the application wizard included in Microsoft Visual Studio to initially create the MFC application, but I won't show the sometimes-confusing wizard-generated comments (//{{AFX_MSG and the like) in my code snippets. See the ZIP archive for full source code.

Advertisment

The wxWindows counterpart looks slightly different. It too declares a constructor and a method for initialization but needs nothing for message handling. As you'll see later, the about dialog is handled in the main frame class.



Application class: wxWindows

This class needs a wxDocManager attribute to handle the templates created in the initialization method OnInit(), as described below. The cleanup method OnExit() will delete this wxDocManager object when the application quits.

Advertisment

Every application needs its entry point (also known as main() or WinMain()). The two frameworks have slightly different approaches to this. In MFC you create a static object of your application class like this:

CPortMeApp theApp;


In wxWindows you use the IMPLEMENT_APP() macro like this:


IMPLEMENT_APP(PortedApp)

If you're interested in what this macro does, take a look at its definition in header file wx/app.h, which you'll find in the downloadable source code. Basically, it will insert the appropriate entry point function for the platform at hand.

Advertisment

After an object of the application class is created, you need to initialize this object. For MFC, Microsoft recommends not using the application object's constructor to initialize the object. Instead, you should use its InitInstance() method. To perform any cleanup, implement the ExitInstance() method.

While application initialization has a lot to it, I'll focus on document/view-related code here.

To set up the document/view framework, the InitInstance() method has to create a CMultiDocTemplate, like so:

The wxWindows application provides an OnInit() method to do any initialization work and an OnExit() method for cleanup. To set up the document/view framework in our wxWindows application, the OnInit() method has to create a wxDocTemplate like this:

What happens is basically the same for MFC and wxWindows. The framework needs information about which document relates to which view and what type of document this combination handles. The type includes a descriptive name for the document and the file extension for such documents. Both frame works use a template to handle this (please note that this has nothing to do with Standard C++ templates).

The MFC CMultiDocTemplate also holds information about what child frame relates to a document, and the template is added to the application object that manages the templates. The wxWindows wxDocTemplate additionally needs a wxDocManager object that manages the templates. Remember that the wxDocManager is an attribute of the application class for the wxWindows application.

After document/view framework initialization is complete, the main frame for the application is created. In the MFC application's InitInstance() method, you create a main frame as follows:

The call pMainFrame->LoadFrame(IDR_MAINFRAME) loads all information about the main frame from a resource file. In wxWindows you can set up your menus, dialogs, and controls from a resource file or you can create them in your code. I prefer to create them in the code, but if you like to separate your code and your resources, you should have a look at the wxWindows resource system (see topic overviews in the wxWindows documentation).

(Creating a main frame: wxWindows)

Before I look at what happens after application initialization is complete, let me show you the document and view classes for each framework. The document The document holds the file-based data that your application works with. It is responsible for loading this data



from file and saving it back to file if necessary. The declaration for the MFC class looks like this:

INSERT GIF 10

(Document class declaration: MFC)

Please note that this class has a protected constructor. You will never create any objects of this class directly; instead, the framework uses serialization to create a document. Therefore, you need to use the DECLARE_DYNCREATE() macro. The declaration for our wxWindows class looks like this:

(Document class declaration: wxWindows)

The DECLARE_DYNAMIC_CLASS() macro is necessary, because wxWindows will create objects of this class dynamically just like MFC does. The view If your MFC application deals with text documents, it's a very good idea to derive your view class from CEditView. This class already offers basic editing functionality and a text control inside its client window. I follow my own advice here, and the declaration for the MFC view class looks like this:

View class declaration: MFC

In wxWindows there's no special edit view (yet). But it's easy to create your own. You just need a wxTextCtrl-derived text control inside the views frame. The view class handles both the control and the frame as class attributes. Therefore the wxWindows declaration looks like this:

In addition to the usual event handlers for window creation, window redraw, and window closing, this class has a method that creates the frame and populates its menu bar.While it's not a good idea to have public attributes, I'm doing it for simplicity here. You should avoid this in your applications (and I will remove this in a future version).





The main frame



Now that you have the document class and the view class to handle and show the data, and you also have an application class to handle the document/view framework, you need a main frame class to interact with the user.

Again, both frameworks offer similar functionality while the actual implementations are slightly different. The MFC main frame class holds a status bar and a toolbar as attributes, offers methods to handle window creation, and declares a message map. Please note that this class derives from CMDIFrameWnd because this application



has a MDI interface.

(Main frame class: MFC)

The wxWindows main frame class holds its menu as an attribute, has methods to create its toolbar, and declares an event table plus a method to handle the application's about dialog. Because this application has a MDI interface, this class derives from wxDocMDIParentFrame.

(Main frame class: wxWindows)





How it all works



The port is finished. I'll review what was needed to get to this point. The MFC application class (CWinApp-derived) was ported to a wxApp-derived application class, including initialization code. The MFC document class (CDocument-derived) was ported to a wxDocument-derived document class.

The MFC view class (CView-derived) was ported to a wxView-derived document class. Besides these document/view-related classes, the MFC main frame class (CMDIFrameWnd-derived) was ported to a wxDocMDIParentFrame-derived class.

In its current version, the application already does quite a bit. You can work with multiple text files. You can open, edit, and save them, and the application maintains a history of recently opened files.

If you had to code this functionality from scratch, many more lines of code would be needed -- and more lines of code means more lines to test and maintain. In both frameworks, special command identifiers are used to handle the common document/view-related commands. Common file commands are new, open, and save. Common edit commands are cut, copy, and paste. Other often-used commands are the print command, which is not implemented in this application, and the help command.

The following table lists the command identifiers involved in the



document/view architecture for both frameworks.

(Table 2. Standard command identifiers)

Window managers



If you're serious about Linux development, you may already have done some research and found out that there are different window managers available for Linux. As a former MFC developer, you might find this odd. When developing for Windows, you don't need to worry about different window managers because there's only one available.

When starting out with wxWindows development, you might wonder whether your application will run on both leading window managers, K Desktop Environment (KDE) and GNOME. I have used the wxWindows toolkit on Microsoft Windows NT 4.0, Sun Solaris 2.6 using the Common Desktop Environment (CDE), and Linux 2.2 using KDE without problems.

As wxWindows is just a high-level layer build on top of other lower-level GUI toolkits, you have some options for how to build your Linux application. You can use the Motif version (or better yet, the free Lesstif) or the GTK+ version of wxWindows.

GTK+ is the base widget toolkit GNOME uses, but it also works well under KDE. I recommend that you use the GTK+ version, because it is usually more current, has more developers working on it, and has more users using it. Therefore, you can expect more help if you ask questions about the GTK+ version on the mailing list or in the newsgroup.

Below are some before-and-after screenshots to give you an idea of what the ported application looks like.

Figure 3. Original MFC application

Figure 4. wxWindows application on Windows

Real-world stories The wxWindows toolkit is not just another toy for nerds. It's mature and stable, and people are using it in real-world applications to solve real-world problems. wxWindows project founder Julian Smart, currently with Red Hat, has ported the eCos Configuration Tool to wxWindows. The eCos Configuration

Tool is a graphic tool for configuring the eCos embedded operating system. The original MFC application has been ported to wxWindows and Linux in particular.

The folks at SciTech Software have also used wxWindows to completely redevelop the front-end GUI for their SciTech Display Doctor product. IBM has licensed a special version of SciTech Display Doctor, which is now distributed by IBM as the primary display driver for all of IBM's OS/2 Warp-based operating systems, including the Warp Client, Workspace On Demand, and Warp Server for e-business.

SciTech Software is an active contributor to the wxWindows community and has submitted the extensions wxApplet, wxUniversal, and wxMGL. With wxMGL, wxWindows apps can even run on DOS and other embedded operating systems such as QNX, RT-Target, SMX, and others. SciTech Software has fully funded both the wxUniversal and wxMGL projects

Conclusion



This article has shown the basic principles of porting Windows applications that use the MFC document/view framework to Linux using the wxWindows toolkit. The wxWindows toolkit offers several similarities to the MFC framework to help MFC developers quickly come up to speed on Linux development.

Armed with this basic knowledge, you should now be able to port your cool killer application to Linux. But never forget: wxWindows is not a Linux-only thing. Maybe it's time to think about a version of your application that runs on other UNIXes or even on the Macintosh.

Resources

 



  • The wxWindows home page is the main place to go for wxWindows community members. It provides information on and support for wxWindows, including downloads, mailing lists, sample applications, and wxWindows-related tools.

 



(Markus Neifer first programmed with the help of the LOGO turtle and later used various flavors of BASIC. Currently, he is a software engineer in the field of geographic information systems. You can reach Markus at

markus.neifer@gmx.net.)

tech-news