ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

install.c
Go to the documentation of this file.
00001 /*
00002  * Setupapi install routines
00003  *
00004  * Copyright 2002 Alexandre Julliard for CodeWeavers
00005  *           2005-2006 Hervé Poussineau (hpoussin@reactos.org)
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #include "setupapi_private.h"
00023 
00024 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
00025 
00026 /* Unicode constants */
00027 static const WCHAR BackSlash[] = {'\\',0};
00028 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};
00029 static const WCHAR InfDirectory[] = {'i','n','f','\\',0};
00030 static const WCHAR OemFileMask[] = {'o','e','m','*','.','i','n','f',0};
00031 static const WCHAR OemFileSpecification[] = {'o','e','m','%','l','u','.','i','n','f',0};
00032 static const WCHAR DotLnk[] = {'.','l','n','k',0};
00033 static const WCHAR DotServices[]  = {'.','S','e','r','v','i','c','e','s',0};
00034 
00035 static const WCHAR DependenciesKey[] = {'D','e','p','e','n','d','e','n','c','i','e','s',0};
00036 static const WCHAR DescriptionKey[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
00037 static const WCHAR DisplayNameKey[] = {'D','i','s','p','l','a','y','N','a','m','e',0};
00038 static const WCHAR ErrorControlKey[] = {'E','r','r','o','r','C','o','n','t','r','o','l',0};
00039 static const WCHAR LoadOrderGroupKey[] = {'L','o','a','d','O','r','d','e','r','G','r','o','u','p',0};
00040 static const WCHAR SecurityKey[] = {'S','e','c','u','r','i','t','y',0};
00041 static const WCHAR ServiceBinaryKey[] = {'S','e','r','v','i','c','e','B','i','n','a','r','y',0};
00042 static const WCHAR ServiceTypeKey[] = {'S','e','r','v','i','c','e','T','y','p','e',0};
00043 static const WCHAR StartTypeKey[] = {'S','t','a','r','t','T','y','p','e',0};
00044 
00045 static const WCHAR Name[] = {'N','a','m','e',0};
00046 static const WCHAR CmdLine[] = {'C','m','d','L','i','n','e',0};
00047 static const WCHAR SubDir[] = {'S','u','b','D','i','r',0};
00048 static const WCHAR WorkingDir[] = {'W','o','r','k','i','n','g','D','i','r',0};
00049 static const WCHAR IconPath[] = {'I','c','o','n','P','a','t','h',0};
00050 static const WCHAR IconIndex[] = {'I','c','o','n','I','n','d','e','x',0};
00051 static const WCHAR HotKey[] = {'H','o','t','K','e','y',0};
00052 static const WCHAR InfoTip[] = {'I','n','f','o','T','i','p',0};
00053 static const WCHAR DisplayResource[] = {'D','i','s','p','l','a','y','R','e','s','o','u','r','c','e',0};
00054 
00055 /* info passed to callback functions dealing with files */
00056 struct files_callback_info
00057 {
00058     HSPFILEQ queue;
00059     PCWSTR   src_root;
00060     UINT     copy_flags;
00061     HINF     layout;
00062 };
00063 
00064 /* info passed to callback functions dealing with the registry */
00065 struct registry_callback_info
00066 {
00067     HKEY default_root;
00068     BOOL delete;
00069 };
00070 
00071 /* info passed to callback functions dealing with registering dlls */
00072 struct register_dll_info
00073 {
00074     PSP_FILE_CALLBACK_W callback;
00075     PVOID               callback_context;
00076     BOOL                unregister;
00077 };
00078 
00079 /* info passed to callback functions dealing with Needs directives */
00080 struct needs_callback_info
00081 {
00082     UINT type;
00083 
00084     HWND             owner;
00085     UINT             flags;
00086     HKEY             key_root;
00087     LPCWSTR          src_root;
00088     UINT             copy_flags;
00089     PVOID            callback;
00090     PVOID            context;
00091     HDEVINFO         devinfo;
00092     PSP_DEVINFO_DATA devinfo_data;
00093     PVOID            reserved1;
00094     PVOID            reserved2;
00095 };
00096 
00097 typedef BOOL (*iterate_fields_func)( HINF hinf, PCWSTR field, void *arg );
00098 static BOOL GetLineText( HINF hinf, PCWSTR section_name, PCWSTR key_name, PWSTR *value);
00099 typedef HRESULT (WINAPI *COINITIALIZE)(IN LPVOID pvReserved);
00100 typedef HRESULT (WINAPI *COCREATEINSTANCE)(IN REFCLSID rclsid, IN LPUNKNOWN pUnkOuter, IN DWORD dwClsContext, IN REFIID riid, OUT LPVOID *ppv);
00101 typedef HRESULT (WINAPI *COUNINITIALIZE)(VOID);
00102 
00103 /* Unicode constants */
00104 static const WCHAR AddService[] = {'A','d','d','S','e','r','v','i','c','e',0};
00105 static const WCHAR CopyFiles[]  = {'C','o','p','y','F','i','l','e','s',0};
00106 static const WCHAR DelFiles[]   = {'D','e','l','F','i','l','e','s',0};
00107 static const WCHAR RenFiles[]   = {'R','e','n','F','i','l','e','s',0};
00108 static const WCHAR Ini2Reg[]    = {'I','n','i','2','R','e','g',0};
00109 static const WCHAR LogConf[]    = {'L','o','g','C','o','n','f',0};
00110 static const WCHAR AddReg[]     = {'A','d','d','R','e','g',0};
00111 static const WCHAR DelReg[]     = {'D','e','l','R','e','g',0};
00112 static const WCHAR BitReg[]     = {'B','i','t','R','e','g',0};
00113 static const WCHAR UpdateInis[] = {'U','p','d','a','t','e','I','n','i','s',0};
00114 static const WCHAR CopyINF[]    = {'C','o','p','y','I','N','F',0};
00115 static const WCHAR UpdateIniFields[] = {'U','p','d','a','t','e','I','n','i','F','i','e','l','d','s',0};
00116 static const WCHAR RegisterDlls[]    = {'R','e','g','i','s','t','e','r','D','l','l','s',0};
00117 static const WCHAR UnregisterDlls[]  = {'U','n','r','e','g','i','s','t','e','r','D','l','l','s',0};
00118 static const WCHAR ProfileItems[]    = {'P','r','o','f','i','l','e','I','t','e','m','s',0};
00119 static const WCHAR Include[]         = {'I','n','c','l','u','d','e',0};
00120 static const WCHAR Needs[]           = {'N','e','e','d','s',0};
00121 static const WCHAR DotSecurity[]     = {'.','S','e','c','u','r','i','t','y',0};
00122 #ifdef __WINESRC__
00123 static const WCHAR WineFakeDlls[]    = {'W','i','n','e','F','a','k','e','D','l','l','s',0};
00124 #endif
00125 
00126 
00127 /***********************************************************************
00128  *            get_field_string
00129  *
00130  * Retrieve the contents of a field, dynamically growing the buffer if necessary.
00131  */
00132 static WCHAR *get_field_string( INFCONTEXT *context, DWORD index, WCHAR *buffer,
00133                                 WCHAR *static_buffer, DWORD *size )
00134 {
00135     DWORD required;
00136 
00137     if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer;
00138     if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
00139     {
00140         /* now grow the buffer */
00141         if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
00142         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, required*sizeof(WCHAR) ))) return NULL;
00143         *size = required;
00144         if (SetupGetStringFieldW( context, index, buffer, *size, &required )) return buffer;
00145     }
00146     if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
00147     return NULL;
00148 }
00149 
00150 
00151 /***********************************************************************
00152  *            copy_files_callback
00153  *
00154  * Called once for each CopyFiles entry in a given section.
00155  */
00156 static BOOL copy_files_callback( HINF hinf, PCWSTR field, void *arg )
00157 {
00158     struct files_callback_info *info = arg;
00159 
00160     if (field[0] == '@')  /* special case: copy single file */
00161         SetupQueueDefaultCopyW( info->queue, info->layout ? info->layout : hinf, info->src_root, NULL, field+1, info->copy_flags );
00162     else
00163         SetupQueueCopySectionW( info->queue, info->src_root, info->layout ? info->layout : hinf, hinf, field, info->copy_flags );
00164     return TRUE;
00165 }
00166 
00167 
00168 /***********************************************************************
00169  *            delete_files_callback
00170  *
00171  * Called once for each DelFiles entry in a given section.
00172  */
00173 static BOOL delete_files_callback( HINF hinf, PCWSTR field, void *arg )
00174 {
00175     struct files_callback_info *info = arg;
00176     SetupQueueDeleteSectionW( info->queue, hinf, 0, field );
00177     return TRUE;
00178 }
00179 
00180 
00181 /***********************************************************************
00182  *            rename_files_callback
00183  *
00184  * Called once for each RenFiles entry in a given section.
00185  */
00186 static BOOL rename_files_callback( HINF hinf, PCWSTR field, void *arg )
00187 {
00188     struct files_callback_info *info = arg;
00189     SetupQueueRenameSectionW( info->queue, hinf, 0, field );
00190     return TRUE;
00191 }
00192 
00193 
00194 /***********************************************************************
00195  *            get_root_key
00196  *
00197  * Retrieve the registry root key from its name.
00198  */
00199 static HKEY get_root_key( const WCHAR *name, HKEY def_root )
00200 {
00201     static const WCHAR HKCR[] = {'H','K','C','R',0};
00202     static const WCHAR HKCU[] = {'H','K','C','U',0};
00203     static const WCHAR HKLM[] = {'H','K','L','M',0};
00204     static const WCHAR HKU[]  = {'H','K','U',0};
00205     static const WCHAR HKR[]  = {'H','K','R',0};
00206 
00207     if (!strcmpiW( name, HKCR )) return HKEY_CLASSES_ROOT;
00208     if (!strcmpiW( name, HKCU )) return HKEY_CURRENT_USER;
00209     if (!strcmpiW( name, HKLM )) return HKEY_LOCAL_MACHINE;
00210     if (!strcmpiW( name, HKU )) return HKEY_USERS;
00211     if (!strcmpiW( name, HKR )) return def_root;
00212     return 0;
00213 }
00214 
00215 
00216 /***********************************************************************
00217  *            append_multi_sz_value
00218  *
00219  * Append a multisz string to a multisz registry value.
00220  */
00221 static void append_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *strings,
00222                                    DWORD str_size )
00223 {
00224     DWORD size, type, total;
00225     WCHAR *buffer, *p;
00226 
00227     if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
00228     if (type != REG_MULTI_SZ) return;
00229 
00230     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (size + str_size) * sizeof(WCHAR) ))) return;
00231     if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
00232 
00233     /* compare each string against all the existing ones */
00234     total = size;
00235     while (*strings)
00236     {
00237         int len = strlenW(strings) + 1;
00238 
00239         for (p = buffer; *p; p += strlenW(p) + 1)
00240             if (!strcmpiW( p, strings )) break;
00241 
00242         if (!*p)  /* not found, need to append it */
00243         {
00244             memcpy( p, strings, len * sizeof(WCHAR) );
00245             p[len] = 0;
00246             total += len;
00247         }
00248         strings += len;
00249     }
00250     if (total != size)
00251     {
00252         TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer) );
00253         RegSetValueExW( hkey, value, 0, REG_MULTI_SZ, (BYTE *)buffer, total + sizeof(WCHAR) );
00254     }
00255  done:
00256     HeapFree( GetProcessHeap(), 0, buffer );
00257 }
00258 
00259 
00260 /***********************************************************************
00261  *            delete_multi_sz_value
00262  *
00263  * Remove a string from a multisz registry value.
00264  */
00265 static void delete_multi_sz_value( HKEY hkey, const WCHAR *value, const WCHAR *string )
00266 {
00267     DWORD size, type;
00268     WCHAR *buffer, *src, *dst;
00269 
00270     if (RegQueryValueExW( hkey, value, NULL, &type, NULL, &size )) return;
00271     if (type != REG_MULTI_SZ) return;
00272     /* allocate double the size, one for value before and one for after */
00273     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size * 2 * sizeof(WCHAR) ))) return;
00274     if (RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &size )) goto done;
00275     src = buffer;
00276     dst = buffer + size;
00277     while (*src)
00278     {
00279         int len = strlenW(src) + 1;
00280         if (strcmpiW( src, string ))
00281         {
00282             memcpy( dst, src, len * sizeof(WCHAR) );
00283             dst += len;
00284         }
00285         src += len;
00286     }
00287     *dst++ = 0;
00288     if (dst != buffer + 2*size)  /* did we remove something? */
00289     {
00290         TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(buffer + size) );
00291         RegSetValueExW( hkey, value, 0, REG_MULTI_SZ,
00292                         (BYTE *)(buffer + size), dst - (buffer + size) );
00293     }
00294  done:
00295     HeapFree( GetProcessHeap(), 0, buffer );
00296 }
00297 
00298 
00299 /***********************************************************************
00300  *            do_reg_operation
00301  *
00302  * Perform an add/delete registry operation depending on the flags.
00303  */
00304 static BOOL do_reg_operation( HKEY hkey, const WCHAR *value, INFCONTEXT *context, INT flags )
00305 {
00306     DWORD type, size;
00307 
00308     if (flags & (FLG_ADDREG_DELREG_BIT | FLG_ADDREG_DELVAL))  /* deletion */
00309     {
00310         if (*value && !(flags & FLG_DELREG_KEYONLY_COMMON))
00311         {
00312             if ((flags & FLG_DELREG_MULTI_SZ_DELSTRING) == FLG_DELREG_MULTI_SZ_DELSTRING)
00313             {
00314                 WCHAR *str;
00315 
00316                 if (!SetupGetStringFieldW( context, 5, NULL, 0, &size ) || !size) return TRUE;
00317                 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
00318                 SetupGetStringFieldW( context, 5, str, size, NULL );
00319                 delete_multi_sz_value( hkey, value, str );
00320                 HeapFree( GetProcessHeap(), 0, str );
00321             }
00322             else RegDeleteValueW( hkey, value );
00323         }
00324         else NtDeleteKey( hkey );
00325         return TRUE;
00326     }
00327 
00328     if (flags & (FLG_ADDREG_KEYONLY|FLG_ADDREG_KEYONLY_COMMON)) return TRUE;
00329 
00330     if (flags & (FLG_ADDREG_NOCLOBBER|FLG_ADDREG_OVERWRITEONLY))
00331     {
00332         BOOL exists = !RegQueryValueExW( hkey, value, NULL, NULL, NULL, NULL );
00333         if (exists && (flags & FLG_ADDREG_NOCLOBBER)) return TRUE;
00334         if (!exists && (flags & FLG_ADDREG_OVERWRITEONLY)) return TRUE;
00335     }
00336 
00337     switch(flags & FLG_ADDREG_TYPE_MASK)
00338     {
00339     case FLG_ADDREG_TYPE_SZ:        type = REG_SZ; break;
00340     case FLG_ADDREG_TYPE_MULTI_SZ:  type = REG_MULTI_SZ; break;
00341     case FLG_ADDREG_TYPE_EXPAND_SZ: type = REG_EXPAND_SZ; break;
00342     case FLG_ADDREG_TYPE_BINARY:    type = REG_BINARY; break;
00343     case FLG_ADDREG_TYPE_DWORD:     type = REG_DWORD; break;
00344     case FLG_ADDREG_TYPE_NONE:      type = REG_NONE; break;
00345     default:                        type = flags >> 16; break;
00346     }
00347 
00348     if (!(flags & FLG_ADDREG_BINVALUETYPE) ||
00349         (type == REG_DWORD && SetupGetFieldCount(context) == 5))
00350     {
00351         static const WCHAR empty;
00352         WCHAR *str = NULL;
00353 
00354         if (type == REG_MULTI_SZ)
00355         {
00356             if (!SetupGetMultiSzFieldW( context, 5, NULL, 0, &size )) size = 0;
00357             if (size)
00358             {
00359                 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
00360                 SetupGetMultiSzFieldW( context, 5, str, size, NULL );
00361             }
00362             if (flags & FLG_ADDREG_APPEND)
00363             {
00364                 if (!str) return TRUE;
00365                 append_multi_sz_value( hkey, value, str, size );
00366                 HeapFree( GetProcessHeap(), 0, str );
00367                 return TRUE;
00368             }
00369             /* else fall through to normal string handling */
00370         }
00371         else
00372         {
00373             if (!SetupGetStringFieldW( context, 5, NULL, 0, &size )) size = 0;
00374             if (size)
00375             {
00376                 if (!(str = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return FALSE;
00377                 SetupGetStringFieldW( context, 5, str, size, NULL );
00378             }
00379         }
00380 
00381         if (type == REG_DWORD)
00382         {
00383             DWORD dw = str ? strtoulW( str, NULL, 0 ) : 0;
00384             TRACE( "setting dword %s to %x\n", debugstr_w(value), dw );
00385             RegSetValueExW( hkey, value, 0, type, (BYTE *)&dw, sizeof(dw) );
00386         }
00387         else
00388         {
00389             TRACE( "setting value %s to %s\n", debugstr_w(value), debugstr_w(str) );
00390             if (str) RegSetValueExW( hkey, value, 0, type, (BYTE *)str, size * sizeof(WCHAR) );
00391             else RegSetValueExW( hkey, value, 0, type, (const BYTE *)&empty, sizeof(WCHAR) );
00392         }
00393         HeapFree( GetProcessHeap(), 0, str );
00394         return TRUE;
00395     }
00396     else  /* get the binary data */
00397     {
00398         BYTE *data = NULL;
00399 
00400         if (!SetupGetBinaryField( context, 5, NULL, 0, &size )) size = 0;
00401         if (size)
00402         {
00403             if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
00404             TRACE( "setting binary data %s len %d\n", debugstr_w(value), size );
00405             SetupGetBinaryField( context, 5, data, size, NULL );
00406         }
00407         RegSetValueExW( hkey, value, 0, type, data, size );
00408         HeapFree( GetProcessHeap(), 0, data );
00409         return TRUE;
00410     }
00411 }
00412 
00413 
00414 /***********************************************************************
00415  *            registry_callback
00416  *
00417  * Called once for each AddReg and DelReg entry in a given section.
00418  */
00419 static BOOL registry_callback( HINF hinf, PCWSTR field, void *arg )
00420 {
00421     struct registry_callback_info *info = arg;
00422     LPWSTR security_key, security_descriptor;
00423     INFCONTEXT context, security_context;
00424     PSECURITY_DESCRIPTOR sd = NULL;
00425     SECURITY_ATTRIBUTES security_attributes = { 0, };
00426     HKEY root_key, hkey;
00427     DWORD required;
00428 
00429     BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
00430     if (!ok)
00431         return TRUE;
00432 
00433     /* Check for .Security section */
00434     security_key = MyMalloc( (strlenW( field ) + strlenW( DotSecurity )) * sizeof(WCHAR) + sizeof(UNICODE_NULL) );
00435     if (!security_key)
00436     {
00437         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
00438         return FALSE;
00439     }
00440     strcpyW( security_key, field );
00441     strcatW( security_key, DotSecurity );
00442     ok = SetupFindFirstLineW( hinf, security_key, NULL, &security_context );
00443     MyFree(security_key);
00444     if (ok)
00445     {
00446         if (!SetupGetLineTextW( &security_context, NULL, NULL, NULL, NULL, 0, &required ))
00447             return FALSE;
00448         security_descriptor = MyMalloc( required * sizeof(WCHAR) );
00449         if (!security_descriptor)
00450         {
00451             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
00452             return FALSE;
00453         }
00454         if (!SetupGetLineTextW( &security_context, NULL, NULL, NULL, security_descriptor, required, NULL ))
00455             return FALSE;
00456         ok = ConvertStringSecurityDescriptorToSecurityDescriptorW( security_descriptor, SDDL_REVISION_1, &sd, NULL );
00457         MyFree( security_descriptor );
00458         if (!ok)
00459             return FALSE;
00460         security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
00461         security_attributes.lpSecurityDescriptor = sd;
00462     }
00463 
00464     for (ok = TRUE; ok; ok = SetupFindNextLine( &context, &context ))
00465     {
00466         WCHAR buffer[MAX_INF_STRING_LENGTH];
00467         INT flags;
00468 
00469         /* get root */
00470         if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
00471             continue;
00472         if (!(root_key = get_root_key( buffer, info->default_root )))
00473             continue;
00474 
00475         /* get key */
00476         if (!SetupGetStringFieldW( &context, 2, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
00477             *buffer = 0;
00478 
00479         /* get flags */
00480         if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
00481 
00482         if (!info->delete)
00483         {
00484             if (flags & FLG_ADDREG_DELREG_BIT) continue;  /* ignore this entry */
00485         }
00486         else
00487         {
00488             if (!flags) flags = FLG_ADDREG_DELREG_BIT;
00489             else if (!(flags & FLG_ADDREG_DELREG_BIT)) continue;  /* ignore this entry */
00490         }
00491 
00492         if (info->delete || (flags & FLG_ADDREG_OVERWRITEONLY))
00493         {
00494             if (RegOpenKeyW( root_key, buffer, &hkey )) continue;  /* ignore if it doesn't exist */
00495         }
00496         else if (RegCreateKeyExW( root_key, buffer, 0, NULL, 0, MAXIMUM_ALLOWED,
00497             sd ? &security_attributes : NULL, &hkey, NULL ))
00498         {
00499             ERR( "could not create key %p %s\n", root_key, debugstr_w(buffer) );
00500             continue;
00501         }
00502         TRACE( "key %p %s\n", root_key, debugstr_w(buffer) );
00503 
00504         /* get value name */
00505         if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
00506             *buffer = 0;
00507 
00508         /* and now do it */
00509         if (!do_reg_operation( hkey, buffer, &context, flags ))
00510         {
00511             if (hkey != root_key) RegCloseKey( hkey );
00512             if (sd) LocalFree( sd );
00513             return FALSE;
00514         }
00515         if (hkey != root_key) RegCloseKey( hkey );
00516     }
00517     if (sd) LocalFree( sd );
00518     return TRUE;
00519 }
00520 
00521 
00522 /***********************************************************************
00523  *            do_register_dll
00524  *
00525  * Register or unregister a dll.
00526  */
00527 static BOOL do_register_dll( const struct register_dll_info *info, const WCHAR *path,
00528                              INT flags, INT timeout, const WCHAR *args )
00529 {
00530     HMODULE module;
00531     HRESULT res;
00532     SP_REGISTER_CONTROL_STATUSW status;
00533 #ifdef __WINESRC__
00534     IMAGE_NT_HEADERS *nt;
00535 #endif
00536 
00537     status.cbSize = sizeof(status);
00538     status.FileName = path;
00539     status.FailureCode = SPREG_SUCCESS;
00540     status.Win32Error = ERROR_SUCCESS;
00541 
00542     if (info->callback)
00543     {
00544         switch(info->callback( info->callback_context, SPFILENOTIFY_STARTREGISTRATION,
00545                                (UINT_PTR)&status, !info->unregister ))
00546         {
00547         case FILEOP_ABORT:
00548             SetLastError( ERROR_OPERATION_ABORTED );
00549             return FALSE;
00550         case FILEOP_SKIP:
00551             return TRUE;
00552         case FILEOP_DOIT:
00553             break;
00554         }
00555     }
00556 
00557     if (!(module = LoadLibraryExW( path, 0, LOAD_WITH_ALTERED_SEARCH_PATH )))
00558     {
00559         WARN( "could not load %s\n", debugstr_w(path) );
00560         status.FailureCode = SPREG_LOADLIBRARY;
00561         status.Win32Error = GetLastError();
00562         goto done;
00563     }
00564 
00565 #ifdef __WINESRC__
00566     if ((nt = RtlImageNtHeader( module )) && !(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
00567     {
00568         /* file is an executable, not a dll */
00569         STARTUPINFOW startup;
00570         PROCESS_INFORMATION info;
00571         WCHAR *cmd_line;
00572         BOOL res;
00573         static const WCHAR format[] = {'"','%','s','"',' ','%','s',0};
00574         static const WCHAR default_args[] = {'/','R','e','g','S','e','r','v','e','r',0};
00575 
00576         FreeLibrary( module );
00577         module = NULL;
00578         if (!args) args = default_args;
00579         cmd_line = HeapAlloc( GetProcessHeap(), 0, (strlenW(path) + strlenW(args) + 4) * sizeof(WCHAR) );
00580         sprintfW( cmd_line, format, path, args );
00581         memset( &startup, 0, sizeof(startup) );
00582         startup.cb = sizeof(startup);
00583         TRACE( "executing %s\n", debugstr_w(cmd_line) );
00584         res = CreateProcessW( NULL, cmd_line, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info );
00585         HeapFree( GetProcessHeap(), 0, cmd_line );
00586         if (!res)
00587         {
00588             status.FailureCode = SPREG_LOADLIBRARY;
00589             status.Win32Error = GetLastError();
00590             goto done;
00591         }
00592         CloseHandle( info.hThread );
00593 
00594         if (WaitForSingleObject( info.hProcess, timeout*1000 ) == WAIT_TIMEOUT)
00595         {
00596             /* timed out, kill the process */
00597             TerminateProcess( info.hProcess, 1 );
00598             status.FailureCode = SPREG_TIMEOUT;
00599             status.Win32Error = ERROR_TIMEOUT;
00600         }
00601         CloseHandle( info.hProcess );
00602         goto done;
00603     }
00604 #endif // __WINESRC__
00605 
00606     if (flags & FLG_REGSVR_DLLREGISTER)
00607     {
00608         const char *entry_point = info->unregister ? "DllUnregisterServer" : "DllRegisterServer";
00609         HRESULT (WINAPI *func)(void) = (void *)GetProcAddress( module, entry_point );
00610 
00611         if (!func)
00612         {
00613             status.FailureCode = SPREG_GETPROCADDR;
00614             status.Win32Error = GetLastError();
00615             goto done;
00616         }
00617 
00618         TRACE( "calling %s in %s\n", entry_point, debugstr_w(path) );
00619         res = func();
00620 
00621         if (FAILED(res))
00622         {
00623             WARN( "calling %s in %s returned error %x\n", entry_point, debugstr_w(path), res );
00624             status.FailureCode = SPREG_REGSVR;
00625             status.Win32Error = res;
00626             goto done;
00627         }
00628     }
00629 
00630     if (flags & FLG_REGSVR_DLLINSTALL)
00631     {
00632         HRESULT (WINAPI *func)(BOOL,LPCWSTR) = (void *)GetProcAddress( module, "DllInstall" );
00633 
00634         if (!func)
00635         {
00636             status.FailureCode = SPREG_GETPROCADDR;
00637             status.Win32Error = GetLastError();
00638             goto done;
00639         }
00640 
00641         TRACE( "calling DllInstall(%d,%s) in %s\n",
00642                !info->unregister, debugstr_w(args), debugstr_w(path) );
00643         res = func( !info->unregister, args );
00644 
00645         if (FAILED(res))
00646         {
00647             WARN( "calling DllInstall in %s returned error %x\n", debugstr_w(path), res );
00648             status.FailureCode = SPREG_REGSVR;
00649             status.Win32Error = res;
00650             goto done;
00651         }
00652     }
00653 
00654 done:
00655     if (module) FreeLibrary( module );
00656     if (info->callback) info->callback( info->callback_context, SPFILENOTIFY_ENDREGISTRATION,
00657                                         (UINT_PTR)&status, !info->unregister );
00658     return TRUE;
00659 }
00660 
00661 
00662 /***********************************************************************
00663  *            register_dlls_callback
00664  *
00665  * Called once for each RegisterDlls entry in a given section.
00666  */
00667 static BOOL register_dlls_callback( HINF hinf, PCWSTR field, void *arg )
00668 {
00669     struct register_dll_info *info = arg;
00670     INFCONTEXT context;
00671     BOOL ret = TRUE;
00672     BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
00673 
00674     for (; ok; ok = SetupFindNextLine( &context, &context ))
00675     {
00676         WCHAR *path, *args, *p;
00677         WCHAR buffer[MAX_INF_STRING_LENGTH];
00678         INT flags, timeout;
00679 
00680         /* get directory */
00681         if (!(path = PARSER_get_dest_dir( &context ))) continue;
00682 
00683         /* get dll name */
00684         if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
00685             goto done;
00686         if (!(p = HeapReAlloc( GetProcessHeap(), 0, path,
00687                                (strlenW(path) + strlenW(buffer) + 2) * sizeof(WCHAR) ))) goto done;
00688         path = p;
00689         p += strlenW(p);
00690         if (p == path || p[-1] != '\\') *p++ = '\\';
00691         strcpyW( p, buffer );
00692 
00693         /* get flags */
00694         if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
00695 
00696         /* get timeout */
00697         if (!SetupGetIntField( &context, 5, &timeout )) timeout = 60;
00698 
00699         /* get command line */
00700         args = NULL;
00701         if (SetupGetStringFieldW( &context, 6, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
00702             args = buffer;
00703 
00704         ret = do_register_dll( info, path, flags, timeout, args );
00705 
00706     done:
00707         HeapFree( GetProcessHeap(), 0, path );
00708         if (!ret) break;
00709     }
00710     return ret;
00711 }
00712 
00713 #ifdef __WINESRC__
00714 /***********************************************************************
00715  *            fake_dlls_callback
00716  *
00717  * Called once for each WineFakeDlls entry in a given section.
00718  */
00719 static BOOL fake_dlls_callback( HINF hinf, PCWSTR field, void *arg )
00720 {
00721     INFCONTEXT context;
00722     BOOL ret = TRUE;
00723     BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
00724 
00725     for (; ok; ok = SetupFindNextLine( &context, &context ))
00726     {
00727         WCHAR *path, *p;
00728         WCHAR buffer[MAX_INF_STRING_LENGTH];
00729 
00730         /* get directory */
00731         if (!(path = PARSER_get_dest_dir( &context ))) continue;
00732 
00733         /* get dll name */
00734         if (!SetupGetStringFieldW( &context, 3, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
00735             goto done;
00736         if (!(p = HeapReAlloc( GetProcessHeap(), 0, path,
00737                                (strlenW(path) + strlenW(buffer) + 2) * sizeof(WCHAR) ))) goto done;
00738         path = p;
00739         p += strlenW(p);
00740         if (p == path || p[-1] != '\\') *p++ = '\\';
00741         strcpyW( p, buffer );
00742 
00743         /* get source dll */
00744         if (SetupGetStringFieldW( &context, 4, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
00745             p = buffer;  /* otherwise use target base name as default source */
00746 
00747         create_fake_dll( path, p );  /* ignore errors */
00748 
00749     done:
00750         HeapFree( GetProcessHeap(), 0, path );
00751         if (!ret) break;
00752     }
00753     return ret;
00754 }
00755 #endif // __WINESRC__
00756 
00757 /***********************************************************************
00758  *            update_ini_callback
00759  *
00760  * Called once for each UpdateInis entry in a given section.
00761  */
00762 static BOOL update_ini_callback( HINF hinf, PCWSTR field, void *arg )
00763 {
00764     INFCONTEXT context;
00765 
00766     BOOL ok = SetupFindFirstLineW( hinf, field, NULL, &context );
00767 
00768     for (; ok; ok = SetupFindNextLine( &context, &context ))
00769     {
00770         WCHAR buffer[MAX_INF_STRING_LENGTH];
00771         WCHAR  filename[MAX_INF_STRING_LENGTH];
00772         WCHAR  section[MAX_INF_STRING_LENGTH];
00773         WCHAR  entry[MAX_INF_STRING_LENGTH];
00774         WCHAR  string[MAX_INF_STRING_LENGTH];
00775         LPWSTR divider;
00776 
00777         if (!SetupGetStringFieldW( &context, 1, filename,
00778                                    sizeof(filename)/sizeof(WCHAR), NULL ))
00779             continue;
00780 
00781         if (!SetupGetStringFieldW( &context, 2, section,
00782                                    sizeof(section)/sizeof(WCHAR), NULL ))
00783             continue;
00784 
00785         if (!SetupGetStringFieldW( &context, 4, buffer,
00786                                    sizeof(buffer)/sizeof(WCHAR), NULL ))
00787             continue;
00788 
00789         divider = strchrW(buffer,'=');
00790         if (divider)
00791         {
00792             *divider = 0;
00793             strcpyW(entry,buffer);
00794             divider++;
00795             strcpyW(string,divider);
00796         }
00797         else
00798         {
00799             strcpyW(entry,buffer);
00800             string[0]=0;
00801         }
00802 
00803         TRACE("Writing %s = %s in %s of file %s\n",debugstr_w(entry),
00804                debugstr_w(string),debugstr_w(section),debugstr_w(filename));
00805         WritePrivateProfileStringW(section,entry,string,filename);
00806 
00807     }
00808     return TRUE;
00809 }
00810 
00811 static BOOL update_ini_fields_callback( HINF hinf, PCWSTR field, void *arg )
00812 {
00813     FIXME( "should update ini fields %s\n", debugstr_w(field) );
00814     return TRUE;
00815 }
00816 
00817 static BOOL ini2reg_callback( HINF hinf, PCWSTR field, void *arg )
00818 {
00819     FIXME( "should do ini2reg %s\n", debugstr_w(field) );
00820     return TRUE;
00821 }
00822 
00823 static BOOL logconf_callback( HINF hinf, PCWSTR field, void *arg )
00824 {
00825     FIXME( "should do logconf %s\n", debugstr_w(field) );
00826     return TRUE;
00827 }
00828 
00829 static BOOL bitreg_callback( HINF hinf, PCWSTR field, void *arg )
00830 {
00831     FIXME( "should do bitreg %s\n", debugstr_w(field) );
00832     return TRUE;
00833 }
00834 
00835 static BOOL Concatenate(int DirId, LPCWSTR SubDirPart, LPCWSTR NamePart, LPWSTR *pFullName)
00836 {
00837     DWORD dwRequired = 0;
00838     LPCWSTR Dir;
00839     LPWSTR FullName;
00840 
00841     *pFullName = NULL;
00842 
00843     Dir = DIRID_get_string(DirId);
00844     if (Dir)
00845         dwRequired += wcslen(Dir) + 1;
00846     if (SubDirPart)
00847         dwRequired += wcslen(SubDirPart) + 1;
00848     if (NamePart)
00849         dwRequired += wcslen(NamePart);
00850     dwRequired = dwRequired * sizeof(WCHAR) + sizeof(UNICODE_NULL);
00851 
00852     FullName = MyMalloc(dwRequired);
00853     if (!FullName)
00854     {
00855         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
00856         return FALSE;
00857     }
00858     FullName[0] = UNICODE_NULL;
00859 
00860     if (Dir)
00861     {
00862         wcscat(FullName, Dir);
00863         if (FullName[wcslen(FullName) - 1] != '\\')
00864             wcscat(FullName, BackSlash);
00865     }
00866     if (SubDirPart)
00867     {
00868         wcscat(FullName, SubDirPart);
00869         if (FullName[wcslen(FullName) - 1] != '\\')
00870             wcscat(FullName, BackSlash);
00871     }
00872     if (NamePart)
00873         wcscat(FullName, NamePart);
00874 
00875     *pFullName = FullName;
00876     return TRUE;
00877 }
00878 
00879 /***********************************************************************
00880  *            profile_items_callback
00881  *
00882  * Called once for each ProfileItems entry in a given section.
00883  */
00884 static BOOL
00885 profile_items_callback(
00886     IN HINF hInf,
00887     IN PCWSTR SectionName,
00888     IN PVOID Arg)
00889 {
00890     INFCONTEXT Context;
00891     LPWSTR LinkSubDir = NULL, LinkName = NULL;
00892     INT LinkAttributes = 0;
00893     INT LinkFolder = 0;
00894     INT FileDirId = 0;
00895     INT CSIDL = CSIDL_COMMON_PROGRAMS;
00896     LPWSTR FileSubDir = NULL;
00897     INT DirId = 0;
00898     LPWSTR SubDirPart = NULL, NamePart = NULL;
00899     LPWSTR FullLinkName = NULL, FullFileName = NULL, FullWorkingDir = NULL, FullIconName = NULL;
00900     INT IconIdx = 0;
00901     LPWSTR lpHotKey = NULL, lpInfoTip = NULL;
00902     LPWSTR DisplayName = NULL;
00903     INT DisplayResId = 0;
00904     BOOL ret = FALSE;
00905     DWORD Index, Required;
00906 
00907     IShellLinkW *psl;
00908     IPersistFile *ppf;
00909     HMODULE hOle32 = NULL;
00910     COINITIALIZE pCoInitialize;
00911     COCREATEINSTANCE pCoCreateInstance;
00912     COUNINITIALIZE pCoUninitialize;
00913     HRESULT hr;
00914 
00915     TRACE("hInf %p, SectionName %s, Arg %p\n",
00916         hInf, debugstr_w(SectionName), Arg);
00917 
00918     /* Read 'Name' entry */
00919     if (!SetupFindFirstLineW(hInf, SectionName, Name, &Context))
00920         goto cleanup;
00921     if (!GetStringField(&Context, 1, &LinkName))
00922         goto cleanup;
00923     if (SetupGetFieldCount(&Context) >= 2)
00924     {
00925         if (!SetupGetIntField(&Context, 2, &LinkAttributes))
00926             goto cleanup;
00927     }
00928     if (SetupGetFieldCount(&Context) >= 3)
00929     {
00930         if (!SetupGetIntField(&Context, 3, &LinkFolder))
00931             goto cleanup;
00932     }
00933 
00934     /* Read 'CmdLine' entry */
00935     if (!SetupFindFirstLineW(hInf, SectionName, CmdLine, &Context))
00936         goto cleanup;
00937     Index = 1;
00938     if (!SetupGetIntField(&Context, Index++, &FileDirId))
00939         goto cleanup;
00940     if (SetupGetFieldCount(&Context) >= 3)
00941     {
00942         if (!GetStringField(&Context, Index++, &FileSubDir))
00943             goto cleanup;
00944     }
00945     if (!GetStringField(&Context, Index++, &NamePart))
00946         goto cleanup;
00947     if (!Concatenate(FileDirId, FileSubDir, NamePart, &FullFileName))
00948         goto cleanup;
00949     MyFree(NamePart);
00950     NamePart = NULL;
00951 
00952     /* Read 'SubDir' entry */
00953     if ((LinkAttributes & FLG_PROFITEM_GROUP) == 0 && SetupFindFirstLineW(hInf, SectionName, SubDir, &Context))
00954     {
00955         if (!GetStringField(&Context, 1, &LinkSubDir))
00956             goto cleanup;
00957     }
00958 
00959     /* Read 'WorkingDir' entry */
00960     if (SetupFindFirstLineW(hInf, SectionName, WorkingDir, &Context))
00961     {
00962         if (!SetupGetIntField(&Context, 1, &DirId))
00963             goto cleanup;
00964         if (SetupGetFieldCount(&Context) >= 2)
00965         {
00966             if (!GetStringField(&Context, 2, &SubDirPart))
00967                 goto cleanup;
00968         }
00969         if (!Concatenate(DirId, SubDirPart, NULL, &FullWorkingDir))
00970             goto cleanup;
00971         MyFree(SubDirPart);
00972         SubDirPart = NULL;
00973     }
00974     else
00975     {
00976         if (!Concatenate(FileDirId, FileSubDir, NULL, &FullWorkingDir))
00977             goto cleanup;
00978     }
00979 
00980     /* Read 'IconPath' entry */
00981     if (SetupFindFirstLineW(hInf, SectionName, IconPath, &Context))
00982     {
00983         Index = 1;
00984         if (!SetupGetIntField(&Context, Index++, &DirId))
00985             goto cleanup;
00986         if (SetupGetFieldCount(&Context) >= 3)
00987         {
00988             if (!GetStringField(&Context, Index++, &SubDirPart))
00989                 goto cleanup;
00990         }
00991         if (!GetStringField(&Context, Index, &NamePart))
00992             goto cleanup;
00993         if (!Concatenate(DirId, SubDirPart, NamePart, &FullIconName))
00994             goto cleanup;
00995         MyFree(SubDirPart);
00996         MyFree(NamePart);
00997         SubDirPart = NamePart = NULL;
00998     }
00999     else
01000     {
01001         FullIconName = pSetupDuplicateString(FullFileName);
01002         if (!FullIconName)
01003             goto cleanup;
01004     }
01005 
01006     /* Read 'IconIndex' entry */
01007     if (SetupFindFirstLineW(hInf, SectionName, IconIndex, &Context))
01008     {
01009         if (!SetupGetIntField(&Context, 1, &IconIdx))
01010             goto cleanup;
01011     }
01012 
01013     /* Read 'HotKey' and 'InfoTip' entries */
01014     GetLineText(hInf, SectionName, HotKey, &lpHotKey);
01015     GetLineText(hInf, SectionName, InfoTip, &lpInfoTip);
01016 
01017     /* Read 'DisplayResource' entry */
01018     if (SetupFindFirstLineW(hInf, SectionName, DisplayResource, &Context))
01019     {
01020         if (!GetStringField(&Context, 1, &DisplayName))
01021             goto cleanup;
01022         if (!SetupGetIntField(&Context, 2, &DisplayResId))
01023             goto cleanup;
01024     }
01025 
01026     /* Some debug */
01027     TRACE("Link is %s\\%s, attributes 0x%x\n", debugstr_w(LinkSubDir), debugstr_w(LinkName), LinkAttributes);
01028     TRACE("File is %s\n", debugstr_w(FullFileName));
01029     TRACE("Working dir %s\n", debugstr_w(FullWorkingDir));
01030     TRACE("Icon is %s, %d\n", debugstr_w(FullIconName), IconIdx);
01031     TRACE("Hotkey %s\n", debugstr_w(lpHotKey));
01032     TRACE("InfoTip %s\n", debugstr_w(lpInfoTip));
01033     TRACE("Display %s, %d\n", DisplayName, DisplayResId);
01034 
01035     /* Load ole32.dll */
01036     hOle32 = LoadLibraryA("ole32.dll");
01037     if (!hOle32)
01038         goto cleanup;
01039     pCoInitialize = (COINITIALIZE)GetProcAddress(hOle32, "CoInitialize");
01040     if (!pCoInitialize)
01041         goto cleanup;
01042     pCoCreateInstance = (COCREATEINSTANCE)GetProcAddress(hOle32, "CoCreateInstance");
01043     if (!pCoCreateInstance)
01044         goto cleanup;
01045     pCoUninitialize = (COUNINITIALIZE)GetProcAddress(hOle32, "CoUninitialize");
01046     if (!pCoUninitialize)
01047         goto cleanup;
01048 
01049     /* Create shortcut */
01050     hr = pCoInitialize(NULL);
01051     if (!SUCCEEDED(hr))
01052     {
01053         if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
01054             SetLastError(HRESULT_CODE(hr));
01055         else
01056             SetLastError(E_FAIL);
01057         goto cleanup;
01058     }
01059     hr = pCoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&psl);
01060     if (SUCCEEDED(hr))
01061     {
01062         /* Fill link properties */
01063         if (SUCCEEDED(hr))
01064             hr = IShellLinkW_SetPath(psl, FullFileName);
01065         if (SUCCEEDED(hr))
01066             hr = IShellLinkW_SetArguments(psl, L"");
01067         if (SUCCEEDED(hr))
01068             hr = IShellLinkW_SetWorkingDirectory(psl, FullWorkingDir);
01069         if (SUCCEEDED(hr))
01070             hr = IShellLinkW_SetIconLocation(psl, FullIconName, IconIdx);
01071         if (SUCCEEDED(hr) && lpHotKey)
01072             FIXME("Need to store hotkey %s in shell link\n", debugstr_w(lpHotKey));
01073         if (SUCCEEDED(hr) && lpInfoTip)
01074             hr = IShellLinkW_SetDescription(psl, lpInfoTip);
01075         if (SUCCEEDED(hr) && DisplayName)
01076             FIXME("Need to store display name %s, %d in shell link\n", debugstr_w(DisplayName), DisplayResId);
01077         if (SUCCEEDED(hr))
01078         {
01079             hr = IShellLinkW_QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf);
01080             if (SUCCEEDED(hr))
01081             {
01082                 Required = (MAX_PATH + wcslen(LinkSubDir) + 1 + wcslen(LinkName)) * sizeof(WCHAR);
01083                 FullLinkName = MyMalloc(Required);
01084                 if (!FullLinkName)
01085                     hr = E_OUTOFMEMORY;
01086                 else
01087                 {
01088                     if (LinkAttributes & (FLG_PROFITEM_DELETE | FLG_PROFITEM_GROUP))
01089                         FIXME("Need to handle FLG_PROFITEM_DELETE and FLG_PROFITEM_GROUP\n");
01090                     if (LinkAttributes & FLG_PROFITEM_CSIDL)
01091                         CSIDL = LinkFolder;
01092                     else if (LinkAttributes & FLG_PROFITEM_CURRENTUSER)
01093                         CSIDL = CSIDL_PROGRAMS;
01094 
01095                     if (SHGetSpecialFolderPathW(
01096                         NULL,
01097                         FullLinkName,
01098                         CSIDL,
01099                         TRUE))
01100                     {
01101                         if (FullLinkName[wcslen(FullLinkName) - 1] != '\\')
01102                             wcscat(FullLinkName, BackSlash);
01103                         if (LinkSubDir)
01104                         {
01105                             wcscat(FullLinkName, LinkSubDir);
01106                             if (FullLinkName[wcslen(FullLinkName) - 1] != '\\')
01107                                 wcscat(FullLinkName, BackSlash);
01108                         }
01109                         wcscat(FullLinkName, LinkName);
01110                         wcscat(FullLinkName, DotLnk);
01111                         hr = IPersistFile_Save(ppf, FullLinkName, TRUE);
01112                     }
01113                     else
01114                         hr = HRESULT_FROM_WIN32(GetLastError());
01115                 }
01116                 IPersistFile_Release(ppf);
01117             }
01118         }
01119         IShellLinkW_Release(psl);
01120     }
01121     pCoUninitialize();
01122     if (SUCCEEDED(hr))
01123         ret = TRUE;
01124     else
01125     {
01126         if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
01127             SetLastError(HRESULT_CODE(hr));
01128         else
01129             SetLastError(E_FAIL);
01130     }
01131 
01132 cleanup:
01133     MyFree(LinkSubDir);
01134     MyFree(LinkName);
01135     MyFree(FileSubDir);
01136     MyFree(SubDirPart);
01137     MyFree(NamePart);
01138     MyFree(FullFileName);
01139     MyFree(FullWorkingDir);
01140     MyFree(FullIconName);
01141     MyFree(FullLinkName);
01142     MyFree(lpHotKey);
01143     MyFree(lpInfoTip);
01144     MyFree(DisplayName);
01145     if (hOle32)
01146         FreeLibrary(hOle32);
01147 
01148     TRACE("Returning %d\n", ret);
01149     return ret;
01150 }
01151 
01152 static BOOL copy_inf_callback( HINF hinf, PCWSTR field, void *arg )
01153 {
01154     FIXME( "should do copy inf %s\n", debugstr_w(field) );
01155     return TRUE;
01156 }
01157 
01158 
01159 /***********************************************************************
01160  *            iterate_section_fields
01161  *
01162  * Iterate over all fields of a certain key of a certain section
01163  */
01164 static BOOL iterate_section_fields( HINF hinf, PCWSTR section, PCWSTR key,
01165                                     iterate_fields_func callback, void *arg )
01166 {
01167     WCHAR static_buffer[200];
01168     WCHAR *buffer = static_buffer;
01169     DWORD size = sizeof(static_buffer)/sizeof(WCHAR);
01170     INFCONTEXT context;
01171     BOOL ret = FALSE;
01172 
01173     BOOL ok = SetupFindFirstLineW( hinf, section, key, &context );
01174     while (ok)
01175     {
01176         UINT i, count = SetupGetFieldCount( &context );
01177         for (i = 1; i <= count; i++)
01178         {
01179             if (!(buffer = get_field_string( &context, i, buffer, static_buffer, &size )))
01180                 goto done;
01181             if (!callback( hinf, buffer, arg ))
01182             {
01183                 WARN("callback failed for %s %s err %d\n",
01184                      debugstr_w(section), debugstr_w(buffer), GetLastError() );
01185                 goto done;
01186             }
01187         }
01188         ok = SetupFindNextMatchLineW( &context, key, &context );
01189     }
01190     ret = TRUE;
01191  done:
01192     if (buffer != static_buffer) HeapFree( GetProcessHeap(), 0, buffer );
01193     return ret;
01194 }
01195 
01196 
01197 /***********************************************************************
01198  *            SetupInstallFilesFromInfSectionA   (SETUPAPI.@)
01199  */
01200 BOOL WINAPI SetupInstallFilesFromInfSectionA( HINF hinf, HINF hlayout, HSPFILEQ queue,
01201                                               PCSTR section, PCSTR src_root, UINT flags )
01202 {
01203     UNICODE_STRING sectionW;
01204     BOOL ret = FALSE;
01205 
01206     if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
01207     {
01208         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
01209         return FALSE;
01210     }
01211     if (!src_root)
01212         ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
01213                                                 NULL, flags );
01214     else
01215     {
01216         UNICODE_STRING srcW;
01217         if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
01218         {
01219             ret = SetupInstallFilesFromInfSectionW( hinf, hlayout, queue, sectionW.Buffer,
01220                                                     srcW.Buffer, flags );
01221             RtlFreeUnicodeString( &srcW );
01222         }
01223         else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
01224     }
01225     RtlFreeUnicodeString( &sectionW );
01226     return ret;
01227 }
01228 
01229 
01230 /***********************************************************************
01231  *            SetupInstallFilesFromInfSectionW   (SETUPAPI.@)
01232  */
01233 BOOL WINAPI SetupInstallFilesFromInfSectionW( HINF hinf, HINF hlayout, HSPFILEQ queue,
01234                                               PCWSTR section, PCWSTR src_root, UINT flags )
01235 {
01236     struct files_callback_info info;
01237 
01238     info.queue      = queue;
01239     info.src_root   = src_root;
01240     info.copy_flags = flags;
01241     info.layout     = hlayout;
01242     return iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info );
01243 }
01244 
01245 
01246 /***********************************************************************
01247  *            SetupInstallFromInfSectionA   (SETUPAPI.@)
01248  */
01249 BOOL WINAPI SetupInstallFromInfSectionA( HWND owner, HINF hinf, PCSTR section, UINT flags,
01250                                          HKEY key_root, PCSTR src_root, UINT copy_flags,
01251                                          PSP_FILE_CALLBACK_A callback, PVOID context,
01252                                          HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
01253 {
01254     UNICODE_STRING sectionW, src_rootW;
01255     struct callback_WtoA_context ctx;
01256     BOOL ret = FALSE;
01257 
01258     src_rootW.Buffer = NULL;
01259     if (src_root && !RtlCreateUnicodeStringFromAsciiz( &src_rootW, src_root ))
01260     {
01261         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
01262         return FALSE;
01263     }
01264 
01265     if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
01266     {
01267         ctx.orig_context = context;
01268         ctx.orig_handler = callback;
01269         ret = SetupInstallFromInfSectionW( owner, hinf, sectionW.Buffer, flags, key_root,
01270                                            src_rootW.Buffer, copy_flags, QUEUE_callback_WtoA,
01271                                            &ctx, devinfo, devinfo_data );
01272         RtlFreeUnicodeString( &sectionW );
01273     }
01274     else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
01275 
01276     RtlFreeUnicodeString( &src_rootW );
01277     return ret;
01278 }
01279 
01280 
01281 /***********************************************************************
01282  *            include_callback
01283  *
01284  * Called once for each Include entry in a given section.
01285  */
01286 static BOOL include_callback( HINF hinf, PCWSTR field, void *arg )
01287 {
01288     return SetupOpenAppendInfFileW( field, hinf, NULL );
01289 }
01290 
01291 
01292 /***********************************************************************
01293  *            needs_callback
01294  *
01295  * Called once for each Needs entry in a given section.
01296  */
01297 static BOOL needs_callback( HINF hinf, PCWSTR field, void *arg )
01298 {
01299     struct needs_callback_info *info = arg;
01300 
01301     switch (info->type)
01302     {
01303         case 0:
01304             return SetupInstallFromInfSectionW(info->owner, *(HINF*)hinf, field, info->flags,
01305                info->key_root, info->src_root, info->copy_flags, info->callback,
01306                info->context, info->devinfo, info->devinfo_data);
01307         case 1:
01308             return SetupInstallServicesFromInfSectionExW(*(HINF*)hinf, field, info->flags,
01309                 info->devinfo, info->devinfo_data, info->reserved1, info->reserved2);
01310         default:
01311             ERR("Unknown info type %u\n", info->type);
01312             return FALSE;
01313     }
01314 }
01315 
01316 
01317 /***********************************************************************
01318  *            SetupInstallFromInfSectionW   (SETUPAPI.@)
01319  */
01320 BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section, UINT flags,
01321                                          HKEY key_root, PCWSTR src_root, UINT copy_flags,
01322                                          PSP_FILE_CALLBACK_W callback, PVOID context,
01323                                          HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data )
01324 {
01325     struct needs_callback_info needs_info;
01326 
01327     /* Parse 'Include' and 'Needs' directives */
01328     iterate_section_fields( hinf, section, Include, include_callback, NULL);
01329     needs_info.type = 0;
01330     needs_info.owner = owner;
01331     needs_info.flags = flags;
01332     needs_info.key_root = key_root;
01333     needs_info.src_root = src_root;
01334     needs_info.copy_flags = copy_flags;
01335     needs_info.callback = callback;
01336     needs_info.context = context;
01337     needs_info.devinfo = devinfo;
01338     needs_info.devinfo_data = devinfo_data;
01339     iterate_section_fields( hinf, section, Needs, needs_callback, &needs_info);
01340 
01341     if (flags & SPINST_FILES)
01342     {
01343         SP_DEVINSTALL_PARAMS_W install_params;
01344         struct files_callback_info info;
01345         HSPFILEQ queue = NULL;
01346         BOOL use_custom_queue;
01347         BOOL ret;
01348 
01349         install_params.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
01350         use_custom_queue = SetupDiGetDeviceInstallParamsW(devinfo, devinfo_data, &install_params) && (install_params.Flags & DI_NOVCP);
01351         if (!use_custom_queue && ((queue = SetupOpenFileQueue()) == (HSPFILEQ)INVALID_HANDLE_VALUE ))
01352             return FALSE;
01353         info.queue      = use_custom_queue ? install_params.FileQueue : queue;
01354         info.src_root   = src_root;
01355         info.copy_flags = copy_flags;
01356         info.layout     = hinf;
01357         ret = (iterate_section_fields( hinf, section, CopyFiles, copy_files_callback, &info ) &&
01358                iterate_section_fields( hinf, section, DelFiles, delete_files_callback, &info ) &&
01359                iterate_section_fields( hinf, section, RenFiles, rename_files_callback, &info ));
01360         if (!use_custom_queue)
01361         {
01362             if (ret)
01363                 ret = SetupCommitFileQueueW( owner, queue, callback, context );
01364             SetupCloseFileQueue( queue );
01365         }
01366         if (!ret) return FALSE;
01367     }
01368     if (flags & SPINST_INIFILES)
01369     {
01370         if (!iterate_section_fields( hinf, section, UpdateInis, update_ini_callback, NULL ) ||
01371             !iterate_section_fields( hinf, section, UpdateIniFields,
01372                                      update_ini_fields_callback, NULL ))
01373             return FALSE;
01374     }
01375     if (flags & SPINST_INI2REG)
01376     {
01377         if (!iterate_section_fields( hinf, section, Ini2Reg, ini2reg_callback, NULL ))
01378             return FALSE;
01379     }
01380     if (flags & SPINST_LOGCONFIG)
01381     {
01382         if (!iterate_section_fields( hinf, section, LogConf, logconf_callback, NULL ))
01383             return FALSE;
01384     }
01385     if (flags & SPINST_REGSVR)
01386     {
01387         struct register_dll_info info;
01388 
01389         info.unregister = FALSE;
01390         if (flags & SPINST_REGISTERCALLBACKAWARE)
01391         {
01392             info.callback         = callback;
01393             info.callback_context = context;
01394         }
01395         else info.callback = NULL;
01396 
01397         if (!iterate_section_fields( hinf, section, RegisterDlls, register_dlls_callback, &info ))
01398             return FALSE;
01399 
01400 #ifdef __WINESRC__
01401         if (!iterate_section_fields( hinf, section, WineFakeDlls, fake_dlls_callback, NULL ))
01402             return FALSE;
01403 #endif // __WINESRC__
01404     }
01405     if (flags & SPINST_UNREGSVR)
01406     {
01407         struct register_dll_info info;
01408 
01409         info.unregister = TRUE;
01410         if (flags & SPINST_REGISTERCALLBACKAWARE)
01411         {
01412             info.callback         = callback;
01413             info.callback_context = context;
01414         }
01415         else info.callback = NULL;
01416 
01417         if (!iterate_section_fields( hinf, section, UnregisterDlls, register_dlls_callback, &info ))
01418             return FALSE;
01419     }
01420     if (flags & SPINST_REGISTRY)
01421     {
01422         struct registry_callback_info info;
01423 
01424         info.default_root = key_root;
01425         info.delete = TRUE;
01426         if (!iterate_section_fields( hinf, section, DelReg, registry_callback, &info ))
01427             return FALSE;
01428         info.delete = FALSE;
01429         if (!iterate_section_fields( hinf, section, AddReg, registry_callback, &info ))
01430             return FALSE;
01431     }
01432     if (flags & SPINST_BITREG)
01433     {
01434         if (!iterate_section_fields( hinf, section, BitReg, bitreg_callback, NULL ))
01435             return FALSE;
01436     }
01437     if (flags & SPINST_PROFILEITEMS)
01438     {
01439         if (!iterate_section_fields( hinf, section, ProfileItems, profile_items_callback, NULL ))
01440             return FALSE;
01441     }
01442     if (flags & SPINST_COPYINF)
01443     {
01444         if (!iterate_section_fields( hinf, section, CopyINF, copy_inf_callback, NULL ))
01445             return FALSE;
01446     }
01447 
01448     return TRUE;
01449 }
01450 
01451 
01452 /***********************************************************************
01453  *      InstallHinfSectionW  (SETUPAPI.@)
01454  *
01455  * NOTE: 'cmdline' is <section> <mode> <path> from
01456  *   RUNDLL32.EXE SETUPAPI.DLL,InstallHinfSection <section> <mode> <path>
01457  */
01458 void WINAPI InstallHinfSectionW( HWND hwnd, HINSTANCE handle, LPCWSTR cmdline, INT show )
01459 {
01460     WCHAR *s, *path, section[MAX_PATH];
01461     void *callback_context = NULL;
01462     DWORD SectionNameLength;
01463     UINT mode;
01464     HINF hinf = INVALID_HANDLE_VALUE;
01465     BOOL bRebootRequired = FALSE;
01466     BOOL ret;
01467 
01468     TRACE("hwnd %p, handle %p, cmdline %s\n", hwnd, handle, debugstr_w(cmdline));
01469 
01470     lstrcpynW( section, cmdline, MAX_PATH );
01471 
01472     if (!(s = strchrW( section, ' ' ))) return;
01473     *s++ = 0;
01474     while (*s == ' ') s++;
01475     mode = atoiW( s );
01476 
01477     /* quoted paths are not allowed on native, the rest of the command line is taken as the path */
01478     if (!(s = strchrW( s, ' ' ))) return;
01479     while (*s == ' ') s++;
01480     path = s;
01481 
01482     if (mode & 0x80)
01483     {
01484         FIXME("default path of the installation not changed\n");
01485         mode &= ~0x80;
01486     }
01487 
01488     hinf = SetupOpenInfFileW( path, NULL, INF_STYLE_WIN4, NULL );
01489     if (hinf == INVALID_HANDLE_VALUE)
01490     {
01491         WARN("SetupOpenInfFileW(%s) failed (Error %u)\n", path, GetLastError());
01492         goto cleanup;
01493     }
01494 
01495     ret = SetupDiGetActualSectionToInstallW(
01496        hinf, section, section, sizeof(section)/sizeof(section[0]), &SectionNameLength, NULL );
01497     if (!ret)
01498     {
01499         WARN("SetupDiGetActualSectionToInstallW() failed (Error %u)\n", GetLastError());
01500         goto cleanup;
01501     }
01502     if (SectionNameLength > MAX_PATH - strlenW(DotServices))
01503     {
01504         WARN("Section name '%s' too long\n", section);
01505         goto cleanup;
01506     }
01507 
01508     /* Copy files and add registry entries */
01509     callback_context = SetupInitDefaultQueueCallback( hwnd );
01510     ret = SetupInstallFromInfSectionW( hwnd, hinf, section, SPINST_ALL, NULL, NULL,
01511                                        SP_COPY_NEWER | SP_COPY_IN_USE_NEEDS_REBOOT,
01512                                        SetupDefaultQueueCallbackW, callback_context,
01513                                        NULL, NULL );
01514     if (!ret)
01515     {
01516         WARN("SetupInstallFromInfSectionW() failed (Error %u)\n", GetLastError());
01517         goto cleanup;
01518     }
01519     /* FIXME: need to check if some files were in use and need reboot
01520      * bReboot = ...;
01521      */
01522 
01523     /* Install services */
01524     wcscat(section, DotServices);
01525     ret = SetupInstallServicesFromInfSectionW( hinf, section, 0 );
01526     if (!ret && GetLastError() == ERROR_SECTION_NOT_FOUND)
01527         ret = TRUE;
01528     if (!ret)
01529     {
01530         WARN("SetupInstallServicesFromInfSectionW() failed (Error %u)\n", GetLastError());
01531         goto cleanup;
01532     }
01533     else if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED)
01534     {
01535         bRebootRequired = TRUE;
01536     }
01537 
01538     /* Check if we need to reboot */
01539     switch (mode)
01540     {
01541         case 0:
01542             /* Never reboot */
01543             break;
01544         case 1:
01545             /* Always reboot */
01546             ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_APPLICATION |
01547                 SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED);
01548             break;
01549         case 2:
01550             /* Query user before rebooting */
01551             SetupPromptReboot(NULL, hwnd, FALSE);
01552             break;
01553         case 3:
01554             /* Reboot if necessary */
01555             if (bRebootRequired)
01556             {
01557                 ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_APPLICATION |
01558                     SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED);
01559             }
01560             break;
01561         case 4:
01562             /* If necessary, query user before rebooting */
01563             if (bRebootRequired)
01564             {
01565                 SetupPromptReboot(NULL, hwnd, FALSE);
01566             }
01567             break;
01568         default:
01569             break;
01570     }
01571 
01572 cleanup:
01573     if ( callback_context )
01574         SetupTermDefaultQueueCallback( callback_context );
01575     if ( hinf != INVALID_HANDLE_VALUE )
01576         SetupCloseInfFile( hinf );
01577 }
01578 
01579 
01580 /***********************************************************************
01581  *      InstallHinfSectionA  (SETUPAPI.@)
01582  */
01583 void WINAPI InstallHinfSectionA( HWND hwnd, HINSTANCE handle, LPCSTR cmdline, INT show )
01584 {
01585     UNICODE_STRING cmdlineW;
01586 
01587     if (RtlCreateUnicodeStringFromAsciiz( &cmdlineW, cmdline ))
01588     {
01589         InstallHinfSectionW( hwnd, handle, cmdlineW.Buffer, show );
01590         RtlFreeUnicodeString( &cmdlineW );
01591     }
01592 }
01593 
01594 /***********************************************************************
01595  *              SetupInstallServicesFromInfSectionW  (SETUPAPI.@)
01596  */
01597 BOOL WINAPI SetupInstallServicesFromInfSectionW( HINF Inf, PCWSTR SectionName, DWORD Flags)
01598 {
01599     return SetupInstallServicesFromInfSectionExW( Inf, SectionName, Flags,
01600                                                   NULL, NULL, NULL, NULL );
01601 }
01602 
01603 /***********************************************************************
01604  *              SetupInstallServicesFromInfSectionA  (SETUPAPI.@)
01605  */
01606 BOOL WINAPI SetupInstallServicesFromInfSectionA( HINF Inf, PCSTR SectionName, DWORD Flags)
01607 {
01608     return SetupInstallServicesFromInfSectionExA( Inf, SectionName, Flags,
01609                                                   NULL, NULL, NULL, NULL );
01610 }
01611 
01612 /***********************************************************************
01613  *      SetupInstallServicesFromInfSectionExA  (SETUPAPI.@)
01614  */
01615 BOOL WINAPI SetupInstallServicesFromInfSectionExA( HINF hinf, PCSTR sectionname, DWORD flags, HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data, PVOID reserved1, PVOID reserved2 )
01616 {
01617     UNICODE_STRING sectionnameW;
01618     BOOL ret = FALSE;
01619 
01620     if (RtlCreateUnicodeStringFromAsciiz( &sectionnameW, sectionname ))
01621     {
01622         ret = SetupInstallServicesFromInfSectionExW( hinf, sectionnameW.Buffer, flags, devinfo, devinfo_data, reserved1, reserved2 );
01623         RtlFreeUnicodeString( &sectionnameW );
01624     }
01625     else
01626         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
01627 
01628     return ret;
01629 }
01630 
01631 
01632 static BOOL GetLineText( HINF hinf, PCWSTR section_name, PCWSTR key_name, PWSTR *value)
01633 {
01634     DWORD required;
01635     PWSTR buf = NULL;
01636 
01637     *value = NULL;
01638 
01639     if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, NULL, 0, &required )
01640         && GetLastError() != ERROR_INSUFFICIENT_BUFFER )
01641         return FALSE;
01642 
01643     buf = HeapAlloc( GetProcessHeap(), 0, required * sizeof(WCHAR) );
01644     if ( ! buf )
01645     {
01646         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
01647         return FALSE;
01648     }
01649 
01650     if (! SetupGetLineTextW( NULL, hinf, section_name, key_name, buf, required, &required ) )
01651     {
01652         HeapFree( GetProcessHeap(), 0, buf );
01653         return FALSE;
01654     }
01655 
01656     *value = buf;
01657     return TRUE;
01658 }
01659 
01660 
01661 static BOOL GetIntField( HINF hinf, PCWSTR section_name, PCWSTR key_name, INT *value)
01662 {
01663     LPWSTR buffer, end;
01664     INT res;
01665 
01666     if (! GetLineText( hinf, section_name, key_name, &buffer ) )
01667         return FALSE;
01668 
01669     res = wcstol( buffer, &end, 0 );
01670     if (end != buffer && !*end)
01671     {
01672         HeapFree(GetProcessHeap(), 0, buffer);
01673         *value = res;
01674         return TRUE;
01675     }
01676     else
01677     {
01678         HeapFree(GetProcessHeap(), 0, buffer);
01679         SetLastError( ERROR_INVALID_DATA );
01680         return FALSE;
01681     }
01682 }
01683 
01684 
01685 BOOL GetStringField( PINFCONTEXT context, DWORD index, PWSTR *value)
01686 {
01687     DWORD RequiredSize;
01688     BOOL ret;
01689 
01690     ret = SetupGetStringFieldW(
01691         context,
01692         index,
01693         NULL, 0,
01694         &RequiredSize);
01695     if (!ret)
01696         return FALSE;
01697     else if (RequiredSize == 0)
01698     {
01699         *value = NULL;
01700         return TRUE;
01701     }
01702 
01703     /* We got the needed size for the buffer */
01704     *value = MyMalloc(RequiredSize * sizeof(WCHAR));
01705     if (!*value)
01706     {
01707         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
01708         return FALSE;
01709     }
01710     ret = SetupGetStringFieldW(
01711         context,
01712         index,
01713         *value, RequiredSize, NULL);
01714     if (!ret)
01715         MyFree(*value);
01716 
01717     return ret;
01718 }
01719 
01720 static VOID FixupServiceBinaryPath(
01721     IN DWORD ServiceType,
01722     IN OUT LPWSTR *ServiceBinary)
01723 {
01724     LPWSTR Buffer;
01725     WCHAR ReactosDir[MAX_PATH];
01726     DWORD RosDirLength, ServiceLength, Win32Length;
01727 
01728     GetWindowsDirectoryW(ReactosDir, MAX_PATH);
01729     RosDirLength = strlenW(ReactosDir);
01730     ServiceLength = strlenW(*ServiceBinary);
01731 
01732     /* Check and fix two things:
01733        1. Get rid of C:\ReactOS and use relative
01734           path instead.
01735        2. Add %SystemRoot% for Win32 services */
01736 
01737     if (ServiceLength < RosDirLength)
01738         return;
01739 
01740     if (!wcsnicmp(*ServiceBinary, ReactosDir, RosDirLength))
01741     {
01742         /* Yes, the first part is the C:\ReactOS\, just skip it */
01743         MoveMemory(*ServiceBinary, *ServiceBinary + RosDirLength + 1,
01744             (ServiceLength - RosDirLength) * sizeof(WCHAR));
01745 
01746         /* Handle Win32-services differently */
01747         if (ServiceType & SERVICE_WIN32)
01748         {
01749             Win32Length = (ServiceLength -
01750                 RosDirLength - 1 + 13) * sizeof(WCHAR);
01751             /* -1 to not count the separator after C:\ReactOS
01752                wcslen(L"%SystemRoot%\\") = 13*sizeof(wchar_t) */
01753             Buffer = MyMalloc(Win32Length);
01754 
01755             wcscpy(Buffer, L"%SystemRoot%\\");
01756             wcscat(Buffer, *ServiceBinary);
01757             MyFree(*ServiceBinary);
01758 
01759             *ServiceBinary = Buffer;
01760         }
01761     }
01762 }
01763 
01764 static BOOL InstallOneService(
01765     struct DeviceInfoSet *list,
01766     IN HINF hInf,
01767     IN LPCWSTR ServiceSection,
01768     IN LPCWSTR ServiceName,
01769     IN UINT ServiceFlags)
01770 {
01771     SC_HANDLE hSCManager = NULL;
01772     SC_HANDLE hService = NULL;
01773     LPDWORD GroupOrder = NULL;
01774     LPQUERY_SERVICE_CONFIGW ServiceConfig = NULL;
01775     HKEY hServicesKey, hServiceKey;
01776     LONG rc;
01777     BOOL ret = FALSE;
01778 
01779     HKEY hGroupOrderListKey = NULL;
01780     LPWSTR ServiceBinary = NULL;
01781     LPWSTR LoadOrderGroup = NULL;
01782     LPWSTR DisplayName = NULL;
01783     LPWSTR Description = NULL;
01784     LPWSTR Dependencies = NULL;
01785     LPWSTR SecurityDescriptor = NULL;
01786     PSECURITY_DESCRIPTOR sd = NULL;
01787     INT ServiceType, StartType, ErrorControl;
01788     DWORD dwRegType;
01789     DWORD tagId = (DWORD)-1;
01790     BOOL useTag;
01791 
01792     if (!GetIntField(hInf, ServiceSection, ServiceTypeKey, &ServiceType))
01793         goto cleanup;
01794     if (!GetIntField(hInf, ServiceSection, StartTypeKey, &StartType))
01795         goto cleanup;
01796     if (!GetIntField(hInf, ServiceSection, ErrorControlKey, &ErrorControl))
01797         goto cleanup;
01798     useTag = (ServiceType == SERVICE_BOOT_START || ServiceType == SERVICE_SYSTEM_START);
01799 
01800     hSCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE);
01801     if (hSCManager == NULL)
01802         goto cleanup;
01803 
01804     if (!GetLineText(hInf, ServiceSection, ServiceBinaryKey, &ServiceBinary))
01805         goto cleanup;
01806 
01807     /* Adjust binary path according to the service type */
01808     FixupServiceBinaryPath(ServiceType, &ServiceBinary);
01809 
01810     /* Don't check return value, as these fields are optional and
01811      * GetLineText initialize output parameter even on failure */
01812     GetLineText(hInf, ServiceSection, LoadOrderGroupKey, &LoadOrderGroup);
01813     GetLineText(hInf, ServiceSection, DisplayNameKey, &DisplayName);
01814     GetLineText(hInf, ServiceSection, DescriptionKey, &Description);
01815     GetLineText(hInf, ServiceSection, DependenciesKey, &Dependencies);
01816 
01817     /* If there is no group, we must not request a tag */
01818     if (!LoadOrderGroup || !*LoadOrderGroup)
01819         useTag = FALSE;
01820 
01821     hService = OpenServiceW(
01822         hSCManager,
01823         ServiceName,
01824         DELETE | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | WRITE_DAC);
01825     if (hService == NULL && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
01826         goto cleanup;
01827 
01828     if (hService && (ServiceFlags & SPSVCINST_DELETEEVENTLOGENTRY))
01829     {
01830         ret = DeleteService(hService);
01831         if (!ret && GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE)
01832             goto cleanup;
01833     }
01834 
01835     if (hService == NULL)
01836     {
01837         /* Create new service */
01838         hService = CreateServiceW(
01839             hSCManager,
01840             ServiceName,
01841             DisplayName,
01842             WRITE_DAC,
01843             ServiceType,
01844             StartType,
01845             ErrorControl,
01846             ServiceBinary,
01847             LoadOrderGroup,
01848             useTag ? &tagId : NULL,
01849             Dependencies,
01850             NULL, NULL);
01851         if (hService == NULL)
01852             goto cleanup;
01853     }
01854     else
01855     {
01856         DWORD bufferSize;
01857         /* Read current configuration */
01858         if (!QueryServiceConfigW(hService, NULL, 0, &bufferSize))
01859         {
01860             if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
01861                 goto cleanup;
01862             ServiceConfig = MyMalloc(bufferSize);
01863             if (!ServiceConfig)
01864             {
01865                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
01866                 goto cleanup;
01867             }
01868             if (!QueryServiceConfigW(hService, ServiceConfig, bufferSize, &bufferSize))
01869                 goto cleanup;
01870         }
01871         tagId = ServiceConfig->dwTagId;
01872 
01873         /* Update configuration */
01874         ret = ChangeServiceConfigW(
01875             hService,
01876             ServiceType,
01877             (ServiceFlags & SPSVCINST_NOCLOBBER_STARTTYPE) ? SERVICE_NO_CHANGE : StartType,
01878             (ServiceFlags & SPSVCINST_NOCLOBBER_ERRORCONTROL) ? SERVICE_NO_CHANGE : ErrorControl,
01879             ServiceBinary,
01880             (ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP && ServiceConfig->lpLoadOrderGroup) ? NULL : LoadOrderGroup,
01881             useTag ? &tagId : NULL,
01882             (ServiceFlags & SPSVCINST_NOCLOBBER_DEPENDENCIES && ServiceConfig->lpDependencies) ? NULL : Dependencies,
01883             NULL, NULL,
01884             (ServiceFlags & SPSVCINST_NOCLOBBER_DISPLAYNAME && ServiceConfig->lpDisplayName) ? NULL : DisplayName);
01885         if (!ret)
01886             goto cleanup;
01887     }
01888 
01889     /* Set security */
01890     if (GetLineText(hInf, ServiceSection, SecurityKey, &SecurityDescriptor))
01891     {
01892         ret = ConvertStringSecurityDescriptorToSecurityDescriptorW(SecurityDescriptor, SDDL_REVISION_1, &sd, NULL);
01893         if (!ret)
01894             goto cleanup;
01895         ret = SetServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, sd);
01896         if (!ret)
01897             goto cleanup;
01898     }
01899 
01900     /* FIXME: use Description and SPSVCINST_NOCLOBBER_DESCRIPTION */
01901 
01902     if (useTag)
01903     {
01904         /* Add the tag to SYSTEM\CurrentControlSet\Control\GroupOrderList key */
01905         LPCWSTR lpLoadOrderGroup;
01906         DWORD bufferSize;
01907 
01908         lpLoadOrderGroup = LoadOrderGroup;
01909         if ((ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP) && ServiceConfig && ServiceConfig->lpLoadOrderGroup)
01910             lpLoadOrderGroup = ServiceConfig->lpLoadOrderGroup;
01911 
01912         rc = RegOpenKeyW(
01913             list ? list->HKLM : HKEY_LOCAL_MACHINE,
01914             GroupOrderListKey,
01915             &hGroupOrderListKey);
01916         if (rc != ERROR_SUCCESS)
01917         {
01918             SetLastError(rc);
01919             goto cleanup;
01920         }
01921         rc = RegQueryValueExW(hGroupOrderListKey, lpLoadOrderGroup, NULL, &dwRegType, NULL, &bufferSize);
01922         if (rc == ERROR_FILE_NOT_FOUND)
01923             bufferSize = sizeof(DWORD);
01924         else if (rc != ERROR_SUCCESS)
01925         {
01926             SetLastError(rc);
01927             goto cleanup;
01928         }
01929         else if (dwRegType != REG_BINARY || bufferSize == 0 || bufferSize % sizeof(DWORD) != 0)
01930         {
01931             SetLastError(ERROR_GEN_FAILURE);
01932             goto cleanup;
01933         }
01934         /* Allocate buffer to store existing data + the new tag */
01935         GroupOrder = MyMalloc(bufferSize + sizeof(DWORD));
01936         if (!GroupOrder)
01937         {
01938             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
01939             goto cleanup;
01940         }
01941         if (rc == ERROR_SUCCESS)
01942         {
01943             /* Read existing data */
01944             rc = RegQueryValueExW(
01945                 hGroupOrderListKey,
01946                 lpLoadOrderGroup,
01947                 NULL,
01948                 NULL,
01949                 (BYTE*)GroupOrder,
01950                 &bufferSize);
01951             if (rc != ERROR_SUCCESS)
01952             {
01953                 SetLastError(rc);
01954                 goto cleanup;
01955             }
01956             if (ServiceFlags & SPSVCINST_TAGTOFRONT)
01957                 memmove(&GroupOrder[2], &GroupOrder[1], bufferSize - sizeof(DWORD));
01958         }
01959         else
01960         {
01961             GroupOrder[0] = 0;
01962         }
01963         GroupOrder[0]++;
01964         if (ServiceFlags & SPSVCINST_TAGTOFRONT)
01965             GroupOrder[1] = tagId;
01966         else
01967             GroupOrder[bufferSize / sizeof(DWORD)] = tagId;
01968 
01969         rc = RegSetValueExW(
01970             hGroupOrderListKey,
01971             lpLoadOrderGroup,
01972             0,
01973             REG_BINARY,
01974             (BYTE*)GroupOrder,
01975             bufferSize + sizeof(DWORD));
01976         if (rc != ERROR_SUCCESS)
01977         {
01978             SetLastError(rc);
01979             goto cleanup;
01980         }
01981     }
01982 
01983     /* Handle AddReg and DelReg */
01984     rc = RegOpenKeyExW(
01985         list ? list->HKLM : HKEY_LOCAL_MACHINE,
01986         REGSTR_PATH_SERVICES,
01987         0,
01988         0,
01989         &hServicesKey);
01990     if (rc != ERROR_SUCCESS)
01991     {
01992         SetLastError(rc);
01993         goto cleanup;
01994     }
01995     rc = RegOpenKeyExW(
01996         hServicesKey,
01997         ServiceName,
01998         0,
01999         KEY_READ | KEY_WRITE,
02000         &hServiceKey);
02001     RegCloseKey(hServicesKey);
02002     if (rc != ERROR_SUCCESS)
02003     {
02004         SetLastError(rc);
02005         goto cleanup;
02006     }
02007 
02008     ret = SetupInstallFromInfSectionW(
02009         NULL,
02010         hInf,
02011         ServiceSection,
02012         SPINST_REGISTRY,
02013         hServiceKey,
02014         NULL,
02015         0,
02016         NULL,
02017         NULL,
02018         NULL,
02019         NULL);
02020     RegCloseKey(hServiceKey);
02021 
02022 cleanup:
02023     if (hSCManager != NULL)
02024         CloseServiceHandle(hSCManager);
02025     if (hService != NULL)
02026         CloseServiceHandle(hService);
02027     if (hGroupOrderListKey != NULL)
02028         RegCloseKey(hGroupOrderListKey);
02029     if (sd != NULL)
02030         LocalFree(sd);
02031     MyFree(ServiceConfig);
02032     MyFree(ServiceBinary);
02033     MyFree(LoadOrderGroup);
02034     MyFree(DisplayName);
02035     MyFree(Description);
02036     MyFree(Dependencies);
02037     MyFree(SecurityDescriptor);
02038     MyFree(GroupOrder);
02039 
02040     TRACE("Returning %d\n", ret);
02041     return ret;
02042 }
02043 
02044 
02045 /***********************************************************************
02046  *      SetupInstallServicesFromInfSectionExW  (SETUPAPI.@)
02047  */
02048 BOOL WINAPI SetupInstallServicesFromInfSectionExW( HINF hinf, PCWSTR sectionname, DWORD flags, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PVOID reserved1, PVOID reserved2 )
02049 {
02050     struct DeviceInfoSet *list = NULL;
02051     BOOL ret = FALSE;
02052 
02053     TRACE("%p, %s, 0x%lx, %p, %p, %p, %p\n", hinf, debugstr_w(sectionname),
02054         flags, DeviceInfoSet, DeviceInfoData, reserved1, reserved2);
02055 
02056     if (!sectionname)
02057         SetLastError(ERROR_INVALID_PARAMETER);
02058     else if (flags & ~(SPSVCINST_TAGTOFRONT | SPSVCINST_DELETEEVENTLOGENTRY | SPSVCINST_NOCLOBBER_DISPLAYNAME | SPSVCINST_NOCLOBBER_STARTTYPE | SPSVCINST_NOCLOBBER_ERRORCONTROL | SPSVCINST_NOCLOBBER_LOADORDERGROUP | SPSVCINST_NOCLOBBER_DEPENDENCIES | SPSVCINST_STOPSERVICE))
02059     {
02060         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));
02061         SetLastError(ERROR_INVALID_FLAGS);
02062     }
02063     else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE)
02064         SetLastError(ERROR_INVALID_HANDLE);
02065     else if (DeviceInfoSet && (list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEVICE_INFO_SET_MAGIC)
02066         SetLastError(ERROR_INVALID_HANDLE);
02067     else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA))
02068         SetLastError(ERROR_INVALID_USER_BUFFER);
02069     else if (reserved1 != NULL || reserved2 != NULL)
02070         SetLastError(ERROR_INVALID_PARAMETER);
02071     else
02072     {
02073         struct needs_callback_info needs_info;
02074         LPWSTR ServiceName = NULL;
02075         LPWSTR ServiceSection = NULL;
02076         INT ServiceFlags;
02077         INFCONTEXT ContextService;
02078         BOOL bNeedReboot = FALSE;
02079 
02080         /* Parse 'Include' and 'Needs' directives */
02081         iterate_section_fields( hinf, sectionname, Include, include_callback, NULL);
02082         needs_info.type = 1;
02083         needs_info.flags = flags;
02084         needs_info.devinfo = DeviceInfoSet;
02085         needs_info.devinfo_data = DeviceInfoData;
02086         needs_info.reserved1 = reserved1;
02087         needs_info.reserved2 = reserved2;
02088         iterate_section_fields( hinf, sectionname, Needs, needs_callback, &needs_info);
02089 
02090         if (flags & SPSVCINST_STOPSERVICE)
02091         {
02092             FIXME("Stopping the device not implemented\n");
02093             /* This may lead to require a reboot */
02094             /* bNeedReboot = TRUE; */
02095 #if 0
02096             SERVICE_STATUS ServiceStatus;
02097             ret = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus);
02098             if (!ret && GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
02099                 goto cleanup;
02100             if (ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING && ServiceStatus.dwCurrentState != SERVICE_STOPPED)
02101             {
02102                 SetLastError(ERROR_INSTALL_SERVICE_FAILURE);
02103                 goto cleanup;
02104             }
02105 #endif
02106             flags &= ~SPSVCINST_STOPSERVICE;
02107         }
02108 
02109         ret = SetupFindFirstLineW(hinf, sectionname, AddService, &ContextService);
02110         while (ret)
02111         {
02112             if (!GetStringField(&ContextService, 1, &ServiceName))
02113                 goto nextservice;
02114 
02115             ret = SetupGetIntField(
02116                 &ContextService,
02117                 2, /* Field index */
02118                 &ServiceFlags);
02119             if (!ret)
02120             {
02121                 /* The field may be empty. Ignore the error */
02122                 ServiceFlags = 0;
02123             }
02124 
02125             if (!GetStringField(&ContextService, 3, &ServiceSection))
02126                 goto nextservice;
02127 
02128             ret = InstallOneService(list, hinf, ServiceSection, ServiceName, (ServiceFlags & ~SPSVCINST_ASSOCSERVICE) | flags);
02129             if (!ret)
02130                 goto nextservice;
02131 
02132             if (ServiceFlags & SPSVCINST_ASSOCSERVICE)
02133             {
02134                 ret = SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet, DeviceInfoData, SPDRP_SERVICE, (LPBYTE)ServiceName, (strlenW(ServiceName) + 1) * sizeof(WCHAR));
02135                 if (!ret)
02136                     goto nextservice;
02137             }
02138 
02139 nextservice:
02140             HeapFree(GetProcessHeap(), 0, ServiceName);
02141             HeapFree(GetProcessHeap(), 0, ServiceSection);
02142             ServiceName = ServiceSection = NULL;
02143             ret = SetupFindNextMatchLineW(&ContextService, AddService, &ContextService);
02144         }
02145 
02146         if (bNeedReboot)
02147             SetLastError(ERROR_SUCCESS_REBOOT_REQUIRED);
02148         else
02149             SetLastError(ERROR_SUCCESS);
02150         ret = TRUE;
02151     }
02152 
02153     TRACE("Returning %d\n", ret);
02154     return ret;
02155 }
02156 
02157 
02158 /***********************************************************************
02159  *      SetupCopyOEMInfA  (SETUPAPI.@)
02160  */
02161 BOOL WINAPI SetupCopyOEMInfA(
02162         IN PCSTR SourceInfFileName,
02163         IN PCSTR OEMSourceMediaLocation,
02164         IN DWORD OEMSourceMediaType,
02165         IN DWORD CopyStyle,
02166         OUT PSTR DestinationInfFileName OPTIONAL,
02167         IN DWORD DestinationInfFileNameSize,
02168         OUT PDWORD RequiredSize OPTIONAL,
02169         OUT PSTR* DestinationInfFileNameComponent OPTIONAL)
02170 {
02171     PWSTR SourceInfFileNameW = NULL;
02172     PWSTR OEMSourceMediaLocationW = NULL;
02173     PWSTR DestinationInfFileNameW = NULL;
02174     PWSTR DestinationInfFileNameComponentW = NULL;
02175     BOOL ret = FALSE;
02176 
02177     TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n",
02178         SourceInfFileName, OEMSourceMediaLocation, OEMSourceMediaType,
02179         CopyStyle, DestinationInfFileName, DestinationInfFileNameSize,
02180         RequiredSize, DestinationInfFileNameComponent);
02181 
02182     if (!DestinationInfFileName && DestinationInfFileNameSize > 0)
02183         SetLastError(ERROR_INVALID_PARAMETER);
02184     else if (!(SourceInfFileNameW = pSetupMultiByteToUnicode(SourceInfFileName, CP_ACP)))
02185         SetLastError(ERROR_INVALID_PARAMETER);
02186     else if (OEMSourceMediaType != SPOST_NONE && !(OEMSourceMediaLocationW = pSetupMultiByteToUnicode(OEMSourceMediaLocation, CP_ACP)))
02187         SetLastError(ERROR_INVALID_PARAMETER);
02188     else
02189     {
02190         if (DestinationInfFileNameSize != 0)
02191         {
02192             DestinationInfFileNameW = MyMalloc(DestinationInfFileNameSize * sizeof(WCHAR));
02193             if (!DestinationInfFileNameW)
02194             {
02195                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
02196                 goto cleanup;
02197             }
02198         }
02199 
02200         ret = SetupCopyOEMInfW(
02201             SourceInfFileNameW,
02202             OEMSourceMediaLocationW,
02203             OEMSourceMediaType,
02204             CopyStyle,
02205             DestinationInfFileNameW,
02206             DestinationInfFileNameSize,
02207             RequiredSize,
02208             DestinationInfFileNameComponent ? &DestinationInfFileNameComponentW : NULL);
02209         if (!ret)
02210             goto cleanup;
02211 
02212         if (DestinationInfFileNameSize != 0)
02213         {
02214             if (WideCharToMultiByte(CP_ACP, 0, DestinationInfFileNameW, -1,
02215                 DestinationInfFileName, DestinationInfFileNameSize, NULL, NULL) == 0)
02216             {
02217                 DestinationInfFileName[0] = '\0';
02218                 goto cleanup;
02219             }
02220         }
02221         if (DestinationInfFileNameComponent)
02222         {
02223             if (DestinationInfFileNameComponentW)
02224                 *DestinationInfFileNameComponent = &DestinationInfFileName[DestinationInfFileNameComponentW - DestinationInfFileNameW];
02225             else
02226                 *DestinationInfFileNameComponent = NULL;
02227         }
02228         ret = TRUE;
02229     }
02230 
02231 cleanup:
02232     MyFree(SourceInfFileNameW);
02233     MyFree(OEMSourceMediaLocationW);
02234     MyFree(DestinationInfFileNameW);
02235     TRACE("Returning %d\n", ret);
02236     if (ret) SetLastError(ERROR_SUCCESS);
02237     return ret;
02238 }
02239 
02240 static int compare_files( HANDLE file1, HANDLE file2 )
02241 {
02242     char buffer1[2048];
02243     char buffer2[2048];
02244     DWORD size1;
02245     DWORD size2;
02246 
02247     while( ReadFile(file1, buffer1, sizeof(buffer1), &size1, NULL) &&
02248            ReadFile(file2, buffer2, sizeof(buffer2), &size2, NULL) )
02249     {
02250         int ret;
02251         if (size1 != size2)
02252             return size1 > size2 ? 1 : -1;
02253         if (!size1)
02254             return 0;
02255         ret = memcmp( buffer1, buffer2, size1 );
02256         if (ret)
02257             return ret;
02258     }
02259 
02260     return 0;
02261 }
02262 
02263 /***********************************************************************
02264  *      SetupCopyOEMInfW  (SETUPAPI.@)
02265  */
02266 BOOL WINAPI SetupCopyOEMInfW(
02267         IN PCWSTR SourceInfFileName,
02268         IN PCWSTR OEMSourceMediaLocation,
02269         IN DWORD OEMSourceMediaType,
02270         IN DWORD CopyStyle,
02271         OUT PWSTR DestinationInfFileName OPTIONAL,
02272         IN DWORD DestinationInfFileNameSize,
02273         OUT PDWORD RequiredSize OPTIONAL,
02274         OUT PWSTR* DestinationInfFileNameComponent OPTIONAL)
02275 {
02276     BOOL ret = FALSE;
02277 
02278     TRACE("%s %s 0x%lx 0x%lx %p 0%lu %p %p\n",
02279         debugstr_w(SourceInfFileName), debugstr_w(OEMSourceMediaLocation), OEMSourceMediaType,
02280         CopyStyle, DestinationInfFileName, DestinationInfFileNameSize,
02281         RequiredSize, DestinationInfFileNameComponent);
02282 
02283     if (!SourceInfFileName)
02284         SetLastError(ERROR_INVALID_PARAMETER);
02285     else if (OEMSourceMediaType != SPOST_NONE && OEMSourceMediaType != SPOST_PATH && OEMSourceMediaType != SPOST_URL)
02286         SetLastError(ERROR_INVALID_PARAMETER);
02287     else if (OEMSourceMediaType != SPOST_NONE && !OEMSourceMediaLocation)
02288         SetLastError(ERROR_INVALID_PARAMETER);
02289     else if (CopyStyle & ~(SP_COPY_DELETESOURCE | SP_COPY_REPLACEONLY | SP_COPY_NOOVERWRITE | SP_COPY_OEMINF_CATALOG_ONLY))
02290     {
02291         TRACE("Unknown flags: 0x%08lx\n", CopyStyle & ~(SP_COPY_DELETESOURCE | SP_COPY_REPLACEONLY | SP_COPY_NOOVERWRITE | SP_COPY_OEMINF_CATALOG_ONLY));
02292         SetLastError(ERROR_INVALID_FLAGS);
02293     }
02294     else if (!DestinationInfFileName && DestinationInfFileNameSize > 0)
02295         SetLastError(ERROR_INVALID_PARAMETER);
02296     else if (CopyStyle & SP_COPY_OEMINF_CATALOG_ONLY)
02297     {
02298         FIXME("CopyStyle 0x%x not supported\n", SP_COPY_OEMINF_CATALOG_ONLY);
02299         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
02300     }
02301     else
02302     {
02303         HANDLE hSearch = INVALID_HANDLE_VALUE;
02304         WIN32_FIND_DATAW FindFileData;
02305         BOOL AlreadyExists;
02306         DWORD NextFreeNumber = 0;
02307         SIZE_T len;
02308         LPWSTR pFullFileName = NULL;
02309         LPWSTR pFileName; /* Pointer into pFullFileName buffer */
02310         HANDLE hSourceFile = INVALID_HANDLE_VALUE;
02311 
02312         if (OEMSourceMediaType == SPOST_PATH || OEMSourceMediaType == SPOST_URL)
02313             FIXME("OEMSourceMediaType 0x%lx ignored\n", OEMSourceMediaType);
02314 
02315         /* Check if source file exists, and open it */
02316         if (strchrW(SourceInfFileName, '\\' ) || strchrW(SourceInfFileName, '/' ))
02317         {
02318             WCHAR *path;
02319 
02320             if (!(len = GetFullPathNameW(SourceInfFileName, 0, NULL, NULL)))
02321                 return FALSE;
02322             if (!(path = MyMalloc(len * sizeof(WCHAR))))
02323             {
02324                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
02325                 return FALSE;
02326             }
02327             GetFullPathNameW(SourceInfFileName, len, path, NULL);
02328             hSourceFile = CreateFileW(
02329                 path, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
02330                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
02331                 NULL, OPEN_EXISTING, 0, NULL);
02332             MyFree(path);
02333         }
02334         else  /* try Windows directory */
02335         {
02336             WCHAR *path, *p;
02337             static const WCHAR Inf[]      = {'\\','i','n','f','\\',0};
02338             static const WCHAR System32[] = {'\\','s','y','s','t','e','m','3','2','\\',0};
02339 
02340             len = GetWindowsDirectoryW(NULL, 0) + strlenW(SourceInfFileName) + 12;
02341             if (!(path = MyMalloc(len * sizeof(WCHAR))))
02342             {
02343                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
02344                 return FALSE;
02345             }
02346             GetWindowsDirectoryW(path, len);
02347             p = path + strlenW(path);
02348             strcpyW(p, Inf);
02349             strcatW(p, SourceInfFileName);
02350             hSourceFile = CreateFileW(
02351                 path, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
02352                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
02353                 NULL, OPEN_EXISTING, 0, NULL);
02354             if (hSourceFile == INVALID_HANDLE_VALUE)
02355             {
02356                 strcpyW(p, System32);
02357                 strcatW(p, SourceInfFileName);
02358                 hSourceFile = CreateFileW(
02359                     path, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
02360                     FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
02361                     NULL, OPEN_EXISTING, 0, NULL);
02362             }
02363             MyFree(path);
02364         }
02365         if (hSourceFile == INVALID_HANDLE_VALUE)
02366         {
02367             SetLastError(ERROR_FILE_NOT_FOUND);
02368             goto cleanup;
02369         }
02370 
02371         /* Prepare .inf file specification */
02372         len = MAX_PATH + 1 + strlenW(InfDirectory) + 13;
02373         pFullFileName = MyMalloc(len * sizeof(WCHAR));
02374         if (!pFullFileName)
02375         {
02376             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
02377             goto cleanup;
02378         }
02379         len = GetSystemWindowsDirectoryW(pFullFileName, MAX_PATH);
02380         if (len == 0 || len > MAX_PATH)
02381             goto cleanup;
02382         if (pFullFileName[strlenW(pFullFileName) - 1] != '\\')
02383             strcatW(pFullFileName, BackSlash);
02384         strcatW(pFullFileName, InfDirectory);
02385         pFileName = &pFullFileName[strlenW(pFullFileName)];
02386 
02387         /* Search if the specified .inf file already exists in %WINDIR%\Inf */
02388         AlreadyExists = FALSE;
02389         strcpyW(pFileName, OemFileMask);
02390         hSearch = FindFirstFileW(pFullFileName, &FindFileData);
02391         if (hSearch != INVALID_HANDLE_VALUE)
02392         {
02393             LARGE_INTEGER SourceFileSize;
02394 
02395             if (GetFileSizeEx(hSourceFile, &SourceFileSize))
02396             {
02397                 do
02398                 {
02399                     LARGE_INTEGER DestFileSize;
02400                     HANDLE hDestFile;
02401 
02402                     strcpyW(pFileName, FindFileData.cFileName);
02403                     hDestFile = CreateFileW(
02404                         pFullFileName, FILE_READ_DATA | FILE_READ_ATTRIBUTES,
02405                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
02406                         NULL, OPEN_EXISTING, 0, NULL);
02407                     if (hDestFile != INVALID_HANDLE_VALUE)
02408                     {
02409                         if (GetFileSizeEx(hDestFile, &DestFileSize)
02410                          && DestFileSize.QuadPart == SourceFileSize.QuadPart
02411                          && !compare_files(hSourceFile, hDestFile))
02412                         {
02413                             TRACE("%s already exists as %s\n",
02414                                 debugstr_w(SourceInfFileName), debugstr_w(pFileName));
02415                             AlreadyExists = TRUE;
02416                         }
02417                     }
02418                 } while (!AlreadyExists && FindNextFileW(hSearch, &FindFileData));
02419             }
02420             FindClose(hSearch);
02421             hSearch = INVALID_HANDLE_VALUE;
02422         }
02423 
02424         if (!AlreadyExists && CopyStyle & SP_COPY_REPLACEONLY)
02425         {
02426             /* FIXME: set DestinationInfFileName, RequiredSize, DestinationInfFileNameComponent */
02427             SetLastError(ERROR_FILE_NOT_FOUND);
02428             goto cleanup;
02429         }
02430         else if (AlreadyExists && (CopyStyle & SP_COPY_NOOVERWRITE))
02431         {
02432             DWORD Size = strlenW(pFileName) + 1;
02433 
02434             if (RequiredSize)
02435                 *RequiredSize = Size;
02436             if (DestinationInfFileNameSize == 0)
02437                 SetLastError(ERROR_FILE_EXISTS);
02438             else if (DestinationInfFileNameSize < Size)
02439                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
02440             else
02441             {
02442                 SetLastError(ERROR_FILE_EXISTS);
02443                 strcpyW(DestinationInfFileName, pFileName);
02444             }
02445             goto cleanup;
02446         }
02447 
02448         /* Search the number to give to OEM??.INF */
02449         strcpyW(pFileName, OemFileMask);
02450         hSearch = FindFirstFileW(pFullFileName, &FindFileData);
02451         if (hSearch == INVALID_HANDLE_VALUE)
02452         {
02453             if (GetLastError() != ERROR_FILE_NOT_FOUND)
02454                 goto cleanup;
02455         }
02456         else
02457         {
02458             do
02459             {
02460                 DWORD CurrentNumber;
02461                 if (swscanf(FindFileData.cFileName, OemFileSpecification, &CurrentNumber) == 1
02462                     && CurrentNumber <= 99999)
02463                 {
02464                     if (CurrentNumber >= NextFreeNumber)
02465                         NextFreeNumber = CurrentNumber + 1;
02466                 }
02467             } while (FindNextFileW(hSearch, &FindFileData));
02468         }
02469 
02470         if (NextFreeNumber > 99999)
02471         {
02472             ERR("Too much custom .inf files\n");
02473             SetLastError(ERROR_GEN_FAILURE);
02474             goto cleanup;
02475         }
02476 
02477         /* Create the full path: %WINDIR%\Inf\OEM{XXXXX}.inf */
02478         sprintfW(pFileName, OemFileSpecification, NextFreeNumber);
02479         TRACE("Next available file is %s\n", debugstr_w(pFileName));
02480 
02481         if (!CopyFileW(SourceInfFileName, pFullFileName, TRUE))
02482         {
02483             TRACE("CopyFileW() failed with error 0x%lx\n", GetLastError());
02484             goto cleanup;
02485         }
02486 
02487         len = strlenW(pFullFileName) + 1;
02488         if (RequiredSize)
02489             *RequiredSize = len;
02490         if (DestinationInfFileName)
02491         {
02492             if (DestinationInfFileNameSize >= len)
02493             {
02494                 strcpyW(DestinationInfFileName, pFullFileName);
02495                 if (DestinationInfFileNameComponent)
02496                     *DestinationInfFileNameComponent = &DestinationInfFileName[pFileName - pFullFileName];
02497             }
02498             else
02499             {
02500                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
02501                 goto cleanup;
02502             }
02503         }
02504 
02505         if (CopyStyle & SP_COPY_DELETESOURCE)
02506         {
02507             if (!DeleteFileW(SourceInfFileName))
02508             {
02509                 TRACE("DeleteFileW() failed with error 0x%lx\n", GetLastError());
02510                 goto cleanup;
02511             }
02512         }
02513 
02514         ret = TRUE;
02515 
02516 cleanup:
02517         if (hSourceFile != INVALID_HANDLE_VALUE)
02518             CloseHandle(hSourceFile);
02519         if (hSearch != INVALID_HANDLE_VALUE)
02520             FindClose(hSearch);
02521         MyFree(pFullFileName);
02522     }
02523 
02524     TRACE("Returning %d\n", ret);
02525     if (ret) SetLastError(ERROR_SUCCESS);
02526     return ret;
02527 }

Generated on Mon May 28 2012 04:19:03 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.