[MMIXER] Fix additional data size initialization for different audio formats (#6753)
[reactos.git] / dll / win32 / setupapi / install.c
1 /*
2 * Setupapi install routines
3 *
4 * Copyright 2002 Alexandre Julliard for CodeWeavers
5 * 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 #ifdef __WINESRC__
537 IMAGE_NT_HEADERS *nt;
538 #endif
539
540 status.cbSize = sizeof(status);
541 status.FileName = path;
542 status.FailureCode = SPREG_SUCCESS;
543 status.Win32Error = ERROR_SUCCESS;
544
545 if (info->callback)
546 {
547 switch(info->callback( info->callback_context, SPFILENOTIFY_STARTREGISTRATION,
548 (UINT_PTR)&status, !info->unregister ))
549 {
550 case FILEOP_ABORT:
551 SetLastError( ERROR_OPERATION_ABORTED );
552 return FALSE;
553 case FILEOP_SKIP:
554 return TRUE;
555 case FILEOP_DOIT:
556 break;
557 }
558 }
559
560 if (!(module = LoadLibraryExW( path, 0, LOAD_WITH_ALTERED_SEARCH_PATH )))
561 {
562 WARN( "could not load %s\n", debugstr_w(path) );
563 status.FailureCode = SPREG_LOADLIBRARY;
564 status.Win32Error = GetLastError();
565 goto done;
566 }
567
568 #ifdef __WINESRC__
569 if ((nt = RtlImageNtHeader( module )) && !(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
570 {
571 /* file is an executable, not a dll */
572 STARTUPINFOW startup;
573 PROCESS_INFORMATION info;
574 WCHAR *cmd_line;
575 BOOL res;
576 static const WCHAR format[] = {'"','%','s','"',' ','%','s',0};
577 static const WCHAR default_args[] = {'/','R','e','g','S','e','r','v','e','r',0};
578
579 FreeLibrary( module );
580 module = NULL;
581 if (!args) args = default_args;
582 cmd_line = HeapAlloc( GetProcessHeap(), 0, (strlenW(path) + strlenW(args) + 4) * sizeof(WCHAR) );
583 sprintfW( cmd_line, format, path, args );
584 memset( &startup, 0, sizeof(startup) );
585 startup.cb = sizeof(startup);
586 TRACE( "executing %s\n", debugstr_w(cmd_line) );
587 res = CreateProcessW( NULL, cmd_line, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info );
588 HeapFree( GetProcessHeap(), 0, cmd_line );
589 if (!res)
590 {
591 status.FailureCode = SPREG_LOADLIBRARY;
592 status.Win32Error = GetLastError();
593 goto done;
594 }
595 CloseHandle( info.hThread );
596
597 if (WaitForSingleObject( info.hProcess, timeout*1000 ) == WAIT_TIMEOUT)
598 {
599 /* timed out, kill the process */
600 TerminateProcess( info.hProcess, 1 );
601 status.FailureCode = SPREG_TIMEOUT;
602 status.Win32Error = ERROR_TIMEOUT;
603 }
604 CloseHandle( info.hProcess );
605 goto done;
606 }
607 #endif // __WINESRC__
608
609 if (flags & FLG_REGSVR_DLLREGISTER)
610 {
611 const char *entry_point = info->unregister ? "DllUnregisterServer" : "DllRegisterServer";
612 HRESULT (WINAPI *func)(void) = (void *)GetProcAddress( module, entry_point );
613
614 if (!func)
615 {
616 status.FailureCode = SPREG_GETPROCADDR;
617 status.Win32Error = GetLastError();
618 goto done;
619 }
620
621 TRACE( "calling %s in %s\n", entry_point, debugstr_w(path) );
622 res = func();
623
624 if (FAILED(res))
625 {
626 WARN( "calling %s in %s returned error %x\n", entry_point, debugstr_w(path), res );
627 status.FailureCode = SPREG_REGSVR;
628 status.Win32Error = res;
629 goto done;
630 }
631 }
632
633 if (flags & FLG_REGSVR_DLLINSTALL)
634 {
635 HRESULT (WINAPI *func)(BOOL,LPCWSTR) = (void *)GetProcAddress( module, "DllInstall" );
636
637 if (!func)
638 {
639 status.FailureCode = SPREG_GETPROCADDR;
640 status.Win32Error = GetLastError();
641 goto done;
642 }
643
644 TRACE( "calling DllInstall(%d,%s) in %s\n",
645 !info->unregister, debugstr_w(args), debugstr_w(path) );
646 res = func( !info->unregister, args );
647
648 if (FAILED(res))
649 {
650 WARN( "calling DllInstall in %s returned error %x\n", debugstr_w(path), res );
651 status.FailureCode = SPREG_REGSVR;
652 status.Win32Error = res;
653 goto done;
654 }
655 }
656
657 done:
658 if (module) FreeLibrary( module );
659 if (info->callback) info->callback( info->callback_context, SPFILENOTIFY_ENDREGISTRATION,
660 (UINT_PTR)&status, !info->unregister );
661 return TRUE;
662 }
663
664
665 /***********************************************************************
666 * register_dlls_callback
667 *
668 * Called once for each RegisterDlls entry in a given section.
669 */
670 static BOOL register_dlls_callback( HINF hinf, PCWSTR field, void *arg )
671 {
672 struct register_dll_info *info = arg;
673 INFCONTEXT context;
674 BOOL ret = TRUE;
675 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
676
677 for (; ok; ok = SetupFindNextLine( &context, &context ))
678 {
679 WCHAR *path, *args, *p;
680 WCHAR buffer[MAX_INF_STRING_LENGTH];
681 INT flags, timeout;
682
683 /* get directory */
684 if (!(path = PARSER_get_dest_dir( &context ))) continue;
685
686 /* get dll name */
687 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
688 goto done;
689 if (!(p = HeapReAlloc( GetProcessHeap(), 0, path,
690 (strlenW(path) + strlenW(buffer) + 2) * sizeof(WCHAR) ))) goto done;
691 path = p;
692 p += strlenW(p);
693 if (p == path || p[-1] != '\\') *p++ = '\\';
694 strcpyW( p, buffer );
695
696 /* get flags */
697 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
698
699 /* get timeout */
700 if (!SetupGetIntField( &context, 5, &timeout )) timeout = 60;
701
702 /* get command line */
703 args = NULL;
704 if (SetupGetStringFieldW( &context, 6, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
705 args = buffer;
706
707 ret = do_register_dll( info, path, flags, timeout, args );
708
709 done:
710 HeapFree( GetProcessHeap(), 0, path );
711 if (!ret) break;
712 }
713 return ret;
714 }
715
716 #ifdef __WINESRC__
717 /***********************************************************************
718 * fake_dlls_callback
719 *
720 * Called once for each WineFakeDlls entry in a given section.
721 */
722 static BOOL fake_dlls_callback( HINF hinf, PCWSTR field, void *arg )
723 {
724 INFCONTEXT context;
725 BOOL ret = TRUE;
726 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
727
728 for (; ok; ok = SetupFindNextLine( &context, &context ))
729 {
730 WCHAR *path, *p;
731 WCHAR buffer[MAX_INF_STRING_LENGTH];
732
733 /* get directory */
734 if (!(path = PARSER_get_dest_dir( &context ))) continue;
735
736 /* get dll name */
737 if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
738 goto done;
739 if (!(p = HeapReAlloc( GetProcessHeap(), 0, path,
740 (strlenW(path) + strlenW(buffer) + 2) * sizeof(WCHAR) ))) goto done;
741 path = p;
742 p += strlenW(p);
743 if (p == path || p[-1] != '\\') *p++ = '\\';
744 strcpyW( p, buffer );
745
746 /* get source dll */
747 if (SetupGetStringFieldW( &context, 4, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
748 p = buffer; /* otherwise use target base name as default source */
749
750 create_fake_dll( path, p ); /* ignore errors */
751
752 done:
753 HeapFree( GetProcessHeap(), 0, path );
754 if (!ret) break;
755 }
756 return ret;
757 }
758 #endif // __WINESRC__
759
760 /***********************************************************************
761 * update_ini_callback
762 *
763 * Called once for each UpdateInis entry in a given section.
764 */
765 static BOOL update_ini_callback( HINF hinf, PCWSTR field, void *arg )
766 {
767 INFCONTEXT context;
768
769 BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
770
771 for (; ok; ok = SetupFindNextLine( &context, &context ))
772 {
773 WCHAR buffer[MAX_INF_STRING_LENGTH];
774 WCHAR filename[MAX_INF_STRING_LENGTH];
775 WCHAR section[MAX_INF_STRING_LENGTH];
776 WCHAR entry[MAX_INF_STRING_LENGTH];
777 WCHAR string[MAX_INF_STRING_LENGTH];
778 LPWSTR divider;
779
780 if (!SetupGetStringFieldW( &context, 1, filename,
781 sizeof(filename)/sizeof(WCHAR), NULL ))
782 continue;
783
784 if (!SetupGetStringFieldW( &context, 2, section,
785 sizeof(section)/sizeof(WCHAR), NULL ))
786 continue;
787
788 if (!SetupGetStringFieldW( &context, 4, buffer,
789 sizeof(buffer)/sizeof(WCHAR), NULL ))
790 continue;
791
792 divider = strchrW(buffer,'=');
793 if (divider)
794 {
795 *divider = 0;
796 strcpyW(entry,buffer);
797 divider++;
798 strcpyW(string,divider);
799 }
800 else
801 {
802 strcpyW(entry,buffer);
803 string[0]=0;
804 }
805
806 TRACE("Writing %s = %s in %s of file %s\n",debugstr_w(entry),
807 debugstr_w(string),debugstr_w(section),debugstr_w(filename));
808 WritePrivateProfileStringW(section,entry,string,filename);
809
810 }
811 return TRUE;
812 }
813
814 static BOOL update_ini_fields_callback( HINF hinf, PCWSTR field, void *arg )
815 {
816 FIXME( "should update ini fields %s\n", debugstr_w(field) );
817 return TRUE;
818 }
819
820 static BOOL ini2reg_callback( HINF hinf, PCWSTR field, void *arg )
821 {
822 FIXME( "should do ini2reg %s\n", debugstr_w(field) );
823 return TRUE;
824 }
825
826 static BOOL logconf_callback( HINF hinf, PCWSTR field, void *arg )
827 {
828 FIXME( "should do logconf %s\n", debugstr_w(field) );
829 return TRUE;
830 }
831
832 static BOOL bitreg_callback( HINF hinf, PCWSTR field, void *arg )
833 {
834 FIXME( "should do bitreg %s\n", debugstr_w(field) );
835 return TRUE;
836 }
837
838 static BOOL Concatenate(int DirId, LPCWSTR SubDirPart, LPCWSTR NamePart, LPWSTR *pFullName)
839 {
840 DWORD dwRequired = 0;
841 LPCWSTR Dir;
842 LPWSTR FullName;
843
844 *pFullName = NULL;
845
846 Dir = DIRID_get_string(DirId);
847 if (Dir)
848 dwRequired += wcslen(Dir) + 1;
849 if (SubDirPart)
850 dwRequired += wcslen(SubDirPart) + 1;
851 if (NamePart)
852 dwRequired += wcslen(NamePart);
853 dwRequired = dwRequired * sizeof(WCHAR) + sizeof(UNICODE_NULL);
854
855 FullName = MyMalloc(dwRequired);
856 if (!FullName)
857 {
858 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
859 return FALSE;
860 }
861 FullName[0] = UNICODE_NULL;
862
863 if (Dir)
864 {
865 wcscat(FullName, Dir);
866 if (FullName[wcslen(FullName) - 1] != '\\')
867 wcscat(FullName, BackSlash);
868 }
869 if (SubDirPart)
870 {
871 wcscat(FullName, SubDirPart);
872 if (FullName[wcslen(FullName) - 1] != '\\')
873 wcscat(FullName, BackSlash);
874 }
875 if (NamePart)
876 wcscat(FullName, NamePart);
877
878 *pFullName = FullName;
879 return TRUE;
880 }
881
882 /***********************************************************************
883 * profile_items_callback
884 *
885 * Called once for each ProfileItems entry in a given section.
886 */
887 static BOOL
888 profile_items_callback(
889 IN HINF hInf,
890 IN PCWSTR SectionName,
891 IN PVOID Arg)
892 {
893 INFCONTEXT Context;
894 LPWSTR LinkSubDir = NULL, LinkName = NULL;
895 INT LinkAttributes = 0;
896 INT LinkFolder = 0;
897 INT FileDirId = 0;
898 INT CSIDL = CSIDL_COMMON_PROGRAMS;
899 LPWSTR FileSubDir = NULL;
900 INT DirId = 0;
901 LPWSTR SubDirPart = NULL, NamePart = NULL;
902 LPWSTR FullLinkName = NULL, FullFileName = NULL, FullWorkingDir = NULL, FullIconName = NULL;
903 INT IconIdx = 0;
904 LPWSTR lpHotKey = NULL, lpInfoTip = NULL;
905 LPWSTR DisplayName = NULL;
906 INT DisplayResId = 0;
907 BOOL ret = FALSE;
908 DWORD Index, Required;
909
910 IShellLinkW *psl;
911 IPersistFile *ppf;
912 HMODULE hOle32 = NULL;
913 COINITIALIZE pCoInitialize;
914 COCREATEINSTANCE pCoCreateInstance;
915 COUNINITIALIZE pCoUninitialize;
916 HRESULT hr;
917
918 TRACE("hInf %p, SectionName %s, Arg %p\n",
919 hInf, debugstr_w(SectionName), Arg);
920
921 /* Read 'Name' entry */
922 if (!SetupFindFirstLineW(hInf, SectionName, Name, &Context))
923 goto cleanup;
924 if (!GetStringField(&Context, 1, &LinkName))
925 goto cleanup;
926 if (SetupGetFieldCount(&Context) >= 2)
927 {
928 if (!SetupGetIntField(&Context, 2, &LinkAttributes))
929 goto cleanup;
930 }
931 if (SetupGetFieldCount(&Context) >= 3)
932 {
933 if (!SetupGetIntField(&Context, 3, &LinkFolder))
934 goto cleanup;
935 }
936
937 /* Read 'CmdLine' entry */
938 if (!SetupFindFirstLineW(hInf, SectionName, CmdLine, &Context))
939 goto cleanup;
940 Index = 1;
941 if (!SetupGetIntField(&Context, Index++, &FileDirId))
942 goto cleanup;
943 if (SetupGetFieldCount(&Context) >= 3)
944 {
945 if (!GetStringField(&Context, Index++, &FileSubDir))
946 goto cleanup;
947 }
948 if (!GetStringField(&Context, Index++, &NamePart))
949 goto cleanup;
950 if (!Concatenate(FileDirId, FileSubDir, NamePart, &FullFileName))
951 goto cleanup;
952 MyFree(NamePart);
953 NamePart = NULL;
954
955 /* Read 'SubDir' entry */
956 if ((LinkAttributes & FLG_PROFITEM_GROUP) == 0 && SetupFindFirstLineW(hInf, SectionName, SubDir, &Context))
957 {
958 if (!GetStringField(&Context, 1, &LinkSubDir))
959 goto cleanup;
960 }
961
962 /* Read 'WorkingDir' entry */
963 if (SetupFindFirstLineW(hInf, SectionName, WorkingDir, &Context))
964 {
965 if (!SetupGetIntField(&Context, 1, &DirId))
966 goto cleanup;
967 if (SetupGetFieldCount(&Context) >= 2)
968 {
969 if (!GetStringField(&Context, 2, &SubDirPart))
970 goto cleanup;
971 }
972 if (!Concatenate(DirId, SubDirPart, NULL, &FullWorkingDir))
973 goto cleanup;
974 MyFree(SubDirPart);
975 SubDirPart = NULL;
976 }
977 else
978 {
979 if (!Concatenate(FileDirId, FileSubDir, NULL, &FullWorkingDir))
980 goto cleanup;
981 }
982
983 /* Read 'IconPath' entry */
984 if (SetupFindFirstLineW(hInf, SectionName, IconPath, &Context))
985 {
986 Index = 1;
987 if (!SetupGetIntField(&Context, Index++, &DirId))
988 goto cleanup;
989 if (SetupGetFieldCount(&Context) >= 3)
990 {
991 if (!GetStringField(&Context, Index++, &SubDirPart))
992 goto cleanup;
993 }
994 if (!GetStringField(&Context, Index, &NamePart))
995 goto cleanup;
996 if (!Concatenate(DirId, SubDirPart, NamePart, &FullIconName))
997 goto cleanup;
998 MyFree(SubDirPart);
999 MyFree(NamePart);
1000 SubDirPart = NamePart = NULL;
1001 }
1002 else
1003 {
1004 FullIconName = pSetupDuplicateString(FullFileName);
1005 if (!FullIconName)
1006 goto cleanup;
1007 }
1008
1009 /* Read 'IconIndex' entry */
1010 if (SetupFindFirstLineW(hInf, SectionName, IconIndex, &Context))
1011 {
1012 if (!SetupGetIntField(&Context, 1, &IconIdx))
1013 goto cleanup;
1014 }
1015
1016 /* Read 'HotKey' and 'InfoTip' entries */
1017 GetLineText(hInf, SectionName, HotKey, &lpHotKey);
1018 GetLineText(hInf, SectionName, InfoTip, &lpInfoTip);
1019
1020 /* Read 'DisplayResource' entry */
1021 if (SetupFindFirstLineW(hInf, SectionName, DisplayResource, &Context))
1022 {
1023 if (!GetStringField(&Context, 1, &DisplayName))
1024 goto cleanup;
1025 if (!SetupGetIntField(&Context, 2, &DisplayResId))
1026 goto cleanup;
1027 }
1028
1029 /* Some debug */
1030 TRACE("Link is %s\\%s, attributes 0x%x\n", debugstr_w(LinkSubDir), debugstr_w(LinkName), LinkAttributes);
1031 TRACE("File is %s\n", debugstr_w(FullFileName));
1032 TRACE("Working dir %s\n", debugstr_w(FullWorkingDir));
1033 TRACE("Icon is %s, %d\n", debugstr_w(FullIconName), IconIdx);
1034 TRACE("Hotkey %s\n", debugstr_w(lpHotKey));
1035 TRACE("InfoTip %s\n", debugstr_w(lpInfoTip));
1036 TRACE("Display %s, %d\n", DisplayName, DisplayResId);
1037
1038 /* Load ole32.dll */
1039 hOle32 = LoadLibraryA("ole32.dll");
1040 if (!hOle32)
1041 goto cleanup;
1042 pCoInitialize = (COINITIALIZE)GetProcAddress(hOle32, "CoInitialize");
1043 if (!pCoInitialize)
1044 goto cleanup;
1045 pCoCreateInstance = (COCREATEINSTANCE)GetProcAddress(hOle32, "CoCreateInstance");
1046 if (!pCoCreateInstance)
1047 goto cleanup;
1048 pCoUninitialize = (COUNINITIALIZE)GetProcAddress(hOle32, "CoUninitialize");
1049 if (!pCoUninitialize)
1050 goto cleanup;
1051
1052 /* Create shortcut */
1053 hr = pCoInitialize(NULL);
1054 if (!SUCCEEDED(hr))
1055 {
1056 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1057 SetLastError(HRESULT_CODE(hr));
1058 else
1059 SetLastError(E_FAIL);
1060 goto cleanup;
1061 }
1062 hr = pCoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&psl);
1063 if (SUCCEEDED(hr))
1064 {
1065 /* Fill link properties */
1066 hr = IShellLinkW_SetPath(psl, FullFileName);
1067 if (SUCCEEDED(hr))
1068 hr = IShellLinkW_SetArguments(psl, L"");
1069 if (SUCCEEDED(hr))
1070 hr = IShellLinkW_SetWorkingDirectory(psl, FullWorkingDir);
1071 if (SUCCEEDED(hr))
1072 hr = IShellLinkW_SetIconLocation(psl, FullIconName, IconIdx);
1073 if (SUCCEEDED(hr) && lpHotKey)
1074 FIXME("Need to store hotkey %s in shell link\n", debugstr_w(lpHotKey));
1075 if (SUCCEEDED(hr) && lpInfoTip)
1076 hr = IShellLinkW_SetDescription(psl, lpInfoTip);
1077 if (SUCCEEDED(hr) && DisplayName)
1078 FIXME("Need to store display name %s, %d in shell link\n", debugstr_w(DisplayName), DisplayResId);
1079 if (SUCCEEDED(hr))
1080 {
1081 hr = IShellLinkW_QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf);
1082 if (SUCCEEDED(hr))
1083 {
1084 Required = (MAX_PATH + 1 +
1085 ((LinkSubDir != NULL) ? wcslen(LinkSubDir) : 0) +
1086 ((LinkName != NULL) ? wcslen(LinkName) : 0)) * sizeof(WCHAR);
1087 FullLinkName = MyMalloc(Required);
1088 if (!FullLinkName)
1089 hr = E_OUTOFMEMORY;
1090 else
1091 {
1092 if (LinkAttributes & (FLG_PROFITEM_DELETE | FLG_PROFITEM_GROUP))
1093 FIXME("Need to handle FLG_PROFITEM_DELETE and FLG_PROFITEM_GROUP\n");
1094 if (LinkAttributes & FLG_PROFITEM_CSIDL)
1095 CSIDL = LinkFolder;
1096 else if (LinkAttributes & FLG_PROFITEM_CURRENTUSER)
1097 CSIDL = CSIDL_PROGRAMS;
1098
1099 if (SHGetSpecialFolderPathW(
1100 NULL,
1101 FullLinkName,
1102 CSIDL,
1103 TRUE))
1104 {
1105 if (FullLinkName[wcslen(FullLinkName) - 1] != '\\')
1106 wcscat(FullLinkName, BackSlash);
1107 if (LinkSubDir)
1108 {
1109 wcscat(FullLinkName, LinkSubDir);
1110 if (FullLinkName[wcslen(FullLinkName) - 1] != '\\')
1111 wcscat(FullLinkName, BackSlash);
1112 }
1113 if (LinkName)
1114 {
1115 wcscat(FullLinkName, LinkName);
1116 wcscat(FullLinkName, DotLnk);
1117 }
1118 hr = IPersistFile_Save(ppf, FullLinkName, TRUE);
1119 }
1120 else
1121 hr = HRESULT_FROM_WIN32(GetLastError());
1122 }
1123 IPersistFile_Release(ppf);
1124 }
1125 }
1126 IShellLinkW_Release(psl);
1127 }
1128 pCoUninitialize();
1129 if (SUCCEEDED(hr))
1130 ret = TRUE;
1131 else
1132 {
1133 if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
1134 SetLastError(HRESULT_CODE(hr));
1135 else
1136 SetLastError(E_FAIL);
1137 }
1138
1139 cleanup:
1140 MyFree(LinkSubDir);
1141 MyFree(LinkName);
1142 MyFree(FileSubDir);
1143 MyFree(SubDirPart);
1144 MyFree(NamePart);
1145 MyFree(FullFileName);
1146 MyFree(FullWorkingDir);
1147 MyFree(FullIconName);
1148 MyFree(FullLinkName);
1149 MyFree(lpHotKey);
1150 MyFree(lpInfoTip);
1151 MyFree(DisplayName);
1152 if (hOle32)
1153 FreeLibrary(hOle32);
1154
1155 TRACE("Returning %d\n", ret);
1156 return ret;
1157 }
1158
1159 static BOOL copy_inf_callback( HINF hinf, PCWSTR field, void *arg )
1160 {
1161 FIXME( "should do copy inf %s\n", debugstr_w(field) );
1162 return TRUE;
1163 }
1164
1165
1166 /***********************************************************************
1167 * iterate_section_fields
1168 *
1169 * Iterate over all fields of a certain key of a certain section
1170 */
1171 static BOOL iterate_section_fields( HINF hinf, PCWSTR section, PCWSTR key,
1172 iterate_fields_func callback, void *arg )
1173 {
1174 WCHAR static_buffer[200];
1175 WCHAR *buffer = static_buffer;
1176 DWORD size = sizeof(static_buffer)/sizeof(WCHAR);
1177 INFCONTEXT context;
1178 BOOL ret = FALSE;
1179
1180 BOOL ok = SetupFindFirstLineW( hinf, section, key, &context );
1181 while (ok)
1182 {
1183 UINT i, count = SetupGetFieldCount( &context );
1184 for (i = 1; i <= count; i++)
1185 {
1186 if (!(buffer = get_field_string( &context, i, buffer, static_buffer, &size )))
1187 goto done;
1188 if (!callback( hinf, buffer, arg ))
1189 {
1190 WARN("callback failed for %s %s err %d\n",
1191 debugstr_w(section), debugstr_w(buffer), GetLastError() );
1192 goto done;
1193 }
1194 }
1195 ok = SetupFindNextMatchLineW( &context, key, &context );
1196 }
1197 ret = TRUE;
1198 done:
1199 if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
1200 return ret;
1201 }
1202
1203
1204 /***********************************************************************
1205 * SetupInstallFilesFromInfSectionA (SETUPAPI.@)
1206 */
1207 BOOL WINAPI SetupInstallFilesFromInfSectionA( HINF hinf, HINF hlayout, HSPFILEQ queue,
1208 PCSTR section, PCSTR src_root, UINT flags )
1209 {
1210 UNICODE_STRING sectionW;
1211 BOOL ret = FALSE;
1212
1213 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
1214 {
1215 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1216 return FALSE;
1217 }
1218 if (!src_root)
1219 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
1220 NULL, flags );
1221 else
1222 {
1223 UNICODE_STRING srcW;
1224 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
1225 {
1226 ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
1227 srcW.Buffer, flags );
1228 RtlFreeUnicodeString( &srcW );
1229 }
1230 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1231 }
1232 RtlFreeUnicodeString( &sectionW );
1233 return ret;
1234 }
1235
1236
1237 /***********************************************************************
1238 * SetupInstallFilesFromInfSectionW (SETUPAPI.@)
1239 */
1240 BOOL WINAPI SetupInstallFilesFromInfSectionW( HINF hinf, HINF hlayout, HSPFILEQ queue,
1241 PCWSTR section, PCWSTR src_root, UINT flags )
1242 {
1243 struct files_callback_info info;
1244
1245 info.queue = queue;
1246 info.src_root = src_root;
1247 info.copy_flags = flags;
1248 info.layout = hlayout;
1249 return iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info );
1250 }
1251
1252
1253 /***********************************************************************
1254 * SetupInstallFromInfSectionA (SETUPAPI.@)
1255 */
1256 BOOL WINAPI SetupInstallFromInfSectionA( HWND owner, HINF hinf, PCSTR section, UINT flags,
1257 HKEY key_root, PCSTR src_root, UINT copy_flags,
1258 PSP_FILE_CALLBACK_A callback, PVOID context,
1259 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
1260 {
1261 UNICODE_STRING sectionW, src_rootW;
1262 struct callback_WtoA_context ctx;
1263 BOOL ret = FALSE;
1264
1265 src_rootW.Buffer = NULL;
1266 if (src_root && !RtlCreateUnicodeStringFromAsciiz( &src_rootW, src_root ))
1267 {
1268 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1269 return FALSE;
1270 }
1271
1272 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
1273 {
1274 ctx.orig_context = context;
1275 ctx.orig_handler = callback;
1276 ret = SetupInstallFromInfSectionW( owner, hinf, sectionW.Buffer, flags, key_root,
1277 src_rootW.Buffer, copy_flags, QUEUE_callback_WtoA,
1278 &ctx, devinfo, devinfo_data );
1279 RtlFreeUnicodeString( &sectionW );
1280 }
1281 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1282
1283 RtlFreeUnicodeString( &src_rootW );
1284 return ret;
1285 }
1286
1287
1288 /***********************************************************************
1289 * include_callback
1290 *
1291 * Called once for each Include entry in a given section.
1292 */
1293 static BOOL include_callback( HINF hinf, PCWSTR field, void *arg )
1294 {
1295 return SetupOpenAppendInfFileW( field, hinf, NULL );
1296 }
1297
1298
1299 /***********************************************************************
1300 * needs_callback
1301 *
1302 * Called once for each Needs entry in a given section.
1303 */
1304 static BOOL needs_callback( HINF hinf, PCWSTR field, void *arg )
1305 {
1306 struct needs_callback_info *info = arg;
1307
1308 switch (info->type)
1309 {
1310 case 0:
1311 return SetupInstallFromInfSectionW(info->owner, *(HINF*)hinf, field, info->flags,
1312 info->key_root, info->src_root, info->copy_flags, info->callback,
1313 info->context, info->devinfo, info->devinfo_data);
1314 case 1:
1315 return SetupInstallServicesFromInfSectionExW(*(HINF*)hinf, field, info->flags,
1316 info->devinfo, info->devinfo_data, info->reserved1, info->reserved2);
1317 default:
1318 ERR("Unknown info type %u\n", info->type);
1319 return FALSE;
1320 }
1321 }
1322
1323
1324 /***********************************************************************
1325 * SetupInstallFromInfSectionW (SETUPAPI.@)
1326 */
1327 BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section, UINT flags,
1328 HKEY key_root, PCWSTR src_root, UINT copy_flags,
1329 PSP_FILE_CALLBACK_W callback, PVOID context,
1330 HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
1331 {
1332 struct needs_callback_info needs_info;
1333
1334 /* Parse 'Include' and 'Needs' directives */
1335 iterate_section_fields( hinf, section, Include, include_callback, NULL);
1336 needs_info.type = 0;
1337 needs_info.owner = owner;
1338 needs_info.flags = flags;
1339 needs_info.key_root = key_root;
1340 needs_info.src_root = src_root;
1341 needs_info.copy_flags = copy_flags;
1342 needs_info.callback = callback;
1343 needs_info.context = context;
1344 needs_info.devinfo = devinfo;
1345 needs_info.devinfo_data = devinfo_data;
1346 iterate_section_fields( hinf, section, Needs, needs_callback, &needs_info);
1347
1348 if (flags & SPINST_FILES)
1349 {
1350 SP_DEVINSTALL_PARAMS_W install_params;
1351 struct files_callback_info info;
1352 HSPFILEQ queue = NULL;
1353 BOOL use_custom_queue;
1354 BOOL ret;
1355
1356 install_params.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
1357 use_custom_queue = SetupDiGetDeviceInstallParamsW(devinfo, devinfo_data, &install_params) && (install_params.Flags & DI_NOVCP);
1358 if (!use_custom_queue && ((queue = SetupOpenFileQueue()) == (HSPFILEQ)INVALID_HANDLE_VALUE ))
1359 return FALSE;
1360 info.queue = use_custom_queue ? install_params.FileQueue : queue;
1361 info.src_root = src_root;
1362 info.copy_flags = copy_flags;
1363 info.layout = hinf;
1364 ret = (iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ) &&
1365 iterate_section_fields( hinf, section, DelFiles, delete_files_callback, &info ) &&
1366 iterate_section_fields( hinf, section, RenFiles, rename_files_callback, &info ));
1367 if (!use_custom_queue)
1368 {
1369 if (ret)
1370 ret = SetupCommitFileQueueW( owner, queue, callback, context );
1371 SetupCloseFileQueue( queue );
1372 }
1373 if (!ret) return FALSE;
1374 }
1375 if (flags & SPINST_INIFILES)
1376 {
1377 if (!iterate_section_fields( hinf, section, UpdateInis, update_ini_callback, NULL ) ||
1378 !iterate_section_fields( hinf, section, UpdateIniFields,
1379 update_ini_fields_callback, NULL ))
1380 return FALSE;
1381 }
1382 if (flags & SPINST_INI2REG)
1383 {
1384 if (!iterate_section_fields( hinf, section, Ini2Reg, ini2reg_callback, NULL ))
1385 return FALSE;
1386 }
1387 if (flags & SPINST_LOGCONFIG)
1388 {
1389 if (!iterate_section_fields( hinf, section, LogConf, logconf_callback, NULL ))
1390 return FALSE;
1391 }
1392 if (flags & SPINST_REGSVR)
1393 {
1394 struct register_dll_info info;
1395
1396 info.unregister = FALSE;
1397 if (flags & SPINST_REGISTERCALLBACKAWARE)
1398 {
1399 info.callback = callback;
1400 info.callback_context = context;
1401 }
1402 else info.callback = NULL;
1403
1404 if (!iterate_section_fields( hinf, section, RegisterDlls, register_dlls_callback, &info ))
1405 return FALSE;
1406
1407 #ifdef __WINESRC__
1408 if (!iterate_section_fields( hinf, section, WineFakeDlls, fake_dlls_callback, NULL ))
1409 return FALSE;
1410 #endif // __WINESRC__
1411 }
1412 if (flags & SPINST_UNREGSVR)
1413 {
1414 struct register_dll_info info;
1415
1416 info.unregister = TRUE;
1417 if (flags & SPINST_REGISTERCALLBACKAWARE)
1418 {
1419 info.callback = callback;
1420 info.callback_context = context;
1421 }
1422 else info.callback = NULL;
1423
1424 if (!iterate_section_fields( hinf, section, UnregisterDlls, register_dlls_callback, &info ))
1425 return FALSE;
1426 }
1427 if (flags & SPINST_REGISTRY)
1428 {
1429 struct registry_callback_info info;
1430
1431 info.default_root = key_root;
1432 info.delete = TRUE;
1433 if (!iterate_section_fields( hinf, section, DelReg, registry_callback, &info ))
1434 return FALSE;
1435 info.delete = FALSE;
1436 if (!iterate_section_fields( hinf, section, AddReg, registry_callback, &info ))
1437 return FALSE;
1438 }
1439 if (flags & SPINST_BITREG)
1440 {
1441 if (!iterate_section_fields( hinf, section, BitReg, bitreg_callback, NULL ))
1442 return FALSE;
1443 }
1444 if (flags & SPINST_PROFILEITEMS)
1445 {
1446 if (!iterate_section_fields( hinf, section, ProfileItems, profile_items_callback, NULL ))
1447 return FALSE;
1448 }
1449 if (flags & SPINST_COPYINF)
1450 {
1451 if (!iterate_section_fields( hinf, section, CopyINF, copy_inf_callback, NULL ))
1452 return FALSE;
1453 }
1454
1455 return TRUE;
1456 }
1457
1458
1459 /***********************************************************************
1460 * InstallHinfSectionW (SETUPAPI.@)
1461 *
1462 * NOTE: 'cmdline' is <section> <mode> <path> from
1463 * RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection <section> <mode> <path>
1464 */
1465 void WINAPI InstallHinfSectionW( HWND hwnd, HINSTANCE handle, LPCWSTR cmdline, INT show )
1466 {
1467 BOOL ret = FALSE;
1468 WCHAR *s, *path, section[MAX_PATH];
1469 void *callback_context = NULL;
1470 DWORD SectionNameLength;
1471 UINT mode;
1472 HINF hinf = INVALID_HANDLE_VALUE;
1473 BOOL bRebootRequired = FALSE;
1474
1475 TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd, handle, debugstr_w(cmdline));
1476
1477 lstrcpynW( section, cmdline, MAX_PATH );
1478
1479 if (!(s = strchrW( section, ' ' ))) goto cleanup;
1480 *s++ = 0;
1481 while (*s == ' ') s++;
1482 mode = atoiW( s );
1483
1484 /* quoted paths are not allowed on native, the rest of the command line is taken as the path */
1485 if (!(s = strchrW( s, ' ' ))) goto cleanup;
1486 while (*s == ' ') s++;
1487 path = s;
1488
1489 if (mode & 0x80)
1490 {
1491 FIXME("default path of the installation not changed\n");
1492 mode &= ~0x80;
1493 }
1494
1495 hinf = SetupOpenInfFileW( path, NULL, INF_STYLE_WIN4, NULL );
1496 if (hinf == INVALID_HANDLE_VALUE)
1497 {
1498 WARN("SetupOpenInfFileW(%s) failed (Error %u)\n", path, GetLastError());
1499 goto cleanup;
1500 }
1501
1502 ret = SetupDiGetActualSectionToInstallW(
1503 hinf, section, section, sizeof(section)/sizeof(section[0]), &SectionNameLength, NULL );
1504 if (!ret)
1505 {
1506 WARN("SetupDiGetActualSectionToInstallW() failed (Error %u)\n", GetLastError());
1507 goto cleanup;
1508 }
1509 if (SectionNameLength > MAX_PATH - strlenW(DotServices))
1510 {
1511 WARN("Section name '%s' too long\n", section);
1512 goto cleanup;
1513 }
1514
1515 /* Copy files and add registry entries */
1516 callback_context = SetupInitDefaultQueueCallback( hwnd );
1517 ret = SetupInstallFromInfSectionW( hwnd, hinf, section, SPINST_ALL, NULL, NULL,
1518 SP_COPY_NEWER | SP_COPY_IN_USE_NEEDS_REBOOT,
1519 SetupDefaultQueueCallbackW, callback_context,
1520 NULL, NULL );
1521 if (!ret)
1522 {
1523 WARN("SetupInstallFromInfSectionW() failed (Error %u)\n", GetLastError());
1524 goto cleanup;
1525 }
1526 /* FIXME: need to check if some files were in use and need reboot
1527 * bReboot = ...;
1528 */
1529
1530 /* Install services */
1531 wcscat(section, DotServices);
1532 ret = SetupInstallServicesFromInfSectionW( hinf, section, 0 );
1533 if (!ret && GetLastError() == ERROR_SECTION_NOT_FOUND)
1534 ret = TRUE;
1535 if (!ret)
1536 {
1537 WARN("SetupInstallServicesFromInfSectionW() failed (Error %u)\n", GetLastError());
1538 goto cleanup;
1539 }
1540 else if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
1541 {
1542 bRebootRequired = TRUE;
1543 }
1544
1545 /* Check if we need to reboot */
1546 switch (mode)
1547 {
1548 case 0:
1549 /* Never reboot */
1550 break;
1551 case 1:
1552 /* Always reboot */
1553 ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_APPLICATION |
1554 SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED);
1555 break;
1556 case 2:
1557 /* Query user before rebooting */
1558 SetupPromptReboot(NULL, hwnd, FALSE);
1559 break;
1560 case 3:
1561 /* Reboot if necessary */
1562 if (bRebootRequired)
1563 {
1564 ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_APPLICATION |
1565 SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED);
1566 }
1567 break;
1568 case 4:
1569 /* If necessary, query user before rebooting */
1570 if (bRebootRequired)
1571 {
1572 SetupPromptReboot(NULL, hwnd, FALSE);
1573 }
1574 break;
1575 default:
1576 break;
1577 }
1578
1579 cleanup:
1580 if ( callback_context )
1581 SetupTermDefaultQueueCallback( callback_context );
1582 if ( hinf != INVALID_HANDLE_VALUE )
1583 SetupCloseInfFile( hinf );
1584
1585 #ifdef CORE_11689_IS_FIXED
1586 // TODO: Localize the error string.
1587 if (!ret && !(GlobalSetupFlags & PSPGF_NONINTERACTIVE))
1588 {
1589 MessageBoxW(hwnd, section, L"setupapi.dll: An error happened...", MB_ICONERROR | MB_OK);
1590 }
1591 #endif
1592 }
1593
1594
1595 /***********************************************************************
1596 * InstallHinfSectionA (SETUPAPI.@)
1597 */
1598 void WINAPI InstallHinfSectionA( HWND hwnd, HINSTANCE handle, LPCSTR cmdline, INT show )
1599 {
1600 UNICODE_STRING cmdlineW;
1601
1602 if (RtlCreateUnicodeStringFromAsciiz( &cmdlineW, cmdline ))
1603 {
1604 InstallHinfSectionW( hwnd, handle, cmdlineW.Buffer, show );
1605 RtlFreeUnicodeString( &cmdlineW );
1606 }
1607 }
1608
1609 /***********************************************************************
1610 * SetupInstallServicesFromInfSectionW (SETUPAPI.@)
1611 */
1612 BOOL WINAPI SetupInstallServicesFromInfSectionW( HINF Inf, PCWSTR SectionName, DWORD Flags)
1613 {
1614 return SetupInstallServicesFromInfSectionExW( Inf, SectionName, Flags,
1615 NULL, NULL, NULL, NULL );
1616 }
1617
1618 /***********************************************************************
1619 * SetupInstallServicesFromInfSectionA (SETUPAPI.@)
1620 */
1621 BOOL WINAPI SetupInstallServicesFromInfSectionA( HINF Inf, PCSTR SectionName, DWORD Flags)
1622 {
1623 return SetupInstallServicesFromInfSectionExA( Inf, SectionName, Flags,
1624 NULL, NULL, NULL, NULL );
1625 }
1626
1627 /***********************************************************************
1628 * SetupInstallServicesFromInfSectionExA (SETUPAPI.@)
1629 */
1630 BOOL WINAPI SetupInstallServicesFromInfSectionExA( HINF hinf, PCSTR sectionname, DWORD flags, HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data, PVOID reserved1, PVOID reserved2 )
1631 {
1632 UNICODE_STRING sectionnameW;
1633 BOOL ret = FALSE;
1634
1635 if (RtlCreateUnicodeStringFromAsciiz( &sectionnameW, sectionname ))
1636 {
1637 ret = SetupInstallServicesFromInfSectionExW( hinf, sectionnameW.Buffer, flags, devinfo, devinfo_data, reserved1, reserved2 );
1638 RtlFreeUnicodeString( &sectionnameW );
1639 }
1640 else
1641 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1642
1643 return ret;
1644 }
1645
1646
1647 static BOOL GetLineText( HINF hinf, PCWSTR section_name, PCWSTR key_name, PWSTR *value)
1648 {
1649 DWORD required;
1650 PWSTR buf = NULL;
1651
1652 *value = NULL;
1653
1654 if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, NULL, 0, &required )
1655 && GetLastError() != ERROR_INSUFFICIENT_BUFFER )
1656 return FALSE;
1657
1658 buf = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) );
1659 if ( ! buf )
1660 {
1661 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1662 return FALSE;
1663 }
1664
1665 if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, buf, required, &required ) )
1666 {
1667 HeapFree( GetProcessHeap(), 0, buf );
1668 return FALSE;
1669 }
1670
1671 *value = buf;
1672 return TRUE;
1673 }
1674
1675
1676 static BOOL GetIntField( HINF hinf, PCWSTR section_name, PCWSTR key_name, INT *value)
1677 {
1678 LPWSTR buffer, end;
1679 INT res;
1680
1681 if (! GetLineText( hinf, section_name, key_name, &buffer ) )
1682 return FALSE;
1683
1684 res = wcstol( buffer, &end, 0 );
1685 if (end != buffer && !*end)
1686 {
1687 HeapFree(GetProcessHeap(), 0, buffer);
1688 *value = res;
1689 return TRUE;
1690 }
1691 else
1692 {
1693 HeapFree(GetProcessHeap(), 0, buffer);
1694 SetLastError( ERROR_INVALID_DATA );
1695 return FALSE;
1696 }
1697 }
1698
1699
1700 BOOL GetStringField( PINFCONTEXT context, DWORD index, PWSTR *value)
1701 {
1702 DWORD RequiredSize;
1703 BOOL ret;
1704
1705 ret = SetupGetStringFieldW(
1706 context,
1707 index,
1708 NULL, 0,
1709 &RequiredSize);
1710 if (!ret)
1711 return FALSE;
1712 else if (RequiredSize == 0)
1713 {
1714 *value = NULL;
1715 return TRUE;
1716 }
1717
1718 /* We got the needed size for the buffer */
1719 *value = MyMalloc(RequiredSize * sizeof(WCHAR));
1720 if (!*value)
1721 {
1722 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1723 return FALSE;
1724 }
1725 ret = SetupGetStringFieldW(
1726 context,
1727 index,
1728 *value, RequiredSize, NULL);
1729 if (!ret)
1730 MyFree(*value);
1731
1732 return ret;
1733 }
1734
1735 static VOID FixupServiceBinaryPath(
1736 IN DWORD ServiceType,
1737 IN OUT LPWSTR *ServiceBinary)
1738 {
1739 LPWSTR Buffer;
1740 WCHAR ReactOSDir[MAX_PATH];
1741 DWORD RosDirLength, ServiceLength, Win32Length;
1742
1743 GetWindowsDirectoryW(ReactOSDir, MAX_PATH);
1744 RosDirLength = strlenW(ReactOSDir);
1745 ServiceLength = strlenW(*ServiceBinary);
1746
1747 /* Check and fix two things:
1748 1. Get rid of C:\ReactOS and use relative
1749 path instead.
1750 2. Add %SystemRoot% for Win32 services */
1751
1752 if (ServiceLength < RosDirLength)
1753 return;
1754
1755 if (!wcsnicmp(*ServiceBinary, ReactOSDir, RosDirLength))
1756 {
1757 /* Yes, the first part is the C:\ReactOS\, just skip it */
1758 MoveMemory(*ServiceBinary, *ServiceBinary + RosDirLength + 1,
1759 (ServiceLength - RosDirLength) * sizeof(WCHAR));
1760
1761 /* Handle Win32-services differently */
1762 if (ServiceType & SERVICE_WIN32)
1763 {
1764 Win32Length = (ServiceLength - RosDirLength) * sizeof(WCHAR)
1765 - sizeof(L'\\') + sizeof(L"%SystemRoot%\\");
1766 Buffer = MyMalloc(Win32Length);
1767
1768 wcscpy(Buffer, L"%SystemRoot%\\");
1769 wcscat(Buffer, *ServiceBinary);
1770 MyFree(*ServiceBinary);
1771
1772 *ServiceBinary = Buffer;
1773 }
1774 }
1775 }
1776
1777 static BOOL InstallOneService(
1778 struct DeviceInfoSet *list,
1779 IN HINF hInf,
1780 IN LPCWSTR ServiceSection,
1781 IN LPCWSTR ServiceName,
1782 IN UINT ServiceFlags)
1783 {
1784 SC_HANDLE hSCManager = NULL;
1785 SC_HANDLE hService = NULL;
1786 LPDWORD GroupOrder = NULL;
1787 LPQUERY_SERVICE_CONFIGW ServiceConfig = NULL;
1788 HKEY hServicesKey, hServiceKey;
1789 LONG rc;
1790 BOOL ret = FALSE;
1791
1792 HKEY hGroupOrderListKey = NULL;
1793 LPWSTR ServiceBinary = NULL;
1794 LPWSTR LoadOrderGroup = NULL;
1795 LPWSTR DisplayName = NULL;
1796 LPWSTR Description = NULL;
1797 LPWSTR Dependencies = NULL;
1798 LPWSTR StartName = NULL;
1799 LPWSTR SecurityDescriptor = NULL;
1800 PSECURITY_DESCRIPTOR sd = NULL;
1801 INT ServiceType, StartType, ErrorControl;
1802 DWORD dwRegType;
1803 DWORD tagId = (DWORD)-1;
1804 BOOL useTag;
1805
1806 if (!GetIntField(hInf, ServiceSection, ServiceTypeKey, &ServiceType))
1807 {
1808 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT );
1809 goto cleanup;
1810 }
1811 if (!GetIntField(hInf, ServiceSection, StartTypeKey, &StartType))
1812 {
1813 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT );
1814 goto cleanup;
1815 }
1816 if (!GetIntField(hInf, ServiceSection, ErrorControlKey, &ErrorControl))
1817 {
1818 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT );
1819 goto cleanup;
1820 }
1821 useTag = (ServiceType == SERVICE_BOOT_START || ServiceType == SERVICE_SYSTEM_START);
1822
1823 hSCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE);
1824 if (hSCManager == NULL)
1825 goto cleanup;
1826
1827 if (!GetLineText(hInf, ServiceSection, ServiceBinaryKey, &ServiceBinary))
1828 {
1829 SetLastError( ERROR_BAD_SERVICE_INSTALLSECT );
1830 goto cleanup;
1831 }
1832
1833 /* Adjust binary path according to the service type */
1834 FixupServiceBinaryPath(ServiceType, &ServiceBinary);
1835
1836 /* Don't check return value, as these fields are optional and
1837 * GetLineText initialize output parameter even on failure */
1838 GetLineText(hInf, ServiceSection, LoadOrderGroupKey, &LoadOrderGroup);
1839 GetLineText(hInf, ServiceSection, DisplayNameKey, &DisplayName);
1840 GetLineText(hInf, ServiceSection, DescriptionKey, &Description);
1841 GetLineText(hInf, ServiceSection, DependenciesKey, &Dependencies);
1842 GetLineText(hInf, ServiceSection, StartNameKey, &StartName);
1843
1844 /* If there is no group, we must not request a tag */
1845 if (!LoadOrderGroup || !*LoadOrderGroup)
1846 useTag = FALSE;
1847
1848 hService = OpenServiceW(
1849 hSCManager,
1850 ServiceName,
1851 DELETE | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | WRITE_DAC);
1852 if (hService == NULL && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
1853 goto cleanup;
1854
1855 if (hService && (ServiceFlags & SPSVCINST_DELETEEVENTLOGENTRY))
1856 {
1857 ret = DeleteService(hService);
1858 if (!ret && GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
1859 goto cleanup;
1860 }
1861
1862 if (hService == NULL)
1863 {
1864 /* Create new service */
1865 hService = CreateServiceW(
1866 hSCManager,
1867 ServiceName,
1868 DisplayName,
1869 WRITE_DAC,
1870 ServiceType,
1871 StartType,
1872 ErrorControl,
1873 ServiceBinary,
1874 LoadOrderGroup,
1875 useTag ? &tagId : NULL,
1876 Dependencies,
1877 StartName,
1878 NULL);
1879 if (hService == NULL)
1880 goto cleanup;
1881 }
1882 else
1883 {
1884 DWORD bufferSize;
1885 /* Read current configuration */
1886 if (!QueryServiceConfigW(hService, NULL, 0, &bufferSize))
1887 {
1888 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1889 goto cleanup;
1890 ServiceConfig = MyMalloc(bufferSize);
1891 if (!ServiceConfig)
1892 {
1893 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1894 goto cleanup;
1895 }
1896 if (!QueryServiceConfigW(hService, ServiceConfig, bufferSize, &bufferSize))
1897 goto cleanup;
1898 }
1899 tagId = ServiceConfig->dwTagId;
1900
1901 /* Update configuration */
1902 ret = ChangeServiceConfigW(
1903 hService,
1904 ServiceType,
1905 (ServiceFlags & SPSVCINST_NOCLOBBER_STARTTYPE) ? SERVICE_NO_CHANGE : StartType,
1906 (ServiceFlags & SPSVCINST_NOCLOBBER_ERRORCONTROL) ? SERVICE_NO_CHANGE : ErrorControl,
1907 ServiceBinary,
1908 (ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP && ServiceConfig->lpLoadOrderGroup) ? NULL : LoadOrderGroup,
1909 useTag ? &tagId : NULL,
1910 (ServiceFlags & SPSVCINST_NOCLOBBER_DEPENDENCIES && ServiceConfig->lpDependencies) ? NULL : Dependencies,
1911 StartName,
1912 NULL,
1913 (ServiceFlags & SPSVCINST_NOCLOBBER_DISPLAYNAME && ServiceConfig->lpDisplayName) ? NULL : DisplayName);
1914 if (!ret)
1915 goto cleanup;
1916 }
1917
1918 /* Set security */
1919 if (GetLineText(hInf, ServiceSection, SecurityKey, &SecurityDescriptor))
1920 {
1921 ret = ConvertStringSecurityDescriptorToSecurityDescriptorW(SecurityDescriptor, SDDL_REVISION_1, &sd, NULL);
1922 if (!ret)
1923 goto cleanup;
1924 ret = SetServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, sd);
1925 if (!ret)
1926 goto cleanup;
1927 }
1928
1929 /* FIXME: use Description and SPSVCINST_NOCLOBBER_DESCRIPTION */
1930
1931 if (useTag)
1932 {
1933 /* Add the tag to SYSTEM\CurrentControlSet\Control\GroupOrderList key */
1934 LPCWSTR lpLoadOrderGroup;
1935 DWORD bufferSize;
1936
1937 lpLoadOrderGroup = LoadOrderGroup;
1938 if ((ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP) && ServiceConfig && ServiceConfig->lpLoadOrderGroup)
1939 lpLoadOrderGroup = ServiceConfig->lpLoadOrderGroup;
1940
1941 rc = RegOpenKeyW(
1942 list ? list->HKLM : HKEY_LOCAL_MACHINE,
1943 GroupOrderListKey,
1944 &hGroupOrderListKey);
1945 if (rc != ERROR_SUCCESS)
1946 {
1947 SetLastError(rc);
1948 goto cleanup;
1949 }
1950 rc = RegQueryValueExW(hGroupOrderListKey, lpLoadOrderGroup, NULL, &dwRegType, NULL, &bufferSize);
1951 if (rc == ERROR_FILE_NOT_FOUND)
1952 bufferSize = sizeof(DWORD);
1953 else if (rc != ERROR_SUCCESS)
1954 {
1955 SetLastError(rc);
1956 goto cleanup;
1957 }
1958 else if (dwRegType != REG_BINARY || bufferSize == 0 || bufferSize % sizeof(DWORD) != 0)
1959 {
1960 SetLastError(ERROR_GEN_FAILURE);
1961 goto cleanup;
1962 }
1963 /* Allocate buffer to store existing data + the new tag */
1964 GroupOrder = MyMalloc(bufferSize + sizeof(DWORD));
1965 if (!GroupOrder)
1966 {
1967 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1968 goto cleanup;
1969 }
1970 if (rc == ERROR_SUCCESS)
1971 {
1972 /* Read existing data */
1973 rc = RegQueryValueExW(
1974 hGroupOrderListKey,
1975 lpLoadOrderGroup,
1976 NULL,
1977 NULL,
1978 (BYTE*)GroupOrder,
1979 &bufferSize);
1980 if (rc != ERROR_SUCCESS)
1981 {
1982 SetLastError(rc);
1983 goto cleanup;
1984 }
1985 if (ServiceFlags & SPSVCINST_TAGTOFRONT)
1986 memmove(&GroupOrder[2], &GroupOrder[1], bufferSize - sizeof(DWORD));
1987 }
1988 else
1989 {
1990 GroupOrder[0] = 0;
1991 }
1992 GroupOrder[0]++;
1993 if (ServiceFlags & SPSVCINST_TAGTOFRONT)
1994 GroupOrder[1] = tagId;
1995 else
1996 GroupOrder[bufferSize / sizeof(DWORD)] = tagId;
1997
1998 rc = RegSetValueExW(
1999 hGroupOrderListKey,
2000 lpLoadOrderGroup,
2001 0,
2002 REG_BINARY,
2003 (BYTE*)GroupOrder,
2004 bufferSize + sizeof(DWORD));
2005 if (rc != ERROR_SUCCESS)
2006 {
2007 SetLastError(rc);
2008 goto cleanup;
2009 }
2010 }
2011
2012 /* Handle AddReg and DelReg */
2013 rc = RegOpenKeyExW(
2014 list ? list->HKLM : HKEY_LOCAL_MACHINE,
2015 REGSTR_PATH_SERVICES,
2016 0,
2017 READ_CONTROL,
2018 &hServicesKey);
2019 if (rc != ERROR_SUCCESS)
2020 {
2021 SetLastError(rc);
2022 goto cleanup;
2023 }
2024 rc = RegOpenKeyExW(
2025 hServicesKey,
2026 ServiceName,
2027 0,
2028 KEY_READ | KEY_WRITE,
2029 &hServiceKey);
2030 RegCloseKey(hServicesKey);
2031 if (rc != ERROR_SUCCESS)
2032 {
2033 SetLastError(rc);
2034 goto cleanup;
2035 }
2036
2037 ret = SetupInstallFromInfSectionW(
2038 NULL,
2039 hInf,
2040 ServiceSection,
2041 SPINST_REGISTRY,
2042 hServiceKey,
2043 NULL,
2044 0,
2045 NULL,
2046 NULL,
2047 NULL,
2048 NULL);
2049 RegCloseKey(hServiceKey);
2050
2051 cleanup:
2052 if (hSCManager != NULL)
2053 CloseServiceHandle(hSCManager);
2054 if (hService != NULL)
2055 CloseServiceHandle(hService);
2056 if (hGroupOrderListKey != NULL)
2057 RegCloseKey(hGroupOrderListKey);
2058 if (sd != NULL)
2059 LocalFree(sd);
2060 MyFree(ServiceConfig);
2061 MyFree(ServiceBinary);
2062 MyFree(LoadOrderGroup);
2063 MyFree(DisplayName);
2064 MyFree(Description);
2065 MyFree(Dependencies);
2066 MyFree(SecurityDescriptor);
2067 MyFree(GroupOrder);
2068 MyFree(StartName);
2069
2070 TRACE("Returning %d\n", ret);
2071 return ret;
2072 }
2073
2074
2075 /***********************************************************************
2076 * SetupInstallServicesFromInfSectionExW (SETUPAPI.@)
2077 */
2078 BOOL WINAPI SetupInstallServicesFromInfSectionExW( HINF hinf, PCWSTR sectionname, DWORD flags, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PVOID reserved1, PVOID reserved2 )
2079 {
2080 struct DeviceInfoSet *list = NULL;
2081 BOOL ret = FALSE;
2082
2083 TRACE("%p, %s, 0x%lx, %p, %p, %p, %p\n", hinf, debugstr_w(sectionname),
2084 flags, DeviceInfoSet, DeviceInfoData, reserved1, reserved2);
2085
2086 if (!sectionname)
2087 SetLastError(ERROR_INVALID_PARAMETER);
2088 else if (flags & ~(SPSVCINST_TAGTOFRONT | SPSVCINST_DELETEEVENTLOGENTRY | SPSVCINST_NOCLOBBER_DISPLAYNAME | SPSVCINST_NOCLOBBER_STARTTYPE | SPSVCINST_NOCLOBBER_ERRORCONTROL | SPSVCINST_NOCLOBBER_LOADORDERGROUP | SPSVCINST_NOCLOBBER_DEPENDENCIES | SPSVCINST_STOPSERVICE))
2089 {
2090 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));
2091 SetLastError(ERROR_INVALID_FLAGS);
2092 }
2093 else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
2094 SetLastError(ERROR_INVALID_HANDLE);
2095 else if (DeviceInfoSet && (list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
2096 SetLastError(ERROR_INVALID_HANDLE);
2097 else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
2098 SetLastError(ERROR_INVALID_USER_BUFFER);
2099 else if (reserved1 != NULL || reserved2 != NULL)
2100 SetLastError(ERROR_INVALID_PARAMETER);
2101 else
2102 {
2103 struct needs_callback_info needs_info;
2104 LPWSTR ServiceName = NULL;
2105 LPWSTR ServiceSection = NULL;
2106 INT ServiceFlags;
2107 INFCONTEXT ContextService;
2108 BOOL bNeedReboot = FALSE;
2109
2110 /* Parse 'Include' and 'Needs' directives */
2111 iterate_section_fields( hinf, sectionname, Include, include_callback, NULL);
2112 needs_info.type = 1;
2113 needs_info.flags = flags;
2114 needs_info.devinfo = DeviceInfoSet;
2115 needs_info.devinfo_data = DeviceInfoData;
2116 needs_info.reserved1 = reserved1;
2117 needs_info.reserved2 = reserved2;
2118 iterate_section_fields( hinf, sectionname, Needs, needs_callback, &needs_info);
2119
2120 if (flags & SPSVCINST_STOPSERVICE)
2121 {
2122 FIXME("Stopping the device not implemented\n");
2123 /* This may lead to require a reboot */
2124 /* bNeedReboot = TRUE; */
2125 #if 0
2126 SERVICE_STATUS ServiceStatus;
2127 ret = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus);
2128 if (!ret && GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
2129 goto done;
2130 if (ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING && ServiceStatus.dwCurrentState != SERVICE_STOPPED)
2131 {
2132 SetLastError(ERROR_INSTALL_SERVICE_FAILURE);
2133 goto done;
2134 }
2135 #endif
2136 flags &= ~SPSVCINST_STOPSERVICE;
2137 }
2138
2139 if (!(ret = SetupFindFirstLineW( hinf, sectionname, NULL, &ContextService )))
2140 {
2141 SetLastError( ERROR_SECTION_NOT_FOUND );
2142 goto done;
2143 }
2144
2145 ret = SetupFindFirstLineW(hinf, sectionname, AddService, &ContextService);
2146 while (ret)
2147 {
2148 if (!GetStringField(&ContextService, 1, &ServiceName))
2149 goto done;
2150
2151 ret = SetupGetIntField(
2152 &ContextService,
2153 2, /* Field index */
2154 &ServiceFlags);
2155 if (!ret)
2156 {
2157 /* The field may be empty. Ignore the error */
2158 ServiceFlags = 0;
2159 }
2160
2161 if (!GetStringField(&ContextService, 3, &ServiceSection))
2162 goto done;
2163
2164 ret = InstallOneService(list, hinf, ServiceSection, ServiceName, (ServiceFlags & ~SPSVCINST_ASSOCSERVICE) | flags);
2165 if (!ret)
2166 goto done;
2167
2168 if (ServiceFlags & SPSVCINST_ASSOCSERVICE)
2169 {
2170 ret = SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet, DeviceInfoData, SPDRP_SERVICE, (LPBYTE)ServiceName, (strlenW(ServiceName) + 1) * sizeof(WCHAR));
2171 if (!ret)
2172 goto done;
2173 }
2174
2175 HeapFree(GetProcessHeap(), 0, ServiceName);
2176 HeapFree(GetProcessHeap(), 0, ServiceSection);
2177 ServiceName = ServiceSection = NULL;
2178 ret = SetupFindNextMatchLineW(&ContextService, AddService, &ContextService);
2179 }
2180
2181 if (bNeedReboot)
2182 SetLastError(ERROR_SUCCESS_REBOOT_REQUIRED);
2183 else
2184 SetLastError(ERROR_SUCCESS);
2185 ret = TRUE;
2186 }
2187 done:
2188 TRACE("Returning %d\n", ret);
2189 return ret;
2190 }
2191
2192
2193 /***********************************************************************
2194 * SetupCopyOEMInfA (SETUPAPI.@)
2195 */
2196 BOOL WINAPI SetupCopyOEMInfA(
2197 IN PCSTR SourceInfFileName,
2198 IN PCSTR OEMSourceMediaLocation,
2199 IN DWORD OEMSourceMediaType,
2200 IN DWORD CopyStyle,
2201 OUT PSTR DestinationInfFileName OPTIONAL,
2202 IN DWORD DestinationInfFileNameSize,
2203 OUT PDWORD RequiredSize OPTIONAL,
2204 OUT PSTR* DestinationInfFileNameComponent OPTIONAL)
2205 {
2206 PWSTR SourceInfFileNameW = NULL;
2207 PWSTR OEMSourceMediaLocationW = NULL;
2208 PWSTR DestinationInfFileNameW = NULL;
2209 PWSTR DestinationInfFileNameComponentW = NULL;
2210 BOOL ret = FALSE;
2211 DWORD size;
2212
2213 TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n",
2214 SourceInfFileName, OEMSourceMediaLocation, OEMSourceMediaType,
2215 CopyStyle, DestinationInfFileName, DestinationInfFileNameSize,
2216 RequiredSize, DestinationInfFileNameComponent);
2217
2218 if (!DestinationInfFileName && DestinationInfFileNameSize > 0)
2219 SetLastError(ERROR_INVALID_PARAMETER);
2220 else if (!(SourceInfFileNameW = pSetupMultiByteToUnicode(SourceInfFileName, CP_ACP)))
2221 SetLastError(ERROR_INVALID_PARAMETER);
2222 else if (OEMSourceMediaType != SPOST_NONE && !(OEMSourceMediaLocationW = pSetupMultiByteToUnicode(OEMSourceMediaLocation, CP_ACP)))
2223 SetLastError(ERROR_INVALID_PARAMETER);
2224 else
2225 {
2226 if (DestinationInfFileNameSize != 0)
2227 {
2228 DestinationInfFileNameW = MyMalloc(DestinationInfFileNameSize * sizeof(WCHAR));
2229 if (!DestinationInfFileNameW)
2230 {
2231 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2232 goto cleanup;
2233 }
2234 }
2235
2236 ret = SetupCopyOEMInfW(
2237 SourceInfFileNameW,
2238 OEMSourceMediaLocationW,
2239 OEMSourceMediaType,
2240 CopyStyle,
2241 DestinationInfFileNameW,
2242 DestinationInfFileNameSize,
2243 &size,
2244 DestinationInfFileNameComponent ? &DestinationInfFileNameComponentW : NULL);
2245 if (!ret)
2246 {
2247 if (RequiredSize) *RequiredSize = size;
2248 goto cleanup;
2249 }
2250
2251 if (DestinationInfFileNameSize != 0)
2252 {
2253 if (WideCharToMultiByte(CP_ACP, 0, DestinationInfFileNameW, -1,
2254 DestinationInfFileName, DestinationInfFileNameSize, NULL, NULL) == 0)
2255 {
2256 DestinationInfFileName[0] = '\0';
2257 goto cleanup;
2258 }
2259 }
2260 if (DestinationInfFileNameComponent)
2261 {
2262 if (DestinationInfFileNameComponentW)
2263 *DestinationInfFileNameComponent = &DestinationInfFileName[DestinationInfFileNameComponentW - DestinationInfFileNameW];
2264 else
2265 *DestinationInfFileNameComponent = NULL;
2266 }
2267 ret = TRUE;
2268 }
2269
2270 cleanup:
2271 MyFree(SourceInfFileNameW);
2272 MyFree(OEMSourceMediaLocationW);
2273 MyFree(DestinationInfFileNameW);
2274 TRACE("Returning %d\n", ret);
2275 if (ret) SetLastError(ERROR_SUCCESS);
2276 return ret;
2277 }
2278
2279 static int compare_files( HANDLE file1, HANDLE file2 )
2280 {
2281 char buffer1[2048];
2282 char buffer2[2048];
2283 DWORD size1;
2284 DWORD size2;
2285
2286 while( ReadFile(file1, buffer1, sizeof(buffer1), &size1, NULL) &&
2287 ReadFile(file2, buffer2, sizeof(buffer2), &size2, NULL) )
2288 {
2289 int ret;
2290 if (size1 != size2)
2291 return size1 > size2 ? 1 : -1;
2292 if (!size1)
2293 return 0;
2294 ret = memcmp( buffer1, buffer2, size1 );
2295 if (ret)
2296 return ret;
2297 }
2298
2299 return 0;
2300 }
2301
2302 /***********************************************************************
2303 * SetupCopyOEMInfW (SETUPAPI.@)
2304 */
2305 BOOL WINAPI SetupCopyOEMInfW(
2306 IN PCWSTR SourceInfFileName,
2307 IN PCWSTR OEMSourceMediaLocation,
2308 IN DWORD OEMSourceMediaType,
2309 IN DWORD CopyStyle,
2310 OUT PWSTR DestinationInfFileName OPTIONAL,
2311 IN DWORD DestinationInfFileNameSize,
2312 OUT PDWORD RequiredSize OPTIONAL,
2313 OUT PWSTR* DestinationInfFileNameComponent OPTIONAL)
2314 {
2315 BOOL ret = FALSE;
2316
2317 TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n",
2318 debugstr_w(SourceInfFileName), debugstr_w(OEMSourceMediaLocation), OEMSourceMediaType,
2319 CopyStyle, DestinationInfFileName, DestinationInfFileNameSize,
2320 RequiredSize, DestinationInfFileNameComponent);
2321
2322 if (!SourceInfFileName)
2323 SetLastError(ERROR_INVALID_PARAMETER);
2324 else if (OEMSourceMediaType != SPOST_NONE && OEMSourceMediaType != SPOST_PATH && OEMSourceMediaType != SPOST_URL)
2325 SetLastError(ERROR_INVALID_PARAMETER);
2326 else if (CopyStyle & ~(SP_COPY_DELETESOURCE | SP_COPY_REPLACEONLY | SP_COPY_NOOVERWRITE | SP_COPY_OEMINF_CATALOG_ONLY))
2327 {
2328 TRACE("Unknown flags: 0x%08lx\n", CopyStyle & ~(SP_COPY_DELETESOURCE | SP_COPY_REPLACEONLY | SP_COPY_NOOVERWRITE | SP_COPY_OEMINF_CATALOG_ONLY));
2329 SetLastError(ERROR_INVALID_FLAGS);
2330 }
2331 else if (!DestinationInfFileName && DestinationInfFileNameSize > 0)
2332 SetLastError(ERROR_INVALID_PARAMETER);
2333 else if (CopyStyle & SP_COPY_OEMINF_CATALOG_ONLY)
2334 {
2335 FIXME("CopyStyle 0x%x not supported\n", SP_COPY_OEMINF_CATALOG_ONLY);
2336 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2337 }
2338 else
2339 {
2340 HANDLE hSearch = INVALID_HANDLE_VALUE;
2341 WIN32_FIND_DATAW FindFileData;
2342 BOOL AlreadyExists;
2343 DWORD NextFreeNumber = 0;
2344 SIZE_T len;
2345 LPWSTR pFullFileName = NULL;
2346 LPWSTR pFileName; /* Pointer into pFullFileName buffer */
2347 HANDLE hSourceFile = INVALID_HANDLE_VALUE;
2348
2349 if (OEMSourceMediaType == SPOST_PATH || OEMSourceMediaType == SPOST_URL)
2350 FIXME("OEMSourceMediaType 0x%lx ignored\n", OEMSourceMediaType);
2351
2352 /* Check if source file exists, and open it */
2353 if (strchrW(SourceInfFileName, '\\' ) || strchrW(SourceInfFileName, '/' ))
2354 {
2355 WCHAR *path;
2356
2357 if (!(len = GetFullPathNameW(SourceInfFileName, 0, NULL, NULL)))
2358 return FALSE;
2359 if (!(path = MyMalloc(len * sizeof(WCHAR))))
2360 {
2361 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2362 return FALSE;
2363 }
2364 GetFullPathNameW(SourceInfFileName, len, path, NULL);
2365 hSourceFile = CreateFileW(
2366 path, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
2367 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2368 NULL, OPEN_EXISTING, 0, NULL);
2369 MyFree(path);
2370 }
2371 else /* try Windows directory */
2372 {
2373 WCHAR *path, *p;
2374 static const WCHAR Inf[] = {'\\','i','n','f','\\',0};
2375 static const WCHAR System32[] = {'\\','s','y','s','t','e','m','3','2','\\',0};
2376
2377 len = GetWindowsDirectoryW(NULL, 0) + strlenW(SourceInfFileName) + 12;
2378 if (!(path = MyMalloc(len * sizeof(WCHAR))))
2379 {
2380 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2381 return FALSE;
2382 }
2383 GetWindowsDirectoryW(path, len);
2384 p = path + strlenW(path);
2385 strcpyW(p, Inf);
2386 strcatW(p, SourceInfFileName);
2387 hSourceFile = CreateFileW(
2388 path, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
2389 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2390 NULL, OPEN_EXISTING, 0, NULL);
2391 if (hSourceFile == INVALID_HANDLE_VALUE)
2392 {
2393 strcpyW(p, System32);
2394 strcatW(p, SourceInfFileName);
2395 hSourceFile = CreateFileW(
2396 path, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
2397 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2398 NULL, OPEN_EXISTING, 0, NULL);
2399 }
2400 MyFree(path);
2401 }
2402 if (hSourceFile == INVALID_HANDLE_VALUE)
2403 {
2404 SetLastError(ERROR_FILE_NOT_FOUND);
2405 goto cleanup;
2406 }
2407
2408 /* Prepare .inf file specification */
2409 len = MAX_PATH + 1 + strlenW(InfDirectory) + 13;
2410 pFullFileName = MyMalloc(len * sizeof(WCHAR));
2411 if (!pFullFileName)
2412 {
2413 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2414 goto cleanup;
2415 }
2416 len = GetSystemWindowsDirectoryW(pFullFileName, MAX_PATH);
2417 if (len == 0 || len > MAX_PATH)
2418 goto cleanup;
2419 if (pFullFileName[strlenW(pFullFileName) - 1] != '\\')
2420 strcatW(pFullFileName, BackSlash);
2421 strcatW(pFullFileName, InfDirectory);
2422 pFileName = &pFullFileName[strlenW(pFullFileName)];
2423
2424 /* Search if the specified .inf file already exists in %WINDIR%\Inf */
2425 AlreadyExists = FALSE;
2426 strcpyW(pFileName, OemFileMask);
2427 hSearch = FindFirstFileW(pFullFileName, &FindFileData);
2428 if (hSearch != INVALID_HANDLE_VALUE)
2429 {
2430 LARGE_INTEGER SourceFileSize;
2431
2432 if (GetFileSizeEx(hSourceFile, &SourceFileSize))
2433 {
2434 do
2435 {
2436 LARGE_INTEGER DestFileSize;
2437 HANDLE hDestFile;
2438
2439 strcpyW(pFileName, FindFileData.cFileName);
2440 hDestFile = CreateFileW(
2441 pFullFileName, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
2442 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2443 NULL, OPEN_EXISTING, 0, NULL);
2444 if (hDestFile != INVALID_HANDLE_VALUE)
2445 {
2446 if (GetFileSizeEx(hDestFile, &DestFileSize)
2447 && DestFileSize.QuadPart == SourceFileSize.QuadPart
2448 && !compare_files(hSourceFile, hDestFile))
2449 {
2450 TRACE("%s already exists as %s\n",
2451 debugstr_w(SourceInfFileName), debugstr_w(pFileName));
2452 AlreadyExists = TRUE;
2453 }
2454 }
2455 } while (!AlreadyExists && FindNextFileW(hSearch, &FindFileData));
2456 }
2457 FindClose(hSearch);
2458 hSearch = INVALID_HANDLE_VALUE;
2459 }
2460
2461 if (!AlreadyExists && CopyStyle & SP_COPY_REPLACEONLY)
2462 {
2463 /* FIXME: set DestinationInfFileName, RequiredSize, DestinationInfFileNameComponent */
2464 SetLastError(ERROR_FILE_NOT_FOUND);
2465 goto cleanup;
2466 }
2467 else if (AlreadyExists && (CopyStyle & SP_COPY_NOOVERWRITE))
2468 {
2469 DWORD Size = strlenW(pFileName) + 1;
2470
2471 if (RequiredSize)
2472 *RequiredSize = Size;
2473 if (DestinationInfFileNameSize == 0)
2474 SetLastError(ERROR_FILE_EXISTS);
2475 else if (DestinationInfFileNameSize < Size)
2476 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2477 else
2478 {
2479 SetLastError(ERROR_FILE_EXISTS);
2480 strcpyW(DestinationInfFileName, pFileName);
2481 }
2482 goto cleanup;
2483 }
2484
2485 /* Search the number to give to OEM??.INF */
2486 strcpyW(pFileName, OemFileMask);
2487 hSearch = FindFirstFileW(pFullFileName, &FindFileData);
2488 if (hSearch == INVALID_HANDLE_VALUE)
2489 {
2490 if (GetLastError() != ERROR_FILE_NOT_FOUND)
2491 goto cleanup;
2492 }
2493 else
2494 {
2495 do
2496 {
2497 DWORD CurrentNumber;
2498 if (swscanf(FindFileData.cFileName, OemFileSpecification, &CurrentNumber) == 1
2499 && CurrentNumber <= 99999)
2500 {
2501 if (CurrentNumber >= NextFreeNumber)
2502 NextFreeNumber = CurrentNumber + 1;
2503 }
2504 } while (FindNextFileW(hSearch, &FindFileData));
2505 }
2506
2507 if (NextFreeNumber > 99999)
2508 {
2509 ERR("Too much custom .inf files\n");
2510 SetLastError(ERROR_GEN_FAILURE);
2511 goto cleanup;
2512 }
2513
2514 /* Create the full path: %WINDIR%\Inf\OEM{XXXXX}.inf */
2515 sprintfW(pFileName, OemFileSpecification, NextFreeNumber);
2516 TRACE("Next available file is %s\n", debugstr_w(pFileName));
2517
2518 if (!CopyFileW(SourceInfFileName, pFullFileName, TRUE))
2519 {
2520 TRACE("CopyFileW() failed with error 0x%lx\n", GetLastError());
2521 goto cleanup;
2522 }
2523
2524 len = strlenW(pFullFileName) + 1;
2525 if (RequiredSize)
2526 *RequiredSize = len;
2527 if (DestinationInfFileName)
2528 {
2529 if (DestinationInfFileNameSize >= len)
2530 {
2531 strcpyW(DestinationInfFileName, pFullFileName);
2532 if (DestinationInfFileNameComponent)
2533 *DestinationInfFileNameComponent = &DestinationInfFileName[pFileName - pFullFileName];
2534 }
2535 else
2536 {
2537 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2538 goto cleanup;
2539 }
2540 }
2541
2542 if (CopyStyle & SP_COPY_DELETESOURCE)
2543 {
2544 if (!DeleteFileW(SourceInfFileName))
2545 {
2546 TRACE("DeleteFileW() failed with error 0x%lx\n", GetLastError());
2547 goto cleanup;
2548 }
2549 }
2550
2551 ret = TRUE;
2552
2553 cleanup:
2554 if (hSourceFile != INVALID_HANDLE_VALUE)
2555 CloseHandle(hSourceFile);
2556 if (hSearch != INVALID_HANDLE_VALUE)
2557 FindClose(hSearch);
2558 MyFree(pFullFileName);
2559 }
2560
2561 TRACE("Returning %d\n", ret);
2562 if (ret) SetLastError(ERROR_SUCCESS);
2563 return ret;
2564 }