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