widl: Don't create the CurVer key if the ProgId is already version-independent.
[wine/multimedia.git] / tools / widl / register.c
blobf7092144a0b7ca4b11e8b02451c060c4ef14b491
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 int write_interface( const type_t *iface )
66 const UUID *uuid = get_attrp( iface->attrs, ATTR_UUID );
68 if (!uuid) return 0;
69 if (!is_object( iface )) return 0;
70 if (!type_iface_get_inherit(iface)) /* special case for IUnknown */
72 put_str( indent, "ForceRemove '%s' = s '%s'\n", format_uuid( uuid ), iface->name );
73 return 0;
75 if (is_local( iface->attrs )) return 0;
76 put_str( indent, "ForceRemove '%s' = s '%s'\n", format_uuid( uuid ), iface->name );
77 put_str( indent, "{\n" );
78 indent++;
79 put_str( indent, "NumMethods = s %u\n", count_methods( iface ));
80 put_str( indent, "ProxyStubClsid32 = s '%%CLSID_PSFactoryBuffer%%'\n" );
81 indent--;
82 put_str( indent, "}\n" );
83 return 1;
86 static int write_interfaces( const statement_list_t *stmts )
88 const statement_t *stmt;
89 int count = 0;
91 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
93 if (stmt->type == STMT_TYPE && type_get_type( stmt->u.type ) == TYPE_INTERFACE)
94 count += write_interface( stmt->u.type );
96 return count;
99 static int write_coclass( const type_t *class, const typelib_t *typelib )
101 const UUID *uuid = get_attrp( class->attrs, ATTR_UUID );
102 const char *descr = get_attrp( class->attrs, ATTR_HELPSTRING );
103 const char *progid = get_attrp( class->attrs, ATTR_PROGID );
104 const char *vi_progid = get_attrp( class->attrs, ATTR_VIPROGID );
105 const char *threading = get_coclass_threading( class );
107 if (!uuid) return 0;
108 if (typelib && !threading) return 0;
109 if (!descr) descr = class->name;
111 put_str( indent, "ForceRemove '%s' = s '%s'\n", format_uuid( uuid ), descr );
112 put_str( indent++, "{\n" );
113 if (threading) put_str( indent, "InprocServer32 = s '%%MODULE%%' { val ThreadingModel = s '%s' }\n",
114 threading );
115 if (progid) put_str( indent, "ProgId = s '%s'\n", progid );
116 if (typelib)
118 const UUID *typelib_uuid = get_attrp( typelib->attrs, ATTR_UUID );
119 const unsigned int version = get_attrv( typelib->attrs, ATTR_VERSION );
120 put_str( indent, "TypeLib = s '%s'\n", format_uuid( typelib_uuid ));
121 put_str( indent, "Version = s '%u.%u'\n", MAJORVERSION(version), MINORVERSION(version) );
123 if (vi_progid) put_str( indent, "VersionIndependentProgId = s '%s'\n", vi_progid );
124 put_str( --indent, "}\n" );
125 return 1;
128 static void write_coclasses( const statement_list_t *stmts, const typelib_t *typelib )
130 const statement_t *stmt;
132 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
134 if (stmt->type == STMT_TYPE)
136 const type_t *type = stmt->u.type;
137 if (type_get_type(type) == TYPE_COCLASS) write_coclass( type, typelib );
139 else if (stmt->type == STMT_LIBRARY)
141 const typelib_t *lib = stmt->u.lib;
142 write_coclasses( lib->stmts, lib );
147 static int write_progid( const type_t *class )
149 const UUID *uuid = get_attrp( class->attrs, ATTR_UUID );
150 const char *descr = get_attrp( class->attrs, ATTR_HELPSTRING );
151 const char *progid = get_attrp( class->attrs, ATTR_PROGID );
152 const char *vi_progid = get_attrp( class->attrs, ATTR_VIPROGID );
154 if (!uuid) return 0;
155 if (!descr) descr = class->name;
157 if (progid)
159 put_str( indent, "'%s' = s '%s'\n", progid, descr );
160 put_str( indent++, "{\n" );
161 put_str( indent, "CLSID = s '%s'\n", format_uuid( uuid ) );
162 put_str( --indent, "}\n" );
164 if (vi_progid)
166 put_str( indent, "'%s' = s '%s'\n", vi_progid, descr );
167 put_str( indent++, "{\n" );
168 put_str( indent, "CLSID = s '%s'\n", format_uuid( uuid ) );
169 if (progid && strcmp( progid, vi_progid )) put_str( indent, "CurVer = s '%s'\n", progid );
170 put_str( --indent, "}\n" );
172 return 1;
175 static void write_progids( const statement_list_t *stmts )
177 const statement_t *stmt;
179 if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
181 if (stmt->type == STMT_TYPE)
183 const type_t *type = stmt->u.type;
184 if (type_get_type(type) == TYPE_COCLASS) write_progid( type );
186 else if (stmt->type == STMT_LIBRARY)
188 write_progids( stmt->u.lib->stmts );
193 /* put a string into the resource file */
194 static inline void put_string( const char *str )
196 while (*str)
198 unsigned char ch = *str++;
199 put_word( toupper(ch) );
201 put_word( 0 );
204 void write_regscript( const statement_list_t *stmts )
206 int count;
208 if (!do_regscript) return;
209 if (do_everything && !need_proxy_file( stmts )) return;
211 init_output_buffer();
213 put_str( indent, "HKCR\n" );
214 put_str( indent++, "{\n" );
216 put_str( indent, "NoRemove Interface\n" );
217 put_str( indent++, "{\n" );
218 count = write_interfaces( stmts );
219 put_str( --indent, "}\n" );
221 put_str( indent, "NoRemove CLSID\n" );
222 put_str( indent++, "{\n" );
223 if (count)
225 put_str( indent, "ForceRemove '%%CLSID_PSFactoryBuffer%%' = s 'PSFactoryBuffer'\n" );
226 put_str( indent++, "{\n" );
227 put_str( indent, "InprocServer32 = s '%%MODULE%%' { val ThreadingModel = s 'Both' }\n" );
228 put_str( --indent, "}\n" );
230 write_coclasses( stmts, NULL );
231 put_str( --indent, "}\n" );
233 write_progids( stmts );
234 put_str( --indent, "}\n" );
236 if (strendswith( regscript_name, ".res" )) /* create a binary resource file */
238 unsigned char *data = output_buffer;
239 size_t data_size = output_buffer_pos;
240 size_t header_size = 5 * sizeof(unsigned int) + 2 * sizeof(unsigned short);
242 header_size += (strlen(regscript_token) + strlen("WINE_REGISTRY") + 2) * sizeof(unsigned short);
244 init_output_buffer();
246 put_dword( 0 ); /* ResSize */
247 put_dword( 32 ); /* HeaderSize */
248 put_word( 0xffff ); /* ResType */
249 put_word( 0x0000 );
250 put_word( 0xffff ); /* ResName */
251 put_word( 0x0000 );
252 put_dword( 0 ); /* DataVersion */
253 put_word( 0 ); /* Memory options */
254 put_word( 0 ); /* Language */
255 put_dword( 0 ); /* Version */
256 put_dword( 0 ); /* Characteristics */
258 put_dword( data_size ); /* ResSize */
259 put_dword( (header_size + 3) & ~3 ); /* HeaderSize */
260 put_string( "WINE_REGISTRY" ); /* ResType */
261 put_string( regscript_token ); /* ResName */
262 align_output( 4 );
263 put_dword( 0 ); /* DataVersion */
264 put_word( 0 ); /* Memory options */
265 put_word( 0 ); /* Language */
266 put_dword( 0 ); /* Version */
267 put_dword( 0 ); /* Characteristics */
269 put_data( data, data_size );
270 free( data );
271 align_output( 4 );
272 flush_output_buffer( regscript_name );
274 else
276 FILE *f = fopen( regscript_name, "w" );
277 if (!f) error( "Could not open %s for output\n", regscript_name );
278 if (fwrite( output_buffer, output_buffer_pos, 1, f ) != output_buffer_pos)
279 error( "Failed to write to %s\n", regscript_name );
280 if (fclose( f ))
281 error( "Failed to write to %s\n", regscript_name );