Porting Mobile Applications Between Windows Mobile and Symbian OS

Why May You Ever Need to Port Your Mobile Applications?

The recent state of the mobile market is quietly challenging from a developer’s perspective. A competition among Symbian OS, Linux, Windows Mobilem and few others (Palm, BREW, Apple, and proprietary OSes, just to mention a few) demands some degree of flexibility from your product. It means that you need to keep in mind how to design your system to be able to support multiple operating systems with minimal headaches while porting. Obviously, you might choose not to bother with porting at all to make your developer’s life easier, but more often than not you simply have no choice because your competitors do it. I don’t mention such a motive as covering wider markets and so forth. Having said this, one needs to make a decision (and not always a simple one); is it worth it to port existing application to a new platform? In many cases, the answer is “YES;” you may choose to port it instead of re-writing it from scratch. It will require some additional work, of course, but the outcome may benefit you a lot. The porting assumes that you may re-use your code and even make it much more robust.

What Effort Will It Require?

There are several well-established patterns for cross-platform development. You can choose to use any of them if you designed your application recently. When you consider the possibility of porting an existing application, the answer may be not so encouraging. In the case of Symbian OS and Windows Mobile, the differences in the platform API are significant, so it is pretty possible that you will have to re-develop all from scratch. Nevertheless, there are many similar concepts and functional API/classes that may be easily replace each other. On the bright side, it may be possible to re-use your existing application design. You still have to create appropriate implementations, but at least the main application structure and control flow remain the same.

The main idea behind porting techniques in regard to the discussion may be expressed as follows: a separate GUI and engine for your application. Most recent frameworks use this paradigm in some form. Symbian OS applications have it naturally due to various GUIs built upon the same Core OS and multiple target platforms. MFC comes with a similar approach for SDI architecture (or WTL classes if you don’t like MFC). Hence, if you followed the guidance and have an engine and the GUI separated, you’re quite lucky. Most of the platform-independent code may be re-used with some modifications. If your application utilizes STL, that helps you too, because both platforms have STL support. POSIX-compliant applications are in the best position because they require minimal porting effort. So, generally speaking, the more platform-neutral code you have, the easier porting will go.

Obviously, the real situation is usually far from ideal. More often than not, you may have the GUI and engine mixing up, GUI handlers keeping some knowledge about the data, and so forth. Well, if you are already facing the need to port, maybe it is a good time to make the code cleaner. The minimal price you have to pay is to re-develop all GUI parts of the application because it will be certainly different between various OSes. As I said earlier, in case of using standard frameworks, it should not be a big issue, though. You still will be able to have the Application object, Document, and View objects in C++ code or use suitable classes in C# for the majority of the situations.

Another aspect of the porting process to consider will be some ‘common type system.’ Symbian OS C++ applications use (or at least are encouraged to use) prefix-based type names, such as ‘T’, ‘C’, ‘M’ and ‘R’ classes. T-classes may be easily #define-ed and mapped to standard C++ types; for example, Tint becomes int and vice versa, BOOL matches TBool, and so forth. Just keep in mind the size of the given type when doing such remapping to avoid any problems with using sizeof(); for example, sizeof(BOOL) and sizeof(bool) are different. For more complicated classes, #define directives also may help where possible. Nevertheless, usually you re-implement particular missing methods for either platform. Having such ‘neutral’ functions makes all the process much easier.

The Differences You Ought to Remember

There are a few basic differences between Symbian OS and Windows Mobile OS you will come across first. I will outline them as the following:

  • CBase class in Symbian OS
  • Two-phase construction in Symbian OS
  • Leaves in Symbian OS vs. Exceptions in Windows Mobile
  • Descriptors in Symbian OS vs. C-style strings or BSTR in Windows Mobile

Those are not the only differences you spot during the porting, but rather the most obvious ones. Let me talk about them one by one.

The CBase class in Symbian OS, being a base class for all heap-based ‘C’ classes, ensures that all class members are zeroed. This fact should be taken into account when you port in either direction to avoid unexpected or unpredictable behavior during code execution. If you port from Symbian OS to Windows Mobile, be sure that all class members are initialized properly. I would say that it is a good practice in general terms.

