setupapi: Make sure machine name is non-empty before failing.
[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 int 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 = ps_factory ? get_attrp( ps_factory->attrs, ATTR_UUID ) : NULL;
84
85     if (!uuid) return 0;
86     if (!is_object( iface )) return 0;
87     if (!type_iface_get_inherit(iface)) /* special case for IUnknown */
88     {
89         put_str( indent, "ForceRemove '%s' = s '%s'\n", format_uuid( uuid ), iface->name );
90         return 0;
91     }
92     if (is_local( iface->attrs )) return 0;
93     put_str( indent, "ForceRemove '%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",
98              ps_uuid ? format_uuid( ps_uuid ) : "%CLSID_PSFactoryBuffer%" );
99     indent--;
100     put_str( indent, "}\n" );
101     return 1;
102 }
103
104 static int write_interfaces( const statement_list_t *stmts, const type_t *ps_factory )
105 {
106     const statement_t *stmt;
107     int count = 0;
108
109     if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
110     {
111         if (stmt->type == STMT_TYPE && type_get_type( stmt->u.type ) == TYPE_INTERFACE)
112             count += write_interface( stmt->u.type, ps_factory );
113     }
114     return count;
115 }
116
117 static int write_coclass( const type_t *class, const typelib_t *typelib )
118 {
119     const UUID *uuid = get_attrp( class->attrs, ATTR_UUID );
120     const char *descr = get_attrp( class->attrs, ATTR_HELPSTRING );
121     const char *progid = get_attrp( class->attrs, ATTR_PROGID );
122     const char *vi_progid = get_attrp( class->attrs, ATTR_VIPROGID );
123     const char *threading = get_coclass_threading( class );
124     unsigned int version = get_attrv( class->attrs, ATTR_VERSION );
125
126     if (!uuid) return 0;
127     if (typelib && !threading) return 0;
128     if (!descr) descr = class->name;
129
130     put_str( indent, "ForceRemove '%s' = s '%s'\n", format_uuid( uuid ), descr );
131     put_str( indent++, "{\n" );
132     if (threading) put_str( indent, "InprocServer32 = s '%%MODULE%%' { val ThreadingModel = s '%s' }\n",
133                             threading );
134     if (progid) put_str( indent, "ProgId = s '%s'\n", progid );
135     if (typelib)
136     {
137         const UUID *typelib_uuid = get_attrp( typelib->attrs, ATTR_UUID );
138         put_str( indent, "TypeLib = s '%s'\n", format_uuid( typelib_uuid ));
139         if (!version) version = get_attrv( typelib->attrs, ATTR_VERSION );
140     }
141     if (version) put_str( indent, "Version = s '%u.%u'\n", MAJORVERSION(version), MINORVERSION(version) );
142     if (vi_progid) put_str( indent, "VersionIndependentProgId = s '%s'\n", vi_progid );
143     put_str( --indent, "}\n" );
144     return 1;
145 }
146
147 static void write_coclasses( const statement_list_t *stmts, const typelib_t *typelib )
148 {
149     const statement_t *stmt;
150
151     if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
152     {
153         if (stmt->type == STMT_TYPE)
154         {
155             const type_t *type = stmt->u.type;
156             if (type_get_type(type) == TYPE_COCLASS) write_coclass( type, typelib );
157         }
158         else if (stmt->type == STMT_LIBRARY)
159         {
160             const typelib_t *lib = stmt->u.lib;
161             write_coclasses( lib->stmts, lib );
162         }
163     }
164 }
165
166 static int write_progid( const type_t *class )
167 {
168     const UUID *uuid = get_attrp( class->attrs, ATTR_UUID );
169     const char *descr = get_attrp( class->attrs, ATTR_HELPSTRING );
170     const char *progid = get_attrp( class->attrs, ATTR_PROGID );
171     const char *vi_progid = get_attrp( class->attrs, ATTR_VIPROGID );
172
173     if (!uuid) return 0;
174     if (!descr) descr = class->name;
175
176     if (progid)
177     {
178         put_str( indent, "'%s' = s '%s'\n", progid, descr );
179         put_str( indent++, "{\n" );
180         put_str( indent, "CLSID = s '%s'\n", format_uuid( uuid ) );
181         put_str( --indent, "}\n" );
182     }
183     if (vi_progid)
184     {
185         put_str( indent, "'%s' = s '%s'\n", vi_progid, descr );
186         put_str( indent++, "{\n" );
187         put_str( indent, "CLSID = s '%s'\n", format_uuid( uuid ) );
188         if (progid && strcmp( progid, vi_progid )) put_str( indent, "CurVer = s '%s'\n", progid );
189         put_str( --indent, "}\n" );
190     }
191     return 1;
192 }
193
194 static void write_progids( const statement_list_t *stmts )
195 {
196     const statement_t *stmt;
197
198     if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
199     {
200         if (stmt->type == STMT_TYPE)
201         {
202             const type_t *type = stmt->u.type;
203             if (type_get_type(type) == TYPE_COCLASS) write_progid( type );
204         }
205         else if (stmt->type == STMT_LIBRARY)
206         {
207             write_progids( stmt->u.lib->stmts );
208         }
209     }
210 }
211
212 /* put a string into the resource file */
213 static inline void put_string( const char *str )
214 {
215     while (*str)
216     {
217         unsigned char ch = *str++;
218         put_word( toupper(ch) );
219     }
220     put_word( 0 );
221 }
222
223 void write_regscript( const statement_list_t *stmts )
224 {
225     int count;
226     const type_t *ps_factory;
227
228     if (!do_regscript) return;
229     if (do_everything && !need_proxy_file( stmts )) return;
230
231     init_output_buffer();
232
233     put_str( indent, "HKCR\n" );
234     put_str( indent++, "{\n" );
235
236     put_str( indent, "NoRemove Interface\n" );
237     put_str( indent++, "{\n" );
238     ps_factory = find_ps_factory( stmts );
239     count = write_interfaces( stmts, ps_factory );
240     put_str( --indent, "}\n" );
241
242     put_str( indent, "NoRemove CLSID\n" );
243     put_str( indent++, "{\n" );
244     if (count && !ps_factory)
245     {
246         put_str( indent, "ForceRemove '%%CLSID_PSFactoryBuffer%%' = s 'PSFactoryBuffer'\n" );
247         put_str( indent++, "{\n" );
248         put_str( indent, "InprocServer32 = s '%%MODULE%%' { val ThreadingModel = s 'Both' }\n" );
249         put_str( --indent, "}\n" );
250     }
251     write_coclasses( stmts, NULL );
252     put_str( --indent, "}\n" );
253
254     write_progids( stmts );
255     put_str( --indent, "}\n" );
256
257     if (strendswith( regscript_name, ".res" ))  /* create a binary resource file */
258     {
259         unsigned char *data = output_buffer;
260         size_t data_size = output_buffer_pos;
261         size_t header_size = 5 * sizeof(unsigned int) + 2 * sizeof(unsigned short);
262
263         header_size += (strlen(regscript_token) + strlen("WINE_REGISTRY") + 2) * sizeof(unsigned short);
264
265         init_output_buffer();
266
267         put_dword( 0 );      /* ResSize */
268         put_dword( 32 );     /* HeaderSize */
269         put_word( 0xffff );  /* ResType */
270         put_word( 0x0000 );
271         put_word( 0xffff );  /* ResName */
272         put_word( 0x0000 );
273         put_dword( 0 );      /* DataVersion */
274         put_word( 0 );       /* Memory options */
275         put_word( 0 );       /* Language */
276         put_dword( 0 );      /* Version */
277         put_dword( 0 );      /* Characteristics */
278
279         put_dword( data_size );               /* ResSize */
280         put_dword( (header_size + 3) & ~3 );  /* HeaderSize */
281         put_string( "WINE_REGISTRY" );        /* ResType */
282         put_string( regscript_token );        /* ResName */
283         align_output( 4 );
284         put_dword( 0 );      /* DataVersion */
285         put_word( 0 );       /* Memory options */
286         put_word( 0 );       /* Language */
287         put_dword( 0 );      /* Version */
288         put_dword( 0 );      /* Characteristics */
289
290         put_data( data, data_size );
291         free( data );
292         align_output( 4 );
293         flush_output_buffer( regscript_name );
294     }
295     else
296     {
297         FILE *f = fopen( regscript_name, "w" );
298         if (!f) error( "Could not open %s for output\n", regscript_name );
299         if (fwrite( output_buffer, output_buffer_pos, 1, f ) != output_buffer_pos)
300             error( "Failed to write to %s\n", regscript_name );
301         if (fclose( f ))
302             error( "Failed to write to %s\n", regscript_name );
303     }
304 }