/* $Id: Porting.txt,v 1.2 2000-08-11 10:54:06 sandervl Exp $ */ Porting Win32 applications to OS/2 using Odin - 991212 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.0 Introduction ---------------- Although Odin's primary goal is to run win32 applications in OS/2 without requiring a recompile, it is possible to port Win95/98/NT apps to OS/2 with minimal effort. This is the first draft of this porting guide. If anything is unclear or not mentioned, please contact the author (sandervl@xs4all.nl) 1.1 Odin32 ----------- Odin32 is the win32 compatible API provided with the Odin alpha (or daily builds). It's consists of hundreds of win32 APIs in several dlls (kernel32, user32, gdi32 etc). Keep in mind that Odin is still alpha software, so don't expect all apis to work exactly like those in Windows NT. If you find bugs, please contact the developers or send an email to the Odin programmers mailinglist (win32os2-wai@egroups.com). 1.2 Required tools for porting win32 apps to OS/2 ------------------------------------------------- - IBM VisualAge C++ 3.08 - OS/2 Warp 4 Toolkit (project apparently doesn't compile with VAC's OS/2 headers) Might also work with EMX headers. (haven't tried this) - ALP 4.0 (IBM Assembly Language Processor) Download the tools zipfile from http://service.boulder.ibm.com/ddk/ (you need to register, but it's free) It should also be possible to use Watcom or EMX to do the job, but you might need to make some changes to our headers to make this work. 2.0 Porting Win32 applications to OS/2 -------------------------------------- In order to port win32 apps a few things have to be done: - Change all the makefiles for VAC (or any other OS/2 compiler) - Use Wine RC (wrc.exe) to compile the resources - Add the Odin executable and/or dll wrapper files to the project - Change the source code in case of compile problems 2.1 Changing the makefile(s) ---------------------------- This will probably be the most time consuming (and boring) part of the port. You have to make sure all compiler options are correct for the project and make some changes for compiling the resource script. (see 2.2) To build the ported application, you must link with the necessary Odin libraries in your makefile. These libraries (i.e. kernel32.lib, user32.lib etc) are built when compiling Odin itself. Paragraph 2.6 contains a skeleton makefile. 2.2 Wine's resource compiler (wrc) ---------------------------------- Wrc must be used to compile the resources of the win32 project. Unfortunately wrc isn't completely compatible with Microsoft's rc.exe. You might need to make some changes to the resource script in order to make wrc happy. Wrc produces an assembly file with the a resource tree and binary resources. This resembles the resource section in win32 (PE) executables/dlls. This assembly file should be added to the list of objects files in the makefile. 2.3 Odin's entrypoint wrappers ------------------------------ Kernel32 keeps track of all loaded executables and dlls. The PE loader makes sure image objects are created when loading a win32 executable. A ported win32 app must do this manually by calling certain kernel32 exports. In the src\Odin32API directory of the Odin CVS tree, you'll find two wrappers: - odinexe.cpp: Executable entrypoint (main) - odindll.cpp: Dll entrypoint (_DLL_InitTerm) The executable wrapper calls RegisterLXExe (exported api in kernel32) to create an executable object and tell kernel32 where to find it's win32 entrypoint (usually WinMain) and resources. The dll version does the same thing. It calls RegisterLXDll to create the dll object during a dll load and UnregisterLXDll when the dll is unloaded. It's parameters are the dll module handle, the win32 dll entrypoint (LibMain) and, again, a pointer to the resource object. (as produced by wrc) The resource pointer can be NULL. The handle returned by RegisterLxDll must be used when calling UnregisterLxDll. In the skeleton dll entrypoint we also call ctordtorInit/Term to create/destroy and static C++ objects. If you don't link with odincrt.lib for the runtime C/C++ functions, you must also call CRT_init/CRT_term (before _ctordtorInit, after ctordtorTerm). After RegisterLXExe/Dll has finished it's job in kernel32, it will call the exe/dll entrypoint. 2.4 Win32 source code changes ----------------------------- Usually you shouldn't have to make many changes to the existing win32 source code. However, there might be a few differences between the MS SDK and Odin headers. If you find such problems, please correct them and notify the Odin developers. Complex applications might be hard to port to OS/2 for several reasons: - Compiler differences (i.e. VAC 3.08 doesn't support unnamed unions) VAC 3.6.5 should be a better choice for compiling win32 sources, but it has it's own share of problems (bugs). - TLS (thread local storage) data; VAC has no facilities to support this, so this could require a major rewrite. Other compilers (Watcom) may have better support for this. You can recognize this type of data by the __declspec(thread) keyword. Using the TLS apis (i.e. TlsAlloc) is no problem. - OLE/COM objects. Wine headers aren't exactly built with C++ in mind, so you'll most likely run into a lot of problems if the app uses these win32 features. 2.5 Exception handling ---------------------- RegisterLXExe/RegisterLXDll in kernel32 registers an exception handler for Odin. This handler is used to support file mappings. You must make sure that your code doesn't remove this handler from the chain of exception handlers. To create a thread, use CreateThread; not _beginthread or DosCreateThread. CreateThread takes care of setting up an exception handler, creates TLS structures and calls dll entrypoints. Starting with r21382, Odin also implements the compiler-level support for SEH (structured exception handling) performed using the __try/__except statement in MSVC. Note that this is not a real compiler statement, it is just an emulation of the corresponding MSVC behavior and it has the following limitations: - You should not use goto or longjmp() to jump into or out of the __try or __except block -- this will most likely screw up the stack. - __try/__finally/__leave functionality is not yet supported. - Only the GCC compiler is supported ATM. In order to enable proper handling of the __try/__except statement, you must call EnableSEH() right before a call to RegisterLXDll() or RegisterLXExe() (as described above). A failure to do so will break the filter expression functionality. Note that you normally don't need to chage the Windows sources that the __try/__except statement themselves (except for the limitations mentioned above) as they should already include (which is normally provided by a compiler for the windows platform) and the one included in Odin SDK provides the source-level compatible definitions. 2.6 Sample makefile ------------------- This makefile is used to compile the MS SDK generic sample in OS/2: PDWIN32_INCLUDE = k:\source\odin32\include PDWIN32_LIB = k:\source\odin32\lib PDWIN32_BIN = k:\source\odin32\bin !include $(PDWIN32_INCLUDE)/pdwin32.mk PROJ = GENERIC all: $(PROJ).exe RC = wrc RCFLAGS = -s -I. -I$(CPPMAIN)\include -I$(PDWIN32_INCLUDE) -I$(PDWIN32_INCLUDE)\win # Define project specific macros PROJ_OBJS = generic.obj BASE_OBJS = resource.obj odinexe.obj EXTRA_LIBS = $(PDWIN32_LIB)\version.lib GLOBAL_DEP = generic.h resource.h RC_DEP = resource.h CFLAGS = -Q -Si -Ti -Tm+ -Ge- -Ss+ -W3 -Gm+ /Gn+ -I$(PDWIN32_INCLUDE)\Win -D__WIN32OS2__ -DDEBUG -D__i386__ CXXFLAGS = -Q -Si -Ti -Tm+ -Ge- -Ss+ -W3 -Gm+ /Gn+ -I$(PDWIN32_INCLUDE)\Win -D__WIN32OS2__ -DDEBUG -D__i386__ CFLAGS = $(CFLAGS) /Ge+ -I$(PDWIN32_INCLUDE) CXXFLAGS = $(CXXFLAGS) /Ge+ -I$(PDWIN32_INCLUDE) LDFLAGSEXE = $(LDFLAGS) /Ge+ /B"/pmtype:pm /stack:0x30000 /NOBASE /Map" \ $(EXTRA_LIBS) $(PDWIN32_LIB)\kernel32.lib $(PDWIN32_LIB)\user32.lib \ $(PDWIN32_LIB)\gdi32.lib os2386.lib $(PDWIN32_LIB)\odincrt.lib $(RTLLIB_O) resource.obj: resource.asm # Build rule for resource file resource.asm: $(PROJ).rc $(RC_DEP) $(RC) $(RCFLAGS) -o resource.asm $(PROJ).rc # Build rule for EXE $(PROJ).EXE: $(BASE_OBJS) $(PROJ_OBJS) resource.asm $(LD) $(LDFLAGSEXE) -Fe$@ $(PROJ_OBJS) $(BASE_OBJS) # Build rule for help file #$(PROJ).hlp: $(PROJ).rtf $(PROJ).hpj # $(hc) generic.hpj # Rules for cleaning out those old files clean: del *.bak *.pdb *.obj *.res *.exp *.map *.sbr *.bsc 3.0 Project participation ------------------------- As ODIN became an open source project, everybody is kindly invited to contribute his/her share to the progress of the project. May it be active coding, fixing bugs or just providing detailed information about examined problems. We suggest you subscribe to win32os2-wai and the corresponsing mailing lists on http://www.egroups.com. In case you are interested in participating, every member of the project will be happy to give you direction to the right places and to give a personal introduction to further development of the particular modules.