The next thing is a two-phase construction mechanism that is extensively employed in Symbian applications. It is a robust solution to prevent memory leaks during object initialization. Windows developers often allocate memory directly in constructors. I personally think that this is bad practice and should be avoided where possible because it is pretty hard to control the initialization process if something goes wrong. Imagine that you just declared a member of some class or even a variable on the stack. If a constructor may, for example, throw exceptions, it is quite possible that you will observe very strange behavior under stress conditions. Two-phase construction allows you to avoid such situations and proposes that your class has protected constructor (which only initializes class data members, no allocations there) to prevent direct instantiation of the class instances, static NewL() method to act as a class factory, and a protected Construct() method that performs all required allocations and other tasks. For the Symbian component, you will be forced to follow this coding style; for Windows Mobile applications, you may easily implement similar initialization scheme. So, you can swing from Symbian OS code:

// Typical Symbian OS class sample
EXPORT_C CYourClass* CYourClass::NewL()
   {
   CYourClass* self = new (ELeave) CYourClass;
   CleanupStack::PushL(self);
   self->ConstructL();
   CleanupStack::Pop(self);
   return self;
   }

EXPORT_C void CYourClass::ConstructL()
   {
   // Put your implementation here
   }

EXPORT_C CYourClass::CYourClass()
   {
   // Put your implementation here
   }

to something like the following snippet in Windows Mobile:

// Windows Mobile implementation
CYourClass* CYourClass::NewL()
{
   CYourClass*  self = new CYourClass;
   if (self == 0)
      throw ("Memory allocation error for CYourClass");

   //pass ownership to an auto_ptr
   std::auto_ptr<CYourClass> aptrSelf(self);
   aptrSelf->ConstructL();

   // release self - if we did not, self is deleted when the
   // auto_ptr goes out of scope
   self = aptrSelf.release();
   return self;
}

void CYourClass::ConstructL()
{
   // Put your implementation here
}

CYourClass::CYourClass()
{
   // Put your implementation here
}

The sample above shows also what a ‘Symbian’-style for object’s initialization is.

Once you have isolated your Engine code into a DLL, for Windows Mobile implementation you can provide simple C-style methods for creation, deletion, and other operations upon objects in a given library. Such an approach is convenient when you plan to use the component—for example, from C# code. The Symbian OS uses the method’s index rather than name to get access to the code within the DLL, so you will be able to use exported classes directly from your Symbian application and don’t need to bother about additional exported functions.

If you code for Symbian OS, you know what “Leave” means. For Windows developers, it should be treated as an alternative to an exception handling. Many people may blame Symbian for not supporting exceptions, but what’s done is done, so you can’t help but accept it. According to Symbian’s coding convention, all functions with names ending with ‘L’ may leave. Hence, you should implement the same in your Windows Mobile code. And vice versa, in your Symbian code make the method leave when the original function throws an exception.

And finally, descriptors and strings. The former may be considered as an analogue to BSTR under Windows and can hold both string and binary data. Descriptor manipulation in Symbian OS is painful, no doubt, but with the Carbide.c++ IDE coming onto the scene, you will be able to see their values during debugging at the least. If you can afford using STL port for Symbian OS, it will be a bit easier. Thus, in many cases, std::wstring will be a sufficient replacement for various descriptor classes. With MFC/WTL, you may use CString class as well.

Conclusion

In this article, I discussed a few general topics that may help you when porting various applications between Symbian OS and Windows Mobile OS. As you have seen, such porting is not always possible and often requires too much effort. Nevertheless, you still can use some parts of your existing code, perhaps adopted to new environment. To get some initial feeling of the whole process, you might apply it to one of the samples coming with each SDK; for instance, with WM50 or S60 SDK. Enjoy!

About the Author

Alex Gusev started to play with mainframes at the end of the 1980s, using Pascal and REXX, but soon switched to C/C++ and Java on different platforms. When mobile PDAs seriously rose their heads in the IT market, Alex did it too. After working almost a decade for an international retail software company as a team leader of the Windows Mobile R department, he has decided to dive into Symbian OS ™ Core development.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read