Novell Home

Porting Windows MFC applications to Linux

Novell Cool Solutions: Feature
By Bill Bodine

Digg This - Slashdot This

Posted: 17 Aug 2004
 

Introduction

This article is designed to give some ideas and direction to developers who have been writing applications in a Windows environment using the Microsoft Foundation Classes (MFC) and who now recognize that they need to support the Linux platform with their applications as well. Articles abound on the Internet that take up the religious fervor of trying to persuade readers why they should develop to either MFC or the various Linux APIs. I happily leave that argument to others. The assumption here is that the reader is not so much interested in the marketing and religious wars, but that they accept that the Linux world represents a vast revenue potential for them and so, irrespective of strengths or weaknesses between the two platforms, they must have their application running on Linux to compete.

First off, it is important to recognize that the developer is going to have to make a choice as to which GUI toolkit they will use when moving to Linux. It is not that different from the Windows developer who has had to choose whether to use Microsoft's MFC or Borland's ObjectWindows Library (OWL), or some other vendor's object libraries. While the options may be plentiful, a few of the options a Linux developer may choose between that I will discuss in this article are

1) wxWidgets -- an open source, cross-platform, C++ GUI toolkit,

2) QT -- another cross-platform, C++ GUI toolkit developed by Trolltech, and

3) GTK+ - another cross-platform, 'C' based GUI toolkit.

A developer will likely choose any one of these toolkits for their application based on experience and development preference rather than technical inadequacies that may exist. All three are available on the SUSE distribution or from the SUSE SDK for end user and development purposes.

One of the obvious differences a Windows developer may notice when they first move to the Linux environment is that, unlike Windows, there is not one single desktop environment that is used in all cases. I guess it could be argued that there are a few possibilities in Windows, since a machine may have Windows 2000 or Windows XP or others. The difference here is that all these originate from the same vendor, whereas the two most popular Linux desktop environments, KDE and GNOME, are developed and managed by different organizations. In fact they really compete with each other for ownership of the desktop. This should not concern a developer, however, since most Linux distributions, and in our case SUSE, ship with both environments and the user can switch between the two at any time. Additionally, all the toolkits mentioned previously will work in both desktop environments.

In this article I will overview each of the three toolkits to see if I can help give some direction to the new Linux developer that needs to write an application for this platform, and has been developing their application using MFC. Of course, it is assumed that tools like WINE, the Open Source implementation of Windows on Linux, have been tested and do not fit the developer's need for some reason. WINE is usually worth investigating early on, since there is a good chance that a Windows application will run without any modifications when using these libraries. However, some developers will choose not to use WINE, even if their application does run for a few common reasons:

1) using WINE gives a Windows look and feel on Linux that frankly may be offensive to some of the user community that the developer is attempting to reach, and

2) at times some dialogs and components are not displayed on Linux in a way that is pleasing to the developer.

The only way to know this is to test it. Fortunately, WINE is included with SUSE distributions, so it is very easily tested.

wxWidgets

One of the nicest things to note about wxWidgets, right up front, is that it is a cross-platform tool that uses native libraries to interface with the host system. What this means is that when a wxWidget application is executed on Windows it will conform to the look and feel of other Windows applications, however, when it is run on Linux it will look like other Linux applications, specifically, GTK+/GNOME applications, since that is the set of libraries typically used by wxWidgets for Linux. I don't mean to imply that wxWidgets gives 'binary' compatibility across platforms like you can get with WINE, however, while achieving a high level of source code compatibility, you will still be getting the desired native UI look and feel with your application.

wxWidgets is also one of the more mature open source GUI projects around. It began in 1992 at the Artificial Intelligence Applications Institute (University of Edinburgh) and was called wxWindows. In February of 2004 the name was changed to wxWidgets to help avoid potential confusion with any Microsoft products. It supports most of the prevailing desktop environments, including Windows 95/98/ME, Windows NT/2000/XP, Linux/Unix with the GTK+ toolkit (motif or the X11 APIs can also be used), and MacOS.

Part of this toolkit's attractiveness to developers is that besides being free to use (it uses a GNU GPL compatible license called the wxWindows Library license), it is also very well documented. It has roughly 1800 pages of documentation in HTML, PDF and Windows Help formats. It also has over 50 sample programs that can be used to help learn the tool.

