diff --git a/tools/widl/Makefile.in b/tools/widl/Makefile.in index 4cfa77107df..3fc98fe3940 100644 --- a/tools/widl/Makefile.in +++ b/tools/widl/Makefile.in @@ -9,6 +9,7 @@ C_SRCS = \ hash.c \ header.c \ proxy.c \ + register.c \ server.c \ typegen.c \ typelib.c \ diff --git a/tools/widl/header.h b/tools/widl/header.h index 2175f5ecc32..6a37192f395 100644 --- a/tools/widl/header.h +++ b/tools/widl/header.h @@ -39,6 +39,7 @@ extern void write_type_decl_left(FILE *f, type_t *t); extern int needs_space_after(type_t *t); extern int is_object(const type_t *iface); extern int is_local(const attr_list_t *list); +extern int count_methods(const type_t *iface); extern int need_stub(const type_t *iface); extern int need_proxy(const type_t *iface); extern int need_stub_files(const statement_list_t *stmts); diff --git a/tools/widl/parser.y b/tools/widl/parser.y index 2ffa51531bb..1bf9a1e9150 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -332,6 +332,7 @@ input: gbl_statements { fix_incomplete(); write_proxies($1); write_client($1); write_server($1); + write_regscript($1); write_dlldata($1); write_local_stubs($1); } diff --git a/tools/widl/proxy.c b/tools/widl/proxy.c index a3ffc33a706..9952179ebf2 100644 --- a/tools/widl/proxy.c +++ b/tools/widl/proxy.c @@ -490,7 +490,7 @@ static void gen_stub(type_t *iface, const var_t *func, const char *cas, print_proxy("\n"); } -static int count_methods(type_t *iface) +int count_methods(const type_t *iface) { const statement_t *stmt; int count = 0; diff --git a/tools/widl/register.c b/tools/widl/register.c new file mode 100644 index 00000000000..61870ea1349 --- /dev/null +++ b/tools/widl/register.c @@ -0,0 +1,170 @@ +/* + * Generation of dll registration scripts + * + * Copyright 2010 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include + +#include "widl.h" +#include "utils.h" +#include "parser.h" +#include "header.h" +#include "typegen.h" + +static int indent; + +static const char *format_uuid( const UUID *uuid ) +{ + static char buffer[40]; + sprintf( buffer, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + uuid->Data1, uuid->Data2, uuid->Data3, + uuid->Data4[0], uuid->Data4[1], uuid->Data4[2], uuid->Data4[3], + uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], uuid->Data4[7] ); + return buffer; +} + +static int write_interface( const type_t *iface ) +{ + const UUID *uuid = get_attrp( iface->attrs, ATTR_UUID ); + + if (!type_iface_get_inherit( iface )) return 0; + if (!need_proxy( iface )) return 0; + if (!uuid) return 0; + put_str( indent, "ForceRemove '%s' = s '%s'\n", format_uuid( uuid ), iface->name ); + put_str( indent, "{\n" ); + indent++; + put_str( indent, "NumMethods = s %u\n", count_methods( iface )); + put_str( indent, "ProxyStubClsid32 = s '%%CLSID_PSFactoryBuffer%%'\n" ); + indent--; + put_str( indent, "}\n" ); + return 1; +} + +static int write_interfaces( const statement_list_t *stmts ) +{ + const statement_t *stmt; + int count = 0; + + if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry ) + { + if (stmt->type == STMT_LIBRARY) + count += write_interfaces( stmt->u.lib->stmts ); + else if (stmt->type == STMT_TYPE && type_get_type( stmt->u.type ) == TYPE_INTERFACE) + count += write_interface( stmt->u.type ); + } + return count; +} + +/* put a string into the resource file */ +static inline void put_string( const char *str ) +{ + while (*str) + { + unsigned char ch = *str++; + put_word( toupper(ch) ); + } + put_word( 0 ); +} + +void write_regscript( const statement_list_t *stmts ) +{ + int count; + + if (!do_regscript) return; + if (do_everything && !need_proxy_file( stmts )) return; + + init_output_buffer(); + + put_str( indent, "HKCR\n" ); + put_str( indent++, "{\n" ); + + put_str( indent, "NoRemove Interface\n" ); + put_str( indent++, "{\n" ); + count = write_interfaces( stmts ); + put_str( --indent, "}\n" ); + + if (count) + { + put_str( indent, "NoRemove CLSID\n" ); + put_str( indent++, "{\n" ); + put_str( indent, "ForceRemove '%%CLSID_PSFactoryBuffer%%' = s 'PSFactoryBuffer'\n" ); + put_str( indent++, "{\n" ); + put_str( indent, "InprocServer32 = s '%%MODULE%%' { val ThreadingModel = s 'Both' }\n" ); + put_str( --indent, "}\n" ); + put_str( --indent, "}\n" ); + } + + put_str( --indent, "}\n" ); + + if (strendswith( regscript_name, ".res" )) /* create a binary resource file */ + { + unsigned char *data = output_buffer; + size_t data_size = output_buffer_pos; + size_t header_size = 5 * sizeof(unsigned int) + 2 * sizeof(unsigned short); + + header_size += (strlen(regscript_token) + strlen("WINE_REGISTRY") + 2) * sizeof(unsigned short); + + init_output_buffer(); + + put_dword( 0 ); /* ResSize */ + put_dword( 32 ); /* HeaderSize */ + put_word( 0xffff ); /* ResType */ + put_word( 0x0000 ); + put_word( 0xffff ); /* ResName */ + put_word( 0x0000 ); + put_dword( 0 ); /* DataVersion */ + put_word( 0 ); /* Memory options */ + put_word( 0 ); /* Language */ + put_dword( 0 ); /* Version */ + put_dword( 0 ); /* Characteristics */ + + put_dword( data_size ); /* ResSize */ + put_dword( (header_size + 3) & ~3 ); /* HeaderSize */ + put_string( "WINE_REGISTRY" ); /* ResType */ + put_string( regscript_token ); /* ResName */ + align_output( 4 ); + put_dword( 0 ); /* DataVersion */ + put_word( 0 ); /* Memory options */ + put_word( 0 ); /* Language */ + put_dword( 0 ); /* Version */ + put_dword( 0 ); /* Characteristics */ + + put_data( data, data_size ); + free( data ); + align_output( 4 ); + flush_output_buffer( regscript_name ); + } + else + { + FILE *f = fopen( regscript_name, "w" ); + if (!f) error( "Could not open %s for output\n", regscript_name ); + if (fwrite( output_buffer, output_buffer_pos, 1, f ) != output_buffer_pos) + error( "Failed to write to %s\n", regscript_name ); + if (fclose( f )) + error( "Failed to write to %s\n", regscript_name ); + } +} diff --git a/tools/widl/utils.c b/tools/widl/utils.c index c0f6de6b4cf..b025c9a4e8f 100644 --- a/tools/widl/utils.c +++ b/tools/widl/utils.c @@ -326,6 +326,32 @@ void put_pword( unsigned int val ) else put_dword( val ); } +void put_str( int indent, const char *format, ... ) +{ + int n; + va_list args; + + check_output_buffer_space( 4 * indent ); + memset( output_buffer + output_buffer_pos, ' ', 4 * indent ); + output_buffer_pos += 4 * indent; + + for (;;) + { + size_t size = output_buffer_size - output_buffer_pos; + va_start( args, format ); + n = vsnprintf( (char *)output_buffer + output_buffer_pos, size, format, args ); + va_end( args ); + if (n == -1) size *= 2; + else if ((size_t)n >= size) size = n + 1; + else + { + output_buffer_pos += n; + return; + } + check_output_buffer_space( size ); + } +} + void align_output( unsigned int align ) { size_t size = align - (output_buffer_pos % align); diff --git a/tools/widl/utils.h b/tools/widl/utils.h index da589b9dc2c..5b44aace3f6 100644 --- a/tools/widl/utils.h +++ b/tools/widl/utils.h @@ -64,6 +64,7 @@ extern void put_word( unsigned short val ); extern void put_dword( unsigned int val ); extern void put_qword( unsigned int val ); extern void put_pword( unsigned int val ); +extern void put_str( int indent, const char *format, ... ) __attribute__((format (printf, 2, 3))); extern void align_output( unsigned int align ); /* typelibs expect the minor version to be stored in the higher bits and diff --git a/tools/widl/widl.c b/tools/widl/widl.c index 05feae22754..dc5c165e0bb 100644 --- a/tools/widl/widl.c +++ b/tools/widl/widl.c @@ -69,6 +69,7 @@ static const char usage[] = " --prefix-all=p Prefix names of client stubs / server functions with 'p'\n" " --prefix-client=p Prefix names of client stubs with 'p'\n" " --prefix-server=p Prefix names of server functions with 'p'\n" +" -r Generate registration script\n" " -s Generate server stub\n" " -t Generate typelib\n" " -u Generate interface identifiers file\n" @@ -101,6 +102,7 @@ int do_typelib = 0; int do_proxies = 0; int do_client = 0; int do_server = 0; +int do_regscript = 0; int do_idfile = 0; int do_dlldata = 0; static int no_preprocess = 0; @@ -122,6 +124,8 @@ char *client_name; char *client_token; char *server_name; char *server_token; +char *regscript_name; +char *regscript_token; static char *idfile_name; static char *idfile_token; char *temp_name; @@ -152,7 +156,7 @@ enum { }; static const char short_options[] = - "b:cC:d:D:EhH:I:m:No:pP:sS:tT:uU:VW"; + "b:cC:d:D:EhH:I:m:No:pP:rsS:tT:uU:VW"; static const struct option long_options[] = { { "dlldata", 1, NULL, DLLDATA_OPTION }, { "dlldata-only", 0, NULL, DLLDATA_ONLY_OPTION }, @@ -284,6 +288,7 @@ static void set_everything(int x) do_proxies = x; do_client = x; do_server = x; + do_regscript = x; do_idfile = x; do_dlldata = x; } @@ -584,6 +589,10 @@ int main(int argc,char *argv[]) case 'P': proxy_name = xstrdup(optarg); break; + case 'r': + do_everything = 0; + do_regscript = 1; + break; case 's': do_everything = 0; do_server = 1; @@ -624,13 +633,15 @@ int main(int argc,char *argv[]) if (!output_name) output_name = dup_basename(input_name, ".idl"); if (!do_everything && - do_header + do_typelib + do_proxies + do_client + do_server + do_idfile + do_dlldata == 1) + do_header + do_typelib + do_proxies + do_client + + do_server + do_regscript + do_idfile + do_dlldata == 1) { if (do_header) header_name = output_name; else if (do_typelib) typelib_name = output_name; else if (do_proxies) proxy_name = output_name; else if (do_client) client_name = output_name; else if (do_server) server_name = output_name; + else if (do_regscript) regscript_name = output_name; else if (do_idfile) idfile_name = output_name; else if (do_dlldata) dlldata_name = output_name; } @@ -698,6 +709,11 @@ int main(int argc,char *argv[]) strcat(server_name, "_s.c"); } + if (!regscript_name && do_regscript) { + regscript_name = dup_basename(input_name, ".idl"); + strcat(regscript_name, "_r.rgs"); + } + if (!idfile_name && do_idfile) { idfile_name = dup_basename(input_name, ".idl"); strcat(idfile_name, "_i.c"); @@ -706,6 +722,7 @@ int main(int argc,char *argv[]) if (do_proxies) proxy_token = dup_basename_token(proxy_name,"_p.c"); if (do_client) client_token = dup_basename_token(client_name,"_c.c"); if (do_server) server_token = dup_basename_token(server_name,"_s.c"); + if (do_regscript) regscript_token = dup_basename_token(regscript_name,"_r.rgs"); add_widl_version_define(); wpp_add_define("_WIN32", NULL); @@ -784,6 +801,8 @@ static void rm_tempfile(void) unlink(client_name); if (do_server) unlink(server_name); + if (do_regscript) + unlink(regscript_name); if (do_idfile) unlink(idfile_name); if (do_proxies) diff --git a/tools/widl/widl.h b/tools/widl/widl.h index 5de2cba16db..515e122e41f 100644 --- a/tools/widl/widl.h +++ b/tools/widl/widl.h @@ -41,6 +41,7 @@ extern int do_typelib; extern int do_proxies; extern int do_client; extern int do_server; +extern int do_regscript; extern int do_idfile; extern int do_dlldata; extern int old_names; @@ -61,6 +62,8 @@ extern char *client_name; extern char *client_token; extern char *server_name; extern char *server_token; +extern char *regscript_name; +extern char *regscript_token; extern const char *prefix_client; extern const char *prefix_server; extern size_t pointer_size; @@ -74,6 +77,7 @@ extern void write_id_data(const statement_list_t *stmts); extern void write_proxies(const statement_list_t *stmts); extern void write_client(const statement_list_t *stmts); extern void write_server(const statement_list_t *stmts); +extern void write_regscript(const statement_list_t *stmts); extern void write_local_stubs(const statement_list_t *stmts); extern void write_dlldata(const statement_list_t *stmts); diff --git a/tools/widl/widl.man.in b/tools/widl/widl.man.in index 17aa8aa68c4..3bbc1cf336c 100644 --- a/tools/widl/widl.man.in +++ b/tools/widl/widl.man.in @@ -75,6 +75,12 @@ Only generate 32-bit, respectively 64-bit code (the default is to generate both 32-bit and 64-bit versions into the same destination file). .PP +.B Registration script options: +.IP "\fB-r\fR" +Generate a registration script. The default output filename is +\fIinfile\fB_r.rgs\fR. If the output file name ends in \fB.res\fR, a +binary resource file containing the script is generated instead. +.PP .B Dlldata file options: .IP "\fB--dlldata-only\fI name1 [name2...]" Regenerate the dlldata file from scratch using the specified proxy