2 * Setupapi install routines
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
5 * 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "setupapi_private.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
26 /* info passed to callback functions dealing with files */
27 struct files_callback_info
35 /* info passed to callback functions dealing with the registry */
36 struct registry_callback_info
42 /* info passed to callback functions dealing with registering dlls */
43 struct register_dll_info
45 PSP_FILE_CALLBACK_W callback
;
46 PVOID callback_context
;
50 typedef BOOL (*iterate_fields_func
)( HINF hinf
, PCWSTR field
, void *arg
);
52 /* Unicode constants */
53 static const WCHAR CopyFiles
[] = {'C','o','p','y','F','i','l','e','s',0};
54 static const WCHAR DelFiles
[] = {'D','e','l','F','i','l','e','s',0};
55 static const WCHAR RenFiles
[] = {'R','e','n','F','i','l','e','s',0};
56 static const WCHAR Ini2Reg
[] = {'I','n','i','2','R','e','g',0};
57 static const WCHAR LogConf
[] = {'L','o','g','C','o','n','f',0};
58 static const WCHAR AddReg
[] = {'A','d','d','R','e','g',0};
59 static const WCHAR DelReg
[] = {'D','e','l','R','e','g',0};
60 static const WCHAR BitReg
[] = {'B','i','t','R','e','g',0};
61 static const WCHAR UpdateInis
[] = {'U','p','d','a','t','e','I','n','i','s',0};
62 static const WCHAR CopyINF
[] = {'C','o','p','y','I','N','F',0};
63 static const WCHAR UpdateIniFields
[] = {'U','p','d','a','t','e','I','n','i','F','i','e','l','d','s',0};
64 static const WCHAR RegisterDlls
[] = {'R','e','g','i','s','t','e','r','D','l','l','s',0};
65 static const WCHAR UnregisterDlls
[] = {'U','n','r','e','g','i','s','t','e','r','D','l','l','s',0};
66 static const WCHAR ProfileItems
[] = {'P','r','o','f','i','l','e','I','t','e','m','s',0};
67 static const WCHAR Include
[] = {'I','n','c','l','u','d','e',0};
68 static const WCHAR Needs
[] = {'N','e','e','d','s',0};
71 /***********************************************************************
74 * Retrieve the contents of a field, dynamically growing the buffer if necessary.
76 static WCHAR
*get_field_string( INFCONTEXT
*context
, DWORD index
, WCHAR
*buffer
,
77 WCHAR
*static_buffer
, DWORD
*size
)
81 if (SetupGetStringFieldW( context
, index
, buffer
, *size
, &required
)) return buffer
;
82 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
84 /* now grow the buffer */
85 if (buffer
!= static_buffer
) HeapFree( GetProcessHeap(), 0, buffer
);
86 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, required
*sizeof(WCHAR
) ))) return NULL
;
88 if (SetupGetStringFieldW( context
, index
, buffer
, *size
, &required
)) return buffer
;
90 if (buffer
!= static_buffer
) HeapFree( GetProcessHeap(), 0, buffer
);
95 /***********************************************************************
98 * Called once for each CopyFiles entry in a given section.
100 static BOOL
copy_files_callback( HINF hinf
, PCWSTR field
, void *arg
)
102 struct files_callback_info
*info
= arg
;
104 if (field
[0] == '@') /* special case: copy single file */
105 SetupQueueDefaultCopyW( info
->queue
, info
->layout
, info
->src_root
, NULL
, field
, info
->copy_flags
);
107 SetupQueueCopySectionW( info
->queue
, info
->src_root
, info
->layout
, hinf
, field
, info
->copy_flags
);
112 /***********************************************************************
113 * delete_files_callback
115 * Called once for each DelFiles entry in a given section.
117 static BOOL
delete_files_callback( HINF hinf
, PCWSTR field
, void *arg
)
119 struct files_callback_info
*info
= arg
;
120 SetupQueueDeleteSectionW( info
->queue
, hinf
, 0, field
);
125 /***********************************************************************
126 * rename_files_callback
128 * Called once for each RenFiles entry in a given section.
130 static BOOL
rename_files_callback( HINF hinf
, PCWSTR field
, void *arg
)
132 struct files_callback_info
*info
= arg
;
133 SetupQueueRenameSectionW( info
->queue
, hinf
, 0, field
);
138 /***********************************************************************
141 * Retrieve the registry root key from its name.
143 static HKEY
get_root_key( const WCHAR
*name
, HKEY def_root
)
145 static const WCHAR HKCR
[] = {'H','K','C','R',0};
146 static const WCHAR HKCU
[] = {'H','K','C','U',0};
147 static const WCHAR HKLM
[] = {'H','K','L','M',0};
148 static const WCHAR HKU
[] = {'H','K','U',0};
149 static const WCHAR HKR
[] = {'H','K','R',0};
151 if (!strcmpiW( name
, HKCR
)) return HKEY_CLASSES_ROOT
;
152 if (!strcmpiW( name
, HKCU
)) return HKEY_CURRENT_USER
;
153 if (!strcmpiW( name
, HKLM
)) return HKEY_LOCAL_MACHINE
;
154 if (!strcmpiW( name
, HKU
)) return HKEY_USERS
;
155 if (!strcmpiW( name
, HKR
)) return def_root
;
160 /***********************************************************************
161 * append_multi_sz_value
163 * Append a multisz string to a multisz registry value.
165 static void append_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*strings
,
168 DWORD size
, type
, total
;
171 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
172 if (type
!= REG_MULTI_SZ
) return;
174 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, (size
+ str_size
) * sizeof(WCHAR
) ))) return;
175 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
177 /* compare each string against all the existing ones */
181 int len
= strlenW(strings
) + 1;
183 for (p
= buffer
; *p
; p
+= strlenW(p
) + 1)
184 if (!strcmpiW( p
, strings
)) break;
186 if (!*p
) /* not found, need to append it */
188 memcpy( p
, strings
, len
* sizeof(WCHAR
) );
196 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
) );
197 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
, (BYTE
*)buffer
, total
);
200 HeapFree( GetProcessHeap(), 0, buffer
);
204 /***********************************************************************
205 * delete_multi_sz_value
207 * Remove a string from a multisz registry value.
209 static void delete_multi_sz_value( HKEY hkey
, const WCHAR
*value
, const WCHAR
*string
)
212 WCHAR
*buffer
, *src
, *dst
;
214 if (RegQueryValueExW( hkey
, value
, NULL
, &type
, NULL
, &size
)) return;
215 if (type
!= REG_MULTI_SZ
) return;
216 /* allocate double the size, one for value before and one for after */
217 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, size
* 2 * sizeof(WCHAR
) ))) return;
218 if (RegQueryValueExW( hkey
, value
, NULL
, NULL
, (BYTE
*)buffer
, &size
)) goto done
;
223 int len
= strlenW(src
) + 1;
224 if (strcmpiW( src
, string
))
226 memcpy( dst
, src
, len
* sizeof(WCHAR
) );
232 if (dst
!= buffer
+ 2*size
) /* did we remove something? */
234 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(buffer
+ size
) );
235 RegSetValueExW( hkey
, value
, 0, REG_MULTI_SZ
,
236 (BYTE
*)(buffer
+ size
), dst
- (buffer
+ size
) );
239 HeapFree( GetProcessHeap(), 0, buffer
);
243 /***********************************************************************
246 * Perform an add/delete registry operation depending on the flags.
248 static BOOL
do_reg_operation( HKEY hkey
, const WCHAR
*value
, INFCONTEXT
*context
, INT flags
)
252 if (flags
& (FLG_ADDREG_DELREG_BIT
| FLG_ADDREG_DELVAL
)) /* deletion */
254 if (*value
&& !(flags
& FLG_DELREG_KEYONLY_COMMON
))
256 if ((flags
& FLG_DELREG_MULTI_SZ_DELSTRING
) == FLG_DELREG_MULTI_SZ_DELSTRING
)
260 if (!SetupGetStringFieldW( context
, 5, NULL
, 0, &size
) || !size
) return TRUE
;
261 if (!(str
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return FALSE
;
262 SetupGetStringFieldW( context
, 5, str
, size
, NULL
);
263 delete_multi_sz_value( hkey
, value
, str
);
264 HeapFree( GetProcessHeap(), 0, str
);
266 else RegDeleteValueW( hkey
, value
);
268 else RegDeleteKeyW( hkey
, NULL
);
272 if (flags
& (FLG_ADDREG_KEYONLY
|FLG_ADDREG_KEYONLY_COMMON
)) return TRUE
;
274 if (flags
& (FLG_ADDREG_NOCLOBBER
|FLG_ADDREG_OVERWRITEONLY
))
276 BOOL exists
= !RegQueryValueExW( hkey
, value
, NULL
, NULL
, NULL
, NULL
);
277 if (exists
&& (flags
& FLG_ADDREG_NOCLOBBER
)) return TRUE
;
278 if (!exists
& (flags
& FLG_ADDREG_OVERWRITEONLY
)) return TRUE
;
281 switch(flags
& FLG_ADDREG_TYPE_MASK
)
283 case FLG_ADDREG_TYPE_SZ
: type
= REG_SZ
; break;
284 case FLG_ADDREG_TYPE_MULTI_SZ
: type
= REG_MULTI_SZ
; break;
285 case FLG_ADDREG_TYPE_EXPAND_SZ
: type
= REG_EXPAND_SZ
; break;
286 case FLG_ADDREG_TYPE_BINARY
: type
= REG_BINARY
; break;
287 case FLG_ADDREG_TYPE_DWORD
: type
= REG_DWORD
; break;
288 case FLG_ADDREG_TYPE_NONE
: type
= REG_NONE
; break;
289 default: type
= flags
>> 16; break;
292 if (!(flags
& FLG_ADDREG_BINVALUETYPE
) ||
293 (type
== REG_DWORD
&& SetupGetFieldCount(context
) == 5))
295 static const WCHAR empty
;
298 if (type
== REG_MULTI_SZ
)
300 if (!SetupGetMultiSzFieldW( context
, 5, NULL
, 0, &size
)) size
= 0;
303 if (!(str
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return FALSE
;
304 SetupGetMultiSzFieldW( context
, 5, str
, size
, NULL
);
306 if (flags
& FLG_ADDREG_APPEND
)
308 if (!str
) return TRUE
;
309 append_multi_sz_value( hkey
, value
, str
, size
);
310 HeapFree( GetProcessHeap(), 0, str
);
313 /* else fall through to normal string handling */
317 if (!SetupGetStringFieldW( context
, 5, NULL
, 0, &size
)) size
= 0;
320 if (!(str
= HeapAlloc( GetProcessHeap(), 0, size
* sizeof(WCHAR
) ))) return FALSE
;
321 SetupGetStringFieldW( context
, 5, str
, size
, NULL
);
325 if (type
== REG_DWORD
)
327 DWORD dw
= str
? strtoulW( str
, NULL
, 0 ) : 0;
328 TRACE( "setting dword %s to %lx\n", debugstr_w(value
), dw
);
329 RegSetValueExW( hkey
, value
, 0, type
, (BYTE
*)&dw
, sizeof(dw
) );
333 TRACE( "setting value %s to %s\n", debugstr_w(value
), debugstr_w(str
) );
334 if (str
) RegSetValueExW( hkey
, value
, 0, type
, (BYTE
*)str
, size
* sizeof(WCHAR
) );
335 else RegSetValueExW( hkey
, value
, 0, type
, (const BYTE
*)&empty
, sizeof(WCHAR
) );
337 HeapFree( GetProcessHeap(), 0, str
);
340 else /* get the binary data */
344 if (!SetupGetBinaryField( context
, 5, NULL
, 0, &size
)) size
= 0;
347 if (!(data
= HeapAlloc( GetProcessHeap(), 0, size
))) return FALSE
;
348 TRACE( "setting binary data %s len %ld\n", debugstr_w(value
), size
);
349 SetupGetBinaryField( context
, 5, data
, size
, NULL
);
351 RegSetValueExW( hkey
, value
, 0, type
, data
, size
);
352 HeapFree( GetProcessHeap(), 0, data
);
358 /***********************************************************************
361 * Called once for each AddReg and DelReg entry in a given section.
363 static BOOL
registry_callback( HINF hinf
, PCWSTR field
, void *arg
)
365 struct registry_callback_info
*info
= arg
;
369 BOOL ok
= SetupFindFirstLineW( hinf
, field
, NULL
, &context
);
371 for (; ok
; ok
= SetupFindNextLine( &context
, &context
))
373 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
377 if (!SetupGetStringFieldW( &context
, 1, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
379 if (!(root_key
= get_root_key( buffer
, info
->default_root
)))
383 if (!SetupGetStringFieldW( &context
, 2, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
387 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0;
391 if (flags
& FLG_ADDREG_DELREG_BIT
) continue; /* ignore this entry */
395 if (!flags
) flags
= FLG_ADDREG_DELREG_BIT
;
396 else if (!(flags
& FLG_ADDREG_DELREG_BIT
)) continue; /* ignore this entry */
399 if (info
->delete || (flags
& FLG_ADDREG_OVERWRITEONLY
))
401 if (RegOpenKeyW( root_key
, buffer
, &hkey
)) continue; /* ignore if it doesn't exist */
403 else if (RegCreateKeyW( root_key
, buffer
, &hkey
))
405 ERR( "could not create key %p %s\n", root_key
, debugstr_w(buffer
) );
408 TRACE( "key %p %s\n", root_key
, debugstr_w(buffer
) );
411 if (!SetupGetStringFieldW( &context
, 3, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
415 if (!do_reg_operation( hkey
, buffer
, &context
, flags
))
426 /***********************************************************************
429 * Register or unregister a dll.
431 static BOOL
do_register_dll( const struct register_dll_info
*info
, const WCHAR
*path
,
432 INT flags
, INT timeout
, const WCHAR
*args
)
436 SP_REGISTER_CONTROL_STATUSW status
;
438 status
.cbSize
= sizeof(status
);
439 status
.FileName
= path
;
440 status
.FailureCode
= SPREG_SUCCESS
;
441 status
.Win32Error
= ERROR_SUCCESS
;
445 switch(info
->callback( info
->callback_context
, SPFILENOTIFY_STARTREGISTRATION
,
446 (UINT_PTR
)&status
, !info
->unregister
))
449 SetLastError( ERROR_OPERATION_ABORTED
);
458 if (!(module
= LoadLibraryExW( path
, 0, LOAD_WITH_ALTERED_SEARCH_PATH
)))
460 WARN( "could not load %s\n", debugstr_w(path
) );
461 status
.FailureCode
= SPREG_LOADLIBRARY
;
462 status
.Win32Error
= GetLastError();
466 if (flags
& FLG_REGSVR_DLLREGISTER
)
468 const char *entry_point
= info
->unregister
? "DllUnregisterServer" : "DllRegisterServer";
469 HRESULT (WINAPI
*func
)(void) = (void *)GetProcAddress( module
, entry_point
);
473 status
.FailureCode
= SPREG_GETPROCADDR
;
474 status
.Win32Error
= GetLastError();
478 TRACE( "calling %s in %s\n", entry_point
, debugstr_w(path
) );
483 WARN( "calling %s in %s returned error %lx\n", entry_point
, debugstr_w(path
), res
);
484 status
.FailureCode
= SPREG_REGSVR
;
485 status
.Win32Error
= res
;
490 if (flags
& FLG_REGSVR_DLLINSTALL
)
492 HRESULT (WINAPI
*func
)(BOOL
,LPCWSTR
) = (void *)GetProcAddress( module
, "DllInstall" );
496 status
.FailureCode
= SPREG_GETPROCADDR
;
497 status
.Win32Error
= GetLastError();
501 TRACE( "calling DllInstall(%d,%s) in %s\n",
502 !info
->unregister
, debugstr_w(args
), debugstr_w(path
) );
503 res
= func( !info
->unregister
, args
);
507 WARN( "calling DllInstall in %s returned error %lx\n", debugstr_w(path
), res
);
508 status
.FailureCode
= SPREG_REGSVR
;
509 status
.Win32Error
= res
;
515 if (module
) FreeLibrary( module
);
516 if (info
->callback
) info
->callback( info
->callback_context
, SPFILENOTIFY_ENDREGISTRATION
,
517 (UINT_PTR
)&status
, !info
->unregister
);
522 /***********************************************************************
523 * register_dlls_callback
525 * Called once for each RegisterDlls entry in a given section.
527 static BOOL
register_dlls_callback( HINF hinf
, PCWSTR field
, void *arg
)
529 struct register_dll_info
*info
= arg
;
532 BOOL ok
= SetupFindFirstLineW( hinf
, field
, NULL
, &context
);
534 for (; ok
; ok
= SetupFindNextLine( &context
, &context
))
536 WCHAR
*path
, *args
, *p
;
537 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
541 if (!(path
= PARSER_get_dest_dir( &context
))) continue;
544 if (!SetupGetStringFieldW( &context
, 3, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
546 if (!(p
= HeapReAlloc( GetProcessHeap(), 0, path
,
547 (strlenW(path
) + strlenW(buffer
) + 2) * sizeof(WCHAR
) ))) goto done
;
550 if (p
== path
|| p
[-1] != '\\') *p
++ = '\\';
551 strcpyW( p
, buffer
);
554 if (!SetupGetIntField( &context
, 4, &flags
)) flags
= 0;
557 if (!SetupGetIntField( &context
, 5, &timeout
)) timeout
= 60;
559 /* get command line */
561 if (SetupGetStringFieldW( &context
, 6, buffer
, sizeof(buffer
)/sizeof(WCHAR
), NULL
))
564 ret
= do_register_dll( info
, path
, flags
, timeout
, args
);
567 HeapFree( GetProcessHeap(), 0, path
);
573 /***********************************************************************
574 * update_ini_callback
576 * Called once for each UpdateInis entry in a given section.
578 static BOOL
update_ini_callback( HINF hinf
, PCWSTR field
, void *arg
)
582 BOOL ok
= SetupFindFirstLineW( hinf
, field
, NULL
, &context
);
584 for (; ok
; ok
= SetupFindNextLine( &context
, &context
))
586 WCHAR buffer
[MAX_INF_STRING_LENGTH
];
587 WCHAR filename
[MAX_INF_STRING_LENGTH
];
588 WCHAR section
[MAX_INF_STRING_LENGTH
];
589 WCHAR entry
[MAX_INF_STRING_LENGTH
];
590 WCHAR string
[MAX_INF_STRING_LENGTH
];
593 if (!SetupGetStringFieldW( &context
, 1, filename
,
594 sizeof(filename
)/sizeof(WCHAR
), NULL
))
597 if (!SetupGetStringFieldW( &context
, 2, section
,
598 sizeof(section
)/sizeof(WCHAR
), NULL
))
601 if (!SetupGetStringFieldW( &context
, 4, buffer
,
602 sizeof(buffer
)/sizeof(WCHAR
), NULL
))
605 divider
= strchrW(buffer
,'=');
609 strcpyW(entry
,buffer
);
611 strcpyW(string
,divider
);
615 strcpyW(entry
,buffer
);
619 TRACE("Writing %s = %s in %s of file %s\n",debugstr_w(entry
),
620 debugstr_w(string
),debugstr_w(section
),debugstr_w(filename
));
621 WritePrivateProfileStringW(section
,entry
,string
,filename
);
627 static BOOL
update_ini_fields_callback( HINF hinf
, PCWSTR field
, void *arg
)
629 FIXME( "should update ini fields %s\n", debugstr_w(field
) );
633 static BOOL
ini2reg_callback( HINF hinf
, PCWSTR field
, void *arg
)
635 FIXME( "should do ini2reg %s\n", debugstr_w(field
) );
639 static BOOL
logconf_callback( HINF hinf
, PCWSTR field
, void *arg
)
641 FIXME( "should do logconf %s\n", debugstr_w(field
) );
645 static BOOL
bitreg_callback( HINF hinf
, PCWSTR field
, void *arg
)
647 FIXME( "should do bitreg %s\n", debugstr_w(field
) );
651 static BOOL
profile_items_callback( HINF hinf
, PCWSTR field
, void *arg
)
653 FIXME( "should do profile items %s\n", debugstr_w(field
) );
657 static BOOL
copy_inf_callback( HINF hinf
, PCWSTR field
, void *arg
)
659 FIXME( "should do copy inf %s\n", debugstr_w(field
) );
664 /***********************************************************************
665 * iterate_section_fields
667 * Iterate over all fields of a certain key of a certain section
669 static BOOL
iterate_section_fields( HINF hinf
, PCWSTR section
, PCWSTR key
,
670 iterate_fields_func callback
, void *arg
)
672 WCHAR static_buffer
[200];
673 WCHAR
*buffer
= static_buffer
;
674 DWORD size
= sizeof(static_buffer
)/sizeof(WCHAR
);
678 BOOL ok
= SetupFindFirstLineW( hinf
, section
, key
, &context
);
681 UINT i
, count
= SetupGetFieldCount( &context
);
682 for (i
= 1; i
<= count
; i
++)
684 if (!(buffer
= get_field_string( &context
, i
, buffer
, static_buffer
, &size
)))
686 if (!callback( hinf
, buffer
, arg
))
688 WARN("callback failed for %s %s err %ld\n",
689 debugstr_w(section
), debugstr_w(buffer
), GetLastError() );
693 ok
= SetupFindNextMatchLineW( &context
, key
, &context
);
697 if (buffer
&& buffer
!= static_buffer
) HeapFree( GetProcessHeap(), 0, buffer
);
702 /***********************************************************************
703 * SetupInstallFilesFromInfSectionA (SETUPAPI.@)
705 BOOL WINAPI
SetupInstallFilesFromInfSectionA( HINF hinf
, HINF hlayout
, HSPFILEQ queue
,
706 PCSTR section
, PCSTR src_root
, UINT flags
)
708 UNICODE_STRING sectionW
;
711 if (!RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
713 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
717 ret
= SetupInstallFilesFromInfSectionW( hinf
, hlayout
, queue
, sectionW
.Buffer
,
722 if (RtlCreateUnicodeStringFromAsciiz( &srcW
, src_root
))
724 ret
= SetupInstallFilesFromInfSectionW( hinf
, hlayout
, queue
, sectionW
.Buffer
,
725 srcW
.Buffer
, flags
);
726 RtlFreeUnicodeString( &srcW
);
728 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
730 RtlFreeUnicodeString( §ionW
);
735 /***********************************************************************
736 * SetupInstallFilesFromInfSectionW (SETUPAPI.@)
738 BOOL WINAPI
SetupInstallFilesFromInfSectionW( HINF hinf
, HINF hlayout
, HSPFILEQ queue
,
739 PCWSTR section
, PCWSTR src_root
, UINT flags
)
741 struct files_callback_info info
;
744 info
.src_root
= src_root
;
745 info
.copy_flags
= flags
;
746 info
.layout
= hlayout
;
747 return iterate_section_fields( hinf
, section
, CopyFiles
, copy_files_callback
, &info
);
751 /***********************************************************************
752 * SetupInstallFromInfSectionA (SETUPAPI.@)
754 BOOL WINAPI
SetupInstallFromInfSectionA( HWND owner
, HINF hinf
, PCSTR section
, UINT flags
,
755 HKEY key_root
, PCSTR src_root
, UINT copy_flags
,
756 PSP_FILE_CALLBACK_A callback
, PVOID context
,
757 HDEVINFO devinfo
, PSP_DEVINFO_DATA devinfo_data
)
759 UNICODE_STRING sectionW
, src_rootW
;
760 struct callback_WtoA_context ctx
;
763 src_rootW
.Buffer
= NULL
;
764 if (src_root
&& !RtlCreateUnicodeStringFromAsciiz( &src_rootW
, src_root
))
766 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
770 if (RtlCreateUnicodeStringFromAsciiz( §ionW
, section
))
772 ctx
.orig_context
= context
;
773 ctx
.orig_handler
= callback
;
774 ret
= SetupInstallFromInfSectionW( owner
, hinf
, sectionW
.Buffer
, flags
, key_root
,
775 src_rootW
.Buffer
, copy_flags
, QUEUE_callback_WtoA
,
776 &ctx
, devinfo
, devinfo_data
);
777 RtlFreeUnicodeString( §ionW
);
779 else SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
781 RtlFreeUnicodeString( &src_rootW
);
786 /***********************************************************************
787 * SetupInstallFromInfSectionW (SETUPAPI.@)
789 BOOL WINAPI
SetupInstallFromInfSectionW( HWND owner
, HINF hinf
, PCWSTR section
, UINT flags
,
790 HKEY key_root
, PCWSTR src_root
, UINT copy_flags
,
791 PSP_FILE_CALLBACK_W callback
, PVOID context
,
792 HDEVINFO devinfo
, PSP_DEVINFO_DATA devinfo_data
)
794 INFCONTEXT include_context
;
796 /* Parse 'Include' line */
797 if (SetupFindFirstLineW( hinf
, section
, Include
, &include_context
))
802 static WCHAR szBuffer
[MAX_PATH
];
803 PWSTR pBuffer
= NULL
;
807 ok
= SetupGetStringFieldW( &include_context
, index
, szBuffer
, MAX_PATH
, &required
);
808 if (!ok
&& GetLastError() == ERROR_INVALID_PARAMETER
)
810 else if (!ok
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
812 pBuffer
= MyMalloc(required
);
813 ok
= SetupGetStringFieldW( &include_context
, index
, pBuffer
, required
, &required
);
816 ok
= SetupOpenAppendInfFileW( pBuffer
? pBuffer
: szBuffer
, hinf
, NULL
);
819 if (!ok
) return FALSE
;
824 /* Parse 'Needs' line */
825 if (SetupFindFirstLineW( hinf
, section
, Needs
, &include_context
))
830 static WCHAR szBuffer
[MAX_PATH
];
831 PWSTR pBuffer
= NULL
;
835 ok
= SetupGetStringFieldW( &include_context
, index
, szBuffer
, MAX_PATH
, &required
);
836 if (!ok
&& GetLastError() == ERROR_INVALID_PARAMETER
)
838 else if (!ok
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
840 pBuffer
= MyMalloc(required
);
841 ok
= SetupGetStringFieldW( &include_context
, index
, pBuffer
, required
, &required
);
845 ok
= SetupInstallFromInfSectionW( owner
, hinf
, pBuffer
? pBuffer
: szBuffer
,
846 flags
, key_root
, src_root
, copy_flags
, callback
, context
, devinfo
, devinfo_data
);
850 if (!ok
) return FALSE
;
855 if (flags
& SPINST_FILES
)
857 struct files_callback_info info
;
861 if (!(queue
= SetupOpenFileQueue())) return FALSE
;
863 info
.src_root
= src_root
;
864 info
.copy_flags
= copy_flags
;
866 ret
= (iterate_section_fields( hinf
, section
, CopyFiles
, copy_files_callback
, &info
) &&
867 iterate_section_fields( hinf
, section
, DelFiles
, delete_files_callback
, &info
) &&
868 iterate_section_fields( hinf
, section
, RenFiles
, rename_files_callback
, &info
) &&
869 SetupCommitFileQueueW( owner
, queue
, callback
, context
));
870 SetupCloseFileQueue( queue
);
871 if (!ret
) return FALSE
;
873 if (flags
& SPINST_INIFILES
)
875 if (!iterate_section_fields( hinf
, section
, UpdateInis
, update_ini_callback
, NULL
) ||
876 !iterate_section_fields( hinf
, section
, UpdateIniFields
,
877 update_ini_fields_callback
, NULL
))
880 if (flags
& SPINST_INI2REG
)
882 if (!iterate_section_fields( hinf
, section
, Ini2Reg
, ini2reg_callback
, NULL
))
885 if (flags
& SPINST_LOGCONFIG
)
887 if (!iterate_section_fields( hinf
, section
, LogConf
, logconf_callback
, NULL
))
890 if (flags
& SPINST_REGSVR
)
892 struct register_dll_info info
;
894 info
.unregister
= FALSE
;
895 if (flags
& SPINST_REGISTERCALLBACKAWARE
)
897 info
.callback
= callback
;
898 info
.callback_context
= context
;
900 else info
.callback
= NULL
;
902 if (!iterate_section_fields( hinf
, section
, RegisterDlls
, register_dlls_callback
, &info
))
905 if (flags
& SPINST_UNREGSVR
)
907 struct register_dll_info info
;
909 info
.unregister
= TRUE
;
910 if (flags
& SPINST_REGISTERCALLBACKAWARE
)
912 info
.callback
= callback
;
913 info
.callback_context
= context
;
915 else info
.callback
= NULL
;
917 if (!iterate_section_fields( hinf
, section
, UnregisterDlls
, register_dlls_callback
, &info
))
920 if (flags
& SPINST_REGISTRY
)
922 struct registry_callback_info info
;
924 info
.default_root
= key_root
;
926 if (!iterate_section_fields( hinf
, section
, DelReg
, registry_callback
, &info
))
929 if (!iterate_section_fields( hinf
, section
, AddReg
, registry_callback
, &info
))
932 if (flags
& SPINST_BITREG
)
934 if (!iterate_section_fields( hinf
, section
, BitReg
, bitreg_callback
, NULL
))
937 if (flags
& SPINST_PROFILEITEMS
)
939 if (!iterate_section_fields( hinf
, section
, ProfileItems
, profile_items_callback
, NULL
))
942 if (flags
& SPINST_COPYINF
)
944 if (!iterate_section_fields( hinf
, section
, CopyINF
, copy_inf_callback
, NULL
))
952 /***********************************************************************
953 * InstallHinfSectionW (SETUPAPI.@)
955 * NOTE: 'cmdline' is <section> <mode> <path> from
956 * RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection <section> <mode> <path>
958 void WINAPI
InstallHinfSectionW( HWND hwnd
, HINSTANCE handle
, LPCWSTR cmdline
, INT show
)
960 WCHAR
*p
, *path
, section
[MAX_PATH
];
961 void *callback_context
;
965 TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd
, handle
, debugstr_w(cmdline
));
967 lstrcpynW( section
, cmdline
, sizeof(section
)/sizeof(WCHAR
) );
969 if (!(p
= strchrW( section
, ' ' ))) return;
971 while (*p
== ' ') p
++;
974 if (!(p
= strchrW( p
, ' ' ))) return;
976 while (*path
== ' ') path
++;
978 hinf
= SetupOpenInfFileW( path
, NULL
, INF_STYLE_WIN4
, NULL
);
979 if (hinf
== INVALID_HANDLE_VALUE
) return;
981 callback_context
= SetupInitDefaultQueueCallback( hwnd
);
982 SetupInstallFromInfSectionW( hwnd
, hinf
, section
, SPINST_ALL
, NULL
, NULL
, SP_COPY_NEWER
,
983 SetupDefaultQueueCallbackW
, callback_context
,
985 SetupTermDefaultQueueCallback( callback_context
);
986 SetupCloseInfFile( hinf
);
988 /* FIXME: should check the mode and maybe reboot */
989 /* there isn't much point in doing that since we */
990 /* don't yet handle deferred file copies anyway. */
994 /***********************************************************************
995 * InstallHinfSectionA (SETUPAPI.@)
997 void WINAPI
InstallHinfSectionA( HWND hwnd
, HINSTANCE handle
, LPCSTR cmdline
, INT show
)
999 UNICODE_STRING cmdlineW
;
1001 if (RtlCreateUnicodeStringFromAsciiz( &cmdlineW
, cmdline
))
1003 InstallHinfSectionW( hwnd
, handle
, cmdlineW
.Buffer
, show
);
1004 RtlFreeUnicodeString( &cmdlineW
);
1009 /***********************************************************************
1010 * SetupInstallServicesFromInfSectionA (SETUPAPI.@)
1012 BOOL WINAPI
SetupInstallServicesFromInfSectionA( HINF hinf
, PCSTR sectionname
, DWORD flags
)
1014 return SetupInstallServicesFromInfSectionExA( hinf
, sectionname
, flags
,
1015 NULL
, NULL
, NULL
, NULL
);
1019 /***********************************************************************
1020 * SetupInstallServicesFromInfSectionW (SETUPAPI.@)
1022 BOOL WINAPI
SetupInstallServicesFromInfSectionW( HINF hinf
, PCWSTR sectionname
, DWORD flags
)
1024 return SetupInstallServicesFromInfSectionExW( hinf
, sectionname
, flags
,
1025 NULL
, NULL
, NULL
, NULL
);
1029 /***********************************************************************
1030 * SetupInstallServicesFromInfSectionExA (SETUPAPI.@)
1032 BOOL WINAPI
SetupInstallServicesFromInfSectionExA( HINF hinf
, PCSTR sectionname
, DWORD flags
, HDEVINFO devinfo
, PSP_DEVINFO_DATA devinfo_data
, PVOID reserved1
, PVOID reserved2
)
1034 UNICODE_STRING sectionnameW
;
1037 if (RtlCreateUnicodeStringFromAsciiz( §ionnameW
, sectionname
))
1039 ret
= SetupInstallServicesFromInfSectionExW( hinf
, sectionnameW
.Buffer
, flags
, devinfo
, devinfo_data
, reserved1
, reserved2
);
1040 RtlFreeUnicodeString( §ionnameW
);
1043 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1049 static BOOL
GetLineText( HINF hinf
, PCWSTR section_name
, PCWSTR key_name
, PWSTR
*value
)
1056 if (! SetupGetLineTextW( NULL
, hinf
, section_name
, key_name
, NULL
, 0, &required
)
1057 && GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
1060 buf
= HeapAlloc( GetProcessHeap(), 0, required
* sizeof(WCHAR
) );
1063 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1067 if (! SetupGetLineTextW( NULL
, hinf
, section_name
, key_name
, buf
, required
, &required
) )
1069 HeapFree( GetProcessHeap(), 0, buf
);
1078 static BOOL
GetIntField( HINF hinf
, PCWSTR section_name
, PCWSTR key_name
, INT
*value
)
1083 if (! GetLineText( hinf
, section_name
, key_name
, &buffer
) )
1086 res
= wcstol( buffer
, &end
, 0 );
1087 if (end
!= buffer
&& !*end
)
1089 HeapFree(GetProcessHeap(), 0, buffer
);
1095 HeapFree(GetProcessHeap(), 0, buffer
);
1096 SetLastError( ERROR_INVALID_DATA
);
1102 /***********************************************************************
1103 * SetupInstallServicesFromInfSectionExW (SETUPAPI.@)
1105 BOOL WINAPI
SetupInstallServicesFromInfSectionExW( HINF hinf
, PCWSTR sectionname
, DWORD flags
, HDEVINFO DeviceInfoSet
, PSP_DEVINFO_DATA DeviceInfoData
, PVOID reserved1
, PVOID reserved2
)
1107 SC_HANDLE hSCManager
= NULL
;
1108 SC_HANDLE hService
= NULL
;
1109 LPDWORD GroupOrder
= NULL
;
1110 LPQUERY_SERVICE_CONFIG ServiceConfig
= NULL
;
1111 struct DeviceInfoSet
*list
;
1114 TRACE("%p, %s, 0x%lx, %p, %p, %p, %p\n", hinf
, debugstr_w(sectionname
),
1115 flags
, DeviceInfoSet
, DeviceInfoData
, reserved1
, reserved2
);
1118 SetLastError(ERROR_INVALID_PARAMETER
);
1119 else if (DeviceInfoSet
== (HDEVINFO
)INVALID_HANDLE_VALUE
)
1120 SetLastError(ERROR_INVALID_HANDLE
);
1121 else if ((list
= (struct DeviceInfoSet
*)DeviceInfoSet
)->magic
!= SETUP_DEV_INFO_SET_MAGIC
)
1122 SetLastError(ERROR_INVALID_HANDLE
);
1123 else if (DeviceInfoData
&& DeviceInfoData
->cbSize
!= sizeof(SP_DEVINFO_DATA
))
1124 SetLastError(ERROR_INVALID_USER_BUFFER
);
1125 else if (!reserved1
)
1127 /* FIXME: I don't know how to get the service name. ATM, just fail the call */
1128 /* Maybe find it in DeviceInfoSet/DeviceInfoData? */
1129 FIXME("Service name not specified!\n");
1130 SetLastError(ERROR_GEN_FAILURE
);
1135 HKEY hGroupOrderListKey
= INVALID_HANDLE_VALUE
;
1136 LPWSTR ServiceBinary
= NULL
;
1137 LPWSTR LoadOrderGroup
= NULL
;
1138 LPWSTR DisplayName
= NULL
;
1139 LPWSTR Description
= NULL
;
1140 LPWSTR Dependencies
= NULL
;
1141 INT ServiceType
, StartType
, ErrorControl
;
1143 DWORD tagId
= (DWORD
)-1;
1146 if (!GetIntField(hinf
, sectionname
, L
"ServiceType", &ServiceType
))
1148 if (!GetIntField(hinf
, sectionname
, L
"StartType", &StartType
))
1150 if (!GetIntField(hinf
, sectionname
, L
"ErrorControl", &ErrorControl
))
1152 useTag
= (ServiceType
== SERVICE_BOOT_START
|| ServiceType
== SERVICE_SYSTEM_START
);
1154 hSCManager
= OpenSCManagerW(NULL
, SERVICES_ACTIVE_DATABASE
, SC_MANAGER_CREATE_SERVICE
);
1155 if (hSCManager
== NULL
)
1158 if (!GetLineText(hinf
, sectionname
, L
"ServiceBinary", &ServiceBinary
))
1161 /* Don't check return value, as these fields are optional and
1162 * GetLineText initialize output parameter even on failure */
1163 GetLineText(hinf
, sectionname
, L
"LoadOrderGroup", &LoadOrderGroup
);
1164 GetLineText(hinf
, sectionname
, L
"DisplayName", &DisplayName
);
1165 GetLineText(hinf
, sectionname
, L
"Description", &Description
);
1166 GetLineText(hinf
, sectionname
, L
"Dependencies", &Dependencies
);
1168 hService
= OpenServiceW(
1171 GENERIC_READ
| GENERIC_WRITE
);
1172 if (hService
== NULL
&& GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST
)
1175 if (flags
& (SPSVCINST_STOPSERVICE
| SPSVCINST_DELETEEVENTLOGENTRY
))
1177 if (hService
== NULL
)
1179 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
1182 if (flags
& SPSVCINST_STOPSERVICE
)
1184 SERVICE_STATUS ServiceStatus
;
1185 ret
= ControlService(hService
, SERVICE_CONTROL_STOP
, &ServiceStatus
);
1186 if (!ret
&& GetLastError() != ERROR_SERVICE_NOT_ACTIVE
)
1188 if (ServiceStatus
.dwCurrentState
!= SERVICE_STOP_PENDING
&& ServiceStatus
.dwCurrentState
!= SERVICE_STOPPED
)
1190 SetLastError(ERROR_INSTALL_SERVICE_FAILURE
);
1194 if (flags
& SPSVCINST_DELETEEVENTLOGENTRY
)
1196 ret
= DeleteService(hService
);
1203 if (hService
== NULL
)
1205 /* Create new service */
1206 hService
= CreateServiceW(
1216 useTag
? &tagId
: NULL
,
1219 if (hService
== NULL
)
1225 /* Read current configuration */
1226 if (!QueryServiceConfigW(hService
, NULL
, 0, &bufferSize
))
1228 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
1230 ServiceConfig
= HeapAlloc(GetProcessHeap(), 0, bufferSize
);
1233 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1236 if (!QueryServiceConfigW(hService
, ServiceConfig
, bufferSize
, &bufferSize
))
1239 tagId
= ServiceConfig
->dwTagId
;
1241 /* Update configuration */
1242 ret
= ChangeServiceConfigW(
1245 (flags
& SPSVCINST_NOCLOBBER_STARTTYPE
) ? SERVICE_NO_CHANGE
: StartType
,
1246 (flags
& SPSVCINST_NOCLOBBER_ERRORCONTROL
) ? SERVICE_NO_CHANGE
: ErrorControl
,
1248 (flags
& SPSVCINST_NOCLOBBER_LOADORDERGROUP
&& ServiceConfig
->lpLoadOrderGroup
) ? NULL
: LoadOrderGroup
,
1249 useTag
? &tagId
: NULL
,
1250 (flags
& SPSVCINST_NOCLOBBER_DEPENDENCIES
&& ServiceConfig
->lpDependencies
) ? NULL
: Dependencies
,
1252 (flags
& SPSVCINST_NOCLOBBER_DISPLAYNAME
&& ServiceConfig
->lpDisplayName
) ? NULL
: DisplayName
);
1257 /* FIXME: use Description and SPSVCINST_NOCLOBBER_DESCRIPTION */
1261 /* Add the tag to SYSTEM\CurrentControlSet\Control\GroupOrderList key */
1263 LPCWSTR lpLoadOrderGroup
;
1266 lpLoadOrderGroup
= LoadOrderGroup
;
1267 if ((flags
& SPSVCINST_NOCLOBBER_LOADORDERGROUP
) && ServiceConfig
&& ServiceConfig
->lpLoadOrderGroup
)
1268 lpLoadOrderGroup
= ServiceConfig
->lpLoadOrderGroup
;
1270 rc
= RegOpenKey(list
->HKLM
, L
"SYSTEM\\CurrentControlSet\\Control\\GroupOrderList", &hGroupOrderListKey
);
1271 if (rc
!= ERROR_SUCCESS
)
1276 rc
= RegQueryValueExW(hGroupOrderListKey
, lpLoadOrderGroup
, NULL
, &dwRegType
, NULL
, &bufferSize
);
1277 if (rc
== ERROR_FILE_NOT_FOUND
)
1278 bufferSize
= sizeof(DWORD
);
1279 else if (rc
!= ERROR_SUCCESS
)
1284 else if (dwRegType
!= REG_BINARY
|| bufferSize
== 0 || bufferSize
% sizeof(DWORD
) != 0)
1286 SetLastError(ERROR_GEN_FAILURE
);
1289 /* Allocate buffer to store existing data + the new tag */
1290 GroupOrder
= HeapAlloc(GetProcessHeap(), 0, bufferSize
+ sizeof(DWORD
));
1293 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1296 if (rc
== ERROR_SUCCESS
)
1298 /* Read existing data */
1299 rc
= RegQueryValueExW(
1306 if (rc
!= ERROR_SUCCESS
)
1311 if (flags
& SPSVCINST_TAGTOFRONT
)
1312 memmove(&GroupOrder
[2], &GroupOrder
[1], bufferSize
- sizeof(DWORD
));
1319 if (flags
& SPSVCINST_TAGTOFRONT
)
1320 GroupOrder
[1] = tagId
;
1322 GroupOrder
[bufferSize
/ sizeof(DWORD
)] = tagId
;
1324 rc
= RegSetValueExW(
1330 bufferSize
+ sizeof(DWORD
));
1331 if (rc
!= ERROR_SUCCESS
)
1341 if (hSCManager
!= NULL
)
1342 CloseServiceHandle(hSCManager
);
1343 if (hService
!= NULL
)
1344 CloseServiceHandle(hService
);
1345 if (hGroupOrderListKey
!= INVALID_HANDLE_VALUE
)
1346 RegCloseKey(hGroupOrderListKey
);
1347 HeapFree(GetProcessHeap(), 0, ServiceConfig
);
1348 HeapFree(GetProcessHeap(), 0, ServiceBinary
);
1349 HeapFree(GetProcessHeap(), 0, LoadOrderGroup
);
1350 HeapFree(GetProcessHeap(), 0, DisplayName
);
1351 HeapFree(GetProcessHeap(), 0, Description
);
1352 HeapFree(GetProcessHeap(), 0, Dependencies
);
1353 HeapFree(GetProcessHeap(), 0, GroupOrder
);
1356 TRACE("Returning %d\n", ret
);