Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygeninstall.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( §ionW, 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( §ionW ); 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( §ionW, 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( §ionW ); 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( §ionnameW, sectionname )) 01621 { 01622 ret = SetupInstallServicesFromInfSectionExW( hinf, sectionnameW.Buffer, flags, devinfo, devinfo_data, reserved1, reserved2 ); 01623 RtlFreeUnicodeString( §ionnameW ); 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
1.7.6.1
|