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