2 * Setupapi install routines
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "setupapi_private.h"
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
38 /* info passed to callback functions dealing with files */
39 struct files_callback_info
47 /* info passed to callback functions dealing with the registry */
48 struct registry_callback_info
54 /* info passed to callback functions dealing with registering dlls */
55 struct register_dll_info
57 PSP_FILE_CALLBACK_W callback;
58 PVOID callback_context;
62 typedef BOOL (*iterate_fields_func)( HINF hinf, PCWSTR field, void *arg );
64 /* Unicode constants */
65 static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0};
66 static const WCHAR DelFiles[] = {'D','e','l','F','i','l','e','s',0};
67 static const WCHAR RenFiles[] = {'R','e','n','F','i','l','e','s',0};
68 static const WCHAR Ini2Reg[] = {'I','n','i','2','R','e','g',0};
69 static const WCHAR LogConf[] = {'L','o','g','C','o','n','f',0};
70 static const WCHAR AddReg[] = {'A','d','d','R','e','g',0};
71 static const WCHAR DelReg[] = {'D','e','l','R','e','g',0};
72 static const WCHAR BitReg[] = {'B','i','t','R','e','g',0};
73 static const WCHAR UpdateInis[] = {'U','p','d','a','t','e','I','n','i','s',0};
74 static const WCHAR CopyINF[] = {'C','o','p','y','I','N','F',0};
75 static const WCHAR UpdateIniFields[] = {'U','p','d','a','t','e','I','n','i','F','i','e','l','d','s',0};
76 static const WCHAR RegisterDlls[] = {'R','e','g','i','s','t','e','r','D','l','l','s',0};
77 static const WCHAR UnregisterDlls[] = {'U','n','r','e','g','i','s','t','e','r','D','l','l','s',0};
78 static const WCHAR ProfileItems[] = {'P','r','o','f','i','l','e','I','t','e','m','s',0};
81 /***********************************************************************
84 * Retrieve the contents of a field, dynamically growing the buffer if necessary.
86 static WCHAR *get_field_string( INFCONTEXT *context, DWORD index, WCHAR *buffer,
87 WCHAR *static_buffer, DWORD *size )
91 if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer;
92 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
94 /* now grow the buffer */
95 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
96 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required*sizeof(WCHAR) ))) return NULL;
98 if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer;
100 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
105 /***********************************************************************
106 * copy_files_callback
108 * Called once for each CopyFiles entry in a given section.
110 static BOOL copy_files_callback( HINF hinf, PCWSTR field, void *arg )
112 struct files_callback_info *info = arg;
114 if (field[0] == '@') /* special case: copy single file */
115 SetupQueueDefaultCopyW( info->queue, info->layout, info->src_root, NULL, field, info->copy_flags );
117 SetupQueueCopySectionW( info->queue, info->src_root, info->layout, hinf, field, info->copy_flags );
122 /***********************************************************************
123 * delete_files_callback
125 * Called once for each DelFiles entry in a given section.
127 static BOOL delete_files_callback( HINF hinf, PCWSTR field, void *arg )
129 struct files_callback_info *info = arg;
130 SetupQueueDeleteSectionW( info->queue, hinf, 0, field );
135 /***********************************************************************
136 * rename_files_callback
138 * Called once for each RenFiles entry in a given section.
140 static BOOL rename_files_callback( HINF hinf, PCWSTR field, void *arg )
142 struct files_callback_info *info = arg;
143 SetupQueueRenameSectionW( info->queue, hinf, 0, field );
148 /***********************************************************************
151 * Retrieve the registry root key from its name.
153 static HKEY get_root_key( const WCHAR *name, HKEY def_root )
155 static const WCHAR HKCR[] = {'H','K','C','R',0};
156 static const WCHAR HKCU[] = {'H','K','C','U',0};
157 static const WCHAR HKLM[] = {'H','K','L','M',0};
158 static const WCHAR HKU[] = {'H','K','U',0};
159 static const WCHAR HKR[] = {'H','K','R',0};
161 if (!strcmpiW( name, HKCR )) return HKEY_CLASSES_ROOT;
162 if (!strcmpiW( name, HKCU )) return HKEY_CURRENT_USER;
163 if (!strcmpiW( name, HKLM )) return HKEY_LOCAL_MACHINE;
164 if (!strcmpiW( name, HKU )) return HKEY_USERS;
165 if (!strcmpiW( name, HKR )) return def_root;
170 /***********************************************************************
171 * append_multi_sz_value
173 * Append a multisz string to a multisz registry value.
175 static void append_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *strings,
178 DWORD size, type, total;
181 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
182 if (type != REG_MULTI_SZ) return;
184 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return;
185 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
187 /* compare each string against all the existing ones */
191 int len = strlenW(strings) + 1;
193 for (p = buffer; *p; p += strlenW(p) + 1)
194 if (!strcmpiW( p, strings )) break;
196 if (!*p) /* not found, need to append it */
198 memcpy( p, strings, len * sizeof(WCHAR) );
206 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) );
207 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total );
210 HeapFree( GetProcessHeap(), 0, buffer );
214 /***********************************************************************
215 * delete_multi_sz_value
217 * Remove a string from a multisz registry value.
219 static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string )
222 WCHAR *buffer, *src, *dst;
224 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
225 if (type != REG_MULTI_SZ) return;
226 /* allocate double the size, one for value before and one for after */
227 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return;
228 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
233 int len = strlenW(src) + 1;
234 if (strcmpiW( src, string ))
236 memcpy( dst, src, len * sizeof(WCHAR) );
242 if (dst != buffer + 2*size) /* did we remove something? */
244 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) );
245 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ,
246 (BYTE *)(buffer + size), dst - (buffer + size) );
249 HeapFree( GetProcessHeap(), 0, buffer );
253 /***********************************************************************
256 * Perform an add/delete registry operation depending on the flags.
258 static BOOL do_reg_operation( HKEY hkey, const WCHAR *value, INFCONTEXT *context, INT flags )
262 if (flags & (FLG_ADDREG_DELREG_BIT | FLG_ADDREG_DELVAL)) /* deletion */
264 if (*value && !(flags & FLG_DELREG_KEYONLY_COMMON))
266 if ((flags & FLG_DELREG_MULTI_SZ_DELSTRING) == FLG_DELREG_MULTI_SZ_DELSTRING)
270 if (!SetupGetStringFieldW( context, 5, NULL, 0, &size ) || !size) return TRUE;
271 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
272 SetupGetStringFieldW( context, 5, str, size, NULL );
273 delete_multi_sz_value( hkey, value, str );
274 HeapFree( GetProcessHeap(), 0, str );
276 else RegDeleteValueW( hkey, value );
278 else RegDeleteKeyW( hkey, NULL );
282 if (flags & (FLG_ADDREG_KEYONLY|FLG_ADDREG_KEYONLY_COMMON)) return TRUE;
284 if (flags & (FLG_ADDREG_NOCLOBBER|FLG_ADDREG_OVERWRITEONLY))
286 BOOL exists = !RegQueryValueExW( hkey, value, NULL, NULL, NULL, NULL );
287 if (exists && (flags & FLG_ADDREG_NOCLOBBER)) return TRUE;
288 if (!exists & (flags & FLG_ADDREG_OVERWRITEONLY)) return TRUE;
291 switch(flags & FLG_ADDREG_TYPE_MASK)
293 case FLG_ADDREG_TYPE_SZ: type = REG_SZ; break;
294 case FLG_ADDREG_TYPE_MULTI_SZ: type = REG_MULTI_SZ; break;
295 case FLG_ADDREG_TYPE_EXPAND_SZ: type = REG_EXPAND_SZ; break;
296 case FLG_ADDREG_TYPE_BINARY: type = REG_BINARY; break;
297 case FLG_ADDREG_TYPE_DWORD: type = REG_DWORD; break;
298 case FLG_ADDREG_TYPE_NONE: type = REG_NONE; break;
299 default: type = flags >> 16; break;
302 if (!(flags & FLG_ADDREG_BINVALUETYPE) ||
303 (type == REG_DWORD && SetupGetFieldCount(context) == 5))
305 static const WCHAR empty;
308 if (type == REG_MULTI_SZ)
310 if (!SetupGetMultiSzFieldW( context, 5, NULL, 0, &size )) size = 0;
313 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
314 SetupGetMultiSzFieldW( context, 5, str, size, NULL );
316 if (flags & FLG_ADDREG_APPEND)
318 if (!str) return TRUE;
319 append_multi_sz_value( hkey, value, str, size );
320 HeapFree( GetProcessHeap(), 0, str );
323 /* else fall through to normal string handling */
327 if (!SetupGetStringFieldW( context, 5, NULL, 0, &size )) size = 0;
330 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
331 SetupGetStringFieldW( context, 5, str, size, NULL );
335 if (type == REG_DWORD)
337 DWORD dw = str ? strtoulW( str, NULL, 16 ) : 0;
338 TRACE( "setting dword %s to %lx\n", debugstr_w(value), dw );
339 RegSetValueExW( hkey, value, 0, type, (BYTE *)&dw, sizeof(dw) );
343 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(str) );
344 if (str) RegSetValueExW( hkey, value, 0, type, (BYTE *)str, size * sizeof(WCHAR) );
345 else RegSetValueExW( hkey, value, 0, type, (const BYTE *)&empty, sizeof(WCHAR) );
347 HeapFree( GetProcessHeap(), 0, str );
350 else /* get the binary data */
354 if (!SetupGetBinaryField( context, 5, NULL, 0, &size )) size = 0;
357 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
358 TRACE( "setting binary data %s len %ld\n", debugstr_w(value), size );
359 SetupGetBinaryField( context, 5, data, size, NULL );
361 RegSetValueExW( hkey, value, 0, type, data, size );
362 HeapFree( GetProcessHeap(), 0, data );
368 /***********************************************************************
371 * Called once for each AddReg and DelReg entry in a given section.
373 static BOOL registry_callback( HINF hinf, PCWSTR field, void *arg )
375 struct registry_callback_info *info = arg;
379 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
381 for (; ok; ok = SetupFindNextLine( &context, &context ))
383 WCHAR buffer[MAX_INF_STRING_LENGTH];
387 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
389 if (!(root_key = get_root_key( buffer, info->default_root )))
393 if (!SetupGetStringFieldW( &context, 2, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
397 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
401 if (flags & FLG_ADDREG_DELREG_BIT) continue; /* ignore this entry */
405 if (!flags) flags = FLG_ADDREG_DELREG_BIT;
406 else if (!(flags & FLG_ADDREG_DELREG_BIT)) continue; /* ignore this entry */
409 if (info->delete || (flags & FLG_ADDREG_OVERWRITEONLY))
411 if (RegOpenKeyW( root_key, buffer, &hkey )) continue; /* ignore if it doesn't exist */
413 else if (RegCreateKeyW( root_key, buffer, &hkey ))
415 ERR( "could not create key %p %s\n", root_key, debugstr_w(buffer) );
418 TRACE( "key %p %s\n", root_key, debugstr_w(buffer) );
421 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
425 if (!do_reg_operation( hkey, buffer, &context, flags ))
436 /***********************************************************************
439 * Register or unregister a dll.
441 static BOOL do_register_dll( const struct register_dll_info *info, const WCHAR *path,
442 INT flags, INT timeout, const WCHAR *args )
446 SP_REGISTER_CONTROL_STATUSW status;
448 status.cbSize = sizeof(status);
449 status.FileName = path;
450 status.FailureCode = SPREG_SUCCESS;
451 status.Win32Error = ERROR_SUCCESS;
455 switch(info->callback( info->callback_context, SPFILENOTIFY_STARTREGISTRATION,
456 (UINT_PTR)&status, !info->unregister ))
459 SetLastError( ERROR_OPERATION_ABORTED );
468 if (!(module = LoadLibraryExW( path, 0, LOAD_WITH_ALTERED_SEARCH_PATH )))
470 WARN( "could not load %s\n", debugstr_w(path) );
471 status.FailureCode = SPREG_LOADLIBRARY;
472 status.Win32Error = GetLastError();
476 if (flags & FLG_REGSVR_DLLREGISTER)
478 const char *entry_point = info->unregister ? "DllUnregisterServer" : "DllRegisterServer";
479 HRESULT (WINAPI *func)(void) = (void *)GetProcAddress( module, entry_point );
483 status.FailureCode = SPREG_GETPROCADDR;
484 status.Win32Error = GetLastError();
488 TRACE( "calling %s in %s\n", entry_point, debugstr_w(path) );
493 WARN( "calling %s in %s returned error %lx\n", entry_point, debugstr_w(path), res );
494 status.FailureCode = SPREG_REGSVR;
495 status.Win32Error = res;
500 if (flags & FLG_REGSVR_DLLINSTALL)
502 HRESULT (WINAPI *func)(BOOL,LPCWSTR) = (void *)GetProcAddress( module, "DllInstall" );
506 status.FailureCode = SPREG_GETPROCADDR;
507 status.Win32Error = GetLastError();
511 TRACE( "calling DllInstall(%d,%s) in %s\n",
512 !info->unregister, debugstr_w(args), debugstr_w(path) );
513 res = func( !info->unregister, args );
517 WARN( "calling DllInstall in %s returned error %lx\n", debugstr_w(path), res );
518 status.FailureCode = SPREG_REGSVR;
519 status.Win32Error = res;
525 if (module) FreeLibrary( module );
526 if (info->callback) info->callback( info->callback_context, SPFILENOTIFY_ENDREGISTRATION,
527 (UINT_PTR)&status, !info->unregister );
532 /***********************************************************************
533 * register_dlls_callback
535 * Called once for each RegisterDlls entry in a given section.
537 static BOOL register_dlls_callback( HINF hinf, PCWSTR field, void *arg )
539 struct register_dll_info *info = arg;
542 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
544 for (; ok; ok = SetupFindNextLine( &context, &context ))
546 WCHAR *path, *args, *p;
547 WCHAR buffer[MAX_INF_STRING_LENGTH];
551 if (!(path = PARSER_get_dest_dir( &context ))) continue;
554 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
556 if (!(p = HeapReAlloc( GetProcessHeap(), 0, path,
557 (strlenW(path) + strlenW(buffer) + 2) * sizeof(WCHAR) ))) goto done;
560 if (p == path || p[-1] != '\\') *p++ = '\\';
561 strcpyW( p, buffer );
564 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
567 if (!SetupGetIntField( &context, 5, &timeout )) timeout = 60;
569 /* get command line */
571 if (SetupGetStringFieldW( &context, 6, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
574 ret = do_register_dll( info, path, flags, timeout, args );
577 HeapFree( GetProcessHeap(), 0, path );
583 /***********************************************************************
584 * update_ini_callback
586 * Called once for each UpdateInis entry in a given section.
588 static BOOL update_ini_callback( HINF hinf, PCWSTR field, void *arg )
592 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
594 for (; ok; ok = SetupFindNextLine( &context, &context ))
596 WCHAR buffer[MAX_INF_STRING_LENGTH];
597 WCHAR filename[MAX_INF_STRING_LENGTH];
598 WCHAR section[MAX_INF_STRING_LENGTH];
599 WCHAR entry[MAX_INF_STRING_LENGTH];
600 WCHAR string[MAX_INF_STRING_LENGTH];
603 if (!SetupGetStringFieldW( &context, 1, filename,
604 sizeof(filename)/sizeof(WCHAR), NULL ))
607 if (!SetupGetStringFieldW( &context, 2, section,
608 sizeof(section)/sizeof(WCHAR), NULL ))
611 if (!SetupGetStringFieldW( &context, 4, buffer,
612 sizeof(buffer)/sizeof(WCHAR), NULL ))
615 divider = strchrW(buffer,'=');
619 strcpyW(entry,buffer);
621 strcpyW(string,divider);
625 strcpyW(entry,buffer);
629 TRACE("Writing %s = %s in %s of file %s\n",debugstr_w(entry),
630 debugstr_w(string),debugstr_w(section),debugstr_w(filename));
631 WritePrivateProfileStringW(section,entry,string,filename);
637 static BOOL update_ini_fields_callback( HINF hinf, PCWSTR field, void *arg )
639 FIXME( "should update ini fields %s\n", debugstr_w(field) );
643 static BOOL ini2reg_callback( HINF hinf, PCWSTR field, void *arg )
645 FIXME( "should do ini2reg %s\n", debugstr_w(field) );
649 static BOOL logconf_callback( HINF hinf, PCWSTR field, void *arg )
651 FIXME( "should do logconf %s\n", debugstr_w(field) );
655 static BOOL bitreg_callback( HINF hinf, PCWSTR field, void *arg )
657 FIXME( "should do bitreg %s\n", debugstr_w(field) );
661 static BOOL profile_items_callback( HINF hinf, PCWSTR field, void *arg )
663 FIXME( "should do profile items %s\n", debugstr_w(field) );
667 static BOOL copy_inf_callback( HINF hinf, PCWSTR field, void *arg )
669 FIXME( "should do copy inf %s\n", debugstr_w(field) );
674 /***********************************************************************
675 * iterate_section_fields
677 * Iterate over all fields of a certain key of a certain section
679 static BOOL iterate_section_fields( HINF hinf, PCWSTR section, PCWSTR key,
680 iterate_fields_func callback, void *arg )
682 WCHAR static_buffer[200];
683 WCHAR *buffer = static_buffer;
684 DWORD size = sizeof(static_buffer)/sizeof(WCHAR);
688 BOOL ok = SetupFindFirstLineW( hinf, section, key, &context );
691 UINT i, count = SetupGetFieldCount( &context );
692 for (i = 1; i <= count; i++)
694 if (!(buffer = get_field_string( &context, i, buffer, static_buffer, &size )))
696 if (!callback( hinf, buffer, arg ))
698 WARN("callback failed for %s %s err %ld\n",
699 debugstr_w(section), debugstr_w(buffer), GetLastError() );
703 ok = SetupFindNextMatchLineW( &context, key, &context );
707 if (buffer && buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
712 /***********************************************************************
713 * SetupInstallFilesFromInfSectionA (SETUPAPI.@)
715 BOOL WINAPI SetupInstallFilesFromInfSectionA( HINF hinf, HINF hlayout, HSPFILEQ queue,
716 PCSTR section, PCSTR src_root, UINT flags )
718 UNICODE_STRING sectionW;
721 if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section ))
723 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
727 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
732 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
734 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
735 srcW.Buffer, flags );
736 RtlFreeUnicodeString( &srcW );
738 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
740 RtlFreeUnicodeString( §ionW );
745 /***********************************************************************
746 * SetupInstallFilesFromInfSectionW (SETUPAPI.@)
748 BOOL WINAPI SetupInstallFilesFromInfSectionW( HINF hinf, HINF hlayout, HSPFILEQ queue,
749 PCWSTR section, PCWSTR src_root, UINT flags )
751 struct files_callback_info info;
754 info.src_root = src_root;
755 info.copy_flags = flags;
756 info.layout = hlayout;
757 return iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info );
761 /***********************************************************************
762 * SetupInstallFromInfSectionA (SETUPAPI.@)
764 BOOL WINAPI SetupInstallFromInfSectionA( HWND owner, HINF hinf, PCSTR section, UINT flags,
765 HKEY key_root, PCSTR src_root, UINT copy_flags,
766 PSP_FILE_CALLBACK_A callback, PVOID context,
767 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
769 UNICODE_STRING sectionW, src_rootW;
770 struct callback_WtoA_context ctx;
773 src_rootW.Buffer = NULL;
774 if (src_root && !RtlCreateUnicodeStringFromAsciiz( &src_rootW, src_root ))
776 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
780 if (RtlCreateUnicodeStringFromAsciiz( §ionW, section ))
782 ctx.orig_context = context;
783 ctx.orig_handler = callback;
784 ret = SetupInstallFromInfSectionW( owner, hinf, sectionW.Buffer, flags, key_root,
785 src_rootW.Buffer, copy_flags, QUEUE_callback_WtoA,
786 &ctx, devinfo, devinfo_data );
787 RtlFreeUnicodeString( §ionW );
789 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
791 RtlFreeUnicodeString( &src_rootW );
796 /***********************************************************************
797 * SetupInstallFromInfSectionW (SETUPAPI.@)
799 BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section, UINT flags,
800 HKEY key_root, PCWSTR src_root, UINT copy_flags,
801 PSP_FILE_CALLBACK_W callback, PVOID context,
802 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
804 if (flags & SPINST_FILES)
806 struct files_callback_info info;
810 if (!(queue = SetupOpenFileQueue())) return FALSE;
812 info.src_root = src_root;
813 info.copy_flags = copy_flags;
815 ret = (iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ) &&
816 iterate_section_fields( hinf, section, DelFiles, delete_files_callback, &info ) &&
817 iterate_section_fields( hinf, section, RenFiles, rename_files_callback, &info ) &&
818 SetupCommitFileQueueW( owner, queue, callback, context ));
819 SetupCloseFileQueue( queue );
820 if (!ret) return FALSE;
822 if (flags & SPINST_INIFILES)
824 if (!iterate_section_fields( hinf, section, UpdateInis, update_ini_callback, NULL ) ||
825 !iterate_section_fields( hinf, section, UpdateIniFields,
826 update_ini_fields_callback, NULL ))
829 if (flags & SPINST_INI2REG)
831 if (!iterate_section_fields( hinf, section, Ini2Reg, ini2reg_callback, NULL ))
834 if (flags & SPINST_LOGCONFIG)
836 if (!iterate_section_fields( hinf, section, LogConf, logconf_callback, NULL ))
839 if (flags & SPINST_REGSVR)
841 struct register_dll_info info;
843 info.unregister = FALSE;
844 if (flags & SPINST_REGISTERCALLBACKAWARE)
846 info.callback = callback;
847 info.callback_context = context;
849 else info.callback = NULL;
851 if (!iterate_section_fields( hinf, section, RegisterDlls, register_dlls_callback, &info ))
854 if (flags & SPINST_UNREGSVR)
856 struct register_dll_info info;
858 info.unregister = TRUE;
859 if (flags & SPINST_REGISTERCALLBACKAWARE)
861 info.callback = callback;
862 info.callback_context = context;
864 else info.callback = NULL;
866 if (!iterate_section_fields( hinf, section, UnregisterDlls, register_dlls_callback, &info ))
869 if (flags & SPINST_REGISTRY)
871 struct registry_callback_info info;
873 info.default_root = key_root;
875 if (!iterate_section_fields( hinf, section, DelReg, registry_callback, &info ))
878 if (!iterate_section_fields( hinf, section, AddReg, registry_callback, &info ))
881 if (flags & SPINST_BITREG)
883 if (!iterate_section_fields( hinf, section, BitReg, bitreg_callback, NULL ))
886 if (flags & SPINST_PROFILEITEMS)
888 if (!iterate_section_fields( hinf, section, ProfileItems, profile_items_callback, NULL ))
891 if (flags & SPINST_COPYINF)
893 if (!iterate_section_fields( hinf, section, CopyINF, copy_inf_callback, NULL ))
901 /***********************************************************************
902 * InstallHinfSectionW (SETUPAPI.@)
904 * NOTE: 'cmdline' is <section> <mode> <path> from
905 * RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection <section> <mode> <path>
907 void WINAPI InstallHinfSectionW( HWND hwnd, HINSTANCE handle, LPCWSTR cmdline, INT show )
909 WCHAR *p, *path, section[MAX_PATH];
910 void *callback_context;
914 TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd, handle, debugstr_w(cmdline));
916 lstrcpynW( section, cmdline, sizeof(section)/sizeof(WCHAR) );
918 if (!(p = strchrW( section, ' ' ))) return;
920 while (*p == ' ') p++;
923 if (!(p = strchrW( p, ' ' ))) return;
925 while (*path == ' ') path++;
927 hinf = SetupOpenInfFileW( path, NULL, INF_STYLE_WIN4, NULL );
928 if (hinf == INVALID_HANDLE_VALUE) return;
930 callback_context = SetupInitDefaultQueueCallback( hwnd );
931 SetupInstallFromInfSectionW( hwnd, hinf, section, SPINST_ALL, NULL, NULL, SP_COPY_NEWER,
932 SetupDefaultQueueCallbackW, callback_context,
934 SetupTermDefaultQueueCallback( callback_context );
935 SetupCloseInfFile( hinf );
937 /* FIXME: should check the mode and maybe reboot */
938 /* there isn't much point in doing that since we */
939 /* don't yet handle deferred file copies anyway. */
943 /***********************************************************************
944 * InstallHinfSectionA (SETUPAPI.@)
946 void WINAPI InstallHinfSectionA( HWND hwnd, HINSTANCE handle, LPCSTR cmdline, INT show )
948 UNICODE_STRING cmdlineW;
950 if (RtlCreateUnicodeStringFromAsciiz( &cmdlineW, cmdline ))
952 InstallHinfSectionW( hwnd, handle, cmdlineW.Buffer, show );
953 RtlFreeUnicodeString( &cmdlineW );