kernel32: Reset LastError if GetModuleFileName() succeeds.
[wine/multimedia.git] / tools / widl / register.c
blobc75a6acd88ec7b06773ca8eb75eeaeadd5559d97
1 /*
2 * Generation of dll registration scripts
4 * Copyright 2010 Alexandre Julliard
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
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>
32 #include "widl.h"
33 #include "utils.h"
34 #include "parser.h"
35 #include "header.h"
36 #include "typegen.h"
38 static int indent;
40 static const char *format_uuid( const UUID *uuid )
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;
50 static const char *get_coclass_threading( const type_t *class )
52 static const char * const models[] =
54 NULL,
55 "Apartment", /* THREADING_APARTMENT */
56 "Neutral", /* THREADING_NEUTRAL */
57 "Single", /* THREADING_SINGLE */
58 "Free", /* THREADING_FREE */
59 "Both", /* THREADING_BOTH */
61 return models[get_attrv( class->attrs, ATTR_THREADING )];
64 static const type_t *find_ps_factory( const statement_list_t *stmts )
66 const statement_t *stmt;
68 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
70 if (stmt->type == STMT_TYPE)
72 const type_t *type = stmt->u.type;
73 if (type_get_type(type) == TYPE_COCLASS && !strcmp( type->name, "PSFactoryBuffer" ))
74 return type;
77 return NULL;
80 static void write_interface( const type_t *iface, const type_t *ps_factory )
82 const UUID *uuid = get_attrp( iface->attrs, ATTR_UUID );
83 const UUID *ps_uuid = get_attrp( ps_factory->attrs, ATTR_UUID );
85 if (!uuid) return;
86 if (!is_object( iface )) return;
87 if (!type_iface_get_inherit(iface)) /* special case for IUnknown */
89 put_str( indent, "'%s' = s '%s'\n", format_uuid( uuid ), iface->name );
90 return;
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" );
102 static void write_interfaces( const statement_list_t *stmts, const type_t *ps_factory )
104 const statement_t *stmt;
106 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
108 if (stmt->type == STMT_TYPE && type_get_type( stmt->u.type ) == TYPE_INTERFACE)
109 write_interface( stmt->u.type, ps_factory );
113 static void write_typelib_interface( const type_t *iface, const typelib_t *typelib )
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 );
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" );
137 static void write_typelib_interfaces( const typelib_t *typelib )
139 const statement_t *stmt;
141 if (typelib->stmts) LIST_FOR_EACH_ENTRY( stmt, typelib->stmts, const statement_t, entry )
143 if (stmt->type == STMT_TYPE && type_get_type( stmt->u.type ) == TYPE_INTERFACE)
144 write_typelib_interface( stmt->u.type, typelib );
148 static int write_coclass( const type_t *class, const typelib_t *typelib )
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 );
157 if (!uuid) return 0;
158 if (typelib && !threading && !progid) return 0;
159 if (!descr) descr = class->name;
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)
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 );
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;
178 static void write_coclasses( const statement_list_t *stmts, const typelib_t *typelib )
180 const statement_t *stmt;
182 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
184 if (stmt->type == STMT_TYPE)
186 const type_t *type = stmt->u.type;
187 if (type_get_type(type) == TYPE_COCLASS) write_coclass( type, typelib );
192 static int write_progid( const type_t *class )
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 );
199 if (!uuid) return 0;
200 if (!descr) descr = class->name;
202 if (progid)
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" );
209 if (vi_progid)
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" );
217 return 1;
220 static void write_progids( const statement_list_t *stmts )
222 const statement_t *stmt;
224 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
226 if (stmt->type == STMT_TYPE)
228 const type_t *type = stmt->u.type;
229 if (type_get_type(type) == TYPE_COCLASS) write_progid( type );
234 void write_regscript( const statement_list_t *stmts )
236 const type_t *ps_factory;
238 if (!do_regscript) return;
239 if (do_everything && !need_proxy_file( stmts )) return;
241 init_output_buffer();
243 put_str( indent, "HKCR\n" );
244 put_str( indent++, "{\n" );
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" );
252 put_str( indent, "NoRemove CLSID\n" );
253 put_str( indent++, "{\n" );
254 write_coclasses( stmts, NULL );
255 put_str( --indent, "}\n" );
257 write_progids( stmts );
258 put_str( --indent, "}\n" );
260 if (strendswith( regscript_name, ".res" )) /* create a binary resource file */
262 add_output_to_resources( "WINE_REGISTRY", regscript_token );
263 flush_output_resources( regscript_name );
265 else
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, output_buffer_pos, 1, 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 );
276 void output_typelib_regscript( const typelib_t *typelib )
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;
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 */
288 put_str( indent, "HKCR\n" );
289 put_str( indent++, "{\n" );
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" );
305 put_str( indent, "NoRemove Interface\n" );
306 put_str( indent++, "{\n" );
307 write_typelib_interfaces( typelib );
308 put_str( --indent, "}\n" );
310 put_str( indent, "NoRemove CLSID\n" );
311 put_str( indent++, "{\n" );
312 write_coclasses( typelib->stmts, typelib );
313 put_str( --indent, "}\n" );
315 write_progids( typelib->stmts );
316 put_str( --indent, "}\n" );
318 add_output_to_resources( "WINE_REGISTRY", typelib_name );