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"
24 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
26 /* Unicode constants */
27 static const WCHAR BackSlash
[] = {'\\',0};
28 static const WCHAR InfDirectory
[] = {'i','n','f','\\',0};
30 /* info passed to callback functions dealing with files */
31 struct files_callback_info
39 /* info passed to callback functions dealing with the registry */
40 struct registry_callback_info
46 /* info passed to callback functions dealing with registering dlls */
47 struct register_dll_info
49 PSP_FILE_CALLBACK_W callback
;
50 PVOID callback_context
;
54 /* info passed to callback functions dealing with Needs directives */
55 struct needs_callback_info
67 PSP_DEVINFO_DATA devinfo_data
;
72 typedef BOOL (*iterate_fields_func
)( HINF hinf
, PCWSTR field
, void *arg
);
74 /* Unicode constants */
75 static const WCHAR AddService
[] = {'A','d','d','S','e','r','v','i','c','e',0};
76 static const WCHAR CopyFiles
[] = {'C','o','p','y','F','i','l','e','s',0};
77 static const WCHAR DelFiles
[] = {'D','e','l','F','i','l','e','s',0};
78 static const WCHAR RenFiles
[] = {'R','e','n','F','i','l','e','s',0};
79 static const WCHAR Ini2Reg
[] = {'I','n','i','2','R','e','g',0};
80 static const WCHAR LogConf
[] = {'L','o','g','C','o','n','f',0};
81 static const WCHAR AddReg
[] = {'A','d','d','R','e','g',0};
82 static const WCHAR DelReg
[] = {'D','e','l','R','e','g',0};
83 static const WCHAR BitReg
[] = {'B','i','t','R','e','g',0};
84 static const WCHAR UpdateInis
[] = {'U','p','d','a','t','e','I','n','i','s',0};
85 static const WCHAR CopyINF
[] = {'C','o','p','y','I','N','F',0};
86 static const WCHAR UpdateIniFields
[] = {'U','p','d','a','t','e','I','n','i','F','i','e','l','d','s',0};
87 static const WCHAR RegisterDlls
[] = {'R','e','g','i','s','t','e','r','D','l','l','s',0};
88 static const WCHAR UnregisterDlls
[] = {'U','n','r','e','g','i','s','t','e','r','D','l','l','s',0};
89 static const WCHAR ProfileItems
[] = {'P','r','o','f','i','l','e','I','t','e','m','s',0};
90 static const WCHAR Include
[] = {'I','n','c','l','u','d','e',0};
91 static const WCHAR Needs
[] = {'N','e','e','d','s',0};
94 /***********************************************************************
97 * Retrieve the contents of a field, dynamically growing the buffer if necessary.
99 static WCHAR
*get_field_string( INFCONTEXT
*context
, DWORD index
, WCHAR
*buffer
,
100 WCHAR
*static_buffer
, DWORD
*size
)
104 if (SetupGetStringFieldW( context
, index
, buffer
, *size
, &required
)) return buffer
;
105 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
107 /* now grow the buffer */
108 if (buffer
!= static_buffer
) HeapFree( GetProcessHeap(), 0, buffer
);
109 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, required
*sizeof(WCHAR
) ))) return NULL
;
111 if (SetupGetStringFieldW( context
, index
, buffer
, *size
, &required
)) return buffer
;
113 if (buffer
!= static_buffer
) HeapFree( GetProcessHeap(), 0, buffer
);
118 /***********************************************************************
119 * copy_files_callback
121 * Called once for each CopyFiles entry in a given section.
123 static BOOL
copy_files_callback( HINF hinf
, PCWSTR field
, void *arg
)
125 struct files_callback_info
*info
= arg
;
127 if (field
[0] == '@') /* special case: copy single file */
128 SetupQueueDefaultCopyW( info
->queue
, info
->layout
, info
->src_root
, NULL
, &field
[1], info
->copy_flags
);
130 SetupQueueCopySectionW( info
->queue
, info
->src_root
, info
->layout
, hinf
, field
, info
->copy_flags
);
135 /***********************************************************************
136 * delete_files_callback
138 * Called once for each DelFiles entry in a given section.
140 static BOOL
delete_files_callback( HINF hinf
, PCWSTR field
, void *arg
)
142 struct files_callback_info
*info
= arg
;
143 SetupQueueDeleteSectionW( info
->queue
, hinf
, 0, field
);
148 /***********************************************************************
149 * rename_files_callback
151 * Called once for each RenFiles entry in a given section.
153 static BOOL
rename_files_callback( HINF hinf
, PCWSTR field
, void *arg
)
155 struct files_callback_info
*info
= arg
;
156 SetupQueueRenameSectionW( info
->queue
, hinf
, 0, field
);
161 /***********************************************************************
164 * Retrieve the registry root key from its name.
166 static HKEY
get_root_key( const WCHAR
*name
, HKEY def_root
)
168 static const WCHAR HKCR
[] = {'H','K','C','R',0};
169 static const WCHAR HKCU
[] = {'H','K','C','U',0};
170 static const WCHAR HKLM
[] = {'H','K','L','M',0};
171 static const WCHAR HKU
[] = {'H','K','U',0};
172 static const WCHAR HKR
[] = {'H','K','R',0};
174 if (!strcmpiW( name
, HKCR
)) return HKEY_CLASSES_ROOT
;
175 if (!strcmpiW( name
, HKCU
)) return HKEY_CURRENT_USER
;
176 if (!strcmpiW( name
, HKLM
)) return HKEY_LOCAL_MACHINE
;
177 if (!strcmpiW( name
, HKU
)) return HKEY_USERS
;
178 if (!strcmpiW( name
, HKR
)) return def_root
;
183 /***********************************************************************
184 * append_multi_sz_value
186 * Append a multisz string to a multisz registry value.
188 static void append_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*strings
,
191 DWORD size
, type
, total
;
194 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
195 if (type
!= REG_MULTI_SZ
) return;
197 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, (size
+ str_size
) * sizeof(WCHAR
) ))) return;
198 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
200 /* compare each string against all the existing ones */
204 int len
= strlenW(strings
) + 1;
206 for (p
= buffer
; *p
; p
+= strlenW(p
) + 1)
207 if (!strcmpiW( p
, strings
)) break;
209 if (!*p
) /* not found, need to append it */
211 memcpy( p
, strings
, len
* sizeof(WCHAR
) );
219 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
) );
220 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
, (BYTE
*)buffer
, total
);
223 HeapFree( GetProcessHeap(), 0, buffer
);
227 /***********************************************************************
228 * delete_multi_sz_value
230 * Remove a string from a multisz registry value.
232 static void delete_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*string
)
235 WCHAR
*buffer
, *src
, *dst
;
237 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
238 if (type
!= REG_MULTI_SZ
) return;
239 /* allocate double the size, one for value before and one for after */
240 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, size
* 2 * sizeof(WCHAR
) ))) return;
241 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
246 int len
= strlenW(src
) + 1;
247 if (strcmpiW( src
, string
))
249 memcpy( dst
, src
, len
* sizeof(WCHAR
) );
255 if (dst
!= buffer
+ 2*size
) /* did we remove something? */
257 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
+ size
) );
258 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
,
259 (BYTE
*)(buffer
+ size
), dst
- (buffer
+ size
) );
262 HeapFree( GetProcessHeap(), 0, buffer
);
266 /***********************************************************************
269 * Perform an add/delete registry operation depending on the flags.
271 static BOOL
do_reg_operation( HKEY hkey
, const WCHAR
*value
, INFCONTEXT
*context
, INT flags
)
275 if (flags
& (FLG_ADDREG_DELREG_BIT
| FLG_ADDREG_DELVAL
)) /* deletion */
277 if (*value
&& !(flags
& FLG_DELREG_KEYONLY_COMMON
))
279 if ((flags
& FLG_DELREG_MULTI_SZ_DELSTRING
) == FLG_DELREG_MULTI_SZ_DELSTRING
)
283 if (!SetupGetStringFieldW( context
, 5, NULL
, 0, &size
) || !size
) return TRUE
;
284 if (!(str
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return FALSE
;
285 SetupGetStringFieldW( context
, 5, str
, size
, NULL
);
286 delete_multi_sz_value( hkey
, value
, str
);
287 HeapFree( GetProcessHeap(), 0, str
);
289 else RegDeleteValueW( hkey
, value
);
291 else RegDeleteKeyW( hkey
, NULL
);
295 if (flags
& (FLG_ADDREG_KEYONLY
|FLG_ADDREG_KEYONLY_COMMON
)) return TRUE
;
297 if (flags
& (FLG_ADDREG_NOCLOBBER
|FLG_ADDREG_OVERWRITEONLY
))
299 BOOL exists
= !RegQueryValueExW( hkey
, value
, NULL
, NULL
, NULL
, NULL
);
300 if (exists
&& (flags
& FLG_ADDREG_NOCLOBBER
)) return TRUE
;
301 if (!exists
& (flags
& FLG_ADDREG_OVERWRITEONLY
)) return TRUE
;
304 switch(flags
& FLG_ADDREG_TYPE_MASK
)
306 case FLG_ADDREG_TYPE_SZ
: type
= REG_SZ
; break;
307 case FLG_ADDREG_TYPE_MULTI_SZ
: type
= REG_MULTI_SZ
; break;
308 case FLG_ADDREG_TYPE_EXPAND_SZ
: type
= REG_EXPAND_SZ
; break;
309 case FLG_ADDREG_TYPE_BINARY
: type
= REG_BINARY
; break;
310 case FLG_ADDREG_TYPE_DWORD
: type
= REG_DWORD
; break;
311 case FLG_ADDREG_TYPE_NONE
: type
= REG_NONE
; break;
312 default: type
= flags
>> 16; break;
315 if (!(flags
& FLG_ADDREG_BINVALUETYPE
) ||
316 (type
== REG_DWORD
&& SetupGetFieldCount(context
) == 5))
318 static const WCHAR empty
;
321 if (type
== REG_MULTI_SZ
)
323 if (!SetupGetMultiSzFieldW( context
, 5, NULL
, 0, &size
)) size
= 0;
326 if (!(str
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return FALSE
;
327 SetupGetMultiSzFieldW( context
, 5, str
, size
, NULL
);
329 if (flags
& FLG_ADDREG_APPEND
)
331 if (!str
) return TRUE
;
332 append_multi_sz_value( hkey
, value
, str
, size
);
333 HeapFree( GetProcessHeap(), 0, str
);
336 /* else fall through to normal string handling */
340 if (!SetupGetStringFieldW( context
, 5, NULL
, 0, &size
)) size
= 0;
343 if (!(str
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return FALSE
;
344 SetupGetStringFieldW( context
, 5, str
, size
, NULL
);
348 if (type
== REG_DWORD
)
350 DWORD dw
= str
? strtoulW( str
, NULL
, 0 ) : 0;
351 TRACE( "setting dword %s to %lx\n", debugstr_w(value
), dw
);
352 RegSetValueExW( hkey
, value
, 0, type
, (BYTE
*)&dw
, sizeof(dw
) );
356 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(str
) );
357 if (str
) RegSetValueExW( hkey
, value
, 0, type
, (BYTE
*)str
, size
* sizeof(WCHAR
) );
358 else RegSetValueExW( hkey
, value
, 0, type
, (const BYTE
*)&empty
, sizeof(WCHAR
) );
360 HeapFree( GetProcessHeap(), 0, str
);
363 else /* get the binary data */
367 if (!SetupGetBinaryField( context
, 5, NULL
, 0, &size
)) size
= 0;
370 if (!(data
= HeapAlloc( GetProcessHeap(), 0, size
))) return FALSE
;
371 TRACE( "setting binary data %s len %ld\n", debugstr_w(value
), size
);
372 SetupGetBinaryField( context
, 5, data
, size
, NULL
);
374 RegSetValueExW( hkey
, value
, 0, type
, data
, size
);
375 HeapFree( GetProcessHeap(), 0, data
);
381 /***********************************************************************
384 * Called once for each AddReg and DelReg entry in a given section.
386 static BOOL
registry_callback( HINF hinf
, PCWSTR field
, void *arg
)
388 struct registry_callback_info
*info
= arg
;
392 BOOL ok
= SetupFindFirstLineW( hinf
, field
, NULL
, &context
);
394 for (; ok
; ok
= SetupFindNextLine( &context
, &context
))
396 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
400 if (!SetupGetStringFieldW( &context
, 1, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
402 if (!(root_key
= get_root_key( buffer
, info
->default_root
)))
406 if (!SetupGetStringFieldW( &context
, 2, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
410 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0;
414 if (flags
& FLG_ADDREG_DELREG_BIT
) continue; /* ignore this entry */
418 if (!flags
) flags
= FLG_ADDREG_DELREG_BIT
;
419 else if (!(flags
& FLG_ADDREG_DELREG_BIT
)) continue; /* ignore this entry */
422 if (info
->delete || (flags
& FLG_ADDREG_OVERWRITEONLY
))
424 if (RegOpenKeyW( root_key
, buffer
, &hkey
)) continue; /* ignore if it doesn't exist */
426 else if (RegCreateKeyW( root_key
, buffer
, &hkey
))
428 ERR( "could not create key %p %s\n", root_key
, debugstr_w(buffer
) );
431 TRACE( "key %p %s\n", root_key
, debugstr_w(buffer
) );
434 if (!SetupGetStringFieldW( &context
, 3, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
438 if (!do_reg_operation( hkey
, buffer
, &context
, flags
))
440 if (hkey
!= root_key
) RegCloseKey( hkey
);
443 if (hkey
!= root_key
) RegCloseKey( hkey
);
449 /***********************************************************************
452 * Register or unregister a dll.
454 static BOOL
do_register_dll( const struct register_dll_info
*info
, const WCHAR
*path
,
455 INT flags
, INT timeout
, const WCHAR
*args
)
459 SP_REGISTER_CONTROL_STATUSW status
;
461 IMAGE_NT_HEADERS
*nt
;
464 status
.cbSize
= sizeof(status
);
465 status
.FileName
= path
;
466 status
.FailureCode
= SPREG_SUCCESS
;
467 status
.Win32Error
= ERROR_SUCCESS
;
471 switch(info
->callback( info
->callback_context
, SPFILENOTIFY_STARTREGISTRATION
,
472 (UINT_PTR
)&status
, !info
->unregister
))
475 SetLastError( ERROR_OPERATION_ABORTED
);
484 if (!(module
= LoadLibraryExW( path
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
)))
486 WARN( "could not load %s\n", debugstr_w(path
) );
487 status
.FailureCode
= SPREG_LOADLIBRARY
;
488 status
.Win32Error
= GetLastError();
493 if ((nt
= RtlImageNtHeader( module
)) && !(nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
))
495 /* file is an executable, not a dll */
496 STARTUPINFOW startup
;
497 PROCESS_INFORMATION info
;
500 static const WCHAR format
[] = {'"','%','s','"',' ','%','s',0};
501 static const WCHAR default_args
[] = {'/','R','e','g','S','e','r','v','e','r',0};
503 FreeLibrary( module
);
505 if (!args
) args
= default_args
;
506 cmd_line
= HeapAlloc( GetProcessHeap(), 0, (strlenW(path
) + strlenW(args
) + 4) * sizeof(WCHAR
) );
507 sprintfW( cmd_line
, format
, path
, args
);
508 memset( &startup
, 0, sizeof(startup
) );
509 startup
.cb
= sizeof(startup
);
510 TRACE( "executing %s\n", debugstr_w(cmd_line
) );
511 res
= CreateProcessW( NULL
, cmd_line
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
);
512 HeapFree( GetProcessHeap(), 0, cmd_line
);
515 status
.FailureCode
= SPREG_LOADLIBRARY
;
516 status
.Win32Error
= GetLastError();
519 CloseHandle( info
.hThread
);
521 if (WaitForSingleObject( info
.hProcess
, timeout
*1000 ) == WAIT_TIMEOUT
)
523 /* timed out, kill the process */
524 TerminateProcess( info
.hProcess
, 1 );
525 status
.FailureCode
= SPREG_TIMEOUT
;
526 status
.Win32Error
= ERROR_TIMEOUT
;
528 CloseHandle( info
.hProcess
);
531 #endif // __WINESRC__
533 if (flags
& FLG_REGSVR_DLLREGISTER
)
535 const char *entry_point
= info
->unregister
? "DllUnregisterServer" : "DllRegisterServer";
536 HRESULT (WINAPI
*func
)(void) = (void *)GetProcAddress( module
, entry_point
);
540 status
.FailureCode
= SPREG_GETPROCADDR
;
541 status
.Win32Error
= GetLastError();
545 TRACE( "calling %s in %s\n", entry_point
, debugstr_w(path
) );
550 WARN( "calling %s in %s returned error %lx\n", entry_point
, debugstr_w(path
), res
);
551 status
.FailureCode
= SPREG_REGSVR
;
552 status
.Win32Error
= res
;
557 if (flags
& FLG_REGSVR_DLLINSTALL
)
559 HRESULT (WINAPI
*func
)(BOOL
,LPCWSTR
) = (void *)GetProcAddress( module
, "DllInstall" );
563 status
.FailureCode
= SPREG_GETPROCADDR
;
564 status
.Win32Error
= GetLastError();
568 TRACE( "calling DllInstall(%d,%s) in %s\n",
569 !info
->unregister
, debugstr_w(args
), debugstr_w(path
) );
570 res
= func( !info
->unregister
, args
);
574 WARN( "calling DllInstall in %s returned error %lx\n", debugstr_w(path
), res
);
575 status
.FailureCode
= SPREG_REGSVR
;
576 status
.Win32Error
= res
;
582 if (module
) FreeLibrary( module
);
583 if (info
->callback
) info
->callback( info
->callback_context
, SPFILENOTIFY_ENDREGISTRATION
,
584 (UINT_PTR
)&status
, !info
->unregister
);
589 /***********************************************************************
590 * register_dlls_callback
592 * Called once for each RegisterDlls entry in a given section.
594 static BOOL
register_dlls_callback( HINF hinf
, PCWSTR field
, void *arg
)
596 struct register_dll_info
*info
= arg
;
599 BOOL ok
= SetupFindFirstLineW( hinf
, field
, NULL
, &context
);
601 for (; ok
; ok
= SetupFindNextLine( &context
, &context
))
603 WCHAR
*path
, *args
, *p
;
604 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
608 if (!(path
= PARSER_get_dest_dir( &context
))) continue;
611 if (!SetupGetStringFieldW( &context
, 3, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
613 if (!(p
= HeapReAlloc( GetProcessHeap(), 0, path
,
614 (strlenW(path
) + strlenW(buffer
) + 2) * sizeof(WCHAR
) ))) goto done
;
617 if (p
== path
|| p
[-1] != '\\') *p
++ = '\\';
618 strcpyW( p
, buffer
);
621 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0;
624 if (!SetupGetIntField( &context
, 5, &timeout
)) timeout
= 60;
626 /* get command line */
628 if (SetupGetStringFieldW( &context
, 6, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
631 ret
= do_register_dll( info
, path
, flags
, timeout
, args
);
634 HeapFree( GetProcessHeap(), 0, path
);
641 /***********************************************************************
644 * Called once for each WineFakeDlls entry in a given section.
646 static BOOL
fake_dlls_callback( HINF hinf
, PCWSTR field
, void *arg
)
650 BOOL ok
= SetupFindFirstLineW( hinf
, field
, NULL
, &context
);
652 for (; ok
; ok
= SetupFindNextLine( &context
, &context
))
655 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
658 if (!(path
= PARSER_get_dest_dir( &context
))) continue;
661 if (!SetupGetStringFieldW( &context
, 3, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
663 if (!(p
= HeapReAlloc( GetProcessHeap(), 0, path
,
664 (strlenW(path
) + strlenW(buffer
) + 2) * sizeof(WCHAR
) ))) goto done
;
667 if (p
== path
|| p
[-1] != '\\') *p
++ = '\\';
668 strcpyW( p
, buffer
);
671 if (SetupGetStringFieldW( &context
, 4, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
672 p
= buffer
; /* otherwise use target base name as default source */
674 create_fake_dll( path
, p
); /* ignore errors */
677 HeapFree( GetProcessHeap(), 0, path
);
682 #endif // __WINESRC__
684 /***********************************************************************
685 * update_ini_callback
687 * Called once for each UpdateInis entry in a given section.
689 static BOOL
update_ini_callback( HINF hinf
, PCWSTR field
, void *arg
)
693 BOOL ok
= SetupFindFirstLineW( hinf
, field
, NULL
, &context
);
695 for (; ok
; ok
= SetupFindNextLine( &context
, &context
))
697 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
698 WCHAR filename
[MAX_INF_STRING_LENGTH
];
699 WCHAR section
[MAX_INF_STRING_LENGTH
];
700 WCHAR entry
[MAX_INF_STRING_LENGTH
];
701 WCHAR string
[MAX_INF_STRING_LENGTH
];
704 if (!SetupGetStringFieldW( &context
, 1, filename
,
705 sizeof(filename
)/sizeof(WCHAR
), NULL
))
708 if (!SetupGetStringFieldW( &context
, 2, section
,
709 sizeof(section
)/sizeof(WCHAR
), NULL
))
712 if (!SetupGetStringFieldW( &context
, 4, buffer
,
713 sizeof(buffer
)/sizeof(WCHAR
), NULL
))
716 divider
= strchrW(buffer
,'=');
720 strcpyW(entry
,buffer
);
722 strcpyW(string
,divider
);
726 strcpyW(entry
,buffer
);
730 TRACE("Writing %s = %s in %s of file %s\n",debugstr_w(entry
),
731 debugstr_w(string
),debugstr_w(section
),debugstr_w(filename
));
732 WritePrivateProfileStringW(section
,entry
,string
,filename
);
738 static BOOL
update_ini_fields_callback( HINF hinf
, PCWSTR field
, void *arg
)
740 FIXME( "should update ini fields %s\n", debugstr_w(field
) );
744 static BOOL
ini2reg_callback( HINF hinf
, PCWSTR field
, void *arg
)
746 FIXME( "should do ini2reg %s\n", debugstr_w(field
) );
750 static BOOL
logconf_callback( HINF hinf
, PCWSTR field
, void *arg
)
752 FIXME( "should do logconf %s\n", debugstr_w(field
) );
756 static BOOL
bitreg_callback( HINF hinf
, PCWSTR field
, void *arg
)
758 FIXME( "should do bitreg %s\n", debugstr_w(field
) );
762 static BOOL
profile_items_callback( HINF hinf
, PCWSTR field
, void *arg
)
764 FIXME( "should do profile items %s\n", debugstr_w(field
) );
768 static BOOL
copy_inf_callback( HINF hinf
, PCWSTR field
, void *arg
)
770 FIXME( "should do copy inf %s\n", debugstr_w(field
) );
775 /***********************************************************************
776 * iterate_section_fields
778 * Iterate over all fields of a certain key of a certain section
780 static BOOL
iterate_section_fields( HINF hinf
, PCWSTR section
, PCWSTR key
,
781 iterate_fields_func callback
, void *arg
)
783 WCHAR static_buffer
[200];
784 WCHAR
*buffer
= static_buffer
;
785 DWORD size
= sizeof(static_buffer
)/sizeof(WCHAR
);
789 BOOL ok
= SetupFindFirstLineW( hinf
, section
, key
, &context
);
792 UINT i
, count
= SetupGetFieldCount( &context
);
793 for (i
= 1; i
<= count
; i
++)
795 if (!(buffer
= get_field_string( &context
, i
, buffer
, static_buffer
, &size
)))
797 if (!callback( hinf
, buffer
, arg
))
799 WARN("callback failed for %s %s err %ld\n",
800 debugstr_w(section
), debugstr_w(buffer
), GetLastError() );
804 ok
= SetupFindNextMatchLineW( &context
, key
, &context
);
808 if (buffer
&& buffer
!= static_buffer
) HeapFree( GetProcessHeap(), 0, buffer
);
813 /***********************************************************************
814 * SetupInstallFilesFromInfSectionA (SETUPAPI.@)
816 BOOL WINAPI
SetupInstallFilesFromInfSectionA( HINF hinf
, HINF hlayout
, HSPFILEQ queue
,
817 PCSTR section
, PCSTR src_root
, UINT flags
)
819 UNICODE_STRING sectionW
;
822 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
824 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
828 ret
= SetupInstallFilesFromInfSectionW( hinf
, hlayout
, queue
, sectionW
.Buffer
,
833 if (RtlCreateUnicodeStringFromAsciiz( &srcW
, src_root
))
835 ret
= SetupInstallFilesFromInfSectionW( hinf
, hlayout
, queue
, sectionW
.Buffer
,
836 srcW
.Buffer
, flags
);
837 RtlFreeUnicodeString( &srcW
);
839 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
841 RtlFreeUnicodeString( §ionW
);
846 /***********************************************************************
847 * SetupInstallFilesFromInfSectionW (SETUPAPI.@)
849 BOOL WINAPI
SetupInstallFilesFromInfSectionW( HINF hinf
, HINF hlayout
, HSPFILEQ queue
,
850 PCWSTR section
, PCWSTR src_root
, UINT flags
)
852 struct files_callback_info info
;
855 info
.src_root
= src_root
;
856 info
.copy_flags
= flags
;
857 info
.layout
= hlayout
;
858 return iterate_section_fields( hinf
, section
, CopyFiles
, copy_files_callback
, &info
);
862 /***********************************************************************
863 * SetupInstallFromInfSectionA (SETUPAPI.@)
865 BOOL WINAPI
SetupInstallFromInfSectionA( HWND owner
, HINF hinf
, PCSTR section
, UINT flags
,
866 HKEY key_root
, PCSTR src_root
, UINT copy_flags
,
867 PSP_FILE_CALLBACK_A callback
, PVOID context
,
868 HDEVINFO devinfo
, PSP_DEVINFO_DATA devinfo_data
)
870 UNICODE_STRING sectionW
, src_rootW
;
871 struct callback_WtoA_context ctx
;
874 src_rootW
.Buffer
= NULL
;
875 if (src_root
&& !RtlCreateUnicodeStringFromAsciiz( &src_rootW
, src_root
))
877 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
881 if (RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
883 ctx
.orig_context
= context
;
884 ctx
.orig_handler
= callback
;
885 ret
= SetupInstallFromInfSectionW( owner
, hinf
, sectionW
.Buffer
, flags
, key_root
,
886 src_rootW
.Buffer
, copy_flags
, QUEUE_callback_WtoA
,
887 &ctx
, devinfo
, devinfo_data
);
888 RtlFreeUnicodeString( §ionW
);
890 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
892 RtlFreeUnicodeString( &src_rootW
);
897 /***********************************************************************
900 * Called once for each Include entry in a given section.
902 static BOOL
include_callback( HINF hinf
, PCWSTR field
, void *arg
)
904 return SetupOpenAppendInfFileW( field
, hinf
, NULL
);
908 /***********************************************************************
911 * Called once for each Needs entry in a given section.
913 static BOOL
needs_callback( HINF hinf
, PCWSTR field
, void *arg
)
915 struct needs_callback_info
*info
= arg
;
920 return SetupInstallFromInfSectionW(info
->owner
, *(HINF
*)hinf
, field
, info
->flags
,
921 info
->key_root
, info
->src_root
, info
->copy_flags
, info
->callback
,
922 info
->context
, info
->devinfo
, info
->devinfo_data
);
924 return SetupInstallServicesFromInfSectionExW(*(HINF
*)hinf
, field
, info
->flags
,
925 info
->devinfo
, info
->devinfo_data
, info
->reserved1
, info
->reserved2
);
927 ERR("Unknown info type %ld\n", info
->type
);
933 /***********************************************************************
934 * SetupInstallFromInfSectionW (SETUPAPI.@)
936 BOOL WINAPI
SetupInstallFromInfSectionW( HWND owner
, HINF hinf
, PCWSTR section
, UINT flags
,
937 HKEY key_root
, PCWSTR src_root
, UINT copy_flags
,
938 PSP_FILE_CALLBACK_W callback
, PVOID context
,
939 HDEVINFO devinfo
, PSP_DEVINFO_DATA devinfo_data
)
941 struct needs_callback_info needs_info
;
943 /* Parse 'Include' and 'Needs' directives */
944 iterate_section_fields( hinf
, section
, Include
, include_callback
, NULL
);
946 needs_info
.owner
= owner
;
947 needs_info
.flags
= flags
;
948 needs_info
.key_root
= key_root
;
949 needs_info
.src_root
= src_root
;
950 needs_info
.copy_flags
= copy_flags
;
951 needs_info
.callback
= callback
;
952 needs_info
.context
= context
;
953 needs_info
.devinfo
= devinfo
;
954 needs_info
.devinfo_data
= devinfo_data
;
955 iterate_section_fields( hinf
, section
, Needs
, needs_callback
, &needs_info
);
957 if (flags
& SPINST_FILES
)
959 SP_DEVINSTALL_PARAMS_W install_params
;
960 struct files_callback_info info
;
961 HSPFILEQ queue
= NULL
;
962 BOOL use_custom_queue
;
965 install_params
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
966 use_custom_queue
= SetupDiGetDeviceInstallParamsW(devinfo
, devinfo_data
, &install_params
) && (install_params
.Flags
& DI_NOVCP
);
967 if (!use_custom_queue
&& ((queue
= SetupOpenFileQueue()) == (HSPFILEQ
)INVALID_HANDLE_VALUE
))
969 info
.queue
= use_custom_queue
? install_params
.FileQueue
: queue
;
970 info
.src_root
= src_root
;
971 info
.copy_flags
= copy_flags
;
973 ret
= (iterate_section_fields( hinf
, section
, CopyFiles
, copy_files_callback
, &info
) &&
974 iterate_section_fields( hinf
, section
, DelFiles
, delete_files_callback
, &info
) &&
975 iterate_section_fields( hinf
, section
, RenFiles
, rename_files_callback
, &info
));
976 if (!use_custom_queue
)
979 ret
= SetupCommitFileQueueW( owner
, queue
, callback
, context
);
980 SetupCloseFileQueue( queue
);
982 if (!ret
) return FALSE
;
984 if (flags
& SPINST_INIFILES
)
986 if (!iterate_section_fields( hinf
, section
, UpdateInis
, update_ini_callback
, NULL
) ||
987 !iterate_section_fields( hinf
, section
, UpdateIniFields
,
988 update_ini_fields_callback
, NULL
))
991 if (flags
& SPINST_INI2REG
)
993 if (!iterate_section_fields( hinf
, section
, Ini2Reg
, ini2reg_callback
, NULL
))
996 if (flags
& SPINST_LOGCONFIG
)
998 if (!iterate_section_fields( hinf
, section
, LogConf
, logconf_callback
, NULL
))
1001 if (flags
& SPINST_REGSVR
)
1003 struct register_dll_info info
;
1005 info
.unregister
= FALSE
;
1006 if (flags
& SPINST_REGISTERCALLBACKAWARE
)
1008 info
.callback
= callback
;
1009 info
.callback_context
= context
;
1011 else info
.callback
= NULL
;
1013 if (!iterate_section_fields( hinf
, section
, RegisterDlls
, register_dlls_callback
, &info
))
1017 if (!iterate_section_fields( hinf
, section
, WineFakeDlls
, fake_dlls_callback
, NULL
))
1019 #endif // __WINESRC__
1021 if (flags
& SPINST_UNREGSVR
)
1023 struct register_dll_info info
;
1025 info
.unregister
= TRUE
;
1026 if (flags
& SPINST_REGISTERCALLBACKAWARE
)
1028 info
.callback
= callback
;
1029 info
.callback_context
= context
;
1031 else info
.callback
= NULL
;
1033 if (!iterate_section_fields( hinf
, section
, UnregisterDlls
, register_dlls_callback
, &info
))
1036 if (flags
& SPINST_REGISTRY
)
1038 struct registry_callback_info info
;
1040 info
.default_root
= key_root
;
1042 if (!iterate_section_fields( hinf
, section
, DelReg
, registry_callback
, &info
))
1044 info
.delete = FALSE
;
1045 if (!iterate_section_fields( hinf
, section
, AddReg
, registry_callback
, &info
))
1048 if (flags
& SPINST_BITREG
)
1050 if (!iterate_section_fields( hinf
, section
, BitReg
, bitreg_callback
, NULL
))
1053 if (flags
& SPINST_PROFILEITEMS
)
1055 if (!iterate_section_fields( hinf
, section
, ProfileItems
, profile_items_callback
, NULL
))
1058 if (flags
& SPINST_COPYINF
)
1060 if (!iterate_section_fields( hinf
, section
, CopyINF
, copy_inf_callback
, NULL
))
1068 /***********************************************************************
1069 * InstallHinfSectionW (SETUPAPI.@)
1071 * NOTE: 'cmdline' is <section> <mode> <path> from
1072 * RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection <section> <mode> <path>
1074 void WINAPI
InstallHinfSectionW( HWND hwnd
, HINSTANCE handle
, LPCWSTR cmdline
, INT show
)
1076 WCHAR
*p
, *path
, section
[MAX_PATH
];
1077 void *callback_context
;
1081 TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd
, handle
, debugstr_w(cmdline
));
1083 lstrcpynW( section
, cmdline
, sizeof(section
)/sizeof(WCHAR
) );
1085 if (!(p
= strchrW( section
, ' ' ))) return;
1087 while (*p
== ' ') p
++;
1090 if (!(p
= strchrW( p
, ' ' ))) return;
1092 while (*path
== ' ') path
++;
1094 hinf
= SetupOpenInfFileW( path
, NULL
, INF_STYLE_WIN4
, NULL
);
1095 if (hinf
== INVALID_HANDLE_VALUE
) return;
1097 callback_context
= SetupInitDefaultQueueCallback( hwnd
);
1098 SetupInstallFromInfSectionW( hwnd
, hinf
, section
, SPINST_ALL
, NULL
, NULL
, SP_COPY_NEWER
,
1099 SetupDefaultQueueCallbackW
, callback_context
,
1101 SetupTermDefaultQueueCallback( callback_context
);
1102 SetupCloseInfFile( hinf
);
1104 /* FIXME: should check the mode and maybe reboot */
1105 /* there isn't much point in doing that since we */
1106 /* don't yet handle deferred file copies anyway. */
1110 /***********************************************************************
1111 * InstallHinfSectionA (SETUPAPI.@)
1113 void WINAPI
InstallHinfSectionA( HWND hwnd
, HINSTANCE handle
, LPCSTR cmdline
, INT show
)
1115 UNICODE_STRING cmdlineW
;
1117 if (RtlCreateUnicodeStringFromAsciiz( &cmdlineW
, cmdline
))
1119 InstallHinfSectionW( hwnd
, handle
, cmdlineW
.Buffer
, show
);
1120 RtlFreeUnicodeString( &cmdlineW
);
1125 /***********************************************************************
1126 * SetupInstallServicesFromInfSectionA (SETUPAPI.@)
1128 BOOL WINAPI
SetupInstallServicesFromInfSectionA( HINF hinf
, PCSTR sectionname
, DWORD flags
)
1130 return SetupInstallServicesFromInfSectionExA( hinf
, sectionname
, flags
,
1131 NULL
, NULL
, NULL
, NULL
);
1135 /***********************************************************************
1136 * SetupInstallServicesFromInfSectionW (SETUPAPI.@)
1138 BOOL WINAPI
SetupInstallServicesFromInfSectionW( HINF hinf
, PCWSTR sectionname
, DWORD flags
)
1140 return SetupInstallServicesFromInfSectionExW( hinf
, sectionname
, flags
,
1141 NULL
, NULL
, NULL
, NULL
);
1145 /***********************************************************************
1146 * SetupInstallServicesFromInfSectionExA (SETUPAPI.@)
1148 BOOL WINAPI
SetupInstallServicesFromInfSectionExA( HINF hinf
, PCSTR sectionname
, DWORD flags
, HDEVINFO devinfo
, PSP_DEVINFO_DATA devinfo_data
, PVOID reserved1
, PVOID reserved2
)
1150 UNICODE_STRING sectionnameW
;
1153 if (RtlCreateUnicodeStringFromAsciiz( §ionnameW
, sectionname
))
1155 ret
= SetupInstallServicesFromInfSectionExW( hinf
, sectionnameW
.Buffer
, flags
, devinfo
, devinfo_data
, reserved1
, reserved2
);
1156 RtlFreeUnicodeString( §ionnameW
);
1159 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1165 static BOOL
GetLineText( HINF hinf
, PCWSTR section_name
, PCWSTR key_name
, PWSTR
*value
)
1172 if (! SetupGetLineTextW( NULL
, hinf
, section_name
, key_name
, NULL
, 0, &required
)
1173 && GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
1176 buf
= HeapAlloc( GetProcessHeap(), 0, required
* sizeof(WCHAR
) );
1179 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1183 if (! SetupGetLineTextW( NULL
, hinf
, section_name
, key_name
, buf
, required
, &required
) )
1185 HeapFree( GetProcessHeap(), 0, buf
);
1194 static BOOL
GetIntField( HINF hinf
, PCWSTR section_name
, PCWSTR key_name
, INT
*value
)
1199 if (! GetLineText( hinf
, section_name
, key_name
, &buffer
) )
1202 res
= wcstol( buffer
, &end
, 0 );
1203 if (end
!= buffer
&& !*end
)
1205 HeapFree(GetProcessHeap(), 0, buffer
);
1211 HeapFree(GetProcessHeap(), 0, buffer
);
1212 SetLastError( ERROR_INVALID_DATA
);
1218 BOOL
GetStringField( PINFCONTEXT context
, DWORD index
, PWSTR
*value
)
1223 ret
= SetupGetStringFieldW(
1230 else if (RequiredSize
== 0)
1236 /* We got the needed size for the buffer */
1237 *value
= MyMalloc(RequiredSize
* sizeof(WCHAR
));
1240 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1243 ret
= SetupGetStringFieldW(
1246 *value
, RequiredSize
, NULL
);
1254 static BOOL
InstallOneService(
1255 struct DeviceInfoSet
*list
,
1257 IN LPCWSTR ServiceSection
,
1258 IN LPCWSTR ServiceName
,
1259 IN UINT ServiceFlags
)
1261 SC_HANDLE hSCManager
= NULL
;
1262 SC_HANDLE hService
= NULL
;
1263 LPDWORD GroupOrder
= NULL
;
1264 LPQUERY_SERVICE_CONFIG ServiceConfig
= NULL
;
1267 HKEY hGroupOrderListKey
= NULL
;
1268 LPWSTR ServiceBinary
= NULL
;
1269 LPWSTR LoadOrderGroup
= NULL
;
1270 LPWSTR DisplayName
= NULL
;
1271 LPWSTR Description
= NULL
;
1272 LPWSTR Dependencies
= NULL
;
1273 INT ServiceType
, StartType
, ErrorControl
;
1275 DWORD tagId
= (DWORD
)-1;
1278 if (!GetIntField(hInf
, ServiceSection
, L
"ServiceType", &ServiceType
))
1280 if (!GetIntField(hInf
, ServiceSection
, L
"StartType", &StartType
))
1282 if (!GetIntField(hInf
, ServiceSection
, L
"ErrorControl", &ErrorControl
))
1284 useTag
= (ServiceType
== SERVICE_BOOT_START
|| ServiceType
== SERVICE_SYSTEM_START
);
1286 hSCManager
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASE
, SC_MANAGER_CREATE_SERVICE
);
1287 if (hSCManager
== NULL
)
1290 if (!GetLineText(hInf
, ServiceSection
, L
"ServiceBinary", &ServiceBinary
))
1293 /* Don't check return value, as these fields are optional and
1294 * GetLineText initialize output parameter even on failure */
1295 GetLineText(hInf
, ServiceSection
, L
"LoadOrderGroup", &LoadOrderGroup
);
1296 GetLineText(hInf
, ServiceSection
, L
"DisplayName", &DisplayName
);
1297 GetLineText(hInf
, ServiceSection
, L
"Description", &Description
);
1298 GetLineText(hInf
, ServiceSection
, L
"Dependencies", &Dependencies
);
1300 hService
= OpenServiceW(
1303 GENERIC_READ
| GENERIC_WRITE
);
1304 if (hService
== NULL
&& GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST
)
1307 if (hService
&& (ServiceFlags
& SPSVCINST_DELETEEVENTLOGENTRY
))
1309 ret
= DeleteService(hService
);
1310 if (!ret
&& GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE
)
1314 if (hService
== NULL
)
1316 /* Create new service */
1317 hService
= CreateServiceW(
1327 useTag
? &tagId
: NULL
,
1330 if (hService
== NULL
)
1336 /* Read current configuration */
1337 if (!QueryServiceConfigW(hService
, NULL
, 0, &bufferSize
))
1339 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
1341 ServiceConfig
= MyMalloc(bufferSize
);
1344 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1347 if (!QueryServiceConfigW(hService
, ServiceConfig
, bufferSize
, &bufferSize
))
1350 tagId
= ServiceConfig
->dwTagId
;
1352 /* Update configuration */
1353 ret
= ChangeServiceConfigW(
1356 (ServiceFlags
& SPSVCINST_NOCLOBBER_STARTTYPE
) ? SERVICE_NO_CHANGE
: StartType
,
1357 (ServiceFlags
& SPSVCINST_NOCLOBBER_ERRORCONTROL
) ? SERVICE_NO_CHANGE
: ErrorControl
,
1359 (ServiceFlags
& SPSVCINST_NOCLOBBER_LOADORDERGROUP
&& ServiceConfig
->lpLoadOrderGroup
) ? NULL
: LoadOrderGroup
,
1360 useTag
? &tagId
: NULL
,
1361 (ServiceFlags
& SPSVCINST_NOCLOBBER_DEPENDENCIES
&& ServiceConfig
->lpDependencies
) ? NULL
: Dependencies
,
1363 (ServiceFlags
& SPSVCINST_NOCLOBBER_DISPLAYNAME
&& ServiceConfig
->lpDisplayName
) ? NULL
: DisplayName
);
1368 /* FIXME: use Description and SPSVCINST_NOCLOBBER_DESCRIPTION */
1372 /* Add the tag to SYSTEM\CurrentControlSet\Control\GroupOrderList key */
1374 LPCWSTR lpLoadOrderGroup
;
1377 lpLoadOrderGroup
= LoadOrderGroup
;
1378 if ((ServiceFlags
& SPSVCINST_NOCLOBBER_LOADORDERGROUP
) && ServiceConfig
&& ServiceConfig
->lpLoadOrderGroup
)
1379 lpLoadOrderGroup
= ServiceConfig
->lpLoadOrderGroup
;
1382 list
? list
->HKLM
: HKEY_LOCAL_MACHINE
,
1383 L
"SYSTEM\\CurrentControlSet\\Control\\GroupOrderList",
1384 &hGroupOrderListKey
);
1385 if (rc
!= ERROR_SUCCESS
)
1390 rc
= RegQueryValueExW(hGroupOrderListKey
, lpLoadOrderGroup
, NULL
, &dwRegType
, NULL
, &bufferSize
);
1391 if (rc
== ERROR_FILE_NOT_FOUND
)
1392 bufferSize
= sizeof(DWORD
);
1393 else if (rc
!= ERROR_SUCCESS
)
1398 else if (dwRegType
!= REG_BINARY
|| bufferSize
== 0 || bufferSize
% sizeof(DWORD
) != 0)
1400 SetLastError(ERROR_GEN_FAILURE
);
1403 /* Allocate buffer to store existing data + the new tag */
1404 GroupOrder
= MyMalloc(bufferSize
+ sizeof(DWORD
));
1407 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1410 if (rc
== ERROR_SUCCESS
)
1412 /* Read existing data */
1413 rc
= RegQueryValueExW(
1420 if (rc
!= ERROR_SUCCESS
)
1425 if (ServiceFlags
& SPSVCINST_TAGTOFRONT
)
1426 memmove(&GroupOrder
[2], &GroupOrder
[1], bufferSize
- sizeof(DWORD
));
1433 if (ServiceFlags
& SPSVCINST_TAGTOFRONT
)
1434 GroupOrder
[1] = tagId
;
1436 GroupOrder
[bufferSize
/ sizeof(DWORD
)] = tagId
;
1438 rc
= RegSetValueExW(
1444 bufferSize
+ sizeof(DWORD
));
1445 if (rc
!= ERROR_SUCCESS
)
1455 if (hSCManager
!= NULL
)
1456 CloseServiceHandle(hSCManager
);
1457 if (hService
!= NULL
)
1458 CloseServiceHandle(hService
);
1459 if (hGroupOrderListKey
!= NULL
)
1460 RegCloseKey(hGroupOrderListKey
);
1461 MyFree(ServiceConfig
);
1462 MyFree(ServiceBinary
);
1463 MyFree(LoadOrderGroup
);
1464 MyFree(DisplayName
);
1465 MyFree(Description
);
1466 MyFree(Dependencies
);
1469 TRACE("Returning %d\n", ret
);
1474 /***********************************************************************
1475 * SetupInstallServicesFromInfSectionExW (SETUPAPI.@)
1477 BOOL WINAPI
SetupInstallServicesFromInfSectionExW( HINF hinf
, PCWSTR sectionname
, DWORD flags
, HDEVINFO DeviceInfoSet
, PSP_DEVINFO_DATA DeviceInfoData
, PVOID reserved1
, PVOID reserved2
)
1479 struct DeviceInfoSet
*list
= NULL
;
1482 TRACE("%p, %s, 0x%lx, %p, %p, %p, %p\n", hinf
, debugstr_w(sectionname
),
1483 flags
, DeviceInfoSet
, DeviceInfoData
, reserved1
, reserved2
);
1486 SetLastError(ERROR_INVALID_PARAMETER
);
1487 else if (flags
& ~(SPSVCINST_TAGTOFRONT
| SPSVCINST_DELETEEVENTLOGENTRY
| SPSVCINST_NOCLOBBER_DISPLAYNAME
| SPSVCINST_NOCLOBBER_STARTTYPE
| SPSVCINST_NOCLOBBER_ERRORCONTROL
| SPSVCINST_NOCLOBBER_LOADORDERGROUP
| SPSVCINST_NOCLOBBER_DEPENDENCIES
| SPSVCINST_STOPSERVICE
))
1489 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
));
1490 SetLastError(ERROR_INVALID_FLAGS
);
1492 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
1493 SetLastError(ERROR_INVALID_HANDLE
);
1494 else if (DeviceInfoSet
&& (list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEV_INFO_SET_MAGIC
)
1495 SetLastError(ERROR_INVALID_HANDLE
);
1496 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
1497 SetLastError(ERROR_INVALID_USER_BUFFER
);
1498 else if (reserved1
!= NULL
|| reserved2
!= NULL
)
1499 SetLastError(ERROR_INVALID_PARAMETER
);
1502 struct needs_callback_info needs_info
;
1503 LPWSTR ServiceName
= NULL
;
1504 LPWSTR ServiceSection
= NULL
;
1506 INFCONTEXT ContextService
;
1507 BOOL bNeedReboot
= FALSE
;
1509 /* Parse 'Include' and 'Needs' directives */
1510 iterate_section_fields( hinf
, sectionname
, Include
, include_callback
, NULL
);
1511 needs_info
.type
= 1;
1512 needs_info
.flags
= flags
;
1513 needs_info
.devinfo
= DeviceInfoSet
;
1514 needs_info
.devinfo_data
= DeviceInfoData
;
1515 needs_info
.reserved1
= reserved1
;
1516 needs_info
.reserved2
= reserved2
;
1517 iterate_section_fields( hinf
, sectionname
, Needs
, needs_callback
, &needs_info
);
1519 if (flags
& SPSVCINST_STOPSERVICE
)
1521 FIXME("Stopping the device not implemented\n");
1522 /* This may lead to require a reboot */
1523 /* bNeedReboot = TRUE; */
1525 SERVICE_STATUS ServiceStatus
;
1526 ret
= ControlService(hService
, SERVICE_CONTROL_STOP
, &ServiceStatus
);
1527 if (!ret
&& GetLastError() != ERROR_SERVICE_NOT_ACTIVE
)
1529 if (ServiceStatus
.dwCurrentState
!= SERVICE_STOP_PENDING
&& ServiceStatus
.dwCurrentState
!= SERVICE_STOPPED
)
1531 SetLastError(ERROR_INSTALL_SERVICE_FAILURE
);
1535 flags
&= ~SPSVCINST_STOPSERVICE
;
1538 ret
= SetupFindFirstLineW(hinf
, sectionname
, AddService
, &ContextService
);
1541 if (!GetStringField(&ContextService
, 1, &ServiceName
))
1544 ret
= SetupGetIntField(
1546 2, /* Field index */
1550 /* The field may be empty. Ignore the error */
1554 if (!GetStringField(&ContextService
, 3, &ServiceSection
))
1557 ret
= InstallOneService(list
, hinf
, ServiceSection
, ServiceName
, (ServiceFlags
& ~SPSVCINST_ASSOCSERVICE
) | flags
);
1561 if (ServiceFlags
& SPSVCINST_ASSOCSERVICE
)
1563 ret
= SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet
, DeviceInfoData
, SPDRP_SERVICE
, (LPBYTE
)ServiceName
, (strlenW(ServiceName
) + 1) * sizeof(WCHAR
));
1569 HeapFree(GetProcessHeap(), 0, ServiceName
);
1570 HeapFree(GetProcessHeap(), 0, ServiceSection
);
1571 ServiceName
= ServiceSection
= NULL
;
1572 ret
= SetupFindNextMatchLineW(&ContextService
, AddService
, &ContextService
);
1576 SetLastError(ERROR_SUCCESS_REBOOT_REQUIRED
);
1578 SetLastError(ERROR_SUCCESS
);
1582 TRACE("Returning %d\n", ret
);
1587 /***********************************************************************
1588 * SetupCopyOEMInfA (SETUPAPI.@)
1590 BOOL WINAPI
SetupCopyOEMInfA(
1591 IN PCSTR SourceInfFileName
,
1592 IN PCSTR OEMSourceMediaLocation
,
1593 IN DWORD OEMSourceMediaType
,
1595 OUT PSTR DestinationInfFileName OPTIONAL
,
1596 IN DWORD DestinationInfFileNameSize
,
1597 OUT PDWORD RequiredSize OPTIONAL
,
1598 OUT PSTR
* DestinationInfFileNameComponent OPTIONAL
)
1600 PWSTR SourceInfFileNameW
= NULL
;
1601 PWSTR OEMSourceMediaLocationW
= NULL
;
1602 PWSTR DestinationInfFileNameW
= NULL
;
1603 PWSTR DestinationInfFileNameComponentW
= NULL
;
1606 TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n",
1607 SourceInfFileName
, OEMSourceMediaLocation
, OEMSourceMediaType
,
1608 CopyStyle
, DestinationInfFileName
, DestinationInfFileNameSize
,
1609 RequiredSize
, DestinationInfFileNameComponent
);
1611 if (!DestinationInfFileName
&& DestinationInfFileNameSize
> 0)
1612 SetLastError(ERROR_INVALID_PARAMETER
);
1613 else if (!(SourceInfFileNameW
= MultiByteToUnicode(SourceInfFileName
, CP_ACP
)))
1614 SetLastError(ERROR_INVALID_PARAMETER
);
1615 else if (!(OEMSourceMediaLocationW
= MultiByteToUnicode(OEMSourceMediaLocation
, CP_ACP
)))
1616 SetLastError(ERROR_INVALID_PARAMETER
);
1619 if (DestinationInfFileNameSize
!= 0)
1621 DestinationInfFileNameW
= MyMalloc(DestinationInfFileNameSize
* sizeof(WCHAR
));
1622 if (!DestinationInfFileNameW
)
1624 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1629 ret
= SetupCopyOEMInfW(
1631 OEMSourceMediaLocationW
,
1634 DestinationInfFileNameW
,
1635 DestinationInfFileNameSize
,
1637 DestinationInfFileNameComponent
? &DestinationInfFileNameComponentW
: NULL
);
1641 if (DestinationInfFileNameSize
!= 0)
1643 if (WideCharToMultiByte(CP_ACP
, 0, DestinationInfFileNameW
, -1,
1644 DestinationInfFileName
, DestinationInfFileNameSize
, NULL
, NULL
) == 0)
1646 DestinationInfFileName
[0] = '\0';
1650 if (DestinationInfFileNameComponent
)
1652 if (DestinationInfFileNameComponentW
)
1653 *DestinationInfFileNameComponent
= &DestinationInfFileName
[DestinationInfFileNameComponentW
- DestinationInfFileNameW
];
1655 *DestinationInfFileNameComponent
= NULL
;
1661 MyFree(SourceInfFileNameW
);
1662 MyFree(OEMSourceMediaLocationW
);
1663 MyFree(DestinationInfFileNameW
);
1665 TRACE("Returning %d\n", ret
);
1669 /***********************************************************************
1670 * SetupCopyOEMInfW (SETUPAPI.@)
1672 BOOL WINAPI
SetupCopyOEMInfW(
1673 IN PCWSTR SourceInfFileName
,
1674 IN PCWSTR OEMSourceMediaLocation
,
1675 IN DWORD OEMSourceMediaType
,
1677 OUT PWSTR DestinationInfFileName OPTIONAL
,
1678 IN DWORD DestinationInfFileNameSize
,
1679 OUT PDWORD RequiredSize OPTIONAL
,
1680 OUT PWSTR
* DestinationInfFileNameComponent OPTIONAL
)
1684 TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n",
1685 debugstr_w(SourceInfFileName
), debugstr_w(OEMSourceMediaLocation
), OEMSourceMediaType
,
1686 CopyStyle
, DestinationInfFileName
, DestinationInfFileNameSize
,
1687 RequiredSize
, DestinationInfFileNameComponent
);
1689 if (!SourceInfFileName
)
1690 SetLastError(ERROR_INVALID_PARAMETER
);
1691 else if (OEMSourceMediaType
!= SPOST_NONE
&& OEMSourceMediaType
!= SPOST_PATH
&& OEMSourceMediaType
!= SPOST_URL
)
1692 SetLastError(ERROR_INVALID_PARAMETER
);
1693 else if (CopyStyle
& ~(SP_COPY_DELETESOURCE
| SP_COPY_REPLACEONLY
| SP_COPY_NOOVERWRITE
| SP_COPY_OEMINF_CATALOG_ONLY
))
1695 TRACE("Unknown flags: 0x%08lx\n", CopyStyle
& ~(SP_COPY_DELETESOURCE
| SP_COPY_REPLACEONLY
| SP_COPY_NOOVERWRITE
| SP_COPY_OEMINF_CATALOG_ONLY
));
1696 SetLastError(ERROR_INVALID_FLAGS
);
1698 else if (!DestinationInfFileName
&& DestinationInfFileNameSize
> 0)
1699 SetLastError(ERROR_INVALID_PARAMETER
);
1700 else if (CopyStyle
& SP_COPY_OEMINF_CATALOG_ONLY
)
1702 FIXME("CopyStyle 0x%lx not supported\n", SP_COPY_OEMINF_CATALOG_ONLY
);
1703 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1707 HANDLE hSearch
= INVALID_HANDLE_VALUE
;
1708 WIN32_FIND_DATAW FindFileData
;
1710 DWORD NextFreeNumber
= 0;
1712 LPWSTR pFullFileName
= NULL
;
1713 LPWSTR pFileName
; /* Pointer into pFullFileName buffer */
1715 if (OEMSourceMediaType
== SPOST_PATH
|| OEMSourceMediaType
== SPOST_URL
)
1716 FIXME("OEMSourceMediaType 0x%lx ignored\n", OEMSourceMediaType
);
1718 /* Search if the specified .inf file already exists in %WINDIR%\Inf */
1719 AlreadyExists
= FALSE
; /* FIXME */
1721 if (!AlreadyExists
&& CopyStyle
& SP_COPY_REPLACEONLY
)
1723 /* FIXME: set DestinationInfFileName, RequiredSize, DestinationInfFileNameComponent */
1724 SetLastError(ERROR_FILE_NOT_FOUND
);
1727 else if (AlreadyExists
&& (CopyStyle
& SP_COPY_NOOVERWRITE
))
1729 //SetLastError(ERROR_FILE_EXISTS);
1730 /* FIXME: set return fields */
1731 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1732 FIXME("File already exists. Need to return its name!\n");
1736 /* Search the number to give to OEM??.INF */
1737 len
= MAX_PATH
+ 1 + strlenW(InfDirectory
) + 13;
1738 pFullFileName
= MyMalloc(len
* sizeof(WCHAR
));
1741 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1744 len
= GetSystemWindowsDirectoryW(pFullFileName
, MAX_PATH
);
1745 if (len
== 0 || len
> MAX_PATH
)
1747 if (pFullFileName
[strlenW(pFullFileName
) - 1] != '\\')
1748 strcatW(pFullFileName
, BackSlash
);
1749 strcatW(pFullFileName
, InfDirectory
);
1750 pFileName
= &pFullFileName
[strlenW(pFullFileName
)];
1751 sprintfW(pFileName
, L
"oem*.inf", NextFreeNumber
);
1752 hSearch
= FindFirstFileW(pFullFileName
, &FindFileData
);
1753 if (hSearch
== INVALID_HANDLE_VALUE
)
1755 if (GetLastError() != ERROR_FILE_NOT_FOUND
)
1762 DWORD CurrentNumber
;
1763 if (swscanf(FindFileData
.cFileName
, L
"oem%lu.inf", &CurrentNumber
) == 1
1764 && CurrentNumber
<= 99999)
1766 NextFreeNumber
= CurrentNumber
+ 1;
1768 } while (FindNextFile(hSearch
, &FindFileData
));
1771 if (NextFreeNumber
> 99999)
1773 ERR("Too much custom .inf files\n");
1774 SetLastError(ERROR_GEN_FAILURE
);
1778 /* Create the full path: %WINDIR%\Inf\OEM{XXXXX}.inf */
1779 sprintfW(pFileName
, L
"oem%lu.inf", NextFreeNumber
);
1780 TRACE("Next available file is %s\n", debugstr_w(pFileName
));
1783 *RequiredSize
= len
;
1784 if (DestinationInfFileName
)
1786 if (DestinationInfFileNameSize
< len
)
1788 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1791 strcpyW(DestinationInfFileName
, pFullFileName
);
1792 if (DestinationInfFileNameComponent
)
1793 *DestinationInfFileNameComponent
= &DestinationInfFileName
[pFileName
- pFullFileName
];
1796 if (!CopyFileW(SourceInfFileName
, pFullFileName
, TRUE
))
1798 TRACE("CopyFileW() failed with error 0x%lx\n", GetLastError());
1802 if (CopyStyle
& SP_COPY_DELETESOURCE
)
1804 if (!DeleteFileW(SourceInfFileName
))
1806 TRACE("DeleteFileW() failed with error 0x%lx\n", GetLastError());
1814 if (hSearch
!= INVALID_HANDLE_VALUE
)
1816 MyFree(pFullFileName
);
1819 TRACE("Returning %d\n", ret
);