Added an example of using winemaker.
[wine] / documentation / winelib-bindlls.sgml
1   <chapter id="bindlls">
2     <title id="bindlls.title">Dealing with binary only dlls</title>
3     <sect1 id="bindlls-intro">
4       <title id="binary-dlls-intro.title">Introduction</title>
5       <para>
6         For one reason or another you may find yourself with a Linux shared
7         library that you want to use as if it was a Windows Dll.  There are
8         various reasons for this including the following:
9         <itemizedlist>
10           <listitem>
11             <para>
12               You are porting a large application that uses several third-party
13               libraries.  One is available on Linux but you are not yet ready
14               to link to it directly as a Linux shared library.
15             </para>
16           </listitem>
17           <listitem>
18             <para>
19               (The ODBC interface in WINE).  There is a well-defined interface
20               available and there are several Linux solutions that are
21               available for it.
22             </para>
23           </listitem>
24         </itemizedlist>
25       </para>
26       <para>
27         The process for dealing with these situations is actually quite simple.
28         You need to write a spec file that will describe the library's 
29         interface in the same format as a Dll (primarily what functions it
30         exports).  Also you will want to write a small wrapper around the
31         library.  We combine these to form a Wine builtin Dll that links to the
32         Linux library.
33       </para>
34       <para>
35         In this section we will look at two examples.  The first example is
36         extremely simple and leads into the subject in "baby steps".  The
37         second example is the ODBC interface proxy in Wine.  The files to which
38         we will refer for the ODBC example are currently in the 
39         <filename class="Directory">dlls/odbc32</filename> directory of the
40         Wine source.
41       </para>
42       <para>
43          The first example is based very closely on a real case (the names
44          of the functions etc. have been changed to protect the innocent).
45          A large Windows application includes a DLL that links to a third-party
46          DLL.  For various reasons the third-party DLL does not work too well
47          under Wine.  However the third-party DLL is also available for the
48          Linux environment.  Conveniently the DLL and Linux shared library 
49          export only a small number of functions and the application only uses
50          one of those.
51        </para>
52        <para>
53          Specifically, the application calls a function:
54 <programlisting>
55 signed short WINAPI MyWinFunc (unsigned short a, void *b, void *c,
56         unsigned long *d, void *e, unsigned char f, char g,
57         unsigned char *h);
58 </programlisting>
59          and the linux library exports a corresponding function:
60 <programlisting>
61 signed short MyLinuxFunc (unsigned short a, void *b, void *c,
62         unsigned short *d, void *e, char g, unsigned char *h);
63 </programlisting>
64        </para>
65     </sect1>
66
67     <sect1 id="bindlls-spec">
68       <title id="bindlls-spec.title">Writing the spec file</title>
69       <para>
70         Start by writing the spec file.  This file will describe the interface
71         as if it was a dll.  See elsewhere for the details of the format of
72         a spec file.
73       </para>
74       <para>
75         In the simple example we want a Wine builtin Dll that corresponds to
76         the MyWin Dll.  The spec file is <filename>libMyWin.spec</filename> and
77         looks like this.
78 <programlisting>
79 #
80 # File: libMyWin.spec
81 #
82 # some sort of copyright
83 #
84 # Wine spec file for the libMyWin builtin library (a minimal wrapper around the
85 # linux library libMyLinux)
86 #
87 # For further details of wine spec files see the Winelib documentation at
88 # www.winehq.com
89
90 name    MyWin
91 type    win32
92 mode    dll
93
94 2 stdcall _MyWinFunc@32 (long ptr ptr ptr ptr long long ptr) MyProxyWinFunc
95
96 # End of file
97 </programlisting>
98         Notice that the arguments are flagged as long even though they are
99         smaller than that.
100       </para>
101       <para>
102         In the case of the ODBC example you can see this in the file 
103         <filename>odbc32.spec</filename>.
104       </para>
105     </sect1>
106
107     <sect1 id="bindlls-cxx-apis">
108       <title id="bindlls-cxx-apis.title">How to deal with C++ APIs</title>
109       <para>
110         names are mangled, how to demangle them, how to call them
111       </para>
112     </sect1>
113
114     <sect1 id="bindlls-wrapper">
115       <title id="bindlls-wrapper.title">Writing the wrapper</title>
116       <para>
117         Firstly we will look at the simple example.  The main complication of
118         this case is the slightly different argument lists.  The f parameter
119         does not have to be passed to the Linux function and the d parameter
120         (theoretically) has to be converted between unsigned long * and
121         unsigned short *.  Doing this ensures that the "high" bits of the
122         returned value are set correctly.
123         <programlisting>
124 /*
125  * File: MyWin.c
126  *
127  * Copyright (c) The copyright holder.
128  *
129  * Basic WINE wrapper for the linux &lt;3rd party library&gt; so that it can be
130  * used by &lt;the application&gt;
131  *
132  * Currently this file makes no attempt to be a full wrapper for the &lt;3rd
133  * party library&gt;; it only exports enough for our own use.
134  *
135  * Note that this is a Unix file; please don't go converting it to DOS format
136  * (e.g. converting line feeds to Carriage return/Line feed).
137  *
138  * This file should be built in a Wine environment as a WineLib library, 
139  * linked to the Linux &lt;3rd party&gt; libraries (currently libxxxx.so and 
140  * libyyyy.so)
141  */
142
143 #include &lt; &lt;3rd party linux header&gt; &gt;
144 #include &lt;windef.h&gt; /* Part of the Wine header files */
145
146 signed short WINAPI MyProxyWinFunc (unsigned short a, void *b, void *c,
147                 unsigned long *d, void *e, unsigned char f, char g, 
148                 unsigned char *h)
149 /* This declaration is as defined in the spec file.  It is deliberately not
150  * specified in terms of &lt;3rd party&gt; types since we are messing about here
151  * between two operating systems (making it look like a Windows thing when
152  * actually it is a Linux thing).  In this way the compiler will point out any
153  * inconsistencies.
154  * For example the fourth argument needs care
155  */
156 {
157     unsigned short d1;
158     signed short ret;
159
160     d1 = (unsigned short) *d;
161     ret = &lt;3rd party linux function&gt; (a, b, c, &amp;d1, e, g, h);
162     *d = d1;
163
164     return ret;
165 }
166
167 /* End of file */
168         </programlisting>
169       </para>
170       <para>
171         For a more extensive case we can use the ODBC example.  This is
172         implemented as a header file 
173         (<filename class="HeaderFile">proxyodbc.h</filename>) and the actual
174         C source file (<filename>proxyodbc.c</filename>).  Although the file
175         is quite long it is extremely simple in structure.
176       </para>
177       <para>
178         The MAIN_OdbcInit function is the function that was named in the
179         <link linkend="bindlls-spec">spec file</link> as the init function.
180         On the process attach event the function dynamically links to the
181         desired Linux ODBC library (since there are several available) and
182         builds a list of function pointers.  It unlinks on the process
183         detach event.
184       </para>
185       <para>
186         Then each of the functions simply calls the appropriate Linux function
187         through the function pointer that was set up during initialisation.
188       </para>
189     </sect1>
190
191     <sect1 id="bindlls-building">
192       <title id="binary-dlls-building.title">Building</title>
193       <para>
194         So how dow we actually build the Wine builtin Dll?  The easiest way is
195         to get Winemaker to do the hard work for us.  For the simple example we
196         have two source files (the wrapper and the spec file).  We also have
197         the 3rd party header and library files of course.
198       </para>
199       <para>
200         Put the two source files in a suitable directory and then use 
201         winemaker to create the build framework, including configure script,
202         makefile etc.  You will want to use the following options of 
203         winemaker:
204         <itemizedlist>
205           <listitem>
206             <para>
207               --nosource-fix and --nogenerate-specs (requires winemaker version
208               0.5.8 or later) to ensure that the two files are not modified.
209               (If using an older version of winemaker then make the two files
210               readonly and ignore the complaints about being unable to modify
211               them).
212             </para>
213           </listitem>
214           <listitem>
215             <para>
216               --dll --single-target MyWin --nomfc to specify the target
217             </para>
218           </listitem>
219           <listitem>
220             <para>
221               -DMightNeedSomething -I3rd_party_include -L3rd_party_lib -lxxxx
222               -lyyyy where these are the locations of the header files etc.
223             </para>
224           </listitem>
225         </itemizedlist>
226       </para>
227       <para>
228         After running winemaker I like to edit the Makefile.in to add the line
229         CEXTRA = -Wall just before the DEFINES =.
230       </para>
231       <para>
232         Then simply run the configure and make as normal (described elsewhere).
233       </para>
234     </sect1>
235   </chapter>
236
237 <!-- Keep this comment at the end of the file
238 Local variables:
239 mode: sgml
240 sgml-parent-document:("wine-doc.sgml" "book" "chapter" "")
241 End:
242 -->