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