Reactos
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
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <ctype.h>
27
28#include "widl.h"
29#include "utils.h"
30#include "parser.h"
31#include "header.h"
32#include "typegen.h"
33#include "typelib.h"
34
35static int indent;
36
37static const char *format_uuid( const struct uuid *uuid )
38{
39 static char buffer[40];
40 snprintf( buffer, sizeof(buffer),
41 "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
42 uuid->Data1, uuid->Data2, uuid->Data3,
43 uuid->Data4[0], uuid->Data4[1], uuid->Data4[2], uuid->Data4[3],
44 uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], uuid->Data4[7] );
45 return buffer;
46}
47
48static const char *get_coclass_threading( const type_t *class )
49{
50 static const char * const models[] =
51 {
52 NULL,
53 "Apartment", /* THREADING_APARTMENT */
54 "Neutral", /* THREADING_NEUTRAL */
55 "Single", /* THREADING_SINGLE */
56 "Free", /* THREADING_FREE */
57 "Both", /* THREADING_BOTH */
58 };
59 return models[get_attrv( class->attrs, ATTR_THREADING )];
60}
61
62static const type_t *find_ps_factory( const statement_list_t *stmts )
63{
64 const statement_t *stmt;
65
66 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
67 {
68 if (stmt->type == STMT_TYPE)
69 {
70 const type_t *type = stmt->u.type;
71 if (type_get_type(type) == TYPE_COCLASS && !strcmp( type->name, "PSFactoryBuffer" ))
72 return type;
73 }
74 }
75 return NULL;
76}
77
78static void write_interface( const type_t *iface, const type_t *ps_factory )
79{
80 const struct uuid *uuid = get_attrp( iface->attrs, ATTR_UUID );
81 const struct uuid *ps_uuid = get_attrp( ps_factory->attrs, ATTR_UUID );
82
83 if (!uuid) return;
84 if (!is_object( iface )) return;
85 if (!type_iface_get_inherit(iface)) /* special case for IUnknown */
86 {
87 put_str( indent, "'%s' = s '%s'\n", format_uuid( uuid ), iface->name );
88 return;
89 }
90 if (is_local( iface->attrs )) return;
91 put_str( indent, "'%s' = s '%s'\n", format_uuid( uuid ), iface->name );
92 put_str( indent, "{\n" );
93 indent++;
94 put_str( indent, "NumMethods = s %u\n", count_methods( iface ));
95 put_str( indent, "ProxyStubClsid32 = s '%s'\n", format_uuid( ps_uuid ));
96 indent--;
97 put_str( indent, "}\n" );
98}
99
100static void write_interfaces( const statement_list_t *stmts, const type_t *ps_factory )
101{
102 const statement_t *stmt;
103
104 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
105 {
106 if (stmt->type == STMT_TYPE && type_get_type( stmt->u.type ) == TYPE_INTERFACE)
107 write_interface( stmt->u.type, ps_factory );
108 }
109}
110
111static void write_typelib_interface( const type_t *iface, const typelib_t *typelib )
112{
113 const struct uuid *typelib_uuid = get_attrp( typelib->attrs, ATTR_UUID );
114 const struct uuid *uuid = get_attrp( iface->attrs, ATTR_UUID );
115 unsigned int version = get_attrv( typelib->attrs, ATTR_VERSION );
116
117 if (!uuid) return;
118 if (!is_object( iface )) return;
119 put_str( indent, "'%s' = s '%s'\n", format_uuid( uuid ), iface->name );
120 put_str( indent, "{\n" );
121 indent++;
122 put_str( indent, "ProxyStubClsid = s '{00020424-0000-0000-C000-000000000046}'\n" );
123 put_str( indent, "ProxyStubClsid32 = s '{00020424-0000-0000-C000-000000000046}'\n" );
124 if (version)
125 put_str( indent, "TypeLib = s '%s' { val Version = s '%u.%u' }\n",
126 format_uuid( typelib_uuid ), MAJORVERSION(version), MINORVERSION(version) );
127 else
128 put_str( indent, "TypeLib = s '%s'", format_uuid( typelib_uuid ));
129 indent--;
130 put_str( indent, "}\n" );
131}
132
133static void write_typelib_interfaces( const typelib_t *typelib )
134{
135 unsigned int i;
136
137 for (i = 0; i < typelib->reg_iface_count; ++i)
138 write_typelib_interface( typelib->reg_ifaces[i], typelib );
139}
140
141static int write_coclass( const type_t *class, const typelib_t *typelib )
142{
143 const struct uuid *uuid = get_attrp( class->attrs, ATTR_UUID );
144 const char *descr = get_attrp( class->attrs, ATTR_HELPSTRING );
145 const char *progid = get_attrp( class->attrs, ATTR_PROGID );
146 const char *vi_progid = get_attrp( class->attrs, ATTR_VIPROGID );
147 const char *threading = get_coclass_threading( class );
148 unsigned int version = get_attrv( class->attrs, ATTR_VERSION );
149
150 if (!uuid) return 0;
151 if (typelib && !threading && !progid) return 0;
152 if (!descr) descr = class->name;
153
154 put_str( indent, "'%s' = s '%s'\n", format_uuid( uuid ), descr );
155 put_str( indent++, "{\n" );
156 if (threading) put_str( indent, "InprocServer32 = s '%%MODULE%%' { val ThreadingModel = s '%s' }\n",
157 threading );
158 if (progid) put_str( indent, "ProgId = s '%s'\n", progid );
159 if (typelib)
160 {
161 const struct uuid *typelib_uuid = get_attrp( typelib->attrs, ATTR_UUID );
162 put_str( indent, "TypeLib = s '%s'\n", format_uuid( typelib_uuid ));
163 if (!version) version = get_attrv( typelib->attrs, ATTR_VERSION );
164 }
165 if (version) put_str( indent, "Version = s '%u.%u'\n", MAJORVERSION(version), MINORVERSION(version) );
166 if (vi_progid) put_str( indent, "VersionIndependentProgId = s '%s'\n", vi_progid );
167 put_str( --indent, "}\n" );
168 return 1;
169}
170
171static void write_coclasses( const statement_list_t *stmts, const typelib_t *typelib )
172{
173 const statement_t *stmt;
174
175 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
176 {
177 if (stmt->type == STMT_TYPE)
178 {
179 const type_t *type = stmt->u.type;
180 if (type_get_type(type) == TYPE_COCLASS) write_coclass( type, typelib );
181 }
182 }
183}
184
185static void write_runtimeclasses_registry( const statement_list_t *stmts )
186{
187 const statement_t *stmt;
188 const type_t *type;
189
190 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
191 {
192 if (stmt->type != STMT_TYPE) continue;
193 if (type_get_type((type = stmt->u.type)) != TYPE_RUNTIMECLASS) continue;
194 if (!get_attrp(type->attrs, ATTR_ACTIVATABLE) && !get_attrp(type->attrs, ATTR_STATIC)) continue;
195 put_str( indent, "ForceRemove %s\n", format_namespace( type->namespace, "", ".", type->name, NULL ) );
196 put_str( indent++, "{\n" );
197 put_str( indent, "val 'DllPath' = s '%%MODULE%%'\n" );
198 put_str( --indent, "}\n" );
199 }
200}
201
202static int write_progid( const type_t *class )
203{
204 const struct uuid *uuid = get_attrp( class->attrs, ATTR_UUID );
205 const char *descr = get_attrp( class->attrs, ATTR_HELPSTRING );
206 const char *progid = get_attrp( class->attrs, ATTR_PROGID );
207 const char *vi_progid = get_attrp( class->attrs, ATTR_VIPROGID );
208
209 if (!uuid) return 0;
210 if (!descr) descr = class->name;
211
212 if (progid)
213 {
214 put_str( indent, "'%s' = s '%s'\n", progid, descr );
215 put_str( indent++, "{\n" );
216 put_str( indent, "CLSID = s '%s'\n", format_uuid( uuid ) );
217 put_str( --indent, "}\n" );
218 }
219 if (vi_progid)
220 {
221 put_str( indent, "'%s' = s '%s'\n", vi_progid, descr );
222 put_str( indent++, "{\n" );
223 put_str( indent, "CLSID = s '%s'\n", format_uuid( uuid ) );
224 if (progid && strcmp( progid, vi_progid )) put_str( indent, "CurVer = s '%s'\n", progid );
225 put_str( --indent, "}\n" );
226 }
227 return 1;
228}
229
230static void write_progids( const statement_list_t *stmts )
231{
232 const statement_t *stmt;
233
234 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
235 {
236 if (stmt->type == STMT_TYPE)
237 {
238 const type_t *type = stmt->u.type;
239 if (type_get_type(type) == TYPE_COCLASS) write_progid( type );
240 }
241 }
242}
243
244void write_regscript( const statement_list_t *stmts )
245{
246 const type_t *ps_factory;
247
248 if (!do_regscript) return;
249 if (do_everything && !need_proxy_file( stmts )) return;
250
251 init_output_buffer();
252
253 if (winrt_mode)
254 {
255 put_str( indent, "HKLM\n" );
256 put_str( indent++, "{\n" );
257 put_str( indent, "NoRemove Software\n" );
258 put_str( indent++, "{\n" );
259 put_str( indent, "NoRemove Microsoft\n" );
260 put_str( indent++, "{\n" );
261 put_str( indent, "NoRemove WindowsRuntime\n" );
262 put_str( indent++, "{\n" );
263 put_str( indent, "NoRemove ActivatableClassId\n" );
264 put_str( indent++, "{\n" );
265 write_runtimeclasses_registry( stmts );
266 put_str( --indent, "}\n" );
267 put_str( --indent, "}\n" );
268 put_str( --indent, "}\n" );
269 put_str( --indent, "}\n" );
270 put_str( --indent, "}\n" );
271 }
272 else
273 {
274 put_str( indent, "HKCR\n" );
275 put_str( indent++, "{\n" );
276
277 ps_factory = find_ps_factory( stmts );
278 if (ps_factory)
279 {
280 put_str( indent, "NoRemove Interface\n" );
281 put_str( indent++, "{\n" );
282 write_interfaces( stmts, ps_factory );
283 put_str( --indent, "}\n" );
284 }
285
286 put_str( indent, "NoRemove CLSID\n" );
287 put_str( indent++, "{\n" );
288 write_coclasses( stmts, NULL );
289 put_str( --indent, "}\n" );
290
291 write_progids( stmts );
292 put_str( --indent, "}\n" );
293 }
294
295 if (strendswith( regscript_name, ".res" )) /* create a binary resource file */
296 {
297 add_output_to_resources( "WINE_REGISTRY", regscript_token );
298 flush_output_resources( regscript_name );
299 }
300 else
301 {
302 FILE *f = fopen( regscript_name, "w" );
303 if (!f) error( "Could not open %s for output\n", regscript_name );
304 if (fwrite( output_buffer, 1, output_buffer_pos, f ) != output_buffer_pos)
305 error( "Failed to write to %s\n", regscript_name );
306 if (fclose( f ))
307 error( "Failed to write to %s\n", regscript_name );
308 }
309}
310
311void write_typelib_regscript( const statement_list_t *stmts )
312{
313 const statement_t *stmt;
314 unsigned int count = 0;
315
316 if (!do_typelib) return;
317 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
318 {
319 if (stmt->type != STMT_LIBRARY) continue;
320 if (count && !strendswith( typelib_name, ".res" ))
321 error( "Cannot store multiple typelibs into %s\n", typelib_name );
322 else
323 {
324 if (old_typelib)
325 create_sltg_typelib( stmt->u.lib );
326 else
327 create_msft_typelib( stmt->u.lib );
328 }
329 count++;
330 }
331 if (count && strendswith( typelib_name, ".res" )) flush_output_resources( typelib_name );
332}
333
334void output_typelib_regscript( const typelib_t *typelib )
335{
336 const struct uuid *typelib_uuid = get_attrp( typelib->attrs, ATTR_UUID );
337 const char *descr = get_attrp( typelib->attrs, ATTR_HELPSTRING );
338 const expr_t *lcid_expr = get_attrp( typelib->attrs, ATTR_LIBLCID );
339 unsigned int version = get_attrv( typelib->attrs, ATTR_VERSION );
340 unsigned int flags = 0;
341 char id_part[12] = "";
342 char *resname = typelib_name;
343 expr_t *expr;
344
345 if (is_attr( typelib->attrs, ATTR_RESTRICTED )) flags |= 1; /* LIBFLAG_FRESTRICTED */
346 if (is_attr( typelib->attrs, ATTR_CONTROL )) flags |= 2; /* LIBFLAG_FCONTROL */
347 if (is_attr( typelib->attrs, ATTR_HIDDEN )) flags |= 4; /* LIBFLAG_FHIDDEN */
348
349 put_str( indent, "HKCR\n" );
350 put_str( indent++, "{\n" );
351
352 put_str( indent, "NoRemove Typelib\n" );
353 put_str( indent++, "{\n" );
354 put_str( indent, "NoRemove '%s'\n", format_uuid( typelib_uuid ));
355 put_str( indent++, "{\n" );
356 put_str( indent, "'%u.%u' = s '%s'\n",
357 MAJORVERSION(version), MINORVERSION(version), descr ? descr : typelib->name );
358 put_str( indent++, "{\n" );
359 expr = get_attrp( typelib->attrs, ATTR_ID );
360 if (expr)
361 {
362 snprintf(id_part, sizeof(id_part), "\\%d", expr->cval);
363 resname = strmake("%s\\%d", typelib_name, expr->cval);
364 }
365 put_str( indent, "'%x' { %s = s '%%MODULE%%%s' }\n",
366 lcid_expr ? lcid_expr->cval : 0, pointer_size == 8 ? "win64" : "win32", id_part );
367 put_str( indent, "FLAGS = s '%u'\n", flags );
368 put_str( --indent, "}\n" );
369 put_str( --indent, "}\n" );
370 put_str( --indent, "}\n" );
371
372 put_str( indent, "NoRemove Interface\n" );
373 put_str( indent++, "{\n" );
374 write_typelib_interfaces( typelib );
375 put_str( --indent, "}\n" );
376
377 put_str( indent, "NoRemove CLSID\n" );
378 put_str( indent++, "{\n" );
379 write_coclasses( typelib->stmts, typelib );
380 put_str( --indent, "}\n" );
381
382 write_progids( typelib->stmts );
383 put_str( --indent, "}\n" );
384
385 add_output_to_resources( "WINE_REGISTRY", resname );
386}