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