ea0943cb46722b9265376c35cee3efd46c44051b
[reactos.git] / reactos / dll / win32 / setupapi / install.c
1 /*
2 * Setupapi install routines
3 *
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
5 * 2005-2006 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*)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*)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 = NULL;
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 != NULL)
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 }
1488
1489
1490 /***********************************************************************
1491 * SetupCopyOEMInfA (SETUPAPI.@)
1492 */
1493 BOOL WINAPI SetupCopyOEMInfA(
1494 IN PCSTR SourceInfFileName,
1495 IN PCSTR OEMSourceMediaLocation,
1496 IN DWORD OEMSourceMediaType,
1497 IN DWORD CopyStyle,
1498 OUT PSTR DestinationInfFileName OPTIONAL,
1499 IN DWORD DestinationInfFileNameSize,
1500 OUT PDWORD RequiredSize OPTIONAL,
1501 OUT PSTR* DestinationInfFileNameComponent OPTIONAL)
1502 {
1503 PWSTR SourceInfFileNameW = NULL;
1504 PWSTR OEMSourceMediaLocationW = NULL;
1505 PWSTR DestinationInfFileNameW = NULL;
1506 PWSTR DestinationInfFileNameComponentW = NULL;
1507 BOOL ret = FALSE;
1508
1509 TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n",
1510 SourceInfFileName, OEMSourceMediaLocation, OEMSourceMediaType,
1511 CopyStyle, DestinationInfFileName, DestinationInfFileNameSize,
1512 RequiredSize, DestinationInfFileNameComponent);
1513
1514 if (!DestinationInfFileName && DestinationInfFileNameSize > 0)
1515 SetLastError(ERROR_INVALID_PARAMETER);
1516 else if (!(SourceInfFileNameW = MultiByteToUnicode(SourceInfFileName, CP_ACP)))
1517 SetLastError(ERROR_INVALID_PARAMETER);
1518 else if (!(OEMSourceMediaLocationW = MultiByteToUnicode(OEMSourceMediaLocation, CP_ACP)))
1519 SetLastError(ERROR_INVALID_PARAMETER);
1520 else
1521 {
1522 if (DestinationInfFileNameSize != 0)
1523 {
1524 DestinationInfFileNameW = MyMalloc(DestinationInfFileNameSize * sizeof(WCHAR));
1525 if (!DestinationInfFileNameW)
1526 {
1527 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1528 goto cleanup;
1529 }
1530 }
1531
1532 ret = SetupCopyOEMInfW(
1533 SourceInfFileNameW,
1534 OEMSourceMediaLocationW,
1535 OEMSourceMediaType,
1536 CopyStyle,
1537 DestinationInfFileNameW,
1538 DestinationInfFileNameSize,
1539 RequiredSize,
1540 DestinationInfFileNameComponent ? &DestinationInfFileNameComponentW : NULL);
1541 if (!ret)
1542 goto cleanup;
1543
1544 if (DestinationInfFileNameSize != 0)
1545 {
1546 if (WideCharToMultiByte(CP_ACP, 0, DestinationInfFileNameW, -1,
1547 DestinationInfFileName, DestinationInfFileNameSize, NULL, NULL) == 0)
1548 {
1549 DestinationInfFileName[0] = '\0';
1550 goto cleanup;
1551 }
1552 }
1553 if (DestinationInfFileNameComponent)
1554 {
1555 if (DestinationInfFileNameComponentW)
1556 *DestinationInfFileNameComponent = &DestinationInfFileName[DestinationInfFileNameComponentW - DestinationInfFileNameW];
1557 else
1558 *DestinationInfFileNameComponent = NULL;
1559 }
1560 ret = TRUE;
1561 }
1562
1563 cleanup:
1564 MyFree(SourceInfFileNameW);
1565 MyFree(OEMSourceMediaLocationW);
1566 MyFree(DestinationInfFileNameW);
1567
1568 TRACE("Returning %d\n", ret);
1569 return ret;
1570 }