Allow more than one USB controller
[reactos.git] / reactos / lib / setupapi / install.c
1 /*
2 * Setupapi install routines
3 *
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
5 * 2005 Hervé Poussineau (hpoussin@reactos.org)
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #include "setupapi_private.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
25
26 /* info passed to callback functions dealing with files */
27 struct files_callback_info
28 {
29 HSPFILEQ queue;
30 PCWSTR src_root;
31 UINT copy_flags;
32 HINF layout;
33 };
34
35 /* info passed to callback functions dealing with the registry */
36 struct registry_callback_info
37 {
38 HKEY default_root;
39 BOOL delete;
40 };
41
42 /* info passed to callback functions dealing with registering dlls */
43 struct register_dll_info
44 {
45 PSP_FILE_CALLBACK_W callback;
46 PVOID callback_context;
47 BOOL unregister;
48 };
49
50 /* info passed to callback functions dealing with Needs directives */
51 struct needs_callback_info
52 {
53 UINT type;
54
55 HWND owner;
56 UINT flags;
57 HKEY key_root;
58 LPCWSTR src_root;
59 UINT copy_flags;
60 PVOID callback;
61 PVOID context;
62 HDEVINFO devinfo;
63 PSP_DEVINFO_DATA devinfo_data;
64 PVOID reserved1;
65 PVOID reserved2;
66 };
67
68 typedef BOOL (*iterate_fields_func)( HINF hinf, PCWSTR field, void *arg );
69
70 /* Unicode constants */
71 static const WCHAR AddService[] = {'A','d','d','S','e','r','v','i','c','e',0};
72 static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0};
73 static const WCHAR DelFiles[] = {'D','e','l','F','i','l','e','s',0};
74 static const WCHAR RenFiles[] = {'R','e','n','F','i','l','e','s',0};
75 static const WCHAR Ini2Reg[] = {'I','n','i','2','R','e','g',0};
76 static const WCHAR LogConf[] = {'L','o','g','C','o','n','f',0};
77 static const WCHAR AddReg[] = {'A','d','d','R','e','g',0};
78 static const WCHAR DelReg[] = {'D','e','l','R','e','g',0};
79 static const WCHAR BitReg[] = {'B','i','t','R','e','g',0};
80 static const WCHAR UpdateInis[] = {'U','p','d','a','t','e','I','n','i','s',0};
81 static const WCHAR CopyINF[] = {'C','o','p','y','I','N','F',0};
82 static const WCHAR UpdateIniFields[] = {'U','p','d','a','t','e','I','n','i','F','i','e','l','d','s',0};
83 static const WCHAR RegisterDlls[] = {'R','e','g','i','s','t','e','r','D','l','l','s',0};
84 static const WCHAR UnregisterDlls[] = {'U','n','r','e','g','i','s','t','e','r','D','l','l','s',0};
85 static const WCHAR ProfileItems[] = {'P','r','o','f','i','l','e','I','t','e','m','s',0};
86 static const WCHAR Include[] = {'I','n','c','l','u','d','e',0};
87 static const WCHAR Needs[] = {'N','e','e','d','s',0};
88
89
90 /***********************************************************************
91 * get_field_string
92 *
93 * Retrieve the contents of a field, dynamically growing the buffer if necessary.
94 */
95 static WCHAR *get_field_string( INFCONTEXT *context, DWORD index, WCHAR *buffer,
96 WCHAR *static_buffer, DWORD *size )
97 {
98 DWORD required;
99
100 if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer;
101 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
102 {
103 /* now grow the buffer */
104 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
105 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required*sizeof(WCHAR) ))) return NULL;
106 *size = required;
107 if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer;
108 }
109 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
110 return NULL;
111 }
112
113
114 /***********************************************************************
115 * copy_files_callback
116 *
117 * Called once for each CopyFiles entry in a given section.
118 */
119 static BOOL copy_files_callback( HINF hinf, PCWSTR field, void *arg )
120 {
121 struct files_callback_info *info = arg;
122
123 if (field[0] == '@') /* special case: copy single file */
124 SetupQueueDefaultCopyW( info->queue, info->layout, info->src_root, NULL, field, info->copy_flags );
125 else
126 SetupQueueCopySectionW( info->queue, info->src_root, info->layout, hinf, field, info->copy_flags );
127 return TRUE;
128 }
129
130
131 /***********************************************************************
132 * delete_files_callback
133 *
134 * Called once for each DelFiles entry in a given section.
135 */
136 static BOOL delete_files_callback( HINF hinf, PCWSTR field, void *arg )
137 {
138 struct files_callback_info *info = arg;
139 SetupQueueDeleteSectionW( info->queue, hinf, 0, field );
140 return TRUE;
141 }
142
143
144 /***********************************************************************
145 * rename_files_callback
146 *
147 * Called once for each RenFiles entry in a given section.
148 */
149 static BOOL rename_files_callback( HINF hinf, PCWSTR field, void *arg )
150 {
151 struct files_callback_info *info = arg;
152 SetupQueueRenameSectionW( info->queue, hinf, 0, field );
153 return TRUE;
154 }
155
156
157 /***********************************************************************
158 * get_root_key
159 *
160 * Retrieve the registry root key from its name.
161 */
162 static HKEY get_root_key( const WCHAR *name, HKEY def_root )
163 {
164 static const WCHAR HKCR[] = {'H','K','C','R',0};
165 static const WCHAR HKCU[] = {'H','K','C','U',0};
166 static const WCHAR HKLM[] = {'H','K','L','M',0};
167 static const WCHAR HKU[] = {'H','K','U',0};
168 static const WCHAR HKR[] = {'H','K','R',0};
169
170 if (!strcmpiW( name, HKCR )) return HKEY_CLASSES_ROOT;
171 if (!strcmpiW( name, HKCU )) return HKEY_CURRENT_USER;
172 if (!strcmpiW( name, HKLM )) return HKEY_LOCAL_MACHINE;
173 if (!strcmpiW( name, HKU )) return HKEY_USERS;
174 if (!strcmpiW( name, HKR )) return def_root;
175 return 0;
176 }
177
178
179 /***********************************************************************
180 * append_multi_sz_value
181 *
182 * Append a multisz string to a multisz registry value.
183 */
184 static void append_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *strings,
185 DWORD str_size )
186 {
187 DWORD size, type, total;
188 WCHAR *buffer, *p;
189
190 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
191 if (type != REG_MULTI_SZ) return;
192
193 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return;
194 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
195
196 /* compare each string against all the existing ones */
197 total = size;
198 while (*strings)
199 {
200 int len = strlenW(strings) + 1;
201
202 for (p = buffer; *p; p += strlenW(p) + 1)
203 if (!strcmpiW( p, strings )) break;
204
205 if (!*p) /* not found, need to append it */
206 {
207 memcpy( p, strings, len * sizeof(WCHAR) );
208 p[len] = 0;
209 total += len;
210 }
211 strings += len;
212 }
213 if (total != size)
214 {
215 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) );
216 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total );
217 }
218 done:
219 HeapFree( GetProcessHeap(), 0, buffer );
220 }
221
222
223 /***********************************************************************
224 * delete_multi_sz_value
225 *
226 * Remove a string from a multisz registry value.
227 */
228 static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string )
229 {
230 DWORD size, type;
231 WCHAR *buffer, *src, *dst;
232
233 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
234 if (type != REG_MULTI_SZ) return;
235 /* allocate double the size, one for value before and one for after */
236 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return;
237 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
238 src = buffer;
239 dst = buffer + size;
240 while (*src)
241 {
242 int len = strlenW(src) + 1;
243 if (strcmpiW( src, string ))
244 {
245 memcpy( dst, src, len * sizeof(WCHAR) );
246 dst += len;
247 }
248 src += len;
249 }
250 *dst++ = 0;
251 if (dst != buffer + 2*size) /* did we remove something? */
252 {
253 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) );
254 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ,
255 (BYTE *)(buffer + size), dst - (buffer + size) );
256 }
257 done:
258 HeapFree( GetProcessHeap(), 0, buffer );
259 }
260
261
262 /***********************************************************************
263 * do_reg_operation
264 *
265 * Perform an add/delete registry operation depending on the flags.
266 */
267 static BOOL do_reg_operation( HKEY hkey, const WCHAR *value, INFCONTEXT *context, INT flags )
268 {
269 DWORD type, size;
270
271 if (flags & (FLG_ADDREG_DELREG_BIT | FLG_ADDREG_DELVAL)) /* deletion */
272 {
273 if (*value && !(flags & FLG_DELREG_KEYONLY_COMMON))
274 {
275 if ((flags & FLG_DELREG_MULTI_SZ_DELSTRING) == FLG_DELREG_MULTI_SZ_DELSTRING)
276 {
277 WCHAR *str;
278
279 if (!SetupGetStringFieldW( context, 5, NULL, 0, &size ) || !size) return TRUE;
280 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
281 SetupGetStringFieldW( context, 5, str, size, NULL );
282 delete_multi_sz_value( hkey, value, str );
283 HeapFree( GetProcessHeap(), 0, str );
284 }
285 else RegDeleteValueW( hkey, value );
286 }
287 else RegDeleteKeyW( hkey, NULL );
288 return TRUE;
289 }
290
291 if (flags & (FLG_ADDREG_KEYONLY|FLG_ADDREG_KEYONLY_COMMON)) return TRUE;
292
293 if (flags & (FLG_ADDREG_NOCLOBBER|FLG_ADDREG_OVERWRITEONLY))
294 {
295 BOOL exists = !RegQueryValueExW( hkey, value, NULL, NULL, NULL, NULL );
296 if (exists && (flags & FLG_ADDREG_NOCLOBBER)) return TRUE;
297 if (!exists & (flags & FLG_ADDREG_OVERWRITEONLY)) return TRUE;
298 }
299
300 switch(flags & FLG_ADDREG_TYPE_MASK)
301 {
302 case FLG_ADDREG_TYPE_SZ: type = REG_SZ; break;
303 case FLG_ADDREG_TYPE_MULTI_SZ: type = REG_MULTI_SZ; break;
304 case FLG_ADDREG_TYPE_EXPAND_SZ: type = REG_EXPAND_SZ; break;
305 case FLG_ADDREG_TYPE_BINARY: type = REG_BINARY; break;
306 case FLG_ADDREG_TYPE_DWORD: type = REG_DWORD; break;
307 case FLG_ADDREG_TYPE_NONE: type = REG_NONE; break;
308 default: type = flags >> 16; break;
309 }
310
311 if (!(flags & FLG_ADDREG_BINVALUETYPE) ||
312 (type == REG_DWORD && SetupGetFieldCount(context) == 5))
313 {
314 static const WCHAR empty;
315 WCHAR *str = NULL;
316
317 if (type == REG_MULTI_SZ)
318 {
319 if (!SetupGetMultiSzFieldW( context, 5, NULL, 0, &size )) size = 0;
320 if (size)
321 {
322 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
323 SetupGetMultiSzFieldW( context, 5, str, size, NULL );
324 }
325 if (flags & FLG_ADDREG_APPEND)
326 {
327 if (!str) return TRUE;
328 append_multi_sz_value( hkey, value, str, size );
329 HeapFree( GetProcessHeap(), 0, str );
330 return TRUE;
331 }
332 /* else fall through to normal string handling */
333 }
334 else
335 {
336 if (!SetupGetStringFieldW( context, 5, NULL, 0, &size )) size = 0;
337 if (size)
338 {
339 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
340 SetupGetStringFieldW( context, 5, str, size, NULL );
341 }
342 }
343
344 if (type == REG_DWORD)
345 {
346 DWORD dw = str ? strtoulW( str, NULL, 0 ) : 0;
347 TRACE( "setting dword %s to %lx\n", debugstr_w(value), dw );
348 RegSetValueExW( hkey, value, 0, type, (BYTE *)&dw, sizeof(dw) );
349 }
350 else
351 {
352 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(str) );
353 if (str) RegSetValueExW( hkey, value, 0, type, (BYTE *)str, size * sizeof(WCHAR) );
354 else RegSetValueExW( hkey, value, 0, type, (const BYTE *)&empty, sizeof(WCHAR) );
355 }
356 HeapFree( GetProcessHeap(), 0, str );
357 return TRUE;
358 }
359 else /* get the binary data */
360 {
361 BYTE *data = NULL;
362
363 if (!SetupGetBinaryField( context, 5, NULL, 0, &size )) size = 0;
364 if (size)
365 {
366 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
367 TRACE( "setting binary data %s len %ld\n", debugstr_w(value), size );
368 SetupGetBinaryField( context, 5, data, size, NULL );
369 }
370 RegSetValueExW( hkey, value, 0, type, data, size );
371 HeapFree( GetProcessHeap(), 0, data );
372 return TRUE;
373 }
374 }
375
376
377 /***********************************************************************
378 * registry_callback
379 *
380 * Called once for each AddReg and DelReg entry in a given section.
381 */
382 static BOOL registry_callback( HINF hinf, PCWSTR field, void *arg )
383 {
384 struct registry_callback_info *info = arg;
385 INFCONTEXT context;
386 HKEY root_key, hkey;
387
388 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
389
390 for (; ok; ok = SetupFindNextLine( &context, &context ))
391 {
392 WCHAR buffer[MAX_INF_STRING_LENGTH];
393 INT flags;
394
395 /* get root */
396 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
397 continue;
398 if (!(root_key = get_root_key( buffer, info->default_root )))
399 continue;
400
401 /* get key */
402 if (!SetupGetStringFieldW( &context, 2, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
403 *buffer = 0;
404
405 /* get flags */
406 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
407
408 if (!info->delete)
409 {
410 if (flags & FLG_ADDREG_DELREG_BIT) continue; /* ignore this entry */
411 }
412 else
413 {
414 if (!flags) flags = FLG_ADDREG_DELREG_BIT;
415 else if (!(flags & FLG_ADDREG_DELREG_BIT)) continue; /* ignore this entry */
416 }
417
418 if (info->delete || (flags & FLG_ADDREG_OVERWRITEONLY))
419 {
420 if (RegOpenKeyW( root_key, buffer, &hkey )) continue; /* ignore if it doesn't exist */
421 }
422 else if (RegCreateKeyW( root_key, buffer, &hkey ))
423 {
424 ERR( "could not create key %p %s\n", root_key, debugstr_w(buffer) );
425 continue;
426 }
427 TRACE( "key %p %s\n", root_key, debugstr_w(buffer) );
428
429 /* get value name */
430 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
431 *buffer = 0;
432
433 /* and now do it */
434 if (!do_reg_operation( hkey, buffer, &context, flags ))
435 {
436 RegCloseKey( hkey );
437 return FALSE;
438 }
439 RegCloseKey( hkey );
440 }
441 return TRUE;
442 }
443
444
445 /***********************************************************************
446 * do_register_dll
447 *
448 * Register or unregister a dll.
449 */
450 static BOOL do_register_dll( const struct register_dll_info *info, const WCHAR *path,
451 INT flags, INT timeout, const WCHAR *args )
452 {
453 HMODULE module;
454 HRESULT res;
455 SP_REGISTER_CONTROL_STATUSW status;
456
457 status.cbSize = sizeof(status);
458 status.FileName = path;
459 status.FailureCode = SPREG_SUCCESS;
460 status.Win32Error = ERROR_SUCCESS;
461
462 if (info->callback)
463 {
464 switch(info->callback( info->callback_context, SPFILENOTIFY_STARTREGISTRATION,
465 (UINT_PTR)&status, !info->unregister ))
466 {
467 case FILEOP_ABORT:
468 SetLastError( ERROR_OPERATION_ABORTED );
469 return FALSE;
470 case FILEOP_SKIP:
471 return TRUE;
472 case FILEOP_DOIT:
473 break;
474 }
475 }
476
477 if (!(module = LoadLibraryExW( path, 0, LOAD_WITH_ALTERED_SEARCH_PATH )))
478 {
479 WARN( "could not load %s\n", debugstr_w(path) );
480 status.FailureCode = SPREG_LOADLIBRARY;
481 status.Win32Error = GetLastError();
482 goto done;
483 }
484
485 if (flags & FLG_REGSVR_DLLREGISTER)
486 {
487 const char *entry_point = info->unregister ? "DllUnregisterServer" : "DllRegisterServer";
488 HRESULT (WINAPI *func)(void) = (void *)GetProcAddress( module, entry_point );
489
490 if (!func)
491 {
492 status.FailureCode = SPREG_GETPROCADDR;
493 status.Win32Error = GetLastError();
494 goto done;
495 }
496
497 TRACE( "calling %s in %s\n", entry_point, debugstr_w(path) );
498 res = func();
499
500 if (FAILED(res))
501 {
502 WARN( "calling %s in %s returned error %lx\n", entry_point, debugstr_w(path), res );
503 status.FailureCode = SPREG_REGSVR;
504 status.Win32Error = res;
505 goto done;
506 }
507 }
508
509 if (flags & FLG_REGSVR_DLLINSTALL)
510 {
511 HRESULT (WINAPI *func)(BOOL,LPCWSTR) = (void *)GetProcAddress( module, "DllInstall" );
512
513 if (!func)
514 {
515 status.FailureCode = SPREG_GETPROCADDR;
516 status.Win32Error = GetLastError();
517 goto done;
518 }
519
520 TRACE( "calling DllInstall(%d,%s) in %s\n",
521 !info->unregister, debugstr_w(args), debugstr_w(path) );
522 res = func( !info->unregister, args );
523
524 if (FAILED(res))
525 {
526 WARN( "calling DllInstall in %s returned error %lx\n", debugstr_w(path), res );
527 status.FailureCode = SPREG_REGSVR;
528 status.Win32Error = res;
529 goto done;
530 }
531 }
532
533 done:
534 if (module) FreeLibrary( module );
535 if (info->callback) info->callback( info->callback_context, SPFILENOTIFY_ENDREGISTRATION,
536 (UINT_PTR)&status, !info->unregister );
537 return TRUE;
538 }
539
540
541 /***********************************************************************
542 * register_dlls_callback
543 *
544 * Called once for each RegisterDlls entry in a given section.
545 */
546 static BOOL register_dlls_callback( HINF hinf, PCWSTR field, void *arg )
547 {
548 struct register_dll_info *info = arg;
549 INFCONTEXT context;
550 BOOL ret = TRUE;
551 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
552
553 for (; ok; ok = SetupFindNextLine( &context, &context ))
554 {
555 WCHAR *path, *args, *p;
556 WCHAR buffer[MAX_INF_STRING_LENGTH];
557 INT flags, timeout;
558
559 /* get directory */
560 if (!(path = PARSER_get_dest_dir( &context ))) continue;
561
562 /* get dll name */
563 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
564 goto done;
565 if (!(p = HeapReAlloc( GetProcessHeap(), 0, path,
566 (strlenW(path) + strlenW(buffer) + 2) * sizeof(WCHAR) ))) goto done;
567 path = p;
568 p += strlenW(p);
569 if (p == path || p[-1] != '\\') *p++ = '\\';
570 strcpyW( p, buffer );
571
572 /* get flags */
573 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
574
575 /* get timeout */
576 if (!SetupGetIntField( &context, 5, &timeout )) timeout = 60;
577
578 /* get command line */
579 args = NULL;
580 if (SetupGetStringFieldW( &context, 6, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
581 args = buffer;
582
583 ret = do_register_dll( info, path, flags, timeout, args );
584
585 done:
586 HeapFree( GetProcessHeap(), 0, path );
587 if (!ret) break;
588 }
589 return ret;
590 }
591
592 /***********************************************************************
593 * update_ini_callback
594 *
595 * Called once for each UpdateInis entry in a given section.
596 */
597 static BOOL update_ini_callback( HINF hinf, PCWSTR field, void *arg )
598 {
599 INFCONTEXT context;
600
601 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
602
603 for (; ok; ok = SetupFindNextLine( &context, &context ))
604 {
605 WCHAR buffer[MAX_INF_STRING_LENGTH];
606 WCHAR filename[MAX_INF_STRING_LENGTH];
607 WCHAR section[MAX_INF_STRING_LENGTH];
608 WCHAR entry[MAX_INF_STRING_LENGTH];
609 WCHAR string[MAX_INF_STRING_LENGTH];
610 LPWSTR divider;
611
612 if (!SetupGetStringFieldW( &context, 1, filename,
613 sizeof(filename)/sizeof(WCHAR), NULL ))
614 continue;
615
616 if (!SetupGetStringFieldW( &context, 2, section,
617 sizeof(section)/sizeof(WCHAR), NULL ))
618 continue;
619
620 if (!SetupGetStringFieldW( &context, 4, buffer,
621 sizeof(buffer)/sizeof(WCHAR), NULL ))
622 continue;
623
624 divider = strchrW(buffer,'=');
625 if (divider)
626 {
627 *divider = 0;
628 strcpyW(entry,buffer);
629 divider++;
630 strcpyW(string,divider);
631 }
632 else
633 {
634 strcpyW(entry,buffer);
635 string[0]=0;
636 }
637
638 TRACE("Writing %s = %s in %s of file %s\n",debugstr_w(entry),
639 debugstr_w(string),debugstr_w(section),debugstr_w(filename));
640 WritePrivateProfileStringW(section,entry,string,filename);
641
642 }
643 return TRUE;
644 }
645
646 static BOOL update_ini_fields_callback( HINF hinf, PCWSTR field, void *arg )
647 {
648 FIXME( "should update ini fields %s\n", debugstr_w(field) );
649 return TRUE;
650 }
651
652 static BOOL ini2reg_callback( HINF hinf, PCWSTR field, void *arg )
653 {
654 FIXME( "should do ini2reg %s\n", debugstr_w(field) );
655 return TRUE;
656 }
657
658 static BOOL logconf_callback( HINF hinf, PCWSTR field, void *arg )
659 {
660 FIXME( "should do logconf %s\n", debugstr_w(field) );
661 return TRUE;
662 }
663
664 static BOOL bitreg_callback( HINF hinf, PCWSTR field, void *arg )
665 {
666 FIXME( "should do bitreg %s\n", debugstr_w(field) );
667 return TRUE;
668 }
669
670 static BOOL profile_items_callback( HINF hinf, PCWSTR field, void *arg )
671 {
672 FIXME( "should do profile items %s\n", debugstr_w(field) );
673 return TRUE;
674 }
675
676 static BOOL copy_inf_callback( HINF hinf, PCWSTR field, void *arg )
677 {
678 FIXME( "should do copy inf %s\n", debugstr_w(field) );
679 return TRUE;
680 }
681
682
683 /***********************************************************************
684 * iterate_section_fields
685 *
686 * Iterate over all fields of a certain key of a certain section
687 */
688 static BOOL iterate_section_fields( HINF hinf, PCWSTR section, PCWSTR key,
689 iterate_fields_func callback, void *arg )
690 {
691 WCHAR static_buffer[200];
692 WCHAR *buffer = static_buffer;
693 DWORD size = sizeof(static_buffer)/sizeof(WCHAR);
694 INFCONTEXT context;
695 BOOL ret = FALSE;
696
697 BOOL ok = SetupFindFirstLineW( hinf, section, key, &context );
698 while (ok)
699 {
700 UINT i, count = SetupGetFieldCount( &context );
701 for (i = 1; i <= count; i++)
702 {
703 if (!(buffer = get_field_string( &context, i, buffer, static_buffer, &size )))
704 goto done;
705 if (!callback( hinf, buffer, arg ))
706 {
707 WARN("callback failed for %s %s err %ld\n",
708 debugstr_w(section), debugstr_w(buffer), GetLastError() );
709 goto done;
710 }
711 }
712 ok = SetupFindNextMatchLineW( &context, key, &context );
713 }
714 ret = TRUE;
715 done:
716 if (buffer && buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
717 return ret;
718 }
719
720
721 /***********************************************************************
722 * SetupInstallFilesFromInfSectionA (SETUPAPI.@)
723 */
724 BOOL WINAPI SetupInstallFilesFromInfSectionA( HINF hinf, HINF hlayout, HSPFILEQ queue,
725 PCSTR section, PCSTR src_root, UINT flags )
726 {
727 UNICODE_STRING sectionW;
728 BOOL ret = FALSE;
729
730 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
731 {
732 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
733 return FALSE;
734 }
735 if (!src_root)
736 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
737 NULL, flags );
738 else
739 {
740 UNICODE_STRING srcW;
741 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
742 {
743 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
744 srcW.Buffer, flags );
745 RtlFreeUnicodeString( &srcW );
746 }
747 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
748 }
749 RtlFreeUnicodeString( &sectionW );
750 return ret;
751 }
752
753
754 /***********************************************************************
755 * SetupInstallFilesFromInfSectionW (SETUPAPI.@)
756 */
757 BOOL WINAPI SetupInstallFilesFromInfSectionW( HINF hinf, HINF hlayout, HSPFILEQ queue,
758 PCWSTR section, PCWSTR src_root, UINT flags )
759 {
760 struct files_callback_info info;
761
762 info.queue = queue;
763 info.src_root = src_root;
764 info.copy_flags = flags;
765 info.layout = hlayout;
766 return iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info );
767 }
768
769
770 /***********************************************************************
771 * SetupInstallFromInfSectionA (SETUPAPI.@)
772 */
773 BOOL WINAPI SetupInstallFromInfSectionA( HWND owner, HINF hinf, PCSTR section, UINT flags,
774 HKEY key_root, PCSTR src_root, UINT copy_flags,
775 PSP_FILE_CALLBACK_A callback, PVOID context,
776 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
777 {
778 UNICODE_STRING sectionW, src_rootW;
779 struct callback_WtoA_context ctx;
780 BOOL ret = FALSE;
781
782 src_rootW.Buffer = NULL;
783 if (src_root && !RtlCreateUnicodeStringFromAsciiz( &src_rootW, src_root ))
784 {
785 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
786 return FALSE;
787 }
788
789 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
790 {
791 ctx.orig_context = context;
792 ctx.orig_handler = callback;
793 ret = SetupInstallFromInfSectionW( owner, hinf, sectionW.Buffer, flags, key_root,
794 src_rootW.Buffer, copy_flags, QUEUE_callback_WtoA,
795 &ctx, devinfo, devinfo_data );
796 RtlFreeUnicodeString( &sectionW );
797 }
798 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
799
800 RtlFreeUnicodeString( &src_rootW );
801 return ret;
802 }
803
804
805 /***********************************************************************
806 * include_callback
807 *
808 * Called once for each Include entry in a given section.
809 */
810 static BOOL include_callback( HINF hinf, PCWSTR field, void *arg )
811 {
812 return SetupOpenAppendInfFileW( field, hinf, NULL );
813 }
814
815
816 /***********************************************************************
817 * needs_callback
818 *
819 * Called once for each Needs entry in a given section.
820 */
821 static BOOL needs_callback( HINF hinf, PCWSTR field, void *arg )
822 {
823 struct needs_callback_info *info = arg;
824
825 switch (info->type)
826 {
827 case 0:
828 return SetupInstallFromInfSectionW(info->owner, hinf, field, info->flags,
829 info->key_root, info->src_root, info->copy_flags, info->callback,
830 info->context, info->devinfo, info->devinfo_data);
831 case 1:
832 return SetupInstallServicesFromInfSectionExW(hinf, field, info->flags,
833 info->devinfo, info->devinfo_data, info->reserved1, info->reserved2);
834 default:
835 ERR("Unknown info type %ld\n", info->type);
836 return FALSE;
837 }
838 }
839
840
841 /***********************************************************************
842 * SetupInstallFromInfSectionW (SETUPAPI.@)
843 */
844 BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section, UINT flags,
845 HKEY key_root, PCWSTR src_root, UINT copy_flags,
846 PSP_FILE_CALLBACK_W callback, PVOID context,
847 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
848 {
849 struct needs_callback_info needs_info;
850
851 /* Parse 'Include' and 'Needs' directives */
852 iterate_section_fields( hinf, section, Include, include_callback, NULL);
853 needs_info.type = 0;
854 needs_info.owner = owner;
855 needs_info.flags = flags;
856 needs_info.key_root = key_root;
857 needs_info.src_root = src_root;
858 needs_info.copy_flags = copy_flags;
859 needs_info.callback = callback;
860 needs_info.context = context;
861 needs_info.devinfo = devinfo;
862 needs_info.devinfo_data = devinfo_data;
863 iterate_section_fields( hinf, section, Needs, needs_callback, &needs_info);
864
865 if (flags & SPINST_FILES)
866 {
867 struct files_callback_info info;
868 HSPFILEQ queue;
869 BOOL ret;
870
871 if (!(queue = SetupOpenFileQueue())) return FALSE;
872 info.queue = queue;
873 info.src_root = src_root;
874 info.copy_flags = copy_flags;
875 info.layout = hinf;
876 ret = (iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ) &&
877 iterate_section_fields( hinf, section, DelFiles, delete_files_callback, &info ) &&
878 iterate_section_fields( hinf, section, RenFiles, rename_files_callback, &info ) &&
879 SetupCommitFileQueueW( owner, queue, callback, context ));
880 SetupCloseFileQueue( queue );
881 if (!ret) return FALSE;
882 }
883 if (flags & SPINST_INIFILES)
884 {
885 if (!iterate_section_fields( hinf, section, UpdateInis, update_ini_callback, NULL ) ||
886 !iterate_section_fields( hinf, section, UpdateIniFields,
887 update_ini_fields_callback, NULL ))
888 return FALSE;
889 }
890 if (flags & SPINST_INI2REG)
891 {
892 if (!iterate_section_fields( hinf, section, Ini2Reg, ini2reg_callback, NULL ))
893 return FALSE;
894 }
895 if (flags & SPINST_LOGCONFIG)
896 {
897 if (!iterate_section_fields( hinf, section, LogConf, logconf_callback, NULL ))
898 return FALSE;
899 }
900 if (flags & SPINST_REGSVR)
901 {
902 struct register_dll_info info;
903
904 info.unregister = FALSE;
905 if (flags & SPINST_REGISTERCALLBACKAWARE)
906 {
907 info.callback = callback;
908 info.callback_context = context;
909 }
910 else info.callback = NULL;
911
912 if (!iterate_section_fields( hinf, section, RegisterDlls, register_dlls_callback, &info ))
913 return FALSE;
914 }
915 if (flags & SPINST_UNREGSVR)
916 {
917 struct register_dll_info info;
918
919 info.unregister = TRUE;
920 if (flags & SPINST_REGISTERCALLBACKAWARE)
921 {
922 info.callback = callback;
923 info.callback_context = context;
924 }
925 else info.callback = NULL;
926
927 if (!iterate_section_fields( hinf, section, UnregisterDlls, register_dlls_callback, &info ))
928 return FALSE;
929 }
930 if (flags & SPINST_REGISTRY)
931 {
932 struct registry_callback_info info;
933
934 info.default_root = key_root;
935 info.delete = TRUE;
936 if (!iterate_section_fields( hinf, section, DelReg, registry_callback, &info ))
937 return FALSE;
938 info.delete = FALSE;
939 if (!iterate_section_fields( hinf, section, AddReg, registry_callback, &info ))
940 return FALSE;
941 }
942 if (flags & SPINST_BITREG)
943 {
944 if (!iterate_section_fields( hinf, section, BitReg, bitreg_callback, NULL ))
945 return FALSE;
946 }
947 if (flags & SPINST_PROFILEITEMS)
948 {
949 if (!iterate_section_fields( hinf, section, ProfileItems, profile_items_callback, NULL ))
950 return FALSE;
951 }
952 if (flags & SPINST_COPYINF)
953 {
954 if (!iterate_section_fields( hinf, section, CopyINF, copy_inf_callback, NULL ))
955 return FALSE;
956 }
957
958 return TRUE;
959 }
960
961
962 /***********************************************************************
963 * InstallHinfSectionW (SETUPAPI.@)
964 *
965 * NOTE: 'cmdline' is <section> <mode> <path> from
966 * RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection <section> <mode> <path>
967 */
968 void WINAPI InstallHinfSectionW( HWND hwnd, HINSTANCE handle, LPCWSTR cmdline, INT show )
969 {
970 WCHAR *p, *path, section[MAX_PATH];
971 void *callback_context;
972 UINT mode;
973 HINF hinf;
974
975 TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd, handle, debugstr_w(cmdline));
976
977 lstrcpynW( section, cmdline, sizeof(section)/sizeof(WCHAR) );
978
979 if (!(p = strchrW( section, ' ' ))) return;
980 *p++ = 0;
981 while (*p == ' ') p++;
982 mode = atoiW( p );
983
984 if (!(p = strchrW( p, ' ' ))) return;
985 path = p + 1;
986 while (*path == ' ') path++;
987
988 hinf = SetupOpenInfFileW( path, NULL, INF_STYLE_WIN4, NULL );
989 if (hinf == INVALID_HANDLE_VALUE) return;
990
991 callback_context = SetupInitDefaultQueueCallback( hwnd );
992 SetupInstallFromInfSectionW( hwnd, hinf, section, SPINST_ALL, NULL, NULL, SP_COPY_NEWER,
993 SetupDefaultQueueCallbackW, callback_context,
994 NULL, NULL );
995 SetupTermDefaultQueueCallback( callback_context );
996 SetupCloseInfFile( hinf );
997
998 /* FIXME: should check the mode and maybe reboot */
999 /* there isn't much point in doing that since we */
1000 /* don't yet handle deferred file copies anyway. */
1001 }
1002
1003
1004 /***********************************************************************
1005 * InstallHinfSectionA (SETUPAPI.@)
1006 */
1007 void WINAPI InstallHinfSectionA( HWND hwnd, HINSTANCE handle, LPCSTR cmdline, INT show )
1008 {
1009 UNICODE_STRING cmdlineW;
1010
1011 if (RtlCreateUnicodeStringFromAsciiz( &cmdlineW, cmdline ))
1012 {
1013 InstallHinfSectionW( hwnd, handle, cmdlineW.Buffer, show );
1014 RtlFreeUnicodeString( &cmdlineW );
1015 }
1016 }
1017
1018
1019 /***********************************************************************
1020 * SetupInstallServicesFromInfSectionA (SETUPAPI.@)
1021 */
1022 BOOL WINAPI SetupInstallServicesFromInfSectionA( HINF hinf, PCSTR sectionname, DWORD flags )
1023 {
1024 return SetupInstallServicesFromInfSectionExA( hinf, sectionname, flags,
1025 NULL, NULL, NULL, NULL );
1026 }
1027
1028
1029 /***********************************************************************
1030 * SetupInstallServicesFromInfSectionW (SETUPAPI.@)
1031 */
1032 BOOL WINAPI SetupInstallServicesFromInfSectionW( HINF hinf, PCWSTR sectionname, DWORD flags )
1033 {
1034 return SetupInstallServicesFromInfSectionExW( hinf, sectionname, flags,
1035 NULL, NULL, NULL, NULL );
1036 }
1037
1038
1039 /***********************************************************************
1040 * SetupInstallServicesFromInfSectionExA (SETUPAPI.@)
1041 */
1042 BOOL WINAPI SetupInstallServicesFromInfSectionExA( HINF hinf, PCSTR sectionname, DWORD flags, HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data, PVOID reserved1, PVOID reserved2 )
1043 {
1044 UNICODE_STRING sectionnameW;
1045 BOOL ret = FALSE;
1046
1047 if (RtlCreateUnicodeStringFromAsciiz( &sectionnameW, sectionname ))
1048 {
1049 ret = SetupInstallServicesFromInfSectionExW( hinf, sectionnameW.Buffer, flags, devinfo, devinfo_data, reserved1, reserved2 );
1050 RtlFreeUnicodeString( &sectionnameW );
1051 }
1052 else
1053 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1054
1055 return ret;
1056 }
1057
1058
1059 static BOOL GetLineText( HINF hinf, PCWSTR section_name, PCWSTR key_name, PWSTR *value)
1060 {
1061 DWORD required;
1062 PWSTR buf = NULL;
1063
1064 *value = NULL;
1065
1066 if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, NULL, 0, &required )
1067 && GetLastError() != ERROR_INSUFFICIENT_BUFFER )
1068 return FALSE;
1069
1070 buf = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) );
1071 if ( ! buf )
1072 {
1073 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1074 return FALSE;
1075 }
1076
1077 if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, buf, required, &required ) )
1078 {
1079 HeapFree( GetProcessHeap(), 0, buf );
1080 return FALSE;
1081 }
1082
1083 *value = buf;
1084 return TRUE;
1085 }
1086
1087
1088 static BOOL GetIntField( HINF hinf, PCWSTR section_name, PCWSTR key_name, INT *value)
1089 {
1090 LPWSTR buffer, end;
1091 INT res;
1092
1093 if (! GetLineText( hinf, section_name, key_name, &buffer ) )
1094 return FALSE;
1095
1096 res = wcstol( buffer, &end, 0 );
1097 if (end != buffer && !*end)
1098 {
1099 HeapFree(GetProcessHeap(), 0, buffer);
1100 *value = res;
1101 return TRUE;
1102 }
1103 else
1104 {
1105 HeapFree(GetProcessHeap(), 0, buffer);
1106 SetLastError( ERROR_INVALID_DATA );
1107 return FALSE;
1108 }
1109 }
1110
1111
1112 BOOL GetStringField( PINFCONTEXT context, DWORD index, PWSTR *value)
1113 {
1114 DWORD RequiredSize;
1115 BOOL ret;
1116
1117 ret = SetupGetStringFieldW(
1118 context,
1119 index,
1120 NULL, 0,
1121 &RequiredSize);
1122 if (!ret)
1123 return FALSE;
1124 else if (RequiredSize == 0)
1125 {
1126 *value = NULL;
1127 return TRUE;
1128 }
1129
1130 /* We got the needed size for the buffer */
1131 *value = MyMalloc(RequiredSize * sizeof(WCHAR));
1132 if (!*value)
1133 {
1134 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1135 return FALSE;
1136 }
1137 ret = SetupGetStringFieldW(
1138 context,
1139 index,
1140 *value, RequiredSize, NULL);
1141 if (!ret)
1142 MyFree(*value);
1143
1144 return ret;
1145 }
1146
1147
1148 static BOOL InstallOneService(
1149 struct DeviceInfoSet *list,
1150 IN HINF hInf,
1151 IN LPCWSTR ServiceSection,
1152 IN LPCWSTR ServiceName,
1153 IN UINT ServiceFlags)
1154 {
1155 SC_HANDLE hSCManager = NULL;
1156 SC_HANDLE hService = NULL;
1157 LPDWORD GroupOrder = NULL;
1158 LPQUERY_SERVICE_CONFIG ServiceConfig = NULL;
1159 BOOL ret = FALSE;
1160
1161 HKEY hGroupOrderListKey = INVALID_HANDLE_VALUE;
1162 LPWSTR ServiceBinary = NULL;
1163 LPWSTR LoadOrderGroup = NULL;
1164 LPWSTR DisplayName = NULL;
1165 LPWSTR Description = NULL;
1166 LPWSTR Dependencies = NULL;
1167 INT ServiceType, StartType, ErrorControl;
1168 DWORD dwRegType;
1169 DWORD tagId = (DWORD)-1;
1170 BOOL useTag;
1171
1172 if (!GetIntField(hInf, ServiceSection, L"ServiceType", &ServiceType))
1173 goto cleanup;
1174 if (!GetIntField(hInf, ServiceSection, L"StartType", &StartType))
1175 goto cleanup;
1176 if (!GetIntField(hInf, ServiceSection, L"ErrorControl", &ErrorControl))
1177 goto cleanup;
1178 useTag = (ServiceType == SERVICE_BOOT_START || ServiceType == SERVICE_SYSTEM_START);
1179
1180 hSCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE);
1181 if (hSCManager == NULL)
1182 goto cleanup;
1183
1184 if (!GetLineText(hInf, ServiceSection, L"ServiceBinary", &ServiceBinary))
1185 goto cleanup;
1186
1187 /* Don't check return value, as these fields are optional and
1188 * GetLineText initialize output parameter even on failure */
1189 GetLineText(hInf, ServiceSection, L"LoadOrderGroup", &LoadOrderGroup);
1190 GetLineText(hInf, ServiceSection, L"DisplayName", &DisplayName);
1191 GetLineText(hInf, ServiceSection, L"Description", &Description);
1192 GetLineText(hInf, ServiceSection, L"Dependencies", &Dependencies);
1193
1194 hService = OpenServiceW(
1195 hSCManager,
1196 ServiceName,
1197 GENERIC_READ | GENERIC_WRITE);
1198 if (hService == NULL && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
1199 goto cleanup;
1200
1201 if (hService && (ServiceFlags & SPSVCINST_DELETEEVENTLOGENTRY))
1202 {
1203 ret = DeleteService(hService);
1204 if (!ret && GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
1205 goto cleanup;
1206 }
1207
1208 if (hService == NULL)
1209 {
1210 /* Create new service */
1211 hService = CreateServiceW(
1212 hSCManager,
1213 ServiceName,
1214 DisplayName,
1215 0,
1216 ServiceType,
1217 StartType,
1218 ErrorControl,
1219 ServiceBinary,
1220 LoadOrderGroup,
1221 useTag ? &tagId : NULL,
1222 Dependencies,
1223 NULL, NULL);
1224 if (hService == NULL)
1225 goto cleanup;
1226 }
1227 else
1228 {
1229 DWORD bufferSize;
1230 /* Read current configuration */
1231 if (!QueryServiceConfigW(hService, NULL, 0, &bufferSize))
1232 {
1233 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1234 goto cleanup;
1235 ServiceConfig = MyMalloc(bufferSize);
1236 if (!ServiceConfig)
1237 {
1238 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1239 goto cleanup;
1240 }
1241 if (!QueryServiceConfigW(hService, ServiceConfig, bufferSize, &bufferSize))
1242 goto cleanup;
1243 }
1244 tagId = ServiceConfig->dwTagId;
1245
1246 /* Update configuration */
1247 ret = ChangeServiceConfigW(
1248 hService,
1249 ServiceType,
1250 (ServiceFlags & SPSVCINST_NOCLOBBER_STARTTYPE) ? SERVICE_NO_CHANGE : StartType,
1251 (ServiceFlags & SPSVCINST_NOCLOBBER_ERRORCONTROL) ? SERVICE_NO_CHANGE : ErrorControl,
1252 ServiceBinary,
1253 (ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP && ServiceConfig->lpLoadOrderGroup) ? NULL : LoadOrderGroup,
1254 useTag ? &tagId : NULL,
1255 (ServiceFlags & SPSVCINST_NOCLOBBER_DEPENDENCIES && ServiceConfig->lpDependencies) ? NULL : Dependencies,
1256 NULL, NULL,
1257 (ServiceFlags & SPSVCINST_NOCLOBBER_DISPLAYNAME && ServiceConfig->lpDisplayName) ? NULL : DisplayName);
1258 if (!ret)
1259 goto cleanup;
1260 }
1261
1262 /* FIXME: use Description and SPSVCINST_NOCLOBBER_DESCRIPTION */
1263
1264 if (useTag)
1265 {
1266 /* Add the tag to SYSTEM\CurrentControlSet\Control\GroupOrderList key */
1267 LONG rc;
1268 LPCWSTR lpLoadOrderGroup;
1269 DWORD bufferSize;
1270
1271 lpLoadOrderGroup = LoadOrderGroup;
1272 if ((ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP) && ServiceConfig && ServiceConfig->lpLoadOrderGroup)
1273 lpLoadOrderGroup = ServiceConfig->lpLoadOrderGroup;
1274
1275 rc = RegOpenKey(
1276 list ? list->HKLM : HKEY_LOCAL_MACHINE,
1277 L"SYSTEM\\CurrentControlSet\\Control\\GroupOrderList",
1278 &hGroupOrderListKey);
1279 if (rc != ERROR_SUCCESS)
1280 {
1281 SetLastError(rc);
1282 goto cleanup;
1283 }
1284 rc = RegQueryValueExW(hGroupOrderListKey, lpLoadOrderGroup, NULL, &dwRegType, NULL, &bufferSize);
1285 if (rc == ERROR_FILE_NOT_FOUND)
1286 bufferSize = sizeof(DWORD);
1287 else if (rc != ERROR_SUCCESS)
1288 {
1289 SetLastError(rc);
1290 goto cleanup;
1291 }
1292 else if (dwRegType != REG_BINARY || bufferSize == 0 || bufferSize % sizeof(DWORD) != 0)
1293 {
1294 SetLastError(ERROR_GEN_FAILURE);
1295 goto cleanup;
1296 }
1297 /* Allocate buffer to store existing data + the new tag */
1298 GroupOrder = MyMalloc(bufferSize + sizeof(DWORD));
1299 if (!GroupOrder)
1300 {
1301 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1302 goto cleanup;
1303 }
1304 if (rc == ERROR_SUCCESS)
1305 {
1306 /* Read existing data */
1307 rc = RegQueryValueExW(
1308 hGroupOrderListKey,
1309 lpLoadOrderGroup,
1310 NULL,
1311 NULL,
1312 (BYTE*)GroupOrder,
1313 &bufferSize);
1314 if (rc != ERROR_SUCCESS)
1315 {
1316 SetLastError(rc);
1317 goto cleanup;
1318 }
1319 if (ServiceFlags & SPSVCINST_TAGTOFRONT)
1320 memmove(&GroupOrder[2], &GroupOrder[1], bufferSize - sizeof(DWORD));
1321 }
1322 else
1323 {
1324 GroupOrder[0] = 0;
1325 }
1326 GroupOrder[0]++;
1327 if (ServiceFlags & SPSVCINST_TAGTOFRONT)
1328 GroupOrder[1] = tagId;
1329 else
1330 GroupOrder[bufferSize / sizeof(DWORD)] = tagId;
1331
1332 rc = RegSetValueExW(
1333 hGroupOrderListKey,
1334 lpLoadOrderGroup,
1335 0,
1336 REG_BINARY,
1337 (BYTE*)GroupOrder,
1338 bufferSize + sizeof(DWORD));
1339 if (rc != ERROR_SUCCESS)
1340 {
1341 SetLastError(rc);
1342 goto cleanup;
1343 }
1344 }
1345
1346 ret = TRUE;
1347
1348 cleanup:
1349 if (hSCManager != NULL)
1350 CloseServiceHandle(hSCManager);
1351 if (hService != NULL)
1352 CloseServiceHandle(hService);
1353 if (hGroupOrderListKey != INVALID_HANDLE_VALUE)
1354 RegCloseKey(hGroupOrderListKey);
1355 MyFree(ServiceConfig);
1356 MyFree(ServiceBinary);
1357 MyFree(LoadOrderGroup);
1358 MyFree(DisplayName);
1359 MyFree(Description);
1360 MyFree(Dependencies);
1361 MyFree(GroupOrder);
1362
1363 TRACE("Returning %d\n", ret);
1364 return ret;
1365 }
1366
1367
1368 /***********************************************************************
1369 * SetupInstallServicesFromInfSectionExW (SETUPAPI.@)
1370 */
1371 BOOL WINAPI SetupInstallServicesFromInfSectionExW( HINF hinf, PCWSTR sectionname, DWORD flags, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PVOID reserved1, PVOID reserved2 )
1372 {
1373 struct DeviceInfoSet *list = NULL;
1374 BOOL ret = FALSE;
1375
1376 TRACE("%p, %s, 0x%lx, %p, %p, %p, %p\n", hinf, debugstr_w(sectionname),
1377 flags, DeviceInfoSet, DeviceInfoData, reserved1, reserved2);
1378
1379 if (!sectionname)
1380 SetLastError(ERROR_INVALID_PARAMETER);
1381 else if (flags & ~(SPSVCINST_TAGTOFRONT | SPSVCINST_DELETEEVENTLOGENTRY | SPSVCINST_NOCLOBBER_DISPLAYNAME | SPSVCINST_NOCLOBBER_STARTTYPE | SPSVCINST_NOCLOBBER_ERRORCONTROL | SPSVCINST_NOCLOBBER_LOADORDERGROUP | SPSVCINST_NOCLOBBER_DEPENDENCIES | SPSVCINST_STOPSERVICE))
1382 {
1383 TRACE("Unknown flags: 0x%08lx\n", flags & ~(SPSVCINST_TAGTOFRONT | SPSVCINST_DELETEEVENTLOGENTRY | SPSVCINST_NOCLOBBER_DISPLAYNAME | SPSVCINST_NOCLOBBER_STARTTYPE | SPSVCINST_NOCLOBBER_ERRORCONTROL | SPSVCINST_NOCLOBBER_LOADORDERGROUP | SPSVCINST_NOCLOBBER_DEPENDENCIES | SPSVCINST_STOPSERVICE));
1384 SetLastError(ERROR_INVALID_FLAGS);
1385 }
1386 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1387 SetLastError(ERROR_INVALID_HANDLE);
1388 else if (DeviceInfoSet && (list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
1389 SetLastError(ERROR_INVALID_HANDLE);
1390 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1391 SetLastError(ERROR_INVALID_USER_BUFFER);
1392 else if (reserved1 != NULL || reserved2 != NULL)
1393 SetLastError(ERROR_INVALID_PARAMETER);
1394 else
1395 {
1396 struct needs_callback_info needs_info;
1397 LPWSTR ServiceName = NULL;
1398 LPWSTR ServiceSection = NULL;
1399 INT ServiceFlags;
1400 INFCONTEXT ContextService;
1401 BOOL bNeedReboot = FALSE;
1402
1403 /* Parse 'Include' and 'Needs' directives */
1404 iterate_section_fields( hinf, sectionname, Include, include_callback, NULL);
1405 needs_info.type = 1;
1406 needs_info.flags = flags;
1407 needs_info.devinfo = DeviceInfoSet;
1408 needs_info.devinfo_data = DeviceInfoData;
1409 needs_info.reserved1 = reserved1;
1410 needs_info.reserved2 = reserved2;
1411 iterate_section_fields( hinf, sectionname, Needs, needs_callback, &needs_info);
1412
1413 if (flags & SPSVCINST_STOPSERVICE)
1414 {
1415 FIXME("Stopping the device not implemented\n");
1416 /* This may lead to require a reboot */
1417 /* bNeedReboot = TRUE; */
1418 #if 0
1419 SERVICE_STATUS ServiceStatus;
1420 ret = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus);
1421 if (!ret && GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
1422 goto cleanup;
1423 if (ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING && ServiceStatus.dwCurrentState != SERVICE_STOPPED)
1424 {
1425 SetLastError(ERROR_INSTALL_SERVICE_FAILURE);
1426 goto cleanup;
1427 }
1428 #endif
1429 flags &= ~SPSVCINST_STOPSERVICE;
1430 }
1431
1432 ret = SetupFindFirstLineW(hinf, sectionname, AddService, &ContextService);
1433 while (ret)
1434 {
1435 if (!GetStringField(&ContextService, 1, &ServiceName))
1436 goto nextservice;
1437
1438 ret = SetupGetIntField(
1439 &ContextService,
1440 2, /* Field index */
1441 &ServiceFlags);
1442 if (!ret)
1443 {
1444 /* The field may be empty. Ignore the error */
1445 ServiceFlags = 0;
1446 }
1447
1448 if (!GetStringField(&ContextService, 3, &ServiceSection))
1449 goto nextservice;
1450
1451 ret = InstallOneService(list, hinf, ServiceSection, ServiceName, (ServiceFlags & ~SPSVCINST_ASSOCSERVICE) | flags);
1452 if (!ret)
1453 goto nextservice;
1454
1455 if (ServiceFlags & SPSVCINST_ASSOCSERVICE)
1456 {
1457 ret = SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet, DeviceInfoData, SPDRP_SERVICE, (LPBYTE)ServiceName, (strlenW(ServiceName) + 1) * sizeof(WCHAR));
1458 if (!ret)
1459 goto nextservice;
1460 }
1461
1462 nextservice:
1463 HeapFree(GetProcessHeap(), 0, ServiceName);
1464 HeapFree(GetProcessHeap(), 0, ServiceSection);
1465 ServiceName = ServiceSection = NULL;
1466 ret = SetupFindNextMatchLineW(&ContextService, AddService, &ContextService);
1467 }
1468
1469 if (bNeedReboot)
1470 SetLastError(ERROR_SUCCESS_REBOOT_REQUIRED);
1471 else
1472 SetLastError(ERROR_SUCCESS);
1473 ret = TRUE;
1474 }
1475
1476 TRACE("Returning %d\n", ret);
1477 return ret;
1478 }