Porting windows applications to unix && portable software

Fortunately most software these days is pretty portable. This trend started with "c" code and today we have languages like Java that are designed to be platform independant. Unfortunately, Microsoft still dominates the PC world and thus most user applications so companies looking to market products to the unix world must port applications using DLL's & COM/DCOM objects.

Most programmers specialize in writing application for either PC, Mac or Unix domains and porting the applications written by these programmers is not a trivial task, unless coded using portable C/C++ or Java software.

This white paper is an attempt to outline some of the important considerations in porting application from windows to unix. For more information regarding porting contact me (joe schartman) at joesch woodtennis.com.

Email WoodTennis.com

I would like to first mention a few C/C++ language features that should be used to make software more portable or machine independent so that porting between platforms is not such an issue and the compiler can determine which machine dependant code to build for a given build :

In order to create a dll that will work on Windows and a shared object (so) that will work on under Unix ... I would recommend creating the dll/so first under Windows using one of MS Visual Studio's wizards. There is a wizard to create a dll. In this wizard, there an option to create "Hello World" type dll -- this option would create the DLLMain that is necessary for dlls under windows but not needed for shared objects on Unix. When you port the dll to Unix, you basically place the DLLMain inside an #ifdef ... #endif block -- this block would be compiled under windows but not under unix. See example below for OracleDac.cpp:

This first block of #ifdef _WIN32 ... #endif MUST occur at beginning of file prior to anyother includes.

#ifdef _WIN32

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

// Insert your headers here

#define WIN32_LEAN_AND_MEAN

// Exclude rarely-used stuff from Windows headers

#include <windows.h>

#endif

#include "OracleDac.h" // include any other files here.

Here's the block for DllMain which is needed for windows but not unix.

#ifdef _WIN32

BOOL APIENTRY DllMain(

HANDLE hModule,DWORD ul_reason_for_call, LPVOID lpReserved)

{ switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

case DLL_THREAD_ATTACH:

case DLL_THREAD_DETACH:

case DLL_PROCESS_DETACH:

break;

}

return TRUE;

}

#endif // ifdef _WIN32

// Add any other exported methods here.

For the dll/shared objects that are created, Windows requires a special macro to be placed before class and function declarations in order to know if the item is to imported or exported. However, these macros aren't known to the unix world and aren't required. So another #define is needed in order to take care of this. Additionally for C++, all compilers tend to mangle class/function definitions differently. Our dlls export classes but a windows user can't create an instance of a class without the exported macro definition being used or the presence of .def file. So in our platform.h/platform.cpp files (included), we have macros defined based on the type of OS you are running. These macros are used during the compilation phase in order to determine if extra code gets placed in your dll/so. So our classes and global functions have "SOEXPORT" placed in front of the function/class declaration. So for windows, SOEXPORT is defined as #define SOEXPORT __declspec(dllexport) and in unix SOEXPORT is Not defined.

Here are some examples:

extern "C" SOEXPORT CDacSession* CreateORACLE(); SOEXPORT CDacSession* CreateORACLE()

{

return new COraSession();

}

class SOEXPORT COraSession : public CDacSession{....}

In our case, we only used the dll/so for use in a dynamic abstract factory. Basically, what that does is only load the dll/so during run-time when it is needed. This factory uses a generic methods (platform.h cpp) to load, unload, get function pointer to a method. See the comment at the near the end of platform.h. I have a generic article (hard-copy only) on abstract factories. The user would request a particular type of object and the factory would determine if the dll/so was loaded (if so, then create instance for user); otherwise attempt to load the dll/so based on type (if it was able to load the dll/so, then create instance for user). DacDynamicPluggableFactory is an example dynamic abstract factory. The factory uses the "C" methods in the dll/so to get instances of objects.

I can't really get into the building of shared objects on unix due each compiler having different compiler switches to build shared objects. But in platform.cpp (at the end) there are the three routines to load, unload, get proc address that work for windows and unix. Unix uses dlopen,dlclose, dl<something ...don't remember off top my head> and windows uses Win32 api calls .... just see the routines at end of platform.cpp



WWW & Internet programming books

This page was created by Joe Schartman for CyberTennis Website.
Last Revised: Nov 2000