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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "setupapi_private.h"
23
24 #include <winsvc.h>
25 #include <ndk/cmfuncs.h>
26
27 /* Unicode constants */
28 static const WCHAR BackSlash[] = {'\\',0};
29 static const WCHAR GroupOrderListKey[] = {'S','Y','S','T','E','M','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','G','r','o','u','p','O','r','d','e','r','L','i','s','t',0};
30 static const WCHAR InfDirectory[] = {'i','n','f','\\',0};
31 static const WCHAR OemFileMask[] = {'o','e','m','*','.','i','n','f',0};
32 static const WCHAR OemFileSpecification[] = {'o','e','m','%','l','u','.','i','n','f',0};
33 static const WCHAR DotLnk[] = {'.','l','n','k',0};
34 static const WCHAR DotServices[] = {'.','S','e','r','v','i','c','e','s',0};
35
36 static const WCHAR DependenciesKey[] = {'D','e','p','e','n','d','e','n','c','i','e','s',0};
37 static const WCHAR DescriptionKey[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
38 static const WCHAR DisplayNameKey[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
39 static const WCHAR ErrorControlKey[] = {'E','r','r','o','r','C','o','n','t','r','o','l',0};
40 static const WCHAR LoadOrderGroupKey[] = {'L','o','a','d','O','r','d','e','r','G','r','o','u','p',0};
41 static const WCHAR SecurityKey[] = {'S','e','c','u','r','i','t','y',0};
42 static const WCHAR ServiceBinaryKey[] = {'S','e','r','v','i','c','e','B','i','n','a','r','y',0};
43 static const WCHAR ServiceTypeKey[] = {'S','e','r','v','i','c','e','T','y','p','e',0};
44 static const WCHAR StartTypeKey[] = {'S','t','a','r','t','T','y','p','e',0};
45 static const WCHAR StartNameKey[] = {'S','t','a','r','t','N','a','m','e',0};
46
47 static const WCHAR Name[] = {'N','a','m','e',0};
48 static const WCHAR CmdLine[] = {'C','m','d','L','i','n','e',0};
49 static const WCHAR SubDir[] = {'S','u','b','D','i','r',0};
50 static const WCHAR WorkingDir[] = {'W','o','r','k','i','n','g','D','i','r',0};
51 static const WCHAR IconPath[] = {'I','c','o','n','P','a','t','h',0};
52 static const WCHAR IconIndex[] = {'I','c','o','n','I','n','d','e','x',0};
53 static const WCHAR HotKey[] = {'H','o','t','K','e','y',0};
54 static const WCHAR InfoTip[] = {'I','n','f','o','T','i','p',0};
55 static const WCHAR DisplayResource[] = {'D','i','s','p','l','a','y','R','e','s','o','u','r','c','e',0};
56
57 /* info passed to callback functions dealing with files */
58 struct files_callback_info
59 {
60 HSPFILEQ queue;
61 PCWSTR src_root;
62 UINT copy_flags;
63 HINF layout;
64 };
65
66 /* info passed to callback functions dealing with the registry */
67 struct registry_callback_info
68 {
69 HKEY default_root;
70 BOOL delete;
71 };
72
73 /* info passed to callback functions dealing with registering dlls */
74 struct register_dll_info
75 {
76 PSP_FILE_CALLBACK_W callback;
77 PVOID callback_context;
78 BOOL unregister;
79 };
80
81 /* info passed to callback functions dealing with Needs directives */
82 struct needs_callback_info
83 {
84 UINT type;
85
86 HWND owner;
87 UINT flags;
88 HKEY key_root;
89 LPCWSTR src_root;
90 UINT copy_flags;
91 PVOID callback;
92 PVOID context;
93 HDEVINFO devinfo;
94 PSP_DEVINFO_DATA devinfo_data;
95 PVOID reserved1;
96 PVOID reserved2;
97 };
98
99 typedef BOOL (*iterate_fields_func)( HINF hinf, PCWSTR field, void *arg );
100 static BOOL GetLineText( HINF hinf, PCWSTR section_name, PCWSTR key_name, PWSTR *value);
101 typedef HRESULT (WINAPI *COINITIALIZE)(IN LPVOID pvReserved);
102 typedef HRESULT (WINAPI *COCREATEINSTANCE)(IN REFCLSID rclsid, IN LPUNKNOWN pUnkOuter, IN DWORD dwClsContext, IN REFIID riid, OUT LPVOID *ppv);
103 typedef HRESULT (WINAPI *COUNINITIALIZE)(VOID);
104
105 /* Unicode constants */
106 static const WCHAR AddService[] = {'A','d','d','S','e','r','v','i','c','e',0};
107 static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0};
108 static const WCHAR DelFiles[] = {'D','e','l','F','i','l','e','s',0};
109 static const WCHAR RenFiles[] = {'R','e','n','F','i','l','e','s',0};
110 static const WCHAR Ini2Reg[] = {'I','n','i','2','R','e','g',0};
111 static const WCHAR LogConf[] = {'L','o','g','C','o','n','f',0};
112 static const WCHAR AddReg[] = {'A','d','d','R','e','g',0};
113 static const WCHAR DelReg[] = {'D','e','l','R','e','g',0};
114 static const WCHAR BitReg[] = {'B','i','t','R','e','g',0};
115 static const WCHAR UpdateInis[] = {'U','p','d','a','t','e','I','n','i','s',0};
116 static const WCHAR CopyINF[] = {'C','o','p','y','I','N','F',0};
117 static const WCHAR UpdateIniFields[] = {'U','p','d','a','t','e','I','n','i','F','i','e','l','d','s',0};
118 static const WCHAR RegisterDlls[] = {'R','e','g','i','s','t','e','r','D','l','l','s',0};
119 static const WCHAR UnregisterDlls[] = {'U','n','r','e','g','i','s','t','e','r','D','l','l','s',0};
120 static const WCHAR ProfileItems[] = {'P','r','o','f','i','l','e','I','t','e','m','s',0};
121 static const WCHAR Include[] = {'I','n','c','l','u','d','e',0};
122 static const WCHAR Needs[] = {'N','e','e','d','s',0};
123 static const WCHAR DotSecurity[] = {'.','S','e','c','u','r','i','t','y',0};
124 #ifdef __WINESRC__
125 static const WCHAR WineFakeDlls[] = {'W','i','n','e','F','a','k','e','D','l','l','s',0};
126 #endif
127
128
129 /***********************************************************************
130 * get_field_string
131 *
132 * Retrieve the contents of a field, dynamically growing the buffer if necessary.
133 */
get_field_string(INFCONTEXT * context,DWORD index,WCHAR * buffer,WCHAR * static_buffer,DWORD * size)134 static WCHAR *get_field_string( INFCONTEXT *context, DWORD index, WCHAR *buffer,
135 WCHAR *static_buffer, DWORD *size )
136 {
137 DWORD required;
138
139 if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer;
140 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
141 {
142 /* now grow the buffer */
143 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
144 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required*sizeof(WCHAR) ))) return NULL;
145 *size = required;
146 if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer;
147 }
148 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
149 return NULL;
150 }
151
152
153 /***********************************************************************
154 * copy_files_callback
155 *
156 * Called once for each CopyFiles entry in a given section.
157 */
copy_files_callback(HINF hinf,PCWSTR field,void * arg)158 static BOOL copy_files_callback( HINF hinf, PCWSTR field, void *arg )
159 {
160 struct files_callback_info *info = arg;
161
162 if (field[0] == '@') /* special case: copy single file */
163 SetupQueueDefaultCopyW( info->queue, info->layout ? info->layout : hinf, info->src_root, NULL, field+1, info->copy_flags );
164 else
165 SetupQueueCopySectionW( info->queue, info->src_root, info->layout ? info->layout : hinf, hinf, field, info->copy_flags );
166 return TRUE;
167 }
168
169
170 /***********************************************************************
171 * delete_files_callback
172 *
173 * Called once for each DelFiles entry in a given section.
174 */
delete_files_callback(HINF hinf,PCWSTR field,void * arg)175 static BOOL delete_files_callback( HINF hinf, PCWSTR field, void *arg )
176 {
177 struct files_callback_info *info = arg;
178 SetupQueueDeleteSectionW( info->queue, hinf, 0, field );
179 return TRUE;
180 }
181
182
183 /***********************************************************************
184 * rename_files_callback
185 *
186 * Called once for each RenFiles entry in a given section.
187 */
rename_files_callback(HINF hinf,PCWSTR field,void * arg)188 static BOOL rename_files_callback( HINF hinf, PCWSTR field, void *arg )
189 {
190 struct files_callback_info *info = arg;
191 SetupQueueRenameSectionW( info->queue, hinf, 0, field );
192 return TRUE;
193 }
194
195
196 /***********************************************************************
197 * get_root_key
198 *
199 * Retrieve the registry root key from its name.
200 */
get_root_key(const WCHAR * name,HKEY def_root)201 static HKEY get_root_key( const WCHAR *name, HKEY def_root )
202 {
203 static const WCHAR HKCR[] = {'H','K','C','R',0};
204 static const WCHAR HKCU[] = {'H','K','C','U',0};
205 static const WCHAR HKLM[] = {'H','K','L','M',0};
206 static const WCHAR HKU[] = {'H','K','U',0};
207 static const WCHAR HKR[] = {'H','K','R',0};
208
209 if (!strcmpiW( name, HKCR )) return HKEY_CLASSES_ROOT;
210 if (!strcmpiW( name, HKCU )) return HKEY_CURRENT_USER;
211 if (!strcmpiW( name, HKLM )) return HKEY_LOCAL_MACHINE;
212 if (!strcmpiW( name, HKU )) return HKEY_USERS;
213 if (!strcmpiW( name, HKR )) return def_root;
214 return 0;
215 }
216
217
218 /***********************************************************************
219 * append_multi_sz_value
220 *
221 * Append a multisz string to a multisz registry value.
222 */
append_multi_sz_value(HKEY hkey,const WCHAR * value,const WCHAR * strings,DWORD str_size)223 static void append_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *strings,
224 DWORD str_size )
225 {
226 DWORD size, type, total;
227 WCHAR *buffer, *p;
228
229 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
230 if (type != REG_MULTI_SZ) return;
231
232 size = size + str_size * sizeof(WCHAR) ;
233 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size))) return;
234 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
235
236 /* compare each string against all the existing ones */
237 total = size;
238 while (*strings)
239 {
240 int len = strlenW(strings) + 1;
241
242 for (p = buffer; *p; p += strlenW(p) + 1)
243 if (!strcmpiW( p, strings )) break;
244
245 if (!*p) /* not found, need to append it */
246 {
247 memcpy( p, strings, len * sizeof(WCHAR) );
248 p[len] = 0;
249 total += len * sizeof(WCHAR);
250 }
251 strings += len;
252 }
253 if (total != size)
254 {
255 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) );
256 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total + sizeof(WCHAR) );
257 }
258 done:
259 HeapFree( GetProcessHeap(), 0, buffer );
260 }
261
262
263 /***********************************************************************
264 * delete_multi_sz_value
265 *
266 * Remove a string from a multisz registry value.
267 */
delete_multi_sz_value(HKEY hkey,const WCHAR * value,const WCHAR * string)268 static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string )
269 {
270 DWORD size, type;
271 WCHAR *buffer, *src, *dst;
272
273 if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
274 if (type != REG_MULTI_SZ) return;
275 /* allocate double the size, one for value before and one for after */
276 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2))) return;
277 if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
278 src = buffer;
279 dst = buffer + size;
280 while (*src)
281 {
282 int len = strlenW(src) + 1;
283 if (strcmpiW( src, string ))
284 {
285 memcpy( dst, src, len * sizeof(WCHAR) );
286 dst += len;
287 }
288 src += len;
289 }
290 *dst++ = 0;
291 if (dst != buffer + 2*size) /* did we remove something? */
292 {
293 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) );
294 RegSetValueExW( hkey, value, 0, REG_MULTI_SZ,
295 (BYTE *)(buffer + size), dst - (buffer + size) );
296 }
297 done:
298 HeapFree( GetProcessHeap(), 0, buffer );
299 }
300
301
302 /***********************************************************************
303 * do_reg_operation
304 *
305 * Perform an add/delete registry operation depending on the flags.
306 */
do_reg_operation(HKEY hkey,const WCHAR * value,INFCONTEXT * context,INT flags)307 static BOOL do_reg_operation( HKEY hkey, const WCHAR *value, INFCONTEXT *context, INT flags )
308 {
309 DWORD type, size;
310
311 if (flags & (FLG_ADDREG_DELREG_BIT | FLG_ADDREG_DELVAL)) /* deletion */
312 {
313 if (*value && !(flags & FLG_DELREG_KEYONLY_COMMON))
314 {
315 if ((flags & FLG_DELREG_MULTI_SZ_DELSTRING) == FLG_DELREG_MULTI_SZ_DELSTRING)
316 {
317 WCHAR *str;
318
319 if (!SetupGetStringFieldW( context, 5, NULL, 0, &size ) || !size) return TRUE;
320 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
321 SetupGetStringFieldW( context, 5, str, size, NULL );
322 delete_multi_sz_value( hkey, value, str );
323 HeapFree( GetProcessHeap(), 0, str );
324 }
325 else RegDeleteValueW( hkey, value );
326 }
327 else NtDeleteKey( hkey );
328 return TRUE;
329 }
330
331 if (flags & (FLG_ADDREG_KEYONLY|FLG_ADDREG_KEYONLY_COMMON)) return TRUE;
332
333 if (flags & (FLG_ADDREG_NOCLOBBER|FLG_ADDREG_OVERWRITEONLY))
334 {
335 BOOL exists = !RegQueryValueExW( hkey, value, NULL, NULL, NULL, NULL );
336 if (exists && (flags & FLG_ADDREG_NOCLOBBER)) return TRUE;
337 if (!exists && (flags & FLG_ADDREG_OVERWRITEONLY)) return TRUE;
338 }
339
340 switch(flags & FLG_ADDREG_TYPE_MASK)
341 {
342 case FLG_ADDREG_TYPE_SZ: type = REG_SZ; break;
343 case FLG_ADDREG_TYPE_MULTI_SZ: type = REG_MULTI_SZ; break;
344 case FLG_ADDREG_TYPE_EXPAND_SZ: type = REG_EXPAND_SZ; break;
345 case FLG_ADDREG_TYPE_BINARY: type = REG_BINARY; break;
346 case FLG_ADDREG_TYPE_DWORD: type = REG_DWORD; break;
347 case FLG_ADDREG_TYPE_NONE: type = REG_NONE; break;
348 default: type = flags >> 16; break;
349 }
350
351 if (!(flags & FLG_ADDREG_BINVALUETYPE) ||
352 (type == REG_DWORD && SetupGetFieldCount(context) == 5))
353 {
354 static const WCHAR empty;
355 WCHAR *str = NULL;
356
357 if (type == REG_MULTI_SZ)
358 {
359 if (!SetupGetMultiSzFieldW( context, 5, NULL, 0, &size )) size = 0;
360 if (size)
361 {
362 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
363 SetupGetMultiSzFieldW( context, 5, str, size, NULL );
364 }
365 if (flags & FLG_ADDREG_APPEND)
366 {
367 if (!str) return TRUE;
368 append_multi_sz_value( hkey, value, str, size );
369 HeapFree( GetProcessHeap(), 0, str );
370 return TRUE;
371 }
372 /* else fall through to normal string handling */
373 }
374 else
375 {
376 if (!SetupGetStringFieldW( context, 5, NULL, 0, &size )) size = 0;
377 if (size)
378 {
379 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
380 SetupGetStringFieldW( context, 5, str, size, NULL );
381 }
382 }
383
384 if (type == REG_DWORD)
385 {
386 DWORD dw = str ? strtoulW( str, NULL, 0 ) : 0;
387 TRACE( "setting dword %s to %x\n", debugstr_w(value), dw );
388 RegSetValueExW( hkey, value, 0, type, (BYTE *)&dw, sizeof(dw) );
389 }
390 else
391 {
392 TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(str) );
393 if (str) RegSetValueExW( hkey, value, 0, type, (BYTE *)str, size * sizeof(WCHAR) );
394 else RegSetValueExW( hkey, value, 0, type, (const BYTE *)&empty, sizeof(WCHAR) );
395 }
396 HeapFree( GetProcessHeap(), 0, str );
397 return TRUE;
398 }
399 else /* get the binary data */
400 {
401 BYTE *data = NULL;
402
403 if (!SetupGetBinaryField( context, 5, NULL, 0, &size )) size = 0;
404 if (size)
405 {
406 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
407 TRACE( "setting binary data %s len %d\n", debugstr_w(value), size );
408 SetupGetBinaryField( context, 5, data, size, NULL );
409 }
410 RegSetValueExW( hkey, value, 0, type, data, size );
411 HeapFree( GetProcessHeap(), 0, data );
412 return TRUE;
413 }
414 }
415
416
417 /***********************************************************************
418 * registry_callback
419 *
420 * Called once for each AddReg and DelReg entry in a given section.
421 */
registry_callback(HINF hinf,PCWSTR field,void * arg)422 static BOOL registry_callback( HINF hinf, PCWSTR field, void *arg )
423 {
424 struct registry_callback_info *info = arg;
425 LPWSTR security_key, security_descriptor;
426 INFCONTEXT context, security_context;
427 PSECURITY_DESCRIPTOR sd = NULL;
428 SECURITY_ATTRIBUTES security_attributes = { 0, };
429 HKEY root_key, hkey;
430 DWORD required;
431
432 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
433 if (!ok)
434 return TRUE;
435
436 /* Check for .Security section */
437 security_key = MyMalloc( (strlenW( field ) + strlenW( DotSecurity )) * sizeof(WCHAR) + sizeof(UNICODE_NULL) );
438 if (!security_key)
439 {
440 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
441 return FALSE;
442 }
443 strcpyW( security_key, field );
444 strcatW( security_key, DotSecurity );
445 ok = SetupFindFirstLineW( hinf, security_key, NULL, &security_context );
446 MyFree(security_key);
447 if (ok)
448 {
449 if (!SetupGetLineTextW( &security_context, NULL, NULL, NULL, NULL, 0, &required ))
450 return FALSE;
451 security_descriptor = MyMalloc( required * sizeof(WCHAR) );
452 if (!security_descriptor)
453 {
454 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
455 return FALSE;
456 }
457 if (!SetupGetLineTextW( &security_context, NULL, NULL, NULL, security_descriptor, required, NULL ))
458 return FALSE;
459 ok = ConvertStringSecurityDescriptorToSecurityDescriptorW( security_descriptor, SDDL_REVISION_1, &sd, NULL );
460 MyFree( security_descriptor );
461 if (!ok)
462 return FALSE;
463 security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
464 security_attributes.lpSecurityDescriptor = sd;
465 }
466
467 for (ok = TRUE; ok; ok = SetupFindNextLine( &context, &context ))
468 {
469 WCHAR buffer[MAX_INF_STRING_LENGTH];
470 INT flags;
471
472 /* get root */
473 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
474 continue;
475 if (!(root_key = get_root_key( buffer, info->default_root )))
476 continue;
477
478 /* get key */
479 if (!SetupGetStringFieldW( &context, 2, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
480 *buffer = 0;
481
482 /* get flags */
483 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
484
485 if (!info->delete)
486 {
487 if (flags & FLG_ADDREG_DELREG_BIT) continue; /* ignore this entry */
488 }
489 else
490 {
491 if (!flags) flags = FLG_ADDREG_DELREG_BIT;
492 else if (!(flags & FLG_ADDREG_DELREG_BIT)) continue; /* ignore this entry */
493 }
494
495 if (info->delete || (flags & FLG_ADDREG_OVERWRITEONLY))
496 {
497 if (RegOpenKeyW( root_key, buffer, &hkey )) continue; /* ignore if it doesn't exist */
498 }
499 else if (RegCreateKeyExW( root_key, buffer, 0, NULL, 0, MAXIMUM_ALLOWED,
500 sd ? &security_attributes : NULL, &hkey, NULL ))
501 {
502 ERR( "could not create key %p %s\n", root_key, debugstr_w(buffer) );
503 continue;
504 }
505 TRACE( "key %p %s\n", root_key, debugstr_w(buffer) );
506
507 /* get value name */
508 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
509 *buffer = 0;
510
511 /* and now do it */
512 if (!do_reg_operation( hkey, buffer, &context, flags ))
513 {
514 if (hkey != root_key) RegCloseKey( hkey );
515 if (sd) LocalFree( sd );
516 return FALSE;
517 }
518 if (hkey != root_key) RegCloseKey( hkey );
519 }
520 if (sd) LocalFree( sd );
521 return TRUE;
522 }
523
524
525 /***********************************************************************
526 * do_register_dll
527 *
528 * Register or unregister a dll.
529 */
do_register_dll(const struct register_dll_info * info,const WCHAR * path,INT flags,INT timeout,const WCHAR * args)530 static BOOL do_register_dll( const struct register_dll_info *info, const WCHAR *path,
531 INT flags, INT timeout, const WCHAR *args )
532 {
533 HMODULE module;
534 HRESULT res;
535 SP_REGISTER_CONTROL_STATUSW status;
536 IMAGE_NT_HEADERS *nt;
537
538 status.cbSize = sizeof(status);
539 status.FileName = path;
540 status.FailureCode = SPREG_SUCCESS;
541 status.Win32Error = ERROR_SUCCESS;
542
543 if (info->callback)
544 {
545 switch(info->callback( info->callback_context, SPFILENOTIFY_STARTREGISTRATION,
546 (UINT_PTR)&status, !info->unregister ))
547 {
548 case FILEOP_ABORT:
549 SetLastError( ERROR_OPERATION_ABORTED );
550 return FALSE;
551 case FILEOP_SKIP:
552 return TRUE;
553 case FILEOP_DOIT:
554 break;
555 }
556 }
557
558 if (!(module = LoadLibraryExW( path, 0, LOAD_WITH_ALTERED_SEARCH_PATH )))
559 {
560 WARN( "could not load %s\n", debugstr_w(path) );
561 status.FailureCode = SPREG_LOADLIBRARY;
562 status.Win32Error = GetLastError();
563 goto done;
564 }
565
566 if ((nt = RtlImageNtHeader( module )) && !(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
567 {
568 /* file is an executable, not a dll */
569 STARTUPINFOW startup;
570 PROCESS_INFORMATION info;
571 WCHAR *cmd_line;
572 BOOL res;
573 static const WCHAR format[] = {'"','%','s','"',' ','%','s',0};
574 static const WCHAR default_args[] = {'/','R','e','g','S','e','r','v','e','r',0};
575
576 FreeLibrary( module );
577 module = NULL;
578 if (!args) args = default_args;
579 cmd_line = HeapAlloc( GetProcessHeap(), 0, (strlenW(path) + strlenW(args) + 4) * sizeof(WCHAR) );
580 sprintfW( cmd_line, format, path, args );
581 memset( &startup, 0, sizeof(startup) );
582 startup.cb = sizeof(startup);
583 TRACE( "executing %s\n", debugstr_w(cmd_line) );
584 res = CreateProcessW( NULL, cmd_line, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info );
585 HeapFree( GetProcessHeap(), 0, cmd_line );
586 if (!res)
587 {
588 status.FailureCode = SPREG_LOADLIBRARY;
589 status.Win32Error = GetLastError();
590 goto done;
591 }
592 CloseHandle( info.hThread );
593
594 if (WaitForSingleObject( info.hProcess, timeout*1000 ) == WAIT_TIMEOUT)
595 {
596 /* timed out, kill the process */
597 TerminateProcess( info.hProcess, 1 );
598 status.FailureCode = SPREG_TIMEOUT;
599 status.Win32Error = ERROR_TIMEOUT;
600 }
601 CloseHandle( info.hProcess );
602 goto done;
603 }
604
605 if (flags & FLG_REGSVR_DLLREGISTER)
606 {
607 const char *entry_point = info->unregister ? "DllUnregisterServer" : "DllRegisterServer";
608 HRESULT (WINAPI *func)(void) = (void *)GetProcAddress( module, entry_point );
609
610 if (!func)
611 {
612 status.FailureCode = SPREG_GETPROCADDR;
613 status.Win32Error = GetLastError();
614 goto done;
615 }
616
617 TRACE( "calling %s in %s\n", entry_point, debugstr_w(path) );
618 res = func();
619
620 if (FAILED(res))
621 {
622 WARN( "calling %s in %s returned error %x\n", entry_point, debugstr_w(path), res );
623 status.FailureCode = SPREG_REGSVR;
624 status.Win32Error = res;
625 goto done;
626 }
627 }
628
629 if (flags & FLG_REGSVR_DLLINSTALL)
630 {
631 HRESULT (WINAPI *func)(BOOL,LPCWSTR) = (void *)GetProcAddress( module, "DllInstall" );
632
633 if (!func)
634 {
635 status.FailureCode = SPREG_GETPROCADDR;
636 status.Win32Error = GetLastError();
637 goto done;
638 }
639
640 TRACE( "calling DllInstall(%d,%s) in %s\n",
641 !info->unregister, debugstr_w(args), debugstr_w(path) );
642 res = func( !info->unregister, args );
643
644 if (FAILED(res))
645 {
646 WARN( "calling DllInstall in %s returned error %x\n", debugstr_w(path), res );
647 status.FailureCode = SPREG_REGSVR;
648 status.Win32Error = res;
649 goto done;
650 }
651 }
652
653 done:
654 if (module) FreeLibrary( module );
655 if (info->callback) info->callback( info->callback_context, SPFILENOTIFY_ENDREGISTRATION,
656 (UINT_PTR)&status, !info->unregister );
657 return TRUE;
658 }
659
660
661 /***********************************************************************
662 * register_dlls_callback
663 *
664 * Called once for each RegisterDlls entry in a given section.
665 */
register_dlls_callback(HINF hinf,PCWSTR field,void * arg)666 static BOOL register_dlls_callback( HINF hinf, PCWSTR field, void *arg )
667 {
668 struct register_dll_info *info = arg;
669 INFCONTEXT context;
670 BOOL ret = TRUE;
671 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
672
673 for (; ok; ok = SetupFindNextLine( &context, &context ))
674 {
675 WCHAR *path, *args, *p;
676 WCHAR buffer[MAX_INF_STRING_LENGTH];
677 INT flags, timeout;
678
679 /* get directory */
680 if (!(path = PARSER_get_dest_dir( &context ))) continue;
681
682 /* get dll name */
683 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
684 goto done;
685 if (!(p = HeapReAlloc( GetProcessHeap(), 0, path,
686 (strlenW(path) + strlenW(buffer) + 2) * sizeof(WCHAR) ))) goto done;
687 path = p;
688 p += strlenW(p);
689 if (p == path || p[-1] != '\\') *p++ = '\\';
690 strcpyW( p, buffer );
691
692 /* get flags */
693 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
694
695 /* get timeout */
696 #ifdef __REACTOS__
697 /* "11,,cmd.exe,,,/K dir" means default timeout, not a timeout of zero */
698 if (!SetupGetIntField( &context, 5, &timeout ) || timeout == 0) timeout = 60;
699 #else
700 if (!SetupGetIntField( &context, 5, &timeout )) timeout = 60;
701 #endif
702
703 /* get command line */
704 args = NULL;
705 if (SetupGetStringFieldW( &context, 6, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
706 args = buffer;
707
708 ret = do_register_dll( info, path, flags, timeout, args );
709
710 done:
711 HeapFree( GetProcessHeap(), 0, path );
712 if (!ret) break;
713 }
714 return ret;
715 }
716
717 #ifdef __WINESRC__
718 /***********************************************************************
719 * fake_dlls_callback
720 *
721 * Called once for each WineFakeDlls entry in a given section.
722 */
fake_dlls_callback(HINF hinf,PCWSTR field,void * arg)723 static BOOL fake_dlls_callback( HINF hinf, PCWSTR field, void *arg )
724 {
725 INFCONTEXT context;
726 BOOL ret = TRUE;
727 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
728
729 for (; ok; ok = SetupFindNextLine( &context, &context ))
730 {
731 WCHAR *path, *p;
732 WCHAR buffer[MAX_INF_STRING_LENGTH];
733
734 /* get directory */
735 if (!(path = PARSER_get_dest_dir( &context ))) continue;
736
737 /* get dll name */
738 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
739 goto done;
740 if (!(p = HeapReAlloc( GetProcessHeap(), 0, path,
741 (strlenW(path) + strlenW(buffer) + 2) * sizeof(WCHAR) ))) goto done;
742 path = p;
743 p += strlenW(p);
744 if (p == path || p[-1] != '\\') *p++ = '\\';
745 strcpyW( p, buffer );
746
747 /* get source dll */
748 if (SetupGetStringFieldW( &context, 4, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
749 p = buffer; /* otherwise use target base name as default source */
750
751 create_fake_dll( path, p ); /* ignore errors */
752
753 done:
754 HeapFree( GetProcessHeap(), 0, path );
755 if (!ret) break;
756 }
757 return ret;
758 }
759 #endif // __WINESRC__
760
761 /***********************************************************************
762 * update_ini_callback
763 *
764 * Called once for each UpdateInis entry in a given section.
765 */
update_ini_callback(HINF hinf,PCWSTR field,void * arg)766 static BOOL update_ini_callback( HINF hinf, PCWSTR field, void *arg )
767 {
768 INFCONTEXT context;
769
770 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
771
772 for (; ok; ok = SetupFindNextLine( &context, &context ))
773 {
774 WCHAR buffer[MAX_INF_STRING_LENGTH];
775 WCHAR filename[MAX_INF_STRING_LENGTH];
776 WCHAR section[MAX_INF_STRING_LENGTH];
777 WCHAR entry[MAX_INF_STRING_LENGTH];
778 WCHAR string[MAX_INF_STRING_LENGTH];
779 LPWSTR divider;
780
781 if (!SetupGetStringFieldW( &context, 1, filename,
782 sizeof(filename)/sizeof(WCHAR), NULL ))
783 continue;
784
785 if (!SetupGetStringFieldW( &context, 2, section,
786 sizeof(section)/sizeof(WCHAR), NULL ))
787 continue;
788
789 if (!SetupGetStringFieldW( &context, 4, buffer,
790 sizeof(buffer)/sizeof(WCHAR), NULL ))
791 continue;
792
793 divider = strchrW(buffer,'=');
794 if (divider)
795 {
796 *divider = 0;
797 strcpyW(entry,buffer);
798 divider++;
799 strcpyW(string,divider);
800 }
801 else
802 {
803 strcpyW(entry,buffer);
804 string[0]=0;
805 }
806
807 TRACE("Writing %s = %s in %s of file %s\n",debugstr_w(entry),
808 debugstr_w(string),debugstr_w(section),debugstr_w(filename));
809 WritePrivateProfileStringW(section,entry,string,filename);
810
811 }
812 return TRUE;
813 }
814
update_ini_fields_callback(HINF hinf,PCWSTR field,void * arg)815 static BOOL update_ini_fields_callback( HINF hinf, PCWSTR field, void *arg )
816 {
817 FIXME( "should update ini fields %s\n", debugstr_w(field) );
818 return TRUE;
819 }
820
ini2reg_callback(HINF hinf,PCWSTR field,void * arg)821 static BOOL ini2reg_callback( HINF hinf, PCWSTR field, void *arg )
822 {
823 FIXME( "should do ini2reg %s\n", debugstr_w(field) );
824 return TRUE;
825 }
826
logconf_callback(HINF hinf,PCWSTR field,void * arg)827 static BOOL logconf_callback( HINF hinf, PCWSTR field, void *arg )
828 {
829 FIXME( "should do logconf %s\n", debugstr_w(field) );
830 return TRUE;
831 }
832
bitreg_callback(HINF hinf,PCWSTR field,void * arg)833 static BOOL bitreg_callback( HINF hinf, PCWSTR field, void *arg )
834 {
835 FIXME( "should do bitreg %s\n", debugstr_w(field) );
836 return TRUE;
837 }
838
Concatenate(int DirId,LPCWSTR SubDirPart,LPCWSTR NamePart,LPWSTR * pFullName)839 static BOOL Concatenate(int DirId, LPCWSTR SubDirPart, LPCWSTR NamePart, LPWSTR *pFullName)
840 {
841 DWORD dwRequired = 0;
842 LPCWSTR Dir;
843 LPWSTR FullName;
844
845 *pFullName = NULL;
846
847 Dir = DIRID_get_string(DirId);
848 if (Dir && *Dir)
849 dwRequired += wcslen(Dir) + 1;
850 else
851 Dir = NULL; /* DIRID_get_string returns L"" for DIRID_ABSOLUTE */
852 if (SubDirPart)
853 dwRequired += wcslen(SubDirPart) + 1;
854 if (NamePart)
855 dwRequired += wcslen(NamePart);
856 dwRequired = dwRequired * sizeof(WCHAR) + sizeof(UNICODE_NULL);
857
858 FullName = MyMalloc(dwRequired);
859 if (!FullName)
860 {
861 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
862 return FALSE;
863 }
864 FullName[0] = UNICODE_NULL;
865
866 if (Dir)
867 {
868 wcscat(FullName, Dir);
869 if (FullName[wcslen(FullName) - 1] != '\\')
870 wcscat(FullName, BackSlash);
871 }
872 if (SubDirPart)
873 {
874 wcscat(FullName, SubDirPart);
875 if (FullName[wcslen(FullName) - 1] != '\\')
876 wcscat(FullName, BackSlash);
877 }
878 if (NamePart)
879 wcscat(FullName, NamePart);
880
881 *pFullName = FullName;
882 return TRUE;
883 }
884
885 /***********************************************************************
886 * profile_items_callback
887 *
888 * Called once for each ProfileItems entry in a given section.
889 */
890 static BOOL
profile_items_callback(IN HINF hInf,IN PCWSTR SectionName,IN PVOID Arg)891 profile_items_callback(
892 IN HINF hInf,
893 IN PCWSTR SectionName,
894 IN PVOID Arg)
895 {
896 INFCONTEXT Context;
897 LPWSTR LinkSubDir = NULL, LinkName = NULL;
898 INT LinkAttributes = 0;
899 INT LinkFolder = 0;
900 INT FileDirId = 0;
901 INT CSIDL = CSIDL_COMMON_PROGRAMS;
902 LPWSTR FileSubDir = NULL;
903 INT DirId = 0;
904 LPWSTR SubDirPart = NULL, NamePart = NULL;
905 LPWSTR FullLinkName = NULL, FullFileName = NULL, FullWorkingDir = NULL, FullIconName = NULL;
906 INT IconIdx = 0;
907 LPWSTR lpHotKey = NULL, lpInfoTip = NULL;
908 LPWSTR DisplayName = NULL;
909 INT DisplayResId = 0;
910 BOOL ret = FALSE;
911 DWORD Index, Required;
912
913 IShellLinkW *psl;
914 IPersistFile *ppf;
915 HMODULE hOle32 = NULL;
916 COINITIALIZE pCoInitialize;
917 COCREATEINSTANCE pCoCreateInstance;
918 COUNINITIALIZE pCoUninitialize;
919 HRESULT hr;
920
921 TRACE("hInf %p, SectionName %s, Arg %p\n",
922 hInf, debugstr_w(SectionName), Arg);
923
924 /* Read 'Name' entry */
925 if (!SetupFindFirstLineW(hInf, SectionName, Name, &Context))
926 goto cleanup;
927 if (!GetStringField(&Context, 1, &LinkName))
928 goto cleanup;
929 if (SetupGetFieldCount(&Context) >= 2)
930 {
931 if (!SetupGetIntField(&Context, 2, &LinkAttributes))
932 goto cleanup;
933 }
934 if (SetupGetFieldCount(&Context) >= 3)
935 {
936 if (!SetupGetIntField(&Context, 3, &LinkFolder))
937 goto cleanup;
938 }
939
940 /* Read 'CmdLine' entry */
941 if (!SetupFindFirstLineW(hInf, SectionName, CmdLine, &Context))
942 goto cleanup;
943 Index = 1;
944 if (!SetupGetIntField(&Context, Index++, &FileDirId))
945 goto cleanup;
946 if (SetupGetFieldCount(&Context) >= 3)
947 {
948 if (!GetStringField(&Context, Index++, &FileSubDir))
949 goto cleanup;
950 }
951 if (!GetStringField(&Context, Index++, &NamePart))
952 goto cleanup;
953 if (!Concatenate(FileDirId, FileSubDir, NamePart, &FullFileName))
954 goto cleanup;
955 MyFree(NamePart);
956 NamePart = NULL;
957
958 /* Read 'SubDir' entry */
959 if ((LinkAttributes & FLG_PROFITEM_GROUP) == 0 && SetupFindFirstLineW(hInf, SectionName, SubDir, &Context))
960 {
961 if (!GetStringField(&Context, 1, &LinkSubDir))
962 goto cleanup;
963 }
964
965 /* Read 'WorkingDir' entry */
966 if (SetupFindFirstLineW(hInf, SectionName, WorkingDir, &Context))
967 {
968 if (!SetupGetIntField(&Context, 1, &DirId))
969 goto cleanup;
970 if (SetupGetFieldCount(&Context) >= 2)
971 {
972 if (!GetStringField(&Context, 2, &SubDirPart))
973 goto cleanup;
974 }
975 if (!Concatenate(DirId, SubDirPart, NULL, &FullWorkingDir))
976 goto cleanup;
977 MyFree(SubDirPart);
978 SubDirPart = NULL;
979 }
980 else
981 {
982 if (!Concatenate(FileDirId, FileSubDir, NULL, &FullWorkingDir))
983 goto cleanup;
984 }
985
986 /* Read 'IconPath' entry */
987 if (SetupFindFirstLineW(hInf, SectionName, IconPath, &Context))
988 {
989 Index = 1;
990 if (!SetupGetIntField(&Context, Index++, &DirId))
991 goto cleanup;
992 if (SetupGetFieldCount(&Context) >= 3)
993 {
994 if (!GetStringField(&Context, Index++, &SubDirPart))
995 goto cleanup;
996 }
997 if (!GetStringField(&Context, Index, &NamePart))
998 goto cleanup;
999 if (!Concatenate(DirId, SubDirPart, NamePart, &FullIconName))
1000 goto cleanup;
1001 MyFree(SubDirPart);
1002 MyFree(NamePart);
1003 SubDirPart = NamePart = NULL;
1004 }
1005 else
1006 {
1007 FullIconName = pSetupDuplicateString(FullFileName);
1008 if (!FullIconName)
1009 goto cleanup;
1010 }
1011
1012 /* Read 'IconIndex' entry */
1013 if (SetupFindFirstLineW(hInf, SectionName, IconIndex, &Context))
1014 {
1015 if (!SetupGetIntField(&Context, 1, &IconIdx))
1016 goto cleanup;
1017 }
1018
1019 /* Read 'HotKey' and 'InfoTip' entries */
1020 GetLineText(hInf, SectionName, HotKey, &lpHotKey);
1021 GetLineText(hInf, SectionName, InfoTip, &lpInfoTip);
1022
1023 /* Read 'DisplayResource' entry */
1024 if (SetupFindFirstLineW(hInf, SectionName, DisplayResource, &Context))
1025 {
1026 if (!GetStringField(&Context, 1, &DisplayName))
1027 goto cleanup;
1028 if (!SetupGetIntField(&Context, 2, &DisplayResId))
1029 goto cleanup;
1030 }
1031
1032 /* Some debug */
1033 TRACE("Link is %s\\%s, attributes 0x%x\n", debugstr_w(LinkSubDir), debugstr_w(LinkName), LinkAttributes);
1034 TRACE("File is %s\n", debugstr_w(FullFileName));
1035 TRACE("Working dir %s\n", debugstr_w(FullWorkingDir));
1036 TRACE("Icon is %s, %d\n", debugstr_w(FullIconName), IconIdx);
1037 TRACE("Hotkey %s\n", debugstr_w(lpHotKey));
1038 TRACE("InfoTip %s\n", debugstr_w(lpInfoTip));
1039 TRACE("Display %s, %d\n", DisplayName, DisplayResId);
1040
1041 /* Load ole32.dll */
1042 hOle32 = LoadLibraryA("ole32.dll");
1043 if (!hOle32)
1044 goto cleanup;
1045 pCoInitialize = (COINITIALIZE)GetProcAddress(hOle32, "CoInitialize");
1046 if (!pCoInitialize)
1047 goto cleanup;
1048 pCoCreateInstance = (COCREATEINSTANCE)GetProcAddress(hOle32, "CoCreateInstance");
1049 if (!pCoCreateInstance)
1050 goto cleanup;
1051 pCoUninitialize = (COUNINITIALIZE)GetProcAddress(hOle32, "CoUninitialize");
1052 if (!pCoUninitialize)
1053 goto cleanup;
1054
1055 /* Create shortcut */
1056 hr = pCoInitialize(NULL);
1057 if (!SUCCEEDED(hr))
1058 {
1059 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1060 SetLastError(HRESULT_CODE(hr));
1061 else
1062 SetLastError(E_FAIL);
1063 goto cleanup;
1064 }
1065 hr = pCoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&psl);
1066 if (SUCCEEDED(hr))
1067 {
1068 /* Fill link properties */
1069 hr = IShellLinkW_SetPath(psl, FullFileName);
1070 if (SUCCEEDED(hr))
1071 hr = IShellLinkW_SetArguments(psl, L"");
1072 if (SUCCEEDED(hr))
1073 hr = IShellLinkW_SetWorkingDirectory(psl, FullWorkingDir);
1074 if (SUCCEEDED(hr))
1075 hr = IShellLinkW_SetIconLocation(psl, FullIconName, IconIdx);
1076 if (SUCCEEDED(hr) && lpHotKey)
1077 FIXME("Need to store hotkey %s in shell link\n", debugstr_w(lpHotKey));
1078 if (SUCCEEDED(hr) && lpInfoTip)
1079 hr = IShellLinkW_SetDescription(psl, lpInfoTip);
1080 if (SUCCEEDED(hr) && DisplayName)
1081 FIXME("Need to store display name %s, %d in shell link\n", debugstr_w(DisplayName), DisplayResId);
1082 if (SUCCEEDED(hr))
1083 {
1084 hr = IShellLinkW_QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf);
1085 if (SUCCEEDED(hr))
1086 {
1087 Required = (MAX_PATH + 1 +
1088 ((LinkSubDir != NULL) ? wcslen(LinkSubDir) : 0) +
1089 ((LinkName != NULL) ? wcslen(LinkName) : 0)) * sizeof(WCHAR);
1090 FullLinkName = MyMalloc(Required);
1091 if (!FullLinkName)
1092 hr = E_OUTOFMEMORY;
1093 else
1094 {
1095 if (LinkAttributes & (FLG_PROFITEM_DELETE | FLG_PROFITEM_GROUP))
1096 FIXME("Need to handle FLG_PROFITEM_DELETE and FLG_PROFITEM_GROUP\n");
1097 if (LinkAttributes & FLG_PROFITEM_CSIDL)
1098 CSIDL = LinkFolder;
1099 else if (LinkAttributes & FLG_PROFITEM_CURRENTUSER)
1100 CSIDL = CSIDL_PROGRAMS;
1101
1102 if (SHGetSpecialFolderPathW(
1103 NULL,
1104 FullLinkName,
1105 CSIDL,
1106 TRUE))
1107 {
1108 if (FullLinkName[wcslen(FullLinkName) - 1] != '\\')
1109 wcscat(FullLinkName, BackSlash);
1110 if (LinkSubDir)
1111 {
1112 wcscat(FullLinkName, LinkSubDir);
1113 if (FullLinkName[wcslen(FullLinkName) - 1] != '\\')
1114 wcscat(FullLinkName, BackSlash);
1115 }
1116 if (LinkName)
1117 {
1118 wcscat(FullLinkName, LinkName);
1119 wcscat(FullLinkName, DotLnk);
1120 }
1121 hr = IPersistFile_Save(ppf, FullLinkName, TRUE);
1122 }
1123 else
1124 hr = HRESULT_FROM_WIN32(GetLastError());
1125 }
1126 IPersistFile_Release(ppf);
1127 }
1128 }
1129 IShellLinkW_Release(psl);
1130 }
1131 pCoUninitialize();
1132 if (SUCCEEDED(hr))
1133 ret = TRUE;
1134 else
1135 {
1136 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1137 SetLastError(HRESULT_CODE(hr));
1138 else
1139 SetLastError(E_FAIL);
1140 }
1141
1142 cleanup:
1143 MyFree(LinkSubDir);
1144 MyFree(LinkName);
1145 MyFree(FileSubDir);
1146 MyFree(SubDirPart);
1147 MyFree(NamePart);
1148 MyFree(FullFileName);
1149 MyFree(FullWorkingDir);
1150 MyFree(FullIconName);
1151 MyFree(FullLinkName);
1152 MyFree(lpHotKey);
1153 MyFree(lpInfoTip);
1154 MyFree(DisplayName);
1155 if (hOle32)
1156 FreeLibrary(hOle32);
1157
1158 TRACE("Returning %d\n", ret);
1159 return ret;
1160 }
1161
copy_inf_callback(HINF hinf,PCWSTR field,void * arg)1162 static BOOL copy_inf_callback( HINF hinf, PCWSTR field, void *arg )
1163 {
1164 FIXME( "should do copy inf %s\n", debugstr_w(field) );
1165 return TRUE;
1166 }
1167
1168
1169 /***********************************************************************
1170 * iterate_section_fields
1171 *
1172 * Iterate over all fields of a certain key of a certain section
1173 */
iterate_section_fields(HINF hinf,PCWSTR section,PCWSTR key,iterate_fields_func callback,void * arg)1174 static BOOL iterate_section_fields( HINF hinf, PCWSTR section, PCWSTR key,
1175 iterate_fields_func callback, void *arg )
1176 {
1177 WCHAR static_buffer[200];
1178 WCHAR *buffer = static_buffer;
1179 DWORD size = sizeof(static_buffer)/sizeof(WCHAR);
1180 INFCONTEXT context;
1181 BOOL ret = FALSE;
1182
1183 BOOL ok = SetupFindFirstLineW( hinf, section, key, &context );
1184 while (ok)
1185 {
1186 UINT i, count = SetupGetFieldCount( &context );
1187 for (i = 1; i <= count; i++)
1188 {
1189 if (!(buffer = get_field_string( &context, i, buffer, static_buffer, &size )))
1190 goto done;
1191 if (!callback( hinf, buffer, arg ))
1192 {
1193 WARN("callback failed for %s %s err %d\n",
1194 debugstr_w(section), debugstr_w(buffer), GetLastError() );
1195 goto done;
1196 }
1197 }
1198 ok = SetupFindNextMatchLineW( &context, key, &context );
1199 }
1200 ret = TRUE;
1201 done:
1202 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
1203 return ret;
1204 }
1205
1206
1207 /***********************************************************************
1208 * SetupInstallFilesFromInfSectionA (SETUPAPI.@)
1209 */
SetupInstallFilesFromInfSectionA(HINF hinf,HINF hlayout,HSPFILEQ queue,PCSTR section,PCSTR src_root,UINT flags)1210 BOOL WINAPI SetupInstallFilesFromInfSectionA( HINF hinf, HINF hlayout, HSPFILEQ queue,
1211 PCSTR section, PCSTR src_root, UINT flags )
1212 {
1213 UNICODE_STRING sectionW;
1214 BOOL ret = FALSE;
1215
1216 if (!RtlCreateUnicodeStringFromAsciiz( §ionW, section ))
1217 {
1218 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1219 return FALSE;
1220 }
1221 if (!src_root)
1222 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
1223 NULL, flags );
1224 else
1225 {
1226 UNICODE_STRING srcW;
1227 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
1228 {
1229 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
1230 srcW.Buffer, flags );
1231 RtlFreeUnicodeString( &srcW );
1232 }
1233 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1234 }
1235 RtlFreeUnicodeString( §ionW );
1236 return ret;
1237 }
1238
1239
1240 /***********************************************************************
1241 * SetupInstallFilesFromInfSectionW (SETUPAPI.@)
1242 */
SetupInstallFilesFromInfSectionW(HINF hinf,HINF hlayout,HSPFILEQ queue,PCWSTR section,PCWSTR src_root,UINT flags)1243 BOOL WINAPI SetupInstallFilesFromInfSectionW( HINF hinf, HINF hlayout, HSPFILEQ queue,
1244 PCWSTR section, PCWSTR src_root, UINT flags )
1245 {
1246 struct files_callback_info info;
1247
1248 info.queue = queue;
1249 info.src_root = src_root;
1250 info.copy_flags = flags;
1251 info.layout = hlayout;
1252 return iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info );
1253 }
1254
1255
1256 /***********************************************************************
1257 * SetupInstallFromInfSectionA (SETUPAPI.@)
1258 */
SetupInstallFromInfSectionA(HWND owner,HINF hinf,PCSTR section,UINT flags,HKEY key_root,PCSTR src_root,UINT copy_flags,PSP_FILE_CALLBACK_A callback,PVOID context,HDEVINFO devinfo,PSP_DEVINFO_DATA devinfo_data)1259 BOOL WINAPI SetupInstallFromInfSectionA( HWND owner, HINF hinf, PCSTR section, UINT flags,
1260 HKEY key_root, PCSTR src_root, UINT copy_flags,
1261 PSP_FILE_CALLBACK_A callback, PVOID context,
1262 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
1263 {
1264 UNICODE_STRING sectionW, src_rootW;
1265 struct callback_WtoA_context ctx;
1266 BOOL ret = FALSE;
1267
1268 src_rootW.Buffer = NULL;
1269 if (src_root && !RtlCreateUnicodeStringFromAsciiz( &src_rootW, src_root ))
1270 {
1271 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1272 return FALSE;
1273 }
1274
1275 if (RtlCreateUnicodeStringFromAsciiz( §ionW, section ))
1276 {
1277 ctx.orig_context = context;
1278 ctx.orig_handler = callback;
1279 ret = SetupInstallFromInfSectionW( owner, hinf, sectionW.Buffer, flags, key_root,
1280 src_rootW.Buffer, copy_flags, QUEUE_callback_WtoA,
1281 &ctx, devinfo, devinfo_data );
1282 RtlFreeUnicodeString( §ionW );
1283 }
1284 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1285
1286 RtlFreeUnicodeString( &src_rootW );
1287 return ret;
1288 }
1289
1290
1291 /***********************************************************************
1292 * include_callback
1293 *
1294 * Called once for each Include entry in a given section.
1295 */
include_callback(HINF hinf,PCWSTR field,void * arg)1296 static BOOL include_callback( HINF hinf, PCWSTR field, void *arg )
1297 {
1298 return SetupOpenAppendInfFileW( field, hinf, NULL );
1299 }
1300
1301
1302 /***********************************************************************
1303 * needs_callback
1304 *
1305 * Called once for each Needs entry in a given section.
1306 */
needs_callback(HINF hinf,PCWSTR field,void * arg)1307 static BOOL needs_callback( HINF hinf, PCWSTR field, void *arg )
1308 {
1309 struct needs_callback_info *info = arg;
1310
1311 switch (info->type)
1312 {
1313 case 0:
1314 return SetupInstallFromInfSectionW(info->owner, *(HINF*)hinf, field, info->flags,
1315 info->key_root, info->src_root, info->copy_flags, info->callback,
1316 info->context, info->devinfo, info->devinfo_data);
1317 case 1:
1318 return SetupInstallServicesFromInfSectionExW(*(HINF*)hinf, field, info->flags,
1319 info->devinfo, info->devinfo_data, info->reserved1, info->reserved2);
1320 default:
1321 ERR("Unknown info type %u\n", info->type);
1322 return FALSE;
1323 }
1324 }
1325
1326
1327 /***********************************************************************
1328 * SetupInstallFromInfSectionW (SETUPAPI.@)
1329 */
SetupInstallFromInfSectionW(HWND owner,HINF hinf,PCWSTR section,UINT flags,HKEY key_root,PCWSTR src_root,UINT copy_flags,PSP_FILE_CALLBACK_W callback,PVOID context,HDEVINFO devinfo,PSP_DEVINFO_DATA devinfo_data)1330 BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section, UINT flags,
1331 HKEY key_root, PCWSTR src_root, UINT copy_flags,
1332 PSP_FILE_CALLBACK_W callback, PVOID context,
1333 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
1334 {
1335 struct needs_callback_info needs_info;
1336
1337 /* Parse 'Include' and 'Needs' directives */
1338 iterate_section_fields( hinf, section, Include, include_callback, NULL);
1339 needs_info.type = 0;
1340 needs_info.owner = owner;
1341 needs_info.flags = flags;
1342 needs_info.key_root = key_root;
1343 needs_info.src_root = src_root;
1344 needs_info.copy_flags = copy_flags;
1345 needs_info.callback = callback;
1346 needs_info.context = context;
1347 needs_info.devinfo = devinfo;
1348 needs_info.devinfo_data = devinfo_data;
1349 iterate_section_fields( hinf, section, Needs, needs_callback, &needs_info);
1350
1351 if (flags & SPINST_FILES)
1352 {
1353 SP_DEVINSTALL_PARAMS_W install_params;
1354 struct files_callback_info info;
1355 HSPFILEQ queue = NULL;
1356 BOOL use_custom_queue;
1357 BOOL ret;
1358
1359 install_params.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
1360 use_custom_queue = SetupDiGetDeviceInstallParamsW(devinfo, devinfo_data, &install_params) && (install_params.Flags & DI_NOVCP);
1361 if (!use_custom_queue && ((queue = SetupOpenFileQueue()) == (HSPFILEQ)INVALID_HANDLE_VALUE ))
1362 return FALSE;
1363 info.queue = use_custom_queue ? install_params.FileQueue : queue;
1364 info.src_root = src_root;
1365 info.copy_flags = copy_flags;
1366 info.layout = hinf;
1367 ret = (iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ) &&
1368 iterate_section_fields( hinf, section, DelFiles, delete_files_callback, &info ) &&
1369 iterate_section_fields( hinf, section, RenFiles, rename_files_callback, &info ));
1370 if (!use_custom_queue)
1371 {
1372 if (ret)
1373 ret = SetupCommitFileQueueW( owner, queue, callback, context );
1374 SetupCloseFileQueue( queue );
1375 }
1376 if (!ret) return FALSE;
1377 }
1378 if (flags & SPINST_INIFILES)
1379 {
1380 if (!iterate_section_fields( hinf, section, UpdateInis, update_ini_callback, NULL ) ||
1381 !iterate_section_fields( hinf, section, UpdateIniFields,
1382 update_ini_fields_callback, NULL ))
1383 return FALSE;
1384 }
1385 if (flags & SPINST_INI2REG)
1386 {
1387 if (!iterate_section_fields( hinf, section, Ini2Reg, ini2reg_callback, NULL ))
1388 return FALSE;
1389 }
1390 if (flags & SPINST_LOGCONFIG)
1391 {
1392 if (!iterate_section_fields( hinf, section, LogConf, logconf_callback, NULL ))
1393 return FALSE;
1394 }
1395 if (flags & SPINST_REGSVR)
1396 {
1397 struct register_dll_info info;
1398
1399 info.unregister = FALSE;
1400 if (flags & SPINST_REGISTERCALLBACKAWARE)
1401 {
1402 info.callback = callback;
1403 info.callback_context = context;
1404 }
1405 else info.callback = NULL;
1406
1407 if (!iterate_section_fields( hinf, section, RegisterDlls, register_dlls_callback, &info ))
1408 return FALSE;
1409
1410 #ifdef __WINESRC__
1411 if (!iterate_section_fields( hinf, section, WineFakeDlls, fake_dlls_callback, NULL ))
1412 return FALSE;
1413 #endif // __WINESRC__
1414 }
1415 if (flags & SPINST_UNREGSVR)
1416 {
1417 struct register_dll_info info;
1418
1419 info.unregister = TRUE;
1420 if (flags & SPINST_REGISTERCALLBACKAWARE)
1421 {
1422 info.callback = callback;
1423 info.callback_context = context;
1424 }
1425 else info.callback = NULL;
1426
1427 if (!iterate_section_fields( hinf, section, UnregisterDlls, register_dlls_callback, &info ))
1428 return FALSE;
1429 }
1430 if (flags & SPINST_REGISTRY)
1431 {
1432 struct registry_callback_info info;
1433
1434 info.default_root = key_root;
1435 info.delete = TRUE;
1436 if (!iterate_section_fields( hinf, section, DelReg, registry_callback, &info ))
1437 return FALSE;
1438 info.delete = FALSE;
1439 if (!iterate_section_fields( hinf, section, AddReg, registry_callback, &info ))
1440 return FALSE;
1441 }
1442 if (flags & SPINST_BITREG)
1443 {
1444 if (!iterate_section_fields( hinf, section, BitReg, bitreg_callback, NULL ))
1445 return FALSE;
1446 }
1447 if (flags & SPINST_PROFILEITEMS)
1448 {
1449 if (!iterate_section_fields( hinf, section, ProfileItems, profile_items_callback, NULL ))
1450 return FALSE;
1451 }
1452 if (flags & SPINST_COPYINF)
1453 {
1454 if (!iterate_section_fields( hinf, section, CopyINF, copy_inf_callback, NULL ))
1455 return FALSE;
1456 }
1457
1458 return TRUE;
1459 }
1460
1461
1462 /***********************************************************************
1463 * InstallHinfSectionW (SETUPAPI.@)
1464 *
1465 * NOTE: 'cmdline' is <section> <mode> <path> from
1466 * RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection <section> <mode> <path>
1467 */
InstallHinfSectionW(HWND hwnd,HINSTANCE handle,LPCWSTR cmdline,INT show)1468 void WINAPI InstallHinfSectionW( HWND hwnd, HINSTANCE handle, LPCWSTR cmdline, INT show )
1469 {
1470 BOOL ret = FALSE;
1471 WCHAR *s, *path, section[MAX_PATH];
1472 void *callback_context = NULL;
1473 DWORD SectionNameLength;
1474 UINT mode;
1475 HINF hinf = INVALID_HANDLE_VALUE;
1476 BOOL bRebootRequired = FALSE;
1477
1478 TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd, handle, debugstr_w(cmdline));
1479
1480 lstrcpynW( section, cmdline, MAX_PATH );
1481
1482 if (!(s = strchrW( section, ' ' ))) goto cleanup;
1483 *s++ = 0;
1484 while (*s == ' ') s++;
1485 mode = atoiW( s );
1486
1487 /* quoted paths are not allowed on native, the rest of the command line is taken as the path */
1488 if (!(s = strchrW( s, ' ' ))) goto cleanup;
1489 while (*s == ' ') s++;
1490 path = s;
1491
1492 if (mode & 0x80)
1493 {
1494 FIXME("default path of the installation not changed\n");
1495 mode &= ~0x80;
1496 }
1497
1498 hinf = SetupOpenInfFileW( path, NULL, INF_STYLE_WIN4, NULL );
1499 if (hinf == INVALID_HANDLE_VALUE)
1500 {
1501 WARN("SetupOpenInfFileW(%s) failed (Error %u)\n", path, GetLastError());
1502 goto cleanup;
1503 }
1504
1505 ret = SetupDiGetActualSectionToInstallW(
1506 hinf, section, section, sizeof(section)/sizeof(section[0]), &SectionNameLength, NULL );
1507 if (!ret)
1508 {
1509 WARN("SetupDiGetActualSectionToInstallW() failed (Error %u)\n", GetLastError());
1510 goto cleanup;
1511 }
1512 if (SectionNameLength > MAX_PATH - strlenW(DotServices))
1513 {
1514 WARN("Section name '%s' too long\n", section);
1515 goto cleanup;
1516 }
1517
1518 /* Copy files and add registry entries */
1519 callback_context = SetupInitDefaultQueueCallback( hwnd );
1520 ret = SetupInstallFromInfSectionW( hwnd, hinf, section, SPINST_ALL, NULL, NULL,
1521 SP_COPY_NEWER | SP_COPY_IN_USE_NEEDS_REBOOT,
1522 SetupDefaultQueueCallbackW, callback_context,
1523 NULL, NULL );
1524 if (!ret)
1525 {
1526 WARN("SetupInstallFromInfSectionW() failed (Error %u)\n", GetLastError());
1527 goto cleanup;
1528 }
1529 /* FIXME: need to check if some files were in use and need reboot
1530 * bReboot = ...;
1531 */
1532
1533 /* Install services */
1534 wcscat(section, DotServices);
1535 ret = SetupInstallServicesFromInfSectionW( hinf, section, 0 );
1536 if (!ret && GetLastError() == ERROR_SECTION_NOT_FOUND)
1537 ret = TRUE;
1538 if (!ret)
1539 {
1540 WARN("SetupInstallServicesFromInfSectionW() failed (Error %u)\n", GetLastError());
1541 goto cleanup;
1542 }
1543 else if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
1544 {
1545 bRebootRequired = TRUE;
1546 }
1547
1548 /* Check if we need to reboot */
1549 switch (mode)
1550 {
1551 case 0:
1552 /* Never reboot */
1553 break;
1554 case 1:
1555 /* Always reboot */
1556 ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_APPLICATION |
1557 SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED);
1558 break;
1559 case 2:
1560 /* Query user before rebooting */
1561 SetupPromptReboot(NULL, hwnd, FALSE);
1562 break;
1563 case 3:
1564 /* Reboot if necessary */
1565 if (bRebootRequired)
1566 {
1567 ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_APPLICATION |
1568 SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED);
1569 }
1570 break;
1571 case 4:
1572 /* If necessary, query user before rebooting */
1573 if (bRebootRequired)
1574 {
1575 SetupPromptReboot(NULL, hwnd, FALSE);
1576 }
1577 break;
1578 default:
1579 break;
1580 }
1581
1582 cleanup:
1583 if ( callback_context )
1584 SetupTermDefaultQueueCallback( callback_context );
1585 if ( hinf != INVALID_HANDLE_VALUE )
1586 SetupCloseInfFile( hinf );
1587
1588 #ifdef CORE_11689_IS_FIXED
1589 // TODO: Localize the error string.
1590 if (!ret && !(GlobalSetupFlags & PSPGF_NONINTERACTIVE))
1591 {
1592 MessageBoxW(hwnd, section, L"setupapi.dll: An error happened...", MB_ICONERROR | MB_OK);
1593 }
1594 #endif
1595 }
1596
1597
1598 /***********************************************************************
1599 * InstallHinfSectionA (SETUPAPI.@)
1600 */
InstallHinfSectionA(HWND hwnd,HINSTANCE handle,LPCSTR cmdline,INT show)1601 void WINAPI InstallHinfSectionA( HWND hwnd, HINSTANCE handle, LPCSTR cmdline, INT show )
1602 {
1603 UNICODE_STRING cmdlineW;
1604
1605 if (RtlCreateUnicodeStringFromAsciiz( &cmdlineW, cmdline ))
1606 {
1607 InstallHinfSectionW( hwnd, handle, cmdlineW.Buffer, show );
1608 RtlFreeUnicodeString( &cmdlineW );
1609 }
1610 }
1611
1612 /***********************************************************************
1613 * SetupInstallServicesFromInfSectionW (SETUPAPI.@)
1614 */
SetupInstallServicesFromInfSectionW(HINF Inf,PCWSTR SectionName,DWORD Flags)1615 BOOL WINAPI SetupInstallServicesFromInfSectionW( HINF Inf, PCWSTR SectionName, DWORD Flags)
1616 {
1617 return SetupInstallServicesFromInfSectionExW( Inf, SectionName, Flags,
1618 NULL, NULL, NULL, NULL );
1619 }
1620
1621 /***********************************************************************
1622 * SetupInstallServicesFromInfSectionA (SETUPAPI.@)
1623 */
SetupInstallServicesFromInfSectionA(HINF Inf,PCSTR SectionName,DWORD Flags)1624 BOOL WINAPI SetupInstallServicesFromInfSectionA( HINF Inf, PCSTR SectionName, DWORD Flags)
1625 {
1626 return SetupInstallServicesFromInfSectionExA( Inf, SectionName, Flags,
1627 NULL, NULL, NULL, NULL );
1628 }
1629
1630 /***********************************************************************
1631 * SetupInstallServicesFromInfSectionExA (SETUPAPI.@)
1632 */
SetupInstallServicesFromInfSectionExA(HINF hinf,PCSTR sectionname,DWORD flags,HDEVINFO devinfo,PSP_DEVINFO_DATA devinfo_data,PVOID reserved1,PVOID reserved2)1633 BOOL WINAPI SetupInstallServicesFromInfSectionExA( HINF hinf, PCSTR sectionname, DWORD flags, HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data, PVOID reserved1, PVOID reserved2 )
1634 {
1635 UNICODE_STRING sectionnameW;
1636 BOOL ret = FALSE;
1637
1638 if (RtlCreateUnicodeStringFromAsciiz( §ionnameW, sectionname ))
1639 {
1640 ret = SetupInstallServicesFromInfSectionExW( hinf, sectionnameW.Buffer, flags, devinfo, devinfo_data, reserved1, reserved2 );
1641 RtlFreeUnicodeString( §ionnameW );
1642 }
1643 else
1644 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1645
1646 return ret;
1647 }
1648
1649
GetLineText(HINF hinf,PCWSTR section_name,PCWSTR key_name,PWSTR * value)1650 static BOOL GetLineText( HINF hinf, PCWSTR section_name, PCWSTR key_name, PWSTR *value)
1651 {
1652 DWORD required;
1653 PWSTR buf = NULL;
1654
1655 *value = NULL;
1656
1657 if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, NULL, 0, &required )
1658 && GetLastError() != ERROR_INSUFFICIENT_BUFFER )
1659 return FALSE;
1660
1661 buf = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) );
1662 if ( ! buf )
1663 {
1664 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1665 return FALSE;
1666 }
1667
1668 if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, buf, required, &required ) )
1669 {
1670 HeapFree( GetProcessHeap(), 0, buf );
1671 return FALSE;
1672 }
1673
1674 *value = buf;
1675 return TRUE;
1676 }
1677
1678
GetIntField(HINF hinf,PCWSTR section_name,PCWSTR key_name,INT * value)1679 static BOOL GetIntField( HINF hinf, PCWSTR section_name, PCWSTR key_name, INT *value)
1680 {
1681 LPWSTR buffer, end;
1682 INT res;
1683
1684 if (! GetLineText( hinf, section_name, key_name, &buffer ) )
1685 return FALSE;
1686
1687 res = wcstol( buffer, &end, 0 );
1688 if (end != buffer && !*end)
1689 {
1690 HeapFree(GetProcessHeap(), 0, buffer);
1691 *value = res;
1692 return TRUE;
1693 }
1694 else
1695 {
1696 HeapFree(GetProcessHeap(), 0, buffer);
1697 SetLastError( ERROR_INVALID_DATA );
1698 return FALSE;
1699 }
1700 }
1701
1702
GetStringField(PINFCONTEXT context,DWORD index,PWSTR * value)1703 BOOL GetStringField( PINFCONTEXT context, DWORD index, PWSTR *value)
1704 {
1705 DWORD RequiredSize;
1706 BOOL ret;
1707
1708 ret = SetupGetStringFieldW(
1709 context,
1710 index,
1711 NULL, 0,
1712 &RequiredSize);
1713 if (!ret)
1714 return FALSE;
1715 else if (RequiredSize == 0)
1716 {
1717 *value = NULL;
1718 return TRUE;
1719 }
1720
1721 /* We got the needed size for the buffer */
1722 *value = MyMalloc(RequiredSize * sizeof(WCHAR));
1723 if (!*value)
1724 {
1725 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1726 return FALSE;
1727 }
1728 ret = SetupGetStringFieldW(
1729 context,
1730 index,
1731 *value, RequiredSize, NULL);
1732 if (!ret)
1733 MyFree(*value);
1734
1735 return ret;
1736 }
1737
FixupServiceBinaryPath(IN DWORD ServiceType,IN OUT LPWSTR * ServiceBinary)1738 static VOID FixupServiceBinaryPath(
1739 IN DWORD ServiceType,
1740 IN OUT LPWSTR *ServiceBinary)
1741 {
1742 LPWSTR Buffer;
1743 WCHAR ReactOSDir[MAX_PATH];
1744 DWORD RosDirLength, ServiceLength, Win32Length;
1745
1746 GetWindowsDirectoryW(ReactOSDir, MAX_PATH);
1747 RosDirLength = strlenW(ReactOSDir);
1748 ServiceLength = strlenW(*ServiceBinary);
1749
1750 /* Check and fix two things:
1751 1. Get rid of C:\ReactOS and use relative
1752 path instead.
1753 2. Add %SystemRoot% for Win32 services */
1754
1755 if (ServiceLength < RosDirLength)
1756 return;
1757
1758 if (!wcsnicmp(*ServiceBinary, ReactOSDir, RosDirLength))
1759 {
1760 /* Yes, the first part is the C:\ReactOS\, just skip it */
1761 MoveMemory(*ServiceBinary, *ServiceBinary + RosDirLength + 1,
1762 (ServiceLength - RosDirLength) * sizeof(WCHAR));
1763
1764 /* Handle Win32-services differently */
1765 if (ServiceType & SERVICE_WIN32)
1766 {
1767 Win32Length = (ServiceLength - RosDirLength) * sizeof(WCHAR)
1768 - sizeof(L'\\') + sizeof(L"%SystemRoot%\\");
1769 Buffer = MyMalloc(Win32Length);
1770
1771 wcscpy(Buffer, L"%SystemRoot%\\");
1772 wcscat(Buffer, *ServiceBinary);
1773 MyFree(*ServiceBinary);
1774
1775 *ServiceBinary = Buffer;
1776 }
1777 }
1778 }
1779
InstallOneService(struct DeviceInfoSet * list,IN HINF hInf,IN LPCWSTR ServiceSection,IN LPCWSTR ServiceName,IN UINT ServiceFlags)1780 static BOOL InstallOneService(
1781 struct DeviceInfoSet *list,
1782 IN HINF hInf,
1783 IN LPCWSTR ServiceSection,
1784 IN LPCWSTR ServiceName,
1785 IN UINT ServiceFlags)
1786 {
1787 SC_HANDLE hSCManager = NULL;
1788 SC_HANDLE hService = NULL;
1789 LPDWORD GroupOrder = NULL;
1790 LPQUERY_SERVICE_CONFIGW ServiceConfig = NULL;
1791 HKEY hServicesKey, hServiceKey;
1792 LONG rc;
1793 BOOL ret = FALSE;
1794
1795 HKEY hGroupOrderListKey = NULL;
1796 LPWSTR ServiceBinary = NULL;
1797 LPWSTR LoadOrderGroup = NULL;
1798 LPWSTR DisplayName = NULL;
1799 LPWSTR Description = NULL;
1800 LPWSTR Dependencies = NULL;
1801 LPWSTR StartName = NULL;
1802 LPWSTR SecurityDescriptor = NULL;
1803 PSECURITY_DESCRIPTOR sd = NULL;
1804 INT ServiceType, StartType, ErrorControl;
1805 DWORD dwRegType;
1806 DWORD tagId = (DWORD)-1;
1807 BOOL useTag;
1808
1809 if (!GetIntField(hInf, ServiceSection, ServiceTypeKey, &ServiceType))
1810 {
1811 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT );
1812 goto cleanup;
1813 }
1814 if (!GetIntField(hInf, ServiceSection, StartTypeKey, &StartType))
1815 {
1816 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT );
1817 goto cleanup;
1818 }
1819 if (!GetIntField(hInf, ServiceSection, ErrorControlKey, &ErrorControl))
1820 {
1821 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT );
1822 goto cleanup;
1823 }
1824 useTag = (ServiceType == SERVICE_BOOT_START || ServiceType == SERVICE_SYSTEM_START);
1825
1826 hSCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE);
1827 if (hSCManager == NULL)
1828 goto cleanup;
1829
1830 if (!GetLineText(hInf, ServiceSection, ServiceBinaryKey, &ServiceBinary))
1831 {
1832 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT );
1833 goto cleanup;
1834 }
1835
1836 /* Adjust binary path according to the service type */
1837 FixupServiceBinaryPath(ServiceType, &ServiceBinary);
1838
1839 /* Don't check return value, as these fields are optional and
1840 * GetLineText initialize output parameter even on failure */
1841 GetLineText(hInf, ServiceSection, LoadOrderGroupKey, &LoadOrderGroup);
1842 GetLineText(hInf, ServiceSection, DisplayNameKey, &DisplayName);
1843 GetLineText(hInf, ServiceSection, DescriptionKey, &Description);
1844 GetLineText(hInf, ServiceSection, DependenciesKey, &Dependencies);
1845 GetLineText(hInf, ServiceSection, StartNameKey, &StartName);
1846
1847 /* If there is no group, we must not request a tag */
1848 if (!LoadOrderGroup || !*LoadOrderGroup)
1849 useTag = FALSE;
1850
1851 hService = OpenServiceW(
1852 hSCManager,
1853 ServiceName,
1854 DELETE | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | WRITE_DAC);
1855 if (hService == NULL && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
1856 goto cleanup;
1857
1858 if (hService && (ServiceFlags & SPSVCINST_DELETEEVENTLOGENTRY))
1859 {
1860 ret = DeleteService(hService);
1861 if (!ret && GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
1862 goto cleanup;
1863 }
1864
1865 if (hService == NULL)
1866 {
1867 /* Create new service */
1868 hService = CreateServiceW(
1869 hSCManager,
1870 ServiceName,
1871 DisplayName,
1872 WRITE_DAC,
1873 ServiceType,
1874 StartType,
1875 ErrorControl,
1876 ServiceBinary,
1877 LoadOrderGroup,
1878 useTag ? &tagId : NULL,
1879 Dependencies,
1880 StartName,
1881 NULL);
1882 if (hService == NULL)
1883 goto cleanup;
1884 }
1885 else
1886 {
1887 DWORD bufferSize;
1888 /* Read current configuration */
1889 if (!QueryServiceConfigW(hService, NULL, 0, &bufferSize))
1890 {
1891 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1892 goto cleanup;
1893 ServiceConfig = MyMalloc(bufferSize);
1894 if (!ServiceConfig)
1895 {
1896 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1897 goto cleanup;
1898 }
1899 if (!QueryServiceConfigW(hService, ServiceConfig, bufferSize, &bufferSize))
1900 goto cleanup;
1901 }
1902 tagId = ServiceConfig->dwTagId;
1903
1904 /* Update configuration */
1905 ret = ChangeServiceConfigW(
1906 hService,
1907 ServiceType,
1908 (ServiceFlags & SPSVCINST_NOCLOBBER_STARTTYPE) ? SERVICE_NO_CHANGE : StartType,
1909 (ServiceFlags & SPSVCINST_NOCLOBBER_ERRORCONTROL) ? SERVICE_NO_CHANGE : ErrorControl,
1910 ServiceBinary,
1911 (ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP && ServiceConfig->lpLoadOrderGroup) ? NULL : LoadOrderGroup,
1912 useTag ? &tagId : NULL,
1913 (ServiceFlags & SPSVCINST_NOCLOBBER_DEPENDENCIES && ServiceConfig->lpDependencies) ? NULL : Dependencies,
1914 StartName,
1915 NULL,
1916 (ServiceFlags & SPSVCINST_NOCLOBBER_DISPLAYNAME && ServiceConfig->lpDisplayName) ? NULL : DisplayName);
1917 if (!ret)
1918 goto cleanup;
1919 }
1920
1921 /* Set security */
1922 if (GetLineText(hInf, ServiceSection, SecurityKey, &SecurityDescriptor))
1923 {
1924 ret = ConvertStringSecurityDescriptorToSecurityDescriptorW(SecurityDescriptor, SDDL_REVISION_1, &sd, NULL);
1925 if (!ret)
1926 goto cleanup;
1927 ret = SetServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, sd);
1928 if (!ret)
1929 goto cleanup;
1930 }
1931
1932 /* FIXME: use Description and SPSVCINST_NOCLOBBER_DESCRIPTION */
1933
1934 if (useTag)
1935 {
1936 /* Add the tag to SYSTEM\CurrentControlSet\Control\GroupOrderList key */
1937 LPCWSTR lpLoadOrderGroup;
1938 DWORD bufferSize;
1939
1940 lpLoadOrderGroup = LoadOrderGroup;
1941 if ((ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP) && ServiceConfig && ServiceConfig->lpLoadOrderGroup)
1942 lpLoadOrderGroup = ServiceConfig->lpLoadOrderGroup;
1943
1944 rc = RegOpenKeyW(
1945 list ? list->HKLM : HKEY_LOCAL_MACHINE,
1946 GroupOrderListKey,
1947 &hGroupOrderListKey);
1948 if (rc != ERROR_SUCCESS)
1949 {
1950 SetLastError(rc);
1951 goto cleanup;
1952 }
1953 rc = RegQueryValueExW(hGroupOrderListKey, lpLoadOrderGroup, NULL, &dwRegType, NULL, &bufferSize);
1954 if (rc == ERROR_FILE_NOT_FOUND)
1955 bufferSize = sizeof(DWORD);
1956 else if (rc != ERROR_SUCCESS)
1957 {
1958 SetLastError(rc);
1959 goto cleanup;
1960 }
1961 else if (dwRegType != REG_BINARY || bufferSize == 0 || bufferSize % sizeof(DWORD) != 0)
1962 {
1963 SetLastError(ERROR_GEN_FAILURE);
1964 goto cleanup;
1965 }
1966 /* Allocate buffer to store existing data + the new tag */
1967 GroupOrder = MyMalloc(bufferSize + sizeof(DWORD));
1968 if (!GroupOrder)
1969 {
1970 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1971 goto cleanup;
1972 }
1973 if (rc == ERROR_SUCCESS)
1974 {
1975 /* Read existing data */
1976 rc = RegQueryValueExW(
1977 hGroupOrderListKey,
1978 lpLoadOrderGroup,
1979 NULL,
1980 NULL,
1981 (BYTE*)GroupOrder,
1982 &bufferSize);
1983 if (rc != ERROR_SUCCESS)
1984 {
1985 SetLastError(rc);
1986 goto cleanup;
1987 }
1988 if (ServiceFlags & SPSVCINST_TAGTOFRONT)
1989 memmove(&GroupOrder[2], &GroupOrder[1], bufferSize - sizeof(DWORD));
1990 }
1991 else
1992 {
1993 GroupOrder[0] = 0;
1994 }
1995 GroupOrder[0]++;
1996 if (ServiceFlags & SPSVCINST_TAGTOFRONT)
1997 GroupOrder[1] = tagId;
1998 else
1999 GroupOrder[bufferSize / sizeof(DWORD)] = tagId;
2000
2001 rc = RegSetValueExW(
2002 hGroupOrderListKey,
2003 lpLoadOrderGroup,
2004 0,
2005 REG_BINARY,
2006 (BYTE*)GroupOrder,
2007 bufferSize + sizeof(DWORD));
2008 if (rc != ERROR_SUCCESS)
2009 {
2010 SetLastError(rc);
2011 goto cleanup;
2012 }
2013 }
2014
2015 /* Handle AddReg and DelReg */
2016 rc = RegOpenKeyExW(
2017 list ? list->HKLM : HKEY_LOCAL_MACHINE,
2018 REGSTR_PATH_SERVICES,
2019 0,
2020 READ_CONTROL,
2021 &hServicesKey);
2022 if (rc != ERROR_SUCCESS)
2023 {
2024 SetLastError(rc);
2025 goto cleanup;
2026 }
2027 rc = RegOpenKeyExW(
2028 hServicesKey,
2029 ServiceName,
2030 0,
2031 KEY_READ | KEY_WRITE,
2032 &hServiceKey);
2033 RegCloseKey(hServicesKey);
2034 if (rc != ERROR_SUCCESS)
2035 {
2036 SetLastError(rc);
2037 goto cleanup;
2038 }
2039
2040 ret = SetupInstallFromInfSectionW(
2041 NULL,
2042 hInf,
2043 ServiceSection,
2044 SPINST_REGISTRY,
2045 hServiceKey,
2046 NULL,
2047 0,
2048 NULL,
2049 NULL,
2050 NULL,
2051 NULL);
2052 RegCloseKey(hServiceKey);
2053
2054 cleanup:
2055 if (hSCManager != NULL)
2056 CloseServiceHandle(hSCManager);
2057 if (hService != NULL)
2058 CloseServiceHandle(hService);
2059 if (hGroupOrderListKey != NULL)
2060 RegCloseKey(hGroupOrderListKey);
2061 if (sd != NULL)
2062 LocalFree(sd);
2063 MyFree(ServiceConfig);
2064 MyFree(ServiceBinary);
2065 MyFree(LoadOrderGroup);
2066 MyFree(DisplayName);
2067 MyFree(Description);
2068 MyFree(Dependencies);
2069 MyFree(SecurityDescriptor);
2070 MyFree(GroupOrder);
2071 MyFree(StartName);
2072
2073 TRACE("Returning %d\n", ret);
2074 return ret;
2075 }
2076
2077
2078 /***********************************************************************
2079 * SetupInstallServicesFromInfSectionExW (SETUPAPI.@)
2080 */
SetupInstallServicesFromInfSectionExW(HINF hinf,PCWSTR sectionname,DWORD flags,HDEVINFO DeviceInfoSet,PSP_DEVINFO_DATA DeviceInfoData,PVOID reserved1,PVOID reserved2)2081 BOOL WINAPI SetupInstallServicesFromInfSectionExW( HINF hinf, PCWSTR sectionname, DWORD flags, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PVOID reserved1, PVOID reserved2 )
2082 {
2083 struct DeviceInfoSet *list = NULL;
2084 BOOL ret = FALSE;
2085
2086 TRACE("%p, %s, 0x%lx, %p, %p, %p, %p\n", hinf, debugstr_w(sectionname),
2087 flags, DeviceInfoSet, DeviceInfoData, reserved1, reserved2);
2088
2089 if (!sectionname)
2090 SetLastError(ERROR_INVALID_PARAMETER);
2091 else if (flags & ~(SPSVCINST_TAGTOFRONT | SPSVCINST_DELETEEVENTLOGENTRY | SPSVCINST_NOCLOBBER_DISPLAYNAME | SPSVCINST_NOCLOBBER_STARTTYPE | SPSVCINST_NOCLOBBER_ERRORCONTROL | SPSVCINST_NOCLOBBER_LOADORDERGROUP | SPSVCINST_NOCLOBBER_DEPENDENCIES | SPSVCINST_STOPSERVICE))
2092 {
2093 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));
2094 SetLastError(ERROR_INVALID_FLAGS);
2095 }
2096 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2097 SetLastError(ERROR_INVALID_HANDLE);
2098 else if (DeviceInfoSet && (list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2099 SetLastError(ERROR_INVALID_HANDLE);
2100 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2101 SetLastError(ERROR_INVALID_USER_BUFFER);
2102 else if (reserved1 != NULL || reserved2 != NULL)
2103 SetLastError(ERROR_INVALID_PARAMETER);
2104 else
2105 {
2106 struct needs_callback_info needs_info;
2107 LPWSTR ServiceName = NULL;
2108 LPWSTR ServiceSection = NULL;
2109 INT ServiceFlags;
2110 INFCONTEXT ContextService;
2111 BOOL bNeedReboot = FALSE;
2112
2113 /* Parse 'Include' and 'Needs' directives */
2114 iterate_section_fields( hinf, sectionname, Include, include_callback, NULL);
2115 needs_info.type = 1;
2116 needs_info.flags = flags;
2117 needs_info.devinfo = DeviceInfoSet;
2118 needs_info.devinfo_data = DeviceInfoData;
2119 needs_info.reserved1 = reserved1;
2120 needs_info.reserved2 = reserved2;
2121 iterate_section_fields( hinf, sectionname, Needs, needs_callback, &needs_info);
2122
2123 if (flags & SPSVCINST_STOPSERVICE)
2124 {
2125 FIXME("Stopping the device not implemented\n");
2126 /* This may lead to require a reboot */
2127 /* bNeedReboot = TRUE; */
2128 #if 0
2129 SERVICE_STATUS ServiceStatus;
2130 ret = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus);
2131 if (!ret && GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
2132 goto done;
2133 if (ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING && ServiceStatus.dwCurrentState != SERVICE_STOPPED)
2134 {
2135 SetLastError(ERROR_INSTALL_SERVICE_FAILURE);
2136 goto done;
2137 }
2138 #endif
2139 flags &= ~SPSVCINST_STOPSERVICE;
2140 }
2141
2142 if (!(ret = SetupFindFirstLineW( hinf, sectionname, NULL, &ContextService )))
2143 {
2144 SetLastError( ERROR_SECTION_NOT_FOUND );
2145 goto done;
2146 }
2147
2148 ret = SetupFindFirstLineW(hinf, sectionname, AddService, &ContextService);
2149 while (ret)
2150 {
2151 if (!GetStringField(&ContextService, 1, &ServiceName))
2152 goto done;
2153
2154 ret = SetupGetIntField(
2155 &ContextService,
2156 2, /* Field index */
2157 &ServiceFlags);
2158 if (!ret)
2159 {
2160 /* The field may be empty. Ignore the error */
2161 ServiceFlags = 0;
2162 }
2163
2164 if (!GetStringField(&ContextService, 3, &ServiceSection))
2165 goto done;
2166
2167 ret = InstallOneService(list, hinf, ServiceSection, ServiceName, (ServiceFlags & ~SPSVCINST_ASSOCSERVICE) | flags);
2168 if (!ret)
2169 goto done;
2170
2171 if (ServiceFlags & SPSVCINST_ASSOCSERVICE)
2172 {
2173 ret = SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet, DeviceInfoData, SPDRP_SERVICE, (LPBYTE)ServiceName, (strlenW(ServiceName) + 1) * sizeof(WCHAR));
2174 if (!ret)
2175 goto done;
2176 }
2177
2178 HeapFree(GetProcessHeap(), 0, ServiceName);
2179 HeapFree(GetProcessHeap(), 0, ServiceSection);
2180 ServiceName = ServiceSection = NULL;
2181 ret = SetupFindNextMatchLineW(&ContextService, AddService, &ContextService);
2182 }
2183
2184 if (bNeedReboot)
2185 SetLastError(ERROR_SUCCESS_REBOOT_REQUIRED);
2186 else
2187 SetLastError(ERROR_SUCCESS);
2188 ret = TRUE;
2189 }
2190 done:
2191 TRACE("Returning %d\n", ret);
2192 return ret;
2193 }
2194
2195
2196 /***********************************************************************
2197 * SetupCopyOEMInfA (SETUPAPI.@)
2198 */
SetupCopyOEMInfA(IN PCSTR SourceInfFileName,IN PCSTR OEMSourceMediaLocation,IN DWORD OEMSourceMediaType,IN DWORD CopyStyle,OUT PSTR DestinationInfFileName OPTIONAL,IN DWORD DestinationInfFileNameSize,OUT PDWORD RequiredSize OPTIONAL,OUT PSTR * DestinationInfFileNameComponent OPTIONAL)2199 BOOL WINAPI SetupCopyOEMInfA(
2200 IN PCSTR SourceInfFileName,
2201 IN PCSTR OEMSourceMediaLocation,
2202 IN DWORD OEMSourceMediaType,
2203 IN DWORD CopyStyle,
2204 OUT PSTR DestinationInfFileName OPTIONAL,
2205 IN DWORD DestinationInfFileNameSize,
2206 OUT PDWORD RequiredSize OPTIONAL,
2207 OUT PSTR* DestinationInfFileNameComponent OPTIONAL)
2208 {
2209 PWSTR SourceInfFileNameW = NULL;
2210 PWSTR OEMSourceMediaLocationW = NULL;
2211 PWSTR DestinationInfFileNameW = NULL;
2212 PWSTR DestinationInfFileNameComponentW = NULL;
2213 BOOL ret = FALSE;
2214 DWORD size;
2215
2216 TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n",
2217 SourceInfFileName, OEMSourceMediaLocation, OEMSourceMediaType,
2218 CopyStyle, DestinationInfFileName, DestinationInfFileNameSize,
2219 RequiredSize, DestinationInfFileNameComponent);
2220
2221 if (!DestinationInfFileName && DestinationInfFileNameSize > 0)
2222 SetLastError(ERROR_INVALID_PARAMETER);
2223 else if (!(SourceInfFileNameW = pSetupMultiByteToUnicode(SourceInfFileName, CP_ACP)))
2224 SetLastError(ERROR_INVALID_PARAMETER);
2225 else if (OEMSourceMediaType != SPOST_NONE && !(OEMSourceMediaLocationW = pSetupMultiByteToUnicode(OEMSourceMediaLocation, CP_ACP)))
2226 SetLastError(ERROR_INVALID_PARAMETER);
2227 else
2228 {
2229 if (DestinationInfFileNameSize != 0)
2230 {
2231 DestinationInfFileNameW = MyMalloc(DestinationInfFileNameSize * sizeof(WCHAR));
2232 if (!DestinationInfFileNameW)
2233 {
2234 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2235 goto cleanup;
2236 }
2237 }
2238
2239 ret = SetupCopyOEMInfW(
2240 SourceInfFileNameW,
2241 OEMSourceMediaLocationW,
2242 OEMSourceMediaType,
2243 CopyStyle,
2244 DestinationInfFileNameW,
2245 DestinationInfFileNameSize,
2246 &size,
2247 DestinationInfFileNameComponent ? &DestinationInfFileNameComponentW : NULL);
2248 if (!ret)
2249 {
2250 if (RequiredSize) *RequiredSize = size;
2251 goto cleanup;
2252 }
2253
2254 if (DestinationInfFileNameSize != 0)
2255 {
2256 if (WideCharToMultiByte(CP_ACP, 0, DestinationInfFileNameW, -1,
2257 DestinationInfFileName, DestinationInfFileNameSize, NULL, NULL) == 0)
2258 {
2259 DestinationInfFileName[0] = '\0';
2260 goto cleanup;
2261 }
2262 }
2263 if (DestinationInfFileNameComponent)
2264 {
2265 if (DestinationInfFileNameComponentW)
2266 *DestinationInfFileNameComponent = &DestinationInfFileName[DestinationInfFileNameComponentW - DestinationInfFileNameW];
2267 else
2268 *DestinationInfFileNameComponent = NULL;
2269 }
2270 ret = TRUE;
2271 }
2272
2273 cleanup:
2274 MyFree(SourceInfFileNameW);
2275 MyFree(OEMSourceMediaLocationW);
2276 MyFree(DestinationInfFileNameW);
2277 TRACE("Returning %d\n", ret);
2278 if (ret) SetLastError(ERROR_SUCCESS);
2279 return ret;
2280 }
2281
compare_files(HANDLE file1,HANDLE file2)2282 static int compare_files( HANDLE file1, HANDLE file2 )
2283 {
2284 char buffer1[2048];
2285 char buffer2[2048];
2286 DWORD size1;
2287 DWORD size2;
2288
2289 while( ReadFile(file1, buffer1, sizeof(buffer1), &size1, NULL) &&
2290 ReadFile(file2, buffer2, sizeof(buffer2), &size2, NULL) )
2291 {
2292 int ret;
2293 if (size1 != size2)
2294 return size1 > size2 ? 1 : -1;
2295 if (!size1)
2296 return 0;
2297 ret = memcmp( buffer1, buffer2, size1 );
2298 if (ret)
2299 return ret;
2300 }
2301
2302 return 0;
2303 }
2304
2305 /***********************************************************************
2306 * SetupCopyOEMInfW (SETUPAPI.@)
2307 */
SetupCopyOEMInfW(IN PCWSTR SourceInfFileName,IN PCWSTR OEMSourceMediaLocation,IN DWORD OEMSourceMediaType,IN DWORD CopyStyle,OUT PWSTR DestinationInfFileName OPTIONAL,IN DWORD DestinationInfFileNameSize,OUT PDWORD RequiredSize OPTIONAL,OUT PWSTR * DestinationInfFileNameComponent OPTIONAL)2308 BOOL WINAPI SetupCopyOEMInfW(
2309 IN PCWSTR SourceInfFileName,
2310 IN PCWSTR OEMSourceMediaLocation,
2311 IN DWORD OEMSourceMediaType,
2312 IN DWORD CopyStyle,
2313 OUT PWSTR DestinationInfFileName OPTIONAL,
2314 IN DWORD DestinationInfFileNameSize,
2315 OUT PDWORD RequiredSize OPTIONAL,
2316 OUT PWSTR* DestinationInfFileNameComponent OPTIONAL)
2317 {
2318 BOOL ret = FALSE;
2319
2320 TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n",
2321 debugstr_w(SourceInfFileName), debugstr_w(OEMSourceMediaLocation), OEMSourceMediaType,
2322 CopyStyle, DestinationInfFileName, DestinationInfFileNameSize,
2323 RequiredSize, DestinationInfFileNameComponent);
2324
2325 if (!SourceInfFileName)
2326 SetLastError(ERROR_INVALID_PARAMETER);
2327 else if (OEMSourceMediaType != SPOST_NONE && OEMSourceMediaType != SPOST_PATH && OEMSourceMediaType != SPOST_URL)
2328 SetLastError(ERROR_INVALID_PARAMETER);
2329 else if (CopyStyle & ~(SP_COPY_DELETESOURCE | SP_COPY_REPLACEONLY | SP_COPY_NOOVERWRITE | SP_COPY_OEMINF_CATALOG_ONLY))
2330 {
2331 TRACE("Unknown flags: 0x%08lx\n", CopyStyle & ~(SP_COPY_DELETESOURCE | SP_COPY_REPLACEONLY | SP_COPY_NOOVERWRITE | SP_COPY_OEMINF_CATALOG_ONLY));
2332 SetLastError(ERROR_INVALID_FLAGS);
2333 }
2334 else if (!DestinationInfFileName && DestinationInfFileNameSize > 0)
2335 SetLastError(ERROR_INVALID_PARAMETER);
2336 else if (CopyStyle & SP_COPY_OEMINF_CATALOG_ONLY)
2337 {
2338 FIXME("CopyStyle 0x%x not supported\n", SP_COPY_OEMINF_CATALOG_ONLY);
2339 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2340 }
2341 else
2342 {
2343 HANDLE hSearch = INVALID_HANDLE_VALUE;
2344 WIN32_FIND_DATAW FindFileData;
2345 BOOL AlreadyExists;
2346 DWORD NextFreeNumber = 0;
2347 SIZE_T len;
2348 LPWSTR pFullFileName = NULL;
2349 LPWSTR pFileName; /* Pointer into pFullFileName buffer */
2350 HANDLE hSourceFile = INVALID_HANDLE_VALUE;
2351
2352 if (OEMSourceMediaType == SPOST_PATH || OEMSourceMediaType == SPOST_URL)
2353 FIXME("OEMSourceMediaType 0x%lx ignored\n", OEMSourceMediaType);
2354
2355 /* Check if source file exists, and open it */
2356 if (strchrW(SourceInfFileName, '\\' ) || strchrW(SourceInfFileName, '/' ))
2357 {
2358 WCHAR *path;
2359
2360 if (!(len = GetFullPathNameW(SourceInfFileName, 0, NULL, NULL)))
2361 return FALSE;
2362 if (!(path = MyMalloc(len * sizeof(WCHAR))))
2363 {
2364 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2365 return FALSE;
2366 }
2367 GetFullPathNameW(SourceInfFileName, len, path, NULL);
2368 hSourceFile = CreateFileW(
2369 path, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
2370 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2371 NULL, OPEN_EXISTING, 0, NULL);
2372 MyFree(path);
2373 }
2374 else /* try Windows directory */
2375 {
2376 WCHAR *path, *p;
2377 static const WCHAR Inf[] = {'\\','i','n','f','\\',0};
2378 static const WCHAR System32[] = {'\\','s','y','s','t','e','m','3','2','\\',0};
2379
2380 len = GetWindowsDirectoryW(NULL, 0) + strlenW(SourceInfFileName) + 12;
2381 if (!(path = MyMalloc(len * sizeof(WCHAR))))
2382 {
2383 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2384 return FALSE;
2385 }
2386 GetWindowsDirectoryW(path, len);
2387 p = path + strlenW(path);
2388 strcpyW(p, Inf);
2389 strcatW(p, SourceInfFileName);
2390 hSourceFile = CreateFileW(
2391 path, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
2392 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2393 NULL, OPEN_EXISTING, 0, NULL);
2394 if (hSourceFile == INVALID_HANDLE_VALUE)
2395 {
2396 strcpyW(p, System32);
2397 strcatW(p, SourceInfFileName);
2398 hSourceFile = CreateFileW(
2399 path, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
2400 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2401 NULL, OPEN_EXISTING, 0, NULL);
2402 }
2403 MyFree(path);
2404 }
2405 if (hSourceFile == INVALID_HANDLE_VALUE)
2406 {
2407 SetLastError(ERROR_FILE_NOT_FOUND);
2408 goto cleanup;
2409 }
2410
2411 /* Prepare .inf file specification */
2412 len = MAX_PATH + 1 + strlenW(InfDirectory) + 13;
2413 pFullFileName = MyMalloc(len * sizeof(WCHAR));
2414 if (!pFullFileName)
2415 {
2416 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2417 goto cleanup;
2418 }
2419 len = GetSystemWindowsDirectoryW(pFullFileName, MAX_PATH);
2420 if (len == 0 || len > MAX_PATH)
2421 goto cleanup;
2422 if (pFullFileName[strlenW(pFullFileName) - 1] != '\\')
2423 strcatW(pFullFileName, BackSlash);
2424 strcatW(pFullFileName, InfDirectory);
2425 pFileName = &pFullFileName[strlenW(pFullFileName)];
2426
2427 /* Search if the specified .inf file already exists in %WINDIR%\Inf */
2428 AlreadyExists = FALSE;
2429 strcpyW(pFileName, OemFileMask);
2430 hSearch = FindFirstFileW(pFullFileName, &FindFileData);
2431 if (hSearch != INVALID_HANDLE_VALUE)
2432 {
2433 LARGE_INTEGER SourceFileSize;
2434
2435 if (GetFileSizeEx(hSourceFile, &SourceFileSize))
2436 {
2437 do
2438 {
2439 LARGE_INTEGER DestFileSize;
2440 HANDLE hDestFile;
2441
2442 strcpyW(pFileName, FindFileData.cFileName);
2443 hDestFile = CreateFileW(
2444 pFullFileName, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
2445 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2446 NULL, OPEN_EXISTING, 0, NULL);
2447 if (hDestFile != INVALID_HANDLE_VALUE)
2448 {
2449 if (GetFileSizeEx(hDestFile, &DestFileSize)
2450 && DestFileSize.QuadPart == SourceFileSize.QuadPart
2451 && !compare_files(hSourceFile, hDestFile))
2452 {
2453 TRACE("%s already exists as %s\n",
2454 debugstr_w(SourceInfFileName), debugstr_w(pFileName));
2455 AlreadyExists = TRUE;
2456 }
2457 }
2458 } while (!AlreadyExists && FindNextFileW(hSearch, &FindFileData));
2459 }
2460 FindClose(hSearch);
2461 hSearch = INVALID_HANDLE_VALUE;
2462 }
2463
2464 if (!AlreadyExists && CopyStyle & SP_COPY_REPLACEONLY)
2465 {
2466 /* FIXME: set DestinationInfFileName, RequiredSize, DestinationInfFileNameComponent */
2467 SetLastError(ERROR_FILE_NOT_FOUND);
2468 goto cleanup;
2469 }
2470 else if (AlreadyExists && (CopyStyle & SP_COPY_NOOVERWRITE))
2471 {
2472 DWORD Size = strlenW(pFileName) + 1;
2473
2474 if (RequiredSize)
2475 *RequiredSize = Size;
2476 if (DestinationInfFileNameSize == 0)
2477 SetLastError(ERROR_FILE_EXISTS);
2478 else if (DestinationInfFileNameSize < Size)
2479 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2480 else
2481 {
2482 SetLastError(ERROR_FILE_EXISTS);
2483 strcpyW(DestinationInfFileName, pFileName);
2484 }
2485 goto cleanup;
2486 }
2487
2488 /* Search the number to give to OEM??.INF */
2489 strcpyW(pFileName, OemFileMask);
2490 hSearch = FindFirstFileW(pFullFileName, &FindFileData);
2491 if (hSearch == INVALID_HANDLE_VALUE)
2492 {
2493 if (GetLastError() != ERROR_FILE_NOT_FOUND)
2494 goto cleanup;
2495 }
2496 else
2497 {
2498 do
2499 {
2500 DWORD CurrentNumber;
2501 if (swscanf(FindFileData.cFileName, OemFileSpecification, &CurrentNumber) == 1
2502 && CurrentNumber <= 99999)
2503 {
2504 if (CurrentNumber >= NextFreeNumber)
2505 NextFreeNumber = CurrentNumber + 1;
2506 }
2507 } while (FindNextFileW(hSearch, &FindFileData));
2508 }
2509
2510 if (NextFreeNumber > 99999)
2511 {
2512 ERR("Too much custom .inf files\n");
2513 SetLastError(ERROR_GEN_FAILURE);
2514 goto cleanup;
2515 }
2516
2517 /* Create the full path: %WINDIR%\Inf\OEM{XXXXX}.inf */
2518 sprintfW(pFileName, OemFileSpecification, NextFreeNumber);
2519 TRACE("Next available file is %s\n", debugstr_w(pFileName));
2520
2521 if (!CopyFileW(SourceInfFileName, pFullFileName, TRUE))
2522 {
2523 TRACE("CopyFileW() failed with error 0x%lx\n", GetLastError());
2524 goto cleanup;
2525 }
2526
2527 len = strlenW(pFullFileName) + 1;
2528 if (RequiredSize)
2529 *RequiredSize = len;
2530 if (DestinationInfFileName)
2531 {
2532 if (DestinationInfFileNameSize >= len)
2533 {
2534 strcpyW(DestinationInfFileName, pFullFileName);
2535 if (DestinationInfFileNameComponent)
2536 *DestinationInfFileNameComponent = &DestinationInfFileName[pFileName - pFullFileName];
2537 }
2538 else
2539 {
2540 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2541 goto cleanup;
2542 }
2543 }
2544
2545 if (CopyStyle & SP_COPY_DELETESOURCE)
2546 {
2547 if (!DeleteFileW(SourceInfFileName))
2548 {
2549 TRACE("DeleteFileW() failed with error 0x%lx\n", GetLastError());
2550 goto cleanup;
2551 }
2552 }
2553
2554 ret = TRUE;
2555
2556 cleanup:
2557 if (hSourceFile != INVALID_HANDLE_VALUE)
2558 CloseHandle(hSourceFile);
2559 if (hSearch != INVALID_HANDLE_VALUE)
2560 FindClose(hSearch);
2561 MyFree(pFullFileName);
2562 }
2563
2564 TRACE("Returning %d\n", ret);
2565 if (ret) SetLastError(ERROR_SUCCESS);
2566 return ret;
2567 }
2568