reshuffling of dlls
[reactos.git] / reactos / dll / win32 / 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 if (hkey != root_key) RegCloseKey( hkey );
437 return FALSE;
438 }
439 if (hkey != root_key) 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 SP_DEVINSTALL_PARAMS_W install_params;
868 struct files_callback_info info;
869 HSPFILEQ queue = NULL;
870 BOOL use_custom_queue;
871 BOOL ret;
872
873 install_params.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
874 use_custom_queue = SetupDiGetDeviceInstallParamsW(devinfo, devinfo_data, &install_params) && (install_params.Flags & DI_NOVCP);
875 if (!use_custom_queue && ((queue = SetupOpenFileQueue()) == (HSPFILEQ)INVALID_HANDLE_VALUE ))
876 return FALSE;
877 info.queue = use_custom_queue ? install_params.FileQueue : queue;
878 info.src_root = src_root;
879 info.copy_flags = copy_flags;
880 info.layout = hinf;
881 ret = (iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ) &&
882 iterate_section_fields( hinf, section, DelFiles, delete_files_callback, &info ) &&
883 iterate_section_fields( hinf, section, RenFiles, rename_files_callback, &info ));
884 if (!use_custom_queue)
885 {
886 if (ret)
887 ret = SetupCommitFileQueueW( owner, queue, callback, context );
888 SetupCloseFileQueue( queue );
889 }
890 if (!ret) return FALSE;
891 }
892 if (flags & SPINST_INIFILES)
893 {
894 if (!iterate_section_fields( hinf, section, UpdateInis, update_ini_callback, NULL ) ||
895 !iterate_section_fields( hinf, section, UpdateIniFields,
896 update_ini_fields_callback, NULL ))
897 return FALSE;
898 }
899 if (flags & SPINST_INI2REG)
900 {
901 if (!iterate_section_fields( hinf, section, Ini2Reg, ini2reg_callback, NULL ))
902 return FALSE;
903 }
904 if (flags & SPINST_LOGCONFIG)
905 {
906 if (!iterate_section_fields( hinf, section, LogConf, logconf_callback, NULL ))
907 return FALSE;
908 }
909 if (flags & SPINST_REGSVR)
910 {
911 struct register_dll_info info;
912
913 info.unregister = FALSE;
914 if (flags & SPINST_REGISTERCALLBACKAWARE)
915 {
916 info.callback = callback;
917 info.callback_context = context;
918 }
919 else info.callback = NULL;
920
921 if (!iterate_section_fields( hinf, section, RegisterDlls, register_dlls_callback, &info ))
922 return FALSE;
923 }
924 if (flags & SPINST_UNREGSVR)
925 {
926 struct register_dll_info info;
927
928 info.unregister = TRUE;
929 if (flags & SPINST_REGISTERCALLBACKAWARE)
930 {
931 info.callback = callback;
932 info.callback_context = context;
933 }
934 else info.callback = NULL;
935
936 if (!iterate_section_fields( hinf, section, UnregisterDlls, register_dlls_callback, &info ))
937 return FALSE;
938 }
939 if (flags & SPINST_REGISTRY)
940 {
941 struct registry_callback_info info;
942
943 info.default_root = key_root;
944 info.delete = TRUE;
945 if (!iterate_section_fields( hinf, section, DelReg, registry_callback, &info ))
946 return FALSE;
947 info.delete = FALSE;
948 if (!iterate_section_fields( hinf, section, AddReg, registry_callback, &info ))
949 return FALSE;
950 }
951 if (flags & SPINST_BITREG)
952 {
953 if (!iterate_section_fields( hinf, section, BitReg, bitreg_callback, NULL ))
954 return FALSE;
955 }
956 if (flags & SPINST_PROFILEITEMS)
957 {
958 if (!iterate_section_fields( hinf, section, ProfileItems, profile_items_callback, NULL ))
959 return FALSE;
960 }
961 if (flags & SPINST_COPYINF)
962 {
963 if (!iterate_section_fields( hinf, section, CopyINF, copy_inf_callback, NULL ))
964 return FALSE;
965 }
966
967 return TRUE;
968 }
969
970
971 /***********************************************************************
972 * InstallHinfSectionW (SETUPAPI.@)
973 *
974 * NOTE: 'cmdline' is <section> <mode> <path> from
975 * RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection <section> <mode> <path>
976 */
977 void WINAPI InstallHinfSectionW( HWND hwnd, HINSTANCE handle, LPCWSTR cmdline, INT show )
978 {
979 WCHAR *p, *path, section[MAX_PATH];
980 void *callback_context;
981 UINT mode;
982 HINF hinf;
983
984 TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd, handle, debugstr_w(cmdline));
985
986 lstrcpynW( section, cmdline, sizeof(section)/sizeof(WCHAR) );
987
988 if (!(p = strchrW( section, ' ' ))) return;
989 *p++ = 0;
990 while (*p == ' ') p++;
991 mode = atoiW( p );
992
993 if (!(p = strchrW( p, ' ' ))) return;
994 path = p + 1;
995 while (*path == ' ') path++;
996
997 hinf = SetupOpenInfFileW( path, NULL, INF_STYLE_WIN4, NULL );
998 if (hinf == INVALID_HANDLE_VALUE) return;
999
1000 callback_context = SetupInitDefaultQueueCallback( hwnd );
1001 SetupInstallFromInfSectionW( hwnd, hinf, section, SPINST_ALL, NULL, NULL, SP_COPY_NEWER,
1002 SetupDefaultQueueCallbackW, callback_context,
1003 NULL, NULL );
1004 SetupTermDefaultQueueCallback( callback_context );
1005 SetupCloseInfFile( hinf );
1006
1007 /* FIXME: should check the mode and maybe reboot */
1008 /* there isn't much point in doing that since we */
1009 /* don't yet handle deferred file copies anyway. */
1010 }
1011
1012
1013 /***********************************************************************
1014 * InstallHinfSectionA (SETUPAPI.@)
1015 */
1016 void WINAPI InstallHinfSectionA( HWND hwnd, HINSTANCE handle, LPCSTR cmdline, INT show )
1017 {
1018 UNICODE_STRING cmdlineW;
1019
1020 if (RtlCreateUnicodeStringFromAsciiz( &cmdlineW, cmdline ))
1021 {
1022 InstallHinfSectionW( hwnd, handle, cmdlineW.Buffer, show );
1023 RtlFreeUnicodeString( &cmdlineW );
1024 }
1025 }
1026
1027
1028 /***********************************************************************
1029 * SetupInstallServicesFromInfSectionA (SETUPAPI.@)
1030 */
1031 BOOL WINAPI SetupInstallServicesFromInfSectionA( HINF hinf, PCSTR sectionname, DWORD flags )
1032 {
1033 return SetupInstallServicesFromInfSectionExA( hinf, sectionname, flags,
1034 NULL, NULL, NULL, NULL );
1035 }
1036
1037
1038 /***********************************************************************
1039 * SetupInstallServicesFromInfSectionW (SETUPAPI.@)
1040 */
1041 BOOL WINAPI SetupInstallServicesFromInfSectionW( HINF hinf, PCWSTR sectionname, DWORD flags )
1042 {
1043 return SetupInstallServicesFromInfSectionExW( hinf, sectionname, flags,
1044 NULL, NULL, NULL, NULL );
1045 }
1046
1047
1048 /***********************************************************************
1049 * SetupInstallServicesFromInfSectionExA (SETUPAPI.@)
1050 */
1051 BOOL WINAPI SetupInstallServicesFromInfSectionExA( HINF hinf, PCSTR sectionname, DWORD flags, HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data, PVOID reserved1, PVOID reserved2 )
1052 {
1053 UNICODE_STRING sectionnameW;
1054 BOOL ret = FALSE;
1055
1056 if (RtlCreateUnicodeStringFromAsciiz( &sectionnameW, sectionname ))
1057 {
1058 ret = SetupInstallServicesFromInfSectionExW( hinf, sectionnameW.Buffer, flags, devinfo, devinfo_data, reserved1, reserved2 );
1059 RtlFreeUnicodeString( &sectionnameW );
1060 }
1061 else
1062 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1063
1064 return ret;
1065 }
1066
1067
1068 static BOOL GetLineText( HINF hinf, PCWSTR section_name, PCWSTR key_name, PWSTR *value)
1069 {
1070 DWORD required;
1071 PWSTR buf = NULL;
1072
1073 *value = NULL;
1074
1075 if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, NULL, 0, &required )
1076 && GetLastError() != ERROR_INSUFFICIENT_BUFFER )
1077 return FALSE;
1078
1079 buf = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) );
1080 if ( ! buf )
1081 {
1082 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1083 return FALSE;
1084 }
1085
1086 if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, buf, required, &required ) )
1087 {
1088 HeapFree( GetProcessHeap(), 0, buf );
1089 return FALSE;
1090 }
1091
1092 *value = buf;
1093 return TRUE;
1094 }
1095
1096
1097 static BOOL GetIntField( HINF hinf, PCWSTR section_name, PCWSTR key_name, INT *value)
1098 {
1099 LPWSTR buffer, end;
1100 INT res;
1101
1102 if (! GetLineText( hinf, section_name, key_name, &buffer ) )
1103 return FALSE;
1104
1105 res = wcstol( buffer, &end, 0 );
1106 if (end != buffer && !*end)
1107 {
1108 HeapFree(GetProcessHeap(), 0, buffer);
1109 *value = res;
1110 return TRUE;
1111 }
1112 else
1113 {
1114 HeapFree(GetProcessHeap(), 0, buffer);
1115 SetLastError( ERROR_INVALID_DATA );
1116 return FALSE;
1117 }
1118 }
1119
1120
1121 BOOL GetStringField( PINFCONTEXT context, DWORD index, PWSTR *value)
1122 {
1123 DWORD RequiredSize;
1124 BOOL ret;
1125
1126 ret = SetupGetStringFieldW(
1127 context,
1128 index,
1129 NULL, 0,
1130 &RequiredSize);
1131 if (!ret)
1132 return FALSE;
1133 else if (RequiredSize == 0)
1134 {
1135 *value = NULL;
1136 return TRUE;
1137 }
1138
1139 /* We got the needed size for the buffer */
1140 *value = MyMalloc(RequiredSize * sizeof(WCHAR));
1141 if (!*value)
1142 {
1143 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1144 return FALSE;
1145 }
1146 ret = SetupGetStringFieldW(
1147 context,
1148 index,
1149 *value, RequiredSize, NULL);
1150 if (!ret)
1151 MyFree(*value);
1152
1153 return ret;
1154 }
1155
1156
1157 static BOOL InstallOneService(
1158 struct DeviceInfoSet *list,
1159 IN HINF hInf,
1160 IN LPCWSTR ServiceSection,
1161 IN LPCWSTR ServiceName,
1162 IN UINT ServiceFlags)
1163 {
1164 SC_HANDLE hSCManager = NULL;
1165 SC_HANDLE hService = NULL;
1166 LPDWORD GroupOrder = NULL;
1167 LPQUERY_SERVICE_CONFIG ServiceConfig = NULL;
1168 BOOL ret = FALSE;
1169
1170 HKEY hGroupOrderListKey = INVALID_HANDLE_VALUE;
1171 LPWSTR ServiceBinary = NULL;
1172 LPWSTR LoadOrderGroup = NULL;
1173 LPWSTR DisplayName = NULL;
1174 LPWSTR Description = NULL;
1175 LPWSTR Dependencies = NULL;
1176 INT ServiceType, StartType, ErrorControl;
1177 DWORD dwRegType;
1178 DWORD tagId = (DWORD)-1;
1179 BOOL useTag;
1180
1181 if (!GetIntField(hInf, ServiceSection, L"ServiceType", &ServiceType))
1182 goto cleanup;
1183 if (!GetIntField(hInf, ServiceSection, L"StartType", &StartType))
1184 goto cleanup;
1185 if (!GetIntField(hInf, ServiceSection, L"ErrorControl", &ErrorControl))
1186 goto cleanup;
1187 useTag = (ServiceType == SERVICE_BOOT_START || ServiceType == SERVICE_SYSTEM_START);
1188
1189 hSCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE);
1190 if (hSCManager == NULL)
1191 goto cleanup;
1192
1193 if (!GetLineText(hInf, ServiceSection, L"ServiceBinary", &ServiceBinary))
1194 goto cleanup;
1195
1196 /* Don't check return value, as these fields are optional and
1197 * GetLineText initialize output parameter even on failure */
1198 GetLineText(hInf, ServiceSection, L"LoadOrderGroup", &LoadOrderGroup);
1199 GetLineText(hInf, ServiceSection, L"DisplayName", &DisplayName);
1200 GetLineText(hInf, ServiceSection, L"Description", &Description);
1201 GetLineText(hInf, ServiceSection, L"Dependencies", &Dependencies);
1202
1203 hService = OpenServiceW(
1204 hSCManager,
1205 ServiceName,
1206 GENERIC_READ | GENERIC_WRITE);
1207 if (hService == NULL && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
1208 goto cleanup;
1209
1210 if (hService && (ServiceFlags & SPSVCINST_DELETEEVENTLOGENTRY))
1211 {
1212 ret = DeleteService(hService);
1213 if (!ret && GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
1214 goto cleanup;
1215 }
1216
1217 if (hService == NULL)
1218 {
1219 /* Create new service */
1220 hService = CreateServiceW(
1221 hSCManager,
1222 ServiceName,
1223 DisplayName,
1224 0,
1225 ServiceType,
1226 StartType,
1227 ErrorControl,
1228 ServiceBinary,
1229 LoadOrderGroup,
1230 useTag ? &tagId : NULL,
1231 Dependencies,
1232 NULL, NULL);
1233 if (hService == NULL)
1234 goto cleanup;
1235 }
1236 else
1237 {
1238 DWORD bufferSize;
1239 /* Read current configuration */
1240 if (!QueryServiceConfigW(hService, NULL, 0, &bufferSize))
1241 {
1242 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1243 goto cleanup;
1244 ServiceConfig = MyMalloc(bufferSize);
1245 if (!ServiceConfig)
1246 {
1247 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1248 goto cleanup;
1249 }
1250 if (!QueryServiceConfigW(hService, ServiceConfig, bufferSize, &bufferSize))
1251 goto cleanup;
1252 }
1253 tagId = ServiceConfig->dwTagId;
1254
1255 /* Update configuration */
1256 ret = ChangeServiceConfigW(
1257 hService,
1258 ServiceType,
1259 (ServiceFlags & SPSVCINST_NOCLOBBER_STARTTYPE) ? SERVICE_NO_CHANGE : StartType,
1260 (ServiceFlags & SPSVCINST_NOCLOBBER_ERRORCONTROL) ? SERVICE_NO_CHANGE : ErrorControl,
1261 ServiceBinary,
1262 (ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP && ServiceConfig->lpLoadOrderGroup) ? NULL : LoadOrderGroup,
1263 useTag ? &tagId : NULL,
1264 (ServiceFlags & SPSVCINST_NOCLOBBER_DEPENDENCIES && ServiceConfig->lpDependencies) ? NULL : Dependencies,
1265 NULL, NULL,
1266 (ServiceFlags & SPSVCINST_NOCLOBBER_DISPLAYNAME && ServiceConfig->lpDisplayName) ? NULL : DisplayName);
1267 if (!ret)
1268 goto cleanup;
1269 }
1270
1271 /* FIXME: use Description and SPSVCINST_NOCLOBBER_DESCRIPTION */
1272
1273 if (useTag)
1274 {
1275 /* Add the tag to SYSTEM\CurrentControlSet\Control\GroupOrderList key */
1276 LONG rc;
1277 LPCWSTR lpLoadOrderGroup;
1278 DWORD bufferSize;
1279
1280 lpLoadOrderGroup = LoadOrderGroup;
1281 if ((ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP) && ServiceConfig && ServiceConfig->lpLoadOrderGroup)
1282 lpLoadOrderGroup = ServiceConfig->lpLoadOrderGroup;
1283
1284 rc = RegOpenKey(
1285 list ? list->HKLM : HKEY_LOCAL_MACHINE,
1286 L"SYSTEM\\CurrentControlSet\\Control\\GroupOrderList",
1287 &hGroupOrderListKey);
1288 if (rc != ERROR_SUCCESS)
1289 {
1290 SetLastError(rc);
1291 goto cleanup;
1292 }
1293 rc = RegQueryValueExW(hGroupOrderListKey, lpLoadOrderGroup, NULL, &dwRegType, NULL, &bufferSize);
1294 if (rc == ERROR_FILE_NOT_FOUND)
1295 bufferSize = sizeof(DWORD);
1296 else if (rc != ERROR_SUCCESS)
1297 {
1298 SetLastError(rc);
1299 goto cleanup;
1300 }
1301 else if (dwRegType != REG_BINARY || bufferSize == 0 || bufferSize % sizeof(DWORD) != 0)
1302 {
1303 SetLastError(ERROR_GEN_FAILURE);
1304 goto cleanup;
1305 }
1306 /* Allocate buffer to store existing data + the new tag */
1307 GroupOrder = MyMalloc(bufferSize + sizeof(DWORD));
1308 if (!GroupOrder)
1309 {
1310 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1311 goto cleanup;
1312 }
1313 if (rc == ERROR_SUCCESS)
1314 {
1315 /* Read existing data */
1316 rc = RegQueryValueExW(
1317 hGroupOrderListKey,
1318 lpLoadOrderGroup,
1319 NULL,
1320 NULL,
1321 (BYTE*)GroupOrder,
1322 &bufferSize);
1323 if (rc != ERROR_SUCCESS)
1324 {
1325 SetLastError(rc);
1326 goto cleanup;
1327 }
1328 if (ServiceFlags & SPSVCINST_TAGTOFRONT)
1329 memmove(&GroupOrder[2], &GroupOrder[1], bufferSize - sizeof(DWORD));
1330 }
1331 else
1332 {
1333 GroupOrder[0] = 0;
1334 }
1335 GroupOrder[0]++;
1336 if (ServiceFlags & SPSVCINST_TAGTOFRONT)
1337 GroupOrder[1] = tagId;
1338 else
1339 GroupOrder[bufferSize / sizeof(DWORD)] = tagId;
1340
1341 rc = RegSetValueExW(
1342 hGroupOrderListKey,
1343 lpLoadOrderGroup,
1344 0,
1345 REG_BINARY,
1346 (BYTE*)GroupOrder,
1347 bufferSize + sizeof(DWORD));
1348 if (rc != ERROR_SUCCESS)
1349 {
1350 SetLastError(rc);
1351 goto cleanup;
1352 }
1353 }
1354
1355 ret = TRUE;
1356
1357 cleanup:
1358 if (hSCManager != NULL)
1359 CloseServiceHandle(hSCManager);
1360 if (hService != NULL)
1361 CloseServiceHandle(hService);
1362 if (hGroupOrderListKey != INVALID_HANDLE_VALUE)
1363 RegCloseKey(hGroupOrderListKey);
1364 MyFree(ServiceConfig);
1365 MyFree(ServiceBinary);
1366 MyFree(LoadOrderGroup);
1367 MyFree(DisplayName);
1368 MyFree(Description);
1369 MyFree(Dependencies);
1370 MyFree(GroupOrder);
1371
1372 TRACE("Returning %d\n", ret);
1373 return ret;
1374 }
1375
1376
1377 /***********************************************************************
1378 * SetupInstallServicesFromInfSectionExW (SETUPAPI.@)
1379 */
1380 BOOL WINAPI SetupInstallServicesFromInfSectionExW( HINF hinf, PCWSTR sectionname, DWORD flags, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PVOID reserved1, PVOID reserved2 )
1381 {
1382 struct DeviceInfoSet *list = NULL;
1383 BOOL ret = FALSE;
1384
1385 TRACE("%p, %s, 0x%lx, %p, %p, %p, %p\n", hinf, debugstr_w(sectionname),
1386 flags, DeviceInfoSet, DeviceInfoData, reserved1, reserved2);
1387
1388 if (!sectionname)
1389 SetLastError(ERROR_INVALID_PARAMETER);
1390 else if (flags & ~(SPSVCINST_TAGTOFRONT | SPSVCINST_DELETEEVENTLOGENTRY | SPSVCINST_NOCLOBBER_DISPLAYNAME | SPSVCINST_NOCLOBBER_STARTTYPE | SPSVCINST_NOCLOBBER_ERRORCONTROL | SPSVCINST_NOCLOBBER_LOADORDERGROUP | SPSVCINST_NOCLOBBER_DEPENDENCIES | SPSVCINST_STOPSERVICE))
1391 {
1392 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));
1393 SetLastError(ERROR_INVALID_FLAGS);
1394 }
1395 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
1396 SetLastError(ERROR_INVALID_HANDLE);
1397 else if (DeviceInfoSet && (list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC)
1398 SetLastError(ERROR_INVALID_HANDLE);
1399 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
1400 SetLastError(ERROR_INVALID_USER_BUFFER);
1401 else if (reserved1 != NULL || reserved2 != NULL)
1402 SetLastError(ERROR_INVALID_PARAMETER);
1403 else
1404 {
1405 struct needs_callback_info needs_info;
1406 LPWSTR ServiceName = NULL;
1407 LPWSTR ServiceSection = NULL;
1408 INT ServiceFlags;
1409 INFCONTEXT ContextService;
1410 BOOL bNeedReboot = FALSE;
1411
1412 /* Parse 'Include' and 'Needs' directives */
1413 iterate_section_fields( hinf, sectionname, Include, include_callback, NULL);
1414 needs_info.type = 1;
1415 needs_info.flags = flags;
1416 needs_info.devinfo = DeviceInfoSet;
1417 needs_info.devinfo_data = DeviceInfoData;
1418 needs_info.reserved1 = reserved1;
1419 needs_info.reserved2 = reserved2;
1420 iterate_section_fields( hinf, sectionname, Needs, needs_callback, &needs_info);
1421
1422 if (flags & SPSVCINST_STOPSERVICE)
1423 {
1424 FIXME("Stopping the device not implemented\n");
1425 /* This may lead to require a reboot */
1426 /* bNeedReboot = TRUE; */
1427 #if 0
1428 SERVICE_STATUS ServiceStatus;
1429 ret = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus);
1430 if (!ret && GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
1431 goto cleanup;
1432 if (ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING && ServiceStatus.dwCurrentState != SERVICE_STOPPED)
1433 {
1434 SetLastError(ERROR_INSTALL_SERVICE_FAILURE);
1435 goto cleanup;
1436 }
1437 #endif
1438 flags &= ~SPSVCINST_STOPSERVICE;
1439 }
1440
1441 ret = SetupFindFirstLineW(hinf, sectionname, AddService, &ContextService);
1442 while (ret)
1443 {
1444 if (!GetStringField(&ContextService, 1, &ServiceName))
1445 goto nextservice;
1446
1447 ret = SetupGetIntField(
1448 &ContextService,
1449 2, /* Field index */
1450 &ServiceFlags);
1451 if (!ret)
1452 {
1453 /* The field may be empty. Ignore the error */
1454 ServiceFlags = 0;
1455 }
1456
1457 if (!GetStringField(&ContextService, 3, &ServiceSection))
1458 goto nextservice;
1459
1460 ret = InstallOneService(list, hinf, ServiceSection, ServiceName, (ServiceFlags & ~SPSVCINST_ASSOCSERVICE) | flags);
1461 if (!ret)
1462 goto nextservice;
1463
1464 if (ServiceFlags & SPSVCINST_ASSOCSERVICE)
1465 {
1466 ret = SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet, DeviceInfoData, SPDRP_SERVICE, (LPBYTE)ServiceName, (strlenW(ServiceName) + 1) * sizeof(WCHAR));
1467 if (!ret)
1468 goto nextservice;
1469 }
1470
1471 nextservice:
1472 HeapFree(GetProcessHeap(), 0, ServiceName);
1473 HeapFree(GetProcessHeap(), 0, ServiceSection);
1474 ServiceName = ServiceSection = NULL;
1475 ret = SetupFindNextMatchLineW(&ContextService, AddService, &ContextService);
1476 }
1477
1478 if (bNeedReboot)
1479 SetLastError(ERROR_SUCCESS_REBOOT_REQUIRED);
1480 else
1481 SetLastError(ERROR_SUCCESS);
1482 ret = TRUE;
1483 }
1484
1485 TRACE("Returning %d\n", ret);
1486 return ret;
1487 }