source: trunk/src/setupapi/install.c@ 22015

Last change on this file since 22015 was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 22.5 KB
Line 
1/*
2 * Setupapi install routines
3 *
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
5 *
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.
10 *
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.
15 *
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
19 */
20
21#include <memory.h>
22
23#include "windef.h"
24#include "winbase.h"
25#include "winternl.h"
26#include "winerror.h"
27#include "setupapi.h"
28#include "wine/unicode.h"
29#include "setupapi_private.h"
30#include "wine/debug.h"
31
32WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
33
34/* info passed to callback functions dealing with files */
35struct files_callback_info
36{
37 HSPFILEQ queue;
38 PCWSTR src_root;
39 UINT copy_flags;
40 HINF layout;
41};
42
43/* info passed to callback functions dealing with the registry */
44struct registry_callback_info
45{
46 HKEY default_root;
47 BOOL delete;
48};
49
50typedef BOOL (*iterate_fields_func)( HINF hinf, PCWSTR field, void *arg );
51
52/* Unicode constants */
53static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0};
54static const WCHAR DelFiles[] = {'D','e','l','F','i','l','e','s',0};
55static const WCHAR RenFiles[] = {'R','e','n','F','i','l','e','s',0};
56static const WCHAR Ini2Reg[] = {'I','n','i','2','R','e','g',0};
57static const WCHAR LogConf[] = {'L','o','g','C','o','n','f',0};
58static const WCHAR AddReg[] = {'A','d','d','R','e','g',0};
59static const WCHAR DelReg[] = {'D','e','l','R','e','g',0};
60static const WCHAR UpdateInis[] = {'U','p','d','a','t','e','I','n','i','s',0};
61static const WCHAR UpdateIniFields[] = {'U','p','d','a','t','e','I','n','i','F','i','e','l','d','s',0};
62
63
64/***********************************************************************
65 * get_field_string
66 *
67 * Retrieve the contents of a field, dynamically growing the buffer if necessary.
68 */
69static WCHAR *get_field_string( INFCONTEXT *context, DWORD index, WCHAR *buffer,
70 WCHAR *static_buffer, DWORD *size )
71{
72 DWORD required;
73
74 if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer;
75 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
76 {
77 /* now grow the buffer */
78 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
79 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required*sizeof(WCHAR) ))) return NULL;
80 *size = required;
81 if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer;
82 }
83 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
84 return NULL;
85}
86
87
88/***********************************************************************
89 * copy_files_callback
90 *
91 * Called once for each CopyFiles entry in a given section.
92 */
93static BOOL copy_files_callback( HINF hinf, PCWSTR field, void *arg )
94{
95 struct files_callback_info *info = arg;
96
97 if (field[0] == '@') /* special case: copy single file */
98 SetupQueueDefaultCopyW( info->queue, info->layout, info->src_root, NULL, field, info->copy_flags );
99 else
100 SetupQueueCopySectionW( info->queue, info->src_root, info->layout, hinf, field, info->copy_flags );
101 return TRUE;
102}
103
104
105/***********************************************************************
106 * delete_files_callback
107 *
108 * Called once for each DelFiles entry in a given section.
109 */
110static BOOL delete_files_callback( HINF hinf, PCWSTR field, void *arg )
111{
112 struct files_callback_info *info = arg;
113 SetupQueueDeleteSectionW( info->queue, hinf, 0, field );
114 return TRUE;
115}
116
117
118/***********************************************************************
119 * rename_files_callback
120 *
121 * Called once for each RenFiles entry in a given section.
122 */
123static BOOL rename_files_callback( HINF hinf, PCWSTR field, void *arg )
124{
125 struct files_callback_info *info = arg;
126 SetupQueueRenameSectionW( info->queue, hinf, 0, field );
127 return TRUE;
128}
129
130
131/***********************************************************************
132 * get_root_key
133 *
134 * Retrieve the registry root key from its name.
135 */
136static HKEY get_root_key( const WCHAR *name, HKEY def_root )
137{
138 static const WCHAR HKCR[] = {'H','K','C','R',0};
139 static const WCHAR HKCU[] = {'H','K','C','U',0};
140 static const WCHAR HKLM[] = {'H','K','L','M',0};
141 static const WCHAR HKU[] = {'H','K','U',0};
142 static const WCHAR HKR[] = {'H','K','R',0};
143
144 if (!strcmpiW( name, HKCR )) return HKEY_CLASSES_ROOT;
145 if (!strcmpiW( name, HKCU )) return HKEY_CURRENT_USER;
146 if (!strcmpiW( name, HKLM )) return HKEY_LOCAL_MACHINE;
147 if (!strcmpiW( name, HKU )) return HKEY_USERS;
148 if (!strcmpiW( name, HKR )) return def_root;
149 return 0;
150}
151
152
153/***********************************************************************
154 * append_multi_sz_value
155 *
156 * Append a multisz string to a multisz registry value.
157 */
158static void append_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *strings,
159 DWORD str_size )
160{
161 DWORD size, type, total;
162 WCHAR *buffer, *p;
163
164 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
165 if (type != REG_MULTI_SZ) return;
166
167 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return;
168 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
169
170 /* compare each string against all the existing ones */
171 total = size;
172 while (*strings)
173 {
174 int len = strlenW(strings) + 1;
175
176 for (p = buffer; *p; p += strlenW(p) + 1)
177 if (!strcmpiW( p, strings )) break;
178
179 if (!*p) /* not found, need to append it */
180 {
181 memcpy( p, strings, len * sizeof(WCHAR) );
182 p[len] = 0;
183 total += len;
184 }
185 strings += len;
186 }
187 if (total != size)
188 {
189 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) );
190 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total );
191 }
192 done:
193 HeapFree( GetProcessHeap(), 0, buffer );
194}
195
196
197/***********************************************************************
198 * delete_multi_sz_value
199 *
200 * Remove a string from a multisz registry value.
201 */
202static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string )
203{
204 DWORD size, type;
205 WCHAR *buffer, *src, *dst;
206
207 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
208 if (type != REG_MULTI_SZ) return;
209 /* allocate double the size, one for value before and one for after */
210 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return;
211 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
212 src = buffer;
213 dst = buffer + size;
214 while (*src)
215 {
216 int len = strlenW(src) + 1;
217 if (strcmpiW( src, string ))
218 {
219 memcpy( dst, src, len * sizeof(WCHAR) );
220 dst += len;
221 }
222 src += len;
223 }
224 *dst++ = 0;
225 if (dst != buffer + 2*size) /* did we remove something? */
226 {
227 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) );
228 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ,
229 (BYTE *)(buffer + size), dst - (buffer + size) );
230 }
231 done:
232 HeapFree( GetProcessHeap(), 0, buffer );
233}
234
235
236/***********************************************************************
237 * do_reg_operation
238 *
239 * Perform an add/delete registry operation depending on the flags.
240 */
241static BOOL do_reg_operation( HKEY hkey, const WCHAR *value, INFCONTEXT *context, INT flags )
242{
243 DWORD type, size;
244
245 if (flags & (FLG_ADDREG_DELREG_BIT | FLG_ADDREG_DELVAL)) /* deletion */
246 {
247 if (*value && !(flags & FLG_DELREG_KEYONLY_COMMON))
248 {
249 if ((flags & FLG_DELREG_MULTI_SZ_DELSTRING) == FLG_DELREG_MULTI_SZ_DELSTRING)
250 {
251 WCHAR *str;
252
253 if (!SetupGetStringFieldW( context, 5, NULL, 0, &size ) || !size) return TRUE;
254 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
255 SetupGetStringFieldW( context, 5, str, size, NULL );
256 delete_multi_sz_value( hkey, value, str );
257 HeapFree( GetProcessHeap(), 0, str );
258 }
259 else RegDeleteValueW( hkey, value );
260 }
261 else RegDeleteKeyW( hkey, NULL );
262 return TRUE;
263 }
264
265 if (flags & (FLG_ADDREG_KEYONLY|FLG_ADDREG_KEYONLY_COMMON)) return TRUE;
266
267 if (flags & (FLG_ADDREG_NOCLOBBER|FLG_ADDREG_OVERWRITEONLY))
268 {
269 BOOL exists = !RegQueryValueExW( hkey, value, NULL, NULL, NULL, NULL );
270 if (exists && (flags & FLG_ADDREG_NOCLOBBER)) return TRUE;
271 if (!exists & (flags & FLG_ADDREG_OVERWRITEONLY)) return TRUE;
272 }
273
274 switch(flags & FLG_ADDREG_TYPE_MASK)
275 {
276 case FLG_ADDREG_TYPE_SZ: type = REG_SZ; break;
277 case FLG_ADDREG_TYPE_MULTI_SZ: type = REG_MULTI_SZ; break;
278 case FLG_ADDREG_TYPE_EXPAND_SZ: type = REG_EXPAND_SZ; break;
279 case FLG_ADDREG_TYPE_BINARY: type = REG_BINARY; break;
280 case FLG_ADDREG_TYPE_DWORD: type = REG_DWORD; break;
281 case FLG_ADDREG_TYPE_NONE: type = REG_NONE; break;
282 default: type = flags >> 16; break;
283 }
284
285 if (!(flags & FLG_ADDREG_BINVALUETYPE) ||
286 (type == REG_DWORD && SetupGetFieldCount(context) == 5))
287 {
288 static const WCHAR empty;
289 WCHAR *str = NULL;
290
291 if (type == REG_MULTI_SZ)
292 {
293 if (!SetupGetMultiSzFieldW( context, 5, NULL, 0, &size )) size = 0;
294 if (size)
295 {
296 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
297 SetupGetMultiSzFieldW( context, 5, str, size, NULL );
298 }
299 if (flags & FLG_ADDREG_APPEND)
300 {
301 if (!str) return TRUE;
302 append_multi_sz_value( hkey, value, str, size );
303 HeapFree( GetProcessHeap(), 0, str );
304 return TRUE;
305 }
306 /* else fall through to normal string handling */
307 }
308 else
309 {
310 if (!SetupGetStringFieldW( context, 5, NULL, 0, &size )) size = 0;
311 if (size)
312 {
313 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
314 SetupGetStringFieldW( context, 5, str, size, NULL );
315 }
316 }
317
318 if (type == REG_DWORD)
319 {
320 DWORD dw = str ? strtolW( str, NULL, 16 ) : 0;
321 TRACE( "setting dword %s to %lx\n", debugstr_w(value), dw );
322 RegSetValueExW( hkey, value, 0, type, (BYTE *)&dw, sizeof(dw) );
323 }
324 else
325 {
326 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(str) );
327 if (str) RegSetValueExW( hkey, value, 0, type, (BYTE *)str, size * sizeof(WCHAR) );
328 else RegSetValueExW( hkey, value, 0, type, (BYTE *)&empty, sizeof(WCHAR) );
329 }
330 HeapFree( GetProcessHeap(), 0, str );
331 return TRUE;
332 }
333 else /* get the binary data */
334 {
335 BYTE *data = NULL;
336
337 if (!SetupGetBinaryField( context, 5, NULL, 0, &size )) size = 0;
338 if (size)
339 {
340 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
341 TRACE( "setting binary data %s len %ld\n", debugstr_w(value), size );
342 SetupGetBinaryField( context, 5, data, size, NULL );
343 }
344 RegSetValueExW( hkey, value, 0, type, data, size );
345 HeapFree( GetProcessHeap(), 0, data );
346 return TRUE;
347 }
348}
349
350
351/***********************************************************************
352 * registry_callback
353 *
354 * Called once for each AddReg and DelReg entry in a given section.
355 */
356static BOOL registry_callback( HINF hinf, PCWSTR field, void *arg )
357{
358 struct registry_callback_info *info = arg;
359 INFCONTEXT context;
360 HKEY root_key, hkey;
361
362 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
363
364 for (; ok; ok = SetupFindNextLine( &context, &context ))
365 {
366 WCHAR buffer[MAX_INF_STRING_LENGTH];
367 INT flags;
368
369 /* get root */
370 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
371 continue;
372 if (!(root_key = get_root_key( buffer, info->default_root )))
373 continue;
374
375 /* get key */
376 if (!SetupGetStringFieldW( &context, 2, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
377 *buffer = 0;
378
379 /* get flags */
380 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
381
382 if (!info->delete)
383 {
384 if (flags & FLG_ADDREG_DELREG_BIT) continue; /* ignore this entry */
385 }
386 else
387 {
388 if (!flags) flags = FLG_ADDREG_DELREG_BIT;
389 else if (!(flags & FLG_ADDREG_DELREG_BIT)) continue; /* ignore this entry */
390 }
391
392 if (info->delete || (flags & FLG_ADDREG_OVERWRITEONLY))
393 {
394 if (RegOpenKeyW( root_key, buffer, &hkey )) continue; /* ignore if it doesn't exist */
395 }
396 else if (RegCreateKeyW( root_key, buffer, &hkey ))
397 {
398 ERR( "could not create key %p %s\n", root_key, debugstr_w(buffer) );
399 continue;
400 }
401 TRACE( "key %p %s\n", root_key, debugstr_w(buffer) );
402
403 /* get value name */
404 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
405 *buffer = 0;
406
407 /* and now do it */
408 if (!do_reg_operation( hkey, buffer, &context, flags ))
409 {
410 RegCloseKey( hkey );
411 return FALSE;
412 }
413 RegCloseKey( hkey );
414 }
415 return TRUE;
416}
417
418
419static BOOL update_ini_callback( HINF hinf, PCWSTR field, void *arg )
420{
421 INFCONTEXT context;
422
423 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
424
425 for (; ok; ok = SetupFindNextLine( &context, &context ))
426 {
427 WCHAR buffer[MAX_INF_STRING_LENGTH];
428 WCHAR filename[MAX_INF_STRING_LENGTH];
429 WCHAR section[MAX_INF_STRING_LENGTH];
430 WCHAR entry[MAX_INF_STRING_LENGTH];
431 WCHAR string[MAX_INF_STRING_LENGTH];
432 LPWSTR divider;
433
434 if (!SetupGetStringFieldW( &context, 1, filename,
435 sizeof(filename)/sizeof(WCHAR), NULL ))
436 continue;
437
438 if (!SetupGetStringFieldW( &context, 2, section,
439 sizeof(section)/sizeof(WCHAR), NULL ))
440 continue;
441
442 if (!SetupGetStringFieldW( &context, 4, buffer,
443 sizeof(buffer)/sizeof(WCHAR), NULL ))
444 continue;
445
446 divider = strchrW(buffer,'=');
447 if (divider)
448 {
449 *divider = 0;
450 strcpyW(entry,buffer);
451 divider++;
452 strcpyW(string,divider);
453 }
454 else
455 {
456 strcpyW(entry,buffer);
457 string[0]=0;
458 }
459
460 TRACE("Writing %s = %s in %s of file %s\n",debugstr_w(entry),
461 debugstr_w(string),debugstr_w(section),debugstr_w(filename));
462 WritePrivateProfileStringW(section,entry,string,filename);
463
464 }
465 return TRUE;
466}
467
468static BOOL update_ini_fields_callback( HINF hinf, PCWSTR field, void *arg )
469{
470 FIXME( "should update ini fields %s\n", debugstr_w(field) );
471 return TRUE;
472}
473
474static BOOL ini2reg_callback( HINF hinf, PCWSTR field, void *arg )
475{
476 FIXME( "should do ini2reg %s\n", debugstr_w(field) );
477 return TRUE;
478}
479
480static BOOL logconf_callback( HINF hinf, PCWSTR field, void *arg )
481{
482 FIXME( "should do logconf %s\n", debugstr_w(field) );
483 return TRUE;
484}
485
486
487/***********************************************************************
488 * iterate_section_fields
489 *
490 * Iterate over all fields of a certain key of a certain section
491 */
492static BOOL iterate_section_fields( HINF hinf, PCWSTR section, PCWSTR key,
493 iterate_fields_func callback, void *arg )
494{
495 WCHAR static_buffer[200];
496 WCHAR *buffer = static_buffer;
497 DWORD size = sizeof(static_buffer)/sizeof(WCHAR);
498 INFCONTEXT context;
499 BOOL ret = FALSE;
500
501 BOOL ok = SetupFindFirstLineW( hinf, section, key, &context );
502 while (ok)
503 {
504 UINT i, count = SetupGetFieldCount( &context );
505 for (i = 1; i <= count; i++)
506 {
507 if (!(buffer = get_field_string( &context, i, buffer, static_buffer, &size )))
508 goto done;
509 if (!callback( hinf, buffer, arg ))
510 {
511 ERR("callback failed for %s %s\n", debugstr_w(section), debugstr_w(buffer) );
512 goto done;
513 }
514 }
515 ok = SetupFindNextMatchLineW( &context, key, &context );
516 }
517 ret = TRUE;
518 done:
519 if (buffer && buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
520 return ret;
521}
522
523
524/***********************************************************************
525 * SetupInstallFilesFromInfSectionA (SETUPAPI.@)
526 */
527BOOL WINAPI SetupInstallFilesFromInfSectionA( HINF hinf, HINF hlayout, HSPFILEQ queue,
528 PCSTR section, PCSTR src_root, UINT flags )
529{
530 UNICODE_STRING sectionW;
531 BOOL ret = FALSE;
532
533 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
534 {
535 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
536 return FALSE;
537 }
538 if (!src_root)
539 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
540 NULL, flags );
541 else
542 {
543 UNICODE_STRING srcW;
544 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
545 {
546 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
547 srcW.Buffer, flags );
548 RtlFreeUnicodeString( &srcW );
549 }
550 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
551 }
552 RtlFreeUnicodeString( &sectionW );
553 return ret;
554}
555
556
557/***********************************************************************
558 * SetupInstallFilesFromInfSectionW (SETUPAPI.@)
559 */
560BOOL WINAPI SetupInstallFilesFromInfSectionW( HINF hinf, HINF hlayout, HSPFILEQ queue,
561 PCWSTR section, PCWSTR src_root, UINT flags )
562{
563 struct files_callback_info info;
564
565 info.queue = queue;
566 info.src_root = src_root;
567 info.copy_flags = flags;
568 info.layout = hlayout;
569 return iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info );
570}
571
572
573/***********************************************************************
574 * SetupInstallFromInfSectionA (SETUPAPI.@)
575 */
576BOOL WINAPI SetupInstallFromInfSectionA( HWND owner, HINF hinf, PCSTR section, UINT flags,
577 HKEY key_root, PCSTR src_root, UINT copy_flags,
578 PSP_FILE_CALLBACK_A callback, PVOID context,
579 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
580{
581 UNICODE_STRING sectionW, src_rootW;
582 struct callback_WtoA_context ctx;
583 BOOL ret = FALSE;
584
585 src_rootW.Buffer = NULL;
586 if (src_root && !RtlCreateUnicodeStringFromAsciiz( &src_rootW, src_root ))
587 {
588 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
589 return FALSE;
590 }
591
592 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
593 {
594 ctx.orig_context = context;
595 ctx.orig_handler = callback;
596 ret = SetupInstallFromInfSectionW( owner, hinf, sectionW.Buffer, flags, key_root,
597 src_rootW.Buffer, copy_flags, QUEUE_callback_WtoA,
598 &ctx, devinfo, devinfo_data );
599 RtlFreeUnicodeString( &sectionW );
600 }
601 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
602
603 RtlFreeUnicodeString( &src_rootW );
604 return ret;
605}
606
607
608/***********************************************************************
609 * SetupInstallFromInfSectionW (SETUPAPI.@)
610 */
611BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section, UINT flags,
612 HKEY key_root, PCWSTR src_root, UINT copy_flags,
613 PSP_FILE_CALLBACK_W callback, PVOID context,
614 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
615{
616 if (flags & SPINST_FILES)
617 {
618 struct files_callback_info info;
619 HSPFILEQ queue;
620 BOOL ret;
621
622 if (!(queue = SetupOpenFileQueue())) return FALSE;
623 info.queue = queue;
624 info.src_root = src_root;
625 info.copy_flags = copy_flags;
626 info.layout = hinf;
627 ret = (iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ) &&
628 iterate_section_fields( hinf, section, DelFiles, delete_files_callback, &info ) &&
629 iterate_section_fields( hinf, section, RenFiles, rename_files_callback, &info ) &&
630 SetupCommitFileQueueW( owner, queue, callback, context ));
631 SetupCloseFileQueue( queue );
632 if (!ret) return FALSE;
633 }
634 if (flags & SPINST_INIFILES)
635 {
636 if (!iterate_section_fields( hinf, section, UpdateInis, update_ini_callback, NULL ) ||
637 !iterate_section_fields( hinf, section, UpdateIniFields,
638 update_ini_fields_callback, NULL ))
639 return FALSE;
640 }
641 if (flags & SPINST_INI2REG)
642 {
643 if (!iterate_section_fields( hinf, section, Ini2Reg, ini2reg_callback, NULL ))
644 return FALSE;
645 }
646
647 if (flags & SPINST_LOGCONFIG)
648 {
649 if (!iterate_section_fields( hinf, section, LogConf, logconf_callback, NULL ))
650 return FALSE;
651 }
652
653 if (flags & SPINST_REGISTRY)
654 {
655 struct registry_callback_info info;
656
657 info.default_root = key_root;
658 info.delete = TRUE;
659 if (!iterate_section_fields( hinf, section, DelReg, registry_callback, &info ))
660 return FALSE;
661 info.delete = FALSE;
662 if (!iterate_section_fields( hinf, section, AddReg, registry_callback, &info ))
663 return FALSE;
664 }
665 if (flags & (SPINST_BITREG|SPINST_REGSVR|SPINST_UNREGSVR|SPINST_PROFILEITEMS|SPINST_COPYINF))
666 FIXME( "unsupported flags %x\n", flags );
667 return TRUE;
668}
Note: See TracBrowser for help on using the repository browser.