1 /* 2 * Setupapi install routines 3 * 4 * Copyright 2002 Alexandre Julliard for CodeWeavers 5 * 2005-2006 Herv� Poussineau (hpoussin@reactos.org) 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #include "setupapi_private.h" 23 24 WINE_DEFAULT_DEBUG_CHANNEL(setupapi); 25 26 /* Unicode constants */ 27 static const WCHAR BackSlash[] = {'\\',0}; 28 static const WCHAR GroupOrderListKey[] = {'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','G','r','o','u','p','O','r','d','e','r','L','i','s','t',0}; 29 static const WCHAR InfDirectory[] = {'i','n','f','\\',0}; 30 static const WCHAR OemFileMask[] = {'o','e','m','*','.','i','n','f',0}; 31 static const WCHAR OemFileSpecification[] = {'o','e','m','%','l','u','.','i','n','f',0}; 32 static const WCHAR DotLnk[] = {'.','l','n','k',0}; 33 static const WCHAR DotServices[] = {'.','S','e','r','v','i','c','e','s',0}; 34 35 static const WCHAR DependenciesKey[] = {'D','e','p','e','n','d','e','n','c','i','e','s',0}; 36 static const WCHAR DescriptionKey[] = {'D','e','s','c','r','i','p','t','i','o','n',0}; 37 static const WCHAR DisplayNameKey[] = {'D','i','s','p','l','a','y','N','a','m','e',0}; 38 static const WCHAR ErrorControlKey[] = {'E','r','r','o','r','C','o','n','t','r','o','l',0}; 39 static const WCHAR LoadOrderGroupKey[] = {'L','o','a','d','O','r','d','e','r','G','r','o','u','p',0}; 40 static const WCHAR SecurityKey[] = {'S','e','c','u','r','i','t','y',0}; 41 static const WCHAR ServiceBinaryKey[] = {'S','e','r','v','i','c','e','B','i','n','a','r','y',0}; 42 static const WCHAR ServiceTypeKey[] = {'S','e','r','v','i','c','e','T','y','p','e',0}; 43 static const WCHAR StartTypeKey[] = {'S','t','a','r','t','T','y','p','e',0}; 44 45 static const WCHAR Name[] = {'N','a','m','e',0}; 46 static const WCHAR CmdLine[] = {'C','m','d','L','i','n','e',0}; 47 static const WCHAR SubDir[] = {'S','u','b','D','i','r',0}; 48 static const WCHAR WorkingDir[] = {'W','o','r','k','i','n','g','D','i','r',0}; 49 static const WCHAR IconPath[] = {'I','c','o','n','P','a','t','h',0}; 50 static const WCHAR IconIndex[] = {'I','c','o','n','I','n','d','e','x',0}; 51 static const WCHAR HotKey[] = {'H','o','t','K','e','y',0}; 52 static const WCHAR InfoTip[] = {'I','n','f','o','T','i','p',0}; 53 static const WCHAR DisplayResource[] = {'D','i','s','p','l','a','y','R','e','s','o','u','r','c','e',0}; 54 55 /* info passed to callback functions dealing with files */ 56 struct files_callback_info 57 { 58 HSPFILEQ queue; 59 PCWSTR src_root; 60 UINT copy_flags; 61 HINF layout; 62 }; 63 64 /* info passed to callback functions dealing with the registry */ 65 struct registry_callback_info 66 { 67 HKEY default_root; 68 BOOL delete; 69 }; 70 71 /* info passed to callback functions dealing with registering dlls */ 72 struct register_dll_info 73 { 74 PSP_FILE_CALLBACK_W callback; 75 PVOID callback_context; 76 BOOL unregister; 77 }; 78 79 /* info passed to callback functions dealing with Needs directives */ 80 struct needs_callback_info 81 { 82 UINT type; 83 84 HWND owner; 85 UINT flags; 86 HKEY key_root; 87 LPCWSTR src_root; 88 UINT copy_flags; 89 PVOID callback; 90 PVOID context; 91 HDEVINFO devinfo; 92 PSP_DEVINFO_DATA devinfo_data; 93 PVOID reserved1; 94 PVOID reserved2; 95 }; 96 97 typedef BOOL (*iterate_fields_func)( HINF hinf, PCWSTR field, void *arg ); 98 static BOOL GetLineText( HINF hinf, PCWSTR section_name, PCWSTR key_name, PWSTR *value); 99 typedef HRESULT (WINAPI *COINITIALIZE)(IN LPVOID pvReserved); 100 typedef HRESULT (WINAPI *COCREATEINSTANCE)(IN REFCLSID rclsid, IN LPUNKNOWN pUnkOuter, IN DWORD dwClsContext, IN REFIID riid, OUT LPVOID *ppv); 101 typedef HRESULT (WINAPI *COUNINITIALIZE)(VOID); 102 103 /* Unicode constants */ 104 static const WCHAR AddService[] = {'A','d','d','S','e','r','v','i','c','e',0}; 105 static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0}; 106 static const WCHAR DelFiles[] = {'D','e','l','F','i','l','e','s',0}; 107 static const WCHAR RenFiles[] = {'R','e','n','F','i','l','e','s',0}; 108 static const WCHAR Ini2Reg[] = {'I','n','i','2','R','e','g',0}; 109 static const WCHAR LogConf[] = {'L','o','g','C','o','n','f',0}; 110 static const WCHAR AddReg[] = {'A','d','d','R','e','g',0}; 111 static const WCHAR DelReg[] = {'D','e','l','R','e','g',0}; 112 static const WCHAR BitReg[] = {'B','i','t','R','e','g',0}; 113 static const WCHAR UpdateInis[] = {'U','p','d','a','t','e','I','n','i','s',0}; 114 static const WCHAR CopyINF[] = {'C','o','p','y','I','N','F',0}; 115 static const WCHAR UpdateIniFields[] = {'U','p','d','a','t','e','I','n','i','F','i','e','l','d','s',0}; 116 static const WCHAR RegisterDlls[] = {'R','e','g','i','s','t','e','r','D','l','l','s',0}; 117 static const WCHAR UnregisterDlls[] = {'U','n','r','e','g','i','s','t','e','r','D','l','l','s',0}; 118 static const WCHAR ProfileItems[] = {'P','r','o','f','i','l','e','I','t','e','m','s',0}; 119 static const WCHAR Include[] = {'I','n','c','l','u','d','e',0}; 120 static const WCHAR Needs[] = {'N','e','e','d','s',0}; 121 static const WCHAR DotSecurity[] = {'.','S','e','c','u','r','i','t','y',0}; 122 #ifdef __WINESRC__ 123 static const WCHAR WineFakeDlls[] = {'W','i','n','e','F','a','k','e','D','l','l','s',0}; 124 #endif 125 126 127 /*********************************************************************** 128 * get_field_string 129 * 130 * Retrieve the contents of a field, dynamically growing the buffer if necessary. 131 */ 132 static WCHAR *get_field_string( INFCONTEXT *context, DWORD index, WCHAR *buffer, 133 WCHAR *static_buffer, DWORD *size ) 134 { 135 DWORD required; 136 137 if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer; 138 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) 139 { 140 /* now grow the buffer */ 141 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer ); 142 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required*sizeof(WCHAR) ))) return NULL; 143 *size = required; 144 if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer; 145 } 146 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer ); 147 return NULL; 148 } 149 150 151 /*********************************************************************** 152 * copy_files_callback 153 * 154 * Called once for each CopyFiles entry in a given section. 155 */ 156 static BOOL copy_files_callback( HINF hinf, PCWSTR field, void *arg ) 157 { 158 struct files_callback_info *info = arg; 159 160 if (field[0] == '@') /* special case: copy single file */ 161 SetupQueueDefaultCopyW( info->queue, info->layout ? info->layout : hinf, info->src_root, NULL, field+1, info->copy_flags ); 162 else 163 SetupQueueCopySectionW( info->queue, info->src_root, info->layout ? info->layout : hinf, hinf, field, info->copy_flags ); 164 return TRUE; 165 } 166 167 168 /*********************************************************************** 169 * delete_files_callback 170 * 171 * Called once for each DelFiles entry in a given section. 172 */ 173 static BOOL delete_files_callback( HINF hinf, PCWSTR field, void *arg ) 174 { 175 struct files_callback_info *info = arg; 176 SetupQueueDeleteSectionW( info->queue, hinf, 0, field ); 177 return TRUE; 178 } 179 180 181 /*********************************************************************** 182 * rename_files_callback 183 * 184 * Called once for each RenFiles entry in a given section. 185 */ 186 static BOOL rename_files_callback( HINF hinf, PCWSTR field, void *arg ) 187 { 188 struct files_callback_info *info = arg; 189 SetupQueueRenameSectionW( info->queue, hinf, 0, field ); 190 return TRUE; 191 } 192 193 194 /*********************************************************************** 195 * get_root_key 196 * 197 * Retrieve the registry root key from its name. 198 */ 199 static HKEY get_root_key( const WCHAR *name, HKEY def_root ) 200 { 201 static const WCHAR HKCR[] = {'H','K','C','R',0}; 202 static const WCHAR HKCU[] = {'H','K','C','U',0}; 203 static const WCHAR HKLM[] = {'H','K','L','M',0}; 204 static const WCHAR HKU[] = {'H','K','U',0}; 205 static const WCHAR HKR[] = {'H','K','R',0}; 206 207 if (!strcmpiW( name, HKCR )) return HKEY_CLASSES_ROOT; 208 if (!strcmpiW( name, HKCU )) return HKEY_CURRENT_USER; 209 if (!strcmpiW( name, HKLM )) return HKEY_LOCAL_MACHINE; 210 if (!strcmpiW( name, HKU )) return HKEY_USERS; 211 if (!strcmpiW( name, HKR )) return def_root; 212 return 0; 213 } 214 215 216 /*********************************************************************** 217 * append_multi_sz_value 218 * 219 * Append a multisz string to a multisz registry value. 220 */ 221 static void append_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *strings, 222 DWORD str_size ) 223 { 224 DWORD size, type, total; 225 WCHAR *buffer, *p; 226 227 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return; 228 if (type != REG_MULTI_SZ) return; 229 230 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return; 231 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done; 232 233 /* compare each string against all the existing ones */ 234 total = size; 235 while (*strings) 236 { 237 int len = strlenW(strings) + 1; 238 239 for (p = buffer; *p; p += strlenW(p) + 1) 240 if (!strcmpiW( p, strings )) break; 241 242 if (!*p) /* not found, need to append it */ 243 { 244 memcpy( p, strings, len * sizeof(WCHAR) ); 245 p[len] = 0; 246 total += len; 247 } 248 strings += len; 249 } 250 if (total != size) 251 { 252 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) ); 253 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total + sizeof(WCHAR) ); 254 } 255 done: 256 HeapFree( GetProcessHeap(), 0, buffer ); 257 } 258 259 260 /*********************************************************************** 261 * delete_multi_sz_value 262 * 263 * Remove a string from a multisz registry value. 264 */ 265 static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string ) 266 { 267 DWORD size, type; 268 WCHAR *buffer, *src, *dst; 269 270 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return; 271 if (type != REG_MULTI_SZ) return; 272 /* allocate double the size, one for value before and one for after */ 273 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return; 274 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done; 275 src = buffer; 276 dst = buffer + size; 277 while (*src) 278 { 279 int len = strlenW(src) + 1; 280 if (strcmpiW( src, string )) 281 { 282 memcpy( dst, src, len * sizeof(WCHAR) ); 283 dst += len; 284 } 285 src += len; 286 } 287 *dst++ = 0; 288 if (dst != buffer + 2*size) /* did we remove something? */ 289 { 290 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) ); 291 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, 292 (BYTE *)(buffer + size), dst - (buffer + size) ); 293 } 294 done: 295 HeapFree( GetProcessHeap(), 0, buffer ); 296 } 297 298 299 /*********************************************************************** 300 * do_reg_operation 301 * 302 * Perform an add/delete registry operation depending on the flags. 303 */ 304 static BOOL do_reg_operation( HKEY hkey, const WCHAR *value, INFCONTEXT *context, INT flags ) 305 { 306 DWORD type, size; 307 308 if (flags & (FLG_ADDREG_DELREG_BIT | FLG_ADDREG_DELVAL)) /* deletion */ 309 { 310 if (*value && !(flags & FLG_DELREG_KEYONLY_COMMON)) 311 { 312 if ((flags & FLG_DELREG_MULTI_SZ_DELSTRING) == FLG_DELREG_MULTI_SZ_DELSTRING) 313 { 314 WCHAR *str; 315 316 if (!SetupGetStringFieldW( context, 5, NULL, 0, &size ) || !size) return TRUE; 317 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE; 318 SetupGetStringFieldW( context, 5, str, size, NULL ); 319 delete_multi_sz_value( hkey, value, str ); 320 HeapFree( GetProcessHeap(), 0, str ); 321 } 322 else RegDeleteValueW( hkey, value ); 323 } 324 else NtDeleteKey( hkey ); 325 return TRUE; 326 } 327 328 if (flags & (FLG_ADDREG_KEYONLY|FLG_ADDREG_KEYONLY_COMMON)) return TRUE; 329 330 if (flags & (FLG_ADDREG_NOCLOBBER|FLG_ADDREG_OVERWRITEONLY)) 331 { 332 BOOL exists = !RegQueryValueExW( hkey, value, NULL, NULL, NULL, NULL ); 333 if (exists && (flags & FLG_ADDREG_NOCLOBBER)) return TRUE; 334 if (!exists && (flags & FLG_ADDREG_OVERWRITEONLY)) return TRUE; 335 } 336 337 switch(flags & FLG_ADDREG_TYPE_MASK) 338 { 339 case FLG_ADDREG_TYPE_SZ: type = REG_SZ; break; 340 case FLG_ADDREG_TYPE_MULTI_SZ: type = REG_MULTI_SZ; break; 341 case FLG_ADDREG_TYPE_EXPAND_SZ: type = REG_EXPAND_SZ; break; 342 case FLG_ADDREG_TYPE_BINARY: type = REG_BINARY; break; 343 case FLG_ADDREG_TYPE_DWORD: type = REG_DWORD; break; 344 case FLG_ADDREG_TYPE_NONE: type = REG_NONE; break; 345 default: type = flags >> 16; break; 346 } 347 348 if (!(flags & FLG_ADDREG_BINVALUETYPE) || 349 (type == REG_DWORD && SetupGetFieldCount(context) == 5)) 350 { 351 static const WCHAR empty; 352 WCHAR *str = NULL; 353 354 if (type == REG_MULTI_SZ) 355 { 356 if (!SetupGetMultiSzFieldW( context, 5, NULL, 0, &size )) size = 0; 357 if (size) 358 { 359 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE; 360 SetupGetMultiSzFieldW( context, 5, str, size, NULL ); 361 } 362 if (flags & FLG_ADDREG_APPEND) 363 { 364 if (!str) return TRUE; 365 append_multi_sz_value( hkey, value, str, size ); 366 HeapFree( GetProcessHeap(), 0, str ); 367 return TRUE; 368 } 369 /* else fall through to normal string handling */ 370 } 371 else 372 { 373 if (!SetupGetStringFieldW( context, 5, NULL, 0, &size )) size = 0; 374 if (size) 375 { 376 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE; 377 SetupGetStringFieldW( context, 5, str, size, NULL ); 378 } 379 } 380 381 if (type == REG_DWORD) 382 { 383 DWORD dw = str ? strtoulW( str, NULL, 0 ) : 0; 384 TRACE( "setting dword %s to %x\n", debugstr_w(value), dw ); 385 RegSetValueExW( hkey, value, 0, type, (BYTE *)&dw, sizeof(dw) ); 386 } 387 else 388 { 389 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(str) ); 390 if (str) RegSetValueExW( hkey, value, 0, type, (BYTE *)str, size * sizeof(WCHAR) ); 391 else RegSetValueExW( hkey, value, 0, type, (const BYTE *)&empty, sizeof(WCHAR) ); 392 } 393 HeapFree( GetProcessHeap(), 0, str ); 394 return TRUE; 395 } 396 else /* get the binary data */ 397 { 398 BYTE *data = NULL; 399 400 if (!SetupGetBinaryField( context, 5, NULL, 0, &size )) size = 0; 401 if (size) 402 { 403 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE; 404 TRACE( "setting binary data %s len %d\n", debugstr_w(value), size ); 405 SetupGetBinaryField( context, 5, data, size, NULL ); 406 } 407 RegSetValueExW( hkey, value, 0, type, data, size ); 408 HeapFree( GetProcessHeap(), 0, data ); 409 return TRUE; 410 } 411 } 412 413 414 /*********************************************************************** 415 * registry_callback 416 * 417 * Called once for each AddReg and DelReg entry in a given section. 418 */ 419 static BOOL registry_callback( HINF hinf, PCWSTR field, void *arg ) 420 { 421 struct registry_callback_info *info = arg; 422 LPWSTR security_key, security_descriptor; 423 INFCONTEXT context, security_context; 424 PSECURITY_DESCRIPTOR sd = NULL; 425 SECURITY_ATTRIBUTES security_attributes = { 0, }; 426 HKEY root_key, hkey; 427 DWORD required; 428 429 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context ); 430 if (!ok) 431 return TRUE; 432 433 /* Check for .Security section */ 434 security_key = MyMalloc( (strlenW( field ) + strlenW( DotSecurity )) * sizeof(WCHAR) + sizeof(UNICODE_NULL) ); 435 if (!security_key) 436 { 437 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 438 return FALSE; 439 } 440 strcpyW( security_key, field ); 441 strcatW( security_key, DotSecurity ); 442 ok = SetupFindFirstLineW( hinf, security_key, NULL, &security_context ); 443 MyFree(security_key); 444 if (ok) 445 { 446 if (!SetupGetLineTextW( &security_context, NULL, NULL, NULL, NULL, 0, &required )) 447 return FALSE; 448 security_descriptor = MyMalloc( required * sizeof(WCHAR) ); 449 if (!security_descriptor) 450 { 451 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 452 return FALSE; 453 } 454 if (!SetupGetLineTextW( &security_context, NULL, NULL, NULL, security_descriptor, required, NULL )) 455 return FALSE; 456 ok = ConvertStringSecurityDescriptorToSecurityDescriptorW( security_descriptor, SDDL_REVISION_1, &sd, NULL ); 457 MyFree( security_descriptor ); 458 if (!ok) 459 return FALSE; 460 security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); 461 security_attributes.lpSecurityDescriptor = sd; 462 } 463 464 for (ok = TRUE; ok; ok = SetupFindNextLine( &context, &context )) 465 { 466 WCHAR buffer[MAX_INF_STRING_LENGTH]; 467 INT flags; 468 469 /* get root */ 470 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) 471 continue; 472 if (!(root_key = get_root_key( buffer, info->default_root ))) 473 continue; 474 475 /* get key */ 476 if (!SetupGetStringFieldW( &context, 2, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) 477 *buffer = 0; 478 479 /* get flags */ 480 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; 481 482 if (!info->delete) 483 { 484 if (flags & FLG_ADDREG_DELREG_BIT) continue; /* ignore this entry */ 485 } 486 else 487 { 488 if (!flags) flags = FLG_ADDREG_DELREG_BIT; 489 else if (!(flags & FLG_ADDREG_DELREG_BIT)) continue; /* ignore this entry */ 490 } 491 492 if (info->delete || (flags & FLG_ADDREG_OVERWRITEONLY)) 493 { 494 if (RegOpenKeyW( root_key, buffer, &hkey )) continue; /* ignore if it doesn't exist */ 495 } 496 else if (RegCreateKeyExW( root_key, buffer, 0, NULL, 0, MAXIMUM_ALLOWED, 497 sd ? &security_attributes : NULL, &hkey, NULL )) 498 { 499 ERR( "could not create key %p %s\n", root_key, debugstr_w(buffer) ); 500 continue; 501 } 502 TRACE( "key %p %s\n", root_key, debugstr_w(buffer) ); 503 504 /* get value name */ 505 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) 506 *buffer = 0; 507 508 /* and now do it */ 509 if (!do_reg_operation( hkey, buffer, &context, flags )) 510 { 511 if (hkey != root_key) RegCloseKey( hkey ); 512 if (sd) LocalFree( sd ); 513 return FALSE; 514 } 515 if (hkey != root_key) RegCloseKey( hkey ); 516 } 517 if (sd) LocalFree( sd ); 518 return TRUE; 519 } 520 521 522 /*********************************************************************** 523 * do_register_dll 524 * 525 * Register or unregister a dll. 526 */ 527 static BOOL do_register_dll( const struct register_dll_info *info, const WCHAR *path, 528 INT flags, INT timeout, const WCHAR *args ) 529 { 530 HMODULE module; 531 HRESULT res; 532 SP_REGISTER_CONTROL_STATUSW status; 533 #ifdef __WINESRC__ 534 IMAGE_NT_HEADERS *nt; 535 #endif 536 537 status.cbSize = sizeof(status); 538 status.FileName = path; 539 status.FailureCode = SPREG_SUCCESS; 540 status.Win32Error = ERROR_SUCCESS; 541 542 if (info->callback) 543 { 544 switch(info->callback( info->callback_context, SPFILENOTIFY_STARTREGISTRATION, 545 (UINT_PTR)&status, !info->unregister )) 546 { 547 case FILEOP_ABORT: 548 SetLastError( ERROR_OPERATION_ABORTED ); 549 return FALSE; 550 case FILEOP_SKIP: 551 return TRUE; 552 case FILEOP_DOIT: 553 break; 554 } 555 } 556 557 if (!(module = LoadLibraryExW( path, 0, LOAD_WITH_ALTERED_SEARCH_PATH ))) 558 { 559 WARN( "could not load %s\n", debugstr_w(path) ); 560 status.FailureCode = SPREG_LOADLIBRARY; 561 status.Win32Error = GetLastError(); 562 goto done; 563 } 564 565 #ifdef __WINESRC__ 566 if ((nt = RtlImageNtHeader( module )) && !(nt->FileHeader.Characteristics & IMAGE_FILE_DLL)) 567 { 568 /* file is an executable, not a dll */ 569 STARTUPINFOW startup; 570 PROCESS_INFORMATION info; 571 WCHAR *cmd_line; 572 BOOL res; 573 static const WCHAR format[] = {'"','%','s','"',' ','%','s',0}; 574 static const WCHAR default_args[] = {'/','R','e','g','S','e','r','v','e','r',0}; 575 576 FreeLibrary( module ); 577 module = NULL; 578 if (!args) args = default_args; 579 cmd_line = HeapAlloc( GetProcessHeap(), 0, (strlenW(path) + strlenW(args) + 4) * sizeof(WCHAR) ); 580 sprintfW( cmd_line, format, path, args ); 581 memset( &startup, 0, sizeof(startup) ); 582 startup.cb = sizeof(startup); 583 TRACE( "executing %s\n", debugstr_w(cmd_line) ); 584 res = CreateProcessW( NULL, cmd_line, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ); 585 HeapFree( GetProcessHeap(), 0, cmd_line ); 586 if (!res) 587 { 588 status.FailureCode = SPREG_LOADLIBRARY; 589 status.Win32Error = GetLastError(); 590 goto done; 591 } 592 CloseHandle( info.hThread ); 593 594 if (WaitForSingleObject( info.hProcess, timeout*1000 ) == WAIT_TIMEOUT) 595 { 596 /* timed out, kill the process */ 597 TerminateProcess( info.hProcess, 1 ); 598 status.FailureCode = SPREG_TIMEOUT; 599 status.Win32Error = ERROR_TIMEOUT; 600 } 601 CloseHandle( info.hProcess ); 602 goto done; 603 } 604 #endif // __WINESRC__ 605 606 if (flags & FLG_REGSVR_DLLREGISTER) 607 { 608 const char *entry_point = info->unregister ? "DllUnregisterServer" : "DllRegisterServer"; 609 HRESULT (WINAPI *func)(void) = (void *)GetProcAddress( module, entry_point ); 610 611 if (!func) 612 { 613 status.FailureCode = SPREG_GETPROCADDR; 614 status.Win32Error = GetLastError(); 615 goto done; 616 } 617 618 TRACE( "calling %s in %s\n", entry_point, debugstr_w(path) ); 619 res = func(); 620 621 if (FAILED(res)) 622 { 623 WARN( "calling %s in %s returned error %x\n", entry_point, debugstr_w(path), res ); 624 status.FailureCode = SPREG_REGSVR; 625 status.Win32Error = res; 626 goto done; 627 } 628 } 629 630 if (flags & FLG_REGSVR_DLLINSTALL) 631 { 632 HRESULT (WINAPI *func)(BOOL,LPCWSTR) = (void *)GetProcAddress( module, "DllInstall" ); 633 634 if (!func) 635 { 636 status.FailureCode = SPREG_GETPROCADDR; 637 status.Win32Error = GetLastError(); 638 goto done; 639 } 640 641 TRACE( "calling DllInstall(%d,%s) in %s\n", 642 !info->unregister, debugstr_w(args), debugstr_w(path) ); 643 res = func( !info->unregister, args ); 644 645 if (FAILED(res)) 646 { 647 WARN( "calling DllInstall in %s returned error %x\n", debugstr_w(path), res ); 648 status.FailureCode = SPREG_REGSVR; 649 status.Win32Error = res; 650 goto done; 651 } 652 } 653 654 done: 655 if (module) FreeLibrary( module ); 656 if (info->callback) info->callback( info->callback_context, SPFILENOTIFY_ENDREGISTRATION, 657 (UINT_PTR)&status, !info->unregister ); 658 return TRUE; 659 } 660 661 662 /*********************************************************************** 663 * register_dlls_callback 664 * 665 * Called once for each RegisterDlls entry in a given section. 666 */ 667 static BOOL register_dlls_callback( HINF hinf, PCWSTR field, void *arg ) 668 { 669 struct register_dll_info *info = arg; 670 INFCONTEXT context; 671 BOOL ret = TRUE; 672 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context ); 673 674 for (; ok; ok = SetupFindNextLine( &context, &context )) 675 { 676 WCHAR *path, *args, *p; 677 WCHAR buffer[MAX_INF_STRING_LENGTH]; 678 INT flags, timeout; 679 680 /* get directory */ 681 if (!(path = PARSER_get_dest_dir( &context ))) continue; 682 683 /* get dll name */ 684 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) 685 goto done; 686 if (!(p = HeapReAlloc( GetProcessHeap(), 0, path, 687 (strlenW(path) + strlenW(buffer) + 2) * sizeof(WCHAR) ))) goto done; 688 path = p; 689 p += strlenW(p); 690 if (p == path || p[-1] != '\\') *p++ = '\\'; 691 strcpyW( p, buffer ); 692 693 /* get flags */ 694 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; 695 696 /* get timeout */ 697 if (!SetupGetIntField( &context, 5, &timeout )) timeout = 60; 698 699 /* get command line */ 700 args = NULL; 701 if (SetupGetStringFieldW( &context, 6, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) 702 args = buffer; 703 704 ret = do_register_dll( info, path, flags, timeout, args ); 705 706 done: 707 HeapFree( GetProcessHeap(), 0, path ); 708 if (!ret) break; 709 } 710 return ret; 711 } 712 713 #ifdef __WINESRC__ 714 /*********************************************************************** 715 * fake_dlls_callback 716 * 717 * Called once for each WineFakeDlls entry in a given section. 718 */ 719 static BOOL fake_dlls_callback( HINF hinf, PCWSTR field, void *arg ) 720 { 721 INFCONTEXT context; 722 BOOL ret = TRUE; 723 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context ); 724 725 for (; ok; ok = SetupFindNextLine( &context, &context )) 726 { 727 WCHAR *path, *p; 728 WCHAR buffer[MAX_INF_STRING_LENGTH]; 729 730 /* get directory */ 731 if (!(path = PARSER_get_dest_dir( &context ))) continue; 732 733 /* get dll name */ 734 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) 735 goto done; 736 if (!(p = HeapReAlloc( GetProcessHeap(), 0, path, 737 (strlenW(path) + strlenW(buffer) + 2) * sizeof(WCHAR) ))) goto done; 738 path = p; 739 p += strlenW(p); 740 if (p == path || p[-1] != '\\') *p++ = '\\'; 741 strcpyW( p, buffer ); 742 743 /* get source dll */ 744 if (SetupGetStringFieldW( &context, 4, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) 745 p = buffer; /* otherwise use target base name as default source */ 746 747 create_fake_dll( path, p ); /* ignore errors */ 748 749 done: 750 HeapFree( GetProcessHeap(), 0, path ); 751 if (!ret) break; 752 } 753 return ret; 754 } 755 #endif // __WINESRC__ 756 757 /*********************************************************************** 758 * update_ini_callback 759 * 760 * Called once for each UpdateInis entry in a given section. 761 */ 762 static BOOL update_ini_callback( HINF hinf, PCWSTR field, void *arg ) 763 { 764 INFCONTEXT context; 765 766 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context ); 767 768 for (; ok; ok = SetupFindNextLine( &context, &context )) 769 { 770 WCHAR buffer[MAX_INF_STRING_LENGTH]; 771 WCHAR filename[MAX_INF_STRING_LENGTH]; 772 WCHAR section[MAX_INF_STRING_LENGTH]; 773 WCHAR entry[MAX_INF_STRING_LENGTH]; 774 WCHAR string[MAX_INF_STRING_LENGTH]; 775 LPWSTR divider; 776 777 if (!SetupGetStringFieldW( &context, 1, filename, 778 sizeof(filename)/sizeof(WCHAR), NULL )) 779 continue; 780 781 if (!SetupGetStringFieldW( &context, 2, section, 782 sizeof(section)/sizeof(WCHAR), NULL )) 783 continue; 784 785 if (!SetupGetStringFieldW( &context, 4, buffer, 786 sizeof(buffer)/sizeof(WCHAR), NULL )) 787 continue; 788 789 divider = strchrW(buffer,'='); 790 if (divider) 791 { 792 *divider = 0; 793 strcpyW(entry,buffer); 794 divider++; 795 strcpyW(string,divider); 796 } 797 else 798 { 799 strcpyW(entry,buffer); 800 string[0]=0; 801 } 802 803 TRACE("Writing %s = %s in %s of file %s\n",debugstr_w(entry), 804 debugstr_w(string),debugstr_w(section),debugstr_w(filename)); 805 WritePrivateProfileStringW(section,entry,string,filename); 806 807 } 808 return TRUE; 809 } 810 811 static BOOL update_ini_fields_callback( HINF hinf, PCWSTR field, void *arg ) 812 { 813 FIXME( "should update ini fields %s\n", debugstr_w(field) ); 814 return TRUE; 815 } 816 817 static BOOL ini2reg_callback( HINF hinf, PCWSTR field, void *arg ) 818 { 819 FIXME( "should do ini2reg %s\n", debugstr_w(field) ); 820 return TRUE; 821 } 822 823 static BOOL logconf_callback( HINF hinf, PCWSTR field, void *arg ) 824 { 825 FIXME( "should do logconf %s\n", debugstr_w(field) ); 826 return TRUE; 827 } 828 829 static BOOL bitreg_callback( HINF hinf, PCWSTR field, void *arg ) 830 { 831 FIXME( "should do bitreg %s\n", debugstr_w(field) ); 832 return TRUE; 833 } 834 835 static BOOL Concatenate(int DirId, LPCWSTR SubDirPart, LPCWSTR NamePart, LPWSTR *pFullName) 836 { 837 DWORD dwRequired = 0; 838 LPCWSTR Dir; 839 LPWSTR FullName; 840 841 *pFullName = NULL; 842 843 Dir = DIRID_get_string(DirId); 844 if (Dir) 845 dwRequired += wcslen(Dir) + 1; 846 if (SubDirPart) 847 dwRequired += wcslen(SubDirPart) + 1; 848 if (NamePart) 849 dwRequired += wcslen(NamePart); 850 dwRequired = dwRequired * sizeof(WCHAR) + sizeof(UNICODE_NULL); 851 852 FullName = MyMalloc(dwRequired); 853 if (!FullName) 854 { 855 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 856 return FALSE; 857 } 858 FullName[0] = UNICODE_NULL; 859 860 if (Dir) 861 { 862 wcscat(FullName, Dir); 863 if (FullName[wcslen(FullName) - 1] != '\\') 864 wcscat(FullName, BackSlash); 865 } 866 if (SubDirPart) 867 { 868 wcscat(FullName, SubDirPart); 869 if (FullName[wcslen(FullName) - 1] != '\\') 870 wcscat(FullName, BackSlash); 871 } 872 if (NamePart) 873 wcscat(FullName, NamePart); 874 875 *pFullName = FullName; 876 return TRUE; 877 } 878 879 /*********************************************************************** 880 * profile_items_callback 881 * 882 * Called once for each ProfileItems entry in a given section. 883 */ 884 static BOOL 885 profile_items_callback( 886 IN HINF hInf, 887 IN PCWSTR SectionName, 888 IN PVOID Arg) 889 { 890 INFCONTEXT Context; 891 LPWSTR LinkSubDir = NULL, LinkName = NULL; 892 INT LinkAttributes = 0; 893 INT LinkFolder = 0; 894 INT FileDirId = 0; 895 INT CSIDL = CSIDL_COMMON_PROGRAMS; 896 LPWSTR FileSubDir = NULL; 897 INT DirId = 0; 898 LPWSTR SubDirPart = NULL, NamePart = NULL; 899 LPWSTR FullLinkName = NULL, FullFileName = NULL, FullWorkingDir = NULL, FullIconName = NULL; 900 INT IconIdx = 0; 901 LPWSTR lpHotKey = NULL, lpInfoTip = NULL; 902 LPWSTR DisplayName = NULL; 903 INT DisplayResId = 0; 904 BOOL ret = FALSE; 905 DWORD Index, Required; 906 907 IShellLinkW *psl; 908 IPersistFile *ppf; 909 HMODULE hOle32 = NULL; 910 COINITIALIZE pCoInitialize; 911 COCREATEINSTANCE pCoCreateInstance; 912 COUNINITIALIZE pCoUninitialize; 913 HRESULT hr; 914 915 TRACE("hInf %p, SectionName %s, Arg %p\n", 916 hInf, debugstr_w(SectionName), Arg); 917 918 /* Read 'Name' entry */ 919 if (!SetupFindFirstLineW(hInf, SectionName, Name, &Context)) 920 goto cleanup; 921 if (!GetStringField(&Context, 1, &LinkName)) 922 goto cleanup; 923 if (SetupGetFieldCount(&Context) >= 2) 924 { 925 if (!SetupGetIntField(&Context, 2, &LinkAttributes)) 926 goto cleanup; 927 } 928 if (SetupGetFieldCount(&Context) >= 3) 929 { 930 if (!SetupGetIntField(&Context, 3, &LinkFolder)) 931 goto cleanup; 932 } 933 934 /* Read 'CmdLine' entry */ 935 if (!SetupFindFirstLineW(hInf, SectionName, CmdLine, &Context)) 936 goto cleanup; 937 Index = 1; 938 if (!SetupGetIntField(&Context, Index++, &FileDirId)) 939 goto cleanup; 940 if (SetupGetFieldCount(&Context) >= 3) 941 { 942 if (!GetStringField(&Context, Index++, &FileSubDir)) 943 goto cleanup; 944 } 945 if (!GetStringField(&Context, Index++, &NamePart)) 946 goto cleanup; 947 if (!Concatenate(FileDirId, FileSubDir, NamePart, &FullFileName)) 948 goto cleanup; 949 MyFree(NamePart); 950 NamePart = NULL; 951 952 /* Read 'SubDir' entry */ 953 if ((LinkAttributes & FLG_PROFITEM_GROUP) == 0 && SetupFindFirstLineW(hInf, SectionName, SubDir, &Context)) 954 { 955 if (!GetStringField(&Context, 1, &LinkSubDir)) 956 goto cleanup; 957 } 958 959 /* Read 'WorkingDir' entry */ 960 if (SetupFindFirstLineW(hInf, SectionName, WorkingDir, &Context)) 961 { 962 if (!SetupGetIntField(&Context, 1, &DirId)) 963 goto cleanup; 964 if (SetupGetFieldCount(&Context) >= 2) 965 { 966 if (!GetStringField(&Context, 2, &SubDirPart)) 967 goto cleanup; 968 } 969 if (!Concatenate(DirId, SubDirPart, NULL, &FullWorkingDir)) 970 goto cleanup; 971 MyFree(SubDirPart); 972 SubDirPart = NULL; 973 } 974 else 975 { 976 if (!Concatenate(FileDirId, FileSubDir, NULL, &FullWorkingDir)) 977 goto cleanup; 978 } 979 980 /* Read 'IconPath' entry */ 981 if (SetupFindFirstLineW(hInf, SectionName, IconPath, &Context)) 982 { 983 Index = 1; 984 if (!SetupGetIntField(&Context, Index++, &DirId)) 985 goto cleanup; 986 if (SetupGetFieldCount(&Context) >= 3) 987 { 988 if (!GetStringField(&Context, Index++, &SubDirPart)) 989 goto cleanup; 990 } 991 if (!GetStringField(&Context, Index, &NamePart)) 992 goto cleanup; 993 if (!Concatenate(DirId, SubDirPart, NamePart, &FullIconName)) 994 goto cleanup; 995 MyFree(SubDirPart); 996 MyFree(NamePart); 997 SubDirPart = NamePart = NULL; 998 } 999 else 1000 { 1001 FullIconName = pSetupDuplicateString(FullFileName); 1002 if (!FullIconName) 1003 goto cleanup; 1004 } 1005 1006 /* Read 'IconIndex' entry */ 1007 if (SetupFindFirstLineW(hInf, SectionName, IconIndex, &Context)) 1008 { 1009 if (!SetupGetIntField(&Context, 1, &IconIdx)) 1010 goto cleanup; 1011 } 1012 1013 /* Read 'HotKey' and 'InfoTip' entries */ 1014 GetLineText(hInf, SectionName, HotKey, &lpHotKey); 1015 GetLineText(hInf, SectionName, InfoTip, &lpInfoTip); 1016 1017 /* Read 'DisplayResource' entry */ 1018 if (SetupFindFirstLineW(hInf, SectionName, DisplayResource, &Context)) 1019 { 1020 if (!GetStringField(&Context, 1, &DisplayName)) 1021 goto cleanup; 1022 if (!SetupGetIntField(&Context, 2, &DisplayResId)) 1023 goto cleanup; 1024 } 1025 1026 /* Some debug */ 1027 TRACE("Link is %s\\%s, attributes 0x%x\n", debugstr_w(LinkSubDir), debugstr_w(LinkName), LinkAttributes); 1028 TRACE("File is %s\n", debugstr_w(FullFileName)); 1029 TRACE("Working dir %s\n", debugstr_w(FullWorkingDir)); 1030 TRACE("Icon is %s, %d\n", debugstr_w(FullIconName), IconIdx); 1031 TRACE("Hotkey %s\n", debugstr_w(lpHotKey)); 1032 TRACE("InfoTip %s\n", debugstr_w(lpInfoTip)); 1033 TRACE("Display %s, %d\n", DisplayName, DisplayResId); 1034 1035 /* Load ole32.dll */ 1036 hOle32 = LoadLibraryA("ole32.dll"); 1037 if (!hOle32) 1038 goto cleanup; 1039 pCoInitialize = (COINITIALIZE)GetProcAddress(hOle32, "CoInitialize"); 1040 if (!pCoInitialize) 1041 goto cleanup; 1042 pCoCreateInstance = (COCREATEINSTANCE)GetProcAddress(hOle32, "CoCreateInstance"); 1043 if (!pCoCreateInstance) 1044 goto cleanup; 1045 pCoUninitialize = (COUNINITIALIZE)GetProcAddress(hOle32, "CoUninitialize"); 1046 if (!pCoUninitialize) 1047 goto cleanup; 1048 1049 /* Create shortcut */ 1050 hr = pCoInitialize(NULL); 1051 if (!SUCCEEDED(hr)) 1052 { 1053 if (HRESULT_FACILITY(hr) == FACILITY_WIN32) 1054 SetLastError(HRESULT_CODE(hr)); 1055 else 1056 SetLastError(E_FAIL); 1057 goto cleanup; 1058 } 1059 hr = pCoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&psl); 1060 if (SUCCEEDED(hr)) 1061 { 1062 /* Fill link properties */ 1063 hr = IShellLinkW_SetPath(psl, FullFileName); 1064 if (SUCCEEDED(hr)) 1065 hr = IShellLinkW_SetArguments(psl, L""); 1066 if (SUCCEEDED(hr)) 1067 hr = IShellLinkW_SetWorkingDirectory(psl, FullWorkingDir); 1068 if (SUCCEEDED(hr)) 1069 hr = IShellLinkW_SetIconLocation(psl, FullIconName, IconIdx); 1070 if (SUCCEEDED(hr) && lpHotKey) 1071 FIXME("Need to store hotkey %s in shell link\n", debugstr_w(lpHotKey)); 1072 if (SUCCEEDED(hr) && lpInfoTip) 1073 hr = IShellLinkW_SetDescription(psl, lpInfoTip); 1074 if (SUCCEEDED(hr) && DisplayName) 1075 FIXME("Need to store display name %s, %d in shell link\n", debugstr_w(DisplayName), DisplayResId); 1076 if (SUCCEEDED(hr)) 1077 { 1078 hr = IShellLinkW_QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf); 1079 if (SUCCEEDED(hr)) 1080 { 1081 Required = (MAX_PATH + wcslen(LinkSubDir) + 1 + wcslen(LinkName)) * sizeof(WCHAR); 1082 FullLinkName = MyMalloc(Required); 1083 if (!FullLinkName) 1084 hr = E_OUTOFMEMORY; 1085 else 1086 { 1087 if (LinkAttributes & (FLG_PROFITEM_DELETE | FLG_PROFITEM_GROUP)) 1088 FIXME("Need to handle FLG_PROFITEM_DELETE and FLG_PROFITEM_GROUP\n"); 1089 if (LinkAttributes & FLG_PROFITEM_CSIDL) 1090 CSIDL = LinkFolder; 1091 else if (LinkAttributes & FLG_PROFITEM_CURRENTUSER) 1092 CSIDL = CSIDL_PROGRAMS; 1093 1094 if (SHGetSpecialFolderPathW( 1095 NULL, 1096 FullLinkName, 1097 CSIDL, 1098 TRUE)) 1099 { 1100 if (FullLinkName[wcslen(FullLinkName) - 1] != '\\') 1101 wcscat(FullLinkName, BackSlash); 1102 if (LinkSubDir) 1103 { 1104 wcscat(FullLinkName, LinkSubDir); 1105 if (FullLinkName[wcslen(FullLinkName) - 1] != '\\') 1106 wcscat(FullLinkName, BackSlash); 1107 } 1108 wcscat(FullLinkName, LinkName); 1109 wcscat(FullLinkName, DotLnk); 1110 hr = IPersistFile_Save(ppf, FullLinkName, TRUE); 1111 } 1112 else 1113 hr = HRESULT_FROM_WIN32(GetLastError()); 1114 } 1115 IPersistFile_Release(ppf); 1116 } 1117 } 1118 IShellLinkW_Release(psl); 1119 } 1120 pCoUninitialize(); 1121 if (SUCCEEDED(hr)) 1122 ret = TRUE; 1123 else 1124 { 1125 if (HRESULT_FACILITY(hr) == FACILITY_WIN32) 1126 SetLastError(HRESULT_CODE(hr)); 1127 else 1128 SetLastError(E_FAIL); 1129 } 1130 1131 cleanup: 1132 MyFree(LinkSubDir); 1133 MyFree(LinkName); 1134 MyFree(FileSubDir); 1135 MyFree(SubDirPart); 1136 MyFree(NamePart); 1137 MyFree(FullFileName); 1138 MyFree(FullWorkingDir); 1139 MyFree(FullIconName); 1140 MyFree(FullLinkName); 1141 MyFree(lpHotKey); 1142 MyFree(lpInfoTip); 1143 MyFree(DisplayName); 1144 if (hOle32) 1145 FreeLibrary(hOle32); 1146 1147 TRACE("Returning %d\n", ret); 1148 return ret; 1149 } 1150 1151 static BOOL copy_inf_callback( HINF hinf, PCWSTR field, void *arg ) 1152 { 1153 FIXME( "should do copy inf %s\n", debugstr_w(field) ); 1154 return TRUE; 1155 } 1156 1157 1158 /*********************************************************************** 1159 * iterate_section_fields 1160 * 1161 * Iterate over all fields of a certain key of a certain section 1162 */ 1163 static BOOL iterate_section_fields( HINF hinf, PCWSTR section, PCWSTR key, 1164 iterate_fields_func callback, void *arg ) 1165 { 1166 WCHAR static_buffer[200]; 1167 WCHAR *buffer = static_buffer; 1168 DWORD size = sizeof(static_buffer)/sizeof(WCHAR); 1169 INFCONTEXT context; 1170 BOOL ret = FALSE; 1171 1172 BOOL ok = SetupFindFirstLineW( hinf, section, key, &context ); 1173 while (ok) 1174 { 1175 UINT i, count = SetupGetFieldCount( &context ); 1176 for (i = 1; i <= count; i++) 1177 { 1178 if (!(buffer = get_field_string( &context, i, buffer, static_buffer, &size ))) 1179 goto done; 1180 if (!callback( hinf, buffer, arg )) 1181 { 1182 WARN("callback failed for %s %s err %d\n", 1183 debugstr_w(section), debugstr_w(buffer), GetLastError() ); 1184 goto done; 1185 } 1186 } 1187 ok = SetupFindNextMatchLineW( &context, key, &context ); 1188 } 1189 ret = TRUE; 1190 done: 1191 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer ); 1192 return ret; 1193 } 1194 1195 1196 /*********************************************************************** 1197 * SetupInstallFilesFromInfSectionA (SETUPAPI.@) 1198 */ 1199 BOOL WINAPI SetupInstallFilesFromInfSectionA( HINF hinf, HINF hlayout, HSPFILEQ queue, 1200 PCSTR section, PCSTR src_root, UINT flags ) 1201 { 1202 UNICODE_STRING sectionW; 1203 BOOL ret = FALSE; 1204 1205 if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section )) 1206 { 1207 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1208 return FALSE; 1209 } 1210 if (!src_root) 1211 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer, 1212 NULL, flags ); 1213 else 1214 { 1215 UNICODE_STRING srcW; 1216 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root )) 1217 { 1218 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer, 1219 srcW.Buffer, flags ); 1220 RtlFreeUnicodeString( &srcW ); 1221 } 1222 else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1223 } 1224 RtlFreeUnicodeString( §ionW ); 1225 return ret; 1226 } 1227 1228 1229 /*********************************************************************** 1230 * SetupInstallFilesFromInfSectionW (SETUPAPI.@) 1231 */ 1232 BOOL WINAPI SetupInstallFilesFromInfSectionW( HINF hinf, HINF hlayout, HSPFILEQ queue, 1233 PCWSTR section, PCWSTR src_root, UINT flags ) 1234 { 1235 struct files_callback_info info; 1236 1237 info.queue = queue; 1238 info.src_root = src_root; 1239 info.copy_flags = flags; 1240 info.layout = hlayout; 1241 return iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ); 1242 } 1243 1244 1245 /*********************************************************************** 1246 * SetupInstallFromInfSectionA (SETUPAPI.@) 1247 */ 1248 BOOL WINAPI SetupInstallFromInfSectionA( HWND owner, HINF hinf, PCSTR section, UINT flags, 1249 HKEY key_root, PCSTR src_root, UINT copy_flags, 1250 PSP_FILE_CALLBACK_A callback, PVOID context, 1251 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data ) 1252 { 1253 UNICODE_STRING sectionW, src_rootW; 1254 struct callback_WtoA_context ctx; 1255 BOOL ret = FALSE; 1256 1257 src_rootW.Buffer = NULL; 1258 if (src_root && !RtlCreateUnicodeStringFromAsciiz( &src_rootW, src_root )) 1259 { 1260 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1261 return FALSE; 1262 } 1263 1264 if (RtlCreateUnicodeStringFromAsciiz( §ionW, section )) 1265 { 1266 ctx.orig_context = context; 1267 ctx.orig_handler = callback; 1268 ret = SetupInstallFromInfSectionW( owner, hinf, sectionW.Buffer, flags, key_root, 1269 src_rootW.Buffer, copy_flags, QUEUE_callback_WtoA, 1270 &ctx, devinfo, devinfo_data ); 1271 RtlFreeUnicodeString( §ionW ); 1272 } 1273 else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1274 1275 RtlFreeUnicodeString( &src_rootW ); 1276 return ret; 1277 } 1278 1279 1280 /*********************************************************************** 1281 * include_callback 1282 * 1283 * Called once for each Include entry in a given section. 1284 */ 1285 static BOOL include_callback( HINF hinf, PCWSTR field, void *arg ) 1286 { 1287 return SetupOpenAppendInfFileW( field, hinf, NULL ); 1288 } 1289 1290 1291 /*********************************************************************** 1292 * needs_callback 1293 * 1294 * Called once for each Needs entry in a given section. 1295 */ 1296 static BOOL needs_callback( HINF hinf, PCWSTR field, void *arg ) 1297 { 1298 struct needs_callback_info *info = arg; 1299 1300 switch (info->type) 1301 { 1302 case 0: 1303 return SetupInstallFromInfSectionW(info->owner, *(HINF*)hinf, field, info->flags, 1304 info->key_root, info->src_root, info->copy_flags, info->callback, 1305 info->context, info->devinfo, info->devinfo_data); 1306 case 1: 1307 return SetupInstallServicesFromInfSectionExW(*(HINF*)hinf, field, info->flags, 1308 info->devinfo, info->devinfo_data, info->reserved1, info->reserved2); 1309 default: 1310 ERR("Unknown info type %u\n", info->type); 1311 return FALSE; 1312 } 1313 } 1314 1315 1316 /*********************************************************************** 1317 * SetupInstallFromInfSectionW (SETUPAPI.@) 1318 */ 1319 BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section, UINT flags, 1320 HKEY key_root, PCWSTR src_root, UINT copy_flags, 1321 PSP_FILE_CALLBACK_W callback, PVOID context, 1322 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data ) 1323 { 1324 struct needs_callback_info needs_info; 1325 1326 /* Parse 'Include' and 'Needs' directives */ 1327 iterate_section_fields( hinf, section, Include, include_callback, NULL); 1328 needs_info.type = 0; 1329 needs_info.owner = owner; 1330 needs_info.flags = flags; 1331 needs_info.key_root = key_root; 1332 needs_info.src_root = src_root; 1333 needs_info.copy_flags = copy_flags; 1334 needs_info.callback = callback; 1335 needs_info.context = context; 1336 needs_info.devinfo = devinfo; 1337 needs_info.devinfo_data = devinfo_data; 1338 iterate_section_fields( hinf, section, Needs, needs_callback, &needs_info); 1339 1340 if (flags & SPINST_FILES) 1341 { 1342 SP_DEVINSTALL_PARAMS_W install_params; 1343 struct files_callback_info info; 1344 HSPFILEQ queue = NULL; 1345 BOOL use_custom_queue; 1346 BOOL ret; 1347 1348 install_params.cbSize = sizeof(SP_DEVINSTALL_PARAMS); 1349 use_custom_queue = SetupDiGetDeviceInstallParamsW(devinfo, devinfo_data, &install_params) && (install_params.Flags & DI_NOVCP); 1350 if (!use_custom_queue && ((queue = SetupOpenFileQueue()) == (HSPFILEQ)INVALID_HANDLE_VALUE )) 1351 return FALSE; 1352 info.queue = use_custom_queue ? install_params.FileQueue : queue; 1353 info.src_root = src_root; 1354 info.copy_flags = copy_flags; 1355 info.layout = hinf; 1356 ret = (iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ) && 1357 iterate_section_fields( hinf, section, DelFiles, delete_files_callback, &info ) && 1358 iterate_section_fields( hinf, section, RenFiles, rename_files_callback, &info )); 1359 if (!use_custom_queue) 1360 { 1361 if (ret) 1362 ret = SetupCommitFileQueueW( owner, queue, callback, context ); 1363 SetupCloseFileQueue( queue ); 1364 } 1365 if (!ret) return FALSE; 1366 } 1367 if (flags & SPINST_INIFILES) 1368 { 1369 if (!iterate_section_fields( hinf, section, UpdateInis, update_ini_callback, NULL ) || 1370 !iterate_section_fields( hinf, section, UpdateIniFields, 1371 update_ini_fields_callback, NULL )) 1372 return FALSE; 1373 } 1374 if (flags & SPINST_INI2REG) 1375 { 1376 if (!iterate_section_fields( hinf, section, Ini2Reg, ini2reg_callback, NULL )) 1377 return FALSE; 1378 } 1379 if (flags & SPINST_LOGCONFIG) 1380 { 1381 if (!iterate_section_fields( hinf, section, LogConf, logconf_callback, NULL )) 1382 return FALSE; 1383 } 1384 if (flags & SPINST_REGSVR) 1385 { 1386 struct register_dll_info info; 1387 1388 info.unregister = FALSE; 1389 if (flags & SPINST_REGISTERCALLBACKAWARE) 1390 { 1391 info.callback = callback; 1392 info.callback_context = context; 1393 } 1394 else info.callback = NULL; 1395 1396 if (!iterate_section_fields( hinf, section, RegisterDlls, register_dlls_callback, &info )) 1397 return FALSE; 1398 1399 #ifdef __WINESRC__ 1400 if (!iterate_section_fields( hinf, section, WineFakeDlls, fake_dlls_callback, NULL )) 1401 return FALSE; 1402 #endif // __WINESRC__ 1403 } 1404 if (flags & SPINST_UNREGSVR) 1405 { 1406 struct register_dll_info info; 1407 1408 info.unregister = TRUE; 1409 if (flags & SPINST_REGISTERCALLBACKAWARE) 1410 { 1411 info.callback = callback; 1412 info.callback_context = context; 1413 } 1414 else info.callback = NULL; 1415 1416 if (!iterate_section_fields( hinf, section, UnregisterDlls, register_dlls_callback, &info )) 1417 return FALSE; 1418 } 1419 if (flags & SPINST_REGISTRY) 1420 { 1421 struct registry_callback_info info; 1422 1423 info.default_root = key_root; 1424 info.delete = TRUE; 1425 if (!iterate_section_fields( hinf, section, DelReg, registry_callback, &info )) 1426 return FALSE; 1427 info.delete = FALSE; 1428 if (!iterate_section_fields( hinf, section, AddReg, registry_callback, &info )) 1429 return FALSE; 1430 } 1431 if (flags & SPINST_BITREG) 1432 { 1433 if (!iterate_section_fields( hinf, section, BitReg, bitreg_callback, NULL )) 1434 return FALSE; 1435 } 1436 if (flags & SPINST_PROFILEITEMS) 1437 { 1438 if (!iterate_section_fields( hinf, section, ProfileItems, profile_items_callback, NULL )) 1439 return FALSE; 1440 } 1441 if (flags & SPINST_COPYINF) 1442 { 1443 if (!iterate_section_fields( hinf, section, CopyINF, copy_inf_callback, NULL )) 1444 return FALSE; 1445 } 1446 1447 return TRUE; 1448 } 1449 1450 1451 /*********************************************************************** 1452 * InstallHinfSectionW (SETUPAPI.@) 1453 * 1454 * NOTE: 'cmdline' is <section> <mode> <path> from 1455 * RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection <section> <mode> <path> 1456 */ 1457 void WINAPI InstallHinfSectionW( HWND hwnd, HINSTANCE handle, LPCWSTR cmdline, INT show ) 1458 { 1459 WCHAR *s, *path, section[MAX_PATH]; 1460 void *callback_context = NULL; 1461 DWORD SectionNameLength; 1462 UINT mode; 1463 HINF hinf = INVALID_HANDLE_VALUE; 1464 BOOL bRebootRequired = FALSE; 1465 BOOL ret; 1466 1467 TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd, handle, debugstr_w(cmdline)); 1468 1469 lstrcpynW( section, cmdline, MAX_PATH ); 1470 1471 if (!(s = strchrW( section, ' ' ))) return; 1472 *s++ = 0; 1473 while (*s == ' ') s++; 1474 mode = atoiW( s ); 1475 1476 /* quoted paths are not allowed on native, the rest of the command line is taken as the path */ 1477 if (!(s = strchrW( s, ' ' ))) return; 1478 while (*s == ' ') s++; 1479 path = s; 1480 1481 if (mode & 0x80) 1482 { 1483 FIXME("default path of the installation not changed\n"); 1484 mode &= ~0x80; 1485 } 1486 1487 hinf = SetupOpenInfFileW( path, NULL, INF_STYLE_WIN4, NULL ); 1488 if (hinf == INVALID_HANDLE_VALUE) 1489 { 1490 WARN("SetupOpenInfFileW(%s) failed (Error %u)\n", path, GetLastError()); 1491 goto cleanup; 1492 } 1493 1494 ret = SetupDiGetActualSectionToInstallW( 1495 hinf, section, section, sizeof(section)/sizeof(section[0]), &SectionNameLength, NULL ); 1496 if (!ret) 1497 { 1498 WARN("SetupDiGetActualSectionToInstallW() failed (Error %u)\n", GetLastError()); 1499 goto cleanup; 1500 } 1501 if (SectionNameLength > MAX_PATH - strlenW(DotServices)) 1502 { 1503 WARN("Section name '%s' too long\n", section); 1504 goto cleanup; 1505 } 1506 1507 /* Copy files and add registry entries */ 1508 callback_context = SetupInitDefaultQueueCallback( hwnd ); 1509 ret = SetupInstallFromInfSectionW( hwnd, hinf, section, SPINST_ALL, NULL, NULL, 1510 SP_COPY_NEWER | SP_COPY_IN_USE_NEEDS_REBOOT, 1511 SetupDefaultQueueCallbackW, callback_context, 1512 NULL, NULL ); 1513 if (!ret) 1514 { 1515 WARN("SetupInstallFromInfSectionW() failed (Error %u)\n", GetLastError()); 1516 goto cleanup; 1517 } 1518 /* FIXME: need to check if some files were in use and need reboot 1519 * bReboot = ...; 1520 */ 1521 1522 /* Install services */ 1523 wcscat(section, DotServices); 1524 ret = SetupInstallServicesFromInfSectionW( hinf, section, 0 ); 1525 if (!ret && GetLastError() == ERROR_SECTION_NOT_FOUND) 1526 ret = TRUE; 1527 if (!ret) 1528 { 1529 WARN("SetupInstallServicesFromInfSectionW() failed (Error %u)\n", GetLastError()); 1530 goto cleanup; 1531 } 1532 else if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED) 1533 { 1534 bRebootRequired = TRUE; 1535 } 1536 1537 /* Check if we need to reboot */ 1538 switch (mode) 1539 { 1540 case 0: 1541 /* Never reboot */ 1542 break; 1543 case 1: 1544 /* Always reboot */ 1545 ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_APPLICATION | 1546 SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED); 1547 break; 1548 case 2: 1549 /* Query user before rebooting */ 1550 SetupPromptReboot(NULL, hwnd, FALSE); 1551 break; 1552 case 3: 1553 /* Reboot if necessary */ 1554 if (bRebootRequired) 1555 { 1556 ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_APPLICATION | 1557 SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED); 1558 } 1559 break; 1560 case 4: 1561 /* If necessary, query user before rebooting */ 1562 if (bRebootRequired) 1563 { 1564 SetupPromptReboot(NULL, hwnd, FALSE); 1565 } 1566 break; 1567 default: 1568 break; 1569 } 1570 1571 cleanup: 1572 if ( callback_context ) 1573 SetupTermDefaultQueueCallback( callback_context ); 1574 if ( hinf != INVALID_HANDLE_VALUE ) 1575 SetupCloseInfFile( hinf ); 1576 } 1577 1578 1579 /*********************************************************************** 1580 * InstallHinfSectionA (SETUPAPI.@) 1581 */ 1582 void WINAPI InstallHinfSectionA( HWND hwnd, HINSTANCE handle, LPCSTR cmdline, INT show ) 1583 { 1584 UNICODE_STRING cmdlineW; 1585 1586 if (RtlCreateUnicodeStringFromAsciiz( &cmdlineW, cmdline )) 1587 { 1588 InstallHinfSectionW( hwnd, handle, cmdlineW.Buffer, show ); 1589 RtlFreeUnicodeString( &cmdlineW ); 1590 } 1591 } 1592 1593 /*********************************************************************** 1594 * SetupInstallServicesFromInfSectionW (SETUPAPI.@) 1595 */ 1596 BOOL WINAPI SetupInstallServicesFromInfSectionW( HINF Inf, PCWSTR SectionName, DWORD Flags) 1597 { 1598 return SetupInstallServicesFromInfSectionExW( Inf, SectionName, Flags, 1599 NULL, NULL, NULL, NULL ); 1600 } 1601 1602 /*********************************************************************** 1603 * SetupInstallServicesFromInfSectionA (SETUPAPI.@) 1604 */ 1605 BOOL WINAPI SetupInstallServicesFromInfSectionA( HINF Inf, PCSTR SectionName, DWORD Flags) 1606 { 1607 return SetupInstallServicesFromInfSectionExA( Inf, SectionName, Flags, 1608 NULL, NULL, NULL, NULL ); 1609 } 1610 1611 /*********************************************************************** 1612 * SetupInstallServicesFromInfSectionExA (SETUPAPI.@) 1613 */ 1614 BOOL WINAPI SetupInstallServicesFromInfSectionExA( HINF hinf, PCSTR sectionname, DWORD flags, HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data, PVOID reserved1, PVOID reserved2 ) 1615 { 1616 UNICODE_STRING sectionnameW; 1617 BOOL ret = FALSE; 1618 1619 if (RtlCreateUnicodeStringFromAsciiz( §ionnameW, sectionname )) 1620 { 1621 ret = SetupInstallServicesFromInfSectionExW( hinf, sectionnameW.Buffer, flags, devinfo, devinfo_data, reserved1, reserved2 ); 1622 RtlFreeUnicodeString( §ionnameW ); 1623 } 1624 else 1625 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1626 1627 return ret; 1628 } 1629 1630 1631 static BOOL GetLineText( HINF hinf, PCWSTR section_name, PCWSTR key_name, PWSTR *value) 1632 { 1633 DWORD required; 1634 PWSTR buf = NULL; 1635 1636 *value = NULL; 1637 1638 if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, NULL, 0, &required ) 1639 && GetLastError() != ERROR_INSUFFICIENT_BUFFER ) 1640 return FALSE; 1641 1642 buf = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) ); 1643 if ( ! buf ) 1644 { 1645 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1646 return FALSE; 1647 } 1648 1649 if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, buf, required, &required ) ) 1650 { 1651 HeapFree( GetProcessHeap(), 0, buf ); 1652 return FALSE; 1653 } 1654 1655 *value = buf; 1656 return TRUE; 1657 } 1658 1659 1660 static BOOL GetIntField( HINF hinf, PCWSTR section_name, PCWSTR key_name, INT *value) 1661 { 1662 LPWSTR buffer, end; 1663 INT res; 1664 1665 if (! GetLineText( hinf, section_name, key_name, &buffer ) ) 1666 return FALSE; 1667 1668 res = wcstol( buffer, &end, 0 ); 1669 if (end != buffer && !*end) 1670 { 1671 HeapFree(GetProcessHeap(), 0, buffer); 1672 *value = res; 1673 return TRUE; 1674 } 1675 else 1676 { 1677 HeapFree(GetProcessHeap(), 0, buffer); 1678 SetLastError( ERROR_INVALID_DATA ); 1679 return FALSE; 1680 } 1681 } 1682 1683 1684 BOOL GetStringField( PINFCONTEXT context, DWORD index, PWSTR *value) 1685 { 1686 DWORD RequiredSize; 1687 BOOL ret; 1688 1689 ret = SetupGetStringFieldW( 1690 context, 1691 index, 1692 NULL, 0, 1693 &RequiredSize); 1694 if (!ret) 1695 return FALSE; 1696 else if (RequiredSize == 0) 1697 { 1698 *value = NULL; 1699 return TRUE; 1700 } 1701 1702 /* We got the needed size for the buffer */ 1703 *value = MyMalloc(RequiredSize * sizeof(WCHAR)); 1704 if (!*value) 1705 { 1706 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1707 return FALSE; 1708 } 1709 ret = SetupGetStringFieldW( 1710 context, 1711 index, 1712 *value, RequiredSize, NULL); 1713 if (!ret) 1714 MyFree(*value); 1715 1716 return ret; 1717 } 1718 1719 static VOID FixupServiceBinaryPath( 1720 IN DWORD ServiceType, 1721 IN OUT LPWSTR *ServiceBinary) 1722 { 1723 LPWSTR Buffer; 1724 WCHAR ReactosDir[MAX_PATH]; 1725 DWORD RosDirLength, ServiceLength, Win32Length; 1726 1727 GetWindowsDirectoryW(ReactosDir, MAX_PATH); 1728 RosDirLength = strlenW(ReactosDir); 1729 ServiceLength = strlenW(*ServiceBinary); 1730 1731 /* Check and fix two things: 1732 1. Get rid of C:\ReactOS and use relative 1733 path instead. 1734 2. Add %SystemRoot% for Win32 services */ 1735 1736 if (ServiceLength < RosDirLength) 1737 return; 1738 1739 if (!wcsnicmp(*ServiceBinary, ReactosDir, RosDirLength)) 1740 { 1741 /* Yes, the first part is the C:\ReactOS\, just skip it */ 1742 MoveMemory(*ServiceBinary, *ServiceBinary + RosDirLength + 1, 1743 (ServiceLength - RosDirLength) * sizeof(WCHAR)); 1744 1745 /* Handle Win32-services differently */ 1746 if (ServiceType & SERVICE_WIN32) 1747 { 1748 Win32Length = (ServiceLength - 1749 RosDirLength - 1 + 13) * sizeof(WCHAR); 1750 /* -1 to not count the separator after C:\ReactOS 1751 wcslen(L"%SystemRoot%\\") = 13*sizeof(wchar_t) */ 1752 Buffer = MyMalloc(Win32Length); 1753 1754 wcscpy(Buffer, L"%SystemRoot%\\"); 1755 wcscat(Buffer, *ServiceBinary); 1756 MyFree(*ServiceBinary); 1757 1758 *ServiceBinary = Buffer; 1759 } 1760 } 1761 } 1762 1763 static BOOL InstallOneService( 1764 struct DeviceInfoSet *list, 1765 IN HINF hInf, 1766 IN LPCWSTR ServiceSection, 1767 IN LPCWSTR ServiceName, 1768 IN UINT ServiceFlags) 1769 { 1770 SC_HANDLE hSCManager = NULL; 1771 SC_HANDLE hService = NULL; 1772 LPDWORD GroupOrder = NULL; 1773 LPQUERY_SERVICE_CONFIGW ServiceConfig = NULL; 1774 HKEY hServicesKey, hServiceKey; 1775 LONG rc; 1776 BOOL ret = FALSE; 1777 1778 HKEY hGroupOrderListKey = NULL; 1779 LPWSTR ServiceBinary = NULL; 1780 LPWSTR LoadOrderGroup = NULL; 1781 LPWSTR DisplayName = NULL; 1782 LPWSTR Description = NULL; 1783 LPWSTR Dependencies = NULL; 1784 LPWSTR SecurityDescriptor = NULL; 1785 PSECURITY_DESCRIPTOR sd = NULL; 1786 INT ServiceType, StartType, ErrorControl; 1787 DWORD dwRegType; 1788 DWORD tagId = (DWORD)-1; 1789 BOOL useTag; 1790 1791 if (!GetIntField(hInf, ServiceSection, ServiceTypeKey, &ServiceType)) 1792 goto cleanup; 1793 if (!GetIntField(hInf, ServiceSection, StartTypeKey, &StartType)) 1794 goto cleanup; 1795 if (!GetIntField(hInf, ServiceSection, ErrorControlKey, &ErrorControl)) 1796 goto cleanup; 1797 useTag = (ServiceType == SERVICE_BOOT_START || ServiceType == SERVICE_SYSTEM_START); 1798 1799 hSCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE); 1800 if (hSCManager == NULL) 1801 goto cleanup; 1802 1803 if (!GetLineText(hInf, ServiceSection, ServiceBinaryKey, &ServiceBinary)) 1804 goto cleanup; 1805 1806 /* Adjust binary path according to the service type */ 1807 FixupServiceBinaryPath(ServiceType, &ServiceBinary); 1808 1809 /* Don't check return value, as these fields are optional and 1810 * GetLineText initialize output parameter even on failure */ 1811 GetLineText(hInf, ServiceSection, LoadOrderGroupKey, &LoadOrderGroup); 1812 GetLineText(hInf, ServiceSection, DisplayNameKey, &DisplayName); 1813 GetLineText(hInf, ServiceSection, DescriptionKey, &Description); 1814 GetLineText(hInf, ServiceSection, DependenciesKey, &Dependencies); 1815 1816 /* If there is no group, we must not request a tag */ 1817 if (!LoadOrderGroup || !*LoadOrderGroup) 1818 useTag = FALSE; 1819 1820 hService = OpenServiceW( 1821 hSCManager, 1822 ServiceName, 1823 DELETE | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | WRITE_DAC); 1824 if (hService == NULL && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) 1825 goto cleanup; 1826 1827 if (hService && (ServiceFlags & SPSVCINST_DELETEEVENTLOGENTRY)) 1828 { 1829 ret = DeleteService(hService); 1830 if (!ret && GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE) 1831 goto cleanup; 1832 } 1833 1834 if (hService == NULL) 1835 { 1836 /* Create new service */ 1837 hService = CreateServiceW( 1838 hSCManager, 1839 ServiceName, 1840 DisplayName, 1841 WRITE_DAC, 1842 ServiceType, 1843 StartType, 1844 ErrorControl, 1845 ServiceBinary, 1846 LoadOrderGroup, 1847 useTag ? &tagId : NULL, 1848 Dependencies, 1849 NULL, NULL); 1850 if (hService == NULL) 1851 goto cleanup; 1852 } 1853 else 1854 { 1855 DWORD bufferSize; 1856 /* Read current configuration */ 1857 if (!QueryServiceConfigW(hService, NULL, 0, &bufferSize)) 1858 { 1859 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 1860 goto cleanup; 1861 ServiceConfig = MyMalloc(bufferSize); 1862 if (!ServiceConfig) 1863 { 1864 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1865 goto cleanup; 1866 } 1867 if (!QueryServiceConfigW(hService, ServiceConfig, bufferSize, &bufferSize)) 1868 goto cleanup; 1869 } 1870 tagId = ServiceConfig->dwTagId; 1871 1872 /* Update configuration */ 1873 ret = ChangeServiceConfigW( 1874 hService, 1875 ServiceType, 1876 (ServiceFlags & SPSVCINST_NOCLOBBER_STARTTYPE) ? SERVICE_NO_CHANGE : StartType, 1877 (ServiceFlags & SPSVCINST_NOCLOBBER_ERRORCONTROL) ? SERVICE_NO_CHANGE : ErrorControl, 1878 ServiceBinary, 1879 (ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP && ServiceConfig->lpLoadOrderGroup) ? NULL : LoadOrderGroup, 1880 useTag ? &tagId : NULL, 1881 (ServiceFlags & SPSVCINST_NOCLOBBER_DEPENDENCIES && ServiceConfig->lpDependencies) ? NULL : Dependencies, 1882 NULL, NULL, 1883 (ServiceFlags & SPSVCINST_NOCLOBBER_DISPLAYNAME && ServiceConfig->lpDisplayName) ? NULL : DisplayName); 1884 if (!ret) 1885 goto cleanup; 1886 } 1887 1888 /* Set security */ 1889 if (GetLineText(hInf, ServiceSection, SecurityKey, &SecurityDescriptor)) 1890 { 1891 ret = ConvertStringSecurityDescriptorToSecurityDescriptorW(SecurityDescriptor, SDDL_REVISION_1, &sd, NULL); 1892 if (!ret) 1893 goto cleanup; 1894 ret = SetServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, sd); 1895 if (!ret) 1896 goto cleanup; 1897 } 1898 1899 /* FIXME: use Description and SPSVCINST_NOCLOBBER_DESCRIPTION */ 1900 1901 if (useTag) 1902 { 1903 /* Add the tag to SYSTEM\CurrentControlSet\Control\GroupOrderList key */ 1904 LPCWSTR lpLoadOrderGroup; 1905 DWORD bufferSize; 1906 1907 lpLoadOrderGroup = LoadOrderGroup; 1908 if ((ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP) && ServiceConfig && ServiceConfig->lpLoadOrderGroup) 1909 lpLoadOrderGroup = ServiceConfig->lpLoadOrderGroup; 1910 1911 rc = RegOpenKeyW( 1912 list ? list->HKLM : HKEY_LOCAL_MACHINE, 1913 GroupOrderListKey, 1914 &hGroupOrderListKey); 1915 if (rc != ERROR_SUCCESS) 1916 { 1917 SetLastError(rc); 1918 goto cleanup; 1919 } 1920 rc = RegQueryValueExW(hGroupOrderListKey, lpLoadOrderGroup, NULL, &dwRegType, NULL, &bufferSize); 1921 if (rc == ERROR_FILE_NOT_FOUND) 1922 bufferSize = sizeof(DWORD); 1923 else if (rc != ERROR_SUCCESS) 1924 { 1925 SetLastError(rc); 1926 goto cleanup; 1927 } 1928 else if (dwRegType != REG_BINARY || bufferSize == 0 || bufferSize % sizeof(DWORD) != 0) 1929 { 1930 SetLastError(ERROR_GEN_FAILURE); 1931 goto cleanup; 1932 } 1933 /* Allocate buffer to store existing data + the new tag */ 1934 GroupOrder = MyMalloc(bufferSize + sizeof(DWORD)); 1935 if (!GroupOrder) 1936 { 1937 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1938 goto cleanup; 1939 } 1940 if (rc == ERROR_SUCCESS) 1941 { 1942 /* Read existing data */ 1943 rc = RegQueryValueExW( 1944 hGroupOrderListKey, 1945 lpLoadOrderGroup, 1946 NULL, 1947 NULL, 1948 (BYTE*)GroupOrder, 1949 &bufferSize); 1950 if (rc != ERROR_SUCCESS) 1951 { 1952 SetLastError(rc); 1953 goto cleanup; 1954 } 1955 if (ServiceFlags & SPSVCINST_TAGTOFRONT) 1956 memmove(&GroupOrder[2], &GroupOrder[1], bufferSize - sizeof(DWORD)); 1957 } 1958 else 1959 { 1960 GroupOrder[0] = 0; 1961 } 1962 GroupOrder[0]++; 1963 if (ServiceFlags & SPSVCINST_TAGTOFRONT) 1964 GroupOrder[1] = tagId; 1965 else 1966 GroupOrder[bufferSize / sizeof(DWORD)] = tagId; 1967 1968 rc = RegSetValueExW( 1969 hGroupOrderListKey, 1970 lpLoadOrderGroup, 1971 0, 1972 REG_BINARY, 1973 (BYTE*)GroupOrder, 1974 bufferSize + sizeof(DWORD)); 1975 if (rc != ERROR_SUCCESS) 1976 { 1977 SetLastError(rc); 1978 goto cleanup; 1979 } 1980 } 1981 1982 /* Handle AddReg and DelReg */ 1983 rc = RegOpenKeyExW( 1984 list ? list->HKLM : HKEY_LOCAL_MACHINE, 1985 REGSTR_PATH_SERVICES, 1986 0, 1987 0, 1988 &hServicesKey); 1989 if (rc != ERROR_SUCCESS) 1990 { 1991 SetLastError(rc); 1992 goto cleanup; 1993 } 1994 rc = RegOpenKeyExW( 1995 hServicesKey, 1996 ServiceName, 1997 0, 1998 KEY_READ | KEY_WRITE, 1999 &hServiceKey); 2000 RegCloseKey(hServicesKey); 2001 if (rc != ERROR_SUCCESS) 2002 { 2003 SetLastError(rc); 2004 goto cleanup; 2005 } 2006 2007 ret = SetupInstallFromInfSectionW( 2008 NULL, 2009 hInf, 2010 ServiceSection, 2011 SPINST_REGISTRY, 2012 hServiceKey, 2013 NULL, 2014 0, 2015 NULL, 2016 NULL, 2017 NULL, 2018 NULL); 2019 RegCloseKey(hServiceKey); 2020 2021 cleanup: 2022 if (hSCManager != NULL) 2023 CloseServiceHandle(hSCManager); 2024 if (hService != NULL) 2025 CloseServiceHandle(hService); 2026 if (hGroupOrderListKey != NULL) 2027 RegCloseKey(hGroupOrderListKey); 2028 if (sd != NULL) 2029 LocalFree(sd); 2030 MyFree(ServiceConfig); 2031 MyFree(ServiceBinary); 2032 MyFree(LoadOrderGroup); 2033 MyFree(DisplayName); 2034 MyFree(Description); 2035 MyFree(Dependencies); 2036 MyFree(SecurityDescriptor); 2037 MyFree(GroupOrder); 2038 2039 TRACE("Returning %d\n", ret); 2040 return ret; 2041 } 2042 2043 2044 /*********************************************************************** 2045 * SetupInstallServicesFromInfSectionExW (SETUPAPI.@) 2046 */ 2047 BOOL WINAPI SetupInstallServicesFromInfSectionExW( HINF hinf, PCWSTR sectionname, DWORD flags, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PVOID reserved1, PVOID reserved2 ) 2048 { 2049 struct DeviceInfoSet *list = NULL; 2050 BOOL ret = FALSE; 2051 2052 TRACE("%p, %s, 0x%lx, %p, %p, %p, %p\n", hinf, debugstr_w(sectionname), 2053 flags, DeviceInfoSet, DeviceInfoData, reserved1, reserved2); 2054 2055 if (!sectionname) 2056 SetLastError(ERROR_INVALID_PARAMETER); 2057 else if (flags & ~(SPSVCINST_TAGTOFRONT | SPSVCINST_DELETEEVENTLOGENTRY | SPSVCINST_NOCLOBBER_DISPLAYNAME | SPSVCINST_NOCLOBBER_STARTTYPE | SPSVCINST_NOCLOBBER_ERRORCONTROL | SPSVCINST_NOCLOBBER_LOADORDERGROUP | SPSVCINST_NOCLOBBER_DEPENDENCIES | SPSVCINST_STOPSERVICE)) 2058 { 2059 TRACE("Unknown flags: 0x%08lx\n", flags & ~(SPSVCINST_TAGTOFRONT | SPSVCINST_DELETEEVENTLOGENTRY | SPSVCINST_NOCLOBBER_DISPLAYNAME | SPSVCINST_NOCLOBBER_STARTTYPE | SPSVCINST_NOCLOBBER_ERRORCONTROL | SPSVCINST_NOCLOBBER_LOADORDERGROUP | SPSVCINST_NOCLOBBER_DEPENDENCIES | SPSVCINST_STOPSERVICE)); 2060 SetLastError(ERROR_INVALID_FLAGS); 2061 } 2062 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE) 2063 SetLastError(ERROR_INVALID_HANDLE); 2064 else if (DeviceInfoSet && (list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC) 2065 SetLastError(ERROR_INVALID_HANDLE); 2066 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) 2067 SetLastError(ERROR_INVALID_USER_BUFFER); 2068 else if (reserved1 != NULL || reserved2 != NULL) 2069 SetLastError(ERROR_INVALID_PARAMETER); 2070 else 2071 { 2072 struct needs_callback_info needs_info; 2073 LPWSTR ServiceName = NULL; 2074 LPWSTR ServiceSection = NULL; 2075 INT ServiceFlags; 2076 INFCONTEXT ContextService; 2077 BOOL bNeedReboot = FALSE; 2078 2079 /* Parse 'Include' and 'Needs' directives */ 2080 iterate_section_fields( hinf, sectionname, Include, include_callback, NULL); 2081 needs_info.type = 1; 2082 needs_info.flags = flags; 2083 needs_info.devinfo = DeviceInfoSet; 2084 needs_info.devinfo_data = DeviceInfoData; 2085 needs_info.reserved1 = reserved1; 2086 needs_info.reserved2 = reserved2; 2087 iterate_section_fields( hinf, sectionname, Needs, needs_callback, &needs_info); 2088 2089 if (flags & SPSVCINST_STOPSERVICE) 2090 { 2091 FIXME("Stopping the device not implemented\n"); 2092 /* This may lead to require a reboot */ 2093 /* bNeedReboot = TRUE; */ 2094 #if 0 2095 SERVICE_STATUS ServiceStatus; 2096 ret = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus); 2097 if (!ret && GetLastError() != ERROR_SERVICE_NOT_ACTIVE) 2098 goto cleanup; 2099 if (ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING && ServiceStatus.dwCurrentState != SERVICE_STOPPED) 2100 { 2101 SetLastError(ERROR_INSTALL_SERVICE_FAILURE); 2102 goto cleanup; 2103 } 2104 #endif 2105 flags &= ~SPSVCINST_STOPSERVICE; 2106 } 2107 2108 ret = SetupFindFirstLineW(hinf, sectionname, AddService, &ContextService); 2109 while (ret) 2110 { 2111 if (!GetStringField(&ContextService, 1, &ServiceName)) 2112 goto nextservice; 2113 2114 ret = SetupGetIntField( 2115 &ContextService, 2116 2, /* Field index */ 2117 &ServiceFlags); 2118 if (!ret) 2119 { 2120 /* The field may be empty. Ignore the error */ 2121 ServiceFlags = 0; 2122 } 2123 2124 if (!GetStringField(&ContextService, 3, &ServiceSection)) 2125 goto nextservice; 2126 2127 ret = InstallOneService(list, hinf, ServiceSection, ServiceName, (ServiceFlags & ~SPSVCINST_ASSOCSERVICE) | flags); 2128 if (!ret) 2129 goto nextservice; 2130 2131 if (ServiceFlags & SPSVCINST_ASSOCSERVICE) 2132 { 2133 ret = SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet, DeviceInfoData, SPDRP_SERVICE, (LPBYTE)ServiceName, (strlenW(ServiceName) + 1) * sizeof(WCHAR)); 2134 if (!ret) 2135 goto nextservice; 2136 } 2137 2138 nextservice: 2139 HeapFree(GetProcessHeap(), 0, ServiceName); 2140 HeapFree(GetProcessHeap(), 0, ServiceSection); 2141 ServiceName = ServiceSection = NULL; 2142 ret = SetupFindNextMatchLineW(&ContextService, AddService, &ContextService); 2143 } 2144 2145 if (bNeedReboot) 2146 SetLastError(ERROR_SUCCESS_REBOOT_REQUIRED); 2147 else 2148 SetLastError(ERROR_SUCCESS); 2149 ret = TRUE; 2150 } 2151 2152 TRACE("Returning %d\n", ret); 2153 return ret; 2154 } 2155 2156 2157 /*********************************************************************** 2158 * SetupCopyOEMInfA (SETUPAPI.@) 2159 */ 2160 BOOL WINAPI SetupCopyOEMInfA( 2161 IN PCSTR SourceInfFileName, 2162 IN PCSTR OEMSourceMediaLocation, 2163 IN DWORD OEMSourceMediaType, 2164 IN DWORD CopyStyle, 2165 OUT PSTR DestinationInfFileName OPTIONAL, 2166 IN DWORD DestinationInfFileNameSize, 2167 OUT PDWORD RequiredSize OPTIONAL, 2168 OUT PSTR* DestinationInfFileNameComponent OPTIONAL) 2169 { 2170 PWSTR SourceInfFileNameW = NULL; 2171 PWSTR OEMSourceMediaLocationW = NULL; 2172 PWSTR DestinationInfFileNameW = NULL; 2173 PWSTR DestinationInfFileNameComponentW = NULL; 2174 BOOL ret = FALSE; 2175 2176 TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n", 2177 SourceInfFileName, OEMSourceMediaLocation, OEMSourceMediaType, 2178 CopyStyle, DestinationInfFileName, DestinationInfFileNameSize, 2179 RequiredSize, DestinationInfFileNameComponent); 2180 2181 if (!DestinationInfFileName && DestinationInfFileNameSize > 0) 2182 SetLastError(ERROR_INVALID_PARAMETER); 2183 else if (!(SourceInfFileNameW = pSetupMultiByteToUnicode(SourceInfFileName, CP_ACP))) 2184 SetLastError(ERROR_INVALID_PARAMETER); 2185 else if (OEMSourceMediaType != SPOST_NONE && !(OEMSourceMediaLocationW = pSetupMultiByteToUnicode(OEMSourceMediaLocation, CP_ACP))) 2186 SetLastError(ERROR_INVALID_PARAMETER); 2187 else 2188 { 2189 if (DestinationInfFileNameSize != 0) 2190 { 2191 DestinationInfFileNameW = MyMalloc(DestinationInfFileNameSize * sizeof(WCHAR)); 2192 if (!DestinationInfFileNameW) 2193 { 2194 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2195 goto cleanup; 2196 } 2197 } 2198 2199 ret = SetupCopyOEMInfW( 2200 SourceInfFileNameW, 2201 OEMSourceMediaLocationW, 2202 OEMSourceMediaType, 2203 CopyStyle, 2204 DestinationInfFileNameW, 2205 DestinationInfFileNameSize, 2206 RequiredSize, 2207 DestinationInfFileNameComponent ? &DestinationInfFileNameComponentW : NULL); 2208 if (!ret) 2209 goto cleanup; 2210 2211 if (DestinationInfFileNameSize != 0) 2212 { 2213 if (WideCharToMultiByte(CP_ACP, 0, DestinationInfFileNameW, -1, 2214 DestinationInfFileName, DestinationInfFileNameSize, NULL, NULL) == 0) 2215 { 2216 DestinationInfFileName[0] = '\0'; 2217 goto cleanup; 2218 } 2219 } 2220 if (DestinationInfFileNameComponent) 2221 { 2222 if (DestinationInfFileNameComponentW) 2223 *DestinationInfFileNameComponent = &DestinationInfFileName[DestinationInfFileNameComponentW - DestinationInfFileNameW]; 2224 else 2225 *DestinationInfFileNameComponent = NULL; 2226 } 2227 ret = TRUE; 2228 } 2229 2230 cleanup: 2231 MyFree(SourceInfFileNameW); 2232 MyFree(OEMSourceMediaLocationW); 2233 MyFree(DestinationInfFileNameW); 2234 TRACE("Returning %d\n", ret); 2235 if (ret) SetLastError(ERROR_SUCCESS); 2236 return ret; 2237 } 2238 2239 static int compare_files( HANDLE file1, HANDLE file2 ) 2240 { 2241 char buffer1[2048]; 2242 char buffer2[2048]; 2243 DWORD size1; 2244 DWORD size2; 2245 2246 while( ReadFile(file1, buffer1, sizeof(buffer1), &size1, NULL) && 2247 ReadFile(file2, buffer2, sizeof(buffer2), &size2, NULL) ) 2248 { 2249 int ret; 2250 if (size1 != size2) 2251 return size1 > size2 ? 1 : -1; 2252 if (!size1) 2253 return 0; 2254 ret = memcmp( buffer1, buffer2, size1 ); 2255 if (ret) 2256 return ret; 2257 } 2258 2259 return 0; 2260 } 2261 2262 /*********************************************************************** 2263 * SetupCopyOEMInfW (SETUPAPI.@) 2264 */ 2265 BOOL WINAPI SetupCopyOEMInfW( 2266 IN PCWSTR SourceInfFileName, 2267 IN PCWSTR OEMSourceMediaLocation, 2268 IN DWORD OEMSourceMediaType, 2269 IN DWORD CopyStyle, 2270 OUT PWSTR DestinationInfFileName OPTIONAL, 2271 IN DWORD DestinationInfFileNameSize, 2272 OUT PDWORD RequiredSize OPTIONAL, 2273 OUT PWSTR* DestinationInfFileNameComponent OPTIONAL) 2274 { 2275 BOOL ret = FALSE; 2276 2277 TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n", 2278 debugstr_w(SourceInfFileName), debugstr_w(OEMSourceMediaLocation), OEMSourceMediaType, 2279 CopyStyle, DestinationInfFileName, DestinationInfFileNameSize, 2280 RequiredSize, DestinationInfFileNameComponent); 2281 2282 if (!SourceInfFileName) 2283 SetLastError(ERROR_INVALID_PARAMETER); 2284 else if (OEMSourceMediaType != SPOST_NONE && OEMSourceMediaType != SPOST_PATH && OEMSourceMediaType != SPOST_URL) 2285 SetLastError(ERROR_INVALID_PARAMETER); 2286 else if (OEMSourceMediaType != SPOST_NONE && !OEMSourceMediaLocation) 2287 SetLastError(ERROR_INVALID_PARAMETER); 2288 else if (CopyStyle & ~(SP_COPY_DELETESOURCE | SP_COPY_REPLACEONLY | SP_COPY_NOOVERWRITE | SP_COPY_OEMINF_CATALOG_ONLY)) 2289 { 2290 TRACE("Unknown flags: 0x%08lx\n", CopyStyle & ~(SP_COPY_DELETESOURCE | SP_COPY_REPLACEONLY | SP_COPY_NOOVERWRITE | SP_COPY_OEMINF_CATALOG_ONLY)); 2291 SetLastError(ERROR_INVALID_FLAGS); 2292 } 2293 else if (!DestinationInfFileName && DestinationInfFileNameSize > 0) 2294 SetLastError(ERROR_INVALID_PARAMETER); 2295 else if (CopyStyle & SP_COPY_OEMINF_CATALOG_ONLY) 2296 { 2297 FIXME("CopyStyle 0x%x not supported\n", SP_COPY_OEMINF_CATALOG_ONLY); 2298 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 2299 } 2300 else 2301 { 2302 HANDLE hSearch = INVALID_HANDLE_VALUE; 2303 WIN32_FIND_DATAW FindFileData; 2304 BOOL AlreadyExists; 2305 DWORD NextFreeNumber = 0; 2306 SIZE_T len; 2307 LPWSTR pFullFileName = NULL; 2308 LPWSTR pFileName; /* Pointer into pFullFileName buffer */ 2309 HANDLE hSourceFile = INVALID_HANDLE_VALUE; 2310 2311 if (OEMSourceMediaType == SPOST_PATH || OEMSourceMediaType == SPOST_URL) 2312 FIXME("OEMSourceMediaType 0x%lx ignored\n", OEMSourceMediaType); 2313 2314 /* Check if source file exists, and open it */ 2315 if (strchrW(SourceInfFileName, '\\' ) || strchrW(SourceInfFileName, '/' )) 2316 { 2317 WCHAR *path; 2318 2319 if (!(len = GetFullPathNameW(SourceInfFileName, 0, NULL, NULL))) 2320 return FALSE; 2321 if (!(path = MyMalloc(len * sizeof(WCHAR)))) 2322 { 2323 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2324 return FALSE; 2325 } 2326 GetFullPathNameW(SourceInfFileName, len, path, NULL); 2327 hSourceFile = CreateFileW( 2328 path, FILE_READ_DATA | FILE_READ_ATTRIBUTES, 2329 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 2330 NULL, OPEN_EXISTING, 0, NULL); 2331 MyFree(path); 2332 } 2333 else /* try Windows directory */ 2334 { 2335 WCHAR *path, *p; 2336 static const WCHAR Inf[] = {'\\','i','n','f','\\',0}; 2337 static const WCHAR System32[] = {'\\','s','y','s','t','e','m','3','2','\\',0}; 2338 2339 len = GetWindowsDirectoryW(NULL, 0) + strlenW(SourceInfFileName) + 12; 2340 if (!(path = MyMalloc(len * sizeof(WCHAR)))) 2341 { 2342 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2343 return FALSE; 2344 } 2345 GetWindowsDirectoryW(path, len); 2346 p = path + strlenW(path); 2347 strcpyW(p, Inf); 2348 strcatW(p, SourceInfFileName); 2349 hSourceFile = CreateFileW( 2350 path, FILE_READ_DATA | FILE_READ_ATTRIBUTES, 2351 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 2352 NULL, OPEN_EXISTING, 0, NULL); 2353 if (hSourceFile == INVALID_HANDLE_VALUE) 2354 { 2355 strcpyW(p, System32); 2356 strcatW(p, SourceInfFileName); 2357 hSourceFile = CreateFileW( 2358 path, FILE_READ_DATA | FILE_READ_ATTRIBUTES, 2359 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 2360 NULL, OPEN_EXISTING, 0, NULL); 2361 } 2362 MyFree(path); 2363 } 2364 if (hSourceFile == INVALID_HANDLE_VALUE) 2365 { 2366 SetLastError(ERROR_FILE_NOT_FOUND); 2367 goto cleanup; 2368 } 2369 2370 /* Prepare .inf file specification */ 2371 len = MAX_PATH + 1 + strlenW(InfDirectory) + 13; 2372 pFullFileName = MyMalloc(len * sizeof(WCHAR)); 2373 if (!pFullFileName) 2374 { 2375 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2376 goto cleanup; 2377 } 2378 len = GetSystemWindowsDirectoryW(pFullFileName, MAX_PATH); 2379 if (len == 0 || len > MAX_PATH) 2380 goto cleanup; 2381 if (pFullFileName[strlenW(pFullFileName) - 1] != '\\') 2382 strcatW(pFullFileName, BackSlash); 2383 strcatW(pFullFileName, InfDirectory); 2384 pFileName = &pFullFileName[strlenW(pFullFileName)]; 2385 2386 /* Search if the specified .inf file already exists in %WINDIR%\Inf */ 2387 AlreadyExists = FALSE; 2388 strcpyW(pFileName, OemFileMask); 2389 hSearch = FindFirstFileW(pFullFileName, &FindFileData); 2390 if (hSearch != INVALID_HANDLE_VALUE) 2391 { 2392 LARGE_INTEGER SourceFileSize; 2393 2394 if (GetFileSizeEx(hSourceFile, &SourceFileSize)) 2395 { 2396 do 2397 { 2398 LARGE_INTEGER DestFileSize; 2399 HANDLE hDestFile; 2400 2401 strcpyW(pFileName, FindFileData.cFileName); 2402 hDestFile = CreateFileW( 2403 pFullFileName, FILE_READ_DATA | FILE_READ_ATTRIBUTES, 2404 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 2405 NULL, OPEN_EXISTING, 0, NULL); 2406 if (hDestFile != INVALID_HANDLE_VALUE) 2407 { 2408 if (GetFileSizeEx(hDestFile, &DestFileSize) 2409 && DestFileSize.QuadPart == SourceFileSize.QuadPart 2410 && !compare_files(hSourceFile, hDestFile)) 2411 { 2412 TRACE("%s already exists as %s\n", 2413 debugstr_w(SourceInfFileName), debugstr_w(pFileName)); 2414 AlreadyExists = TRUE; 2415 } 2416 } 2417 } while (!AlreadyExists && FindNextFileW(hSearch, &FindFileData)); 2418 } 2419 FindClose(hSearch); 2420 hSearch = INVALID_HANDLE_VALUE; 2421 } 2422 2423 if (!AlreadyExists && CopyStyle & SP_COPY_REPLACEONLY) 2424 { 2425 /* FIXME: set DestinationInfFileName, RequiredSize, DestinationInfFileNameComponent */ 2426 SetLastError(ERROR_FILE_NOT_FOUND); 2427 goto cleanup; 2428 } 2429 else if (AlreadyExists && (CopyStyle & SP_COPY_NOOVERWRITE)) 2430 { 2431 DWORD Size = strlenW(pFileName) + 1; 2432 2433 if (RequiredSize) 2434 *RequiredSize = Size; 2435 if (DestinationInfFileNameSize == 0) 2436 SetLastError(ERROR_FILE_EXISTS); 2437 else if (DestinationInfFileNameSize < Size) 2438 SetLastError(ERROR_INSUFFICIENT_BUFFER); 2439 else 2440 { 2441 SetLastError(ERROR_FILE_EXISTS); 2442 strcpyW(DestinationInfFileName, pFileName); 2443 } 2444 goto cleanup; 2445 } 2446 2447 /* Search the number to give to OEM??.INF */ 2448 strcpyW(pFileName, OemFileMask); 2449 hSearch = FindFirstFileW(pFullFileName, &FindFileData); 2450 if (hSearch == INVALID_HANDLE_VALUE) 2451 { 2452 if (GetLastError() != ERROR_FILE_NOT_FOUND) 2453 goto cleanup; 2454 } 2455 else 2456 { 2457 do 2458 { 2459 DWORD CurrentNumber; 2460 if (swscanf(FindFileData.cFileName, OemFileSpecification, &CurrentNumber) == 1 2461 && CurrentNumber <= 99999) 2462 { 2463 if (CurrentNumber >= NextFreeNumber) 2464 NextFreeNumber = CurrentNumber + 1; 2465 } 2466 } while (FindNextFileW(hSearch, &FindFileData)); 2467 } 2468 2469 if (NextFreeNumber > 99999) 2470 { 2471 ERR("Too much custom .inf files\n"); 2472 SetLastError(ERROR_GEN_FAILURE); 2473 goto cleanup; 2474 } 2475 2476 /* Create the full path: %WINDIR%\Inf\OEM{XXXXX}.inf */ 2477 sprintfW(pFileName, OemFileSpecification, NextFreeNumber); 2478 TRACE("Next available file is %s\n", debugstr_w(pFileName)); 2479 2480 if (!CopyFileW(SourceInfFileName, pFullFileName, TRUE)) 2481 { 2482 TRACE("CopyFileW() failed with error 0x%lx\n", GetLastError()); 2483 goto cleanup; 2484 } 2485 2486 len = strlenW(pFullFileName) + 1; 2487 if (RequiredSize) 2488 *RequiredSize = len; 2489 if (DestinationInfFileName) 2490 { 2491 if (DestinationInfFileNameSize >= len) 2492 { 2493 strcpyW(DestinationInfFileName, pFullFileName); 2494 if (DestinationInfFileNameComponent) 2495 *DestinationInfFileNameComponent = &DestinationInfFileName[pFileName - pFullFileName]; 2496 } 2497 else 2498 { 2499 SetLastError(ERROR_INSUFFICIENT_BUFFER); 2500 goto cleanup; 2501 } 2502 } 2503 2504 if (CopyStyle & SP_COPY_DELETESOURCE) 2505 { 2506 if (!DeleteFileW(SourceInfFileName)) 2507 { 2508 TRACE("DeleteFileW() failed with error 0x%lx\n", GetLastError()); 2509 goto cleanup; 2510 } 2511 } 2512 2513 ret = TRUE; 2514 2515 cleanup: 2516 if (hSourceFile != INVALID_HANDLE_VALUE) 2517 CloseHandle(hSourceFile); 2518 if (hSearch != INVALID_HANDLE_VALUE) 2519 FindClose(hSearch); 2520 MyFree(pFullFileName); 2521 } 2522 2523 TRACE("Returning %d\n", ret); 2524 if (ret) SetLastError(ERROR_SUCCESS); 2525 return ret; 2526 } 2527