Add SetupPromptReboot stub
[reactos.git] / reactos / lib / setupapi / install.c
1 /*
2 * Setupapi install routines
3 *
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winreg.h"
26 #include "winternl.h"
27 #include "winerror.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "setupapi.h"
32 #include "setupapi_private.h"
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
37
38 /* info passed to callback functions dealing with files */
39 struct files_callback_info
40 {
41 HSPFILEQ queue;
42 PCWSTR src_root;
43 UINT copy_flags;
44 HINF layout;
45 };
46
47 /* info passed to callback functions dealing with the registry */
48 struct registry_callback_info
49 {
50 HKEY default_root;
51 BOOL delete;
52 };
53
54 /* info passed to callback functions dealing with registering dlls */
55 struct register_dll_info
56 {
57 PSP_FILE_CALLBACK_W callback;
58 PVOID callback_context;
59 BOOL unregister;
60 };
61
62 typedef BOOL (*iterate_fields_func)( HINF hinf, PCWSTR field, void *arg );
63
64 /* Unicode constants */
65 static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0};
66 static const WCHAR DelFiles[] = {'D','e','l','F','i','l','e','s',0};
67 static const WCHAR RenFiles[] = {'R','e','n','F','i','l','e','s',0};
68 static const WCHAR Ini2Reg[] = {'I','n','i','2','R','e','g',0};
69 static const WCHAR LogConf[] = {'L','o','g','C','o','n','f',0};
70 static const WCHAR AddReg[] = {'A','d','d','R','e','g',0};
71 static const WCHAR DelReg[] = {'D','e','l','R','e','g',0};
72 static const WCHAR BitReg[] = {'B','i','t','R','e','g',0};
73 static const WCHAR UpdateInis[] = {'U','p','d','a','t','e','I','n','i','s',0};
74 static const WCHAR CopyINF[] = {'C','o','p','y','I','N','F',0};
75 static const WCHAR UpdateIniFields[] = {'U','p','d','a','t','e','I','n','i','F','i','e','l','d','s',0};
76 static const WCHAR RegisterDlls[] = {'R','e','g','i','s','t','e','r','D','l','l','s',0};
77 static const WCHAR UnregisterDlls[] = {'U','n','r','e','g','i','s','t','e','r','D','l','l','s',0};
78 static const WCHAR ProfileItems[] = {'P','r','o','f','i','l','e','I','t','e','m','s',0};
79
80
81 /***********************************************************************
82 * get_field_string
83 *
84 * Retrieve the contents of a field, dynamically growing the buffer if necessary.
85 */
86 static WCHAR *get_field_string( INFCONTEXT *context, DWORD index, WCHAR *buffer,
87 WCHAR *static_buffer, DWORD *size )
88 {
89 DWORD required;
90
91 if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer;
92 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
93 {
94 /* now grow the buffer */
95 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
96 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required*sizeof(WCHAR) ))) return NULL;
97 *size = required;
98 if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer;
99 }
100 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
101 return NULL;
102 }
103
104
105 /***********************************************************************
106 * copy_files_callback
107 *
108 * Called once for each CopyFiles entry in a given section.
109 */
110 static BOOL copy_files_callback( HINF hinf, PCWSTR field, void *arg )
111 {
112 struct files_callback_info *info = arg;
113
114 if (field[0] == '@') /* special case: copy single file */
115 SetupQueueDefaultCopyW( info->queue, info->layout, info->src_root, NULL, field, info->copy_flags );
116 else
117 SetupQueueCopySectionW( info->queue, info->src_root, info->layout, hinf, field, info->copy_flags );
118 return TRUE;
119 }
120
121
122 /***********************************************************************
123 * delete_files_callback
124 *
125 * Called once for each DelFiles entry in a given section.
126 */
127 static BOOL delete_files_callback( HINF hinf, PCWSTR field, void *arg )
128 {
129 struct files_callback_info *info = arg;
130 SetupQueueDeleteSectionW( info->queue, hinf, 0, field );
131 return TRUE;
132 }
133
134
135 /***********************************************************************
136 * rename_files_callback
137 *
138 * Called once for each RenFiles entry in a given section.
139 */
140 static BOOL rename_files_callback( HINF hinf, PCWSTR field, void *arg )
141 {
142 struct files_callback_info *info = arg;
143 SetupQueueRenameSectionW( info->queue, hinf, 0, field );
144 return TRUE;
145 }
146
147
148 /***********************************************************************
149 * get_root_key
150 *
151 * Retrieve the registry root key from its name.
152 */
153 static HKEY get_root_key( const WCHAR *name, HKEY def_root )
154 {
155 static const WCHAR HKCR[] = {'H','K','C','R',0};
156 static const WCHAR HKCU[] = {'H','K','C','U',0};
157 static const WCHAR HKLM[] = {'H','K','L','M',0};
158 static const WCHAR HKU[] = {'H','K','U',0};
159 static const WCHAR HKR[] = {'H','K','R',0};
160
161 if (!strcmpiW( name, HKCR )) return HKEY_CLASSES_ROOT;
162 if (!strcmpiW( name, HKCU )) return HKEY_CURRENT_USER;
163 if (!strcmpiW( name, HKLM )) return HKEY_LOCAL_MACHINE;
164 if (!strcmpiW( name, HKU )) return HKEY_USERS;
165 if (!strcmpiW( name, HKR )) return def_root;
166 return 0;
167 }
168
169
170 /***********************************************************************
171 * append_multi_sz_value
172 *
173 * Append a multisz string to a multisz registry value.
174 */
175 static void append_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *strings,
176 DWORD str_size )
177 {
178 DWORD size, type, total;
179 WCHAR *buffer, *p;
180
181 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
182 if (type != REG_MULTI_SZ) return;
183
184 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return;
185 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
186
187 /* compare each string against all the existing ones */
188 total = size;
189 while (*strings)
190 {
191 int len = strlenW(strings) + 1;
192
193 for (p = buffer; *p; p += strlenW(p) + 1)
194 if (!strcmpiW( p, strings )) break;
195
196 if (!*p) /* not found, need to append it */
197 {
198 memcpy( p, strings, len * sizeof(WCHAR) );
199 p[len] = 0;
200 total += len;
201 }
202 strings += len;
203 }
204 if (total != size)
205 {
206 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) );
207 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total );
208 }
209 done:
210 HeapFree( GetProcessHeap(), 0, buffer );
211 }
212
213
214 /***********************************************************************
215 * delete_multi_sz_value
216 *
217 * Remove a string from a multisz registry value.
218 */
219 static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string )
220 {
221 DWORD size, type;
222 WCHAR *buffer, *src, *dst;
223
224 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
225 if (type != REG_MULTI_SZ) return;
226 /* allocate double the size, one for value before and one for after */
227 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return;
228 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
229 src = buffer;
230 dst = buffer + size;
231 while (*src)
232 {
233 int len = strlenW(src) + 1;
234 if (strcmpiW( src, string ))
235 {
236 memcpy( dst, src, len * sizeof(WCHAR) );
237 dst += len;
238 }
239 src += len;
240 }
241 *dst++ = 0;
242 if (dst != buffer + 2*size) /* did we remove something? */
243 {
244 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) );
245 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ,
246 (BYTE *)(buffer + size), dst - (buffer + size) );
247 }
248 done:
249 HeapFree( GetProcessHeap(), 0, buffer );
250 }
251
252
253 /***********************************************************************
254 * do_reg_operation
255 *
256 * Perform an add/delete registry operation depending on the flags.
257 */
258 static BOOL do_reg_operation( HKEY hkey, const WCHAR *value, INFCONTEXT *context, INT flags )
259 {
260 DWORD type, size;
261
262 if (flags & (FLG_ADDREG_DELREG_BIT | FLG_ADDREG_DELVAL)) /* deletion */
263 {
264 if (*value && !(flags & FLG_DELREG_KEYONLY_COMMON))
265 {
266 if ((flags & FLG_DELREG_MULTI_SZ_DELSTRING) == FLG_DELREG_MULTI_SZ_DELSTRING)
267 {
268 WCHAR *str;
269
270 if (!SetupGetStringFieldW( context, 5, NULL, 0, &size ) || !size) return TRUE;
271 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
272 SetupGetStringFieldW( context, 5, str, size, NULL );
273 delete_multi_sz_value( hkey, value, str );
274 HeapFree( GetProcessHeap(), 0, str );
275 }
276 else RegDeleteValueW( hkey, value );
277 }
278 else RegDeleteKeyW( hkey, NULL );
279 return TRUE;
280 }
281
282 if (flags & (FLG_ADDREG_KEYONLY|FLG_ADDREG_KEYONLY_COMMON)) return TRUE;
283
284 if (flags & (FLG_ADDREG_NOCLOBBER|FLG_ADDREG_OVERWRITEONLY))
285 {
286 BOOL exists = !RegQueryValueExW( hkey, value, NULL, NULL, NULL, NULL );
287 if (exists && (flags & FLG_ADDREG_NOCLOBBER)) return TRUE;
288 if (!exists & (flags & FLG_ADDREG_OVERWRITEONLY)) return TRUE;
289 }
290
291 switch(flags & FLG_ADDREG_TYPE_MASK)
292 {
293 case FLG_ADDREG_TYPE_SZ: type = REG_SZ; break;
294 case FLG_ADDREG_TYPE_MULTI_SZ: type = REG_MULTI_SZ; break;
295 case FLG_ADDREG_TYPE_EXPAND_SZ: type = REG_EXPAND_SZ; break;
296 case FLG_ADDREG_TYPE_BINARY: type = REG_BINARY; break;
297 case FLG_ADDREG_TYPE_DWORD: type = REG_DWORD; break;
298 case FLG_ADDREG_TYPE_NONE: type = REG_NONE; break;
299 default: type = flags >> 16; break;
300 }
301
302 if (!(flags & FLG_ADDREG_BINVALUETYPE) ||
303 (type == REG_DWORD && SetupGetFieldCount(context) == 5))
304 {
305 static const WCHAR empty;
306 WCHAR *str = NULL;
307
308 if (type == REG_MULTI_SZ)
309 {
310 if (!SetupGetMultiSzFieldW( context, 5, NULL, 0, &size )) size = 0;
311 if (size)
312 {
313 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
314 SetupGetMultiSzFieldW( context, 5, str, size, NULL );
315 }
316 if (flags & FLG_ADDREG_APPEND)
317 {
318 if (!str) return TRUE;
319 append_multi_sz_value( hkey, value, str, size );
320 HeapFree( GetProcessHeap(), 0, str );
321 return TRUE;
322 }
323 /* else fall through to normal string handling */
324 }
325 else
326 {
327 if (!SetupGetStringFieldW( context, 5, NULL, 0, &size )) size = 0;
328 if (size)
329 {
330 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
331 SetupGetStringFieldW( context, 5, str, size, NULL );
332 }
333 }
334
335 if (type == REG_DWORD)
336 {
337 DWORD dw = str ? strtoulW( str, NULL, 0 ) : 0;
338 TRACE( "setting dword %s to %lx\n", debugstr_w(value), dw );
339 RegSetValueExW( hkey, value, 0, type, (BYTE *)&dw, sizeof(dw) );
340 }
341 else
342 {
343 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(str) );
344 if (str) RegSetValueExW( hkey, value, 0, type, (BYTE *)str, size * sizeof(WCHAR) );
345 else RegSetValueExW( hkey, value, 0, type, (const BYTE *)&empty, sizeof(WCHAR) );
346 }
347 HeapFree( GetProcessHeap(), 0, str );
348 return TRUE;
349 }
350 else /* get the binary data */
351 {
352 BYTE *data = NULL;
353
354 if (!SetupGetBinaryField( context, 5, NULL, 0, &size )) size = 0;
355 if (size)
356 {
357 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
358 TRACE( "setting binary data %s len %ld\n", debugstr_w(value), size );
359 SetupGetBinaryField( context, 5, data, size, NULL );
360 }
361 RegSetValueExW( hkey, value, 0, type, data, size );
362 HeapFree( GetProcessHeap(), 0, data );
363 return TRUE;
364 }
365 }
366
367
368 /***********************************************************************
369 * registry_callback
370 *
371 * Called once for each AddReg and DelReg entry in a given section.
372 */
373 static BOOL registry_callback( HINF hinf, PCWSTR field, void *arg )
374 {
375 struct registry_callback_info *info = arg;
376 INFCONTEXT context;
377 HKEY root_key, hkey;
378
379 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
380
381 for (; ok; ok = SetupFindNextLine( &context, &context ))
382 {
383 WCHAR buffer[MAX_INF_STRING_LENGTH];
384 INT flags;
385
386 /* get root */
387 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
388 continue;
389 if (!(root_key = get_root_key( buffer, info->default_root )))
390 continue;
391
392 /* get key */
393 if (!SetupGetStringFieldW( &context, 2, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
394 *buffer = 0;
395
396 /* get flags */
397 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
398
399 if (!info->delete)
400 {
401 if (flags & FLG_ADDREG_DELREG_BIT) continue; /* ignore this entry */
402 }
403 else
404 {
405 if (!flags) flags = FLG_ADDREG_DELREG_BIT;
406 else if (!(flags & FLG_ADDREG_DELREG_BIT)) continue; /* ignore this entry */
407 }
408
409 if (info->delete || (flags & FLG_ADDREG_OVERWRITEONLY))
410 {
411 if (RegOpenKeyW( root_key, buffer, &hkey )) continue; /* ignore if it doesn't exist */
412 }
413 else if (RegCreateKeyW( root_key, buffer, &hkey ))
414 {
415 ERR( "could not create key %p %s\n", root_key, debugstr_w(buffer) );
416 continue;
417 }
418 TRACE( "key %p %s\n", root_key, debugstr_w(buffer) );
419
420 /* get value name */
421 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
422 *buffer = 0;
423
424 /* and now do it */
425 if (!do_reg_operation( hkey, buffer, &context, flags ))
426 {
427 RegCloseKey( hkey );
428 return FALSE;
429 }
430 RegCloseKey( hkey );
431 }
432 return TRUE;
433 }
434
435
436 /***********************************************************************
437 * do_register_dll
438 *
439 * Register or unregister a dll.
440 */
441 static BOOL do_register_dll( const struct register_dll_info *info, const WCHAR *path,
442 INT flags, INT timeout, const WCHAR *args )
443 {
444 HMODULE module;
445 HRESULT res;
446 SP_REGISTER_CONTROL_STATUSW status;
447
448 status.cbSize = sizeof(status);
449 status.FileName = path;
450 status.FailureCode = SPREG_SUCCESS;
451 status.Win32Error = ERROR_SUCCESS;
452
453 if (info->callback)
454 {
455 switch(info->callback( info->callback_context, SPFILENOTIFY_STARTREGISTRATION,
456 (UINT_PTR)&status, !info->unregister ))
457 {
458 case FILEOP_ABORT:
459 SetLastError( ERROR_OPERATION_ABORTED );
460 return FALSE;
461 case FILEOP_SKIP:
462 return TRUE;
463 case FILEOP_DOIT:
464 break;
465 }
466 }
467
468 if (!(module = LoadLibraryExW( path, 0, LOAD_WITH_ALTERED_SEARCH_PATH )))
469 {
470 WARN( "could not load %s\n", debugstr_w(path) );
471 status.FailureCode = SPREG_LOADLIBRARY;
472 status.Win32Error = GetLastError();
473 goto done;
474 }
475
476 if (flags & FLG_REGSVR_DLLREGISTER)
477 {
478 const char *entry_point = info->unregister ? "DllUnregisterServer" : "DllRegisterServer";
479 HRESULT (WINAPI *func)(void) = (void *)GetProcAddress( module, entry_point );
480
481 if (!func)
482 {
483 status.FailureCode = SPREG_GETPROCADDR;
484 status.Win32Error = GetLastError();
485 goto done;
486 }
487
488 TRACE( "calling %s in %s\n", entry_point, debugstr_w(path) );
489 res = func();
490
491 if (FAILED(res))
492 {
493 WARN( "calling %s in %s returned error %lx\n", entry_point, debugstr_w(path), res );
494 status.FailureCode = SPREG_REGSVR;
495 status.Win32Error = res;
496 goto done;
497 }
498 }
499
500 if (flags & FLG_REGSVR_DLLINSTALL)
501 {
502 HRESULT (WINAPI *func)(BOOL,LPCWSTR) = (void *)GetProcAddress( module, "DllInstall" );
503
504 if (!func)
505 {
506 status.FailureCode = SPREG_GETPROCADDR;
507 status.Win32Error = GetLastError();
508 goto done;
509 }
510
511 TRACE( "calling DllInstall(%d,%s) in %s\n",
512 !info->unregister, debugstr_w(args), debugstr_w(path) );
513 res = func( !info->unregister, args );
514
515 if (FAILED(res))
516 {
517 WARN( "calling DllInstall in %s returned error %lx\n", debugstr_w(path), res );
518 status.FailureCode = SPREG_REGSVR;
519 status.Win32Error = res;
520 goto done;
521 }
522 }
523
524 done:
525 if (module) FreeLibrary( module );
526 if (info->callback) info->callback( info->callback_context, SPFILENOTIFY_ENDREGISTRATION,
527 (UINT_PTR)&status, !info->unregister );
528 return TRUE;
529 }
530
531
532 /***********************************************************************
533 * register_dlls_callback
534 *
535 * Called once for each RegisterDlls entry in a given section.
536 */
537 static BOOL register_dlls_callback( HINF hinf, PCWSTR field, void *arg )
538 {
539 struct register_dll_info *info = arg;
540 INFCONTEXT context;
541 BOOL ret = TRUE;
542 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
543
544 for (; ok; ok = SetupFindNextLine( &context, &context ))
545 {
546 WCHAR *path, *args, *p;
547 WCHAR buffer[MAX_INF_STRING_LENGTH];
548 INT flags, timeout;
549
550 /* get directory */
551 if (!(path = PARSER_get_dest_dir( &context ))) continue;
552
553 /* get dll name */
554 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
555 goto done;
556 if (!(p = HeapReAlloc( GetProcessHeap(), 0, path,
557 (strlenW(path) + strlenW(buffer) + 2) * sizeof(WCHAR) ))) goto done;
558 path = p;
559 p += strlenW(p);
560 if (p == path || p[-1] != '\\') *p++ = '\\';
561 strcpyW( p, buffer );
562
563 /* get flags */
564 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
565
566 /* get timeout */
567 if (!SetupGetIntField( &context, 5, &timeout )) timeout = 60;
568
569 /* get command line */
570 args = NULL;
571 if (SetupGetStringFieldW( &context, 6, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
572 args = buffer;
573
574 ret = do_register_dll( info, path, flags, timeout, args );
575
576 done:
577 HeapFree( GetProcessHeap(), 0, path );
578 if (!ret) break;
579 }
580 return ret;
581 }
582
583 /***********************************************************************
584 * update_ini_callback
585 *
586 * Called once for each UpdateInis entry in a given section.
587 */
588 static BOOL update_ini_callback( HINF hinf, PCWSTR field, void *arg )
589 {
590 INFCONTEXT context;
591
592 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
593
594 for (; ok; ok = SetupFindNextLine( &context, &context ))
595 {
596 WCHAR buffer[MAX_INF_STRING_LENGTH];
597 WCHAR filename[MAX_INF_STRING_LENGTH];
598 WCHAR section[MAX_INF_STRING_LENGTH];
599 WCHAR entry[MAX_INF_STRING_LENGTH];
600 WCHAR string[MAX_INF_STRING_LENGTH];
601 LPWSTR divider;
602
603 if (!SetupGetStringFieldW( &context, 1, filename,
604 sizeof(filename)/sizeof(WCHAR), NULL ))
605 continue;
606
607 if (!SetupGetStringFieldW( &context, 2, section,
608 sizeof(section)/sizeof(WCHAR), NULL ))
609 continue;
610
611 if (!SetupGetStringFieldW( &context, 4, buffer,
612 sizeof(buffer)/sizeof(WCHAR), NULL ))
613 continue;
614
615 divider = strchrW(buffer,'=');
616 if (divider)
617 {
618 *divider = 0;
619 strcpyW(entry,buffer);
620 divider++;
621 strcpyW(string,divider);
622 }
623 else
624 {
625 strcpyW(entry,buffer);
626 string[0]=0;
627 }
628
629 TRACE("Writing %s = %s in %s of file %s\n",debugstr_w(entry),
630 debugstr_w(string),debugstr_w(section),debugstr_w(filename));
631 WritePrivateProfileStringW(section,entry,string,filename);
632
633 }
634 return TRUE;
635 }
636
637 static BOOL update_ini_fields_callback( HINF hinf, PCWSTR field, void *arg )
638 {
639 FIXME( "should update ini fields %s\n", debugstr_w(field) );
640 return TRUE;
641 }
642
643 static BOOL ini2reg_callback( HINF hinf, PCWSTR field, void *arg )
644 {
645 FIXME( "should do ini2reg %s\n", debugstr_w(field) );
646 return TRUE;
647 }
648
649 static BOOL logconf_callback( HINF hinf, PCWSTR field, void *arg )
650 {
651 FIXME( "should do logconf %s\n", debugstr_w(field) );
652 return TRUE;
653 }
654
655 static BOOL bitreg_callback( HINF hinf, PCWSTR field, void *arg )
656 {
657 FIXME( "should do bitreg %s\n", debugstr_w(field) );
658 return TRUE;
659 }
660
661 static BOOL profile_items_callback( HINF hinf, PCWSTR field, void *arg )
662 {
663 FIXME( "should do profile items %s\n", debugstr_w(field) );
664 return TRUE;
665 }
666
667 static BOOL copy_inf_callback( HINF hinf, PCWSTR field, void *arg )
668 {
669 FIXME( "should do copy inf %s\n", debugstr_w(field) );
670 return TRUE;
671 }
672
673
674 /***********************************************************************
675 * iterate_section_fields
676 *
677 * Iterate over all fields of a certain key of a certain section
678 */
679 static BOOL iterate_section_fields( HINF hinf, PCWSTR section, PCWSTR key,
680 iterate_fields_func callback, void *arg )
681 {
682 WCHAR static_buffer[200];
683 WCHAR *buffer = static_buffer;
684 DWORD size = sizeof(static_buffer)/sizeof(WCHAR);
685 INFCONTEXT context;
686 BOOL ret = FALSE;
687
688 BOOL ok = SetupFindFirstLineW( hinf, section, key, &context );
689 while (ok)
690 {
691 UINT i, count = SetupGetFieldCount( &context );
692 for (i = 1; i <= count; i++)
693 {
694 if (!(buffer = get_field_string( &context, i, buffer, static_buffer, &size )))
695 goto done;
696 if (!callback( hinf, buffer, arg ))
697 {
698 WARN("callback failed for %s %s err %ld\n",
699 debugstr_w(section), debugstr_w(buffer), GetLastError() );
700 goto done;
701 }
702 }
703 ok = SetupFindNextMatchLineW( &context, key, &context );
704 }
705 ret = TRUE;
706 done:
707 if (buffer && buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
708 return ret;
709 }
710
711
712 /***********************************************************************
713 * SetupInstallFilesFromInfSectionA (SETUPAPI.@)
714 */
715 BOOL WINAPI SetupInstallFilesFromInfSectionA( HINF hinf, HINF hlayout, HSPFILEQ queue,
716 PCSTR section, PCSTR src_root, UINT flags )
717 {
718 UNICODE_STRING sectionW;
719 BOOL ret = FALSE;
720
721 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
722 {
723 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
724 return FALSE;
725 }
726 if (!src_root)
727 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
728 NULL, flags );
729 else
730 {
731 UNICODE_STRING srcW;
732 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
733 {
734 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
735 srcW.Buffer, flags );
736 RtlFreeUnicodeString( &srcW );
737 }
738 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
739 }
740 RtlFreeUnicodeString( &sectionW );
741 return ret;
742 }
743
744
745 /***********************************************************************
746 * SetupInstallFilesFromInfSectionW (SETUPAPI.@)
747 */
748 BOOL WINAPI SetupInstallFilesFromInfSectionW( HINF hinf, HINF hlayout, HSPFILEQ queue,
749 PCWSTR section, PCWSTR src_root, UINT flags )
750 {
751 struct files_callback_info info;
752
753 info.queue = queue;
754 info.src_root = src_root;
755 info.copy_flags = flags;
756 info.layout = hlayout;
757 return iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info );
758 }
759
760
761 /***********************************************************************
762 * SetupInstallFromInfSectionA (SETUPAPI.@)
763 */
764 BOOL WINAPI SetupInstallFromInfSectionA( HWND owner, HINF hinf, PCSTR section, UINT flags,
765 HKEY key_root, PCSTR src_root, UINT copy_flags,
766 PSP_FILE_CALLBACK_A callback, PVOID context,
767 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
768 {
769 UNICODE_STRING sectionW, src_rootW;
770 struct callback_WtoA_context ctx;
771 BOOL ret = FALSE;
772
773 src_rootW.Buffer = NULL;
774 if (src_root && !RtlCreateUnicodeStringFromAsciiz( &src_rootW, src_root ))
775 {
776 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
777 return FALSE;
778 }
779
780 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
781 {
782 ctx.orig_context = context;
783 ctx.orig_handler = callback;
784 ret = SetupInstallFromInfSectionW( owner, hinf, sectionW.Buffer, flags, key_root,
785 src_rootW.Buffer, copy_flags, QUEUE_callback_WtoA,
786 &ctx, devinfo, devinfo_data );
787 RtlFreeUnicodeString( &sectionW );
788 }
789 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
790
791 RtlFreeUnicodeString( &src_rootW );
792 return ret;
793 }
794
795
796 /***********************************************************************
797 * SetupInstallFromInfSectionW (SETUPAPI.@)
798 */
799 BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section, UINT flags,
800 HKEY key_root, PCWSTR src_root, UINT copy_flags,
801 PSP_FILE_CALLBACK_W callback, PVOID context,
802 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
803 {
804 if (flags & SPINST_FILES)
805 {
806 struct files_callback_info info;
807 HSPFILEQ queue;
808 BOOL ret;
809
810 if (!(queue = SetupOpenFileQueue())) return FALSE;
811 info.queue = queue;
812 info.src_root = src_root;
813 info.copy_flags = copy_flags;
814 info.layout = hinf;
815 ret = (iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ) &&
816 iterate_section_fields( hinf, section, DelFiles, delete_files_callback, &info ) &&
817 iterate_section_fields( hinf, section, RenFiles, rename_files_callback, &info ) &&
818 SetupCommitFileQueueW( owner, queue, callback, context ));
819 SetupCloseFileQueue( queue );
820 if (!ret) return FALSE;
821 }
822 if (flags & SPINST_INIFILES)
823 {
824 if (!iterate_section_fields( hinf, section, UpdateInis, update_ini_callback, NULL ) ||
825 !iterate_section_fields( hinf, section, UpdateIniFields,
826 update_ini_fields_callback, NULL ))
827 return FALSE;
828 }
829 if (flags & SPINST_INI2REG)
830 {
831 if (!iterate_section_fields( hinf, section, Ini2Reg, ini2reg_callback, NULL ))
832 return FALSE;
833 }
834 if (flags & SPINST_LOGCONFIG)
835 {
836 if (!iterate_section_fields( hinf, section, LogConf, logconf_callback, NULL ))
837 return FALSE;
838 }
839 if (flags & SPINST_REGSVR)
840 {
841 struct register_dll_info info;
842
843 info.unregister = FALSE;
844 if (flags & SPINST_REGISTERCALLBACKAWARE)
845 {
846 info.callback = callback;
847 info.callback_context = context;
848 }
849 else info.callback = NULL;
850
851 if (!iterate_section_fields( hinf, section, RegisterDlls, register_dlls_callback, &info ))
852 return FALSE;
853 }
854 if (flags & SPINST_UNREGSVR)
855 {
856 struct register_dll_info info;
857
858 info.unregister = TRUE;
859 if (flags & SPINST_REGISTERCALLBACKAWARE)
860 {
861 info.callback = callback;
862 info.callback_context = context;
863 }
864 else info.callback = NULL;
865
866 if (!iterate_section_fields( hinf, section, UnregisterDlls, register_dlls_callback, &info ))
867 return FALSE;
868 }
869 if (flags & SPINST_REGISTRY)
870 {
871 struct registry_callback_info info;
872
873 info.default_root = key_root;
874 info.delete = TRUE;
875 if (!iterate_section_fields( hinf, section, DelReg, registry_callback, &info ))
876 return FALSE;
877 info.delete = FALSE;
878 if (!iterate_section_fields( hinf, section, AddReg, registry_callback, &info ))
879 return FALSE;
880 }
881 if (flags & SPINST_BITREG)
882 {
883 if (!iterate_section_fields( hinf, section, BitReg, bitreg_callback, NULL ))
884 return FALSE;
885 }
886 if (flags & SPINST_PROFILEITEMS)
887 {
888 if (!iterate_section_fields( hinf, section, ProfileItems, profile_items_callback, NULL ))
889 return FALSE;
890 }
891 if (flags & SPINST_COPYINF)
892 {
893 if (!iterate_section_fields( hinf, section, CopyINF, copy_inf_callback, NULL ))
894 return FALSE;
895 }
896
897 return TRUE;
898 }
899
900
901 /***********************************************************************
902 * InstallHinfSectionW (SETUPAPI.@)
903 *
904 * NOTE: 'cmdline' is <section> <mode> <path> from
905 * RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection <section> <mode> <path>
906 */
907 void WINAPI InstallHinfSectionW( HWND hwnd, HINSTANCE handle, LPCWSTR cmdline, INT show )
908 {
909 WCHAR *p, *path, section[MAX_PATH];
910 void *callback_context;
911 UINT mode;
912 HINF hinf;
913
914 TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd, handle, debugstr_w(cmdline));
915
916 lstrcpynW( section, cmdline, sizeof(section)/sizeof(WCHAR) );
917
918 if (!(p = strchrW( section, ' ' ))) return;
919 *p++ = 0;
920 while (*p == ' ') p++;
921 mode = atoiW( p );
922
923 if (!(p = strchrW( p, ' ' ))) return;
924 path = p + 1;
925 while (*path == ' ') path++;
926
927 hinf = SetupOpenInfFileW( path, NULL, INF_STYLE_WIN4, NULL );
928 if (hinf == INVALID_HANDLE_VALUE) return;
929
930 callback_context = SetupInitDefaultQueueCallback( hwnd );
931 SetupInstallFromInfSectionW( hwnd, hinf, section, SPINST_ALL, NULL, NULL, SP_COPY_NEWER,
932 SetupDefaultQueueCallbackW, callback_context,
933 NULL, NULL );
934 SetupTermDefaultQueueCallback( callback_context );
935 SetupCloseInfFile( hinf );
936
937 /* FIXME: should check the mode and maybe reboot */
938 /* there isn't much point in doing that since we */
939 /* don't yet handle deferred file copies anyway. */
940 }
941
942
943 /***********************************************************************
944 * InstallHinfSectionA (SETUPAPI.@)
945 */
946 void WINAPI InstallHinfSectionA( HWND hwnd, HINSTANCE handle, LPCSTR cmdline, INT show )
947 {
948 UNICODE_STRING cmdlineW;
949
950 if (RtlCreateUnicodeStringFromAsciiz( &cmdlineW, cmdline ))
951 {
952 InstallHinfSectionW( hwnd, handle, cmdlineW.Buffer, show );
953 RtlFreeUnicodeString( &cmdlineW );
954 }
955 }
956
957
958 /***********************************************************************
959 * SetupInstallServicesFromInfSectionA (SETUPAPI.@)
960 */
961 BOOL WINAPI SetupInstallServicesFromInfSectionA( HINF hinf, PCSTR sectionname, DWORD flags )
962 {
963 return SetupInstallServicesFromInfSectionExA( hinf, sectionname, flags,
964 NULL, NULL, NULL, NULL );
965 }
966
967
968 /***********************************************************************
969 * SetupInstallServicesFromInfSectionW (SETUPAPI.@)
970 */
971 BOOL WINAPI SetupInstallServicesFromInfSectionW( HINF hinf, PCWSTR sectionname, DWORD flags )
972 {
973 return SetupInstallServicesFromInfSectionExW( hinf, sectionname, flags,
974 NULL, NULL, NULL, NULL );
975 }
976
977
978 /***********************************************************************
979 * SetupInstallServicesFromInfSectionExA (SETUPAPI.@)
980 */
981 BOOL WINAPI SetupInstallServicesFromInfSectionExA( HINF hinf, PCSTR sectionname, DWORD flags, HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data, PVOID reserved1, PVOID reserved2 )
982 {
983 UNICODE_STRING sectionnameW;
984 BOOL ret = FALSE;
985
986 if (RtlCreateUnicodeStringFromAsciiz( &sectionnameW, sectionname ))
987 {
988 ret = SetupInstallServicesFromInfSectionExW( hinf, sectionnameW.Buffer, flags, devinfo, devinfo_data, reserved1, reserved2 );
989 RtlFreeUnicodeString( &sectionnameW );
990 }
991 else
992 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
993
994 return ret;
995 }
996
997
998 static BOOL GetLineText( HINF hinf, PCWSTR section_name, PCWSTR key_name, PWSTR *value)
999 {
1000 DWORD required;
1001 PWSTR buf = NULL;
1002
1003 *value = NULL;
1004
1005 if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, NULL, 0, &required )
1006 && GetLastError() != ERROR_INSUFFICIENT_BUFFER )
1007 return FALSE;
1008
1009 buf = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) );
1010 if ( ! buf )
1011 {
1012 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1013 return FALSE;
1014 }
1015
1016 if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, buf, required, &required ) )
1017 {
1018 HeapFree( GetProcessHeap(), 0, buf );
1019 return FALSE;
1020 }
1021
1022 *value = buf;
1023 return TRUE;
1024 }
1025
1026
1027 static BOOL GetIntField( HINF hinf, PCWSTR section_name, PCWSTR key_name, INT *value)
1028 {
1029 LPWSTR buffer, end;
1030 INT res;
1031
1032 if (! GetLineText( hinf, section_name, key_name, &buffer ) )
1033 return FALSE;
1034
1035 res = wcstol( buffer, &end, 0 );
1036 if (end != buffer && !*end)
1037 {
1038 HeapFree(GetProcessHeap(), 0, buffer);
1039 *value = res;
1040 return TRUE;
1041 }
1042 else
1043 {
1044 HeapFree(GetProcessHeap(), 0, buffer);
1045 SetLastError( ERROR_INVALID_DATA );
1046 return FALSE;
1047 }
1048 }
1049
1050
1051 /***********************************************************************
1052 * SetupInstallServicesFromInfSectionExW (SETUPAPI.@)
1053 */
1054 BOOL WINAPI SetupInstallServicesFromInfSectionExW( HINF hinf, PCWSTR sectionname, DWORD flags, HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data, PVOID reserved1, PVOID reserved2 )
1055 {
1056 SC_HANDLE hSCManager, hService;
1057 LPWSTR ServiceBinary, LoadOrderGroup;
1058 LPWSTR DisplayName, Description, Dependencies;
1059 INT ServiceType, StartType, ErrorControl;
1060
1061 TRACE("%p, %s, 0x%lx, %p, %p, %p, %p\n", hinf, debugstr_w(sectionname),
1062 flags, devinfo, devinfo_data, reserved1, reserved2);
1063
1064 if (!reserved1)
1065 {
1066 /* FIXME: I don't know how to get the service name. ATM, just fail the call */
1067 DPRINT1("Service name not specified!\n");
1068 return FALSE;
1069 }
1070 /* FIXME: use the flags parameters */
1071 /* FIXME: use DeviceInfoSet, DeviceInfoData parameters */
1072
1073 if (!GetIntField(hinf, sectionname, L"ServiceType", &ServiceType))
1074 return FALSE;
1075 if (!GetIntField(hinf, sectionname, L"StartType", &StartType))
1076 return FALSE;
1077 if (!GetIntField(hinf, sectionname, L"ErrorControl", &ErrorControl))
1078 return FALSE;
1079
1080 hSCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE);
1081 if (hSCManager == NULL)
1082 return FALSE;
1083
1084 if (!GetLineText(hinf, sectionname, L"ServiceBinary", &ServiceBinary))
1085 {
1086 CloseServiceHandle(hSCManager);
1087 return FALSE;
1088 }
1089 if (!GetLineText(hinf, sectionname, L"LoadOrderGroup", &LoadOrderGroup))
1090 /* LoadOrderGroup value is optional. Ignore the error */
1091 LoadOrderGroup = NULL;
1092
1093 /* Don't check return value, as these fields are optional and
1094 * GetLineText initialize output parameter even on failure */
1095 GetLineText(hinf, sectionname, L"DisplayName", &DisplayName);
1096 GetLineText(hinf, sectionname, L"Description", &Description);
1097 GetLineText(hinf, sectionname, L"Dependencies", &Dependencies);
1098
1099 hService = CreateServiceW(
1100 hSCManager,
1101 reserved1,
1102 Description,
1103 0,
1104 ServiceType,
1105 StartType,
1106 ErrorControl,
1107 ServiceBinary,
1108 LoadOrderGroup,
1109 NULL,
1110 Dependencies,
1111 NULL, NULL);
1112 HeapFree(GetProcessHeap(), 0, ServiceBinary);
1113 HeapFree(GetProcessHeap(), 0, LoadOrderGroup);
1114 HeapFree(GetProcessHeap(), 0, DisplayName);
1115 HeapFree(GetProcessHeap(), 0, Description);
1116 HeapFree(GetProcessHeap(), 0, Dependencies);
1117 if (hService == NULL)
1118 {
1119 CloseServiceHandle(hSCManager);
1120 return FALSE;
1121 }
1122 CloseServiceHandle(hService);
1123
1124 return CloseServiceHandle(hSCManager);
1125 }