  <chapter id="bindlls">
    <title id="bindlls.title">Using Linux libraries as 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 shared
        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. 
	      (The ODBC interface in Wine)
            </para>
          </listitem>
          <listitem>
            <para>
              You wish to do something that you can do in Linux but Wine does
              not yet support it.
            </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 DLL 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, unsigned char 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 (depending on changes to the way that the
        specfile is formatted since this was written).
<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.com

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.
        Notice also that we do not specify an initial function.  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-cxx-apis">
      <title id="bindlls-cxx-apis.title">How to deal with C++ APIs</title>
      <para>
        names are mangled, how to demangle them, how to call them
      </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 unsigned long * and
        unsigned short *.  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 &lt;3rd party library&gt; so that it can be
 * used by &lt;the application&gt;
 *
 * Currently this file makes no attempt to be a full wrapper for the &lt;3rd
 * party library&gt;; 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 &lt;3rd party&gt; libraries (currently libxxxx.so and 
 * libyyyy.so)
 */

#include &lt; &lt;3rd party linux header&gt; &gt;
#include &lt;windef.h&gt; /* Part of the Wine header files */

signed short WINAPI MyProxyWinFunc (unsigned short a, void *b, void *c,
                unsigned long *d, void *e, unsigned char f, char g, 
                unsigned char *h)
/* This declaration is as defined in the spec file.  It is deliberately not
 * specified in terms of &lt;3rd party&gt; 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
 */
{
    unsigned short d1;
    signed short ret;

    d1 = (unsigned short) *d;
    ret = &lt;3rd party linux function&gt; (a, b, c, &amp;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>
        The MAIN_OdbcInit function is the function that was named in the
        <link linkend="bindlls-spec">spec file</link> as the init function.
        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 use the --debugmsg +module
        options to wine to see what is actually happening.
      </para>
    </sect1>

    <sect1 id="bindlls-advanced">
      <title id="binary-dlls-advanced.title">Advanced options</title>
      <para>
        Here are a few more advanced options.
      </para>
      <sect2 id="bindlls-adv-filenames">
        <title id="binary-dlls-adv-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 wine_get_unix_file_name (defined in winbase.h).  Use the -ikernel32
          option to winemaker to link to it.
        </para>
      </sect2>
    </sect1>
  </chapter>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-parent-document:("winelib-user.sgml" "book" "chapter" "")
End:
-->
