|  | <chapter id="bindlls"> | 
|  | <!-- FIXME: note that you can link PE DLLs to Winelib apps --> | 
|  | <title id="bindlls.title">Building WineLib DLLs</title> | 
|  | <sect1 id="bindlls-intro"> | 
|  | <title id="binary-dlls-intro.title">Introduction</title> | 
|  | <para> | 
|  | For one reason or another you may find yourself with a Linux | 
|  | library that you want to use as if it were a Windows Dll.  There are | 
|  | various reasons for this including the following: | 
|  | <itemizedlist> | 
|  | <listitem> | 
|  | <para> | 
|  | You are porting a large application that uses several third-party | 
|  | libraries.  One is available on Linux but you are not yet ready | 
|  | to link to it directly as a Linux shared library. | 
|  | </para> | 
|  | </listitem> | 
|  | <listitem> | 
|  | <para> | 
|  | There is a well-defined interface available and there are several | 
|  | Linux solutions that are available for it | 
|  | (e.g. the ODBC interface in Wine). | 
|  | </para> | 
|  | </listitem> | 
|  | <listitem> | 
|  | <para> | 
|  | You have a binary only Windows application that can be extended | 
|  | through plugins, such as a text editor or IDE. | 
|  | </para> | 
|  | </listitem> | 
|  | </itemizedlist> | 
|  | </para> | 
|  | <para> | 
|  | The process for dealing with these situations is actually quite simple. | 
|  | You need to write a spec file that will describe the library's | 
|  | interface in the same format as a Dll (primarily what functions it | 
|  | exports).  Also you will want to write a small wrapper around the | 
|  | library.  You combine these to form a Wine built-in Dll that links to the | 
|  | Linux library.  Then you modify the DllOverrides in the wine config | 
|  | file to ensure that this new built-in DLL is called rather than any | 
|  | windows version. | 
|  | </para> | 
|  | <para> | 
|  | In this section we will look at two examples.  The first example is | 
|  | extremely simple and leads into the subject in "baby steps".  The | 
|  | second example is the ODBC interface proxy in Wine.  The files to which | 
|  | we will refer for the ODBC example are currently in the | 
|  | <filename class="Directory">dlls/odbc32</filename> directory of the | 
|  | Wine source. | 
|  | </para> | 
|  | <para> | 
|  | The first example is based very closely on a real case (the names | 
|  | of the functions etc. have been changed to protect the innocent). | 
|  | A large Windows application includes a DLL that links to a third-party | 
|  | DLL.  For various reasons the third-party DLL does not work too well | 
|  | under Wine.  However the third-party library is also available for the | 
|  | Linux environment.  Conveniently the DLL and Linux shared library | 
|  | export only a small number of functions and the application only uses | 
|  | one of those. | 
|  | </para> | 
|  | <para> | 
|  | Specifically, the application calls a function: | 
|  | <programlisting> | 
|  | signed short WINAPI MyWinFunc (unsigned short a, void *b, void *c, | 
|  | unsigned long *d, void *e, int f, char g, unsigned char *h); | 
|  | </programlisting> | 
|  | and the linux library exports a corresponding function: | 
|  | <programlisting> | 
|  | signed short MyLinuxFunc (unsigned short a, void *b, void *c, | 
|  | unsigned short *d, void *e, char g, unsigned char *h); | 
|  | </programlisting> | 
|  | </para> | 
|  | </sect1> | 
|  |  | 
|  | <sect1 id="bindlls-spec"> | 
|  | <title id="bindlls-spec.title">Writing the spec file</title> | 
|  | <para> | 
|  | Start by writing the spec file.  This file will describe the interface | 
|  | as if it were a DLL.  See elsewhere for the details of the format of | 
|  | a spec file (e.g. man winebuild). | 
|  | </para> | 
|  | <para> | 
|  | In the simple example we want a Wine built-in Dll that corresponds to | 
|  | the MyWin Dll.  The spec file is <filename>MyWin.dll.spec</filename> and | 
|  | looks something like this: | 
|  | <programlisting> | 
|  | # | 
|  | # File: MyWin.dll.spec | 
|  | # | 
|  | # some sort of copyright | 
|  | # | 
|  | # Wine spec file for the MyWin.dll built-in library (a minimal wrapper around the | 
|  | # linux library libMyLinux) | 
|  | # | 
|  | # For further details of wine spec files see the Winelib documentation at | 
|  | # www.winehq.org | 
|  |  | 
|  | 2 stdcall MyWinFunc (long ptr ptr ptr ptr long long ptr) MyProxyWinFunc | 
|  |  | 
|  | # End of file | 
|  | </programlisting> | 
|  | Notice that the arguments are flagged as long even though they are | 
|  | smaller than that.  With this example we will link directly to the | 
|  | Linux shared library whereas with the ODBC example we will load the | 
|  | Linux shared library dynamically. | 
|  | </para> | 
|  | <para> | 
|  | In the case of the ODBC example you can see this in the file | 
|  | <filename>odbc32.spec</filename>. | 
|  | </para> | 
|  | </sect1> | 
|  |  | 
|  | <sect1 id="bindlls-wrapper"> | 
|  | <title id="bindlls-wrapper.title">Writing the wrapper</title> | 
|  | <para> | 
|  | Firstly we will look at the simple example.  The main complication of | 
|  | this case is the slightly different argument lists.  The f parameter | 
|  | does not have to be passed to the Linux function and the d parameter | 
|  | (theoretically) has to be converted between | 
|  | <literal>unsigned long *i</literal> and <literal>unsigned short *</literal>. | 
|  | Doing this ensures that the "high" bits of the returned value are set | 
|  | correctly.  Also unlike with the ODBC example we will link directly to | 
|  | the Linux Shared Library. | 
|  | <programlisting> | 
|  | /* | 
|  | * File: MyWin.c | 
|  | * | 
|  | * Copyright (c) The copyright holder. | 
|  | * | 
|  | * Basic Wine wrapper for the Linux <3rd party library> so that it can be | 
|  | * used by <the application> | 
|  | * | 
|  | * Currently this file makes no attempt to be a full wrapper for the <3rd | 
|  | * party library>; it only exports enough for our own use. | 
|  | * | 
|  | * Note that this is a Unix file; please don't go converting it to DOS format | 
|  | * (e.g. converting line feeds to Carriage return/Line feed). | 
|  | * | 
|  | * This file should be built in a Wine environment as a WineLib library, | 
|  | * linked to the Linux <3rd party> libraries (currently libxxxx.so and | 
|  | * libyyyy.so) | 
|  | */ | 
|  |  | 
|  | #include < <3rd party linux header> > | 
|  | #include <windef.h> /* Part of the Wine header files */ | 
|  |  | 
|  | /* This declaration is as defined in the spec file.  It is deliberately not | 
|  | * specified in terms of <3rd party> types since we are messing about here | 
|  | * between two operating systems (making it look like a Windows thing when | 
|  | * actually it is a Linux thing).  In this way the compiler will point out any | 
|  | * inconsistencies. | 
|  | * For example the fourth argument needs care | 
|  | */ | 
|  | signed short WINAPI MyProxyWinFunc (unsigned short a, void *b, void *c, | 
|  | unsigned long *d, void *e, int f, char g, unsigned char *h) | 
|  | { | 
|  | unsigned short d1; | 
|  | signed short ret; | 
|  |  | 
|  | d1 = (unsigned short) *d; | 
|  | ret = <3rd party linux function> (a, b, c, &d1, e, g, h); | 
|  | *d = d1; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* End of file */ | 
|  | </programlisting> | 
|  | </para> | 
|  | <para> | 
|  | For a more extensive case we can use the ODBC example.  This is | 
|  | implemented as a header file | 
|  | (<filename class="HeaderFile">proxyodbc.h</filename>) and the actual | 
|  | C source file (<filename>proxyodbc.c</filename>).  Although the file | 
|  | is quite long it is extremely simple in structure. | 
|  | </para> | 
|  | <para> | 
|  | <function>DllMain</function> the function is used to initialize the DLL. | 
|  | On the process attach event the function dynamically links to the | 
|  | desired Linux ODBC library (since there are several available) and | 
|  | builds a list of function pointers.  It unlinks on the process | 
|  | detach event. | 
|  | </para> | 
|  | <para> | 
|  | Then each of the functions simply calls the appropriate Linux function | 
|  | through the function pointer that was set up during initialization. | 
|  | </para> | 
|  | </sect1> | 
|  |  | 
|  | <sect1 id="bindlls-building"> | 
|  | <title id="binary-dlls-building.title">Building</title> | 
|  | <para> | 
|  | So how do we actually build the Wine built-in Dll?  The easiest way is | 
|  | to get Winemaker to do the hard work for us.  For the simple example we | 
|  | have two source files (the wrapper and the spec file).  We also have | 
|  | the 3rd party header and library files of course. | 
|  | </para> | 
|  | <para> | 
|  | Put the two source files in a suitable directory and then use | 
|  | winemaker to create the build framework, including configure script, | 
|  | makefile etc.  You will want to use the following options of | 
|  | winemaker: | 
|  | <itemizedlist> | 
|  | <listitem> | 
|  | <para> | 
|  | --nosource-fix and --nogenerate-specs (requires winemaker version | 
|  | 0.5.8 or later) to ensure that the two files are not modified. | 
|  | (If using an older version of winemaker then make the two files | 
|  | readonly and ignore the complaints about being unable to modify | 
|  | them). | 
|  | </para> | 
|  | </listitem> | 
|  | <listitem> | 
|  | <para> | 
|  | --dll --single-target MyWin --nomfc to specify the target | 
|  | </para> | 
|  | </listitem> | 
|  | <listitem> | 
|  | <para> | 
|  | -DMightNeedSomething -I3rd_party_include -L3rd_party_lib -lxxxx | 
|  | -lyyyy where these are the locations of the header files etc. | 
|  | </para> | 
|  | </listitem> | 
|  | </itemizedlist> | 
|  | </para> | 
|  | <para> | 
|  | After running winemaker I like to edit the Makefile.in to add the line | 
|  | CEXTRA = -Wall just before the DEFINES =. | 
|  | </para> | 
|  | <para> | 
|  | Then simply run the configure and make as normal (described elsewhere). | 
|  | </para> | 
|  | </sect1> | 
|  |  | 
|  | <sect1 id="bindlls-installing"> | 
|  | <title id="binary-dlls-installing.title">Installing</title> | 
|  | <para> | 
|  | So how do you install the proxy and ensure that everything connects up | 
|  | correctly?  You have quite a bit of flexibility in this area so what | 
|  | follows are not the only options available. | 
|  | </para> | 
|  | <para> | 
|  | Ensure that the actual Linux Shared Object is placed somewhere where | 
|  | the Linux system will be able to find it.  Typically this means it | 
|  | should be in one of the directories mentioned in the /etc/ld.so.conf | 
|  | file or somewhere in the path specified by LD_LIBRARY_PATH.  If you | 
|  | can link to it from a Linux program it should be OK. | 
|  | </para> | 
|  | <para> | 
|  | Put the proxy shared object (MyWin.dll.so) in the same place as the | 
|  | rest of the built-in DLLs.  (If you used winemaker to set up your build | 
|  | environment then running "make install" as root should do that for you) | 
|  | Alternatively ensure that WINEDLLPATH includes the directory containing | 
|  | the proxy shared object. | 
|  | </para> | 
|  | <para> | 
|  | If you have both a Windows DLL and a Linux DLL/proxy pair then you will | 
|  | have to ensure that the correct one gets called.  The easiest way is | 
|  | probably simply to rename the windows version so that it doesn't get | 
|  | detected.  Alternatively you could specify in the DllOverrides section | 
|  | (or the AppDefaults\\myprog.exe\\DllOverrides section) of the config | 
|  | file (in your .wine directory) that the built-in version be used.  Note | 
|  | that if the Windows version Dll is present and is in the same | 
|  | directory as the executable (as opposed to being in the Windows | 
|  | directory) then you will currently need to specify the whole path to | 
|  | the dll, not merely its name. | 
|  | </para> | 
|  | <para> | 
|  | Once you have done this you should be using the Linux Shared Object | 
|  | successfully.  If you have problems then set the WINEDEBUG=+module | 
|  | environment variable before running wine to see what is actually happening. | 
|  | </para> | 
|  | </sect1> | 
|  |  | 
|  | <sect1 id="bindlls-filenames"> | 
|  | <title id="binary-dlls-filenames.title">Converting filenames</title> | 
|  | <para> | 
|  | Suppose you want to convert incoming DOS format filenames to their | 
|  | Unix equivalent.  Of course there is no suitable function in the true | 
|  | Microsoft Windows API, but wine provides a function for just this | 
|  | task and exports it from its copy of the kernel32 DLL.  The function | 
|  | is <function>wine_get_unix_file_name</function> (defined in winbase.h). | 
|  | </para> | 
|  | </sect1> | 
|  | </chapter> | 
|  |  | 
|  | <!-- Keep this comment at the end of the file | 
|  | Local variables: | 
|  | mode: sgml | 
|  | sgml-parent-document:("winelib-user.sgml" "book" "chapter" "") | 
|  | End: | 
|  | --> |