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) 848 dwRequired += wcslen(Dir) + 1; 849 if (SubDirPart) 850 dwRequired += wcslen(SubDirPart) + 1; 851 if (NamePart) 852 dwRequired += wcslen(NamePart); 853 dwRequired = dwRequired * sizeof(WCHAR) + sizeof(UNICODE_NULL); 854 855 FullName = MyMalloc(dwRequired); 856 if (!FullName) 857 { 858 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 859 return FALSE; 860 } 861 FullName[0] = UNICODE_NULL; 862 863 if (Dir) 864 { 865 wcscat(FullName, Dir); 866 if (FullName[wcslen(FullName) - 1] != '\\') 867 wcscat(FullName, BackSlash); 868 } 869 if (SubDirPart) 870 { 871 wcscat(FullName, SubDirPart); 872 if (FullName[wcslen(FullName) - 1] != '\\') 873 wcscat(FullName, BackSlash); 874 } 875 if (NamePart) 876 wcscat(FullName, NamePart); 877 878 *pFullName = FullName; 879 return TRUE; 880 } 881 882 /*********************************************************************** 883 * profile_items_callback 884 * 885 * Called once for each ProfileItems entry in a given section. 886 */ 887 static BOOL 888 profile_items_callback( 889 IN HINF hInf, 890 IN PCWSTR SectionName, 891 IN PVOID Arg) 892 { 893 INFCONTEXT Context; 894 LPWSTR LinkSubDir = NULL, LinkName = NULL; 895 INT LinkAttributes = 0; 896 INT LinkFolder = 0; 897 INT FileDirId = 0; 898 INT CSIDL = CSIDL_COMMON_PROGRAMS; 899 LPWSTR FileSubDir = NULL; 900 INT DirId = 0; 901 LPWSTR SubDirPart = NULL, NamePart = NULL; 902 LPWSTR FullLinkName = NULL, FullFileName = NULL, FullWorkingDir = NULL, FullIconName = NULL; 903 INT IconIdx = 0; 904 LPWSTR lpHotKey = NULL, lpInfoTip = NULL; 905 LPWSTR DisplayName = NULL; 906 INT DisplayResId = 0; 907 BOOL ret = FALSE; 908 DWORD Index, Required; 909 910 IShellLinkW *psl; 911 IPersistFile *ppf; 912 HMODULE hOle32 = NULL; 913 COINITIALIZE pCoInitialize; 914 COCREATEINSTANCE pCoCreateInstance; 915 COUNINITIALIZE pCoUninitialize; 916 HRESULT hr; 917 918 TRACE("hInf %p, SectionName %s, Arg %p\n", 919 hInf, debugstr_w(SectionName), Arg); 920 921 /* Read 'Name' entry */ 922 if (!SetupFindFirstLineW(hInf, SectionName, Name, &Context)) 923 goto cleanup; 924 if (!GetStringField(&Context, 1, &LinkName)) 925 goto cleanup; 926 if (SetupGetFieldCount(&Context) >= 2) 927 { 928 if (!SetupGetIntField(&Context, 2, &LinkAttributes)) 929 goto cleanup; 930 } 931 if (SetupGetFieldCount(&Context) >= 3) 932 { 933 if (!SetupGetIntField(&Context, 3, &LinkFolder)) 934 goto cleanup; 935 } 936 937 /* Read 'CmdLine' entry */ 938 if (!SetupFindFirstLineW(hInf, SectionName, CmdLine, &Context)) 939 goto cleanup; 940 Index = 1; 941 if (!SetupGetIntField(&Context, Index++, &FileDirId)) 942 goto cleanup; 943 if (SetupGetFieldCount(&Context) >= 3) 944 { 945 if (!GetStringField(&Context, Index++, &FileSubDir)) 946 goto cleanup; 947 } 948 if (!GetStringField(&Context, Index++, &NamePart)) 949 goto cleanup; 950 if (!Concatenate(FileDirId, FileSubDir, NamePart, &FullFileName)) 951 goto cleanup; 952 MyFree(NamePart); 953 NamePart = NULL; 954 955 /* Read 'SubDir' entry */ 956 if ((LinkAttributes & FLG_PROFITEM_GROUP) == 0 && SetupFindFirstLineW(hInf, SectionName, SubDir, &Context)) 957 { 958 if (!GetStringField(&Context, 1, &LinkSubDir)) 959 goto cleanup; 960 } 961 962 /* Read 'WorkingDir' entry */ 963 if (SetupFindFirstLineW(hInf, SectionName, WorkingDir, &Context)) 964 { 965 if (!SetupGetIntField(&Context, 1, &DirId)) 966 goto cleanup; 967 if (SetupGetFieldCount(&Context) >= 2) 968 { 969 if (!GetStringField(&Context, 2, &SubDirPart)) 970 goto cleanup; 971 } 972 if (!Concatenate(DirId, SubDirPart, NULL, &FullWorkingDir)) 973 goto cleanup; 974 MyFree(SubDirPart); 975 SubDirPart = NULL; 976 } 977 else 978 { 979 if (!Concatenate(FileDirId, FileSubDir, NULL, &FullWorkingDir)) 980 goto cleanup; 981 } 982 983 /* Read 'IconPath' entry */ 984 if (SetupFindFirstLineW(hInf, SectionName, IconPath, &Context)) 985 { 986 Index = 1; 987 if (!SetupGetIntField(&Context, Index++, &DirId)) 988 goto cleanup; 989 if (SetupGetFieldCount(&Context) >= 3) 990 { 991 if (!GetStringField(&Context, Index++, &SubDirPart)) 992 goto cleanup; 993 } 994 if (!GetStringField(&Context, Index, &NamePart)) 995 goto cleanup; 996 if (!Concatenate(DirId, SubDirPart, NamePart, &FullIconName)) 997 goto cleanup; 998 MyFree(SubDirPart); 999 MyFree(NamePart); 1000 SubDirPart = NamePart = NULL; 1001 } 1002 else 1003 { 1004 FullIconName = pSetupDuplicateString(FullFileName); 1005 if (!FullIconName) 1006 goto cleanup; 1007 } 1008 1009 /* Read 'IconIndex' entry */ 1010 if (SetupFindFirstLineW(hInf, SectionName, IconIndex, &Context)) 1011 { 1012 if (!SetupGetIntField(&Context, 1, &IconIdx)) 1013 goto cleanup; 1014 } 1015 1016 /* Read 'HotKey' and 'InfoTip' entries */ 1017 GetLineText(hInf, SectionName, HotKey, &lpHotKey); 1018 GetLineText(hInf, SectionName, InfoTip, &lpInfoTip); 1019 1020 /* Read 'DisplayResource' entry */ 1021 if (SetupFindFirstLineW(hInf, SectionName, DisplayResource, &Context)) 1022 { 1023 if (!GetStringField(&Context, 1, &DisplayName)) 1024 goto cleanup; 1025 if (!SetupGetIntField(&Context, 2, &DisplayResId)) 1026 goto cleanup; 1027 } 1028 1029 /* Some debug */ 1030 TRACE("Link is %s\\%s, attributes 0x%x\n", debugstr_w(LinkSubDir), debugstr_w(LinkName), LinkAttributes); 1031 TRACE("File is %s\n", debugstr_w(FullFileName)); 1032 TRACE("Working dir %s\n", debugstr_w(FullWorkingDir)); 1033 TRACE("Icon is %s, %d\n", debugstr_w(FullIconName), IconIdx); 1034 TRACE("Hotkey %s\n", debugstr_w(lpHotKey)); 1035 TRACE("InfoTip %s\n", debugstr_w(lpInfoTip)); 1036 TRACE("Display %s, %d\n", DisplayName, DisplayResId); 1037 1038 /* Load ole32.dll */ 1039 hOle32 = LoadLibraryA("ole32.dll"); 1040 if (!hOle32) 1041 goto cleanup; 1042 pCoInitialize = (COINITIALIZE)GetProcAddress(hOle32, "CoInitialize"); 1043 if (!pCoInitialize) 1044 goto cleanup; 1045 pCoCreateInstance = (COCREATEINSTANCE)GetProcAddress(hOle32, "CoCreateInstance"); 1046 if (!pCoCreateInstance) 1047 goto cleanup; 1048 pCoUninitialize = (COUNINITIALIZE)GetProcAddress(hOle32, "CoUninitialize"); 1049 if (!pCoUninitialize) 1050 goto cleanup; 1051 1052 /* Create shortcut */ 1053 hr = pCoInitialize(NULL); 1054 if (!SUCCEEDED(hr)) 1055 { 1056 if (HRESULT_FACILITY(hr) == FACILITY_WIN32) 1057 SetLastError(HRESULT_CODE(hr)); 1058 else 1059 SetLastError(E_FAIL); 1060 goto cleanup; 1061 } 1062 hr = pCoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&psl); 1063 if (SUCCEEDED(hr)) 1064 { 1065 /* Fill link properties */ 1066 hr = IShellLinkW_SetPath(psl, FullFileName); 1067 if (SUCCEEDED(hr)) 1068 hr = IShellLinkW_SetArguments(psl, L""); 1069 if (SUCCEEDED(hr)) 1070 hr = IShellLinkW_SetWorkingDirectory(psl, FullWorkingDir); 1071 if (SUCCEEDED(hr)) 1072 hr = IShellLinkW_SetIconLocation(psl, FullIconName, IconIdx); 1073 if (SUCCEEDED(hr) && lpHotKey) 1074 FIXME("Need to store hotkey %s in shell link\n", debugstr_w(lpHotKey)); 1075 if (SUCCEEDED(hr) && lpInfoTip) 1076 hr = IShellLinkW_SetDescription(psl, lpInfoTip); 1077 if (SUCCEEDED(hr) && DisplayName) 1078 FIXME("Need to store display name %s, %d in shell link\n", debugstr_w(DisplayName), DisplayResId); 1079 if (SUCCEEDED(hr)) 1080 { 1081 hr = IShellLinkW_QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf); 1082 if (SUCCEEDED(hr)) 1083 { 1084 Required = (MAX_PATH + 1 + 1085 ((LinkSubDir != NULL) ? wcslen(LinkSubDir) : 0) + 1086 ((LinkName != NULL) ? wcslen(LinkName) : 0)) * sizeof(WCHAR); 1087 FullLinkName = MyMalloc(Required); 1088 if (!FullLinkName) 1089 hr = E_OUTOFMEMORY; 1090 else 1091 { 1092 if (LinkAttributes & (FLG_PROFITEM_DELETE | FLG_PROFITEM_GROUP)) 1093 FIXME("Need to handle FLG_PROFITEM_DELETE and FLG_PROFITEM_GROUP\n"); 1094 if (LinkAttributes & FLG_PROFITEM_CSIDL) 1095 CSIDL = LinkFolder; 1096 else if (LinkAttributes & FLG_PROFITEM_CURRENTUSER) 1097 CSIDL = CSIDL_PROGRAMS; 1098 1099 if (SHGetSpecialFolderPathW( 1100 NULL, 1101 FullLinkName, 1102 CSIDL, 1103 TRUE)) 1104 { 1105 if (FullLinkName[wcslen(FullLinkName) - 1] != '\\') 1106 wcscat(FullLinkName, BackSlash); 1107 if (LinkSubDir) 1108 { 1109 wcscat(FullLinkName, LinkSubDir); 1110 if (FullLinkName[wcslen(FullLinkName) - 1] != '\\') 1111 wcscat(FullLinkName, BackSlash); 1112 } 1113 wcscat(FullLinkName, LinkName); 1114 wcscat(FullLinkName, DotLnk); 1115 hr = IPersistFile_Save(ppf, FullLinkName, TRUE); 1116 } 1117 else 1118 hr = HRESULT_FROM_WIN32(GetLastError()); 1119 } 1120 IPersistFile_Release(ppf); 1121 } 1122 } 1123 IShellLinkW_Release(psl); 1124 } 1125 pCoUninitialize(); 1126 if (SUCCEEDED(hr)) 1127 ret = TRUE; 1128 else 1129 { 1130 if (HRESULT_FACILITY(hr) == FACILITY_WIN32) 1131 SetLastError(HRESULT_CODE(hr)); 1132 else 1133 SetLastError(E_FAIL); 1134 } 1135 1136 cleanup: 1137 MyFree(LinkSubDir); 1138 MyFree(LinkName); 1139 MyFree(FileSubDir); 1140 MyFree(SubDirPart); 1141 MyFree(NamePart); 1142 MyFree(FullFileName); 1143 MyFree(FullWorkingDir); 1144 MyFree(FullIconName); 1145 MyFree(FullLinkName); 1146 MyFree(lpHotKey); 1147 MyFree(lpInfoTip); 1148 MyFree(DisplayName); 1149 if (hOle32) 1150 FreeLibrary(hOle32); 1151 1152 TRACE("Returning %d\n", ret); 1153 return ret; 1154 } 1155 1156 static BOOL copy_inf_callback( HINF hinf, PCWSTR field, void *arg ) 1157 { 1158 FIXME( "should do copy inf %s\n", debugstr_w(field) ); 1159 return TRUE; 1160 } 1161 1162 1163 /*********************************************************************** 1164 * iterate_section_fields 1165 * 1166 * Iterate over all fields of a certain key of a certain section 1167 */ 1168 static BOOL iterate_section_fields( HINF hinf, PCWSTR section, PCWSTR key, 1169 iterate_fields_func callback, void *arg ) 1170 { 1171 WCHAR static_buffer[200]; 1172 WCHAR *buffer = static_buffer; 1173 DWORD size = sizeof(static_buffer)/sizeof(WCHAR); 1174 INFCONTEXT context; 1175 BOOL ret = FALSE; 1176 1177 BOOL ok = SetupFindFirstLineW( hinf, section, key, &context ); 1178 while (ok) 1179 { 1180 UINT i, count = SetupGetFieldCount( &context ); 1181 for (i = 1; i <= count; i++) 1182 { 1183 if (!(buffer = get_field_string( &context, i, buffer, static_buffer, &size ))) 1184 goto done; 1185 if (!callback( hinf, buffer, arg )) 1186 { 1187 WARN("callback failed for %s %s err %d\n", 1188 debugstr_w(section), debugstr_w(buffer), GetLastError() ); 1189 goto done; 1190 } 1191 } 1192 ok = SetupFindNextMatchLineW( &context, key, &context ); 1193 } 1194 ret = TRUE; 1195 done: 1196 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer ); 1197 return ret; 1198 } 1199 1200 1201 /*********************************************************************** 1202 * SetupInstallFilesFromInfSectionA (SETUPAPI.@) 1203 */ 1204 BOOL WINAPI SetupInstallFilesFromInfSectionA( HINF hinf, HINF hlayout, HSPFILEQ queue, 1205 PCSTR section, PCSTR src_root, UINT flags ) 1206 { 1207 UNICODE_STRING sectionW; 1208 BOOL ret = FALSE; 1209 1210 if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section )) 1211 { 1212 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1213 return FALSE; 1214 } 1215 if (!src_root) 1216 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer, 1217 NULL, flags ); 1218 else 1219 { 1220 UNICODE_STRING srcW; 1221 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root )) 1222 { 1223 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer, 1224 srcW.Buffer, flags ); 1225 RtlFreeUnicodeString( &srcW ); 1226 } 1227 else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1228 } 1229 RtlFreeUnicodeString( §ionW ); 1230 return ret; 1231 } 1232 1233 1234 /*********************************************************************** 1235 * SetupInstallFilesFromInfSectionW (SETUPAPI.@) 1236 */ 1237 BOOL WINAPI SetupInstallFilesFromInfSectionW( HINF hinf, HINF hlayout, HSPFILEQ queue, 1238 PCWSTR section, PCWSTR src_root, UINT flags ) 1239 { 1240 struct files_callback_info info; 1241 1242 info.queue = queue; 1243 info.src_root = src_root; 1244 info.copy_flags = flags; 1245 info.layout = hlayout; 1246 return iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ); 1247 } 1248 1249 1250 /*********************************************************************** 1251 * SetupInstallFromInfSectionA (SETUPAPI.@) 1252 */ 1253 BOOL WINAPI SetupInstallFromInfSectionA( HWND owner, HINF hinf, PCSTR section, UINT flags, 1254 HKEY key_root, PCSTR src_root, UINT copy_flags, 1255 PSP_FILE_CALLBACK_A callback, PVOID context, 1256 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data ) 1257 { 1258 UNICODE_STRING sectionW, src_rootW; 1259 struct callback_WtoA_context ctx; 1260 BOOL ret = FALSE; 1261 1262 src_rootW.Buffer = NULL; 1263 if (src_root && !RtlCreateUnicodeStringFromAsciiz( &src_rootW, src_root )) 1264 { 1265 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1266 return FALSE; 1267 } 1268 1269 if (RtlCreateUnicodeStringFromAsciiz( §ionW, section )) 1270 { 1271 ctx.orig_context = context; 1272 ctx.orig_handler = callback; 1273 ret = SetupInstallFromInfSectionW( owner, hinf, sectionW.Buffer, flags, key_root, 1274 src_rootW.Buffer, copy_flags, QUEUE_callback_WtoA, 1275 &ctx, devinfo, devinfo_data ); 1276 RtlFreeUnicodeString( §ionW ); 1277 } 1278 else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1279 1280 RtlFreeUnicodeString( &src_rootW ); 1281 return ret; 1282 } 1283 1284 1285 /*********************************************************************** 1286 * include_callback 1287 * 1288 * Called once for each Include entry in a given section. 1289 */ 1290 static BOOL include_callback( HINF hinf, PCWSTR field, void *arg ) 1291 { 1292 return SetupOpenAppendInfFileW( field, hinf, NULL ); 1293 } 1294 1295 1296 /*********************************************************************** 1297 * needs_callback 1298 * 1299 * Called once for each Needs entry in a given section. 1300 */ 1301 static BOOL needs_callback( HINF hinf, PCWSTR field, void *arg ) 1302 { 1303 struct needs_callback_info *info = arg; 1304 1305 switch (info->type) 1306 { 1307 case 0: 1308 return SetupInstallFromInfSectionW(info->owner, *(HINF*)hinf, field, info->flags, 1309 info->key_root, info->src_root, info->copy_flags, info->callback, 1310 info->context, info->devinfo, info->devinfo_data); 1311 case 1: 1312 return SetupInstallServicesFromInfSectionExW(*(HINF*)hinf, field, info->flags, 1313 info->devinfo, info->devinfo_data, info->reserved1, info->reserved2); 1314 default: 1315 ERR("Unknown info type %u\n", info->type); 1316 return FALSE; 1317 } 1318 } 1319 1320 1321 /*********************************************************************** 1322 * SetupInstallFromInfSectionW (SETUPAPI.@) 1323 */ 1324 BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section, UINT flags, 1325 HKEY key_root, PCWSTR src_root, UINT copy_flags, 1326 PSP_FILE_CALLBACK_W callback, PVOID context, 1327 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data ) 1328 { 1329 struct needs_callback_info needs_info; 1330 1331 /* Parse 'Include' and 'Needs' directives */ 1332 iterate_section_fields( hinf, section, Include, include_callback, NULL); 1333 needs_info.type = 0; 1334 needs_info.owner = owner; 1335 needs_info.flags = flags; 1336 needs_info.key_root = key_root; 1337 needs_info.src_root = src_root; 1338 needs_info.copy_flags = copy_flags; 1339 needs_info.callback = callback; 1340 needs_info.context = context; 1341 needs_info.devinfo = devinfo; 1342 needs_info.devinfo_data = devinfo_data; 1343 iterate_section_fields( hinf, section, Needs, needs_callback, &needs_info); 1344 1345 if (flags & SPINST_FILES) 1346 { 1347 SP_DEVINSTALL_PARAMS_W install_params; 1348 struct files_callback_info info; 1349 HSPFILEQ queue = NULL; 1350 BOOL use_custom_queue; 1351 BOOL ret; 1352 1353 install_params.cbSize = sizeof(SP_DEVINSTALL_PARAMS); 1354 use_custom_queue = SetupDiGetDeviceInstallParamsW(devinfo, devinfo_data, &install_params) && (install_params.Flags & DI_NOVCP); 1355 if (!use_custom_queue && ((queue = SetupOpenFileQueue()) == (HSPFILEQ)INVALID_HANDLE_VALUE )) 1356 return FALSE; 1357 info.queue = use_custom_queue ? install_params.FileQueue : queue; 1358 info.src_root = src_root; 1359 info.copy_flags = copy_flags; 1360 info.layout = hinf; 1361 ret = (iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ) && 1362 iterate_section_fields( hinf, section, DelFiles, delete_files_callback, &info ) && 1363 iterate_section_fields( hinf, section, RenFiles, rename_files_callback, &info )); 1364 if (!use_custom_queue) 1365 { 1366 if (ret) 1367 ret = SetupCommitFileQueueW( owner, queue, callback, context ); 1368 SetupCloseFileQueue( queue ); 1369 } 1370 if (!ret) return FALSE; 1371 } 1372 if (flags & SPINST_INIFILES) 1373 { 1374 if (!iterate_section_fields( hinf, section, UpdateInis, update_ini_callback, NULL ) || 1375 !iterate_section_fields( hinf, section, UpdateIniFields, 1376 update_ini_fields_callback, NULL )) 1377 return FALSE; 1378 } 1379 if (flags & SPINST_INI2REG) 1380 { 1381 if (!iterate_section_fields( hinf, section, Ini2Reg, ini2reg_callback, NULL )) 1382 return FALSE; 1383 } 1384 if (flags & SPINST_LOGCONFIG) 1385 { 1386 if (!iterate_section_fields( hinf, section, LogConf, logconf_callback, NULL )) 1387 return FALSE; 1388 } 1389 if (flags & SPINST_REGSVR) 1390 { 1391 struct register_dll_info info; 1392 1393 info.unregister = FALSE; 1394 if (flags & SPINST_REGISTERCALLBACKAWARE) 1395 { 1396 info.callback = callback; 1397 info.callback_context = context; 1398 } 1399 else info.callback = NULL; 1400 1401 if (!iterate_section_fields( hinf, section, RegisterDlls, register_dlls_callback, &info )) 1402 return FALSE; 1403 1404 #ifdef __WINESRC__ 1405 if (!iterate_section_fields( hinf, section, WineFakeDlls, fake_dlls_callback, NULL )) 1406 return FALSE; 1407 #endif // __WINESRC__ 1408 } 1409 if (flags & SPINST_UNREGSVR) 1410 { 1411 struct register_dll_info info; 1412 1413 info.unregister = TRUE; 1414 if (flags & SPINST_REGISTERCALLBACKAWARE) 1415 { 1416 info.callback = callback; 1417 info.callback_context = context; 1418 } 1419 else info.callback = NULL; 1420 1421 if (!iterate_section_fields( hinf, section, UnregisterDlls, register_dlls_callback, &info )) 1422 return FALSE; 1423 } 1424 if (flags & SPINST_REGISTRY) 1425 { 1426 struct registry_callback_info info; 1427 1428 info.default_root = key_root; 1429 info.delete = TRUE; 1430 if (!iterate_section_fields( hinf, section, DelReg, registry_callback, &info )) 1431 return FALSE; 1432 info.delete = FALSE; 1433 if (!iterate_section_fields( hinf, section, AddReg, registry_callback, &info )) 1434 return FALSE; 1435 } 1436 if (flags & SPINST_BITREG) 1437 { 1438 if (!iterate_section_fields( hinf, section, BitReg, bitreg_callback, NULL )) 1439 return FALSE; 1440 } 1441 if (flags & SPINST_PROFILEITEMS) 1442 { 1443 if (!iterate_section_fields( hinf, section, ProfileItems, profile_items_callback, NULL )) 1444 return FALSE; 1445 } 1446 if (flags & SPINST_COPYINF) 1447 { 1448 if (!iterate_section_fields( hinf, section, CopyINF, copy_inf_callback, NULL )) 1449 return FALSE; 1450 } 1451 1452 return TRUE; 1453 } 1454 1455 1456 /*********************************************************************** 1457 * InstallHinfSectionW (SETUPAPI.@) 1458 * 1459 * NOTE: 'cmdline' is <section> <mode> <path> from 1460 * RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection <section> <mode> <path> 1461 */ 1462 void WINAPI InstallHinfSectionW( HWND hwnd, HINSTANCE handle, LPCWSTR cmdline, INT show ) 1463 { 1464 BOOL ret = FALSE; 1465 WCHAR *s, *path, section[MAX_PATH]; 1466 void *callback_context = NULL; 1467 DWORD SectionNameLength; 1468 UINT mode; 1469 HINF hinf = INVALID_HANDLE_VALUE; 1470 BOOL bRebootRequired = FALSE; 1471 1472 TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd, handle, debugstr_w(cmdline)); 1473 1474 lstrcpynW( section, cmdline, MAX_PATH ); 1475 1476 if (!(s = strchrW( section, ' ' ))) goto cleanup; 1477 *s++ = 0; 1478 while (*s == ' ') s++; 1479 mode = atoiW( s ); 1480 1481 /* quoted paths are not allowed on native, the rest of the command line is taken as the path */ 1482 if (!(s = strchrW( s, ' ' ))) goto cleanup; 1483 while (*s == ' ') s++; 1484 path = s; 1485 1486 if (mode & 0x80) 1487 { 1488 FIXME("default path of the installation not changed\n"); 1489 mode &= ~0x80; 1490 } 1491 1492 hinf = SetupOpenInfFileW( path, NULL, INF_STYLE_WIN4, NULL ); 1493 if (hinf == INVALID_HANDLE_VALUE) 1494 { 1495 WARN("SetupOpenInfFileW(%s) failed (Error %u)\n", path, GetLastError()); 1496 goto cleanup; 1497 } 1498 1499 ret = SetupDiGetActualSectionToInstallW( 1500 hinf, section, section, sizeof(section)/sizeof(section[0]), &SectionNameLength, NULL ); 1501 if (!ret) 1502 { 1503 WARN("SetupDiGetActualSectionToInstallW() failed (Error %u)\n", GetLastError()); 1504 goto cleanup; 1505 } 1506 if (SectionNameLength > MAX_PATH - strlenW(DotServices)) 1507 { 1508 WARN("Section name '%s' too long\n", section); 1509 goto cleanup; 1510 } 1511 1512 /* Copy files and add registry entries */ 1513 callback_context = SetupInitDefaultQueueCallback( hwnd ); 1514 ret = SetupInstallFromInfSectionW( hwnd, hinf, section, SPINST_ALL, NULL, NULL, 1515 SP_COPY_NEWER | SP_COPY_IN_USE_NEEDS_REBOOT, 1516 SetupDefaultQueueCallbackW, callback_context, 1517 NULL, NULL ); 1518 if (!ret) 1519 { 1520 WARN("SetupInstallFromInfSectionW() failed (Error %u)\n", GetLastError()); 1521 goto cleanup; 1522 } 1523 /* FIXME: need to check if some files were in use and need reboot 1524 * bReboot = ...; 1525 */ 1526 1527 /* Install services */ 1528 wcscat(section, DotServices); 1529 ret = SetupInstallServicesFromInfSectionW( hinf, section, 0 ); 1530 if (!ret && GetLastError() == ERROR_SECTION_NOT_FOUND) 1531 ret = TRUE; 1532 if (!ret) 1533 { 1534 WARN("SetupInstallServicesFromInfSectionW() failed (Error %u)\n", GetLastError()); 1535 goto cleanup; 1536 } 1537 else if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED) 1538 { 1539 bRebootRequired = TRUE; 1540 } 1541 1542 /* Check if we need to reboot */ 1543 switch (mode) 1544 { 1545 case 0: 1546 /* Never reboot */ 1547 break; 1548 case 1: 1549 /* Always reboot */ 1550 ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_APPLICATION | 1551 SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED); 1552 break; 1553 case 2: 1554 /* Query user before rebooting */ 1555 SetupPromptReboot(NULL, hwnd, FALSE); 1556 break; 1557 case 3: 1558 /* Reboot if necessary */ 1559 if (bRebootRequired) 1560 { 1561 ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_APPLICATION | 1562 SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED); 1563 } 1564 break; 1565 case 4: 1566 /* If necessary, query user before rebooting */ 1567 if (bRebootRequired) 1568 { 1569 SetupPromptReboot(NULL, hwnd, FALSE); 1570 } 1571 break; 1572 default: 1573 break; 1574 } 1575 1576 cleanup: 1577 if ( callback_context ) 1578 SetupTermDefaultQueueCallback( callback_context ); 1579 if ( hinf != INVALID_HANDLE_VALUE ) 1580 SetupCloseInfFile( hinf ); 1581 1582 #ifdef CORE_11689_IS_FIXED 1583 // TODO: Localize the error string. 1584 if (!ret && !(GlobalSetupFlags & PSPGF_NONINTERACTIVE)) 1585 { 1586 MessageBoxW(hwnd, section, L"setupapi.dll: An error happened...", MB_ICONERROR | MB_OK); 1587 } 1588 #endif 1589 } 1590 1591 1592 /*********************************************************************** 1593 * InstallHinfSectionA (SETUPAPI.@) 1594 */ 1595 void WINAPI InstallHinfSectionA( HWND hwnd, HINSTANCE handle, LPCSTR cmdline, INT show ) 1596 { 1597 UNICODE_STRING cmdlineW; 1598 1599 if (RtlCreateUnicodeStringFromAsciiz( &cmdlineW, cmdline )) 1600 { 1601 InstallHinfSectionW( hwnd, handle, cmdlineW.Buffer, show ); 1602 RtlFreeUnicodeString( &cmdlineW ); 1603 } 1604 } 1605 1606 /*********************************************************************** 1607 * SetupInstallServicesFromInfSectionW (SETUPAPI.@) 1608 */ 1609 BOOL WINAPI SetupInstallServicesFromInfSectionW( HINF Inf, PCWSTR SectionName, DWORD Flags) 1610 { 1611 return SetupInstallServicesFromInfSectionExW( Inf, SectionName, Flags, 1612 NULL, NULL, NULL, NULL ); 1613 } 1614 1615 /*********************************************************************** 1616 * SetupInstallServicesFromInfSectionA (SETUPAPI.@) 1617 */ 1618 BOOL WINAPI SetupInstallServicesFromInfSectionA( HINF Inf, PCSTR SectionName, DWORD Flags) 1619 { 1620 return SetupInstallServicesFromInfSectionExA( Inf, SectionName, Flags, 1621 NULL, NULL, NULL, NULL ); 1622 } 1623 1624 /*********************************************************************** 1625 * SetupInstallServicesFromInfSectionExA (SETUPAPI.@) 1626 */ 1627 BOOL WINAPI SetupInstallServicesFromInfSectionExA( HINF hinf, PCSTR sectionname, DWORD flags, HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data, PVOID reserved1, PVOID reserved2 ) 1628 { 1629 UNICODE_STRING sectionnameW; 1630 BOOL ret = FALSE; 1631 1632 if (RtlCreateUnicodeStringFromAsciiz( §ionnameW, sectionname )) 1633 { 1634 ret = SetupInstallServicesFromInfSectionExW( hinf, sectionnameW.Buffer, flags, devinfo, devinfo_data, reserved1, reserved2 ); 1635 RtlFreeUnicodeString( §ionnameW ); 1636 } 1637 else 1638 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1639 1640 return ret; 1641 } 1642 1643 1644 static BOOL GetLineText( HINF hinf, PCWSTR section_name, PCWSTR key_name, PWSTR *value) 1645 { 1646 DWORD required; 1647 PWSTR buf = NULL; 1648 1649 *value = NULL; 1650 1651 if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, NULL, 0, &required ) 1652 && GetLastError() != ERROR_INSUFFICIENT_BUFFER ) 1653 return FALSE; 1654 1655 buf = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) ); 1656 if ( ! buf ) 1657 { 1658 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1659 return FALSE; 1660 } 1661 1662 if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, buf, required, &required ) ) 1663 { 1664 HeapFree( GetProcessHeap(), 0, buf ); 1665 return FALSE; 1666 } 1667 1668 *value = buf; 1669 return TRUE; 1670 } 1671 1672 1673 static BOOL GetIntField( HINF hinf, PCWSTR section_name, PCWSTR key_name, INT *value) 1674 { 1675 LPWSTR buffer, end; 1676 INT res; 1677 1678 if (! GetLineText( hinf, section_name, key_name, &buffer ) ) 1679 return FALSE; 1680 1681 res = wcstol( buffer, &end, 0 ); 1682 if (end != buffer && !*end) 1683 { 1684 HeapFree(GetProcessHeap(), 0, buffer); 1685 *value = res; 1686 return TRUE; 1687 } 1688 else 1689 { 1690 HeapFree(GetProcessHeap(), 0, buffer); 1691 SetLastError( ERROR_INVALID_DATA ); 1692 return FALSE; 1693 } 1694 } 1695 1696 1697 BOOL GetStringField( PINFCONTEXT context, DWORD index, PWSTR *value) 1698 { 1699 DWORD RequiredSize; 1700 BOOL ret; 1701 1702 ret = SetupGetStringFieldW( 1703 context, 1704 index, 1705 NULL, 0, 1706 &RequiredSize); 1707 if (!ret) 1708 return FALSE; 1709 else if (RequiredSize == 0) 1710 { 1711 *value = NULL; 1712 return TRUE; 1713 } 1714 1715 /* We got the needed size for the buffer */ 1716 *value = MyMalloc(RequiredSize * sizeof(WCHAR)); 1717 if (!*value) 1718 { 1719 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1720 return FALSE; 1721 } 1722 ret = SetupGetStringFieldW( 1723 context, 1724 index, 1725 *value, RequiredSize, NULL); 1726 if (!ret) 1727 MyFree(*value); 1728 1729 return ret; 1730 } 1731 1732 static VOID FixupServiceBinaryPath( 1733 IN DWORD ServiceType, 1734 IN OUT LPWSTR *ServiceBinary) 1735 { 1736 LPWSTR Buffer; 1737 WCHAR ReactOSDir[MAX_PATH]; 1738 DWORD RosDirLength, ServiceLength, Win32Length; 1739 1740 GetWindowsDirectoryW(ReactOSDir, MAX_PATH); 1741 RosDirLength = strlenW(ReactOSDir); 1742 ServiceLength = strlenW(*ServiceBinary); 1743 1744 /* Check and fix two things: 1745 1. Get rid of C:\ReactOS and use relative 1746 path instead. 1747 2. Add %SystemRoot% for Win32 services */ 1748 1749 if (ServiceLength < RosDirLength) 1750 return; 1751 1752 if (!wcsnicmp(*ServiceBinary, ReactOSDir, RosDirLength)) 1753 { 1754 /* Yes, the first part is the C:\ReactOS\, just skip it */ 1755 MoveMemory(*ServiceBinary, *ServiceBinary + RosDirLength + 1, 1756 (ServiceLength - RosDirLength) * sizeof(WCHAR)); 1757 1758 /* Handle Win32-services differently */ 1759 if (ServiceType & SERVICE_WIN32) 1760 { 1761 Win32Length = (ServiceLength - RosDirLength) * sizeof(WCHAR) 1762 - sizeof(L'\\') + sizeof(L"%SystemRoot%\\"); 1763 Buffer = MyMalloc(Win32Length); 1764 1765 wcscpy(Buffer, L"%SystemRoot%\\"); 1766 wcscat(Buffer, *ServiceBinary); 1767 MyFree(*ServiceBinary); 1768 1769 *ServiceBinary = Buffer; 1770 } 1771 } 1772 } 1773 1774 static BOOL InstallOneService( 1775 struct DeviceInfoSet *list, 1776 IN HINF hInf, 1777 IN LPCWSTR ServiceSection, 1778 IN LPCWSTR ServiceName, 1779 IN UINT ServiceFlags) 1780 { 1781 SC_HANDLE hSCManager = NULL; 1782 SC_HANDLE hService = NULL; 1783 LPDWORD GroupOrder = NULL; 1784 LPQUERY_SERVICE_CONFIGW ServiceConfig = NULL; 1785 HKEY hServicesKey, hServiceKey; 1786 LONG rc; 1787 BOOL ret = FALSE; 1788 1789 HKEY hGroupOrderListKey = NULL; 1790 LPWSTR ServiceBinary = NULL; 1791 LPWSTR LoadOrderGroup = NULL; 1792 LPWSTR DisplayName = NULL; 1793 LPWSTR Description = NULL; 1794 LPWSTR Dependencies = NULL; 1795 LPWSTR StartName = NULL; 1796 LPWSTR SecurityDescriptor = NULL; 1797 PSECURITY_DESCRIPTOR sd = NULL; 1798 INT ServiceType, StartType, ErrorControl; 1799 DWORD dwRegType; 1800 DWORD tagId = (DWORD)-1; 1801 BOOL useTag; 1802 1803 if (!GetIntField(hInf, ServiceSection, ServiceTypeKey, &ServiceType)) 1804 { 1805 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT ); 1806 goto cleanup; 1807 } 1808 if (!GetIntField(hInf, ServiceSection, StartTypeKey, &StartType)) 1809 { 1810 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT ); 1811 goto cleanup; 1812 } 1813 if (!GetIntField(hInf, ServiceSection, ErrorControlKey, &ErrorControl)) 1814 { 1815 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT ); 1816 goto cleanup; 1817 } 1818 useTag = (ServiceType == SERVICE_BOOT_START || ServiceType == SERVICE_SYSTEM_START); 1819 1820 hSCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE); 1821 if (hSCManager == NULL) 1822 goto cleanup; 1823 1824 if (!GetLineText(hInf, ServiceSection, ServiceBinaryKey, &ServiceBinary)) 1825 { 1826 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT ); 1827 goto cleanup; 1828 } 1829 1830 /* Adjust binary path according to the service type */ 1831 FixupServiceBinaryPath(ServiceType, &ServiceBinary); 1832 1833 /* Don't check return value, as these fields are optional and 1834 * GetLineText initialize output parameter even on failure */ 1835 GetLineText(hInf, ServiceSection, LoadOrderGroupKey, &LoadOrderGroup); 1836 GetLineText(hInf, ServiceSection, DisplayNameKey, &DisplayName); 1837 GetLineText(hInf, ServiceSection, DescriptionKey, &Description); 1838 GetLineText(hInf, ServiceSection, DependenciesKey, &Dependencies); 1839 GetLineText(hInf, ServiceSection, StartNameKey, &StartName); 1840 1841 /* If there is no group, we must not request a tag */ 1842 if (!LoadOrderGroup || !*LoadOrderGroup) 1843 useTag = FALSE; 1844 1845 hService = OpenServiceW( 1846 hSCManager, 1847 ServiceName, 1848 DELETE | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | WRITE_DAC); 1849 if (hService == NULL && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) 1850 goto cleanup; 1851 1852 if (hService && (ServiceFlags & SPSVCINST_DELETEEVENTLOGENTRY)) 1853 { 1854 ret = DeleteService(hService); 1855 if (!ret && GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE) 1856 goto cleanup; 1857 } 1858 1859 if (hService == NULL) 1860 { 1861 /* Create new service */ 1862 hService = CreateServiceW( 1863 hSCManager, 1864 ServiceName, 1865 DisplayName, 1866 WRITE_DAC, 1867 ServiceType, 1868 StartType, 1869 ErrorControl, 1870 ServiceBinary, 1871 LoadOrderGroup, 1872 useTag ? &tagId : NULL, 1873 Dependencies, 1874 StartName, 1875 NULL); 1876 if (hService == NULL) 1877 goto cleanup; 1878 } 1879 else 1880 { 1881 DWORD bufferSize; 1882 /* Read current configuration */ 1883 if (!QueryServiceConfigW(hService, NULL, 0, &bufferSize)) 1884 { 1885 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 1886 goto cleanup; 1887 ServiceConfig = MyMalloc(bufferSize); 1888 if (!ServiceConfig) 1889 { 1890 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1891 goto cleanup; 1892 } 1893 if (!QueryServiceConfigW(hService, ServiceConfig, bufferSize, &bufferSize)) 1894 goto cleanup; 1895 } 1896 tagId = ServiceConfig->dwTagId; 1897 1898 /* Update configuration */ 1899 ret = ChangeServiceConfigW( 1900 hService, 1901 ServiceType, 1902 (ServiceFlags & SPSVCINST_NOCLOBBER_STARTTYPE) ? SERVICE_NO_CHANGE : StartType, 1903 (ServiceFlags & SPSVCINST_NOCLOBBER_ERRORCONTROL) ? SERVICE_NO_CHANGE : ErrorControl, 1904 ServiceBinary, 1905 (ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP && ServiceConfig->lpLoadOrderGroup) ? NULL : LoadOrderGroup, 1906 useTag ? &tagId : NULL, 1907 (ServiceFlags & SPSVCINST_NOCLOBBER_DEPENDENCIES && ServiceConfig->lpDependencies) ? NULL : Dependencies, 1908 StartName, 1909 NULL, 1910 (ServiceFlags & SPSVCINST_NOCLOBBER_DISPLAYNAME && ServiceConfig->lpDisplayName) ? NULL : DisplayName); 1911 if (!ret) 1912 goto cleanup; 1913 } 1914 1915 /* Set security */ 1916 if (GetLineText(hInf, ServiceSection, SecurityKey, &SecurityDescriptor)) 1917 { 1918 ret = ConvertStringSecurityDescriptorToSecurityDescriptorW(SecurityDescriptor, SDDL_REVISION_1, &sd, NULL); 1919 if (!ret) 1920 goto cleanup; 1921 ret = SetServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, sd); 1922 if (!ret) 1923 goto cleanup; 1924 } 1925 1926 /* FIXME: use Description and SPSVCINST_NOCLOBBER_DESCRIPTION */ 1927 1928 if (useTag) 1929 { 1930 /* Add the tag to SYSTEM\CurrentControlSet\Control\GroupOrderList key */ 1931 LPCWSTR lpLoadOrderGroup; 1932 DWORD bufferSize; 1933 1934 lpLoadOrderGroup = LoadOrderGroup; 1935 if ((ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP) && ServiceConfig && ServiceConfig->lpLoadOrderGroup) 1936 lpLoadOrderGroup = ServiceConfig->lpLoadOrderGroup; 1937 1938 rc = RegOpenKeyW( 1939 list ? list->HKLM : HKEY_LOCAL_MACHINE, 1940 GroupOrderListKey, 1941 &hGroupOrderListKey); 1942 if (rc != ERROR_SUCCESS) 1943 { 1944 SetLastError(rc); 1945 goto cleanup; 1946 } 1947 rc = RegQueryValueExW(hGroupOrderListKey, lpLoadOrderGroup, NULL, &dwRegType, NULL, &bufferSize); 1948 if (rc == ERROR_FILE_NOT_FOUND) 1949 bufferSize = sizeof(DWORD); 1950 else if (rc != ERROR_SUCCESS) 1951 { 1952 SetLastError(rc); 1953 goto cleanup; 1954 } 1955 else if (dwRegType != REG_BINARY || bufferSize == 0 || bufferSize % sizeof(DWORD) != 0) 1956 { 1957 SetLastError(ERROR_GEN_FAILURE); 1958 goto cleanup; 1959 } 1960 /* Allocate buffer to store existing data + the new tag */ 1961 GroupOrder = MyMalloc(bufferSize + sizeof(DWORD)); 1962 if (!GroupOrder) 1963 { 1964 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1965 goto cleanup; 1966 } 1967 if (rc == ERROR_SUCCESS) 1968 { 1969 /* Read existing data */ 1970 rc = RegQueryValueExW( 1971 hGroupOrderListKey, 1972 lpLoadOrderGroup, 1973 NULL, 1974 NULL, 1975 (BYTE*)GroupOrder, 1976 &bufferSize); 1977 if (rc != ERROR_SUCCESS) 1978 { 1979 SetLastError(rc); 1980 goto cleanup; 1981 } 1982 if (ServiceFlags & SPSVCINST_TAGTOFRONT) 1983 memmove(&GroupOrder[2], &GroupOrder[1], bufferSize - sizeof(DWORD)); 1984 } 1985 else 1986 { 1987 GroupOrder[0] = 0; 1988 } 1989 GroupOrder[0]++; 1990 if (ServiceFlags & SPSVCINST_TAGTOFRONT) 1991 GroupOrder[1] = tagId; 1992 else 1993 GroupOrder[bufferSize / sizeof(DWORD)] = tagId; 1994 1995 rc = RegSetValueExW( 1996 hGroupOrderListKey, 1997 lpLoadOrderGroup, 1998 0, 1999 REG_BINARY, 2000 (BYTE*)GroupOrder, 2001 bufferSize + sizeof(DWORD)); 2002 if (rc != ERROR_SUCCESS) 2003 { 2004 SetLastError(rc); 2005 goto cleanup; 2006 } 2007 } 2008 2009 /* Handle AddReg and DelReg */ 2010 rc = RegOpenKeyExW( 2011 list ? list->HKLM : HKEY_LOCAL_MACHINE, 2012 REGSTR_PATH_SERVICES, 2013 0, 2014 READ_CONTROL, 2015 &hServicesKey); 2016 if (rc != ERROR_SUCCESS) 2017 { 2018 SetLastError(rc); 2019 goto cleanup; 2020 } 2021 rc = RegOpenKeyExW( 2022 hServicesKey, 2023 ServiceName, 2024 0, 2025 KEY_READ | KEY_WRITE, 2026 &hServiceKey); 2027 RegCloseKey(hServicesKey); 2028 if (rc != ERROR_SUCCESS) 2029 { 2030 SetLastError(rc); 2031 goto cleanup; 2032 } 2033 2034 ret = SetupInstallFromInfSectionW( 2035 NULL, 2036 hInf, 2037 ServiceSection, 2038 SPINST_REGISTRY, 2039 hServiceKey, 2040 NULL, 2041 0, 2042 NULL, 2043 NULL, 2044 NULL, 2045 NULL); 2046 RegCloseKey(hServiceKey); 2047 2048 cleanup: 2049 if (hSCManager != NULL) 2050 CloseServiceHandle(hSCManager); 2051 if (hService != NULL) 2052 CloseServiceHandle(hService); 2053 if (hGroupOrderListKey != NULL) 2054 RegCloseKey(hGroupOrderListKey); 2055 if (sd != NULL) 2056 LocalFree(sd); 2057 MyFree(ServiceConfig); 2058 MyFree(ServiceBinary); 2059 MyFree(LoadOrderGroup); 2060 MyFree(DisplayName); 2061 MyFree(Description); 2062 MyFree(Dependencies); 2063 MyFree(SecurityDescriptor); 2064 MyFree(GroupOrder); 2065 MyFree(StartName); 2066 2067 TRACE("Returning %d\n", ret); 2068 return ret; 2069 } 2070 2071 2072 /*********************************************************************** 2073 * SetupInstallServicesFromInfSectionExW (SETUPAPI.@) 2074 */ 2075 BOOL WINAPI SetupInstallServicesFromInfSectionExW( HINF hinf, PCWSTR sectionname, DWORD flags, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PVOID reserved1, PVOID reserved2 ) 2076 { 2077 struct DeviceInfoSet *list = NULL; 2078 BOOL ret = FALSE; 2079 2080 TRACE("%p, %s, 0x%lx, %p, %p, %p, %p\n", hinf, debugstr_w(sectionname), 2081 flags, DeviceInfoSet, DeviceInfoData, reserved1, reserved2); 2082 2083 if (!sectionname) 2084 SetLastError(ERROR_INVALID_PARAMETER); 2085 else if (flags & ~(SPSVCINST_TAGTOFRONT | SPSVCINST_DELETEEVENTLOGENTRY | SPSVCINST_NOCLOBBER_DISPLAYNAME | SPSVCINST_NOCLOBBER_STARTTYPE | SPSVCINST_NOCLOBBER_ERRORCONTROL | SPSVCINST_NOCLOBBER_LOADORDERGROUP | SPSVCINST_NOCLOBBER_DEPENDENCIES | SPSVCINST_STOPSERVICE)) 2086 { 2087 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)); 2088 SetLastError(ERROR_INVALID_FLAGS); 2089 } 2090 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE) 2091 SetLastError(ERROR_INVALID_HANDLE); 2092 else if (DeviceInfoSet && (list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC) 2093 SetLastError(ERROR_INVALID_HANDLE); 2094 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) 2095 SetLastError(ERROR_INVALID_USER_BUFFER); 2096 else if (reserved1 != NULL || reserved2 != NULL) 2097 SetLastError(ERROR_INVALID_PARAMETER); 2098 else 2099 { 2100 struct needs_callback_info needs_info; 2101 LPWSTR ServiceName = NULL; 2102 LPWSTR ServiceSection = NULL; 2103 INT ServiceFlags; 2104 INFCONTEXT ContextService; 2105 BOOL bNeedReboot = FALSE; 2106 2107 /* Parse 'Include' and 'Needs' directives */ 2108 iterate_section_fields( hinf, sectionname, Include, include_callback, NULL); 2109 needs_info.type = 1; 2110 needs_info.flags = flags; 2111 needs_info.devinfo = DeviceInfoSet; 2112 needs_info.devinfo_data = DeviceInfoData; 2113 needs_info.reserved1 = reserved1; 2114 needs_info.reserved2 = reserved2; 2115 iterate_section_fields( hinf, sectionname, Needs, needs_callback, &needs_info); 2116 2117 if (flags & SPSVCINST_STOPSERVICE) 2118 { 2119 FIXME("Stopping the device not implemented\n"); 2120 /* This may lead to require a reboot */ 2121 /* bNeedReboot = TRUE; */ 2122 #if 0 2123 SERVICE_STATUS ServiceStatus; 2124 ret = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus); 2125 if (!ret && GetLastError() != ERROR_SERVICE_NOT_ACTIVE) 2126 goto done; 2127 if (ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING && ServiceStatus.dwCurrentState != SERVICE_STOPPED) 2128 { 2129 SetLastError(ERROR_INSTALL_SERVICE_FAILURE); 2130 goto done; 2131 } 2132 #endif 2133 flags &= ~SPSVCINST_STOPSERVICE; 2134 } 2135 2136 if (!(ret = SetupFindFirstLineW( hinf, sectionname, NULL, &ContextService ))) 2137 { 2138 SetLastError( ERROR_SECTION_NOT_FOUND ); 2139 goto done; 2140 } 2141 2142 ret = SetupFindFirstLineW(hinf, sectionname, AddService, &ContextService); 2143 while (ret) 2144 { 2145 if (!GetStringField(&ContextService, 1, &ServiceName)) 2146 goto done; 2147 2148 ret = SetupGetIntField( 2149 &ContextService, 2150 2, /* Field index */ 2151 &ServiceFlags); 2152 if (!ret) 2153 { 2154 /* The field may be empty. Ignore the error */ 2155 ServiceFlags = 0; 2156 } 2157 2158 if (!GetStringField(&ContextService, 3, &ServiceSection)) 2159 goto done; 2160 2161 ret = InstallOneService(list, hinf, ServiceSection, ServiceName, (ServiceFlags & ~SPSVCINST_ASSOCSERVICE) | flags); 2162 if (!ret) 2163 goto done; 2164 2165 if (ServiceFlags & SPSVCINST_ASSOCSERVICE) 2166 { 2167 ret = SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet, DeviceInfoData, SPDRP_SERVICE, (LPBYTE)ServiceName, (strlenW(ServiceName) + 1) * sizeof(WCHAR)); 2168 if (!ret) 2169 goto done; 2170 } 2171 2172 HeapFree(GetProcessHeap(), 0, ServiceName); 2173 HeapFree(GetProcessHeap(), 0, ServiceSection); 2174 ServiceName = ServiceSection = NULL; 2175 ret = SetupFindNextMatchLineW(&ContextService, AddService, &ContextService); 2176 } 2177 2178 if (bNeedReboot) 2179 SetLastError(ERROR_SUCCESS_REBOOT_REQUIRED); 2180 else 2181 SetLastError(ERROR_SUCCESS); 2182 ret = TRUE; 2183 } 2184 done: 2185 TRACE("Returning %d\n", ret); 2186 return ret; 2187 } 2188 2189 2190 /*********************************************************************** 2191 * SetupCopyOEMInfA (SETUPAPI.@) 2192 */ 2193 BOOL WINAPI SetupCopyOEMInfA( 2194 IN PCSTR SourceInfFileName, 2195 IN PCSTR OEMSourceMediaLocation, 2196 IN DWORD OEMSourceMediaType, 2197 IN DWORD CopyStyle, 2198 OUT PSTR DestinationInfFileName OPTIONAL, 2199 IN DWORD DestinationInfFileNameSize, 2200 OUT PDWORD RequiredSize OPTIONAL, 2201 OUT PSTR* DestinationInfFileNameComponent OPTIONAL) 2202 { 2203 PWSTR SourceInfFileNameW = NULL; 2204 PWSTR OEMSourceMediaLocationW = NULL; 2205 PWSTR DestinationInfFileNameW = NULL; 2206 PWSTR DestinationInfFileNameComponentW = NULL; 2207 BOOL ret = FALSE; 2208 DWORD size; 2209 2210 TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n", 2211 SourceInfFileName, OEMSourceMediaLocation, OEMSourceMediaType, 2212 CopyStyle, DestinationInfFileName, DestinationInfFileNameSize, 2213 RequiredSize, DestinationInfFileNameComponent); 2214 2215 if (!DestinationInfFileName && DestinationInfFileNameSize > 0) 2216 SetLastError(ERROR_INVALID_PARAMETER); 2217 else if (!(SourceInfFileNameW = pSetupMultiByteToUnicode(SourceInfFileName, CP_ACP))) 2218 SetLastError(ERROR_INVALID_PARAMETER); 2219 else if (OEMSourceMediaType != SPOST_NONE && !(OEMSourceMediaLocationW = pSetupMultiByteToUnicode(OEMSourceMediaLocation, CP_ACP))) 2220 SetLastError(ERROR_INVALID_PARAMETER); 2221 else 2222 { 2223 if (DestinationInfFileNameSize != 0) 2224 { 2225 DestinationInfFileNameW = MyMalloc(DestinationInfFileNameSize * sizeof(WCHAR)); 2226 if (!DestinationInfFileNameW) 2227 { 2228 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2229 goto cleanup; 2230 } 2231 } 2232 2233 ret = SetupCopyOEMInfW( 2234 SourceInfFileNameW, 2235 OEMSourceMediaLocationW, 2236 OEMSourceMediaType, 2237 CopyStyle, 2238 DestinationInfFileNameW, 2239 DestinationInfFileNameSize, 2240 &size, 2241 DestinationInfFileNameComponent ? &DestinationInfFileNameComponentW : NULL); 2242 if (!ret) 2243 { 2244 if (RequiredSize) *RequiredSize = size; 2245 goto cleanup; 2246 } 2247 2248 if (DestinationInfFileNameSize != 0) 2249 { 2250 if (WideCharToMultiByte(CP_ACP, 0, DestinationInfFileNameW, -1, 2251 DestinationInfFileName, DestinationInfFileNameSize, NULL, NULL) == 0) 2252 { 2253 DestinationInfFileName[0] = '\0'; 2254 goto cleanup; 2255 } 2256 } 2257 if (DestinationInfFileNameComponent) 2258 { 2259 if (DestinationInfFileNameComponentW) 2260 *DestinationInfFileNameComponent = &DestinationInfFileName[DestinationInfFileNameComponentW - DestinationInfFileNameW]; 2261 else 2262 *DestinationInfFileNameComponent = NULL; 2263 } 2264 ret = TRUE; 2265 } 2266 2267 cleanup: 2268 MyFree(SourceInfFileNameW); 2269 MyFree(OEMSourceMediaLocationW); 2270 MyFree(DestinationInfFileNameW); 2271 TRACE("Returning %d\n", ret); 2272 if (ret) SetLastError(ERROR_SUCCESS); 2273 return ret; 2274 } 2275 2276 static int compare_files( HANDLE file1, HANDLE file2 ) 2277 { 2278 char buffer1[2048]; 2279 char buffer2[2048]; 2280 DWORD size1; 2281 DWORD size2; 2282 2283 while( ReadFile(file1, buffer1, sizeof(buffer1), &size1, NULL) && 2284 ReadFile(file2, buffer2, sizeof(buffer2), &size2, NULL) ) 2285 { 2286 int ret; 2287 if (size1 != size2) 2288 return size1 > size2 ? 1 : -1; 2289 if (!size1) 2290 return 0; 2291 ret = memcmp( buffer1, buffer2, size1 ); 2292 if (ret) 2293 return ret; 2294 } 2295 2296 return 0; 2297 } 2298 2299 /*********************************************************************** 2300 * SetupCopyOEMInfW (SETUPAPI.@) 2301 */ 2302 BOOL WINAPI SetupCopyOEMInfW( 2303 IN PCWSTR SourceInfFileName, 2304 IN PCWSTR OEMSourceMediaLocation, 2305 IN DWORD OEMSourceMediaType, 2306 IN DWORD CopyStyle, 2307 OUT PWSTR DestinationInfFileName OPTIONAL, 2308 IN DWORD DestinationInfFileNameSize, 2309 OUT PDWORD RequiredSize OPTIONAL, 2310 OUT PWSTR* DestinationInfFileNameComponent OPTIONAL) 2311 { 2312 BOOL ret = FALSE; 2313 2314 TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n", 2315 debugstr_w(SourceInfFileName), debugstr_w(OEMSourceMediaLocation), OEMSourceMediaType, 2316 CopyStyle, DestinationInfFileName, DestinationInfFileNameSize, 2317 RequiredSize, DestinationInfFileNameComponent); 2318 2319 if (!SourceInfFileName) 2320 SetLastError(ERROR_INVALID_PARAMETER); 2321 else if (OEMSourceMediaType != SPOST_NONE && OEMSourceMediaType != SPOST_PATH && OEMSourceMediaType != SPOST_URL) 2322 SetLastError(ERROR_INVALID_PARAMETER); 2323 else if (CopyStyle & ~(SP_COPY_DELETESOURCE | SP_COPY_REPLACEONLY | SP_COPY_NOOVERWRITE | SP_COPY_OEMINF_CATALOG_ONLY)) 2324 { 2325 TRACE("Unknown flags: 0x%08lx\n", CopyStyle & ~(SP_COPY_DELETESOURCE | SP_COPY_REPLACEONLY | SP_COPY_NOOVERWRITE | SP_COPY_OEMINF_CATALOG_ONLY)); 2326 SetLastError(ERROR_INVALID_FLAGS); 2327 } 2328 else if (!DestinationInfFileName && DestinationInfFileNameSize > 0) 2329 SetLastError(ERROR_INVALID_PARAMETER); 2330 else if (CopyStyle & SP_COPY_OEMINF_CATALOG_ONLY) 2331 { 2332 FIXME("CopyStyle 0x%x not supported\n", SP_COPY_OEMINF_CATALOG_ONLY); 2333 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 2334 } 2335 else 2336 { 2337 HANDLE hSearch = INVALID_HANDLE_VALUE; 2338 WIN32_FIND_DATAW FindFileData; 2339 BOOL AlreadyExists; 2340 DWORD NextFreeNumber = 0; 2341 SIZE_T len; 2342 LPWSTR pFullFileName = NULL; 2343 LPWSTR pFileName; /* Pointer into pFullFileName buffer */ 2344 HANDLE hSourceFile = INVALID_HANDLE_VALUE; 2345 2346 if (OEMSourceMediaType == SPOST_PATH || OEMSourceMediaType == SPOST_URL) 2347 FIXME("OEMSourceMediaType 0x%lx ignored\n", OEMSourceMediaType); 2348 2349 /* Check if source file exists, and open it */ 2350 if (strchrW(SourceInfFileName, '\\' ) || strchrW(SourceInfFileName, '/' )) 2351 { 2352 WCHAR *path; 2353 2354 if (!(len = GetFullPathNameW(SourceInfFileName, 0, NULL, NULL))) 2355 return FALSE; 2356 if (!(path = MyMalloc(len * sizeof(WCHAR)))) 2357 { 2358 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2359 return FALSE; 2360 } 2361 GetFullPathNameW(SourceInfFileName, len, path, NULL); 2362 hSourceFile = CreateFileW( 2363 path, FILE_READ_DATA | FILE_READ_ATTRIBUTES, 2364 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 2365 NULL, OPEN_EXISTING, 0, NULL); 2366 MyFree(path); 2367 } 2368 else /* try Windows directory */ 2369 { 2370 WCHAR *path, *p; 2371 static const WCHAR Inf[] = {'\\','i','n','f','\\',0}; 2372 static const WCHAR System32[] = {'\\','s','y','s','t','e','m','3','2','\\',0}; 2373 2374 len = GetWindowsDirectoryW(NULL, 0) + strlenW(SourceInfFileName) + 12; 2375 if (!(path = MyMalloc(len * sizeof(WCHAR)))) 2376 { 2377 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2378 return FALSE; 2379 } 2380 GetWindowsDirectoryW(path, len); 2381 p = path + strlenW(path); 2382 strcpyW(p, Inf); 2383 strcatW(p, SourceInfFileName); 2384 hSourceFile = CreateFileW( 2385 path, FILE_READ_DATA | FILE_READ_ATTRIBUTES, 2386 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 2387 NULL, OPEN_EXISTING, 0, NULL); 2388 if (hSourceFile == INVALID_HANDLE_VALUE) 2389 { 2390 strcpyW(p, System32); 2391 strcatW(p, SourceInfFileName); 2392 hSourceFile = CreateFileW( 2393 path, FILE_READ_DATA | FILE_READ_ATTRIBUTES, 2394 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 2395 NULL, OPEN_EXISTING, 0, NULL); 2396 } 2397 MyFree(path); 2398 } 2399 if (hSourceFile == INVALID_HANDLE_VALUE) 2400 { 2401 SetLastError(ERROR_FILE_NOT_FOUND); 2402 goto cleanup; 2403 } 2404 2405 /* Prepare .inf file specification */ 2406 len = MAX_PATH + 1 + strlenW(InfDirectory) + 13; 2407 pFullFileName = MyMalloc(len * sizeof(WCHAR)); 2408 if (!pFullFileName) 2409 { 2410 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2411 goto cleanup; 2412 } 2413 len = GetSystemWindowsDirectoryW(pFullFileName, MAX_PATH); 2414 if (len == 0 || len > MAX_PATH) 2415 goto cleanup; 2416 if (pFullFileName[strlenW(pFullFileName) - 1] != '\\') 2417 strcatW(pFullFileName, BackSlash); 2418 strcatW(pFullFileName, InfDirectory); 2419 pFileName = &pFullFileName[strlenW(pFullFileName)]; 2420 2421 /* Search if the specified .inf file already exists in %WINDIR%\Inf */ 2422 AlreadyExists = FALSE; 2423 strcpyW(pFileName, OemFileMask); 2424 hSearch = FindFirstFileW(pFullFileName, &FindFileData); 2425 if (hSearch != INVALID_HANDLE_VALUE) 2426 { 2427 LARGE_INTEGER SourceFileSize; 2428 2429 if (GetFileSizeEx(hSourceFile, &SourceFileSize)) 2430 { 2431 do 2432 { 2433 LARGE_INTEGER DestFileSize; 2434 HANDLE hDestFile; 2435 2436 strcpyW(pFileName, FindFileData.cFileName); 2437 hDestFile = CreateFileW( 2438 pFullFileName, FILE_READ_DATA | FILE_READ_ATTRIBUTES, 2439 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 2440 NULL, OPEN_EXISTING, 0, NULL); 2441 if (hDestFile != INVALID_HANDLE_VALUE) 2442 { 2443 if (GetFileSizeEx(hDestFile, &DestFileSize) 2444 && DestFileSize.QuadPart == SourceFileSize.QuadPart 2445 && !compare_files(hSourceFile, hDestFile)) 2446 { 2447 TRACE("%s already exists as %s\n", 2448 debugstr_w(SourceInfFileName), debugstr_w(pFileName)); 2449 AlreadyExists = TRUE; 2450 } 2451 } 2452 } while (!AlreadyExists && FindNextFileW(hSearch, &FindFileData)); 2453 } 2454 FindClose(hSearch); 2455 hSearch = INVALID_HANDLE_VALUE; 2456 } 2457 2458 if (!AlreadyExists && CopyStyle & SP_COPY_REPLACEONLY) 2459 { 2460 /* FIXME: set DestinationInfFileName, RequiredSize, DestinationInfFileNameComponent */ 2461 SetLastError(ERROR_FILE_NOT_FOUND); 2462 goto cleanup; 2463 } 2464 else if (AlreadyExists && (CopyStyle & SP_COPY_NOOVERWRITE)) 2465 { 2466 DWORD Size = strlenW(pFileName) + 1; 2467 2468 if (RequiredSize) 2469 *RequiredSize = Size; 2470 if (DestinationInfFileNameSize == 0) 2471 SetLastError(ERROR_FILE_EXISTS); 2472 else if (DestinationInfFileNameSize < Size) 2473 SetLastError(ERROR_INSUFFICIENT_BUFFER); 2474 else 2475 { 2476 SetLastError(ERROR_FILE_EXISTS); 2477 strcpyW(DestinationInfFileName, pFileName); 2478 } 2479 goto cleanup; 2480 } 2481 2482 /* Search the number to give to OEM??.INF */ 2483 strcpyW(pFileName, OemFileMask); 2484 hSearch = FindFirstFileW(pFullFileName, &FindFileData); 2485 if (hSearch == INVALID_HANDLE_VALUE) 2486 { 2487 if (GetLastError() != ERROR_FILE_NOT_FOUND) 2488 goto cleanup; 2489 } 2490 else 2491 { 2492 do 2493 { 2494 DWORD CurrentNumber; 2495 if (swscanf(FindFileData.cFileName, OemFileSpecification, &CurrentNumber) == 1 2496 && CurrentNumber <= 99999) 2497 { 2498 if (CurrentNumber >= NextFreeNumber) 2499 NextFreeNumber = CurrentNumber + 1; 2500 } 2501 } while (FindNextFileW(hSearch, &FindFileData)); 2502 } 2503 2504 if (NextFreeNumber > 99999) 2505 { 2506 ERR("Too much custom .inf files\n"); 2507 SetLastError(ERROR_GEN_FAILURE); 2508 goto cleanup; 2509 } 2510 2511 /* Create the full path: %WINDIR%\Inf\OEM{XXXXX}.inf */ 2512 sprintfW(pFileName, OemFileSpecification, NextFreeNumber); 2513 TRACE("Next available file is %s\n", debugstr_w(pFileName)); 2514 2515 if (!CopyFileW(SourceInfFileName, pFullFileName, TRUE)) 2516 { 2517 TRACE("CopyFileW() failed with error 0x%lx\n", GetLastError()); 2518 goto cleanup; 2519 } 2520 2521 len = strlenW(pFullFileName) + 1; 2522 if (RequiredSize) 2523 *RequiredSize = len; 2524 if (DestinationInfFileName) 2525 { 2526 if (DestinationInfFileNameSize >= len) 2527 { 2528 strcpyW(DestinationInfFileName, pFullFileName); 2529 if (DestinationInfFileNameComponent) 2530 *DestinationInfFileNameComponent = &DestinationInfFileName[pFileName - pFullFileName]; 2531 } 2532 else 2533 { 2534 SetLastError(ERROR_INSUFFICIENT_BUFFER); 2535 goto cleanup; 2536 } 2537 } 2538 2539 if (CopyStyle & SP_COPY_DELETESOURCE) 2540 { 2541 if (!DeleteFileW(SourceInfFileName)) 2542 { 2543 TRACE("DeleteFileW() failed with error 0x%lx\n", GetLastError()); 2544 goto cleanup; 2545 } 2546 } 2547 2548 ret = TRUE; 2549 2550 cleanup: 2551 if (hSourceFile != INVALID_HANDLE_VALUE) 2552 CloseHandle(hSourceFile); 2553 if (hSearch != INVALID_HANDLE_VALUE) 2554 FindClose(hSearch); 2555 MyFree(pFullFileName); 2556 } 2557 2558 TRACE("Returning %d\n", ret); 2559 if (ret) SetLastError(ERROR_SUCCESS); 2560 return ret; 2561 } 2562