Of the three tools to be discussed in this article, wxWidgets is the one that most closely resembles MFC, and so may represent the most intuitive port. wxWidget, for example, has an event mechanism that is very similar to the message maps used in MFC. When developing an MFC application, the BEGIN_MESSAGE_MAP and END_MESSAGE_MAP macros are used to define the messages that are used in your application control. Within the scope of these macros, other macro entries are used to define the particular message-handler function (ON_BN_CLICKED, ON_COMMAND, ON_WM_PAINT, etc.). The DECLARE_MESSAGE_MAP macro is used at the end of the class declaration to build the map of those messages declared in the implementation file (.cpp) within the BEGIN_MESSAGE_MAP and END_MESSAGE_MAP macros.

wxWidgets has similar macros to these. The BEGIN_EVENT_TABLE and END_EVENT_TABLE macros are used just as the BEGIN_MESSAGE_MAP and END_MESSAGE_MAP macros are in MFC. Likewise within the scope of these macros the developer will include macros such as EVT_MENU, EVT_BUTTON and EVT_INIT_DIALOG to declare the particular messages that will be implemented in the program. If these macros seem unfamiliar, you may want to take a minute and look at your MFC implementation and header files. You will see these macros that I've discussed here. After analyzing these files and becoming comfortable with what they are doing, you should now know that when you port your application to wxWidgets you will use these macros in almost the same fashion (with name changes, etc.)

The following are examples extracted from an MFC project and from a wxWidgets project. Hopefully the similarities are apparent:

MFC -- file.cpp

BEGIN_MESSAGE_MAP(CLoginDlg, Cdialog)
     //{{AFX_MSG_MAP(CLoginDlg)
     ON_BN_CLICKED(IDC_USE_SSL_CHECK, OnUseSslCheck )
     ON_BN_CLICKED(IDC_SAVE_SETTINGS_CHK, OnSaveSettingsChk )
     //}}AFX_MSG_MAP
END_MESSAGE_MAP()

wxWidgets -- file.cpp

BEGIN_EVENT_TABLE( wxHelloWorldFrame, wxFrame )
     EVT_MENU( Menu_File_Quit, wxHelloWorldFrame::OnQuit )
     EVT_MENU( Menu_File_About, wxHelloWorldFrame::OnAbout )
END_EVENT_TABLE()

MFC -- file.h

class CLoginDlg : public CDialog
{
public:
        // member variables here
protected:
        // Generated message map functions
        //{{AFX_MSG(CLoginDlg)
        virtual void OnOK();
        virtual BOOL OnInitDialog();
        afx_msg void OnUseSslCheck();
        afx_msg void OnLoginSaveSettingsChk();
        //}}AFX_MSG
        DECLARE_MESSAGE_MAP()   
}

wxWidgets -- file.h

class wxHelloWorldFrame : public wxFrame
{
   public:
           wxHelloWorldFrame( const wxString& title, 
                              const wxPoint& pos,
                              const wxSize& pos );
           void OnQuit( wxCommandEvent& event );
           void OnAbout( wxCommandEvent& event );
   private:
           DECLARE_EVENT_TABLE()
}

MFC and wxWidgets also are very similar when you look at a comparison of the core classes. For example, if we look at the Dialog classes in both frameworks we see the following:

The names of these classes alone show their relative similarity. The CCmdTarget and wxEvtHandler classes are both used to handle messages from their respective windowing systems.

Similarities also exist in the various controls for each framework. If we look at the button controls, for example, we see the following:

The wxControl class has only three methods - wxCommand, wxGetLabel, wxSetLabel. MFC includes the equivalent of these methods in the CWnd class (SendDlgItemMsg, GetDlgItemText, SetDlgItemText).

Finally, the two frameworks also share similarities in many of their helper classes such as CString/wxString, and CList/wxList.

Hopefully, with this brief introduction it is apparent that the wxWidget toolkit is a good option for an MFC developer who would like to port their application to run on Linux. In a future article, I will take an MFC application and will port it to Linux, showing some of the tools that a developer may choose to use, and giving some ideas about how a port could possibly be accomplished.

Qt

Qt is an object-oriented toolkit that uses native libraries on each of the platforms that it supports. However, where wxWidgets is built on GTK+ in the Linux world, Qt is written to interface directly with X11. Qt is developed privately by Trolltech and so, obviously, does not enjoy the benefit of being developed by the open source community. However, it is still a very powerful and popular toolkit. KDE, one of the desktop options on SUSE distributions, is implemented on the free edition of Qt. This raises the issue that always seems to come up when talking about Qt. It is free when used in non-commercial applications, however, it is not free when developing a commercial, proprietary or non-free software. Likewise it is not free if developing for Windows or embedded systems. At any rate, before using Qt to develop your application, it would be important to understand its licensing model before you begin.

