2 * Setupapi install routines
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
5 * 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
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.
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.
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
22 #include "setupapi_private.h"
25 #include <ndk/cmfuncs.h>
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};
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};
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};
57 /* info passed to callback functions dealing with files */
58 struct files_callback_info
66 /* info passed to callback functions dealing with the registry */
67 struct registry_callback_info
73 /* info passed to callback functions dealing with registering dlls */
74 struct register_dll_info
76 PSP_FILE_CALLBACK_W callback
;
77 PVOID callback_context
;
81 /* info passed to callback functions dealing with Needs directives */
82 struct needs_callback_info
94 PSP_DEVINFO_DATA devinfo_data
;
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
);
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};
125 static const WCHAR WineFakeDlls
[] = {'W','i','n','e','F','a','k','e','D','l','l','s',0};
129 /***********************************************************************
132 * Retrieve the contents of a field, dynamically growing the buffer if necessary.
134 static WCHAR
*get_field_string( INFCONTEXT
*context
, DWORD index
, WCHAR
*buffer
,
135 WCHAR
*static_buffer
, DWORD
*size
)
139 if (SetupGetStringFieldW( context
, index
, buffer
, *size
, &required
)) return buffer
;
140 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
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
;
146 if (SetupGetStringFieldW( context
, index
, buffer
, *size
, &required
)) return buffer
;
148 if (buffer
!= static_buffer
) HeapFree( GetProcessHeap(), 0, buffer
);
153 /***********************************************************************
154 * copy_files_callback
156 * Called once for each CopyFiles entry in a given section.
158 static BOOL
copy_files_callback( HINF hinf
, PCWSTR field
, void *arg
)
160 struct files_callback_info
*info
= arg
;
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
);
165 SetupQueueCopySectionW( info
->queue
, info
->src_root
, info
->layout
? info
->layout
: hinf
, hinf
, field
, info
->copy_flags
);
170 /***********************************************************************
171 * delete_files_callback
173 * Called once for each DelFiles entry in a given section.
175 static BOOL
delete_files_callback( HINF hinf
, PCWSTR field
, void *arg
)
177 struct files_callback_info
*info
= arg
;
178 SetupQueueDeleteSectionW( info
->queue
, hinf
, 0, field
);
183 /***********************************************************************
184 * rename_files_callback
186 * Called once for each RenFiles entry in a given section.
188 static BOOL
rename_files_callback( HINF hinf
, PCWSTR field
, void *arg
)
190 struct files_callback_info
*info
= arg
;
191 SetupQueueRenameSectionW( info
->queue
, hinf
, 0, field
);
196 /***********************************************************************
199 * Retrieve the registry root key from its name.
201 static HKEY
get_root_key( const WCHAR
*name
, HKEY def_root
)
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};
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
;
218 /***********************************************************************
219 * append_multi_sz_value
221 * Append a multisz string to a multisz registry value.
223 static void append_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*strings
,
226 DWORD size
, type
, total
;
229 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
230 if (type
!= REG_MULTI_SZ
) return;
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
;
236 /* compare each string against all the existing ones */
240 int len
= strlenW(strings
) + 1;
242 for (p
= buffer
; *p
; p
+= strlenW(p
) + 1)
243 if (!strcmpiW( p
, strings
)) break;
245 if (!*p
) /* not found, need to append it */
247 memcpy( p
, strings
, len
* sizeof(WCHAR
) );
249 total
+= len
* sizeof(WCHAR
);
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
) );
259 HeapFree( GetProcessHeap(), 0, buffer
);
263 /***********************************************************************
264 * delete_multi_sz_value
266 * Remove a string from a multisz registry value.
268 static void delete_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*string
)
271 WCHAR
*buffer
, *src
, *dst
;
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
;
282 int len
= strlenW(src
) + 1;
283 if (strcmpiW( src
, string
))
285 memcpy( dst
, src
, len
* sizeof(WCHAR
) );
291 if (dst
!= buffer
+ 2*size
) /* did we remove something? */
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
) );
298 HeapFree( GetProcessHeap(), 0, buffer
);
302 /***********************************************************************
305 * Perform an add/delete registry operation depending on the flags.
307 static BOOL
do_reg_operation( HKEY hkey
, const WCHAR
*value
, INFCONTEXT
*context
, INT flags
)
311 if (flags
& (FLG_ADDREG_DELREG_BIT
| FLG_ADDREG_DELVAL
)) /* deletion */
313 if (*value
&& !(flags
& FLG_DELREG_KEYONLY_COMMON
))
315 if ((flags
& FLG_DELREG_MULTI_SZ_DELSTRING
) == FLG_DELREG_MULTI_SZ_DELSTRING
)
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
);
325 else RegDeleteValueW( hkey
, value
);
327 else NtDeleteKey( hkey
);
331 if (flags
& (FLG_ADDREG_KEYONLY
|FLG_ADDREG_KEYONLY_COMMON
)) return TRUE
;
333 if (flags
& (FLG_ADDREG_NOCLOBBER
|FLG_ADDREG_OVERWRITEONLY
))
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
;
340 switch(flags
& FLG_ADDREG_TYPE_MASK
)
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;
351 if (!(flags
& FLG_ADDREG_BINVALUETYPE
) ||
352 (type
== REG_DWORD
&& SetupGetFieldCount(context
) == 5))
354 static const WCHAR empty
;
357 if (type
== REG_MULTI_SZ
)
359 if (!SetupGetMultiSzFieldW( context
, 5, NULL
, 0, &size
)) size
= 0;
362 if (!(str
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return FALSE
;
363 SetupGetMultiSzFieldW( context
, 5, str
, size
, NULL
);
365 if (flags
& FLG_ADDREG_APPEND
)
367 if (!str
) return TRUE
;
368 append_multi_sz_value( hkey
, value
, str
, size
);
369 HeapFree( GetProcessHeap(), 0, str
);
372 /* else fall through to normal string handling */
376 if (!SetupGetStringFieldW( context
, 5, NULL
, 0, &size
)) size
= 0;
379 if (!(str
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return FALSE
;
380 SetupGetStringFieldW( context
, 5, str
, size
, NULL
);
384 if (type
== REG_DWORD
)
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
) );
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
) );
396 HeapFree( GetProcessHeap(), 0, str
);
399 else /* get the binary data */
403 if (!SetupGetBinaryField( context
, 5, NULL
, 0, &size
)) size
= 0;
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
);
410 RegSetValueExW( hkey
, value
, 0, type
, data
, size
);
411 HeapFree( GetProcessHeap(), 0, data
);
417 /***********************************************************************
420 * Called once for each AddReg and DelReg entry in a given section.
422 static BOOL
registry_callback( HINF hinf
, PCWSTR field
, void *arg
)
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, };
432 BOOL ok
= SetupFindFirstLineW( hinf
, field
, NULL
, &context
);
436 /* Check for .Security section */
437 security_key
= MyMalloc( (strlenW( field
) + strlenW( DotSecurity
)) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
) );
440 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
443 strcpyW( security_key
, field
);
444 strcatW( security_key
, DotSecurity
);
445 ok
= SetupFindFirstLineW( hinf
, security_key
, NULL
, &security_context
);
446 MyFree(security_key
);
449 if (!SetupGetLineTextW( &security_context
, NULL
, NULL
, NULL
, NULL
, 0, &required
))
451 security_descriptor
= MyMalloc( required
* sizeof(WCHAR
) );
452 if (!security_descriptor
)
454 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
457 if (!SetupGetLineTextW( &security_context
, NULL
, NULL
, NULL
, security_descriptor
, required
, NULL
))
459 ok
= ConvertStringSecurityDescriptorToSecurityDescriptorW( security_descriptor
, SDDL_REVISION_1
, &sd
, NULL
);
460 MyFree( security_descriptor
);
463 security_attributes
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
464 security_attributes
.lpSecurityDescriptor
= sd
;
467 for (ok
= TRUE
; ok
; ok
= SetupFindNextLine( &context
, &context
))
469 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
473 if (!SetupGetStringFieldW( &context
, 1, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
475 if (!(root_key
= get_root_key( buffer
, info
->default_root
)))
479 if (!SetupGetStringFieldW( &context
, 2, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
483 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0;
487 if (flags
& FLG_ADDREG_DELREG_BIT
) continue; /* ignore this entry */
491 if (!flags
) flags
= FLG_ADDREG_DELREG_BIT
;
492 else if (!(flags
& FLG_ADDREG_DELREG_BIT
)) continue; /* ignore this entry */
495 if (info
->delete || (flags
& FLG_ADDREG_OVERWRITEONLY
))
497 if (RegOpenKeyW( root_key
, buffer
, &hkey
)) continue; /* ignore if it doesn't exist */
499 else if (RegCreateKeyExW( root_key
, buffer
, 0, NULL
, 0, MAXIMUM_ALLOWED
,
500 sd
? &security_attributes
: NULL
, &hkey
, NULL
))
502 ERR( "could not create key %p %s\n", root_key
, debugstr_w(buffer
) );
505 TRACE( "key %p %s\n", root_key
, debugstr_w(buffer
) );
508 if (!SetupGetStringFieldW( &context
, 3, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
512 if (!do_reg_operation( hkey
, buffer
, &context
, flags
))
514 if (hkey
!= root_key
) RegCloseKey( hkey
);
515 if (sd
) LocalFree( sd
);
518 if (hkey
!= root_key
) RegCloseKey( hkey
);
520 if (sd
) LocalFree( sd
);
525 /***********************************************************************
528 * Register or unregister a dll.
530 static BOOL
do_register_dll( const struct register_dll_info
*info
, const WCHAR
*path
,
531 INT flags
, INT timeout
, const WCHAR
*args
)
535 SP_REGISTER_CONTROL_STATUSW status
;
537 IMAGE_NT_HEADERS
*nt
;
540 status
.cbSize
= sizeof(status
);
541 status
.FileName
= path
;
542 status
.FailureCode
= SPREG_SUCCESS
;
543 status
.Win32Error
= ERROR_SUCCESS
;
547 switch(info
->callback( info
->callback_context
, SPFILENOTIFY_STARTREGISTRATION
,
548 (UINT_PTR
)&status
, !info
->unregister
))
551 SetLastError( ERROR_OPERATION_ABORTED
);
560 if (!(module
= LoadLibraryExW( path
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
)))
562 WARN( "could not load %s\n", debugstr_w(path
) );
563 status
.FailureCode
= SPREG_LOADLIBRARY
;
564 status
.Win32Error
= GetLastError();
569 if ((nt
= RtlImageNtHeader( module
)) && !(nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
))
571 /* file is an executable, not a dll */
572 STARTUPINFOW startup
;
573 PROCESS_INFORMATION info
;
576 static const WCHAR format
[] = {'"','%','s','"',' ','%','s',0};
577 static const WCHAR default_args
[] = {'/','R','e','g','S','e','r','v','e','r',0};
579 FreeLibrary( module
);
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
);
591 status
.FailureCode
= SPREG_LOADLIBRARY
;
592 status
.Win32Error
= GetLastError();
595 CloseHandle( info
.hThread
);
597 if (WaitForSingleObject( info
.hProcess
, timeout
*1000 ) == WAIT_TIMEOUT
)
599 /* timed out, kill the process */
600 TerminateProcess( info
.hProcess
, 1 );
601 status
.FailureCode
= SPREG_TIMEOUT
;
602 status
.Win32Error
= ERROR_TIMEOUT
;
604 CloseHandle( info
.hProcess
);
607 #endif // __WINESRC__
609 if (flags
& FLG_REGSVR_DLLREGISTER
)
611 const char *entry_point
= info
->unregister
? "DllUnregisterServer" : "DllRegisterServer";
612 HRESULT (WINAPI
*func
)(void) = (void *)GetProcAddress( module
, entry_point
);
616 status
.FailureCode
= SPREG_GETPROCADDR
;
617 status
.Win32Error
= GetLastError();
621 TRACE( "calling %s in %s\n", entry_point
, debugstr_w(path
) );
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
;
633 if (flags
& FLG_REGSVR_DLLINSTALL
)
635 HRESULT (WINAPI
*func
)(BOOL
,LPCWSTR
) = (void *)GetProcAddress( module
, "DllInstall" );
639 status
.FailureCode
= SPREG_GETPROCADDR
;
640 status
.Win32Error
= GetLastError();
644 TRACE( "calling DllInstall(%d,%s) in %s\n",
645 !info
->unregister
, debugstr_w(args
), debugstr_w(path
) );
646 res
= func( !info
->unregister
, args
);
650 WARN( "calling DllInstall in %s returned error %x\n", debugstr_w(path
), res
);
651 status
.FailureCode
= SPREG_REGSVR
;
652 status
.Win32Error
= res
;
658 if (module
) FreeLibrary( module
);
659 if (info
->callback
) info
->callback( info
->callback_context
, SPFILENOTIFY_ENDREGISTRATION
,
660 (UINT_PTR
)&status
, !info
->unregister
);
665 /***********************************************************************
666 * register_dlls_callback
668 * Called once for each RegisterDlls entry in a given section.
670 static BOOL
register_dlls_callback( HINF hinf
, PCWSTR field
, void *arg
)
672 struct register_dll_info
*info
= arg
;
675 BOOL ok
= SetupFindFirstLineW( hinf
, field
, NULL
, &context
);
677 for (; ok
; ok
= SetupFindNextLine( &context
, &context
))
679 WCHAR
*path
, *args
, *p
;
680 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
684 if (!(path
= PARSER_get_dest_dir( &context
))) continue;
687 if (!SetupGetStringFieldW( &context
, 3, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
689 if (!(p
= HeapReAlloc( GetProcessHeap(), 0, path
,
690 (strlenW(path
) + strlenW(buffer
) + 2) * sizeof(WCHAR
) ))) goto done
;
693 if (p
== path
|| p
[-1] != '\\') *p
++ = '\\';
694 strcpyW( p
, buffer
);
697 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0;
700 if (!SetupGetIntField( &context
, 5, &timeout
)) timeout
= 60;
702 /* get command line */
704 if (SetupGetStringFieldW( &context
, 6, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
707 ret
= do_register_dll( info
, path
, flags
, timeout
, args
);
710 HeapFree( GetProcessHeap(), 0, path
);
717 /***********************************************************************
720 * Called once for each WineFakeDlls entry in a given section.
722 static BOOL
fake_dlls_callback( HINF hinf
, PCWSTR field
, void *arg
)
726 BOOL ok
= SetupFindFirstLineW( hinf
, field
, NULL
, &context
);
728 for (; ok
; ok
= SetupFindNextLine( &context
, &context
))
731 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
734 if (!(path
= PARSER_get_dest_dir( &context
))) continue;
737 if (!SetupGetStringFieldW( &context
, 3, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
739 if (!(p
= HeapReAlloc( GetProcessHeap(), 0, path
,
740 (strlenW(path
) + strlenW(buffer
) + 2) * sizeof(WCHAR
) ))) goto done
;
743 if (p
== path
|| p
[-1] != '\\') *p
++ = '\\';
744 strcpyW( p
, buffer
);
747 if (SetupGetStringFieldW( &context
, 4, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
748 p
= buffer
; /* otherwise use target base name as default source */
750 create_fake_dll( path
, p
); /* ignore errors */
753 HeapFree( GetProcessHeap(), 0, path
);
758 #endif // __WINESRC__
760 /***********************************************************************
761 * update_ini_callback
763 * Called once for each UpdateInis entry in a given section.
765 static BOOL
update_ini_callback( HINF hinf
, PCWSTR field
, void *arg
)
769 BOOL ok
= SetupFindFirstLineW( hinf
, field
, NULL
, &context
);
771 for (; ok
; ok
= SetupFindNextLine( &context
, &context
))
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
];
780 if (!SetupGetStringFieldW( &context
, 1, filename
,
781 sizeof(filename
)/sizeof(WCHAR
), NULL
))
784 if (!SetupGetStringFieldW( &context
, 2, section
,
785 sizeof(section
)/sizeof(WCHAR
), NULL
))
788 if (!SetupGetStringFieldW( &context
, 4, buffer
,
789 sizeof(buffer
)/sizeof(WCHAR
), NULL
))
792 divider
= strchrW(buffer
,'=');
796 strcpyW(entry
,buffer
);
798 strcpyW(string
,divider
);
802 strcpyW(entry
,buffer
);
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
);
814 static BOOL
update_ini_fields_callback( HINF hinf
, PCWSTR field
, void *arg
)
816 FIXME( "should update ini fields %s\n", debugstr_w(field
) );
820 static BOOL
ini2reg_callback( HINF hinf
, PCWSTR field
, void *arg
)
822 FIXME( "should do ini2reg %s\n", debugstr_w(field
) );
826 static BOOL
logconf_callback( HINF hinf
, PCWSTR field
, void *arg
)
828 FIXME( "should do logconf %s\n", debugstr_w(field
) );
832 static BOOL
bitreg_callback( HINF hinf
, PCWSTR field
, void *arg
)
834 FIXME( "should do bitreg %s\n", debugstr_w(field
) );
838 static BOOL
Concatenate(int DirId
, LPCWSTR SubDirPart
, LPCWSTR NamePart
, LPWSTR
*pFullName
)
840 DWORD dwRequired
= 0;
846 Dir
= DIRID_get_string(DirId
);
848 dwRequired
+= wcslen(Dir
) + 1;
850 dwRequired
+= wcslen(SubDirPart
) + 1;
852 dwRequired
+= wcslen(NamePart
);
853 dwRequired
= dwRequired
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
855 FullName
= MyMalloc(dwRequired
);
858 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
861 FullName
[0] = UNICODE_NULL
;
865 wcscat(FullName
, Dir
);
866 if (FullName
[wcslen(FullName
) - 1] != '\\')
867 wcscat(FullName
, BackSlash
);
871 wcscat(FullName
, SubDirPart
);
872 if (FullName
[wcslen(FullName
) - 1] != '\\')
873 wcscat(FullName
, BackSlash
);
876 wcscat(FullName
, NamePart
);
878 *pFullName
= FullName
;
882 /***********************************************************************
883 * profile_items_callback
885 * Called once for each ProfileItems entry in a given section.
888 profile_items_callback(
890 IN PCWSTR SectionName
,
894 LPWSTR LinkSubDir
= NULL
, LinkName
= NULL
;
895 INT LinkAttributes
= 0;
898 INT CSIDL
= CSIDL_COMMON_PROGRAMS
;
899 LPWSTR FileSubDir
= NULL
;
901 LPWSTR SubDirPart
= NULL
, NamePart
= NULL
;
902 LPWSTR FullLinkName
= NULL
, FullFileName
= NULL
, FullWorkingDir
= NULL
, FullIconName
= NULL
;
904 LPWSTR lpHotKey
= NULL
, lpInfoTip
= NULL
;
905 LPWSTR DisplayName
= NULL
;
906 INT DisplayResId
= 0;
908 DWORD Index
, Required
;
912 HMODULE hOle32
= NULL
;
913 COINITIALIZE pCoInitialize
;
914 COCREATEINSTANCE pCoCreateInstance
;
915 COUNINITIALIZE pCoUninitialize
;
918 TRACE("hInf %p, SectionName %s, Arg %p\n",
919 hInf
, debugstr_w(SectionName
), Arg
);
921 /* Read 'Name' entry */
922 if (!SetupFindFirstLineW(hInf
, SectionName
, Name
, &Context
))
924 if (!GetStringField(&Context
, 1, &LinkName
))
926 if (SetupGetFieldCount(&Context
) >= 2)
928 if (!SetupGetIntField(&Context
, 2, &LinkAttributes
))
931 if (SetupGetFieldCount(&Context
) >= 3)
933 if (!SetupGetIntField(&Context
, 3, &LinkFolder
))
937 /* Read 'CmdLine' entry */
938 if (!SetupFindFirstLineW(hInf
, SectionName
, CmdLine
, &Context
))
941 if (!SetupGetIntField(&Context
, Index
++, &FileDirId
))
943 if (SetupGetFieldCount(&Context
) >= 3)
945 if (!GetStringField(&Context
, Index
++, &FileSubDir
))
948 if (!GetStringField(&Context
, Index
++, &NamePart
))
950 if (!Concatenate(FileDirId
, FileSubDir
, NamePart
, &FullFileName
))
955 /* Read 'SubDir' entry */
956 if ((LinkAttributes
& FLG_PROFITEM_GROUP
) == 0 && SetupFindFirstLineW(hInf
, SectionName
, SubDir
, &Context
))
958 if (!GetStringField(&Context
, 1, &LinkSubDir
))
962 /* Read 'WorkingDir' entry */
963 if (SetupFindFirstLineW(hInf
, SectionName
, WorkingDir
, &Context
))
965 if (!SetupGetIntField(&Context
, 1, &DirId
))
967 if (SetupGetFieldCount(&Context
) >= 2)
969 if (!GetStringField(&Context
, 2, &SubDirPart
))
972 if (!Concatenate(DirId
, SubDirPart
, NULL
, &FullWorkingDir
))
979 if (!Concatenate(FileDirId
, FileSubDir
, NULL
, &FullWorkingDir
))
983 /* Read 'IconPath' entry */
984 if (SetupFindFirstLineW(hInf
, SectionName
, IconPath
, &Context
))
987 if (!SetupGetIntField(&Context
, Index
++, &DirId
))
989 if (SetupGetFieldCount(&Context
) >= 3)
991 if (!GetStringField(&Context
, Index
++, &SubDirPart
))
994 if (!GetStringField(&Context
, Index
, &NamePart
))
996 if (!Concatenate(DirId
, SubDirPart
, NamePart
, &FullIconName
))
1000 SubDirPart
= NamePart
= NULL
;
1004 FullIconName
= pSetupDuplicateString(FullFileName
);
1009 /* Read 'IconIndex' entry */
1010 if (SetupFindFirstLineW(hInf
, SectionName
, IconIndex
, &Context
))
1012 if (!SetupGetIntField(&Context
, 1, &IconIdx
))
1016 /* Read 'HotKey' and 'InfoTip' entries */
1017 GetLineText(hInf
, SectionName
, HotKey
, &lpHotKey
);
1018 GetLineText(hInf
, SectionName
, InfoTip
, &lpInfoTip
);
1020 /* Read 'DisplayResource' entry */
1021 if (SetupFindFirstLineW(hInf
, SectionName
, DisplayResource
, &Context
))
1023 if (!GetStringField(&Context
, 1, &DisplayName
))
1025 if (!SetupGetIntField(&Context
, 2, &DisplayResId
))
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
);
1038 /* Load ole32.dll */
1039 hOle32
= LoadLibraryA("ole32.dll");
1042 pCoInitialize
= (COINITIALIZE
)GetProcAddress(hOle32
, "CoInitialize");
1045 pCoCreateInstance
= (COCREATEINSTANCE
)GetProcAddress(hOle32
, "CoCreateInstance");
1046 if (!pCoCreateInstance
)
1048 pCoUninitialize
= (COUNINITIALIZE
)GetProcAddress(hOle32
, "CoUninitialize");
1049 if (!pCoUninitialize
)
1052 /* Create shortcut */
1053 hr
= pCoInitialize(NULL
);
1056 if (HRESULT_FACILITY(hr
) == FACILITY_WIN32
)
1057 SetLastError(HRESULT_CODE(hr
));
1059 SetLastError(E_FAIL
);
1062 hr
= pCoCreateInstance(&CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IShellLinkW
, (LPVOID
*)&psl
);
1065 /* Fill link properties */
1066 hr
= IShellLinkW_SetPath(psl
, FullFileName
);
1068 hr
= IShellLinkW_SetArguments(psl
, L
"");
1070 hr
= IShellLinkW_SetWorkingDirectory(psl
, FullWorkingDir
);
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
);
1081 hr
= IShellLinkW_QueryInterface(psl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
1084 Required
= (MAX_PATH
+ 1 +
1085 ((LinkSubDir
!= NULL
) ? wcslen(LinkSubDir
) : 0) +
1086 ((LinkName
!= NULL
) ? wcslen(LinkName
) : 0)) * sizeof(WCHAR
);
1087 FullLinkName
= MyMalloc(Required
);
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
)
1096 else if (LinkAttributes
& FLG_PROFITEM_CURRENTUSER
)
1097 CSIDL
= CSIDL_PROGRAMS
;
1099 if (SHGetSpecialFolderPathW(
1105 if (FullLinkName
[wcslen(FullLinkName
) - 1] != '\\')
1106 wcscat(FullLinkName
, BackSlash
);
1109 wcscat(FullLinkName
, LinkSubDir
);
1110 if (FullLinkName
[wcslen(FullLinkName
) - 1] != '\\')
1111 wcscat(FullLinkName
, BackSlash
);
1115 wcscat(FullLinkName
, LinkName
);
1116 wcscat(FullLinkName
, DotLnk
);
1118 hr
= IPersistFile_Save(ppf
, FullLinkName
, TRUE
);
1121 hr
= HRESULT_FROM_WIN32(GetLastError());
1123 IPersistFile_Release(ppf
);
1126 IShellLinkW_Release(psl
);
1133 if (HRESULT_FACILITY(hr
) == FACILITY_WIN32
)
1134 SetLastError(HRESULT_CODE(hr
));
1136 SetLastError(E_FAIL
);
1145 MyFree(FullFileName
);
1146 MyFree(FullWorkingDir
);
1147 MyFree(FullIconName
);
1148 MyFree(FullLinkName
);
1151 MyFree(DisplayName
);
1153 FreeLibrary(hOle32
);
1155 TRACE("Returning %d\n", ret
);
1159 static BOOL
copy_inf_callback( HINF hinf
, PCWSTR field
, void *arg
)
1161 FIXME( "should do copy inf %s\n", debugstr_w(field
) );
1166 /***********************************************************************
1167 * iterate_section_fields
1169 * Iterate over all fields of a certain key of a certain section
1171 static BOOL
iterate_section_fields( HINF hinf
, PCWSTR section
, PCWSTR key
,
1172 iterate_fields_func callback
, void *arg
)
1174 WCHAR static_buffer
[200];
1175 WCHAR
*buffer
= static_buffer
;
1176 DWORD size
= sizeof(static_buffer
)/sizeof(WCHAR
);
1180 BOOL ok
= SetupFindFirstLineW( hinf
, section
, key
, &context
);
1183 UINT i
, count
= SetupGetFieldCount( &context
);
1184 for (i
= 1; i
<= count
; i
++)
1186 if (!(buffer
= get_field_string( &context
, i
, buffer
, static_buffer
, &size
)))
1188 if (!callback( hinf
, buffer
, arg
))
1190 WARN("callback failed for %s %s err %d\n",
1191 debugstr_w(section
), debugstr_w(buffer
), GetLastError() );
1195 ok
= SetupFindNextMatchLineW( &context
, key
, &context
);
1199 if (buffer
!= static_buffer
) HeapFree( GetProcessHeap(), 0, buffer
);
1204 /***********************************************************************
1205 * SetupInstallFilesFromInfSectionA (SETUPAPI.@)
1207 BOOL WINAPI
SetupInstallFilesFromInfSectionA( HINF hinf
, HINF hlayout
, HSPFILEQ queue
,
1208 PCSTR section
, PCSTR src_root
, UINT flags
)
1210 UNICODE_STRING sectionW
;
1213 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
1215 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1219 ret
= SetupInstallFilesFromInfSectionW( hinf
, hlayout
, queue
, sectionW
.Buffer
,
1223 UNICODE_STRING srcW
;
1224 if (RtlCreateUnicodeStringFromAsciiz( &srcW
, src_root
))
1226 ret
= SetupInstallFilesFromInfSectionW( hinf
, hlayout
, queue
, sectionW
.Buffer
,
1227 srcW
.Buffer
, flags
);
1228 RtlFreeUnicodeString( &srcW
);
1230 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1232 RtlFreeUnicodeString( §ionW
);
1237 /***********************************************************************
1238 * SetupInstallFilesFromInfSectionW (SETUPAPI.@)
1240 BOOL WINAPI
SetupInstallFilesFromInfSectionW( HINF hinf
, HINF hlayout
, HSPFILEQ queue
,
1241 PCWSTR section
, PCWSTR src_root
, UINT flags
)
1243 struct files_callback_info info
;
1246 info
.src_root
= src_root
;
1247 info
.copy_flags
= flags
;
1248 info
.layout
= hlayout
;
1249 return iterate_section_fields( hinf
, section
, CopyFiles
, copy_files_callback
, &info
);
1253 /***********************************************************************
1254 * SetupInstallFromInfSectionA (SETUPAPI.@)
1256 BOOL WINAPI
SetupInstallFromInfSectionA( HWND owner
, HINF hinf
, PCSTR section
, UINT flags
,
1257 HKEY key_root
, PCSTR src_root
, UINT copy_flags
,
1258 PSP_FILE_CALLBACK_A callback
, PVOID context
,
1259 HDEVINFO devinfo
, PSP_DEVINFO_DATA devinfo_data
)
1261 UNICODE_STRING sectionW
, src_rootW
;
1262 struct callback_WtoA_context ctx
;
1265 src_rootW
.Buffer
= NULL
;
1266 if (src_root
&& !RtlCreateUnicodeStringFromAsciiz( &src_rootW
, src_root
))
1268 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1272 if (RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
1274 ctx
.orig_context
= context
;
1275 ctx
.orig_handler
= callback
;
1276 ret
= SetupInstallFromInfSectionW( owner
, hinf
, sectionW
.Buffer
, flags
, key_root
,
1277 src_rootW
.Buffer
, copy_flags
, QUEUE_callback_WtoA
,
1278 &ctx
, devinfo
, devinfo_data
);
1279 RtlFreeUnicodeString( §ionW
);
1281 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1283 RtlFreeUnicodeString( &src_rootW
);
1288 /***********************************************************************
1291 * Called once for each Include entry in a given section.
1293 static BOOL
include_callback( HINF hinf
, PCWSTR field
, void *arg
)
1295 return SetupOpenAppendInfFileW( field
, hinf
, NULL
);
1299 /***********************************************************************
1302 * Called once for each Needs entry in a given section.
1304 static BOOL
needs_callback( HINF hinf
, PCWSTR field
, void *arg
)
1306 struct needs_callback_info
*info
= arg
;
1311 return SetupInstallFromInfSectionW(info
->owner
, *(HINF
*)hinf
, field
, info
->flags
,
1312 info
->key_root
, info
->src_root
, info
->copy_flags
, info
->callback
,
1313 info
->context
, info
->devinfo
, info
->devinfo_data
);
1315 return SetupInstallServicesFromInfSectionExW(*(HINF
*)hinf
, field
, info
->flags
,
1316 info
->devinfo
, info
->devinfo_data
, info
->reserved1
, info
->reserved2
);
1318 ERR("Unknown info type %u\n", info
->type
);
1324 /***********************************************************************
1325 * SetupInstallFromInfSectionW (SETUPAPI.@)
1327 BOOL WINAPI
SetupInstallFromInfSectionW( HWND owner
, HINF hinf
, PCWSTR section
, UINT flags
,
1328 HKEY key_root
, PCWSTR src_root
, UINT copy_flags
,
1329 PSP_FILE_CALLBACK_W callback
, PVOID context
,
1330 HDEVINFO devinfo
, PSP_DEVINFO_DATA devinfo_data
)
1332 struct needs_callback_info needs_info
;
1334 /* Parse 'Include' and 'Needs' directives */
1335 iterate_section_fields( hinf
, section
, Include
, include_callback
, NULL
);
1336 needs_info
.type
= 0;
1337 needs_info
.owner
= owner
;
1338 needs_info
.flags
= flags
;
1339 needs_info
.key_root
= key_root
;
1340 needs_info
.src_root
= src_root
;
1341 needs_info
.copy_flags
= copy_flags
;
1342 needs_info
.callback
= callback
;
1343 needs_info
.context
= context
;
1344 needs_info
.devinfo
= devinfo
;
1345 needs_info
.devinfo_data
= devinfo_data
;
1346 iterate_section_fields( hinf
, section
, Needs
, needs_callback
, &needs_info
);
1348 if (flags
& SPINST_FILES
)
1350 SP_DEVINSTALL_PARAMS_W install_params
;
1351 struct files_callback_info info
;
1352 HSPFILEQ queue
= NULL
;
1353 BOOL use_custom_queue
;
1356 install_params
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
1357 use_custom_queue
= SetupDiGetDeviceInstallParamsW(devinfo
, devinfo_data
, &install_params
) && (install_params
.Flags
& DI_NOVCP
);
1358 if (!use_custom_queue
&& ((queue
= SetupOpenFileQueue()) == (HSPFILEQ
)INVALID_HANDLE_VALUE
))
1360 info
.queue
= use_custom_queue
? install_params
.FileQueue
: queue
;
1361 info
.src_root
= src_root
;
1362 info
.copy_flags
= copy_flags
;
1364 ret
= (iterate_section_fields( hinf
, section
, CopyFiles
, copy_files_callback
, &info
) &&
1365 iterate_section_fields( hinf
, section
, DelFiles
, delete_files_callback
, &info
) &&
1366 iterate_section_fields( hinf
, section
, RenFiles
, rename_files_callback
, &info
));
1367 if (!use_custom_queue
)
1370 ret
= SetupCommitFileQueueW( owner
, queue
, callback
, context
);
1371 SetupCloseFileQueue( queue
);
1373 if (!ret
) return FALSE
;
1375 if (flags
& SPINST_INIFILES
)
1377 if (!iterate_section_fields( hinf
, section
, UpdateInis
, update_ini_callback
, NULL
) ||
1378 !iterate_section_fields( hinf
, section
, UpdateIniFields
,
1379 update_ini_fields_callback
, NULL
))
1382 if (flags
& SPINST_INI2REG
)
1384 if (!iterate_section_fields( hinf
, section
, Ini2Reg
, ini2reg_callback
, NULL
))
1387 if (flags
& SPINST_LOGCONFIG
)
1389 if (!iterate_section_fields( hinf
, section
, LogConf
, logconf_callback
, NULL
))
1392 if (flags
& SPINST_REGSVR
)
1394 struct register_dll_info info
;
1396 info
.unregister
= FALSE
;
1397 if (flags
& SPINST_REGISTERCALLBACKAWARE
)
1399 info
.callback
= callback
;
1400 info
.callback_context
= context
;
1402 else info
.callback
= NULL
;
1404 if (!iterate_section_fields( hinf
, section
, RegisterDlls
, register_dlls_callback
, &info
))
1408 if (!iterate_section_fields( hinf
, section
, WineFakeDlls
, fake_dlls_callback
, NULL
))
1410 #endif // __WINESRC__
1412 if (flags
& SPINST_UNREGSVR
)
1414 struct register_dll_info info
;
1416 info
.unregister
= TRUE
;
1417 if (flags
& SPINST_REGISTERCALLBACKAWARE
)
1419 info
.callback
= callback
;
1420 info
.callback_context
= context
;
1422 else info
.callback
= NULL
;
1424 if (!iterate_section_fields( hinf
, section
, UnregisterDlls
, register_dlls_callback
, &info
))
1427 if (flags
& SPINST_REGISTRY
)
1429 struct registry_callback_info info
;
1431 info
.default_root
= key_root
;
1433 if (!iterate_section_fields( hinf
, section
, DelReg
, registry_callback
, &info
))
1435 info
.delete = FALSE
;
1436 if (!iterate_section_fields( hinf
, section
, AddReg
, registry_callback
, &info
))
1439 if (flags
& SPINST_BITREG
)
1441 if (!iterate_section_fields( hinf
, section
, BitReg
, bitreg_callback
, NULL
))
1444 if (flags
& SPINST_PROFILEITEMS
)
1446 if (!iterate_section_fields( hinf
, section
, ProfileItems
, profile_items_callback
, NULL
))
1449 if (flags
& SPINST_COPYINF
)
1451 if (!iterate_section_fields( hinf
, section
, CopyINF
, copy_inf_callback
, NULL
))
1459 /***********************************************************************
1460 * InstallHinfSectionW (SETUPAPI.@)
1462 * NOTE: 'cmdline' is <section> <mode> <path> from
1463 * RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection <section> <mode> <path>
1465 void WINAPI
InstallHinfSectionW( HWND hwnd
, HINSTANCE handle
, LPCWSTR cmdline
, INT show
)
1468 WCHAR
*s
, *path
, section
[MAX_PATH
];
1469 void *callback_context
= NULL
;
1470 DWORD SectionNameLength
;
1472 HINF hinf
= INVALID_HANDLE_VALUE
;
1473 BOOL bRebootRequired
= FALSE
;
1475 TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd
, handle
, debugstr_w(cmdline
));
1477 lstrcpynW( section
, cmdline
, MAX_PATH
);
1479 if (!(s
= strchrW( section
, ' ' ))) goto cleanup
;
1481 while (*s
== ' ') s
++;
1484 /* quoted paths are not allowed on native, the rest of the command line is taken as the path */
1485 if (!(s
= strchrW( s
, ' ' ))) goto cleanup
;
1486 while (*s
== ' ') s
++;
1491 FIXME("default path of the installation not changed\n");
1495 hinf
= SetupOpenInfFileW( path
, NULL
, INF_STYLE_WIN4
, NULL
);
1496 if (hinf
== INVALID_HANDLE_VALUE
)
1498 WARN("SetupOpenInfFileW(%s) failed (Error %u)\n", path
, GetLastError());
1502 ret
= SetupDiGetActualSectionToInstallW(
1503 hinf
, section
, section
, sizeof(section
)/sizeof(section
[0]), &SectionNameLength
, NULL
);
1506 WARN("SetupDiGetActualSectionToInstallW() failed (Error %u)\n", GetLastError());
1509 if (SectionNameLength
> MAX_PATH
- strlenW(DotServices
))
1511 WARN("Section name '%s' too long\n", section
);
1515 /* Copy files and add registry entries */
1516 callback_context
= SetupInitDefaultQueueCallback( hwnd
);
1517 ret
= SetupInstallFromInfSectionW( hwnd
, hinf
, section
, SPINST_ALL
, NULL
, NULL
,
1518 SP_COPY_NEWER
| SP_COPY_IN_USE_NEEDS_REBOOT
,
1519 SetupDefaultQueueCallbackW
, callback_context
,
1523 WARN("SetupInstallFromInfSectionW() failed (Error %u)\n", GetLastError());
1526 /* FIXME: need to check if some files were in use and need reboot
1530 /* Install services */
1531 wcscat(section
, DotServices
);
1532 ret
= SetupInstallServicesFromInfSectionW( hinf
, section
, 0 );
1533 if (!ret
&& GetLastError() == ERROR_SECTION_NOT_FOUND
)
1537 WARN("SetupInstallServicesFromInfSectionW() failed (Error %u)\n", GetLastError());
1540 else if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED
)
1542 bRebootRequired
= TRUE
;
1545 /* Check if we need to reboot */
1553 ExitWindowsEx(EWX_REBOOT
, SHTDN_REASON_MAJOR_APPLICATION
|
1554 SHTDN_REASON_MINOR_INSTALLATION
| SHTDN_REASON_FLAG_PLANNED
);
1557 /* Query user before rebooting */
1558 SetupPromptReboot(NULL
, hwnd
, FALSE
);
1561 /* Reboot if necessary */
1562 if (bRebootRequired
)
1564 ExitWindowsEx(EWX_REBOOT
, SHTDN_REASON_MAJOR_APPLICATION
|
1565 SHTDN_REASON_MINOR_INSTALLATION
| SHTDN_REASON_FLAG_PLANNED
);
1569 /* If necessary, query user before rebooting */
1570 if (bRebootRequired
)
1572 SetupPromptReboot(NULL
, hwnd
, FALSE
);
1580 if ( callback_context
)
1581 SetupTermDefaultQueueCallback( callback_context
);
1582 if ( hinf
!= INVALID_HANDLE_VALUE
)
1583 SetupCloseInfFile( hinf
);
1585 #ifdef CORE_11689_IS_FIXED
1586 // TODO: Localize the error string.
1587 if (!ret
&& !(GlobalSetupFlags
& PSPGF_NONINTERACTIVE
))
1589 MessageBoxW(hwnd
, section
, L
"setupapi.dll: An error happened...", MB_ICONERROR
| MB_OK
);
1595 /***********************************************************************
1596 * InstallHinfSectionA (SETUPAPI.@)
1598 void WINAPI
InstallHinfSectionA( HWND hwnd
, HINSTANCE handle
, LPCSTR cmdline
, INT show
)
1600 UNICODE_STRING cmdlineW
;
1602 if (RtlCreateUnicodeStringFromAsciiz( &cmdlineW
, cmdline
))
1604 InstallHinfSectionW( hwnd
, handle
, cmdlineW
.Buffer
, show
);
1605 RtlFreeUnicodeString( &cmdlineW
);
1609 /***********************************************************************
1610 * SetupInstallServicesFromInfSectionW (SETUPAPI.@)
1612 BOOL WINAPI
SetupInstallServicesFromInfSectionW( HINF Inf
, PCWSTR SectionName
, DWORD Flags
)
1614 return SetupInstallServicesFromInfSectionExW( Inf
, SectionName
, Flags
,
1615 NULL
, NULL
, NULL
, NULL
);
1618 /***********************************************************************
1619 * SetupInstallServicesFromInfSectionA (SETUPAPI.@)
1621 BOOL WINAPI
SetupInstallServicesFromInfSectionA( HINF Inf
, PCSTR SectionName
, DWORD Flags
)
1623 return SetupInstallServicesFromInfSectionExA( Inf
, SectionName
, Flags
,
1624 NULL
, NULL
, NULL
, NULL
);
1627 /***********************************************************************
1628 * SetupInstallServicesFromInfSectionExA (SETUPAPI.@)
1630 BOOL WINAPI
SetupInstallServicesFromInfSectionExA( HINF hinf
, PCSTR sectionname
, DWORD flags
, HDEVINFO devinfo
, PSP_DEVINFO_DATA devinfo_data
, PVOID reserved1
, PVOID reserved2
)
1632 UNICODE_STRING sectionnameW
;
1635 if (RtlCreateUnicodeStringFromAsciiz( §ionnameW
, sectionname
))
1637 ret
= SetupInstallServicesFromInfSectionExW( hinf
, sectionnameW
.Buffer
, flags
, devinfo
, devinfo_data
, reserved1
, reserved2
);
1638 RtlFreeUnicodeString( §ionnameW
);
1641 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1647 static BOOL
GetLineText( HINF hinf
, PCWSTR section_name
, PCWSTR key_name
, PWSTR
*value
)
1654 if (! SetupGetLineTextW( NULL
, hinf
, section_name
, key_name
, NULL
, 0, &required
)
1655 && GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
1658 buf
= HeapAlloc( GetProcessHeap(), 0, required
* sizeof(WCHAR
) );
1661 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1665 if (! SetupGetLineTextW( NULL
, hinf
, section_name
, key_name
, buf
, required
, &required
) )
1667 HeapFree( GetProcessHeap(), 0, buf
);
1676 static BOOL
GetIntField( HINF hinf
, PCWSTR section_name
, PCWSTR key_name
, INT
*value
)
1681 if (! GetLineText( hinf
, section_name
, key_name
, &buffer
) )
1684 res
= wcstol( buffer
, &end
, 0 );
1685 if (end
!= buffer
&& !*end
)
1687 HeapFree(GetProcessHeap(), 0, buffer
);
1693 HeapFree(GetProcessHeap(), 0, buffer
);
1694 SetLastError( ERROR_INVALID_DATA
);
1700 BOOL
GetStringField( PINFCONTEXT context
, DWORD index
, PWSTR
*value
)
1705 ret
= SetupGetStringFieldW(
1712 else if (RequiredSize
== 0)
1718 /* We got the needed size for the buffer */
1719 *value
= MyMalloc(RequiredSize
* sizeof(WCHAR
));
1722 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1725 ret
= SetupGetStringFieldW(
1728 *value
, RequiredSize
, NULL
);
1735 static VOID
FixupServiceBinaryPath(
1736 IN DWORD ServiceType
,
1737 IN OUT LPWSTR
*ServiceBinary
)
1740 WCHAR ReactOSDir
[MAX_PATH
];
1741 DWORD RosDirLength
, ServiceLength
, Win32Length
;
1743 GetWindowsDirectoryW(ReactOSDir
, MAX_PATH
);
1744 RosDirLength
= strlenW(ReactOSDir
);
1745 ServiceLength
= strlenW(*ServiceBinary
);
1747 /* Check and fix two things:
1748 1. Get rid of C:\ReactOS and use relative
1750 2. Add %SystemRoot% for Win32 services */
1752 if (ServiceLength
< RosDirLength
)
1755 if (!wcsnicmp(*ServiceBinary
, ReactOSDir
, RosDirLength
))
1757 /* Yes, the first part is the C:\ReactOS\, just skip it */
1758 MoveMemory(*ServiceBinary
, *ServiceBinary
+ RosDirLength
+ 1,
1759 (ServiceLength
- RosDirLength
) * sizeof(WCHAR
));
1761 /* Handle Win32-services differently */
1762 if (ServiceType
& SERVICE_WIN32
)
1764 Win32Length
= (ServiceLength
- RosDirLength
) * sizeof(WCHAR
)
1765 - sizeof(L
'\\') + sizeof(L
"%SystemRoot%\\");
1766 Buffer
= MyMalloc(Win32Length
);
1768 wcscpy(Buffer
, L
"%SystemRoot%\\");
1769 wcscat(Buffer
, *ServiceBinary
);
1770 MyFree(*ServiceBinary
);
1772 *ServiceBinary
= Buffer
;
1777 static BOOL
InstallOneService(
1778 struct DeviceInfoSet
*list
,
1780 IN LPCWSTR ServiceSection
,
1781 IN LPCWSTR ServiceName
,
1782 IN UINT ServiceFlags
)
1784 SC_HANDLE hSCManager
= NULL
;
1785 SC_HANDLE hService
= NULL
;
1786 LPDWORD GroupOrder
= NULL
;
1787 LPQUERY_SERVICE_CONFIGW ServiceConfig
= NULL
;
1788 HKEY hServicesKey
, hServiceKey
;
1792 HKEY hGroupOrderListKey
= NULL
;
1793 LPWSTR ServiceBinary
= NULL
;
1794 LPWSTR LoadOrderGroup
= NULL
;
1795 LPWSTR DisplayName
= NULL
;
1796 LPWSTR Description
= NULL
;
1797 LPWSTR Dependencies
= NULL
;
1798 LPWSTR StartName
= NULL
;
1799 LPWSTR SecurityDescriptor
= NULL
;
1800 PSECURITY_DESCRIPTOR sd
= NULL
;
1801 INT ServiceType
, StartType
, ErrorControl
;
1803 DWORD tagId
= (DWORD
)-1;
1806 if (!GetIntField(hInf
, ServiceSection
, ServiceTypeKey
, &ServiceType
))
1808 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT
);
1811 if (!GetIntField(hInf
, ServiceSection
, StartTypeKey
, &StartType
))
1813 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT
);
1816 if (!GetIntField(hInf
, ServiceSection
, ErrorControlKey
, &ErrorControl
))
1818 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT
);
1821 useTag
= (ServiceType
== SERVICE_BOOT_START
|| ServiceType
== SERVICE_SYSTEM_START
);
1823 hSCManager
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASE
, SC_MANAGER_CREATE_SERVICE
);
1824 if (hSCManager
== NULL
)
1827 if (!GetLineText(hInf
, ServiceSection
, ServiceBinaryKey
, &ServiceBinary
))
1829 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT
);
1833 /* Adjust binary path according to the service type */
1834 FixupServiceBinaryPath(ServiceType
, &ServiceBinary
);
1836 /* Don't check return value, as these fields are optional and
1837 * GetLineText initialize output parameter even on failure */
1838 GetLineText(hInf
, ServiceSection
, LoadOrderGroupKey
, &LoadOrderGroup
);
1839 GetLineText(hInf
, ServiceSection
, DisplayNameKey
, &DisplayName
);
1840 GetLineText(hInf
, ServiceSection
, DescriptionKey
, &Description
);
1841 GetLineText(hInf
, ServiceSection
, DependenciesKey
, &Dependencies
);
1842 GetLineText(hInf
, ServiceSection
, StartNameKey
, &StartName
);
1844 /* If there is no group, we must not request a tag */
1845 if (!LoadOrderGroup
|| !*LoadOrderGroup
)
1848 hService
= OpenServiceW(
1851 DELETE
| SERVICE_QUERY_CONFIG
| SERVICE_CHANGE_CONFIG
| WRITE_DAC
);
1852 if (hService
== NULL
&& GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST
)
1855 if (hService
&& (ServiceFlags
& SPSVCINST_DELETEEVENTLOGENTRY
))
1857 ret
= DeleteService(hService
);
1858 if (!ret
&& GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE
)
1862 if (hService
== NULL
)
1864 /* Create new service */
1865 hService
= CreateServiceW(
1875 useTag
? &tagId
: NULL
,
1879 if (hService
== NULL
)
1885 /* Read current configuration */
1886 if (!QueryServiceConfigW(hService
, NULL
, 0, &bufferSize
))
1888 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
1890 ServiceConfig
= MyMalloc(bufferSize
);
1893 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1896 if (!QueryServiceConfigW(hService
, ServiceConfig
, bufferSize
, &bufferSize
))
1899 tagId
= ServiceConfig
->dwTagId
;
1901 /* Update configuration */
1902 ret
= ChangeServiceConfigW(
1905 (ServiceFlags
& SPSVCINST_NOCLOBBER_STARTTYPE
) ? SERVICE_NO_CHANGE
: StartType
,
1906 (ServiceFlags
& SPSVCINST_NOCLOBBER_ERRORCONTROL
) ? SERVICE_NO_CHANGE
: ErrorControl
,
1908 (ServiceFlags
& SPSVCINST_NOCLOBBER_LOADORDERGROUP
&& ServiceConfig
->lpLoadOrderGroup
) ? NULL
: LoadOrderGroup
,
1909 useTag
? &tagId
: NULL
,
1910 (ServiceFlags
& SPSVCINST_NOCLOBBER_DEPENDENCIES
&& ServiceConfig
->lpDependencies
) ? NULL
: Dependencies
,
1913 (ServiceFlags
& SPSVCINST_NOCLOBBER_DISPLAYNAME
&& ServiceConfig
->lpDisplayName
) ? NULL
: DisplayName
);
1919 if (GetLineText(hInf
, ServiceSection
, SecurityKey
, &SecurityDescriptor
))
1921 ret
= ConvertStringSecurityDescriptorToSecurityDescriptorW(SecurityDescriptor
, SDDL_REVISION_1
, &sd
, NULL
);
1924 ret
= SetServiceObjectSecurity(hService
, DACL_SECURITY_INFORMATION
, sd
);
1929 /* FIXME: use Description and SPSVCINST_NOCLOBBER_DESCRIPTION */
1933 /* Add the tag to SYSTEM\CurrentControlSet\Control\GroupOrderList key */
1934 LPCWSTR lpLoadOrderGroup
;
1937 lpLoadOrderGroup
= LoadOrderGroup
;
1938 if ((ServiceFlags
& SPSVCINST_NOCLOBBER_LOADORDERGROUP
) && ServiceConfig
&& ServiceConfig
->lpLoadOrderGroup
)
1939 lpLoadOrderGroup
= ServiceConfig
->lpLoadOrderGroup
;
1942 list
? list
->HKLM
: HKEY_LOCAL_MACHINE
,
1944 &hGroupOrderListKey
);
1945 if (rc
!= ERROR_SUCCESS
)
1950 rc
= RegQueryValueExW(hGroupOrderListKey
, lpLoadOrderGroup
, NULL
, &dwRegType
, NULL
, &bufferSize
);
1951 if (rc
== ERROR_FILE_NOT_FOUND
)
1952 bufferSize
= sizeof(DWORD
);
1953 else if (rc
!= ERROR_SUCCESS
)
1958 else if (dwRegType
!= REG_BINARY
|| bufferSize
== 0 || bufferSize
% sizeof(DWORD
) != 0)
1960 SetLastError(ERROR_GEN_FAILURE
);
1963 /* Allocate buffer to store existing data + the new tag */
1964 GroupOrder
= MyMalloc(bufferSize
+ sizeof(DWORD
));
1967 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1970 if (rc
== ERROR_SUCCESS
)
1972 /* Read existing data */
1973 rc
= RegQueryValueExW(
1980 if (rc
!= ERROR_SUCCESS
)
1985 if (ServiceFlags
& SPSVCINST_TAGTOFRONT
)
1986 memmove(&GroupOrder
[2], &GroupOrder
[1], bufferSize
- sizeof(DWORD
));
1993 if (ServiceFlags
& SPSVCINST_TAGTOFRONT
)
1994 GroupOrder
[1] = tagId
;
1996 GroupOrder
[bufferSize
/ sizeof(DWORD
)] = tagId
;
1998 rc
= RegSetValueExW(
2004 bufferSize
+ sizeof(DWORD
));
2005 if (rc
!= ERROR_SUCCESS
)
2012 /* Handle AddReg and DelReg */
2014 list
? list
->HKLM
: HKEY_LOCAL_MACHINE
,
2015 REGSTR_PATH_SERVICES
,
2019 if (rc
!= ERROR_SUCCESS
)
2028 KEY_READ
| KEY_WRITE
,
2030 RegCloseKey(hServicesKey
);
2031 if (rc
!= ERROR_SUCCESS
)
2037 ret
= SetupInstallFromInfSectionW(
2049 RegCloseKey(hServiceKey
);
2052 if (hSCManager
!= NULL
)
2053 CloseServiceHandle(hSCManager
);
2054 if (hService
!= NULL
)
2055 CloseServiceHandle(hService
);
2056 if (hGroupOrderListKey
!= NULL
)
2057 RegCloseKey(hGroupOrderListKey
);
2060 MyFree(ServiceConfig
);
2061 MyFree(ServiceBinary
);
2062 MyFree(LoadOrderGroup
);
2063 MyFree(DisplayName
);
2064 MyFree(Description
);
2065 MyFree(Dependencies
);
2066 MyFree(SecurityDescriptor
);
2070 TRACE("Returning %d\n", ret
);
2075 /***********************************************************************
2076 * SetupInstallServicesFromInfSectionExW (SETUPAPI.@)
2078 BOOL WINAPI
SetupInstallServicesFromInfSectionExW( HINF hinf
, PCWSTR sectionname
, DWORD flags
, HDEVINFO DeviceInfoSet
, PSP_DEVINFO_DATA DeviceInfoData
, PVOID reserved1
, PVOID reserved2
)
2080 struct DeviceInfoSet
*list
= NULL
;
2083 TRACE("%p, %s, 0x%lx, %p, %p, %p, %p\n", hinf
, debugstr_w(sectionname
),
2084 flags
, DeviceInfoSet
, DeviceInfoData
, reserved1
, reserved2
);
2087 SetLastError(ERROR_INVALID_PARAMETER
);
2088 else if (flags
& ~(SPSVCINST_TAGTOFRONT
| SPSVCINST_DELETEEVENTLOGENTRY
| SPSVCINST_NOCLOBBER_DISPLAYNAME
| SPSVCINST_NOCLOBBER_STARTTYPE
| SPSVCINST_NOCLOBBER_ERRORCONTROL
| SPSVCINST_NOCLOBBER_LOADORDERGROUP
| SPSVCINST_NOCLOBBER_DEPENDENCIES
| SPSVCINST_STOPSERVICE
))
2090 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
));
2091 SetLastError(ERROR_INVALID_FLAGS
);
2093 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
2094 SetLastError(ERROR_INVALID_HANDLE
);
2095 else if (DeviceInfoSet
&& (list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEVICE_INFO_SET_MAGIC
)
2096 SetLastError(ERROR_INVALID_HANDLE
);
2097 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
2098 SetLastError(ERROR_INVALID_USER_BUFFER
);
2099 else if (reserved1
!= NULL
|| reserved2
!= NULL
)
2100 SetLastError(ERROR_INVALID_PARAMETER
);
2103 struct needs_callback_info needs_info
;
2104 LPWSTR ServiceName
= NULL
;
2105 LPWSTR ServiceSection
= NULL
;
2107 INFCONTEXT ContextService
;
2108 BOOL bNeedReboot
= FALSE
;
2110 /* Parse 'Include' and 'Needs' directives */
2111 iterate_section_fields( hinf
, sectionname
, Include
, include_callback
, NULL
);
2112 needs_info
.type
= 1;
2113 needs_info
.flags
= flags
;
2114 needs_info
.devinfo
= DeviceInfoSet
;
2115 needs_info
.devinfo_data
= DeviceInfoData
;
2116 needs_info
.reserved1
= reserved1
;
2117 needs_info
.reserved2
= reserved2
;
2118 iterate_section_fields( hinf
, sectionname
, Needs
, needs_callback
, &needs_info
);
2120 if (flags
& SPSVCINST_STOPSERVICE
)
2122 FIXME("Stopping the device not implemented\n");
2123 /* This may lead to require a reboot */
2124 /* bNeedReboot = TRUE; */
2126 SERVICE_STATUS ServiceStatus
;
2127 ret
= ControlService(hService
, SERVICE_CONTROL_STOP
, &ServiceStatus
);
2128 if (!ret
&& GetLastError() != ERROR_SERVICE_NOT_ACTIVE
)
2130 if (ServiceStatus
.dwCurrentState
!= SERVICE_STOP_PENDING
&& ServiceStatus
.dwCurrentState
!= SERVICE_STOPPED
)
2132 SetLastError(ERROR_INSTALL_SERVICE_FAILURE
);
2136 flags
&= ~SPSVCINST_STOPSERVICE
;
2139 if (!(ret
= SetupFindFirstLineW( hinf
, sectionname
, NULL
, &ContextService
)))
2141 SetLastError( ERROR_SECTION_NOT_FOUND
);
2145 ret
= SetupFindFirstLineW(hinf
, sectionname
, AddService
, &ContextService
);
2148 if (!GetStringField(&ContextService
, 1, &ServiceName
))
2151 ret
= SetupGetIntField(
2153 2, /* Field index */
2157 /* The field may be empty. Ignore the error */
2161 if (!GetStringField(&ContextService
, 3, &ServiceSection
))
2164 ret
= InstallOneService(list
, hinf
, ServiceSection
, ServiceName
, (ServiceFlags
& ~SPSVCINST_ASSOCSERVICE
) | flags
);
2168 if (ServiceFlags
& SPSVCINST_ASSOCSERVICE
)
2170 ret
= SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet
, DeviceInfoData
, SPDRP_SERVICE
, (LPBYTE
)ServiceName
, (strlenW(ServiceName
) + 1) * sizeof(WCHAR
));
2175 HeapFree(GetProcessHeap(), 0, ServiceName
);
2176 HeapFree(GetProcessHeap(), 0, ServiceSection
);
2177 ServiceName
= ServiceSection
= NULL
;
2178 ret
= SetupFindNextMatchLineW(&ContextService
, AddService
, &ContextService
);
2182 SetLastError(ERROR_SUCCESS_REBOOT_REQUIRED
);
2184 SetLastError(ERROR_SUCCESS
);
2188 TRACE("Returning %d\n", ret
);
2193 /***********************************************************************
2194 * SetupCopyOEMInfA (SETUPAPI.@)
2196 BOOL WINAPI
SetupCopyOEMInfA(
2197 IN PCSTR SourceInfFileName
,
2198 IN PCSTR OEMSourceMediaLocation
,
2199 IN DWORD OEMSourceMediaType
,
2201 OUT PSTR DestinationInfFileName OPTIONAL
,
2202 IN DWORD DestinationInfFileNameSize
,
2203 OUT PDWORD RequiredSize OPTIONAL
,
2204 OUT PSTR
* DestinationInfFileNameComponent OPTIONAL
)
2206 PWSTR SourceInfFileNameW
= NULL
;
2207 PWSTR OEMSourceMediaLocationW
= NULL
;
2208 PWSTR DestinationInfFileNameW
= NULL
;
2209 PWSTR DestinationInfFileNameComponentW
= NULL
;
2213 TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n",
2214 SourceInfFileName
, OEMSourceMediaLocation
, OEMSourceMediaType
,
2215 CopyStyle
, DestinationInfFileName
, DestinationInfFileNameSize
,
2216 RequiredSize
, DestinationInfFileNameComponent
);
2218 if (!DestinationInfFileName
&& DestinationInfFileNameSize
> 0)
2219 SetLastError(ERROR_INVALID_PARAMETER
);
2220 else if (!(SourceInfFileNameW
= pSetupMultiByteToUnicode(SourceInfFileName
, CP_ACP
)))
2221 SetLastError(ERROR_INVALID_PARAMETER
);
2222 else if (OEMSourceMediaType
!= SPOST_NONE
&& !(OEMSourceMediaLocationW
= pSetupMultiByteToUnicode(OEMSourceMediaLocation
, CP_ACP
)))
2223 SetLastError(ERROR_INVALID_PARAMETER
);
2226 if (DestinationInfFileNameSize
!= 0)
2228 DestinationInfFileNameW
= MyMalloc(DestinationInfFileNameSize
* sizeof(WCHAR
));
2229 if (!DestinationInfFileNameW
)
2231 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2236 ret
= SetupCopyOEMInfW(
2238 OEMSourceMediaLocationW
,
2241 DestinationInfFileNameW
,
2242 DestinationInfFileNameSize
,
2244 DestinationInfFileNameComponent
? &DestinationInfFileNameComponentW
: NULL
);
2247 if (RequiredSize
) *RequiredSize
= size
;
2251 if (DestinationInfFileNameSize
!= 0)
2253 if (WideCharToMultiByte(CP_ACP
, 0, DestinationInfFileNameW
, -1,
2254 DestinationInfFileName
, DestinationInfFileNameSize
, NULL
, NULL
) == 0)
2256 DestinationInfFileName
[0] = '\0';
2260 if (DestinationInfFileNameComponent
)
2262 if (DestinationInfFileNameComponentW
)
2263 *DestinationInfFileNameComponent
= &DestinationInfFileName
[DestinationInfFileNameComponentW
- DestinationInfFileNameW
];
2265 *DestinationInfFileNameComponent
= NULL
;
2271 MyFree(SourceInfFileNameW
);
2272 MyFree(OEMSourceMediaLocationW
);
2273 MyFree(DestinationInfFileNameW
);
2274 TRACE("Returning %d\n", ret
);
2275 if (ret
) SetLastError(ERROR_SUCCESS
);
2279 static int compare_files( HANDLE file1
, HANDLE file2
)
2286 while( ReadFile(file1
, buffer1
, sizeof(buffer1
), &size1
, NULL
) &&
2287 ReadFile(file2
, buffer2
, sizeof(buffer2
), &size2
, NULL
) )
2291 return size1
> size2
? 1 : -1;
2294 ret
= memcmp( buffer1
, buffer2
, size1
);
2302 /***********************************************************************
2303 * SetupCopyOEMInfW (SETUPAPI.@)
2305 BOOL WINAPI
SetupCopyOEMInfW(
2306 IN PCWSTR SourceInfFileName
,
2307 IN PCWSTR OEMSourceMediaLocation
,
2308 IN DWORD OEMSourceMediaType
,
2310 OUT PWSTR DestinationInfFileName OPTIONAL
,
2311 IN DWORD DestinationInfFileNameSize
,
2312 OUT PDWORD RequiredSize OPTIONAL
,
2313 OUT PWSTR
* DestinationInfFileNameComponent OPTIONAL
)
2317 TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n",
2318 debugstr_w(SourceInfFileName
), debugstr_w(OEMSourceMediaLocation
), OEMSourceMediaType
,
2319 CopyStyle
, DestinationInfFileName
, DestinationInfFileNameSize
,
2320 RequiredSize
, DestinationInfFileNameComponent
);
2322 if (!SourceInfFileName
)
2323 SetLastError(ERROR_INVALID_PARAMETER
);
2324 else if (OEMSourceMediaType
!= SPOST_NONE
&& OEMSourceMediaType
!= SPOST_PATH
&& OEMSourceMediaType
!= SPOST_URL
)
2325 SetLastError(ERROR_INVALID_PARAMETER
);
2326 else if (CopyStyle
& ~(SP_COPY_DELETESOURCE
| SP_COPY_REPLACEONLY
| SP_COPY_NOOVERWRITE
| SP_COPY_OEMINF_CATALOG_ONLY
))
2328 TRACE("Unknown flags: 0x%08lx\n", CopyStyle
& ~(SP_COPY_DELETESOURCE
| SP_COPY_REPLACEONLY
| SP_COPY_NOOVERWRITE
| SP_COPY_OEMINF_CATALOG_ONLY
));
2329 SetLastError(ERROR_INVALID_FLAGS
);
2331 else if (!DestinationInfFileName
&& DestinationInfFileNameSize
> 0)
2332 SetLastError(ERROR_INVALID_PARAMETER
);
2333 else if (CopyStyle
& SP_COPY_OEMINF_CATALOG_ONLY
)
2335 FIXME("CopyStyle 0x%x not supported\n", SP_COPY_OEMINF_CATALOG_ONLY
);
2336 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2340 HANDLE hSearch
= INVALID_HANDLE_VALUE
;
2341 WIN32_FIND_DATAW FindFileData
;
2343 DWORD NextFreeNumber
= 0;
2345 LPWSTR pFullFileName
= NULL
;
2346 LPWSTR pFileName
; /* Pointer into pFullFileName buffer */
2347 HANDLE hSourceFile
= INVALID_HANDLE_VALUE
;
2349 if (OEMSourceMediaType
== SPOST_PATH
|| OEMSourceMediaType
== SPOST_URL
)
2350 FIXME("OEMSourceMediaType 0x%lx ignored\n", OEMSourceMediaType
);
2352 /* Check if source file exists, and open it */
2353 if (strchrW(SourceInfFileName
, '\\' ) || strchrW(SourceInfFileName
, '/' ))
2357 if (!(len
= GetFullPathNameW(SourceInfFileName
, 0, NULL
, NULL
)))
2359 if (!(path
= MyMalloc(len
* sizeof(WCHAR
))))
2361 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2364 GetFullPathNameW(SourceInfFileName
, len
, path
, NULL
);
2365 hSourceFile
= CreateFileW(
2366 path
, FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
2367 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
2368 NULL
, OPEN_EXISTING
, 0, NULL
);
2371 else /* try Windows directory */
2374 static const WCHAR Inf
[] = {'\\','i','n','f','\\',0};
2375 static const WCHAR System32
[] = {'\\','s','y','s','t','e','m','3','2','\\',0};
2377 len
= GetWindowsDirectoryW(NULL
, 0) + strlenW(SourceInfFileName
) + 12;
2378 if (!(path
= MyMalloc(len
* sizeof(WCHAR
))))
2380 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2383 GetWindowsDirectoryW(path
, len
);
2384 p
= path
+ strlenW(path
);
2386 strcatW(p
, SourceInfFileName
);
2387 hSourceFile
= CreateFileW(
2388 path
, FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
2389 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
2390 NULL
, OPEN_EXISTING
, 0, NULL
);
2391 if (hSourceFile
== INVALID_HANDLE_VALUE
)
2393 strcpyW(p
, System32
);
2394 strcatW(p
, SourceInfFileName
);
2395 hSourceFile
= CreateFileW(
2396 path
, FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
2397 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
2398 NULL
, OPEN_EXISTING
, 0, NULL
);
2402 if (hSourceFile
== INVALID_HANDLE_VALUE
)
2404 SetLastError(ERROR_FILE_NOT_FOUND
);
2408 /* Prepare .inf file specification */
2409 len
= MAX_PATH
+ 1 + strlenW(InfDirectory
) + 13;
2410 pFullFileName
= MyMalloc(len
* sizeof(WCHAR
));
2413 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2416 len
= GetSystemWindowsDirectoryW(pFullFileName
, MAX_PATH
);
2417 if (len
== 0 || len
> MAX_PATH
)
2419 if (pFullFileName
[strlenW(pFullFileName
) - 1] != '\\')
2420 strcatW(pFullFileName
, BackSlash
);
2421 strcatW(pFullFileName
, InfDirectory
);
2422 pFileName
= &pFullFileName
[strlenW(pFullFileName
)];
2424 /* Search if the specified .inf file already exists in %WINDIR%\Inf */
2425 AlreadyExists
= FALSE
;
2426 strcpyW(pFileName
, OemFileMask
);
2427 hSearch
= FindFirstFileW(pFullFileName
, &FindFileData
);
2428 if (hSearch
!= INVALID_HANDLE_VALUE
)
2430 LARGE_INTEGER SourceFileSize
;
2432 if (GetFileSizeEx(hSourceFile
, &SourceFileSize
))
2436 LARGE_INTEGER DestFileSize
;
2439 strcpyW(pFileName
, FindFileData
.cFileName
);
2440 hDestFile
= CreateFileW(
2441 pFullFileName
, FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
2442 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
2443 NULL
, OPEN_EXISTING
, 0, NULL
);
2444 if (hDestFile
!= INVALID_HANDLE_VALUE
)
2446 if (GetFileSizeEx(hDestFile
, &DestFileSize
)
2447 && DestFileSize
.QuadPart
== SourceFileSize
.QuadPart
2448 && !compare_files(hSourceFile
, hDestFile
))
2450 TRACE("%s already exists as %s\n",
2451 debugstr_w(SourceInfFileName
), debugstr_w(pFileName
));
2452 AlreadyExists
= TRUE
;
2455 } while (!AlreadyExists
&& FindNextFileW(hSearch
, &FindFileData
));
2458 hSearch
= INVALID_HANDLE_VALUE
;
2461 if (!AlreadyExists
&& CopyStyle
& SP_COPY_REPLACEONLY
)
2463 /* FIXME: set DestinationInfFileName, RequiredSize, DestinationInfFileNameComponent */
2464 SetLastError(ERROR_FILE_NOT_FOUND
);
2467 else if (AlreadyExists
&& (CopyStyle
& SP_COPY_NOOVERWRITE
))
2469 DWORD Size
= strlenW(pFileName
) + 1;
2472 *RequiredSize
= Size
;
2473 if (DestinationInfFileNameSize
== 0)
2474 SetLastError(ERROR_FILE_EXISTS
);
2475 else if (DestinationInfFileNameSize
< Size
)
2476 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2479 SetLastError(ERROR_FILE_EXISTS
);
2480 strcpyW(DestinationInfFileName
, pFileName
);
2485 /* Search the number to give to OEM??.INF */
2486 strcpyW(pFileName
, OemFileMask
);
2487 hSearch
= FindFirstFileW(pFullFileName
, &FindFileData
);
2488 if (hSearch
== INVALID_HANDLE_VALUE
)
2490 if (GetLastError() != ERROR_FILE_NOT_FOUND
)
2497 DWORD CurrentNumber
;
2498 if (swscanf(FindFileData
.cFileName
, OemFileSpecification
, &CurrentNumber
) == 1
2499 && CurrentNumber
<= 99999)
2501 if (CurrentNumber
>= NextFreeNumber
)
2502 NextFreeNumber
= CurrentNumber
+ 1;
2504 } while (FindNextFileW(hSearch
, &FindFileData
));
2507 if (NextFreeNumber
> 99999)
2509 ERR("Too much custom .inf files\n");
2510 SetLastError(ERROR_GEN_FAILURE
);
2514 /* Create the full path: %WINDIR%\Inf\OEM{XXXXX}.inf */
2515 sprintfW(pFileName
, OemFileSpecification
, NextFreeNumber
);
2516 TRACE("Next available file is %s\n", debugstr_w(pFileName
));
2518 if (!CopyFileW(SourceInfFileName
, pFullFileName
, TRUE
))
2520 TRACE("CopyFileW() failed with error 0x%lx\n", GetLastError());
2524 len
= strlenW(pFullFileName
) + 1;
2526 *RequiredSize
= len
;
2527 if (DestinationInfFileName
)
2529 if (DestinationInfFileNameSize
>= len
)
2531 strcpyW(DestinationInfFileName
, pFullFileName
);
2532 if (DestinationInfFileNameComponent
)
2533 *DestinationInfFileNameComponent
= &DestinationInfFileName
[pFileName
- pFullFileName
];
2537 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2542 if (CopyStyle
& SP_COPY_DELETESOURCE
)
2544 if (!DeleteFileW(SourceInfFileName
))
2546 TRACE("DeleteFileW() failed with error 0x%lx\n", GetLastError());
2554 if (hSourceFile
!= INVALID_HANDLE_VALUE
)
2555 CloseHandle(hSourceFile
);
2556 if (hSearch
!= INVALID_HANDLE_VALUE
)
2558 MyFree(pFullFileName
);
2561 TRACE("Returning %d\n", ret
);
2562 if (ret
) SetLastError(ERROR_SUCCESS
);