WineLib HOWTO Version 28-Dec-2000 AUTHOR: Wilbur Dale Lumin Software BV Zandheuvel 52 B 4901 HW Oosterhout (NB) The Netherlands wilbur.dale@lumin.nl WARNING: This HOWTO is incomplete. I expect to add to it on a weekly basis until it is complete. ===================================================================== Table of Contents I. Introduction: Wine vs. WineLib II. Legal Issues III. How Much Work? IV. File Format Conversion V. Compiling A Simple Win32 Program VI. Compiling A Win32 Program With Resources VII. DLLs A. Windows executable and Windows DLL. B. Windows executable and WineLib DLL. C. WineLib executable and Windows DLL. D. WineLib executable and WineLib DLL. VIII. How to use MFC A. Using a native MFC DLL B. Compiling MFC VIII. Trademarks Windows 3.x, Windows 95, Windows 98, Windows NT are trademarks of Microsoft Corporation. Unix is a trademark of ???? FIXME: who has the trademark this week? CrypKey is a trademark of Kenonic Controls Ltd. FIXME: Codewright copyright ??? All other trademarks are the property of their respective owners. ===================================================================== I. Introduction: Wine vs. WineLib WineLib provides the Win32 API to a non-Microsoft operating system. The WineLib Win32 functions use X11 functions to perform the actual drawing on the screen. Wine and WineLib are based on the same set of functions that implement the Win32 API. The difference between Wine and WineLib is the type of executable that is loaded into memory and executed. If an executable and any associated DLLs were compiled for x86 hardware running the Windows 95, 98, or Windows NT (TM) operating systems, then Wine can use a special binary loader to load the program and the libraries into memory and execute it. WineLib on the other hand allows you to take the source for such a program and DLLs and compile it into the native format of a x86 Unix or Linux operating system. WineLib also allows you to partially compile the program and DLLs into the native format. For example, if you use a DLL from a vendor to provide some functions to your program and the vendor does not give you source, then you can use the Windows version of the DLL to provide the functions and compile the rest of your program in the native form for your system. [1] Windows compilers and linkers generate executables with a different structure than standard compilers. Windows has two executable formats: the NE format and the PE format. The NE executable format provides for two entry points and the PE format provides for three entry points while a standard executable has a single entry point. Usually, a NE or a PE executable will use one of the entry points for your program and the other entry points will print an error message and exit. However, a linker can link 16 bit objects into one or both of the alternate entry points of a NE or PE executable. Standard compilers assume that the function main() exists. The entry point for a standard program is constructed from the C runtime library, initialization code for static variables in your program, the initialization code for your classes (C++), and your function main(). On the other hand, windows compilers assume WinMain() exists. The entry point for a windows program is constructed from the C runtime library, initialization code for static variables in your program, the initialization code for your classes (C++), and your function WinMain(). [4] Since main() and WinMain() have different type signatures (parameter types), WineLib provides certain aids to generate code so that your program can be compiled and run as written for windows. For example, WineLib generates a main() to initialize the windows API, to load any necessary DLLs and then call your WinMain(). Therefore, you need to learn four basic operations to compile a windows program using WineLib: compiling a simple program, compiling resources, compiling libraries, and compiling MFC (if you will be using MFC). Each of these skills or operations are explained in later sections of this HOWTO. Before you start porting your windows code to WineLib, you need to consider whether you are allowed to port your program to WineLib. As you compile your program using WineLib, you will be combining software from several sources and you need to ensure that the licenses for the components are compatible. Hence, in the next section, we will examine several legal issues. II. Legal Issues Disclaimer! I am not a lawyer. The purpose of this section is to make you aware of potential legal problems. Be sure to read your licenses and to consult your attorney. During the compilation of your program, you will be combining code from several sources: your code, WineLib code, code from your vendor's DLLs (if any), and Microsoft MFC code (if used). As a result, you must ensure that the licenses of all code sources are obeyed. What you are allowed and not allowed to do can vary depending on how you compile your program and if you will be distributing it. For example, if you are releasing your code under the GPL, you cannot link your code to MFC code because the GPL requires that you provide ALL sources to your users. The MFC license forbids you from distributing the MFC source so you can not comply with the GPL license except by not distributing you program. On the other hand, if your code is released under the LGPL, you cannot statically link your program to MFC and distribute it, but you can dynamically link your LGPL code and MFC code and distribute it. Wine/WineLib is distributed under an X11-like license. It places few restrictions on the use and distribution of Wine/WineLib code. I doubt the Wine license will cause you any problems. On the other hand, MFC is distributed under a very restrictive license and the restrictions vary from version to version and between service packs. If you plan on using MFC, there are three hurdles to legally using MFC. The first hurdle is how to legally get MFC source code on your computer. MFC source code comes as a part of Visual Studio. The license for Visual Studio implies it is a single product that can not be broken up into its components. The cleanest way to get MFC on your system is to use a dual boot Linux box with the windows partition visible to the Linux OS. Boot into windows and install Visual Studio. Since Visual Studio is installed on the computer, you have not broken it into its components. There may be other solutions, but I think this is the easiest. FIXME: quote relevant sections of EULA in above paragraph. The second hurdle for MFC is the legality of compiling MFC on a non-Microsoft operating system. This varies with the version of MFC. MFC license from Visual Studio 6.0: 1.1 General License Grant. Microsoft grants to you as an individual, a personal, nonexclusive license to make and use copies of the SOFTWARE PRODUCT for the sole purposes of designing, developing, and testing your software product(s) that are designed to operate in conjunction with any Microsoft operating system product. [Other unrelated stuff deleted.] So it appears you cannot compile MFC for WineLib using this license. On the other hand, Visual Studio 6.0 service pack 3 (Visual Studio 5.0 is similar): 1.1 General License Grant. Microsoft grants to you as an individual, a personal, nonexclusive license to make and use copies of the SOFTWARE PRODUCT for the purpose of designing, developing, and testing your software product(s). [Other unrelated stuff deleted] So it appears you can compile MFC for WineLib using this license. The third hurdle is your legal right to distribute an MFC library. Check the relevant section of the license on redistributables and your redistribution rights. As I read the license, you only have the right to distribute binaries of the MFC library if it has no debug information and if you distribute it with an application that provides significant added functionality to the MFC library. FIXME: quote relevant sections of EULA in above paragraph. Once you have examined the licenses for all of the sources used in compiling your program and have decided you can legally compile you program using WineLib, you should probably experiment with your program running under Wine to determine how much work will be involved in the port. The next section will give advice on estimating the amount of work required for porting your program to WineLib. III. How Much Work? Wine and WineLib use the same functions to implement the windows API; hence, if your program correctly runs under Wine, it should run under WineLib. However, Wine/WineLib is incomplete; you may have trouble running your program under Wine. Many people have successfully run many programs under Wine, so there is a good chance you will have no trouble. Wine executes the binary program that was compiled for a windows operating system. There are differences between the windows operating system and Unix/Linux operating systems. For example, in Windows 95 and Windows 98, the program has direct access to the hardware. A copy protection program that you purchased for your windows executable may use direct hardware access to write data to the disk. Hence, you may need to disable the copy protection in order to test your executable under Wine. As a specific example, CrypKey is a copy protection program we use at Lumin Software. Our program does not execute under Wine with the copy protection enabled. We disabled the copy protection, recompiled the windows executable, and our program works fine. CrypKey also works for Windows NT where it creates a service. Using Wine with the --winver nt40 option "almost" gets the our program working with copy protection. At a later date, we intend to either implement the system calls in Wine that are missing for CrypKey or to use another copy protection program that does work under Linux. During the execution of your program, Wine prints error messages to standard error. These error messages include "stubs", which are windows API functions that have not been completely implemented. Depending on the system call, these could be harmless or crash your program. Most of the common windows API functions have already been implemented, so you should have no missing API functions or only a few missing functions. If you intend to continue with the port to WineLib, you will need to implement these API functions. After running your program for a while, you should have a good feel for the number of windows API functions that you need to implement. FIXME: give info on Wine command line options to control error messages. During the compilation of Wine, you can control the amount of error messages and debug information that will be be generated by Wine and WineLib. For the version released to your customers, you may want to use the following command line to configure the Wine/WineLib libraries. ./configure --disable-debug --disable-trace The option --disable-debug compiles out all debugging messages and the option --disable-trace compile out TRACE messages. [2] It is not necessary for you to implement the entire documented behavior of an API function in order to get your program to work. For example, many API functions have pointer parameters that are NULL in the common cases. If you always call the function with a NULL pointer for the default behavior, you can save yourself some effort by implementing a function that only works for the NULL pointer parameter. If you do this, make sure you test if the parameter is non-null and issue a warning for the non-null case. Also document in the source that the API function is incomplete. FIXME: give info on the FIXME (macro/function?) for partially implemented API functions. Once you have implemented an API function, submit the change back to the Wine project so the next person to need the same function does not need to repeat your work. Remember, someone else wrote all of the other API functions that you are using, so you are benefitting from their work. Let other people benefit from your work as well. If you work for a company, you may need your company's permission to "give away" your work. IV. File Format Conversion Before you can compile your program, you must deal with one major difference between Windows and WineLib. Window sources are in DOS format with carriage return / line feed at the end of each line of text while WineLib files are in Unix format with only line feed at the end of each line of text. The main problem with the difference between Unix and DOS format source files occurs with macro line continuation. A Unix compiler expects a backslash (\) followed by a newline (^J) to indict that a macro is continued on the next line. However, a file in DOS format will have the characters backslash (\), carriage return (^M), and newline (^J). The Unix compiler will interpret the backslash (\), carriage return (^M), newline (^) of a file in DOS format as a quoted carriage return and newline. The Unix compiler will think the line has ended and the macro is completely defined. Hence, before you compile your sources, you will need to convert you DOS format sources to Unix format. There are several tools such as dos2unix and tr that are available to convert the format. FIXME: get more info on dos2unix, tr, and all other such tools and give example commands. Until I do [3] is a good source. FIXME: is CR/LF conversion necessary for gcc 2.95 ? V. Compiling A Simple Win32 Program Wine and WineLib are written in C as is the MS Win32 API; thus, if have a program that calls only the Win32 API directly, you can compile the program using a C compiler and link it with some of the WineLib libraries. There are several simple examples of WineLib programs in the directory libtest/ in the Wine source tree. We shall examine one of these to show you how to compile a WineLib program. The example we shall examine is hello2. If you examine hello2.c, you will see it is a windows program that pops up a message box that says "Hello, hello!". It can be compiled and run using a windows compiler just like any other windows program. However, it can not be compiled and run with a non-windows compiler. As mentioned previously, windows programs have an entry point called WinMain(), while non-windows compilers use an entry point of main(). Hence, we need some "glue" to glue the main() entry point to the WinMain() in the windows program. In WineLib, some of the glue is provided by the spec file. Spec files are used in several places in Wine and WineLib to provide glue between windows code and code for non-windows compilers. WineLib provides a tool called winebuild in the tools/winebuild directory that converts a spec file into a C file that can be compiled and linked with the windows source files. If you examine hello2.spec, you will see the following: name hello2 mode guiexe type win32 import user32.dll import kernel32.dll import ntdll.dll Information on the complete format of the spec file can be found in /tools/winebuild/README. Name is the name of the application. Mode is the type of "glue" that winebuild needs to create. Possible modes are 'dll' for a library, 'cuiexe' for a console application, and 'guiexe' for a regular graphical application. Type is the type of API, either win32 or win16. Win16 is supported only in Wine, not WineLib, so you should use win32. Import is a dll that must be loaded for the program to execute. During compilation of the hello2 executable, the following command is executed. LD_LIBRARY_PATH="..:$LD_LIBRARY_PATH" \ ../tools/winebuild/winebuild -fPIC -L ../dlls -sym hello2.o \ -o hello2.spec.c -spec hello2.spec The program winebuild will generate the output file hello2.spec.c (option -o hello2.spec.c) from the spec file hello2.spec (option -spec hello2.spec). The option -fPIC specifies that winebuild should generate position independent code and is only necessary for building shared library files (.so files). It is not needed when building the main executable spec file, but since there is no assembly code generated for the main executable, it doesn't make any difference anyway. [5] The winebuild program is used in several places in Wine as well as WineLib; however, only the -spec option will be used in WineLib. The output file hello2.spec.c contains the glue code to initialize WineLib and call WinMain(). In order to run hello2, we will compile the code into a shared library (hello2.so) and create a symbolic link (hello2) with the wine executable with the following steps. gcc -c -I. -I. -I../include -I../include -g -O2 -Wall -fPIC -DSTRICT \ -D_REENTRANT -I/usr/X11R6/include -o hello2.o hello2.c to compile the windows program itself and gcc -c -I. -I. -I../include -I../include -g -O2 -Wall -fPIC -DSTRICT \ -D_REENTRANT -I/usr/X11R6/include -o hello2.spec.o hello2.spec.c to compile the spec file and the glue code. Finally, gcc -shared -Wl,-rpath,/usr/local/lib -Wl,-Bsymbolic -o hello2.so \ hello2.o hello2.spec.o -L.. -lwine -lncurses -lm -lutil -ldl links the compiled files into a shared library. FIXME: -D_REENTRANT why? FIXME: explain compiler options FIXME: explain linker options All of the steps are automated with the makefile, so "make hello2.so" will execute all of the steps for you. A final step is "make hello2", which creates a symbolic link from hello2 to the wine executable. Now, when "./hello2" is run, the wine executable sees it was called by the name "hello2" and loads the shared library "hello2.so" and executes the program. THE INFO BELOW IS OUT OF DATE (28-Dec-2000) Thus, you now have the basics of compiling a simple windows program. There are two more things to learn for compiling more complex windows programs: windows resources and DLL dependencies. Window resources are described in the next section. DLL dependencies are handled by linker magic with windows compilers. Thus, in WineLib, you will need to provide information about which DLLs your program depends. This information is given in the spec file. For example, if our hello2 program had a .wav file that it played, it would need the multi-media DLL winmm. Our spec file would then be name hello2 mode guiexe type win32 init WinMain import winmm If you need to list multiple DLLs, then the import specification can appear multiple times, one line per imported DLL. VI. Compiling A Win32 Program With Resources FIXME: to be continued. Describe wrc. Go through hello world example 3. VII. DLLs As mentioned in the introduction, Wine allows you to execute windows executables and windows libraries under non-Microsoft operating systems. WineLib allows you to take sources intended for the windows operating system and to compile them to run as native executables under a Unix/Linux operating system. With an executable and a single library, there are four combinations in which to run the programs and the library: 1. a Windows executable with a Windows DLL, 2. a Windows executable with WineLib DLL, 3. a WineLib executable with Windows DLL, and 4. a WineLib executable with WineLib DLL. In this section, we will discuss each of these and discuss the steps required to implement the executable/DLL combination. A. Windows executable and Windows DLL Running a windows executable with a windows DLL is not a WineLib program: it is a Wine program. If you type wine program.exe and the DLL is in the search path, then the windows program should run using the windows DLL. FIXME: find out what is the search path. B. Windows executable and WineLib DLL Running a windows executable with a WineLib DLL is also accomplished using the Wine program. The source code for the DLL is compiled into a Unix style shared library. When the windows executable "loads" the DLL, Wine will use the shared library (.so file) instead. At first you may wonder why you would want to run a windows executable with a WineLib DLL. Such a situation implies you do not have the source for the executable, but you do have the source for the DLL. This is backwards from what you might expect. However, I do have an example where this situation might arise. Codewright is a popular editor in the windows world, and the capabilities of Codewright can be extended by using DLLs. Since Codewright is a commercial product, you do not have the source and must use the windows executable with Wine. If you have written a DLL to add functionality to Codewright, you have two choices: you can compile the DLL using a windows compiler and use both a windows executable and a windows DLL as in case A above, or you can use WineLib and compile the DLL as a shared library (.so file). I have no idea if Codewright actually runs under Wine, but this is an example of why you might decide to use a windows executable and a WineLib DLL. Many other editors and other programs use DLLs to extend their functionality. In order for Wine to use the WineLib DLL, certain glue code is need to replace the linker magic that windows compilers use. As with a simple executable, the winebuild program uses a spec file to generate the glue code. For example, in the spec file for the DLL will look something like name winedll type win32 init winedll_DllMain 1 cdecl _WINEbirthDay@4 ( str ) WINEbirthDay 2 cdecl _WINEfullName@4 ( str ) WINEfullName The name is the name of the DLL. Since WineLib only supports win32, the type should always be win32. The init function is the name of the initialization function for the DLL. The initialization function for a windows DLL is named DllMain(). You will need to rename the function in the DLL source so there will not be any name clashes with the DllMain() of other DLLs in you program. The last two lines of the spec file above, provide the export information for the DLL. For example, the line 1 cdecl _WINEbirthDay@4 ( str ) WINEbirthDay says that the function at ordinal 1 uses the cdecl calling convention for the parameters. The DLL export name is _WINEbirthDay@4. The function takes a single parameter that is a string. Finally, the C function name to be called whenever this DLL function is called is WINEbirthday. You will need a function ordinal line for each function in the DLL. The export name and the ordinal can be obtained from the windows program dumpbin and the windows version of the DLL. See the file /tools/winebuild/README for more details on the spec file format. During the compile process, a command like winebuild -fPIC -o winedll.spec.c -spec winedll.spec will be executed to create the file winedll.spec.c from information in the file winedll.spec. The file winedll.spec.c and winedll.c are compiled into object files and used to create the shared library. In order for the program to run, a copy of the shared library must be in your EXTRA_LD_LIBRARY_PATH. For example, if your wine.conf file has the following line, EXTRA_LD_LIBRARY_PATH=${HOME}/wine/lib then you must copy the shared library into the directory ~/wine/lib/ and the shared library will now be in the correct search path. Now when you type wine program.exe the program will load the shared library (.so). C. WineLib executable and Windows DLL Running a WineLib executable with a Windows DLL is accomplished using WineLib. This situation will be common since you may have purchased DLLs to use with you project and the DLL vendor may not give you the source code for the DLL. In order for WineLib to use the Windows DLL, certain glue code is needed to replace the linker magic that windows compilers use. Part of the glue code must be written by you. The basic idea of the glue code is that you write a new DLL that consists of function pointers. Each function in the DLL will consist of a call on a function pointer. For example, WINEDLL_ConstString WINEDLL_INTERFACE WINEfullName( WINEDLL_ConstString handle ) { return (* pWINEfullName) ( handle ); } The initialization function for the DLL will use the function LoadLibrary() to load the windows DLL and initialize the function pointers using the function GetProcAddress(). Since Wine can use either windows DLLs or Unix shared libraries (.so), the LoadLibrary() function call may have unexpected results if there is a winedll.dll and a winedll.so file. Hence, the windows version of the DLL should be named something like hiddenWinedll.dll and the shared library should be named winedll.so. Now the shared library will use LoadLibrary() to load the "hidden" DLL. The shared library will need a spec file. Fortunately, it is simpler than case B above. The spec file will look something like name winedll type win32 init winedll_DllMain The name is the name of the DLL. Since WineLib only supports win32, the type should always be win32. The init function is the name of the initialization function for the shared library. This is the function that will load the "hidden" DLL and initialize the function pointers. There is no need for any function ordinals unless your program calls functions by the ordinal. During the compile process, a command like winebuild -fPIC -o winedll.spec.c -spec winedll.spec will be executed to create the file winedll.spec.c from information in the file winedll.spec. The file winedll.spec.c and winedll.c are compiled into object files and used to create the shared library. Now that the shared library is compiled, you still need to compile your program. Part of the compile process for your program will consist of a spec file for your program. For example, name program mode guiexe type win32 init WinMain import winedll.dll This spec file is similar to the spec file of the simple WineLib example in part V above. The only difference is the import specification that tells WineLib that the main program uses winedll.dll. If this import line is not included, the "hidden" DLL will not be loaded and the function pointers will not be initialized. During the compile process, a command like winebuild -fPIC -o program.spec.c -spec program.spec will be executed to create the file program.spec.c from information in the file program.spec. The file program.spec.c and your source code are compiled into object files and used to create the executable. D. WineLib executable and WineLib DLL. Running a WineLib executable with a WineLib DLL is accomplished using WineLib. The source for the DLL will be combined with a spec file to generate the shared library. Likewise, the source for your program and a spec file will be combined to create the executable. In the source for the DLL, you should change the name of DllMain() to a name like winedll_DllMain() so that there will not be a name clash with other initialization functions for other DLLs. The shared library's spec file is like case C above. The spec file will look something like name winedll type win32 init winedll_DllMain The init function is the name of the initialization function for the shared library (what you renamed DllMain to). There is no need for any function ordinals unless your program calls functions by the ordinal. During the compile process, a command like winebuild -fPIC -o winedll.spec.c -spec winedll.spec will be executed to create the file winedll.spec.c from information in the file winedll.spec. The file winedll.spec.c and the source code for your DLL are compiled into object files and used to create the shared library. Compiling your program is exactly like case C above. For example, the spec file for you program will look something like name program mode guiexe type win32 init WinMain import winedll.dll During the compile process, a command like winebuild -fPIC -o program.spec.c -spec program.spec will be executed to create the file program.spec.c from information in the file program.spec. The file program.spec.c and your source code are compiled into object files and used to create the executable. VIII. How to use MFC A. Using a native MFC DLL B. Compiling MFC FIXME: to be continued. ===================================================================== References Until this HOWTO is complete, I will document who gives me what information. Reference [1] From: Patrik Stridvall To: "'wilbur.dale@lumin.nl'" , Date: Mon, 5 Jun 2000 14:25:22 +0200 First of all WineLib suppport for Win16 has been discontinued for quite some time, because: 1. It is difficult for us to support and it is impossible to do so perfectly without special compiler support, because of memory layout issues. For example Win16 int is 16-bit and data is aligned 16-bit. 2. It is in almost all cases easier to port a Win16 application to Win32. A minor detail, I personally would prefer that Wine and WineLib was always used in the uppercase W and uppercase L variant, instead of, as in your document, sometime one variant, sometimes another. Reference [2] The exact options for controlling error messages mentioned in the reference are apparently incorrect, but may have been correct for some earlier version of Wine. From: michael cardenas To: wilbur.dale@lumin.nl Date: Mon, 5 Jun 2000 13:19:34 -0400 a few things you should mention... - you can compile resources as a dll under windows and then load the dll with wine. That's what we do for canvas. This is probably not ideal, but most of my problems porting were in the code. We very seldomly have to change the resources for the porting process. But wrc does work for most cases... - the error messages can be turned off or turned up with options to configure like --enable-trace-msgs=wireoff or --enable-trace-msgs=wireon . Take a look at configure. - you probably want to compile your WineLib with --disable-debugger, at least for the release version of your app. Reference [3] http://fgouget.free.fr/wine/winelib-en.shtml Reference [4] Date: Wed, 21 Jun 2000 10:34:10 +0200 From: Rob Carriere To: Wilbur N Dale Subject: WineLib-HOWTO comments Hello Wilbur, Some picking of nits. It reads right well. Some of Windows xyz are registered trade marks, other are vanilla: Microsoft: Registered Windows NT: Registered Windows (95,98): plain A Windows compiler does NOT generate a fake main. Instead, the executable file format provides for 2 (NE) or 3 (PE) entry points. One of these is your program, the other(s) are normally filled with stubs that print an error message and exit. It is possible to instruct the _linker_ to link 16-bit objects into one or both of the alternate entry points, and create a fat binary. At the C/C++ level, your statement about WinMain() is correct. Of course the actual entry point first inits run time lib etc, and then calls the C/C++ level entry, but that is also true for main() in the standard setup. It may be important to regurgitate this info here, though, because some of the fun things that can happen with multiple run time libs and DLLs occur at this level. Line 86: I only need to know how compile MFC if I use it... :-) Best regards, Rob mailto:rob.carriere@lumin.nl Reference [5] To: wilbur.dale@lumin.nl Subject: Re: tool/build questions From: Alexandre Julliard Date: 13 Jun 2000 20:06:23 -0700 "Wilbur N. Dale" writes: > 2. tools/build for WineLib users -- is there ever a need to not specify -pic? -pic is only necessary for building .so files, so it's not needed when building the main executable spec file (but since there is no assembly code generated for the main exe it doesn't make any difference anyway). -- Alexandre Julliard julliard@winehq.com Reference [6] Wine Weekly News #51 (2000 Week 28) Events, progress, and happenings in the Wine community for July 10, 2000. Uwe Bonnes and Ove Kaven also reminded of some tools to generate under Linux some Windows executables: * Cygwin/Mingw: as native Linux apps * LCC-Win32: run with the help of Wine * Borland C++ 5.5: command line version available for free (after registering to Borland users' database) ===================================================================== The information included here is from various Wine-devel posting and private e-mails. I am including them so that any one starting on MFC will have some documentation. Glean what you can and good luck. Before I write more detailed info on compiling MFC I have three questions. The info I have mentions three problems: 1. Wine header files---what is the status of this? Do changes need to be made in the headers and if so, do I submit the changes back into Wine cvs? Do the changes need #ifdef for C vs. C++ compilation? Francois Gouget has been doing a lot of work in this area. It should be a lot easier to compile using C++ now and to compile MFC. 2. DOS format files and no case distinction in filenames. Do the extensions Corel made to gcc 2.95 handle this? If so, how? 3. Microsoft extensions to the C++ syntax. Do the extensions Corel made to gcc 2.95 handle this? If so, how? If you have info that needs to be added, send me email at and I will add it. ===================================================================== THANKS Most of the information in this file came from postings on and from private e-mails. The following people contributed information for this document and I thank them for their time and effort in answering my questions. I also want to thank them for encouraging me to attack the MFC problem. CONTRIBUTERS: Damyan Ognyanoff Gavriel State Ian Schmidt Jeremy White From: Ian Schmidt Subject: Re: WineLib and MFC "Wilbur N. Dale" wrote: > What is the status of MFC under WineLib? I don't know precisely. Corel has done more MFC work than anyone (all of their applications which they are porting are MFC-based), and reportedly they have MFC itself compiled. I was just trying to get a moderately simple MFC-using app to compile, with moderate success (there are still some problems with MFC's headers after my patch, but at least they don't appear to be Wine's fault :) I did not try to compile MFC itself. > Which versions of MFC, if any? I have no idea what version Corel uses. As noted in my patch, I was fiddling with the headers for MFC 6 (from Visual C++ 6.0 Service Pack 3). Most of the stuff my patch addressed was for newer IE 5-related features, so I'd guess MFC 5 (VC++ 5.0) is likely what they used. > Is there any documentation on how to compile MFC for WineLib? If so > where? Not that I know of. > I have started to compile programs using WineLib (hello.c last > Sunday) and expect to be ready to start compiling MFC in a couple of > weeks. If documentation is not available on compiling MFC, I am > willing to write it. Documentation would be a Good Thing, as WineLib in general is grossly underdocumented right now. Here's a few tips I discovered to get you started: - First off, run all the MFC headers (and source too if you try it) through a utility to strip out the DOS carriage returns. They cause havoc with GCC when it sees one after a line that ends with a \ (and MFC has many macros in it's headers that meet that description). If you don't have one, do a Google search on "fromdos" and you should locate some source (or it's fairly easy to make your own). - Use GCC 2.95.2, and the -fpermissive flag to make it less picky. 2.95.2 has some VC++-compatibility features that Corel paid for, and I believe more are forthcoming in future GCCs. - Use -I to add whereever you have the MFC headers at to your include path, as MFC apps typically use #include <> to access them rather than "". - Be prepared to have to rename and/or symlink headers, unless you compile on a case-insensitive filesystem :) - When you make install Wine it seems not to include all it's headers in /usr/local/include/Wine. To have any chance at getting MFC going you'll want to use -I to add the include/ directory from the Wine source tarball to the path so it can grab everything. Sorry I can't help you more, but good luck! -Ian Schmidt ischmidt@cfl.rr.com From: Jeremy White Subject: Re: RFC: Wine 1.0 "Wilbur N. Dale" wrote: > > Further, we have successfully built MFC after making only > > a modest set of changes to it, even with older > > versions of g++. > > Lumin Software is about to use WineLib to port a window program to linux. A > couple of years ago we thought we had to make a modification to MFC for one > of our projects and we had problems getting MFC to compile under MS Visual C++. > After much wailing and gnashing of teeth, we gave up and did things another > way. After this bad experience, we were wondering --- approximately how many > man-hours did you spend compiling and changing MFC ? Urk. I misspoke. None of the developers here that I thought had working versions of MFC with Wine have working versions any longer. So, it may be a bit trickier than I led you to believe. We have it working pretty reliably with TWine, but not quite so cleanly (yet) with Wine. However, it really shouldn't be too difficult, and this is what I can remember of the process: 1. If you use a very modern version of gcc (2.95.2 or higher), I believe you will need to add the -relaxed flag to have any hope of compiling. 2. If you use an earlier version of gcc, you will need to adjust the many anonymous structs/unions that MFC supplies. We prefer this approach, because requiring very modern gcc implementations seems harsh to us. 3. You will need to adjust for the many type differences between MFC intrinsic types and the types supplied by Wine. For example, I believe that MFC expects a HANDLE to be compatible with certain scalar types, (and it is under Windows/VC, but is not with Wine/gcc). 4. The key procedure: add many -DNO_XXX flags to the makefile. If you start with Microsofts make file for MFC, convert it into a Wine makefile, and then turn on many of the flags they list there (of the form -DNO_XXX), your life will get much easier. Once you get it working with a few -DNO_XXX flags, you can go back and add them back in. 5. The best resource: you need someone who knows C++ very, very well. You occassionaly run into very obscure C++ problems where MS has extended the C++ standard and gcc has not. It really helps to have a guru on hand when you hit those. I hope this helps. Sorry for the earlier deceptive post. Jeremy From: Gavriel State Subject: Re: MFC questions "Wilbur N. Dale" wrote: > 1. Compile MFC. Several years ago we (Lumin Software) tried to > compile MFC. The attempt failed and we found another way to do what > we wanted. MS documentation states that compiling MFC was > deliberately made difficult. Considering my experience with stuff > they call "easy" I am not looking forward to compiling MFC. We are > currently using Visual Studio 5 for windows development. At Corel, we had MFC compiled and running sample apps in WineLib in late 1998. It's mostly a question of the Wine headers, which weren't originally up to snuff. We did quite a bit of work on them, and most of those changes have been contributed back to WineHQ, so it should be pretty easy now. The other thing that was a big deal was getting the startup code working properly - since MFC needs to initialize static data *after* WineLib gets initialized. I believe that that issue has been addressed now on the WineHQ side with some of the work done on the .spec file tools recently. -Gav -- Gavriel State CEO TransGaming Technologies Inc. gav@transgaming.com From: Jeremy White Subject: Re: MFC questions "Wilbur N. Dale" wrote: [snip] > 1. Compile MFC. Several years ago we (Lumin Software) tried to > compile MFC. The attempt failed and we found another way to do what > we wanted. MS documentation states that compiling MFC was > deliberately made difficult. Considering my experience with stuff > they call "easy" I am not looking forward to compiling MFC. We are > currently using Visual Studio 5 for windows development. Wilbur, I personally think that this is the 'right' approach, although approach #2 may prove faster. Despite your previous experience, and despite my earlier incorrect statements, I think that this is simpler than you fear. It's one of those tasks that's darkest before the storm - you spend all of your energy getting all the include files to work. Once you have *one* object file, the rest go much more quickly (alright, getting it to link is also a hairball of a job, but it's tractable ). If you're not in a hurry, getting MFC to compile, and having a documented procedure for compiling it is on our agenda for the relatively near future (see the Wine 1.0 task list). Jer p.s. Stick with Visi C++ 5. IMHO its MFC license is cleaner than that of VC 6. From: Gavriel State Subject: The MSVC++ 6.0 license Jeremy White wrote: > p.s. Stick with Visi C++ 5. IMHO its MFC license is cleaner than that > of VC 6. Actually, I just picked up a copy of MSVC 6.0 and it appears that they changed the license between the original release and the Service Pack 3 release - they removed the bit in section 1.1 about requiring that you be developing your software product only for use with a Microsoft OS. In any case, even the original license explicitly says that the MFC redistribution rights are *in addition* to the usage rights in section 1.1. The relevant portion of the original EULA: 1.1 General License Grant. Microsoft grants to you as an individual, a personal, nonexclusive license to make and use copies of the SOFTWARE PRODUCT for the sole purposes of designing, developing, and testing your software product(s) that are designed to operate in conjunction with any Microsoft operating system product. [Other unrelated stuff deleted] >From the SP3 EULA: 3. Section 1.1 of the EULA is deleted in its entirety and replaced with the following: 1.1 General License Grant. Microsoft grants to you as an individual, a personal, nonexclusive license to make and use copies of the SOFTWARE PRODUCT for the purpose of designing, developing, and testing your software product(s). [Other unrelated stuff deleted] Disclaimer - I am not a lawyer, but I've spent lots of time with them investigating software licenses. -Gav -- Gavriel State CEO TransGaming Technologies Inc. gav@transgaming.com From: Damyan Ognyanoff Subject: Need a hint Hi, I manage to build mfc42 as .so library and a application using it (as a .so library too). I execute it using simple loader which is linked to Wine and I load my application in it's WinMain routine. The problem is how clearly to unload mfc and my application (to invoke mfc's destructors before loader is terminated) All is fine except that there is a "zombi" reference to code in shared library which is invoked in Wine code and generate GPF. debugger stops somewhere in aplication's InitInstance !!! - and the stack is broken so I can't catch where exactly the problem is. Any hints are welcome. I'm using Wine-2000517 shapshot downloaded form Wine.datapary.no TNX. Damyan p.s. If any of You is interested in details I can share my experience. WND comment: Francois Gouget has been doing a lot of work in the headers of wine. It should be a lot easier to compile using C++ now and to compile MFC. Many of the actions needed in the following email are not needed any more. From: Damyan Ognyanoff Subject: Re: Wine MFC info request hi, my MFC is from VC6.0 with SP3 MFC Bulid: (form afxbld_.h) #define _MFC_BUILD 8447 #define _MFC_USER_BUILD "8447" #define _MFC_RBLD 0 mfcdll.rc FILEVERSION 6,0,_MFC_BUILD,_MFC_RBLD PRODUCTVERSION 6,0,0,0 Hints: 1. Wine include files In some of them you will find error about '__attribute__' all kinds of similar errors can be fixed using proper typedefs first example : typedef BOOL (CALLBACK *DLGPROC)(HWND,UINT,WPARAM,LPARAM); must be converted to typedef BOOL CALLBACK (*DLGPROC)(HWND,UINT,WPARAM,LPARAM); and the second kind is something like TYPE* WINAPI SomeFunction(HWND param1,UINT param2); The problem here is a TYPE* or TYPE& (in some of mfc files) the workaround is to declare a type before: typedef TYPE* TYPEPtr; or typedef TYPE& TYPERef; and declaration will look like: TYPEPtr WINAPI SomeFunction(HWND param1,UINT param2); note: don't miss a 'struct' when you define struct type pointers. I miss it and get a lot of problems compiling MFC: >> struct _TEB; typedef !!!struct!!! _TEB* P_TEB; extern inline P_TEB WINAPI NtCurrentTeb(void); << Those conversions are semanticaly the same as above but g++ compile them and generate proper code to invoke __stdcall kind of functions in some of Wine/obj_XXX.h files: Wine/obj_base.h - there are a lot of defines's that are used to declare a COM interfaces #define ICOM_METHOD(ret,xfn) \ public: virtual ret (CALLBACK xfn)(void) = 0; will be (for all of them that are related to C++ (watch #ifdef's carefully)): #define ICOM_METHOD(ret,xfn) \ public: virtual ret CALLBACK (xfn)(void) = 0; and the second tip is an error when compiler stops on line like: ICOM_DEFINE(ISomeInterfase,IUnknown) watch method declarations above to find something like: ICOM_METHOD1(TYPE*,MethodName, DWORD,dwParam) and replace TYPE* with proper TYPEPtr type. In many cases You will see void* which can be replaced simply by LPVOID. qthere are several errors related to anonymous structs and unions but they can be avoided with proper - #ifdef __cplusplus This is all about Wine headers I think. If you find something that I miss type a line of mail to me. 2. MFC The rules are the same with some new issues: virtual BOOL Method1(int param1, BOOL (CALLBACK *param2) (HWND,UINT,WPARAM,LPARAM)); don't compile. I remove a function pointer declaration outside method: typedef BOOL CALLBACK (*param2Type)(HWND,UINT,WPARAM,LPARAM); virtual BOOL Method1(int param1, param2Type param2); I didn't apply this technique to a operator new definitions: void* AFXAPI operator new(size_t nSize); so i remove AFXAPI from these declarations: I got some missed #defines from commctrl.h and I added them form VC6.0 include. these are my defines form Makefile which I used to compile MFC -DTWINE_NO_CMONIKER \ -- this is related to exclude CMonikerFile -D__urlmon_h__ \ -- Wine didn't have URL interfaces -D_AFX_NO_OLEDB_SUPPORT \ -D_WIN32 \ -DNOWIN98 \ -- this is used to exclude all unimplemented classes from commctrl -D_AFX_PACKING \ -D_AFX_NO_DHTML_SUPPORT \ -D_AFX_NO_SOCKET_SUPPORT \ -D_AFX_NO_SYNC_SUPPORT \ -D_AFX_NO_OCX_SUPPORT \ -D_AFX_PORTABLE \ -D_AFX_OLD_EXCEPTIONS \ -D_AFX_NO_SOCKET_SUPPORT \ -D_AFX_NO_DEBUG_CRT \ -D_AFX_NO_DAO_SUPPORT \ -D_AFX_NO_OCC_SUPPORT \ -D_AFX_NO_INET_SUPPORT \ -D_AFX_NO_RICHEDIT_SUPPORT \ -D_X86_ \ -DLONGHANDLES may be you will try to enable some of features of mfc I tested only -D_AFX_NO_OCC_SUPPORT but got missing interfaces from Wine in file afxcom_.h - _CIP<_Interface, _IID>::~_CIP<_Interface, _IID>() + _CIP<_Interface, _IID>::~_CIP() in file afxtempl.h - BOOL Lookup(BASE_CLASS::BASE_ARG_KEY key, VALUE& rValue) const - { return BASE_CLASS::Lookup(key, (BASE_CLASS::BASE_VALUE&)rValue); } + BOOL Lookup(typename BASE_CLASS::BASE_ARG_KEY key, VALUE& rValue) const + { return BASE_CLASS::Lookup(key, (typename BASE_CLASS::BASE_VALUE&)rValue); } and all releated errors can be fixed in this way. 3. spec file name mfc42 type win32 rsrc mfc42 10 stdcall WinMain(long long ptr long) WinMain 4. linking use -rdynamic wnen link libmfc.so to get ARGV and ARGC from loader 5. I didn'n build a extension dll with Wine but I suspect that there will be some problems related to a chaining Runtime classes form MFC to a new dll 6. build your app as a MODULE too. 7. make a loader and in it's _WinMain: ... includes are here iint PASCAL (*winMain)(HINSTANCE,HINSTANCE,LPSTR,int) = 0; my app uses these to manage filenames VOID __cdecl (*_splitpath1)(LPCSTR path, LPSTR drive, LPSTR directory, LPSTR filename, LPSTR extension ) = NULL; VOID __cdecl _splitpath(LPCSTR path, LPSTR drive, LPSTR directory, LPSTR filename, LPSTR extension ) { if (_splitpath1) _splitpath1(path, drive, directory, filename, extension ); } VOID __cdecl (*_makepath1)(LPSTR path, LPCSTR drive, LPCSTR directory, LPCSTR filename, LPCSTR extension ) = NULL; VOID __cdecl _makepath(LPSTR path, LPCSTR drive, LPCSTR directory, LPCSTR filename, LPCSTR extension ) { if (_makepath1) _makepath1(path, drive, directory, filename, extension); } int PASCAL _WinMain(HINSTANCE h,HINSTANCE h1,LPSTR lpszCmdParam,int c) { HINSTANCE hInstance,hins,hlib,htst,hform,himag,hexe; int retv; hins = LoadLibrary("CRTDLL.DLL"); _splitpath1 = GetProcAddress(hins, "_splitpath"); _makepath1 = GetProcAddress(hins, "_makepath"); hins = LoadLibrary("COMCTL32.DLL"); hins = LoadLibrary("COMDLG32.DLL"); hins = dlopen("libmfc42.so",2); hlib = LoadLibrary("mfc42"); himag = dlopen("libmxformatslib.so",2); hform = LoadLibrary("mxformatslib"); hexe = dlopen("libmxpaint.so",2); htst = LoadLibrary("mxpaint"); winMain = GetProcAddress(hlib, "WinMain"); if (winMain) { retv = winMain (htst, // note the > htst < HERE 0, lpszCmdParam, SW_NORMAL); } FreeLibrary(htst); FreeLibrary(hform); FreeLibrary(hlib); dlclose(hexe); dlclose(himag); dlclose(hins); return retv; } the spec for loader is: name c10 mode guiexe type win32 init _WinMain please find attached a Makefile which i use to build MFC Regards Damyan. LocalWords: WineLib HOWTO Jul vs DLLs DLL MFC NT FIXME CrypKey Kenonic API TM LocalWords: Codewright NE PE WinMain GPL LGPL EULA nonexclusive winver nt dos LocalWords: redistributables unix tr CR LF gcc libtest winebuild pic fPIC dll LocalWords: guiexe init cuiexe lwine lncurses lm lutil ldl wav winmm wrc lcc LocalWords: dllExamples WindowsExeWindowsDLL WindowsExeWineDLL WineExeWineDLL LocalWords: WineExeWindowsDLL Borland URL's cd distclean DllMain winemain exe LocalWords: winedll cdecl WINEbirthDay str WINEfullName WINEbirthday libtool LocalWords: proost conf LD libwinedll Gouget docs dumpbin ConstString Lumin LocalWords: pWINEfullName LoadLibrary GetProcAddress hiddenWinedll BV HW dlls LocalWords: Zandheuvel Oosterhout linkers executables runtime ntdll sym Wl LocalWords: DSTRICT REENTRANT rpath Bsymbolic makefile multi