oledb32: Implement DataConvert DBTYPE_R8->VARIANT.
[wine] / tools / widl / register.c
1 /*
2  * Generation of dll registration scripts
3  *
4  * Copyright 2010 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include <string.h>
30 #include <ctype.h>
31
32 #include "widl.h"
33 #include "utils.h"
34 #include "parser.h"
35 #include "header.h"
36 #include "typegen.h"
37
38 static int indent;
39
40 static const char *format_uuid( const UUID *uuid )
41 {
42     static char buffer[40];
43     sprintf( buffer, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
44              uuid->Data1, uuid->Data2, uuid->Data3,
45              uuid->Data4[0], uuid->Data4[1], uuid->Data4[2], uuid->Data4[3],
46              uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], uuid->Data4[7] );
47     return buffer;
48 }
49
50 static const char *get_coclass_threading( const type_t *class )
51 {
52     static const char * const models[] =
53     {
54         NULL,
55         "Apartment", /* THREADING_APARTMENT */
56         "Neutral",   /* THREADING_NEUTRAL */
57         "Single",    /* THREADING_SINGLE */
58         "Free",      /* THREADING_FREE */
59         "Both",      /* THREADING_BOTH */
60     };
61     return models[get_attrv( class->attrs, ATTR_THREADING )];
62 }
63
64 static const type_t *find_ps_factory( const statement_list_t *stmts )
65 {
66     const statement_t *stmt;
67
68     if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
69     {
70         if (stmt->type == STMT_TYPE)
71         {
72             const type_t *type = stmt->u.type;
73             if (type_get_type(type) == TYPE_COCLASS && !strcmp( type->name, "PSFactoryBuffer" ))
74                 return type;
75         }
76     }
77     return NULL;
78 }
79
80 static void write_interface( const type_t *iface, const type_t *ps_factory )
81 {
82     const UUID *uuid = get_attrp( iface->attrs, ATTR_UUID );
83     const UUID *ps_uuid = get_attrp( ps_factory->attrs, ATTR_UUID );
84
85     if (!uuid) return;
86     if (!is_object( iface )) return;
87     if (!type_iface_get_inherit(iface)) /* special case for IUnknown */
88     {
89         put_str( indent, "'%s' = s '%s'\n", format_uuid( uuid ), iface->name );
90         return;
91     }
92     if (is_local( iface->attrs )) return;
93     put_str( indent, "'%s' = s '%s'\n", format_uuid( uuid ), iface->name );
94     put_str( indent, "{\n" );
95     indent++;
96     put_str( indent, "NumMethods = s %u\n", count_methods( iface ));
97     put_str( indent, "ProxyStubClsid32 = s '%s'\n", format_uuid( ps_uuid ));
98     indent--;
99     put_str( indent, "}\n" );
100 }
101
102 static void write_interfaces( const statement_list_t *stmts, const type_t *ps_factory )
103 {
104     const statement_t *stmt;
105
106     if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
107     {
108         if (stmt->type == STMT_TYPE && type_get_type( stmt->u.type ) == TYPE_INTERFACE)
109             write_interface( stmt->u.type, ps_factory );
110     }
111 }
112
113 static void write_typelib_interface( const type_t *iface, const typelib_t *typelib )
114 {
115     const UUID *typelib_uuid = get_attrp( typelib->attrs, ATTR_UUID );
116     const UUID *uuid = get_attrp( iface->attrs, ATTR_UUID );
117     unsigned int version = get_attrv( typelib->attrs, ATTR_VERSION );
118
119     if (!uuid) return;
120     if (!is_object( iface )) return;
121     if (!is_attr( iface->attrs, ATTR_OLEAUTOMATION ) && !is_attr( iface->attrs, ATTR_DISPINTERFACE ))
122         return;
123     put_str( indent, "'%s' = s '%s'\n", format_uuid( uuid ), iface->name );
124     put_str( indent, "{\n" );
125     indent++;
126     put_str( indent, "ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}'\n" );
127     put_str( indent, "ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}'\n" );
128     if (version)
129         put_str( indent, "TypeLib = s '%s' { val Version = s '%u.%u' }\n",
130                  format_uuid( typelib_uuid ), MAJORVERSION(version), MINORVERSION(version) );
131     else
132         put_str( indent, "TypeLib = s '%s'", format_uuid( typelib_uuid ));
133     indent--;
134     put_str( indent, "}\n" );
135 }
136
137 static void write_typelib_interfaces( const typelib_t *typelib )
138 {
139     const statement_t *stmt;
140
141     if (typelib->stmts) LIST_FOR_EACH_ENTRY( stmt, typelib->stmts, const statement_t, entry )
142     {
143         if (stmt->type == STMT_TYPE && type_get_type( stmt->u.type ) == TYPE_INTERFACE)
144             write_typelib_interface( stmt->u.type, typelib );
145     }
146 }
147
148 static int write_coclass( const type_t *class, const typelib_t *typelib )
149 {
150     const UUID *uuid = get_attrp( class->attrs, ATTR_UUID );
151     const char *descr = get_attrp( class->attrs, ATTR_HELPSTRING );
152     const char *progid = get_attrp( class->attrs, ATTR_PROGID );
153     const char *vi_progid = get_attrp( class->attrs, ATTR_VIPROGID );
154     const char *threading = get_coclass_threading( class );
155     unsigned int version = get_attrv( class->attrs, ATTR_VERSION );
156
157     if (!uuid) return 0;
158     if (typelib && !threading && !progid) return 0;
159     if (!descr) descr = class->name;
160
161     put_str( indent, "'%s' = s '%s'\n", format_uuid( uuid ), descr );
162     put_str( indent++, "{\n" );
163     if (threading) put_str( indent, "InprocServer32 = s '%%MODULE%%' { val ThreadingModel = s '%s' }\n",
164                             threading );
165     if (progid) put_str( indent, "ProgId = s '%s'\n", progid );
166     if (typelib)
167     {
168         const UUID *typelib_uuid = get_attrp( typelib->attrs, ATTR_UUID );
169         put_str( indent, "TypeLib = s '%s'\n", format_uuid( typelib_uuid ));
170         if (!version) version = get_attrv( typelib->attrs, ATTR_VERSION );
171     }
172     if (version) put_str( indent, "Version = s '%u.%u'\n", MAJORVERSION(version), MINORVERSION(version) );
173     if (vi_progid) put_str( indent, "VersionIndependentProgId = s '%s'\n", vi_progid );
174     put_str( --indent, "}\n" );
175     return 1;
176 }
177
178 static void write_coclasses( const statement_list_t *stmts, const typelib_t *typelib )
179 {
180     const statement_t *stmt;
181
182     if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
183     {
184         if (stmt->type == STMT_TYPE)
185         {
186             const type_t *type = stmt->u.type;
187             if (type_get_type(type) == TYPE_COCLASS) write_coclass( type, typelib );
188         }
189     }
190 }
191
192 static int write_progid( const type_t *class )
193 {
194     const UUID *uuid = get_attrp( class->attrs, ATTR_UUID );
195     const char *descr = get_attrp( class->attrs, ATTR_HELPSTRING );
196     const char *progid = get_attrp( class->attrs, ATTR_PROGID );
197     const char *vi_progid = get_attrp( class->attrs, ATTR_VIPROGID );
198
199     if (!uuid) return 0;
200     if (!descr) descr = class->name;
201
202     if (progid)
203     {
204         put_str( indent, "'%s' = s '%s'\n", progid, descr );
205         put_str( indent++, "{\n" );
206         put_str( indent, "CLSID = s '%s'\n", format_uuid( uuid ) );
207         put_str( --indent, "}\n" );
208     }
209     if (vi_progid)
210     {
211         put_str( indent, "'%s' = s '%s'\n", vi_progid, descr );
212         put_str( indent++, "{\n" );
213         put_str( indent, "CLSID = s '%s'\n", format_uuid( uuid ) );
214         if (progid && strcmp( progid, vi_progid )) put_str( indent, "CurVer = s '%s'\n", progid );
215         put_str( --indent, "}\n" );
216     }
217     return 1;
218 }
219
220 static void write_progids( const statement_list_t *stmts )
221 {
222     const statement_t *stmt;
223
224     if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
225     {
226         if (stmt->type == STMT_TYPE)
227         {
228             const type_t *type = stmt->u.type;
229             if (type_get_type(type) == TYPE_COCLASS) write_progid( type );
230         }
231     }
232 }
233
234 void write_regscript( const statement_list_t *stmts )
235 {
236     const type_t *ps_factory;
237
238     if (!do_regscript) return;
239     if (do_everything && !need_proxy_file( stmts )) return;
240
241     init_output_buffer();
242
243     put_str( indent, "HKCR\n" );
244     put_str( indent++, "{\n" );
245
246     put_str( indent, "NoRemove Interface\n" );
247     put_str( indent++, "{\n" );
248     ps_factory = find_ps_factory( stmts );
249     if (ps_factory) write_interfaces( stmts, ps_factory );
250     put_str( --indent, "}\n" );
251
252     put_str( indent, "NoRemove CLSID\n" );
253     put_str( indent++, "{\n" );
254     write_coclasses( stmts, NULL );
255     put_str( --indent, "}\n" );
256
257     write_progids( stmts );
258     put_str( --indent, "}\n" );
259
260     if (strendswith( regscript_name, ".res" ))  /* create a binary resource file */
261     {
262         add_output_to_resources( "WINE_REGISTRY", regscript_token );
263         flush_output_resources( regscript_name );
264     }
265     else
266     {
267         FILE *f = fopen( regscript_name, "w" );
268         if (!f) error( "Could not open %s for output\n", regscript_name );
269         if (fwrite( output_buffer, 1, output_buffer_pos, f ) != output_buffer_pos)
270             error( "Failed to write to %s\n", regscript_name );
271         if (fclose( f ))
272             error( "Failed to write to %s\n", regscript_name );
273     }
274 }
275
276 void output_typelib_regscript( const typelib_t *typelib )
277 {
278     const UUID *typelib_uuid = get_attrp( typelib->attrs, ATTR_UUID );
279     const char *descr = get_attrp( typelib->attrs, ATTR_HELPSTRING );
280     const expr_t *lcid_expr = get_attrp( typelib->attrs, ATTR_LIBLCID );
281     unsigned int version = get_attrv( typelib->attrs, ATTR_VERSION );
282     unsigned int flags = 0;
283
284     if (is_attr( typelib->attrs, ATTR_RESTRICTED )) flags |= 1; /* LIBFLAG_FRESTRICTED */
285     if (is_attr( typelib->attrs, ATTR_CONTROL )) flags |= 2; /* LIBFLAG_FCONTROL */
286     if (is_attr( typelib->attrs, ATTR_HIDDEN )) flags |= 4; /* LIBFLAG_FHIDDEN */
287
288     put_str( indent, "HKCR\n" );
289     put_str( indent++, "{\n" );
290
291     put_str( indent, "NoRemove Typelib\n" );
292     put_str( indent++, "{\n" );
293     put_str( indent, "NoRemove '%s'\n", format_uuid( typelib_uuid ));
294     put_str( indent++, "{\n" );
295     put_str( indent, "'%u.%u' = s '%s'\n",
296              MAJORVERSION(version), MINORVERSION(version), descr ? descr : typelib->name );
297     put_str( indent++, "{\n" );
298     put_str( indent, "'%x' { %s = s '%%MODULE%%' }\n",
299              lcid_expr ? lcid_expr->cval : 0, typelib_kind == SYS_WIN64 ? "win64" : "win32" );
300     put_str( indent, "FLAGS = s '%u'\n", flags );
301     put_str( --indent, "}\n" );
302     put_str( --indent, "}\n" );
303     put_str( --indent, "}\n" );
304
305     put_str( indent, "NoRemove Interface\n" );
306     put_str( indent++, "{\n" );
307     write_typelib_interfaces( typelib );
308     put_str( --indent, "}\n" );
309
310     put_str( indent, "NoRemove CLSID\n" );
311     put_str( indent++, "{\n" );
312     write_coclasses( typelib->stmts, typelib );
313     put_str( --indent, "}\n" );
314
315     write_progids( typelib->stmts );
316     put_str( --indent, "}\n" );
317
318     add_output_to_resources( "WINE_REGISTRY", typelib_name );
319 }