Qt does not look as much like MFC as does wxWidgets, which some would see as its strength. One of the primary differences lies in its event mechanism. Where MFC uses message maps, as was discussed earlier, Qt uses the notion of ?signals? and ?slots?. The visual elements in Qt are called widgets and are derived from the QWidget class. These widgets emit signals when an event occurs. For example, a button will emit a ?clicked? signal after it has been clicked by a user. If a developer wants to perform an action when the signal event occurs, they ?connect? to the signal by creating a function called a ?slot?. Since these are not static mappings the developer can connect and disconnect to various symbols at anytime in their application. Signals and slots are type-safe and so will report type errors rather than crashing the system as MFC might with its message maps. In the following example, the developer has connected the clicked signal from the login button to a slot (method) in his application called LoginUser().

connect( loginButton, SIGNAL(clicked()), qApp, SLOT( LoginUser()) );

Even though MFC and Qt have significant differences, the Trolltech people have made efforts to ease the pain of porting an application from MFC to Qt. They have created a library called the ?Windows Migration Framework?. When using this framework within an MFC application, it is possible to use Qt Widgets and events within the MFC message map model. The premise is that if you already have an MFC application you can leave the existing controls as they are initially. When you add new controls you would use Qt widgets rather than MFC controls. The developer would then begin, one at a time, removing any of the MFC controls in their application and replacing them with Qt widgets. While both types of controls exist in the application, the Windows Migration Framework would still be used to provide cross compatibility, but as soon as all the MFC controls and events are removed, then the framework can be removed and the developer will have a cross platform application. The link at: http://doc.trolltech.com/solutions/qtwinmigrate/winmigrate-walkthrough.html contains a good reference to see how this can be accomplished.

GTK+

GTK is a nested acronym for ?GIMP Toolkit?. GIMP stands for ?GNU Image Manipulation Program?, and of course GNU stands for the recursive acronym ?GNU's Not Unix?. GTK+ is free software and is part of the GNU project. The GNU LGPL license that it uses allows it to be used by all developers, even those developing proprietary software, without any license fees or royalties.

Like the other toolkits discussed thus far, GTK+ has the notion of widgets. However, since GTK+ is a 'C' API rather than C++, things are obviously dealt with differently. Porting to GTK+ from MFC would involve much more of a rewrite than it would with the other toolkits. Rather than instantiating classes as you would in C++, this toolkit provides methods that are used to allocated space to structures like ?GTKWidget?. For example the general steps to use a GTKWidget are:

  1. Allocate space for a new widget with one of the gtk_*_new calls
    1. gtk_window_new( GTK_WINDOW_TOPLEVEL);
    2. gtk_button_new();
  2. Connect the appropriate signals to call handling functions
    1. g_signal_connect( G_OBJECT(window), ?destroy?,
                G_CALLBACK(gtk_main_quit), NULL );
    2. g_signal_connect( G_OBJECT(window), ?delete_event?,
                G_CALLBACK(gtk_main_quit), NULL );
    3. g_signal_connect( G_OBJECT(button), ?clicked?,
                G_CALLBACK(buttonCallBack),
                (gpointer)?a data string? );
  3. Set the attributes of the widget
    1. gtk_container_set_border_width( GTK_CONTAINER(window), 10 );
    2. gtk_button_set_label( G_OBJECT(button), ?A Kool Button? );
  4. Pack the widget into a container
    1. gtk_container_add( GTK_CONTAINER(window), button );
  5. Show the widget
    1. gtk_widget_show( window) ;

For those developers who want to use GTK+, but really prefer C++, there is an open source project that has created ?gtkmm?. This is a C++ wrapper that sits on top of GTK+ and offers developers a reasonable alternative if they desire to do object oriented development.

Summary

What has been delivered in this article is a brief overview of a few of the toolkits a developer may want to look at if they see the need to port their MFC application to a Linux platform. It has not been exhaustive, in fact there are other toolkits that I have not covered, like FOX and FLTK, that could be worth looking into as well. In future articles, I plan to take each of the toolkits covered here and describe them in a bit more depth by actually porting an MFC application to these toolkits. A key aspect that will be covered in these articles, will be to look at a few of the visual designers that are available, like GLADE, Anjuta, BOA Constructor, etc. With these introductions a developer should be reasonably well equipped to begin a porting project.

References

Borland OWL - http://www.borland.com/
MFC -- http://www.microsoft.com
wxWidgets -- http://www.wxwindows.org
Qt -- http://www.trolltech.com
Gtk+ - http://www.gtk.org
gtkmm -- http://www.gtkmm.org
FLTK -- http://www.fltk.org
FOX -- http://fox-toolkit.net/cgi-bin/wiki.pl


Novell Cool Solutions (corporate web communities) are produced by WebWise Solutions. www.webwiseone.com

© 2014 Novell