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