Reactos
at master 386 lines 13 kB view raw
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}