Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenaction.c
Go to the documentation of this file.
00001 /* 00002 * Implementation of the Microsoft Installer (msi.dll) 00003 * 00004 * Copyright 2004,2005 Aric Stewart for CodeWeavers 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 */ 00020 00021 #include <stdarg.h> 00022 00023 #define COBJMACROS 00024 00025 #include "windef.h" 00026 #include "winbase.h" 00027 #include "winerror.h" 00028 #include "winreg.h" 00029 #include "winsvc.h" 00030 #include "odbcinst.h" 00031 #include "wine/debug.h" 00032 #include "msidefs.h" 00033 #include "msipriv.h" 00034 #include "winuser.h" 00035 #include "shlobj.h" 00036 #include "objbase.h" 00037 #include "mscoree.h" 00038 #include "shlwapi.h" 00039 #include "imagehlp.h" 00040 #include "wine/unicode.h" 00041 #include "winver.h" 00042 00043 #define REG_PROGRESS_VALUE 13200 00044 #define COMPONENT_PROGRESS_VALUE 24000 00045 00046 WINE_DEFAULT_DEBUG_CHANNEL(msi); 00047 00048 static const WCHAR szCreateFolders[] = 00049 {'C','r','e','a','t','e','F','o','l','d','e','r','s',0}; 00050 static const WCHAR szCostFinalize[] = 00051 {'C','o','s','t','F','i','n','a','l','i','z','e',0}; 00052 static const WCHAR szWriteRegistryValues[] = 00053 {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0}; 00054 static const WCHAR szFileCost[] = 00055 {'F','i','l','e','C','o','s','t',0}; 00056 static const WCHAR szInstallInitialize[] = 00057 {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0}; 00058 static const WCHAR szInstallValidate[] = 00059 {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0}; 00060 static const WCHAR szLaunchConditions[] = 00061 {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0}; 00062 static const WCHAR szProcessComponents[] = 00063 {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0}; 00064 static const WCHAR szRegisterTypeLibraries[] = 00065 {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0}; 00066 static const WCHAR szCreateShortcuts[] = 00067 {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0}; 00068 static const WCHAR szPublishProduct[] = 00069 {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0}; 00070 static const WCHAR szWriteIniValues[] = 00071 {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0}; 00072 static const WCHAR szSelfRegModules[] = 00073 {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0}; 00074 static const WCHAR szPublishFeatures[] = 00075 {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0}; 00076 static const WCHAR szRegisterProduct[] = 00077 {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0}; 00078 static const WCHAR szInstallExecute[] = 00079 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0}; 00080 static const WCHAR szInstallExecuteAgain[] = 00081 {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0}; 00082 static const WCHAR szInstallFinalize[] = 00083 {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0}; 00084 static const WCHAR szForceReboot[] = 00085 {'F','o','r','c','e','R','e','b','o','o','t',0}; 00086 static const WCHAR szResolveSource[] = 00087 {'R','e','s','o','l','v','e','S','o','u','r','c','e',0}; 00088 static const WCHAR szAllocateRegistrySpace[] = 00089 {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0}; 00090 static const WCHAR szBindImage[] = 00091 {'B','i','n','d','I','m','a','g','e',0}; 00092 static const WCHAR szDeleteServices[] = 00093 {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0}; 00094 static const WCHAR szDisableRollback[] = 00095 {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0}; 00096 static const WCHAR szExecuteAction[] = 00097 {'E','x','e','c','u','t','e','A','c','t','i','o','n',0}; 00098 static const WCHAR szInstallAdminPackage[] = 00099 {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0}; 00100 static const WCHAR szInstallSFPCatalogFile[] = 00101 {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0}; 00102 static const WCHAR szIsolateComponents[] = 00103 {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0}; 00104 static const WCHAR szMigrateFeatureStates[] = 00105 {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0}; 00106 static const WCHAR szMsiUnpublishAssemblies[] = 00107 {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0}; 00108 static const WCHAR szInstallODBC[] = 00109 {'I','n','s','t','a','l','l','O','D','B','C',0}; 00110 static const WCHAR szInstallServices[] = 00111 {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0}; 00112 static const WCHAR szPublishComponents[] = 00113 {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0}; 00114 static const WCHAR szRegisterComPlus[] = 00115 {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0}; 00116 static const WCHAR szRegisterUser[] = 00117 {'R','e','g','i','s','t','e','r','U','s','e','r',0}; 00118 static const WCHAR szRemoveEnvironmentStrings[] = 00119 {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0}; 00120 static const WCHAR szRemoveExistingProducts[] = 00121 {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0}; 00122 static const WCHAR szRemoveFolders[] = 00123 {'R','e','m','o','v','e','F','o','l','d','e','r','s',0}; 00124 static const WCHAR szRemoveIniValues[] = 00125 {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0}; 00126 static const WCHAR szRemoveODBC[] = 00127 {'R','e','m','o','v','e','O','D','B','C',0}; 00128 static const WCHAR szRemoveRegistryValues[] = 00129 {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0}; 00130 static const WCHAR szRemoveShortcuts[] = 00131 {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0}; 00132 static const WCHAR szRMCCPSearch[] = 00133 {'R','M','C','C','P','S','e','a','r','c','h',0}; 00134 static const WCHAR szScheduleReboot[] = 00135 {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0}; 00136 static const WCHAR szSelfUnregModules[] = 00137 {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0}; 00138 static const WCHAR szSetODBCFolders[] = 00139 {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0}; 00140 static const WCHAR szStartServices[] = 00141 {'S','t','a','r','t','S','e','r','v','i','c','e','s',0}; 00142 static const WCHAR szStopServices[] = 00143 {'S','t','o','p','S','e','r','v','i','c','e','s',0}; 00144 static const WCHAR szUnpublishComponents[] = 00145 {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0}; 00146 static const WCHAR szUnpublishFeatures[] = 00147 {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0}; 00148 static const WCHAR szUnregisterComPlus[] = 00149 {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0}; 00150 static const WCHAR szUnregisterTypeLibraries[] = 00151 {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0}; 00152 static const WCHAR szValidateProductID[] = 00153 {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0}; 00154 static const WCHAR szWriteEnvironmentStrings[] = 00155 {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0}; 00156 00157 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action) 00158 { 00159 static const WCHAR Query_t[] = 00160 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 00161 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ', 00162 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=', 00163 ' ','\'','%','s','\'',0}; 00164 MSIRECORD * row; 00165 00166 row = MSI_QueryGetRecord( package->db, Query_t, action ); 00167 if (!row) 00168 return; 00169 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row); 00170 msiobj_release(&row->hdr); 00171 } 00172 00173 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, 00174 UINT rc) 00175 { 00176 MSIRECORD * row; 00177 static const WCHAR template_s[]= 00178 {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ', 00179 '%','s', '.',0}; 00180 static const WCHAR template_e[]= 00181 {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ', 00182 '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ', 00183 '%','i','.',0}; 00184 static const WCHAR format[] = 00185 {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0}; 00186 WCHAR message[1024]; 00187 WCHAR timet[0x100]; 00188 00189 GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100); 00190 if (start) 00191 sprintfW(message,template_s,timet,action); 00192 else 00193 sprintfW(message,template_e,timet,action,rc); 00194 00195 row = MSI_CreateRecord(1); 00196 MSI_RecordSetStringW(row,1,message); 00197 00198 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row); 00199 msiobj_release(&row->hdr); 00200 } 00201 00202 enum parse_state 00203 { 00204 state_whitespace, 00205 state_token, 00206 state_quote 00207 }; 00208 00209 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes ) 00210 { 00211 enum parse_state state = state_quote; 00212 const WCHAR *p; 00213 WCHAR *out = value; 00214 int ignore, in_quotes = 0, count = 0, len = 0; 00215 00216 for (p = str; *p; p++) 00217 { 00218 ignore = 0; 00219 switch (state) 00220 { 00221 case state_whitespace: 00222 switch (*p) 00223 { 00224 case ' ': 00225 in_quotes = 1; 00226 ignore = 1; 00227 len++; 00228 break; 00229 case '"': 00230 state = state_quote; 00231 if (in_quotes && p[1] != '\"') count--; 00232 else count++; 00233 break; 00234 default: 00235 state = state_token; 00236 in_quotes = 1; 00237 len++; 00238 break; 00239 } 00240 break; 00241 00242 case state_token: 00243 switch (*p) 00244 { 00245 case '"': 00246 state = state_quote; 00247 if (in_quotes) count--; 00248 else count++; 00249 break; 00250 case ' ': 00251 state = state_whitespace; 00252 if (!count) goto done; 00253 in_quotes = 1; 00254 len++; 00255 break; 00256 default: 00257 if (!count) in_quotes = 0; 00258 else in_quotes = 1; 00259 len++; 00260 break; 00261 } 00262 break; 00263 00264 case state_quote: 00265 switch (*p) 00266 { 00267 case '"': 00268 if (in_quotes && p[1] != '\"') count--; 00269 else count++; 00270 break; 00271 case ' ': 00272 state = state_whitespace; 00273 if (!count || (count > 1 && !len)) goto done; 00274 in_quotes = 1; 00275 len++; 00276 break; 00277 default: 00278 state = state_token; 00279 if (!count) in_quotes = 0; 00280 else in_quotes = 1; 00281 len++; 00282 break; 00283 } 00284 break; 00285 00286 default: break; 00287 } 00288 if (!ignore) *out++ = *p; 00289 } 00290 00291 done: 00292 if (!len) *value = 0; 00293 else *out = 0; 00294 00295 *quotes = count; 00296 return p - str; 00297 } 00298 00299 static void remove_quotes( WCHAR *str ) 00300 { 00301 WCHAR *p = str; 00302 int len = strlenW( str ); 00303 00304 while ((p = strchrW( p, '"' ))) 00305 { 00306 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) ); 00307 p++; 00308 } 00309 } 00310 00311 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine, 00312 BOOL preserve_case ) 00313 { 00314 LPCWSTR ptr, ptr2; 00315 int num_quotes; 00316 DWORD len; 00317 WCHAR *prop, *val; 00318 UINT r; 00319 00320 if (!szCommandLine) 00321 return ERROR_SUCCESS; 00322 00323 ptr = szCommandLine; 00324 while (*ptr) 00325 { 00326 while (*ptr == ' ') ptr++; 00327 if (!*ptr) break; 00328 00329 ptr2 = strchrW( ptr, '=' ); 00330 if (!ptr2) return ERROR_INVALID_COMMAND_LINE; 00331 00332 len = ptr2 - ptr; 00333 if (!len) return ERROR_INVALID_COMMAND_LINE; 00334 00335 prop = msi_alloc( (len + 1) * sizeof(WCHAR) ); 00336 memcpy( prop, ptr, len * sizeof(WCHAR) ); 00337 prop[len] = 0; 00338 if (!preserve_case) struprW( prop ); 00339 00340 ptr2++; 00341 while (*ptr2 == ' ') ptr2++; 00342 00343 num_quotes = 0; 00344 val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) ); 00345 len = parse_prop( ptr2, val, &num_quotes ); 00346 if (num_quotes % 2) 00347 { 00348 WARN("unbalanced quotes\n"); 00349 msi_free( val ); 00350 msi_free( prop ); 00351 return ERROR_INVALID_COMMAND_LINE; 00352 } 00353 remove_quotes( val ); 00354 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val)); 00355 00356 r = msi_set_property( package->db, prop, val ); 00357 if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir )) 00358 msi_reset_folders( package, TRUE ); 00359 00360 msi_free( val ); 00361 msi_free( prop ); 00362 00363 ptr = ptr2 + len; 00364 } 00365 00366 return ERROR_SUCCESS; 00367 } 00368 00369 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep ) 00370 { 00371 LPCWSTR pc; 00372 LPWSTR p, *ret = NULL; 00373 UINT count = 0; 00374 00375 if (!str) 00376 return ret; 00377 00378 /* count the number of substrings */ 00379 for ( pc = str, count = 0; pc; count++ ) 00380 { 00381 pc = strchrW( pc, sep ); 00382 if (pc) 00383 pc++; 00384 } 00385 00386 /* allocate space for an array of substring pointers and the substrings */ 00387 ret = msi_alloc( (count+1) * sizeof (LPWSTR) + 00388 (lstrlenW(str)+1) * sizeof(WCHAR) ); 00389 if (!ret) 00390 return ret; 00391 00392 /* copy the string and set the pointers */ 00393 p = (LPWSTR) &ret[count+1]; 00394 lstrcpyW( p, str ); 00395 for( count = 0; (ret[count] = p); count++ ) 00396 { 00397 p = strchrW( p, sep ); 00398 if (p) 00399 *p++ = 0; 00400 } 00401 00402 return ret; 00403 } 00404 00405 static BOOL ui_sequence_exists( MSIPACKAGE *package ) 00406 { 00407 static const WCHAR query [] = { 00408 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 00409 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ', 00410 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ', 00411 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0}; 00412 MSIQUERY *view; 00413 UINT rc; 00414 00415 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 00416 if (rc == ERROR_SUCCESS) 00417 { 00418 msiobj_release(&view->hdr); 00419 return TRUE; 00420 } 00421 return FALSE; 00422 } 00423 00424 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace) 00425 { 00426 LPWSTR source, check; 00427 00428 if (msi_get_property_int( package->db, szInstalled, 0 )) 00429 { 00430 HKEY hkey; 00431 00432 MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE ); 00433 source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW ); 00434 RegCloseKey( hkey ); 00435 } 00436 else 00437 { 00438 LPWSTR p, db; 00439 DWORD len; 00440 00441 db = msi_dup_property( package->db, szOriginalDatabase ); 00442 if (!db) 00443 return ERROR_OUTOFMEMORY; 00444 00445 p = strrchrW( db, '\\' ); 00446 if (!p) 00447 { 00448 p = strrchrW( db, '/' ); 00449 if (!p) 00450 { 00451 msi_free(db); 00452 return ERROR_SUCCESS; 00453 } 00454 } 00455 00456 len = p - db + 2; 00457 source = msi_alloc( len * sizeof(WCHAR) ); 00458 lstrcpynW( source, db, len ); 00459 msi_free( db ); 00460 } 00461 00462 check = msi_dup_property( package->db, szSourceDir ); 00463 if (!check || replace) 00464 { 00465 UINT r = msi_set_property( package->db, szSourceDir, source ); 00466 if (r == ERROR_SUCCESS) 00467 msi_reset_folders( package, TRUE ); 00468 } 00469 msi_free( check ); 00470 00471 check = msi_dup_property( package->db, szSOURCEDIR ); 00472 if (!check || replace) 00473 msi_set_property( package->db, szSOURCEDIR, source ); 00474 00475 msi_free( check ); 00476 msi_free( source ); 00477 00478 return ERROR_SUCCESS; 00479 } 00480 00481 static BOOL needs_ui_sequence(MSIPACKAGE *package) 00482 { 00483 return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED; 00484 } 00485 00486 UINT msi_set_context(MSIPACKAGE *package) 00487 { 00488 UINT r = msi_locate_product( package->ProductCode, &package->Context ); 00489 if (r != ERROR_SUCCESS) 00490 { 00491 int num = msi_get_property_int( package->db, szAllUsers, 0 ); 00492 if (num == 1 || num == 2) 00493 package->Context = MSIINSTALLCONTEXT_MACHINE; 00494 else 00495 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED; 00496 } 00497 return ERROR_SUCCESS; 00498 } 00499 00500 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param) 00501 { 00502 UINT rc; 00503 LPCWSTR cond, action; 00504 MSIPACKAGE *package = param; 00505 00506 action = MSI_RecordGetString(row,1); 00507 if (!action) 00508 { 00509 ERR("Error is retrieving action name\n"); 00510 return ERROR_FUNCTION_FAILED; 00511 } 00512 00513 /* check conditions */ 00514 cond = MSI_RecordGetString(row,2); 00515 00516 /* this is a hack to skip errors in the condition code */ 00517 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE) 00518 { 00519 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action)); 00520 return ERROR_SUCCESS; 00521 } 00522 00523 if (needs_ui_sequence(package)) 00524 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE); 00525 else 00526 rc = ACTION_PerformAction(package, action, SCRIPT_NONE); 00527 00528 msi_dialog_check_messages( NULL ); 00529 00530 if (package->CurrentInstallState != ERROR_SUCCESS) 00531 rc = package->CurrentInstallState; 00532 00533 if (rc == ERROR_FUNCTION_NOT_CALLED) 00534 rc = ERROR_SUCCESS; 00535 00536 if (rc != ERROR_SUCCESS) 00537 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc); 00538 00539 if (package->need_reboot_now) 00540 { 00541 TRACE("action %s asked for immediate reboot, suspending installation\n", 00542 debugstr_w(action)); 00543 rc = ACTION_ForceReboot( package ); 00544 } 00545 return rc; 00546 } 00547 00548 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table ) 00549 { 00550 static const WCHAR query[] = { 00551 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`', 00552 ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ', 00553 '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ', 00554 '`','S','e','q','u','e','n','c','e','`',0}; 00555 MSIQUERY *view; 00556 UINT r; 00557 00558 TRACE("%p %s\n", package, debugstr_w(table)); 00559 00560 r = MSI_OpenQuery( package->db, &view, query, table ); 00561 if (r == ERROR_SUCCESS) 00562 { 00563 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package ); 00564 msiobj_release(&view->hdr); 00565 } 00566 return r; 00567 } 00568 00569 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) 00570 { 00571 static const WCHAR query[] = { 00572 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', 00573 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e', 00574 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ', 00575 '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ', 00576 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0}; 00577 static const WCHAR query_validate[] = { 00578 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`', 00579 ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l', 00580 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ', 00581 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=', 00582 ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0}; 00583 MSIQUERY *view; 00584 INT seq = 0; 00585 UINT rc; 00586 00587 if (package->script->ExecuteSequenceRun) 00588 { 00589 TRACE("Execute Sequence already Run\n"); 00590 return ERROR_SUCCESS; 00591 } 00592 00593 package->script->ExecuteSequenceRun = TRUE; 00594 00595 /* get the sequence number */ 00596 if (UIran) 00597 { 00598 MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate); 00599 if (!row) return ERROR_FUNCTION_FAILED; 00600 seq = MSI_RecordGetInteger(row,1); 00601 msiobj_release(&row->hdr); 00602 } 00603 rc = MSI_OpenQuery(package->db, &view, query, seq); 00604 if (rc == ERROR_SUCCESS) 00605 { 00606 TRACE("Running the actions\n"); 00607 00608 msi_set_property(package->db, szSourceDir, NULL); 00609 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package); 00610 msiobj_release(&view->hdr); 00611 } 00612 return rc; 00613 } 00614 00615 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package) 00616 { 00617 static const WCHAR query[] = { 00618 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 00619 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ', 00620 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ', 00621 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0}; 00622 MSIQUERY *view; 00623 UINT rc; 00624 00625 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 00626 if (rc == ERROR_SUCCESS) 00627 { 00628 TRACE("Running the actions\n"); 00629 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package); 00630 msiobj_release(&view->hdr); 00631 } 00632 return rc; 00633 } 00634 00635 /******************************************************** 00636 * ACTION helper functions and functions that perform the actions 00637 *******************************************************/ 00638 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action, 00639 UINT* rc, UINT script, BOOL force ) 00640 { 00641 BOOL ret=FALSE; 00642 UINT arc; 00643 00644 arc = ACTION_CustomAction(package, action, script, force); 00645 00646 if (arc != ERROR_CALL_NOT_IMPLEMENTED) 00647 { 00648 *rc = arc; 00649 ret = TRUE; 00650 } 00651 return ret; 00652 } 00653 00654 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component ) 00655 { 00656 MSICOMPONENT *comp; 00657 00658 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) 00659 { 00660 if (!strcmpW( Component, comp->Component )) return comp; 00661 } 00662 return NULL; 00663 } 00664 00665 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature ) 00666 { 00667 MSIFEATURE *feature; 00668 00669 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 00670 { 00671 if (!strcmpW( Feature, feature->Feature )) return feature; 00672 } 00673 return NULL; 00674 } 00675 00676 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key ) 00677 { 00678 MSIFILE *file; 00679 00680 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) 00681 { 00682 if (!strcmpW( key, file->File )) return file; 00683 } 00684 return NULL; 00685 } 00686 00687 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key ) 00688 { 00689 MSIFILEPATCH *patch; 00690 00691 /* FIXME: There might be more than one patch */ 00692 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry ) 00693 { 00694 if (!strcmpW( key, patch->File->File )) return patch; 00695 } 00696 return NULL; 00697 } 00698 00699 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir ) 00700 { 00701 MSIFOLDER *folder; 00702 00703 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry ) 00704 { 00705 if (!strcmpW( dir, folder->Directory )) return folder; 00706 } 00707 return NULL; 00708 } 00709 00710 /* 00711 * Recursively create all directories in the path. 00712 * shamelessly stolen from setupapi/queue.c 00713 */ 00714 BOOL msi_create_full_path( const WCHAR *path ) 00715 { 00716 BOOL ret = TRUE; 00717 WCHAR *new_path; 00718 int len; 00719 00720 new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) ); 00721 strcpyW( new_path, path ); 00722 00723 while ((len = strlenW( new_path )) && new_path[len - 1] == '\\') 00724 new_path[len - 1] = 0; 00725 00726 while (!CreateDirectoryW( new_path, NULL )) 00727 { 00728 WCHAR *slash; 00729 DWORD last_error = GetLastError(); 00730 if (last_error == ERROR_ALREADY_EXISTS) break; 00731 if (last_error != ERROR_PATH_NOT_FOUND) 00732 { 00733 ret = FALSE; 00734 break; 00735 } 00736 if (!(slash = strrchrW( new_path, '\\' ))) 00737 { 00738 ret = FALSE; 00739 break; 00740 } 00741 len = slash - new_path; 00742 new_path[len] = 0; 00743 if (!msi_create_full_path( new_path )) 00744 { 00745 ret = FALSE; 00746 break; 00747 } 00748 new_path[len] = '\\'; 00749 } 00750 msi_free( new_path ); 00751 return ret; 00752 } 00753 00754 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d ) 00755 { 00756 MSIRECORD *row; 00757 00758 row = MSI_CreateRecord( 4 ); 00759 MSI_RecordSetInteger( row, 1, a ); 00760 MSI_RecordSetInteger( row, 2, b ); 00761 MSI_RecordSetInteger( row, 3, c ); 00762 MSI_RecordSetInteger( row, 4, d ); 00763 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row ); 00764 msiobj_release( &row->hdr ); 00765 00766 msi_dialog_check_messages( NULL ); 00767 } 00768 00769 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record ) 00770 { 00771 static const WCHAR query[] = 00772 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 00773 '`','A','c','t','i','o', 'n','T','e','x','t','`',' ', 00774 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0}; 00775 WCHAR message[1024]; 00776 MSIRECORD *row = 0; 00777 DWORD size; 00778 00779 if (!package->LastAction || strcmpW( package->LastAction, action )) 00780 { 00781 if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return; 00782 00783 if (MSI_RecordIsNull( row, 3 )) 00784 { 00785 msiobj_release( &row->hdr ); 00786 return; 00787 } 00788 /* update the cached action format */ 00789 msi_free( package->ActionFormat ); 00790 package->ActionFormat = msi_dup_record_field( row, 3 ); 00791 msi_free( package->LastAction ); 00792 package->LastAction = strdupW( action ); 00793 msiobj_release( &row->hdr ); 00794 } 00795 size = 1024; 00796 MSI_RecordSetStringW( record, 0, package->ActionFormat ); 00797 MSI_FormatRecordW( package, record, message, &size ); 00798 row = MSI_CreateRecord( 1 ); 00799 MSI_RecordSetStringW( row, 1, message ); 00800 MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row ); 00801 msiobj_release( &row->hdr ); 00802 } 00803 00804 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp ) 00805 { 00806 if (!comp->Enabled) 00807 { 00808 TRACE("component is disabled: %s\n", debugstr_w(comp->Component)); 00809 return INSTALLSTATE_UNKNOWN; 00810 } 00811 if (package->need_rollback) return comp->Installed; 00812 return comp->ActionRequest; 00813 } 00814 00815 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature ) 00816 { 00817 if (package->need_rollback) return feature->Installed; 00818 return feature->ActionRequest; 00819 } 00820 00821 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param) 00822 { 00823 MSIPACKAGE *package = param; 00824 LPCWSTR dir, component, full_path; 00825 MSIRECORD *uirow; 00826 MSIFOLDER *folder; 00827 MSICOMPONENT *comp; 00828 00829 component = MSI_RecordGetString(row, 2); 00830 if (!component) 00831 return ERROR_SUCCESS; 00832 00833 comp = msi_get_loaded_component(package, component); 00834 if (!comp) 00835 return ERROR_SUCCESS; 00836 00837 comp->Action = msi_get_component_action( package, comp ); 00838 if (comp->Action != INSTALLSTATE_LOCAL) 00839 { 00840 TRACE("component not scheduled for installation: %s\n", debugstr_w(component)); 00841 return ERROR_SUCCESS; 00842 } 00843 00844 dir = MSI_RecordGetString(row,1); 00845 if (!dir) 00846 { 00847 ERR("Unable to get folder id\n"); 00848 return ERROR_SUCCESS; 00849 } 00850 00851 uirow = MSI_CreateRecord(1); 00852 MSI_RecordSetStringW(uirow, 1, dir); 00853 msi_ui_actiondata(package, szCreateFolders, uirow); 00854 msiobj_release(&uirow->hdr); 00855 00856 full_path = msi_get_target_folder( package, dir ); 00857 if (!full_path) 00858 { 00859 ERR("Unable to retrieve folder %s\n", debugstr_w(dir)); 00860 return ERROR_SUCCESS; 00861 } 00862 TRACE("folder is %s\n", debugstr_w(full_path)); 00863 00864 folder = msi_get_loaded_folder( package, dir ); 00865 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path ); 00866 folder->State = FOLDER_STATE_CREATED; 00867 return ERROR_SUCCESS; 00868 } 00869 00870 static UINT ACTION_CreateFolders(MSIPACKAGE *package) 00871 { 00872 static const WCHAR query[] = { 00873 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 00874 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0}; 00875 MSIQUERY *view; 00876 UINT rc; 00877 00878 rc = MSI_DatabaseOpenViewW( package->db, query, &view ); 00879 if (rc != ERROR_SUCCESS) 00880 return ERROR_SUCCESS; 00881 00882 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package); 00883 msiobj_release(&view->hdr); 00884 return rc; 00885 } 00886 00887 static void remove_persistent_folder( MSIFOLDER *folder ) 00888 { 00889 FolderList *fl; 00890 00891 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry ) 00892 { 00893 remove_persistent_folder( fl->folder ); 00894 } 00895 if (folder->persistent && folder->State != FOLDER_STATE_REMOVED) 00896 { 00897 if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED; 00898 } 00899 } 00900 00901 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param ) 00902 { 00903 MSIPACKAGE *package = param; 00904 LPCWSTR dir, component, full_path; 00905 MSIRECORD *uirow; 00906 MSIFOLDER *folder; 00907 MSICOMPONENT *comp; 00908 00909 component = MSI_RecordGetString(row, 2); 00910 if (!component) 00911 return ERROR_SUCCESS; 00912 00913 comp = msi_get_loaded_component(package, component); 00914 if (!comp) 00915 return ERROR_SUCCESS; 00916 00917 comp->Action = msi_get_component_action( package, comp ); 00918 if (comp->Action != INSTALLSTATE_ABSENT) 00919 { 00920 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 00921 return ERROR_SUCCESS; 00922 } 00923 00924 dir = MSI_RecordGetString( row, 1 ); 00925 if (!dir) 00926 { 00927 ERR("Unable to get folder id\n"); 00928 return ERROR_SUCCESS; 00929 } 00930 00931 full_path = msi_get_target_folder( package, dir ); 00932 if (!full_path) 00933 { 00934 ERR("Unable to resolve folder %s\n", debugstr_w(dir)); 00935 return ERROR_SUCCESS; 00936 } 00937 TRACE("folder is %s\n", debugstr_w(full_path)); 00938 00939 uirow = MSI_CreateRecord( 1 ); 00940 MSI_RecordSetStringW( uirow, 1, dir ); 00941 msi_ui_actiondata( package, szRemoveFolders, uirow ); 00942 msiobj_release( &uirow->hdr ); 00943 00944 folder = msi_get_loaded_folder( package, dir ); 00945 remove_persistent_folder( folder ); 00946 return ERROR_SUCCESS; 00947 } 00948 00949 static UINT ACTION_RemoveFolders( MSIPACKAGE *package ) 00950 { 00951 static const WCHAR query[] = { 00952 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 00953 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0}; 00954 MSIQUERY *view; 00955 UINT rc; 00956 00957 rc = MSI_DatabaseOpenViewW( package->db, query, &view ); 00958 if (rc != ERROR_SUCCESS) 00959 return ERROR_SUCCESS; 00960 00961 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package ); 00962 msiobj_release( &view->hdr ); 00963 return rc; 00964 } 00965 00966 static UINT load_component( MSIRECORD *row, LPVOID param ) 00967 { 00968 MSIPACKAGE *package = param; 00969 MSICOMPONENT *comp; 00970 00971 comp = msi_alloc_zero( sizeof(MSICOMPONENT) ); 00972 if (!comp) 00973 return ERROR_FUNCTION_FAILED; 00974 00975 list_add_tail( &package->components, &comp->entry ); 00976 00977 /* fill in the data */ 00978 comp->Component = msi_dup_record_field( row, 1 ); 00979 00980 TRACE("Loading Component %s\n", debugstr_w(comp->Component)); 00981 00982 comp->ComponentId = msi_dup_record_field( row, 2 ); 00983 comp->Directory = msi_dup_record_field( row, 3 ); 00984 comp->Attributes = MSI_RecordGetInteger(row,4); 00985 comp->Condition = msi_dup_record_field( row, 5 ); 00986 comp->KeyPath = msi_dup_record_field( row, 6 ); 00987 00988 comp->Installed = INSTALLSTATE_UNKNOWN; 00989 comp->Action = INSTALLSTATE_UNKNOWN; 00990 comp->ActionRequest = INSTALLSTATE_UNKNOWN; 00991 00992 comp->assembly = msi_load_assembly( package, comp ); 00993 return ERROR_SUCCESS; 00994 } 00995 00996 UINT msi_load_all_components( MSIPACKAGE *package ) 00997 { 00998 static const WCHAR query[] = { 00999 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 01000 '`','C','o','m','p','o','n','e','n','t','`',0}; 01001 MSIQUERY *view; 01002 UINT r; 01003 01004 if (!list_empty(&package->components)) 01005 return ERROR_SUCCESS; 01006 01007 r = MSI_DatabaseOpenViewW( package->db, query, &view ); 01008 if (r != ERROR_SUCCESS) 01009 return r; 01010 01011 if (!msi_init_assembly_caches( package )) 01012 { 01013 ERR("can't initialize assembly caches\n"); 01014 msiobj_release( &view->hdr ); 01015 return ERROR_FUNCTION_FAILED; 01016 } 01017 01018 r = MSI_IterateRecords(view, NULL, load_component, package); 01019 msiobj_release(&view->hdr); 01020 msi_destroy_assembly_caches( package ); 01021 return r; 01022 } 01023 01024 typedef struct { 01025 MSIPACKAGE *package; 01026 MSIFEATURE *feature; 01027 } _ilfs; 01028 01029 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp ) 01030 { 01031 ComponentList *cl; 01032 01033 cl = msi_alloc( sizeof (*cl) ); 01034 if ( !cl ) 01035 return ERROR_NOT_ENOUGH_MEMORY; 01036 cl->component = comp; 01037 list_add_tail( &feature->Components, &cl->entry ); 01038 01039 return ERROR_SUCCESS; 01040 } 01041 01042 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child ) 01043 { 01044 FeatureList *fl; 01045 01046 fl = msi_alloc( sizeof(*fl) ); 01047 if ( !fl ) 01048 return ERROR_NOT_ENOUGH_MEMORY; 01049 fl->feature = child; 01050 list_add_tail( &parent->Children, &fl->entry ); 01051 01052 return ERROR_SUCCESS; 01053 } 01054 01055 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param) 01056 { 01057 _ilfs* ilfs = param; 01058 LPCWSTR component; 01059 MSICOMPONENT *comp; 01060 01061 component = MSI_RecordGetString(row,1); 01062 01063 /* check to see if the component is already loaded */ 01064 comp = msi_get_loaded_component( ilfs->package, component ); 01065 if (!comp) 01066 { 01067 WARN("ignoring unknown component %s\n", debugstr_w(component)); 01068 return ERROR_SUCCESS; 01069 } 01070 add_feature_component( ilfs->feature, comp ); 01071 comp->Enabled = TRUE; 01072 01073 return ERROR_SUCCESS; 01074 } 01075 01076 static UINT load_feature(MSIRECORD * row, LPVOID param) 01077 { 01078 static const WCHAR query[] = { 01079 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`', 01080 ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e', 01081 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ', 01082 '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0}; 01083 MSIPACKAGE *package = param; 01084 MSIFEATURE *feature; 01085 MSIQUERY *view; 01086 _ilfs ilfs; 01087 UINT rc; 01088 01089 /* fill in the data */ 01090 01091 feature = msi_alloc_zero( sizeof (MSIFEATURE) ); 01092 if (!feature) 01093 return ERROR_NOT_ENOUGH_MEMORY; 01094 01095 list_init( &feature->Children ); 01096 list_init( &feature->Components ); 01097 01098 feature->Feature = msi_dup_record_field( row, 1 ); 01099 01100 TRACE("Loading feature %s\n",debugstr_w(feature->Feature)); 01101 01102 feature->Feature_Parent = msi_dup_record_field( row, 2 ); 01103 feature->Title = msi_dup_record_field( row, 3 ); 01104 feature->Description = msi_dup_record_field( row, 4 ); 01105 01106 if (!MSI_RecordIsNull(row,5)) 01107 feature->Display = MSI_RecordGetInteger(row,5); 01108 01109 feature->Level= MSI_RecordGetInteger(row,6); 01110 feature->Directory = msi_dup_record_field( row, 7 ); 01111 feature->Attributes = MSI_RecordGetInteger(row,8); 01112 01113 feature->Installed = INSTALLSTATE_UNKNOWN; 01114 feature->Action = INSTALLSTATE_UNKNOWN; 01115 feature->ActionRequest = INSTALLSTATE_UNKNOWN; 01116 01117 list_add_tail( &package->features, &feature->entry ); 01118 01119 /* load feature components */ 01120 01121 rc = MSI_OpenQuery( package->db, &view, query, feature->Feature ); 01122 if (rc != ERROR_SUCCESS) 01123 return ERROR_SUCCESS; 01124 01125 ilfs.package = package; 01126 ilfs.feature = feature; 01127 01128 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs); 01129 msiobj_release(&view->hdr); 01130 return rc; 01131 } 01132 01133 static UINT find_feature_children(MSIRECORD * row, LPVOID param) 01134 { 01135 MSIPACKAGE *package = param; 01136 MSIFEATURE *parent, *child; 01137 01138 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) ); 01139 if (!child) 01140 return ERROR_FUNCTION_FAILED; 01141 01142 if (!child->Feature_Parent) 01143 return ERROR_SUCCESS; 01144 01145 parent = msi_get_loaded_feature( package, child->Feature_Parent ); 01146 if (!parent) 01147 return ERROR_FUNCTION_FAILED; 01148 01149 add_feature_child( parent, child ); 01150 return ERROR_SUCCESS; 01151 } 01152 01153 UINT msi_load_all_features( MSIPACKAGE *package ) 01154 { 01155 static const WCHAR query[] = { 01156 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 01157 '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ', 01158 '`','D','i','s','p','l','a','y','`',0}; 01159 MSIQUERY *view; 01160 UINT r; 01161 01162 if (!list_empty(&package->features)) 01163 return ERROR_SUCCESS; 01164 01165 r = MSI_DatabaseOpenViewW( package->db, query, &view ); 01166 if (r != ERROR_SUCCESS) 01167 return r; 01168 01169 r = MSI_IterateRecords( view, NULL, load_feature, package ); 01170 if (r != ERROR_SUCCESS) 01171 { 01172 msiobj_release( &view->hdr ); 01173 return r; 01174 } 01175 r = MSI_IterateRecords( view, NULL, find_feature_children, package ); 01176 msiobj_release( &view->hdr ); 01177 return r; 01178 } 01179 01180 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch) 01181 { 01182 if (!p) 01183 return p; 01184 p = strchrW(p, ch); 01185 if (!p) 01186 return p; 01187 *p = 0; 01188 return p+1; 01189 } 01190 01191 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file) 01192 { 01193 static const WCHAR query[] = { 01194 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', 01195 '`','M','s','i','F','i','l','e','H','a','s','h','`',' ', 01196 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0}; 01197 MSIQUERY *view = NULL; 01198 MSIRECORD *row = NULL; 01199 UINT r; 01200 01201 TRACE("%s\n", debugstr_w(file->File)); 01202 01203 r = MSI_OpenQuery(package->db, &view, query, file->File); 01204 if (r != ERROR_SUCCESS) 01205 goto done; 01206 01207 r = MSI_ViewExecute(view, NULL); 01208 if (r != ERROR_SUCCESS) 01209 goto done; 01210 01211 r = MSI_ViewFetch(view, &row); 01212 if (r != ERROR_SUCCESS) 01213 goto done; 01214 01215 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO); 01216 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3); 01217 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4); 01218 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5); 01219 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6); 01220 01221 done: 01222 if (view) msiobj_release(&view->hdr); 01223 if (row) msiobj_release(&row->hdr); 01224 return r; 01225 } 01226 01227 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file ) 01228 { 01229 MSIRECORD *row; 01230 static const WCHAR query[] = { 01231 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ', 01232 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ', 01233 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0}; 01234 01235 row = MSI_QueryGetRecord( package->db, query, file->Sequence ); 01236 if (!row) 01237 { 01238 WARN("query failed\n"); 01239 return ERROR_FUNCTION_FAILED; 01240 } 01241 01242 file->disk_id = MSI_RecordGetInteger( row, 1 ); 01243 msiobj_release( &row->hdr ); 01244 return ERROR_SUCCESS; 01245 } 01246 01247 static UINT load_file(MSIRECORD *row, LPVOID param) 01248 { 01249 MSIPACKAGE* package = param; 01250 LPCWSTR component; 01251 MSIFILE *file; 01252 01253 /* fill in the data */ 01254 01255 file = msi_alloc_zero( sizeof (MSIFILE) ); 01256 if (!file) 01257 return ERROR_NOT_ENOUGH_MEMORY; 01258 01259 file->File = msi_dup_record_field( row, 1 ); 01260 01261 component = MSI_RecordGetString( row, 2 ); 01262 file->Component = msi_get_loaded_component( package, component ); 01263 01264 if (!file->Component) 01265 { 01266 WARN("Component not found: %s\n", debugstr_w(component)); 01267 msi_free(file->File); 01268 msi_free(file); 01269 return ERROR_SUCCESS; 01270 } 01271 01272 file->FileName = msi_dup_record_field( row, 3 ); 01273 msi_reduce_to_long_filename( file->FileName ); 01274 01275 file->ShortName = msi_dup_record_field( row, 3 ); 01276 file->LongName = strdupW( folder_split_path(file->ShortName, '|')); 01277 01278 file->FileSize = MSI_RecordGetInteger( row, 4 ); 01279 file->Version = msi_dup_record_field( row, 5 ); 01280 file->Language = msi_dup_record_field( row, 6 ); 01281 file->Attributes = MSI_RecordGetInteger( row, 7 ); 01282 file->Sequence = MSI_RecordGetInteger( row, 8 ); 01283 01284 file->state = msifs_invalid; 01285 01286 /* if the compressed bits are not set in the file attributes, 01287 * then read the information from the package word count property 01288 */ 01289 if (package->WordCount & msidbSumInfoSourceTypeAdminImage) 01290 { 01291 file->IsCompressed = FALSE; 01292 } 01293 else if (file->Attributes & 01294 (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded)) 01295 { 01296 file->IsCompressed = TRUE; 01297 } 01298 else if (file->Attributes & msidbFileAttributesNoncompressed) 01299 { 01300 file->IsCompressed = FALSE; 01301 } 01302 else 01303 { 01304 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed; 01305 } 01306 01307 load_file_hash(package, file); 01308 load_file_disk_id(package, file); 01309 01310 TRACE("File Loaded (%s)\n",debugstr_w(file->File)); 01311 01312 list_add_tail( &package->files, &file->entry ); 01313 01314 return ERROR_SUCCESS; 01315 } 01316 01317 static UINT load_all_files(MSIPACKAGE *package) 01318 { 01319 static const WCHAR query[] = { 01320 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', 01321 '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ', 01322 '`','S','e','q','u','e','n','c','e','`', 0}; 01323 MSIQUERY *view; 01324 UINT rc; 01325 01326 if (!list_empty(&package->files)) 01327 return ERROR_SUCCESS; 01328 01329 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 01330 if (rc != ERROR_SUCCESS) 01331 return ERROR_SUCCESS; 01332 01333 rc = MSI_IterateRecords(view, NULL, load_file, package); 01334 msiobj_release(&view->hdr); 01335 return rc; 01336 } 01337 01338 static UINT load_media( MSIRECORD *row, LPVOID param ) 01339 { 01340 MSIPACKAGE *package = param; 01341 UINT disk_id = MSI_RecordGetInteger( row, 1 ); 01342 const WCHAR *cabinet = MSI_RecordGetString( row, 4 ); 01343 01344 /* FIXME: load external cabinets and directory sources too */ 01345 if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS; 01346 msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet ); 01347 return ERROR_SUCCESS; 01348 } 01349 01350 static UINT load_all_media( MSIPACKAGE *package ) 01351 { 01352 static const WCHAR query[] = { 01353 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`', 01354 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ', 01355 '`','D','i','s','k','I','d','`',0}; 01356 MSIQUERY *view; 01357 UINT r; 01358 01359 r = MSI_DatabaseOpenViewW( package->db, query, &view ); 01360 if (r != ERROR_SUCCESS) 01361 return ERROR_SUCCESS; 01362 01363 r = MSI_IterateRecords( view, NULL, load_media, package ); 01364 msiobj_release( &view->hdr ); 01365 return r; 01366 } 01367 01368 static UINT load_patch(MSIRECORD *row, LPVOID param) 01369 { 01370 MSIPACKAGE *package = param; 01371 MSIFILEPATCH *patch; 01372 LPWSTR file_key; 01373 01374 patch = msi_alloc_zero( sizeof (MSIFILEPATCH) ); 01375 if (!patch) 01376 return ERROR_NOT_ENOUGH_MEMORY; 01377 01378 file_key = msi_dup_record_field( row, 1 ); 01379 patch->File = msi_get_loaded_file( package, file_key ); 01380 msi_free(file_key); 01381 01382 if( !patch->File ) 01383 { 01384 ERR("Failed to find target for patch in File table\n"); 01385 msi_free(patch); 01386 return ERROR_FUNCTION_FAILED; 01387 } 01388 01389 patch->Sequence = MSI_RecordGetInteger( row, 2 ); 01390 01391 /* FIXME: The database should be properly transformed */ 01392 patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET; 01393 01394 patch->PatchSize = MSI_RecordGetInteger( row, 3 ); 01395 patch->Attributes = MSI_RecordGetInteger( row, 4 ); 01396 patch->IsApplied = FALSE; 01397 01398 /* FIXME: 01399 * Header field - for patch validation. 01400 * _StreamRef - External key into MsiPatchHeaders (instead of the header field) 01401 */ 01402 01403 TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File)); 01404 01405 list_add_tail( &package->filepatches, &patch->entry ); 01406 01407 return ERROR_SUCCESS; 01408 } 01409 01410 static UINT load_all_patches(MSIPACKAGE *package) 01411 { 01412 static const WCHAR query[] = { 01413 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 01414 '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ', 01415 '`','S','e','q','u','e','n','c','e','`',0}; 01416 MSIQUERY *view; 01417 UINT rc; 01418 01419 if (!list_empty(&package->filepatches)) 01420 return ERROR_SUCCESS; 01421 01422 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 01423 if (rc != ERROR_SUCCESS) 01424 return ERROR_SUCCESS; 01425 01426 rc = MSI_IterateRecords(view, NULL, load_patch, package); 01427 msiobj_release(&view->hdr); 01428 return rc; 01429 } 01430 01431 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder ) 01432 { 01433 static const WCHAR query[] = { 01434 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 01435 '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ', 01436 '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0}; 01437 MSIQUERY *view; 01438 01439 folder->persistent = FALSE; 01440 if (!MSI_OpenQuery( package->db, &view, query, folder->Directory )) 01441 { 01442 if (!MSI_ViewExecute( view, NULL )) 01443 { 01444 MSIRECORD *rec; 01445 if (!MSI_ViewFetch( view, &rec )) 01446 { 01447 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory)); 01448 folder->persistent = TRUE; 01449 msiobj_release( &rec->hdr ); 01450 } 01451 } 01452 msiobj_release( &view->hdr ); 01453 } 01454 return ERROR_SUCCESS; 01455 } 01456 01457 static UINT load_folder( MSIRECORD *row, LPVOID param ) 01458 { 01459 MSIPACKAGE *package = param; 01460 static WCHAR szEmpty[] = { 0 }; 01461 LPWSTR p, tgt_short, tgt_long, src_short, src_long; 01462 MSIFOLDER *folder; 01463 01464 if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY; 01465 list_init( &folder->children ); 01466 folder->Directory = msi_dup_record_field( row, 1 ); 01467 folder->Parent = msi_dup_record_field( row, 2 ); 01468 p = msi_dup_record_field(row, 3); 01469 01470 TRACE("%s\n", debugstr_w(folder->Directory)); 01471 01472 /* split src and target dir */ 01473 tgt_short = p; 01474 src_short = folder_split_path( p, ':' ); 01475 01476 /* split the long and short paths */ 01477 tgt_long = folder_split_path( tgt_short, '|' ); 01478 src_long = folder_split_path( src_short, '|' ); 01479 01480 /* check for no-op dirs */ 01481 if (tgt_short && !strcmpW( szDot, tgt_short )) 01482 tgt_short = szEmpty; 01483 if (src_short && !strcmpW( szDot, src_short )) 01484 src_short = szEmpty; 01485 01486 if (!tgt_long) 01487 tgt_long = tgt_short; 01488 01489 if (!src_short) { 01490 src_short = tgt_short; 01491 src_long = tgt_long; 01492 } 01493 01494 if (!src_long) 01495 src_long = src_short; 01496 01497 /* FIXME: use the target short path too */ 01498 folder->TargetDefault = strdupW(tgt_long); 01499 folder->SourceShortPath = strdupW(src_short); 01500 folder->SourceLongPath = strdupW(src_long); 01501 msi_free(p); 01502 01503 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault )); 01504 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath )); 01505 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath )); 01506 01507 load_folder_persistence( package, folder ); 01508 01509 list_add_tail( &package->folders, &folder->entry ); 01510 return ERROR_SUCCESS; 01511 } 01512 01513 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child ) 01514 { 01515 FolderList *fl; 01516 01517 if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY; 01518 fl->folder = child; 01519 list_add_tail( &parent->children, &fl->entry ); 01520 return ERROR_SUCCESS; 01521 } 01522 01523 static UINT find_folder_children( MSIRECORD *row, LPVOID param ) 01524 { 01525 MSIPACKAGE *package = param; 01526 MSIFOLDER *parent, *child; 01527 01528 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) ))) 01529 return ERROR_FUNCTION_FAILED; 01530 01531 if (!child->Parent) return ERROR_SUCCESS; 01532 01533 if (!(parent = msi_get_loaded_folder( package, child->Parent ))) 01534 return ERROR_FUNCTION_FAILED; 01535 01536 return add_folder_child( parent, child ); 01537 } 01538 01539 static UINT load_all_folders( MSIPACKAGE *package ) 01540 { 01541 static const WCHAR query[] = { 01542 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 01543 '`','D','i','r','e','c','t','o','r','y','`',0}; 01544 MSIQUERY *view; 01545 UINT r; 01546 01547 if (!list_empty(&package->folders)) 01548 return ERROR_SUCCESS; 01549 01550 r = MSI_DatabaseOpenViewW( package->db, query, &view ); 01551 if (r != ERROR_SUCCESS) 01552 return r; 01553 01554 r = MSI_IterateRecords( view, NULL, load_folder, package ); 01555 if (r != ERROR_SUCCESS) 01556 { 01557 msiobj_release( &view->hdr ); 01558 return r; 01559 } 01560 r = MSI_IterateRecords( view, NULL, find_folder_children, package ); 01561 msiobj_release( &view->hdr ); 01562 return r; 01563 } 01564 01565 static UINT ACTION_CostInitialize(MSIPACKAGE *package) 01566 { 01567 msi_set_property( package->db, szCostingComplete, szZero ); 01568 msi_set_property( package->db, szRootDrive, szCRoot ); 01569 01570 load_all_folders( package ); 01571 msi_load_all_components( package ); 01572 msi_load_all_features( package ); 01573 load_all_files( package ); 01574 load_all_patches( package ); 01575 load_all_media( package ); 01576 01577 return ERROR_SUCCESS; 01578 } 01579 01580 static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index ) 01581 { 01582 const WCHAR *action = package->script->Actions[script][index]; 01583 ui_actionstart( package, action ); 01584 TRACE("executing %s\n", debugstr_w(action)); 01585 return ACTION_PerformAction( package, action, script ); 01586 } 01587 01588 static UINT execute_script( MSIPACKAGE *package, UINT script ) 01589 { 01590 UINT i, rc = ERROR_SUCCESS; 01591 01592 TRACE("executing script %u\n", script); 01593 01594 if (!package->script) 01595 { 01596 ERR("no script!\n"); 01597 return ERROR_FUNCTION_FAILED; 01598 } 01599 if (script == SCRIPT_ROLLBACK) 01600 { 01601 for (i = package->script->ActionCount[script]; i > 0; i--) 01602 { 01603 rc = execute_script_action( package, script, i - 1 ); 01604 if (rc != ERROR_SUCCESS) break; 01605 } 01606 } 01607 else 01608 { 01609 for (i = 0; i < package->script->ActionCount[script]; i++) 01610 { 01611 rc = execute_script_action( package, script, i ); 01612 if (rc != ERROR_SUCCESS) break; 01613 } 01614 } 01615 msi_free_action_script(package, script); 01616 return rc; 01617 } 01618 01619 static UINT ACTION_FileCost(MSIPACKAGE *package) 01620 { 01621 return ERROR_SUCCESS; 01622 } 01623 01624 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package) 01625 { 01626 MSICOMPONENT *comp; 01627 UINT r; 01628 01629 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry) 01630 { 01631 if (!comp->ComponentId) continue; 01632 01633 r = MsiQueryComponentStateW( package->ProductCode, NULL, 01634 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId, 01635 &comp->Installed ); 01636 if (r == ERROR_SUCCESS) continue; 01637 01638 r = MsiQueryComponentStateW( package->ProductCode, NULL, 01639 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId, 01640 &comp->Installed ); 01641 if (r == ERROR_SUCCESS) continue; 01642 01643 r = MsiQueryComponentStateW( package->ProductCode, NULL, 01644 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId, 01645 &comp->Installed ); 01646 if (r == ERROR_SUCCESS) continue; 01647 01648 comp->Installed = INSTALLSTATE_ABSENT; 01649 } 01650 } 01651 01652 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package) 01653 { 01654 MSIFEATURE *feature; 01655 01656 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 01657 { 01658 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature ); 01659 01660 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG) 01661 feature->Installed = INSTALLSTATE_ABSENT; 01662 else 01663 feature->Installed = state; 01664 } 01665 } 01666 01667 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level ) 01668 { 01669 return (feature->Level > 0 && feature->Level <= level); 01670 } 01671 01672 static BOOL process_state_property(MSIPACKAGE* package, int level, 01673 LPCWSTR property, INSTALLSTATE state) 01674 { 01675 LPWSTR override; 01676 MSIFEATURE *feature; 01677 01678 override = msi_dup_property( package->db, property ); 01679 if (!override) 01680 return FALSE; 01681 01682 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 01683 { 01684 if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level )) 01685 continue; 01686 01687 if (!strcmpW(property, szReinstall)) state = feature->Installed; 01688 01689 if (!strcmpiW( override, szAll )) 01690 { 01691 if (feature->Installed != state) 01692 { 01693 feature->Action = state; 01694 feature->ActionRequest = state; 01695 } 01696 } 01697 else 01698 { 01699 LPWSTR ptr = override; 01700 LPWSTR ptr2 = strchrW(override,','); 01701 01702 while (ptr) 01703 { 01704 int len = ptr2 - ptr; 01705 01706 if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len)) 01707 || (!ptr2 && !strcmpW(ptr, feature->Feature))) 01708 { 01709 if (feature->Installed != state) 01710 { 01711 feature->Action = state; 01712 feature->ActionRequest = state; 01713 } 01714 break; 01715 } 01716 if (ptr2) 01717 { 01718 ptr=ptr2+1; 01719 ptr2 = strchrW(ptr,','); 01720 } 01721 else 01722 break; 01723 } 01724 } 01725 } 01726 msi_free(override); 01727 return TRUE; 01728 } 01729 01730 static BOOL process_overrides( MSIPACKAGE *package, int level ) 01731 { 01732 static const WCHAR szAddLocal[] = 01733 {'A','D','D','L','O','C','A','L',0}; 01734 static const WCHAR szAddSource[] = 01735 {'A','D','D','S','O','U','R','C','E',0}; 01736 static const WCHAR szAdvertise[] = 01737 {'A','D','V','E','R','T','I','S','E',0}; 01738 BOOL ret = FALSE; 01739 01740 /* all these activation/deactivation things happen in order and things 01741 * later on the list override things earlier on the list. 01742 * 01743 * 0 INSTALLLEVEL processing 01744 * 1 ADDLOCAL 01745 * 2 REMOVE 01746 * 3 ADDSOURCE 01747 * 4 ADDDEFAULT 01748 * 5 REINSTALL 01749 * 6 ADVERTISE 01750 * 7 COMPADDLOCAL 01751 * 8 COMPADDSOURCE 01752 * 9 FILEADDLOCAL 01753 * 10 FILEADDSOURCE 01754 * 11 FILEADDDEFAULT 01755 */ 01756 ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL ); 01757 ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT ); 01758 ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE ); 01759 ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN ); 01760 ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED ); 01761 01762 if (ret) 01763 msi_set_property( package->db, szPreselected, szOne ); 01764 01765 return ret; 01766 } 01767 01768 UINT MSI_SetFeatureStates(MSIPACKAGE *package) 01769 { 01770 int level; 01771 MSICOMPONENT* component; 01772 MSIFEATURE *feature; 01773 01774 TRACE("Checking Install Level\n"); 01775 01776 level = msi_get_property_int(package->db, szInstallLevel, 1); 01777 01778 if (!msi_get_property_int( package->db, szPreselected, 0 )) 01779 { 01780 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 01781 { 01782 if (!is_feature_selected( feature, level )) continue; 01783 01784 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN) 01785 { 01786 if (feature->Attributes & msidbFeatureAttributesFavorSource) 01787 { 01788 feature->Action = INSTALLSTATE_SOURCE; 01789 feature->ActionRequest = INSTALLSTATE_SOURCE; 01790 } 01791 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise) 01792 { 01793 feature->Action = INSTALLSTATE_ADVERTISED; 01794 feature->ActionRequest = INSTALLSTATE_ADVERTISED; 01795 } 01796 else 01797 { 01798 feature->Action = INSTALLSTATE_LOCAL; 01799 feature->ActionRequest = INSTALLSTATE_LOCAL; 01800 } 01801 } 01802 } 01803 /* disable child features of unselected parent or follow parent */ 01804 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 01805 { 01806 FeatureList *fl; 01807 01808 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry ) 01809 { 01810 if (!is_feature_selected( feature, level )) 01811 { 01812 fl->feature->Action = INSTALLSTATE_UNKNOWN; 01813 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN; 01814 } 01815 else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent) 01816 { 01817 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n", 01818 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest, 01819 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest); 01820 fl->feature->Action = feature->Action; 01821 fl->feature->ActionRequest = feature->ActionRequest; 01822 } 01823 } 01824 } 01825 } 01826 else /* preselected */ 01827 { 01828 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 01829 { 01830 if (!is_feature_selected( feature, level )) continue; 01831 01832 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN) 01833 { 01834 if (feature->Installed == INSTALLSTATE_ABSENT) 01835 { 01836 feature->Action = INSTALLSTATE_UNKNOWN; 01837 feature->ActionRequest = INSTALLSTATE_UNKNOWN; 01838 } 01839 else 01840 { 01841 feature->Action = feature->Installed; 01842 feature->ActionRequest = feature->Installed; 01843 } 01844 } 01845 } 01846 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 01847 { 01848 FeatureList *fl; 01849 01850 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry ) 01851 { 01852 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent && 01853 (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise))) 01854 { 01855 TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n", 01856 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest, 01857 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest); 01858 fl->feature->Action = feature->Action; 01859 fl->feature->ActionRequest = feature->ActionRequest; 01860 } 01861 } 01862 } 01863 } 01864 01865 /* now we want to set component state based based on feature state */ 01866 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 01867 { 01868 ComponentList *cl; 01869 01870 TRACE("examining feature %s (level %d installed %d request %d action %d)\n", 01871 debugstr_w(feature->Feature), feature->Level, feature->Installed, 01872 feature->ActionRequest, feature->Action); 01873 01874 if (!is_feature_selected( feature, level )) continue; 01875 01876 /* features with components that have compressed files are made local */ 01877 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) 01878 { 01879 if (cl->component->ForceLocalState && 01880 feature->ActionRequest == INSTALLSTATE_SOURCE) 01881 { 01882 feature->Action = INSTALLSTATE_LOCAL; 01883 feature->ActionRequest = INSTALLSTATE_LOCAL; 01884 break; 01885 } 01886 } 01887 01888 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) 01889 { 01890 component = cl->component; 01891 01892 switch (feature->ActionRequest) 01893 { 01894 case INSTALLSTATE_ABSENT: 01895 component->anyAbsent = 1; 01896 break; 01897 case INSTALLSTATE_ADVERTISED: 01898 component->hasAdvertiseFeature = 1; 01899 break; 01900 case INSTALLSTATE_SOURCE: 01901 component->hasSourceFeature = 1; 01902 break; 01903 case INSTALLSTATE_LOCAL: 01904 component->hasLocalFeature = 1; 01905 break; 01906 case INSTALLSTATE_DEFAULT: 01907 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise) 01908 component->hasAdvertiseFeature = 1; 01909 else if (feature->Attributes & msidbFeatureAttributesFavorSource) 01910 component->hasSourceFeature = 1; 01911 else 01912 component->hasLocalFeature = 1; 01913 break; 01914 default: 01915 break; 01916 } 01917 } 01918 } 01919 01920 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry ) 01921 { 01922 /* check if it's local or source */ 01923 if (!(component->Attributes & msidbComponentAttributesOptional) && 01924 (component->hasLocalFeature || component->hasSourceFeature)) 01925 { 01926 if ((component->Attributes & msidbComponentAttributesSourceOnly) && 01927 !component->ForceLocalState) 01928 { 01929 component->Action = INSTALLSTATE_SOURCE; 01930 component->ActionRequest = INSTALLSTATE_SOURCE; 01931 } 01932 else 01933 { 01934 component->Action = INSTALLSTATE_LOCAL; 01935 component->ActionRequest = INSTALLSTATE_LOCAL; 01936 } 01937 continue; 01938 } 01939 01940 /* if any feature is local, the component must be local too */ 01941 if (component->hasLocalFeature) 01942 { 01943 component->Action = INSTALLSTATE_LOCAL; 01944 component->ActionRequest = INSTALLSTATE_LOCAL; 01945 continue; 01946 } 01947 if (component->hasSourceFeature) 01948 { 01949 component->Action = INSTALLSTATE_SOURCE; 01950 component->ActionRequest = INSTALLSTATE_SOURCE; 01951 continue; 01952 } 01953 if (component->hasAdvertiseFeature) 01954 { 01955 component->Action = INSTALLSTATE_ADVERTISED; 01956 component->ActionRequest = INSTALLSTATE_ADVERTISED; 01957 continue; 01958 } 01959 TRACE("nobody wants component %s\n", debugstr_w(component->Component)); 01960 if (component->anyAbsent && 01961 (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE)) 01962 { 01963 component->Action = INSTALLSTATE_ABSENT; 01964 component->ActionRequest = INSTALLSTATE_ABSENT; 01965 } 01966 } 01967 01968 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry ) 01969 { 01970 if (component->ActionRequest == INSTALLSTATE_DEFAULT) 01971 { 01972 TRACE("%s was default, setting to local\n", debugstr_w(component->Component)); 01973 component->Action = INSTALLSTATE_LOCAL; 01974 component->ActionRequest = INSTALLSTATE_LOCAL; 01975 } 01976 01977 if (component->ActionRequest == INSTALLSTATE_SOURCE && 01978 component->Installed == INSTALLSTATE_SOURCE && 01979 component->hasSourceFeature) 01980 { 01981 component->Action = INSTALLSTATE_UNKNOWN; 01982 component->ActionRequest = INSTALLSTATE_UNKNOWN; 01983 } 01984 01985 TRACE("component %s (installed %d request %d action %d)\n", 01986 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action); 01987 } 01988 01989 return ERROR_SUCCESS; 01990 } 01991 01992 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param) 01993 { 01994 MSIPACKAGE *package = param; 01995 LPCWSTR name; 01996 MSIFEATURE *feature; 01997 01998 name = MSI_RecordGetString( row, 1 ); 01999 02000 feature = msi_get_loaded_feature( package, name ); 02001 if (!feature) 02002 ERR("FAILED to find loaded feature %s\n",debugstr_w(name)); 02003 else 02004 { 02005 LPCWSTR Condition; 02006 Condition = MSI_RecordGetString(row,3); 02007 02008 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE) 02009 { 02010 int level = MSI_RecordGetInteger(row,2); 02011 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level); 02012 feature->Level = level; 02013 } 02014 } 02015 return ERROR_SUCCESS; 02016 } 02017 02018 VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename ) 02019 { 02020 static const WCHAR name[] = {'\\',0}; 02021 VS_FIXEDFILEINFO *ptr, *ret; 02022 LPVOID version; 02023 DWORD versize, handle; 02024 UINT sz; 02025 02026 versize = GetFileVersionInfoSizeW( filename, &handle ); 02027 if (!versize) 02028 return NULL; 02029 02030 version = msi_alloc( versize ); 02031 if (!version) 02032 return NULL; 02033 02034 GetFileVersionInfoW( filename, 0, versize, version ); 02035 02036 if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz )) 02037 { 02038 msi_free( version ); 02039 return NULL; 02040 } 02041 02042 ret = msi_alloc( sz ); 02043 memcpy( ret, ptr, sz ); 02044 02045 msi_free( version ); 02046 return ret; 02047 } 02048 02049 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version ) 02050 { 02051 DWORD ms, ls; 02052 02053 msi_parse_version_string( version, &ms, &ls ); 02054 02055 if (fi->dwFileVersionMS > ms) return 1; 02056 else if (fi->dwFileVersionMS < ms) return -1; 02057 else if (fi->dwFileVersionLS > ls) return 1; 02058 else if (fi->dwFileVersionLS < ls) return -1; 02059 return 0; 02060 } 02061 02062 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 ) 02063 { 02064 DWORD ms1, ms2; 02065 02066 msi_parse_version_string( ver1, &ms1, NULL ); 02067 msi_parse_version_string( ver2, &ms2, NULL ); 02068 02069 if (ms1 > ms2) return 1; 02070 else if (ms1 < ms2) return -1; 02071 return 0; 02072 } 02073 02074 DWORD msi_get_disk_file_size( LPCWSTR filename ) 02075 { 02076 HANDLE file; 02077 DWORD size; 02078 02079 file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); 02080 if (file == INVALID_HANDLE_VALUE) 02081 return INVALID_FILE_SIZE; 02082 02083 size = GetFileSize( file, NULL ); 02084 TRACE("size is %u\n", size); 02085 CloseHandle( file ); 02086 return size; 02087 } 02088 02089 BOOL msi_file_hash_matches( MSIFILE *file ) 02090 { 02091 UINT r; 02092 MSIFILEHASHINFO hash; 02093 02094 hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO); 02095 r = MsiGetFileHashW( file->TargetPath, 0, &hash ); 02096 if (r != ERROR_SUCCESS) 02097 return FALSE; 02098 02099 return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) ); 02100 } 02101 02102 static WCHAR *get_temp_dir( void ) 02103 { 02104 static UINT id; 02105 WCHAR tmp[MAX_PATH], dir[MAX_PATH]; 02106 02107 GetTempPathW( MAX_PATH, tmp ); 02108 for (;;) 02109 { 02110 if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL; 02111 if (CreateDirectoryW( dir, NULL )) break; 02112 } 02113 return strdupW( dir ); 02114 } 02115 02116 /* 02117 * msi_build_directory_name() 02118 * 02119 * This function is to save messing round with directory names 02120 * It handles adding backslashes between path segments, 02121 * and can add \ at the end of the directory name if told to. 02122 * 02123 * It takes a variable number of arguments. 02124 * It always allocates a new string for the result, so make sure 02125 * to free the return value when finished with it. 02126 * 02127 * The first arg is the number of path segments that follow. 02128 * The arguments following count are a list of path segments. 02129 * A path segment may be NULL. 02130 * 02131 * Path segments will be added with a \ separating them. 02132 * A \ will not be added after the last segment, however if the 02133 * last segment is NULL, then the last character will be a \ 02134 */ 02135 WCHAR *msi_build_directory_name( DWORD count, ... ) 02136 { 02137 DWORD sz = 1, i; 02138 WCHAR *dir; 02139 va_list va; 02140 02141 va_start( va, count ); 02142 for (i = 0; i < count; i++) 02143 { 02144 const WCHAR *str = va_arg( va, const WCHAR * ); 02145 if (str) sz += strlenW( str ) + 1; 02146 } 02147 va_end( va ); 02148 02149 dir = msi_alloc( sz * sizeof(WCHAR) ); 02150 dir[0] = 0; 02151 02152 va_start( va, count ); 02153 for (i = 0; i < count; i++) 02154 { 02155 const WCHAR *str = va_arg( va, const WCHAR * ); 02156 if (!str) continue; 02157 strcatW( dir, str ); 02158 if ( i + 1 != count && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash ); 02159 } 02160 va_end( va ); 02161 return dir; 02162 } 02163 02164 static void set_target_path( MSIPACKAGE *package, MSIFILE *file ) 02165 { 02166 MSIASSEMBLY *assembly = file->Component->assembly; 02167 02168 TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName)); 02169 02170 msi_free( file->TargetPath ); 02171 if (assembly && !assembly->application) 02172 { 02173 if (!assembly->tempdir) assembly->tempdir = get_temp_dir(); 02174 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName ); 02175 msi_track_tempfile( package, file->TargetPath ); 02176 } 02177 else 02178 { 02179 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory ); 02180 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName ); 02181 } 02182 02183 TRACE("resolves to %s\n", debugstr_w(file->TargetPath)); 02184 } 02185 02186 static UINT calculate_file_cost( MSIPACKAGE *package ) 02187 { 02188 VS_FIXEDFILEINFO *file_version; 02189 WCHAR *font_version; 02190 MSIFILE *file; 02191 02192 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) 02193 { 02194 MSICOMPONENT *comp = file->Component; 02195 DWORD file_size; 02196 02197 if (!comp->Enabled) continue; 02198 02199 if (file->IsCompressed) 02200 comp->ForceLocalState = TRUE; 02201 02202 set_target_path( package, file ); 02203 02204 if ((comp->assembly && !comp->assembly->installed) || 02205 GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES) 02206 { 02207 comp->Cost += file->FileSize; 02208 continue; 02209 } 02210 file_size = msi_get_disk_file_size( file->TargetPath ); 02211 02212 if (file->Version) 02213 { 02214 if ((file_version = msi_get_disk_file_version( file->TargetPath ))) 02215 { 02216 if (msi_compare_file_versions( file_version, file->Version ) < 0) 02217 { 02218 comp->Cost += file->FileSize - file_size; 02219 } 02220 msi_free( file_version ); 02221 continue; 02222 } 02223 else if ((font_version = msi_font_version_from_file( file->TargetPath ))) 02224 { 02225 if (msi_compare_font_versions( font_version, file->Version ) < 0) 02226 { 02227 comp->Cost += file->FileSize - file_size; 02228 } 02229 msi_free( font_version ); 02230 continue; 02231 } 02232 } 02233 if (file_size != file->FileSize) 02234 { 02235 comp->Cost += file->FileSize - file_size; 02236 } 02237 } 02238 return ERROR_SUCCESS; 02239 } 02240 02241 WCHAR *msi_normalize_path( const WCHAR *in ) 02242 { 02243 const WCHAR *p = in; 02244 WCHAR *q, *ret; 02245 int n, len = strlenW( in ) + 2; 02246 02247 if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL; 02248 02249 len = 0; 02250 while (1) 02251 { 02252 /* copy until the end of the string or a space */ 02253 while (*p != ' ' && (*q = *p)) 02254 { 02255 p++, len++; 02256 /* reduce many backslashes to one */ 02257 if (*p != '\\' || *q != '\\') 02258 q++; 02259 } 02260 02261 /* quit at the end of the string */ 02262 if (!*p) 02263 break; 02264 02265 /* count the number of spaces */ 02266 n = 0; 02267 while (p[n] == ' ') 02268 n++; 02269 02270 /* if it's leading or trailing space, skip it */ 02271 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' ) 02272 p += n; 02273 else /* copy n spaces */ 02274 while (n && (*q++ = *p++)) n--; 02275 } 02276 while (q - ret > 0 && q[-1] == ' ') q--; 02277 if (q - ret > 0 && q[-1] != '\\') 02278 { 02279 q[0] = '\\'; 02280 q[1] = 0; 02281 } 02282 return ret; 02283 } 02284 02285 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop ) 02286 { 02287 FolderList *fl; 02288 MSIFOLDER *folder, *parent, *child; 02289 WCHAR *path, *normalized_path; 02290 02291 TRACE("resolving %s\n", debugstr_w(name)); 02292 02293 if (!(folder = msi_get_loaded_folder( package, name ))) return; 02294 02295 if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */ 02296 { 02297 if (!load_prop || !(path = msi_dup_property( package->db, szTargetDir ))) 02298 { 02299 path = msi_dup_property( package->db, szRootDrive ); 02300 } 02301 } 02302 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory ))) 02303 { 02304 if (folder->Parent && strcmpW( folder->Directory, folder->Parent )) 02305 { 02306 parent = msi_get_loaded_folder( package, folder->Parent ); 02307 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL ); 02308 } 02309 else 02310 path = msi_build_directory_name( 2, folder->TargetDefault, NULL ); 02311 } 02312 normalized_path = msi_normalize_path( path ); 02313 msi_free( path ); 02314 if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget )) 02315 { 02316 TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget)); 02317 msi_free( normalized_path ); 02318 return; 02319 } 02320 msi_set_property( package->db, folder->Directory, normalized_path ); 02321 msi_free( folder->ResolvedTarget ); 02322 folder->ResolvedTarget = normalized_path; 02323 02324 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry ) 02325 { 02326 child = fl->folder; 02327 msi_resolve_target_folder( package, child->Directory, load_prop ); 02328 } 02329 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget)); 02330 } 02331 02332 static UINT ACTION_CostFinalize(MSIPACKAGE *package) 02333 { 02334 static const WCHAR query[] = { 02335 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 02336 '`','C','o','n','d','i','t','i','o','n','`',0}; 02337 static const WCHAR szOutOfDiskSpace[] = { 02338 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0}; 02339 MSICOMPONENT *comp; 02340 MSIQUERY *view; 02341 LPWSTR level; 02342 UINT rc; 02343 02344 TRACE("Building directory properties\n"); 02345 msi_resolve_target_folder( package, szTargetDir, TRUE ); 02346 02347 TRACE("Evaluating component conditions\n"); 02348 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) 02349 { 02350 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE) 02351 { 02352 TRACE("Disabling component %s\n", debugstr_w(comp->Component)); 02353 comp->Enabled = FALSE; 02354 } 02355 else 02356 comp->Enabled = TRUE; 02357 } 02358 02359 /* read components states from the registry */ 02360 ACTION_GetComponentInstallStates(package); 02361 ACTION_GetFeatureInstallStates(package); 02362 02363 if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) )) 02364 { 02365 TRACE("Evaluating feature conditions\n"); 02366 02367 rc = MSI_DatabaseOpenViewW( package->db, query, &view ); 02368 if (rc == ERROR_SUCCESS) 02369 { 02370 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package ); 02371 msiobj_release( &view->hdr ); 02372 if (rc != ERROR_SUCCESS) 02373 return rc; 02374 } 02375 } 02376 02377 TRACE("Calculating file cost\n"); 02378 calculate_file_cost( package ); 02379 02380 msi_set_property( package->db, szCostingComplete, szOne ); 02381 /* set default run level if not set */ 02382 level = msi_dup_property( package->db, szInstallLevel ); 02383 if (!level) 02384 msi_set_property( package->db, szInstallLevel, szOne ); 02385 msi_free(level); 02386 02387 /* FIXME: check volume disk space */ 02388 msi_set_property( package->db, szOutOfDiskSpace, szZero ); 02389 02390 return MSI_SetFeatureStates(package); 02391 } 02392 02393 /* OK this value is "interpreted" and then formatted based on the 02394 first few characters */ 02395 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, 02396 DWORD *size) 02397 { 02398 LPSTR data = NULL; 02399 02400 if (value[0]=='#' && value[1]!='#' && value[1]!='%') 02401 { 02402 if (value[1]=='x') 02403 { 02404 LPWSTR ptr; 02405 CHAR byte[5]; 02406 LPWSTR deformated = NULL; 02407 int count; 02408 02409 deformat_string(package, &value[2], &deformated); 02410 02411 /* binary value type */ 02412 ptr = deformated; 02413 *type = REG_BINARY; 02414 if (strlenW(ptr)%2) 02415 *size = (strlenW(ptr)/2)+1; 02416 else 02417 *size = strlenW(ptr)/2; 02418 02419 data = msi_alloc(*size); 02420 02421 byte[0] = '0'; 02422 byte[1] = 'x'; 02423 byte[4] = 0; 02424 count = 0; 02425 /* if uneven pad with a zero in front */ 02426 if (strlenW(ptr)%2) 02427 { 02428 byte[2]= '0'; 02429 byte[3]= *ptr; 02430 ptr++; 02431 data[count] = (BYTE)strtol(byte,NULL,0); 02432 count ++; 02433 TRACE("Uneven byte count\n"); 02434 } 02435 while (*ptr) 02436 { 02437 byte[2]= *ptr; 02438 ptr++; 02439 byte[3]= *ptr; 02440 ptr++; 02441 data[count] = (BYTE)strtol(byte,NULL,0); 02442 count ++; 02443 } 02444 msi_free(deformated); 02445 02446 TRACE("Data %i bytes(%i)\n",*size,count); 02447 } 02448 else 02449 { 02450 LPWSTR deformated; 02451 LPWSTR p; 02452 DWORD d = 0; 02453 deformat_string(package, &value[1], &deformated); 02454 02455 *type=REG_DWORD; 02456 *size = sizeof(DWORD); 02457 data = msi_alloc(*size); 02458 p = deformated; 02459 if (*p == '-') 02460 p++; 02461 while (*p) 02462 { 02463 if ( (*p < '0') || (*p > '9') ) 02464 break; 02465 d *= 10; 02466 d += (*p - '0'); 02467 p++; 02468 } 02469 if (deformated[0] == '-') 02470 d = -d; 02471 *(LPDWORD)data = d; 02472 TRACE("DWORD %i\n",*(LPDWORD)data); 02473 02474 msi_free(deformated); 02475 } 02476 } 02477 else 02478 { 02479 static const WCHAR szMulti[] = {'[','~',']',0}; 02480 LPCWSTR ptr; 02481 *type=REG_SZ; 02482 02483 if (value[0]=='#') 02484 { 02485 if (value[1]=='%') 02486 { 02487 ptr = &value[2]; 02488 *type=REG_EXPAND_SZ; 02489 } 02490 else 02491 ptr = &value[1]; 02492 } 02493 else 02494 ptr=value; 02495 02496 if (strstrW(value, szMulti)) 02497 *type = REG_MULTI_SZ; 02498 02499 /* remove initial delimiter */ 02500 if (!strncmpW(value, szMulti, 3)) 02501 ptr = value + 3; 02502 02503 *size = deformat_string(package, ptr,(LPWSTR*)&data); 02504 02505 /* add double NULL terminator */ 02506 if (*type == REG_MULTI_SZ) 02507 { 02508 *size += 2 * sizeof(WCHAR); /* two NULL terminators */ 02509 data = msi_realloc_zero(data, *size); 02510 } 02511 } 02512 return data; 02513 } 02514 02515 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key ) 02516 { 02517 const WCHAR *ret; 02518 02519 switch (root) 02520 { 02521 case -1: 02522 if (msi_get_property_int( package->db, szAllUsers, 0 )) 02523 { 02524 *root_key = HKEY_LOCAL_MACHINE; 02525 ret = szHLM; 02526 } 02527 else 02528 { 02529 *root_key = HKEY_CURRENT_USER; 02530 ret = szHCU; 02531 } 02532 break; 02533 case 0: 02534 *root_key = HKEY_CLASSES_ROOT; 02535 ret = szHCR; 02536 break; 02537 case 1: 02538 *root_key = HKEY_CURRENT_USER; 02539 ret = szHCU; 02540 break; 02541 case 2: 02542 *root_key = HKEY_LOCAL_MACHINE; 02543 ret = szHLM; 02544 break; 02545 case 3: 02546 *root_key = HKEY_USERS; 02547 ret = szHU; 02548 break; 02549 default: 02550 ERR("Unknown root %i\n", root); 02551 return NULL; 02552 } 02553 02554 return ret; 02555 } 02556 02557 static WCHAR *get_keypath( MSIPACKAGE *package, HKEY root, const WCHAR *path ) 02558 { 02559 static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'}; 02560 static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]); 02561 02562 if (is_64bit && package->platform == PLATFORM_INTEL && 02563 root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len )) 02564 { 02565 UINT size; 02566 WCHAR *path_32node; 02567 02568 size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR); 02569 if (!(path_32node = msi_alloc( size ))) return NULL; 02570 02571 memcpy( path_32node, path, len * sizeof(WCHAR) ); 02572 strcpyW( path_32node + len, szWow6432Node ); 02573 strcatW( path_32node, szBackSlash ); 02574 strcatW( path_32node, path + len ); 02575 return path_32node; 02576 } 02577 02578 return strdupW( path ); 02579 } 02580 02581 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) 02582 { 02583 MSIPACKAGE *package = param; 02584 LPSTR value_data = NULL; 02585 HKEY root_key, hkey; 02586 DWORD type,size; 02587 LPWSTR deformated, uikey, keypath; 02588 LPCWSTR szRoot, component, name, key, value; 02589 MSICOMPONENT *comp; 02590 MSIRECORD * uirow; 02591 INT root; 02592 BOOL check_first = FALSE; 02593 UINT rc; 02594 02595 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 ); 02596 02597 component = MSI_RecordGetString(row, 6); 02598 comp = msi_get_loaded_component(package,component); 02599 if (!comp) 02600 return ERROR_SUCCESS; 02601 02602 comp->Action = msi_get_component_action( package, comp ); 02603 if (comp->Action != INSTALLSTATE_LOCAL) 02604 { 02605 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 02606 return ERROR_SUCCESS; 02607 } 02608 02609 name = MSI_RecordGetString(row, 4); 02610 if( MSI_RecordIsNull(row,5) && name ) 02611 { 02612 /* null values can have special meanings */ 02613 if (name[0]=='-' && name[1] == 0) 02614 return ERROR_SUCCESS; 02615 else if ((name[0]=='+' && name[1] == 0) || 02616 (name[0] == '*' && name[1] == 0)) 02617 name = NULL; 02618 check_first = TRUE; 02619 } 02620 02621 root = MSI_RecordGetInteger(row,2); 02622 key = MSI_RecordGetString(row, 3); 02623 02624 szRoot = get_root_key( package, root, &root_key ); 02625 if (!szRoot) 02626 return ERROR_SUCCESS; 02627 02628 deformat_string(package, key , &deformated); 02629 size = strlenW(deformated) + strlenW(szRoot) + 1; 02630 uikey = msi_alloc(size*sizeof(WCHAR)); 02631 strcpyW(uikey,szRoot); 02632 strcatW(uikey,deformated); 02633 02634 keypath = get_keypath( package, root_key, deformated ); 02635 msi_free( deformated ); 02636 if (RegCreateKeyW( root_key, keypath, &hkey )) 02637 { 02638 ERR("Could not create key %s\n", debugstr_w(keypath)); 02639 msi_free(uikey); 02640 msi_free(keypath); 02641 return ERROR_SUCCESS; 02642 } 02643 02644 value = MSI_RecordGetString(row,5); 02645 if (value) 02646 value_data = parse_value(package, value, &type, &size); 02647 else 02648 { 02649 value_data = (LPSTR)strdupW(szEmpty); 02650 size = sizeof(szEmpty); 02651 type = REG_SZ; 02652 } 02653 02654 deformat_string(package, name, &deformated); 02655 02656 if (!check_first) 02657 { 02658 TRACE("Setting value %s of %s\n",debugstr_w(deformated), 02659 debugstr_w(uikey)); 02660 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size); 02661 } 02662 else 02663 { 02664 DWORD sz = 0; 02665 rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz); 02666 if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA) 02667 { 02668 TRACE("value %s of %s checked already exists\n", 02669 debugstr_w(deformated), debugstr_w(uikey)); 02670 } 02671 else 02672 { 02673 TRACE("Checked and setting value %s of %s\n", 02674 debugstr_w(deformated), debugstr_w(uikey)); 02675 if (deformated || size) 02676 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size); 02677 } 02678 } 02679 RegCloseKey(hkey); 02680 02681 uirow = MSI_CreateRecord(3); 02682 MSI_RecordSetStringW(uirow,2,deformated); 02683 MSI_RecordSetStringW(uirow,1,uikey); 02684 if (type == REG_SZ || type == REG_EXPAND_SZ) 02685 MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data); 02686 msi_ui_actiondata( package, szWriteRegistryValues, uirow ); 02687 msiobj_release( &uirow->hdr ); 02688 02689 msi_free(value_data); 02690 msi_free(deformated); 02691 msi_free(uikey); 02692 msi_free(keypath); 02693 02694 return ERROR_SUCCESS; 02695 } 02696 02697 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) 02698 { 02699 static const WCHAR query[] = { 02700 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 02701 '`','R','e','g','i','s','t','r','y','`',0}; 02702 MSIQUERY *view; 02703 UINT rc; 02704 02705 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 02706 if (rc != ERROR_SUCCESS) 02707 return ERROR_SUCCESS; 02708 02709 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package); 02710 msiobj_release(&view->hdr); 02711 return rc; 02712 } 02713 02714 static void delete_reg_value( HKEY root, const WCHAR *keypath, const WCHAR *value ) 02715 { 02716 LONG res; 02717 HKEY hkey; 02718 DWORD num_subkeys, num_values; 02719 02720 if (!(res = RegOpenKeyW( root, keypath, &hkey ))) 02721 { 02722 if ((res = RegDeleteValueW( hkey, value ))) 02723 { 02724 TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res); 02725 } 02726 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values, 02727 NULL, NULL, NULL, NULL ); 02728 RegCloseKey( hkey ); 02729 if (!res && !num_subkeys && !num_values) 02730 { 02731 TRACE("removing empty key %s\n", debugstr_w(keypath)); 02732 RegDeleteKeyW( root, keypath ); 02733 } 02734 return; 02735 } 02736 TRACE("failed to open key %s (%d)\n", debugstr_w(keypath), res); 02737 } 02738 02739 static void delete_reg_key( HKEY root, const WCHAR *keypath ) 02740 { 02741 LONG res = RegDeleteTreeW( root, keypath ); 02742 if (res) TRACE("failed to delete key %s (%d)\n", debugstr_w(keypath), res); 02743 } 02744 02745 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param ) 02746 { 02747 MSIPACKAGE *package = param; 02748 LPCWSTR component, name, key_str, root_key_str; 02749 LPWSTR deformated_key, deformated_name, ui_key_str, keypath; 02750 MSICOMPONENT *comp; 02751 MSIRECORD *uirow; 02752 BOOL delete_key = FALSE; 02753 HKEY hkey_root; 02754 UINT size; 02755 INT root; 02756 02757 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 ); 02758 02759 component = MSI_RecordGetString( row, 6 ); 02760 comp = msi_get_loaded_component( package, component ); 02761 if (!comp) 02762 return ERROR_SUCCESS; 02763 02764 comp->Action = msi_get_component_action( package, comp ); 02765 if (comp->Action != INSTALLSTATE_ABSENT) 02766 { 02767 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 02768 return ERROR_SUCCESS; 02769 } 02770 02771 name = MSI_RecordGetString( row, 4 ); 02772 if (MSI_RecordIsNull( row, 5 ) && name ) 02773 { 02774 if (name[0] == '+' && !name[1]) 02775 return ERROR_SUCCESS; 02776 else if ((name[0] == '-' && !name[1]) || (name[0] == '*' && !name[1])) 02777 { 02778 delete_key = TRUE; 02779 name = NULL; 02780 } 02781 } 02782 02783 root = MSI_RecordGetInteger( row, 2 ); 02784 key_str = MSI_RecordGetString( row, 3 ); 02785 02786 root_key_str = get_root_key( package, root, &hkey_root ); 02787 if (!root_key_str) 02788 return ERROR_SUCCESS; 02789 02790 deformat_string( package, key_str, &deformated_key ); 02791 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1; 02792 ui_key_str = msi_alloc( size * sizeof(WCHAR) ); 02793 strcpyW( ui_key_str, root_key_str ); 02794 strcatW( ui_key_str, deformated_key ); 02795 02796 deformat_string( package, name, &deformated_name ); 02797 02798 keypath = get_keypath( package, hkey_root, deformated_key ); 02799 msi_free( deformated_key ); 02800 if (delete_key) delete_reg_key( hkey_root, keypath ); 02801 else delete_reg_value( hkey_root, keypath, deformated_name ); 02802 msi_free( keypath ); 02803 02804 uirow = MSI_CreateRecord( 2 ); 02805 MSI_RecordSetStringW( uirow, 1, ui_key_str ); 02806 MSI_RecordSetStringW( uirow, 2, deformated_name ); 02807 msi_ui_actiondata( package, szRemoveRegistryValues, uirow ); 02808 msiobj_release( &uirow->hdr ); 02809 02810 msi_free( ui_key_str ); 02811 msi_free( deformated_name ); 02812 return ERROR_SUCCESS; 02813 } 02814 02815 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param ) 02816 { 02817 MSIPACKAGE *package = param; 02818 LPCWSTR component, name, key_str, root_key_str; 02819 LPWSTR deformated_key, deformated_name, ui_key_str, keypath; 02820 MSICOMPONENT *comp; 02821 MSIRECORD *uirow; 02822 BOOL delete_key = FALSE; 02823 HKEY hkey_root; 02824 UINT size; 02825 INT root; 02826 02827 component = MSI_RecordGetString( row, 5 ); 02828 comp = msi_get_loaded_component( package, component ); 02829 if (!comp) 02830 return ERROR_SUCCESS; 02831 02832 comp->Action = msi_get_component_action( package, comp ); 02833 if (comp->Action != INSTALLSTATE_LOCAL) 02834 { 02835 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 02836 return ERROR_SUCCESS; 02837 } 02838 02839 if ((name = MSI_RecordGetString( row, 4 ))) 02840 { 02841 if (name[0] == '-' && !name[1]) 02842 { 02843 delete_key = TRUE; 02844 name = NULL; 02845 } 02846 } 02847 02848 root = MSI_RecordGetInteger( row, 2 ); 02849 key_str = MSI_RecordGetString( row, 3 ); 02850 02851 root_key_str = get_root_key( package, root, &hkey_root ); 02852 if (!root_key_str) 02853 return ERROR_SUCCESS; 02854 02855 deformat_string( package, key_str, &deformated_key ); 02856 size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1; 02857 ui_key_str = msi_alloc( size * sizeof(WCHAR) ); 02858 strcpyW( ui_key_str, root_key_str ); 02859 strcatW( ui_key_str, deformated_key ); 02860 02861 deformat_string( package, name, &deformated_name ); 02862 02863 keypath = get_keypath( package, hkey_root, deformated_key ); 02864 msi_free( deformated_key ); 02865 if (delete_key) delete_reg_key( hkey_root, keypath ); 02866 else delete_reg_value( hkey_root, keypath, deformated_name ); 02867 msi_free( keypath ); 02868 02869 uirow = MSI_CreateRecord( 2 ); 02870 MSI_RecordSetStringW( uirow, 1, ui_key_str ); 02871 MSI_RecordSetStringW( uirow, 2, deformated_name ); 02872 msi_ui_actiondata( package, szRemoveRegistryValues, uirow ); 02873 msiobj_release( &uirow->hdr ); 02874 02875 msi_free( ui_key_str ); 02876 msi_free( deformated_name ); 02877 return ERROR_SUCCESS; 02878 } 02879 02880 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package ) 02881 { 02882 static const WCHAR registry_query[] = { 02883 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 02884 '`','R','e','g','i','s','t','r','y','`',0}; 02885 static const WCHAR remove_registry_query[] = { 02886 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 02887 '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0}; 02888 MSIQUERY *view; 02889 UINT rc; 02890 02891 rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view ); 02892 if (rc == ERROR_SUCCESS) 02893 { 02894 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package ); 02895 msiobj_release( &view->hdr ); 02896 if (rc != ERROR_SUCCESS) 02897 return rc; 02898 } 02899 rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view ); 02900 if (rc == ERROR_SUCCESS) 02901 { 02902 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package ); 02903 msiobj_release( &view->hdr ); 02904 if (rc != ERROR_SUCCESS) 02905 return rc; 02906 } 02907 return ERROR_SUCCESS; 02908 } 02909 02910 static UINT ACTION_InstallInitialize(MSIPACKAGE *package) 02911 { 02912 package->script->CurrentlyScripting = TRUE; 02913 02914 return ERROR_SUCCESS; 02915 } 02916 02917 02918 static UINT ACTION_InstallValidate(MSIPACKAGE *package) 02919 { 02920 static const WCHAR query[]= { 02921 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', 02922 '`','R','e','g','i','s','t','r','y','`',0}; 02923 MSICOMPONENT *comp; 02924 DWORD total = 0, count = 0; 02925 MSIQUERY *view; 02926 MSIFEATURE *feature; 02927 MSIFILE *file; 02928 UINT rc; 02929 02930 TRACE("InstallValidate\n"); 02931 02932 rc = MSI_DatabaseOpenViewW( package->db, query, &view ); 02933 if (rc == ERROR_SUCCESS) 02934 { 02935 rc = MSI_IterateRecords( view, &count, NULL, package ); 02936 msiobj_release( &view->hdr ); 02937 if (rc != ERROR_SUCCESS) 02938 return rc; 02939 total += count * REG_PROGRESS_VALUE; 02940 } 02941 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) 02942 total += COMPONENT_PROGRESS_VALUE; 02943 02944 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) 02945 total += file->FileSize; 02946 02947 msi_ui_progress( package, 0, total, 0, 0 ); 02948 02949 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 02950 { 02951 TRACE("Feature: %s Installed %d Request %d Action %d\n", 02952 debugstr_w(feature->Feature), feature->Installed, 02953 feature->ActionRequest, feature->Action); 02954 } 02955 return ERROR_SUCCESS; 02956 } 02957 02958 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param) 02959 { 02960 MSIPACKAGE* package = param; 02961 LPCWSTR cond = NULL; 02962 LPCWSTR message = NULL; 02963 UINT r; 02964 02965 static const WCHAR title[]= 02966 {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0}; 02967 02968 cond = MSI_RecordGetString(row,1); 02969 02970 r = MSI_EvaluateConditionW(package,cond); 02971 if (r == MSICONDITION_FALSE) 02972 { 02973 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE) 02974 { 02975 LPWSTR deformated; 02976 message = MSI_RecordGetString(row,2); 02977 deformat_string(package,message,&deformated); 02978 MessageBoxW(NULL,deformated,title,MB_OK); 02979 msi_free(deformated); 02980 } 02981 02982 return ERROR_INSTALL_FAILURE; 02983 } 02984 02985 return ERROR_SUCCESS; 02986 } 02987 02988 static UINT ACTION_LaunchConditions(MSIPACKAGE *package) 02989 { 02990 static const WCHAR query[] = { 02991 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 02992 '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0}; 02993 MSIQUERY *view; 02994 UINT rc; 02995 02996 TRACE("Checking launch conditions\n"); 02997 02998 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 02999 if (rc != ERROR_SUCCESS) 03000 return ERROR_SUCCESS; 03001 03002 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package); 03003 msiobj_release(&view->hdr); 03004 return rc; 03005 } 03006 03007 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp ) 03008 { 03009 03010 if (!cmp->KeyPath) 03011 return strdupW( msi_get_target_folder( package, cmp->Directory ) ); 03012 03013 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath) 03014 { 03015 static const WCHAR query[] = { 03016 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 03017 '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ', 03018 '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0}; 03019 static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0}; 03020 static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0}; 03021 MSIRECORD *row; 03022 UINT root, len; 03023 LPWSTR deformated, buffer, deformated_name; 03024 LPCWSTR key, name; 03025 03026 row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath); 03027 if (!row) 03028 return NULL; 03029 03030 root = MSI_RecordGetInteger(row,2); 03031 key = MSI_RecordGetString(row, 3); 03032 name = MSI_RecordGetString(row, 4); 03033 deformat_string(package, key , &deformated); 03034 deformat_string(package, name, &deformated_name); 03035 03036 len = strlenW(deformated) + 6; 03037 if (deformated_name) 03038 len+=strlenW(deformated_name); 03039 03040 buffer = msi_alloc( len *sizeof(WCHAR)); 03041 03042 if (deformated_name) 03043 sprintfW(buffer,fmt2,root,deformated,deformated_name); 03044 else 03045 sprintfW(buffer,fmt,root,deformated); 03046 03047 msi_free(deformated); 03048 msi_free(deformated_name); 03049 msiobj_release(&row->hdr); 03050 03051 return buffer; 03052 } 03053 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource) 03054 { 03055 FIXME("UNIMPLEMENTED keypath as ODBC Source\n"); 03056 return NULL; 03057 } 03058 else 03059 { 03060 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath ); 03061 03062 if (file) 03063 return strdupW( file->TargetPath ); 03064 } 03065 return NULL; 03066 } 03067 03068 static HKEY openSharedDLLsKey(void) 03069 { 03070 HKEY hkey=0; 03071 static const WCHAR path[] = 03072 {'S','o','f','t','w','a','r','e','\\', 03073 'M','i','c','r','o','s','o','f','t','\\', 03074 'W','i','n','d','o','w','s','\\', 03075 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 03076 'S','h','a','r','e','d','D','L','L','s',0}; 03077 03078 RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey); 03079 return hkey; 03080 } 03081 03082 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll) 03083 { 03084 HKEY hkey; 03085 DWORD count=0; 03086 DWORD type; 03087 DWORD sz = sizeof(count); 03088 DWORD rc; 03089 03090 hkey = openSharedDLLsKey(); 03091 rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz); 03092 if (rc != ERROR_SUCCESS) 03093 count = 0; 03094 RegCloseKey(hkey); 03095 return count; 03096 } 03097 03098 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count) 03099 { 03100 HKEY hkey; 03101 03102 hkey = openSharedDLLsKey(); 03103 if (count > 0) 03104 msi_reg_set_val_dword( hkey, path, count ); 03105 else 03106 RegDeleteValueW(hkey,path); 03107 RegCloseKey(hkey); 03108 return count; 03109 } 03110 03111 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp ) 03112 { 03113 MSIFEATURE *feature; 03114 INT count = 0; 03115 BOOL write = FALSE; 03116 03117 /* only refcount DLLs */ 03118 if (comp->KeyPath == NULL || 03119 comp->assembly || 03120 comp->Attributes & msidbComponentAttributesRegistryKeyPath || 03121 comp->Attributes & msidbComponentAttributesODBCDataSource) 03122 write = FALSE; 03123 else 03124 { 03125 count = ACTION_GetSharedDLLsCount( comp->FullKeypath); 03126 write = (count > 0); 03127 03128 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount) 03129 write = TRUE; 03130 } 03131 03132 /* increment counts */ 03133 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 03134 { 03135 ComponentList *cl; 03136 03137 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL) 03138 continue; 03139 03140 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) 03141 { 03142 if ( cl->component == comp ) 03143 count++; 03144 } 03145 } 03146 03147 /* decrement counts */ 03148 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 03149 { 03150 ComponentList *cl; 03151 03152 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT) 03153 continue; 03154 03155 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) 03156 { 03157 if ( cl->component == comp ) 03158 count--; 03159 } 03160 } 03161 03162 /* ref count all the files in the component */ 03163 if (write) 03164 { 03165 MSIFILE *file; 03166 03167 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) 03168 { 03169 if (file->Component == comp) 03170 ACTION_WriteSharedDLLsCount( file->TargetPath, count ); 03171 } 03172 } 03173 03174 /* add a count for permanent */ 03175 if (comp->Attributes & msidbComponentAttributesPermanent) 03176 count ++; 03177 03178 comp->RefCount = count; 03179 03180 if (write) 03181 ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount ); 03182 } 03183 03184 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp ) 03185 { 03186 if (comp->assembly) 03187 { 03188 const WCHAR prefixW[] = {'<','\\',0}; 03189 DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name ); 03190 WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) ); 03191 03192 if (keypath) 03193 { 03194 strcpyW( keypath, prefixW ); 03195 strcatW( keypath, comp->assembly->display_name ); 03196 } 03197 return keypath; 03198 } 03199 return resolve_keypath( package, comp ); 03200 } 03201 03202 static UINT ACTION_ProcessComponents(MSIPACKAGE *package) 03203 { 03204 WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE]; 03205 UINT rc; 03206 MSICOMPONENT *comp; 03207 HKEY hkey; 03208 03209 TRACE("\n"); 03210 03211 squash_guid(package->ProductCode,squished_pc); 03212 msi_set_sourcedir_props(package, FALSE); 03213 03214 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) 03215 { 03216 MSIRECORD *uirow; 03217 INSTALLSTATE action; 03218 03219 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 ); 03220 if (!comp->ComponentId) 03221 continue; 03222 03223 squash_guid( comp->ComponentId, squished_cc ); 03224 msi_free( comp->FullKeypath ); 03225 comp->FullKeypath = build_full_keypath( package, comp ); 03226 03227 ACTION_RefCountComponent( package, comp ); 03228 03229 if (package->need_rollback) action = comp->Installed; 03230 else action = comp->ActionRequest; 03231 03232 TRACE("Component %s (%s), Keypath=%s, RefCount=%u Action=%u\n", 03233 debugstr_w(comp->Component), debugstr_w(squished_cc), 03234 debugstr_w(comp->FullKeypath), comp->RefCount, action); 03235 03236 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE) 03237 { 03238 if (package->Context == MSIINSTALLCONTEXT_MACHINE) 03239 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE); 03240 else 03241 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE); 03242 03243 if (rc != ERROR_SUCCESS) 03244 continue; 03245 03246 if (comp->Attributes & msidbComponentAttributesPermanent) 03247 { 03248 static const WCHAR szPermKey[] = 03249 { '0','0','0','0','0','0','0','0','0','0','0','0', 03250 '0','0','0','0','0','0','0','0','0','0','0','0', 03251 '0','0','0','0','0','0','0','0',0 }; 03252 03253 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath); 03254 } 03255 if (action == INSTALLSTATE_LOCAL) 03256 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath); 03257 else 03258 { 03259 MSIFILE *file; 03260 MSIRECORD *row; 03261 LPWSTR ptr, ptr2; 03262 WCHAR source[MAX_PATH]; 03263 WCHAR base[MAX_PATH]; 03264 LPWSTR sourcepath; 03265 03266 static const WCHAR fmt[] = {'%','0','2','d','\\',0}; 03267 static const WCHAR query[] = { 03268 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', 03269 '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ', 03270 '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ', 03271 '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ', 03272 '`','D','i','s','k','I','d','`',0}; 03273 03274 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath))) 03275 continue; 03276 03277 row = MSI_QueryGetRecord(package->db, query, file->Sequence); 03278 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1)); 03279 ptr2 = strrchrW(source, '\\') + 1; 03280 msiobj_release(&row->hdr); 03281 03282 lstrcpyW(base, package->PackagePath); 03283 ptr = strrchrW(base, '\\'); 03284 *(ptr + 1) = '\0'; 03285 03286 sourcepath = msi_resolve_file_source(package, file); 03287 ptr = sourcepath + lstrlenW(base); 03288 lstrcpyW(ptr2, ptr); 03289 msi_free(sourcepath); 03290 03291 msi_reg_set_val_str(hkey, squished_pc, source); 03292 } 03293 RegCloseKey(hkey); 03294 } 03295 else if (action == INSTALLSTATE_ABSENT) 03296 { 03297 if (package->Context == MSIINSTALLCONTEXT_MACHINE) 03298 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid); 03299 else 03300 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL); 03301 } 03302 03303 /* UI stuff */ 03304 uirow = MSI_CreateRecord(3); 03305 MSI_RecordSetStringW(uirow,1,package->ProductCode); 03306 MSI_RecordSetStringW(uirow,2,comp->ComponentId); 03307 MSI_RecordSetStringW(uirow,3,comp->FullKeypath); 03308 msi_ui_actiondata( package, szProcessComponents, uirow ); 03309 msiobj_release( &uirow->hdr ); 03310 } 03311 return ERROR_SUCCESS; 03312 } 03313 03314 typedef struct { 03315 CLSID clsid; 03316 LPWSTR source; 03317 03318 LPWSTR path; 03319 ITypeLib *ptLib; 03320 } typelib_struct; 03321 03322 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, 03323 LPWSTR lpszName, LONG_PTR lParam) 03324 { 03325 TLIBATTR *attr; 03326 typelib_struct *tl_struct = (typelib_struct*) lParam; 03327 static const WCHAR fmt[] = {'%','s','\\','%','i',0}; 03328 int sz; 03329 HRESULT res; 03330 03331 if (!IS_INTRESOURCE(lpszName)) 03332 { 03333 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName)); 03334 return TRUE; 03335 } 03336 03337 sz = strlenW(tl_struct->source)+4; 03338 sz *= sizeof(WCHAR); 03339 03340 if ((INT_PTR)lpszName == 1) 03341 tl_struct->path = strdupW(tl_struct->source); 03342 else 03343 { 03344 tl_struct->path = msi_alloc(sz); 03345 sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName); 03346 } 03347 03348 TRACE("trying %s\n", debugstr_w(tl_struct->path)); 03349 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib); 03350 if (FAILED(res)) 03351 { 03352 msi_free(tl_struct->path); 03353 tl_struct->path = NULL; 03354 03355 return TRUE; 03356 } 03357 03358 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr); 03359 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid))) 03360 { 03361 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr); 03362 return FALSE; 03363 } 03364 03365 msi_free(tl_struct->path); 03366 tl_struct->path = NULL; 03367 03368 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr); 03369 ITypeLib_Release(tl_struct->ptLib); 03370 03371 return TRUE; 03372 } 03373 03374 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param) 03375 { 03376 MSIPACKAGE* package = param; 03377 LPCWSTR component; 03378 MSICOMPONENT *comp; 03379 MSIFILE *file; 03380 typelib_struct tl_struct; 03381 ITypeLib *tlib; 03382 HMODULE module; 03383 HRESULT hr; 03384 03385 component = MSI_RecordGetString(row,3); 03386 comp = msi_get_loaded_component(package,component); 03387 if (!comp) 03388 return ERROR_SUCCESS; 03389 03390 comp->Action = msi_get_component_action( package, comp ); 03391 if (comp->Action != INSTALLSTATE_LOCAL) 03392 { 03393 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 03394 return ERROR_SUCCESS; 03395 } 03396 03397 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath ))) 03398 { 03399 TRACE("component has no key path\n"); 03400 return ERROR_SUCCESS; 03401 } 03402 msi_ui_actiondata( package, szRegisterTypeLibraries, row ); 03403 03404 module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE ); 03405 if (module) 03406 { 03407 LPCWSTR guid; 03408 guid = MSI_RecordGetString(row,1); 03409 CLSIDFromString( guid, &tl_struct.clsid); 03410 tl_struct.source = strdupW( file->TargetPath ); 03411 tl_struct.path = NULL; 03412 03413 EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc, 03414 (LONG_PTR)&tl_struct); 03415 03416 if (tl_struct.path) 03417 { 03418 LPCWSTR helpid, help_path = NULL; 03419 HRESULT res; 03420 03421 helpid = MSI_RecordGetString(row,6); 03422 03423 if (helpid) help_path = msi_get_target_folder( package, helpid ); 03424 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path ); 03425 03426 if (FAILED(res)) 03427 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path)); 03428 else 03429 TRACE("Registered %s\n", debugstr_w(tl_struct.path)); 03430 03431 ITypeLib_Release(tl_struct.ptLib); 03432 msi_free(tl_struct.path); 03433 } 03434 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source)); 03435 03436 FreeLibrary(module); 03437 msi_free(tl_struct.source); 03438 } 03439 else 03440 { 03441 hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib); 03442 if (FAILED(hr)) 03443 { 03444 ERR("Failed to load type library: %08x\n", hr); 03445 return ERROR_INSTALL_FAILURE; 03446 } 03447 03448 ITypeLib_Release(tlib); 03449 } 03450 03451 return ERROR_SUCCESS; 03452 } 03453 03454 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) 03455 { 03456 static const WCHAR query[] = { 03457 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 03458 '`','T','y','p','e','L','i','b','`',0}; 03459 MSIQUERY *view; 03460 UINT rc; 03461 03462 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 03463 if (rc != ERROR_SUCCESS) 03464 return ERROR_SUCCESS; 03465 03466 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package); 03467 msiobj_release(&view->hdr); 03468 return rc; 03469 } 03470 03471 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param ) 03472 { 03473 MSIPACKAGE *package = param; 03474 LPCWSTR component, guid; 03475 MSICOMPONENT *comp; 03476 GUID libid; 03477 UINT version; 03478 LCID language; 03479 SYSKIND syskind; 03480 HRESULT hr; 03481 03482 component = MSI_RecordGetString( row, 3 ); 03483 comp = msi_get_loaded_component( package, component ); 03484 if (!comp) 03485 return ERROR_SUCCESS; 03486 03487 comp->Action = msi_get_component_action( package, comp ); 03488 if (comp->Action != INSTALLSTATE_ABSENT) 03489 { 03490 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 03491 return ERROR_SUCCESS; 03492 } 03493 msi_ui_actiondata( package, szUnregisterTypeLibraries, row ); 03494 03495 guid = MSI_RecordGetString( row, 1 ); 03496 CLSIDFromString( guid, &libid ); 03497 version = MSI_RecordGetInteger( row, 4 ); 03498 language = MSI_RecordGetInteger( row, 2 ); 03499 03500 #ifdef _WIN64 03501 syskind = SYS_WIN64; 03502 #else 03503 syskind = SYS_WIN32; 03504 #endif 03505 03506 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind ); 03507 if (FAILED(hr)) 03508 { 03509 WARN("Failed to unregister typelib: %08x\n", hr); 03510 } 03511 03512 return ERROR_SUCCESS; 03513 } 03514 03515 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package ) 03516 { 03517 static const WCHAR query[] = { 03518 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 03519 '`','T','y','p','e','L','i','b','`',0}; 03520 MSIQUERY *view; 03521 UINT rc; 03522 03523 rc = MSI_DatabaseOpenViewW( package->db, query, &view ); 03524 if (rc != ERROR_SUCCESS) 03525 return ERROR_SUCCESS; 03526 03527 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package ); 03528 msiobj_release( &view->hdr ); 03529 return rc; 03530 } 03531 03532 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row ) 03533 { 03534 static const WCHAR szlnk[] = {'.','l','n','k',0}; 03535 LPCWSTR directory, extension, link_folder; 03536 LPWSTR link_file, filename; 03537 03538 directory = MSI_RecordGetString( row, 2 ); 03539 link_folder = msi_get_target_folder( package, directory ); 03540 if (!link_folder) 03541 { 03542 ERR("unable to resolve folder %s\n", debugstr_w(directory)); 03543 return NULL; 03544 } 03545 /* may be needed because of a bug somewhere else */ 03546 msi_create_full_path( link_folder ); 03547 03548 filename = msi_dup_record_field( row, 3 ); 03549 msi_reduce_to_long_filename( filename ); 03550 03551 extension = strchrW( filename, '.' ); 03552 if (!extension || strcmpiW( extension, szlnk )) 03553 { 03554 int len = strlenW( filename ); 03555 filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) ); 03556 memcpy( filename + len, szlnk, sizeof(szlnk) ); 03557 } 03558 link_file = msi_build_directory_name( 2, link_folder, filename ); 03559 msi_free( filename ); 03560 03561 return link_file; 03562 } 03563 03564 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name ) 03565 { 03566 static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0}; 03567 static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0}; 03568 WCHAR *folder, *dest, *path; 03569 03570 if (package->Context == MSIINSTALLCONTEXT_MACHINE) 03571 folder = msi_dup_property( package->db, szWindowsFolder ); 03572 else 03573 { 03574 WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder ); 03575 folder = msi_build_directory_name( 2, appdata, szMicrosoft ); 03576 msi_free( appdata ); 03577 } 03578 dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode ); 03579 msi_create_full_path( dest ); 03580 path = msi_build_directory_name( 2, dest, icon_name ); 03581 msi_free( folder ); 03582 msi_free( dest ); 03583 return path; 03584 } 03585 03586 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param) 03587 { 03588 MSIPACKAGE *package = param; 03589 LPWSTR link_file, deformated, path; 03590 LPCWSTR component, target; 03591 MSICOMPONENT *comp; 03592 IShellLinkW *sl = NULL; 03593 IPersistFile *pf = NULL; 03594 HRESULT res; 03595 03596 component = MSI_RecordGetString(row, 4); 03597 comp = msi_get_loaded_component(package, component); 03598 if (!comp) 03599 return ERROR_SUCCESS; 03600 03601 comp->Action = msi_get_component_action( package, comp ); 03602 if (comp->Action != INSTALLSTATE_LOCAL) 03603 { 03604 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 03605 return ERROR_SUCCESS; 03606 } 03607 msi_ui_actiondata( package, szCreateShortcuts, row ); 03608 03609 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, 03610 &IID_IShellLinkW, (LPVOID *) &sl ); 03611 03612 if (FAILED( res )) 03613 { 03614 ERR("CLSID_ShellLink not available\n"); 03615 goto err; 03616 } 03617 03618 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf ); 03619 if (FAILED( res )) 03620 { 03621 ERR("QueryInterface(IID_IPersistFile) failed\n"); 03622 goto err; 03623 } 03624 03625 target = MSI_RecordGetString(row, 5); 03626 if (strchrW(target, '[')) 03627 { 03628 deformat_string( package, target, &path ); 03629 TRACE("target path is %s\n", debugstr_w(path)); 03630 IShellLinkW_SetPath( sl, path ); 03631 msi_free( path ); 03632 } 03633 else 03634 { 03635 FIXME("poorly handled shortcut format, advertised shortcut\n"); 03636 IShellLinkW_SetPath(sl,comp->FullKeypath); 03637 } 03638 03639 if (!MSI_RecordIsNull(row,6)) 03640 { 03641 LPCWSTR arguments = MSI_RecordGetString(row, 6); 03642 deformat_string(package, arguments, &deformated); 03643 IShellLinkW_SetArguments(sl,deformated); 03644 msi_free(deformated); 03645 } 03646 03647 if (!MSI_RecordIsNull(row,7)) 03648 { 03649 LPCWSTR description = MSI_RecordGetString(row, 7); 03650 IShellLinkW_SetDescription(sl, description); 03651 } 03652 03653 if (!MSI_RecordIsNull(row,8)) 03654 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8)); 03655 03656 if (!MSI_RecordIsNull(row,9)) 03657 { 03658 INT index; 03659 LPCWSTR icon = MSI_RecordGetString(row, 9); 03660 03661 path = msi_build_icon_path(package, icon); 03662 index = MSI_RecordGetInteger(row,10); 03663 03664 /* no value means 0 */ 03665 if (index == MSI_NULL_INTEGER) 03666 index = 0; 03667 03668 IShellLinkW_SetIconLocation(sl, path, index); 03669 msi_free(path); 03670 } 03671 03672 if (!MSI_RecordIsNull(row,11)) 03673 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11)); 03674 03675 if (!MSI_RecordIsNull(row,12)) 03676 { 03677 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 ); 03678 full_path = msi_get_target_folder( package, wkdir ); 03679 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path ); 03680 } 03681 link_file = get_link_file(package, row); 03682 03683 TRACE("Writing shortcut to %s\n", debugstr_w(link_file)); 03684 IPersistFile_Save(pf, link_file, FALSE); 03685 msi_free(link_file); 03686 03687 err: 03688 if (pf) 03689 IPersistFile_Release( pf ); 03690 if (sl) 03691 IShellLinkW_Release( sl ); 03692 03693 return ERROR_SUCCESS; 03694 } 03695 03696 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) 03697 { 03698 static const WCHAR query[] = { 03699 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 03700 '`','S','h','o','r','t','c','u','t','`',0}; 03701 MSIQUERY *view; 03702 HRESULT res; 03703 UINT rc; 03704 03705 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 03706 if (rc != ERROR_SUCCESS) 03707 return ERROR_SUCCESS; 03708 03709 res = CoInitialize( NULL ); 03710 03711 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package); 03712 msiobj_release(&view->hdr); 03713 03714 if (SUCCEEDED(res)) CoUninitialize(); 03715 return rc; 03716 } 03717 03718 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param ) 03719 { 03720 MSIPACKAGE *package = param; 03721 LPWSTR link_file; 03722 LPCWSTR component; 03723 MSICOMPONENT *comp; 03724 03725 component = MSI_RecordGetString( row, 4 ); 03726 comp = msi_get_loaded_component( package, component ); 03727 if (!comp) 03728 return ERROR_SUCCESS; 03729 03730 comp->Action = msi_get_component_action( package, comp ); 03731 if (comp->Action != INSTALLSTATE_ABSENT) 03732 { 03733 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 03734 return ERROR_SUCCESS; 03735 } 03736 msi_ui_actiondata( package, szRemoveShortcuts, row ); 03737 03738 link_file = get_link_file( package, row ); 03739 03740 TRACE("Removing shortcut file %s\n", debugstr_w( link_file )); 03741 if (!DeleteFileW( link_file )) 03742 { 03743 WARN("Failed to remove shortcut file %u\n", GetLastError()); 03744 } 03745 msi_free( link_file ); 03746 03747 return ERROR_SUCCESS; 03748 } 03749 03750 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package ) 03751 { 03752 static const WCHAR query[] = { 03753 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 03754 '`','S','h','o','r','t','c','u','t','`',0}; 03755 MSIQUERY *view; 03756 UINT rc; 03757 03758 rc = MSI_DatabaseOpenViewW( package->db, query, &view ); 03759 if (rc != ERROR_SUCCESS) 03760 return ERROR_SUCCESS; 03761 03762 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package ); 03763 msiobj_release( &view->hdr ); 03764 return rc; 03765 } 03766 03767 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param) 03768 { 03769 MSIPACKAGE* package = param; 03770 HANDLE the_file; 03771 LPWSTR FilePath; 03772 LPCWSTR FileName; 03773 CHAR buffer[1024]; 03774 DWORD sz; 03775 UINT rc; 03776 03777 FileName = MSI_RecordGetString(row,1); 03778 if (!FileName) 03779 { 03780 ERR("Unable to get FileName\n"); 03781 return ERROR_SUCCESS; 03782 } 03783 03784 FilePath = msi_build_icon_path(package, FileName); 03785 03786 TRACE("Creating icon file at %s\n",debugstr_w(FilePath)); 03787 03788 the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 03789 FILE_ATTRIBUTE_NORMAL, NULL); 03790 03791 if (the_file == INVALID_HANDLE_VALUE) 03792 { 03793 ERR("Unable to create file %s\n",debugstr_w(FilePath)); 03794 msi_free(FilePath); 03795 return ERROR_SUCCESS; 03796 } 03797 03798 do 03799 { 03800 DWORD write; 03801 sz = 1024; 03802 rc = MSI_RecordReadStream(row,2,buffer,&sz); 03803 if (rc != ERROR_SUCCESS) 03804 { 03805 ERR("Failed to get stream\n"); 03806 CloseHandle(the_file); 03807 DeleteFileW(FilePath); 03808 break; 03809 } 03810 WriteFile(the_file,buffer,sz,&write,NULL); 03811 } while (sz == 1024); 03812 03813 msi_free(FilePath); 03814 CloseHandle(the_file); 03815 03816 return ERROR_SUCCESS; 03817 } 03818 03819 static UINT msi_publish_icons(MSIPACKAGE *package) 03820 { 03821 static const WCHAR query[]= { 03822 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 03823 '`','I','c','o','n','`',0}; 03824 MSIQUERY *view; 03825 UINT r; 03826 03827 r = MSI_DatabaseOpenViewW(package->db, query, &view); 03828 if (r == ERROR_SUCCESS) 03829 { 03830 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package); 03831 msiobj_release(&view->hdr); 03832 if (r != ERROR_SUCCESS) 03833 return r; 03834 } 03835 return ERROR_SUCCESS; 03836 } 03837 03838 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey) 03839 { 03840 UINT r; 03841 HKEY source; 03842 LPWSTR buffer; 03843 MSIMEDIADISK *disk; 03844 MSISOURCELISTINFO *info; 03845 03846 r = RegCreateKeyW(hkey, szSourceList, &source); 03847 if (r != ERROR_SUCCESS) 03848 return r; 03849 03850 RegCloseKey(source); 03851 03852 buffer = strrchrW(package->PackagePath, '\\') + 1; 03853 r = MsiSourceListSetInfoW(package->ProductCode, NULL, 03854 package->Context, MSICODE_PRODUCT, 03855 INSTALLPROPERTY_PACKAGENAMEW, buffer); 03856 if (r != ERROR_SUCCESS) 03857 return r; 03858 03859 r = MsiSourceListSetInfoW(package->ProductCode, NULL, 03860 package->Context, MSICODE_PRODUCT, 03861 INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty); 03862 if (r != ERROR_SUCCESS) 03863 return r; 03864 03865 r = MsiSourceListSetInfoW(package->ProductCode, NULL, 03866 package->Context, MSICODE_PRODUCT, 03867 INSTALLPROPERTY_DISKPROMPTW, szEmpty); 03868 if (r != ERROR_SUCCESS) 03869 return r; 03870 03871 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry) 03872 { 03873 if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW )) 03874 msi_set_last_used_source(package->ProductCode, NULL, info->context, 03875 info->options, info->value); 03876 else 03877 MsiSourceListSetInfoW(package->ProductCode, NULL, 03878 info->context, info->options, 03879 info->property, info->value); 03880 } 03881 03882 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry) 03883 { 03884 MsiSourceListAddMediaDiskW(package->ProductCode, NULL, 03885 disk->context, disk->options, 03886 disk->disk_id, disk->volume_label, disk->disk_prompt); 03887 } 03888 03889 return ERROR_SUCCESS; 03890 } 03891 03892 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey) 03893 { 03894 MSIHANDLE hdb, suminfo; 03895 WCHAR guids[MAX_PATH]; 03896 WCHAR packcode[SQUISH_GUID_SIZE]; 03897 LPWSTR buffer; 03898 LPWSTR ptr; 03899 DWORD langid; 03900 DWORD size; 03901 UINT r; 03902 03903 static const WCHAR szARPProductIcon[] = 03904 {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0}; 03905 static const WCHAR szAssignment[] = 03906 {'A','s','s','i','g','n','m','e','n','t',0}; 03907 static const WCHAR szAdvertiseFlags[] = 03908 {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0}; 03909 static const WCHAR szClients[] = 03910 {'C','l','i','e','n','t','s',0}; 03911 static const WCHAR szColon[] = {':',0}; 03912 03913 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW); 03914 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer); 03915 msi_free(buffer); 03916 03917 langid = msi_get_property_int(package->db, szProductLanguage, 0); 03918 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid); 03919 03920 /* FIXME */ 03921 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0); 03922 03923 buffer = msi_dup_property(package->db, szARPProductIcon); 03924 if (buffer) 03925 { 03926 LPWSTR path = msi_build_icon_path(package, buffer); 03927 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path); 03928 msi_free(path); 03929 msi_free(buffer); 03930 } 03931 03932 buffer = msi_dup_property(package->db, szProductVersion); 03933 if (buffer) 03934 { 03935 DWORD verdword = msi_version_str_to_dword(buffer); 03936 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword); 03937 msi_free(buffer); 03938 } 03939 03940 msi_reg_set_val_dword(hkey, szAssignment, 0); 03941 msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184); 03942 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0); 03943 msi_reg_set_val_str(hkey, szClients, szColon); 03944 03945 hdb = alloc_msihandle(&package->db->hdr); 03946 if (!hdb) 03947 return ERROR_NOT_ENOUGH_MEMORY; 03948 03949 r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo); 03950 MsiCloseHandle(hdb); 03951 if (r != ERROR_SUCCESS) 03952 goto done; 03953 03954 size = MAX_PATH; 03955 r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL, 03956 NULL, guids, &size); 03957 if (r != ERROR_SUCCESS) 03958 goto done; 03959 03960 ptr = strchrW(guids, ';'); 03961 if (ptr) *ptr = 0; 03962 squash_guid(guids, packcode); 03963 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode); 03964 03965 done: 03966 MsiCloseHandle(suminfo); 03967 return ERROR_SUCCESS; 03968 } 03969 03970 static UINT msi_publish_upgrade_code(MSIPACKAGE *package) 03971 { 03972 UINT r; 03973 HKEY hkey; 03974 LPWSTR upgrade; 03975 WCHAR squashed_pc[SQUISH_GUID_SIZE]; 03976 03977 upgrade = msi_dup_property(package->db, szUpgradeCode); 03978 if (!upgrade) 03979 return ERROR_SUCCESS; 03980 03981 if (package->Context == MSIINSTALLCONTEXT_MACHINE) 03982 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE); 03983 else 03984 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE); 03985 03986 if (r != ERROR_SUCCESS) 03987 { 03988 WARN("failed to open upgrade code key\n"); 03989 msi_free(upgrade); 03990 return ERROR_SUCCESS; 03991 } 03992 squash_guid(package->ProductCode, squashed_pc); 03993 msi_reg_set_val_str(hkey, squashed_pc, NULL); 03994 RegCloseKey(hkey); 03995 msi_free(upgrade); 03996 return ERROR_SUCCESS; 03997 } 03998 03999 static BOOL msi_check_publish(MSIPACKAGE *package) 04000 { 04001 MSIFEATURE *feature; 04002 04003 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry) 04004 { 04005 feature->Action = msi_get_feature_action( package, feature ); 04006 if (feature->Action == INSTALLSTATE_LOCAL) 04007 return TRUE; 04008 } 04009 04010 return FALSE; 04011 } 04012 04013 static BOOL msi_check_unpublish(MSIPACKAGE *package) 04014 { 04015 MSIFEATURE *feature; 04016 04017 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry) 04018 { 04019 feature->Action = msi_get_feature_action( package, feature ); 04020 if (feature->Action != INSTALLSTATE_ABSENT) 04021 return FALSE; 04022 } 04023 04024 return TRUE; 04025 } 04026 04027 static UINT msi_publish_patches( MSIPACKAGE *package ) 04028 { 04029 static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0}; 04030 WCHAR patch_squashed[GUID_SIZE]; 04031 HKEY patches_key = NULL, product_patches_key = NULL, product_key; 04032 LONG res; 04033 MSIPATCHINFO *patch; 04034 UINT r; 04035 WCHAR *p, *all_patches = NULL; 04036 DWORD len = 0; 04037 04038 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE ); 04039 if (r != ERROR_SUCCESS) 04040 return ERROR_FUNCTION_FAILED; 04041 04042 res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL ); 04043 if (res != ERROR_SUCCESS) 04044 { 04045 r = ERROR_FUNCTION_FAILED; 04046 goto done; 04047 } 04048 04049 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE ); 04050 if (r != ERROR_SUCCESS) 04051 goto done; 04052 04053 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry ) 04054 { 04055 squash_guid( patch->patchcode, patch_squashed ); 04056 len += strlenW( patch_squashed ) + 1; 04057 } 04058 04059 p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) ); 04060 if (!all_patches) 04061 goto done; 04062 04063 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry ) 04064 { 04065 HKEY patch_key; 04066 04067 squash_guid( patch->patchcode, p ); 04068 p += strlenW( p ) + 1; 04069 04070 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ, 04071 (const BYTE *)patch->transforms, 04072 (strlenW(patch->transforms) + 1) * sizeof(WCHAR) ); 04073 if (res != ERROR_SUCCESS) 04074 goto done; 04075 04076 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE ); 04077 if (r != ERROR_SUCCESS) 04078 goto done; 04079 04080 res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile, 04081 (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) ); 04082 RegCloseKey( patch_key ); 04083 if (res != ERROR_SUCCESS) 04084 goto done; 04085 04086 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE )) 04087 { 04088 res = GetLastError(); 04089 ERR("Unable to copy patch package %d\n", res); 04090 goto done; 04091 } 04092 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL ); 04093 if (res != ERROR_SUCCESS) 04094 goto done; 04095 04096 res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) ); 04097 RegCloseKey( patch_key ); 04098 if (res != ERROR_SUCCESS) 04099 goto done; 04100 } 04101 04102 all_patches[len] = 0; 04103 res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ, 04104 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) ); 04105 if (res != ERROR_SUCCESS) 04106 goto done; 04107 04108 res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ, 04109 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) ); 04110 if (res != ERROR_SUCCESS) 04111 r = ERROR_FUNCTION_FAILED; 04112 04113 done: 04114 RegCloseKey( product_patches_key ); 04115 RegCloseKey( patches_key ); 04116 RegCloseKey( product_key ); 04117 msi_free( all_patches ); 04118 return r; 04119 } 04120 04121 static UINT ACTION_PublishProduct(MSIPACKAGE *package) 04122 { 04123 UINT rc; 04124 HKEY hukey = NULL, hudkey = NULL; 04125 MSIRECORD *uirow; 04126 04127 if (!list_empty(&package->patches)) 04128 { 04129 rc = msi_publish_patches(package); 04130 if (rc != ERROR_SUCCESS) 04131 goto end; 04132 } 04133 04134 /* FIXME: also need to publish if the product is in advertise mode */ 04135 if (!msi_check_publish(package)) 04136 return ERROR_SUCCESS; 04137 04138 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context, 04139 &hukey, TRUE); 04140 if (rc != ERROR_SUCCESS) 04141 goto end; 04142 04143 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context, 04144 NULL, &hudkey, TRUE); 04145 if (rc != ERROR_SUCCESS) 04146 goto end; 04147 04148 rc = msi_publish_upgrade_code(package); 04149 if (rc != ERROR_SUCCESS) 04150 goto end; 04151 04152 rc = msi_publish_product_properties(package, hukey); 04153 if (rc != ERROR_SUCCESS) 04154 goto end; 04155 04156 rc = msi_publish_sourcelist(package, hukey); 04157 if (rc != ERROR_SUCCESS) 04158 goto end; 04159 04160 rc = msi_publish_icons(package); 04161 04162 end: 04163 uirow = MSI_CreateRecord( 1 ); 04164 MSI_RecordSetStringW( uirow, 1, package->ProductCode ); 04165 msi_ui_actiondata( package, szPublishProduct, uirow ); 04166 msiobj_release( &uirow->hdr ); 04167 04168 RegCloseKey(hukey); 04169 RegCloseKey(hudkey); 04170 return rc; 04171 } 04172 04173 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row ) 04174 { 04175 WCHAR *filename, *ptr, *folder, *ret; 04176 const WCHAR *dirprop; 04177 04178 filename = msi_dup_record_field( row, 2 ); 04179 if (filename && (ptr = strchrW( filename, '|' ))) 04180 ptr++; 04181 else 04182 ptr = filename; 04183 04184 dirprop = MSI_RecordGetString( row, 3 ); 04185 if (dirprop) 04186 { 04187 folder = strdupW( msi_get_target_folder( package, dirprop ) ); 04188 if (!folder) folder = msi_dup_property( package->db, dirprop ); 04189 } 04190 else 04191 folder = msi_dup_property( package->db, szWindowsFolder ); 04192 04193 if (!folder) 04194 { 04195 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop)); 04196 msi_free( filename ); 04197 return NULL; 04198 } 04199 04200 ret = msi_build_directory_name( 2, folder, ptr ); 04201 04202 msi_free( filename ); 04203 msi_free( folder ); 04204 return ret; 04205 } 04206 04207 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param) 04208 { 04209 MSIPACKAGE *package = param; 04210 LPCWSTR component, section, key, value, identifier; 04211 LPWSTR deformated_section, deformated_key, deformated_value, fullname; 04212 MSIRECORD * uirow; 04213 INT action; 04214 MSICOMPONENT *comp; 04215 04216 component = MSI_RecordGetString(row, 8); 04217 comp = msi_get_loaded_component(package,component); 04218 if (!comp) 04219 return ERROR_SUCCESS; 04220 04221 comp->Action = msi_get_component_action( package, comp ); 04222 if (comp->Action != INSTALLSTATE_LOCAL) 04223 { 04224 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 04225 return ERROR_SUCCESS; 04226 } 04227 04228 identifier = MSI_RecordGetString(row,1); 04229 section = MSI_RecordGetString(row,4); 04230 key = MSI_RecordGetString(row,5); 04231 value = MSI_RecordGetString(row,6); 04232 action = MSI_RecordGetInteger(row,7); 04233 04234 deformat_string(package,section,&deformated_section); 04235 deformat_string(package,key,&deformated_key); 04236 deformat_string(package,value,&deformated_value); 04237 04238 fullname = get_ini_file_name(package, row); 04239 04240 if (action == 0) 04241 { 04242 TRACE("Adding value %s to section %s in %s\n", 04243 debugstr_w(deformated_key), debugstr_w(deformated_section), 04244 debugstr_w(fullname)); 04245 WritePrivateProfileStringW(deformated_section, deformated_key, 04246 deformated_value, fullname); 04247 } 04248 else if (action == 1) 04249 { 04250 WCHAR returned[10]; 04251 GetPrivateProfileStringW(deformated_section, deformated_key, NULL, 04252 returned, 10, fullname); 04253 if (returned[0] == 0) 04254 { 04255 TRACE("Adding value %s to section %s in %s\n", 04256 debugstr_w(deformated_key), debugstr_w(deformated_section), 04257 debugstr_w(fullname)); 04258 04259 WritePrivateProfileStringW(deformated_section, deformated_key, 04260 deformated_value, fullname); 04261 } 04262 } 04263 else if (action == 3) 04264 FIXME("Append to existing section not yet implemented\n"); 04265 04266 uirow = MSI_CreateRecord(4); 04267 MSI_RecordSetStringW(uirow,1,identifier); 04268 MSI_RecordSetStringW(uirow,2,deformated_section); 04269 MSI_RecordSetStringW(uirow,3,deformated_key); 04270 MSI_RecordSetStringW(uirow,4,deformated_value); 04271 msi_ui_actiondata( package, szWriteIniValues, uirow ); 04272 msiobj_release( &uirow->hdr ); 04273 04274 msi_free(fullname); 04275 msi_free(deformated_key); 04276 msi_free(deformated_value); 04277 msi_free(deformated_section); 04278 return ERROR_SUCCESS; 04279 } 04280 04281 static UINT ACTION_WriteIniValues(MSIPACKAGE *package) 04282 { 04283 static const WCHAR query[] = { 04284 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 04285 '`','I','n','i','F','i','l','e','`',0}; 04286 MSIQUERY *view; 04287 UINT rc; 04288 04289 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 04290 if (rc != ERROR_SUCCESS) 04291 return ERROR_SUCCESS; 04292 04293 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package); 04294 msiobj_release(&view->hdr); 04295 return rc; 04296 } 04297 04298 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param ) 04299 { 04300 MSIPACKAGE *package = param; 04301 LPCWSTR component, section, key, value, identifier; 04302 LPWSTR deformated_section, deformated_key, deformated_value, filename; 04303 MSICOMPONENT *comp; 04304 MSIRECORD *uirow; 04305 INT action; 04306 04307 component = MSI_RecordGetString( row, 8 ); 04308 comp = msi_get_loaded_component( package, component ); 04309 if (!comp) 04310 return ERROR_SUCCESS; 04311 04312 comp->Action = msi_get_component_action( package, comp ); 04313 if (comp->Action != INSTALLSTATE_ABSENT) 04314 { 04315 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 04316 return ERROR_SUCCESS; 04317 } 04318 04319 identifier = MSI_RecordGetString( row, 1 ); 04320 section = MSI_RecordGetString( row, 4 ); 04321 key = MSI_RecordGetString( row, 5 ); 04322 value = MSI_RecordGetString( row, 6 ); 04323 action = MSI_RecordGetInteger( row, 7 ); 04324 04325 deformat_string( package, section, &deformated_section ); 04326 deformat_string( package, key, &deformated_key ); 04327 deformat_string( package, value, &deformated_value ); 04328 04329 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine) 04330 { 04331 filename = get_ini_file_name( package, row ); 04332 04333 TRACE("Removing key %s from section %s in %s\n", 04334 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename)); 04335 04336 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename )) 04337 { 04338 WARN("Unable to remove key %u\n", GetLastError()); 04339 } 04340 msi_free( filename ); 04341 } 04342 else 04343 FIXME("Unsupported action %d\n", action); 04344 04345 04346 uirow = MSI_CreateRecord( 4 ); 04347 MSI_RecordSetStringW( uirow, 1, identifier ); 04348 MSI_RecordSetStringW( uirow, 2, deformated_section ); 04349 MSI_RecordSetStringW( uirow, 3, deformated_key ); 04350 MSI_RecordSetStringW( uirow, 4, deformated_value ); 04351 msi_ui_actiondata( package, szRemoveIniValues, uirow ); 04352 msiobj_release( &uirow->hdr ); 04353 04354 msi_free( deformated_key ); 04355 msi_free( deformated_value ); 04356 msi_free( deformated_section ); 04357 return ERROR_SUCCESS; 04358 } 04359 04360 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param ) 04361 { 04362 MSIPACKAGE *package = param; 04363 LPCWSTR component, section, key, value, identifier; 04364 LPWSTR deformated_section, deformated_key, deformated_value, filename; 04365 MSICOMPONENT *comp; 04366 MSIRECORD *uirow; 04367 INT action; 04368 04369 component = MSI_RecordGetString( row, 8 ); 04370 comp = msi_get_loaded_component( package, component ); 04371 if (!comp) 04372 return ERROR_SUCCESS; 04373 04374 comp->Action = msi_get_component_action( package, comp ); 04375 if (comp->Action != INSTALLSTATE_LOCAL) 04376 { 04377 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 04378 return ERROR_SUCCESS; 04379 } 04380 04381 identifier = MSI_RecordGetString( row, 1 ); 04382 section = MSI_RecordGetString( row, 4 ); 04383 key = MSI_RecordGetString( row, 5 ); 04384 value = MSI_RecordGetString( row, 6 ); 04385 action = MSI_RecordGetInteger( row, 7 ); 04386 04387 deformat_string( package, section, &deformated_section ); 04388 deformat_string( package, key, &deformated_key ); 04389 deformat_string( package, value, &deformated_value ); 04390 04391 if (action == msidbIniFileActionRemoveLine) 04392 { 04393 filename = get_ini_file_name( package, row ); 04394 04395 TRACE("Removing key %s from section %s in %s\n", 04396 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename)); 04397 04398 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename )) 04399 { 04400 WARN("Unable to remove key %u\n", GetLastError()); 04401 } 04402 msi_free( filename ); 04403 } 04404 else 04405 FIXME("Unsupported action %d\n", action); 04406 04407 uirow = MSI_CreateRecord( 4 ); 04408 MSI_RecordSetStringW( uirow, 1, identifier ); 04409 MSI_RecordSetStringW( uirow, 2, deformated_section ); 04410 MSI_RecordSetStringW( uirow, 3, deformated_key ); 04411 MSI_RecordSetStringW( uirow, 4, deformated_value ); 04412 msi_ui_actiondata( package, szRemoveIniValues, uirow ); 04413 msiobj_release( &uirow->hdr ); 04414 04415 msi_free( deformated_key ); 04416 msi_free( deformated_value ); 04417 msi_free( deformated_section ); 04418 return ERROR_SUCCESS; 04419 } 04420 04421 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package ) 04422 { 04423 static const WCHAR query[] = { 04424 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 04425 '`','I','n','i','F','i','l','e','`',0}; 04426 static const WCHAR remove_query[] = { 04427 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 04428 '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0}; 04429 MSIQUERY *view; 04430 UINT rc; 04431 04432 rc = MSI_DatabaseOpenViewW( package->db, query, &view ); 04433 if (rc == ERROR_SUCCESS) 04434 { 04435 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package ); 04436 msiobj_release( &view->hdr ); 04437 if (rc != ERROR_SUCCESS) 04438 return rc; 04439 } 04440 rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view ); 04441 if (rc == ERROR_SUCCESS) 04442 { 04443 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package ); 04444 msiobj_release( &view->hdr ); 04445 if (rc != ERROR_SUCCESS) 04446 return rc; 04447 } 04448 return ERROR_SUCCESS; 04449 } 04450 04451 static void register_dll( const WCHAR *dll, BOOL unregister ) 04452 { 04453 HMODULE hmod; 04454 04455 hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH ); 04456 if (hmod) 04457 { 04458 HRESULT (WINAPI *func_ptr)( void ); 04459 const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer"; 04460 04461 func_ptr = (void *)GetProcAddress( hmod, func ); 04462 if (func_ptr) 04463 { 04464 HRESULT hr = func_ptr(); 04465 if (FAILED( hr )) 04466 WARN("failed to register dll 0x%08x\n", hr); 04467 } 04468 else 04469 WARN("entry point %s not found\n", func); 04470 FreeLibrary( hmod ); 04471 return; 04472 } 04473 WARN("failed to load library %u\n", GetLastError()); 04474 } 04475 04476 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param) 04477 { 04478 MSIPACKAGE *package = param; 04479 LPCWSTR filename; 04480 MSIFILE *file; 04481 MSIRECORD *uirow; 04482 04483 filename = MSI_RecordGetString( row, 1 ); 04484 file = msi_get_loaded_file( package, filename ); 04485 if (!file) 04486 { 04487 WARN("unable to find file %s\n", debugstr_w(filename)); 04488 return ERROR_SUCCESS; 04489 } 04490 file->Component->Action = msi_get_component_action( package, file->Component ); 04491 if (file->Component->Action != INSTALLSTATE_LOCAL) 04492 { 04493 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component)); 04494 return ERROR_SUCCESS; 04495 } 04496 04497 TRACE("Registering %s\n", debugstr_w( file->TargetPath )); 04498 register_dll( file->TargetPath, FALSE ); 04499 04500 uirow = MSI_CreateRecord( 2 ); 04501 MSI_RecordSetStringW( uirow, 1, file->File ); 04502 MSI_RecordSetStringW( uirow, 2, file->Component->Directory ); 04503 msi_ui_actiondata( package, szSelfRegModules, uirow ); 04504 msiobj_release( &uirow->hdr ); 04505 04506 return ERROR_SUCCESS; 04507 } 04508 04509 static UINT ACTION_SelfRegModules(MSIPACKAGE *package) 04510 { 04511 static const WCHAR query[] = { 04512 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 04513 '`','S','e','l','f','R','e','g','`',0}; 04514 MSIQUERY *view; 04515 UINT rc; 04516 04517 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 04518 if (rc != ERROR_SUCCESS) 04519 return ERROR_SUCCESS; 04520 04521 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package); 04522 msiobj_release(&view->hdr); 04523 return rc; 04524 } 04525 04526 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param ) 04527 { 04528 MSIPACKAGE *package = param; 04529 LPCWSTR filename; 04530 MSIFILE *file; 04531 MSIRECORD *uirow; 04532 04533 filename = MSI_RecordGetString( row, 1 ); 04534 file = msi_get_loaded_file( package, filename ); 04535 if (!file) 04536 { 04537 WARN("unable to find file %s\n", debugstr_w(filename)); 04538 return ERROR_SUCCESS; 04539 } 04540 file->Component->Action = msi_get_component_action( package, file->Component ); 04541 if (file->Component->Action != INSTALLSTATE_ABSENT) 04542 { 04543 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component)); 04544 return ERROR_SUCCESS; 04545 } 04546 04547 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath )); 04548 register_dll( file->TargetPath, TRUE ); 04549 04550 uirow = MSI_CreateRecord( 2 ); 04551 MSI_RecordSetStringW( uirow, 1, file->File ); 04552 MSI_RecordSetStringW( uirow, 2, file->Component->Directory ); 04553 msi_ui_actiondata( package, szSelfUnregModules, uirow ); 04554 msiobj_release( &uirow->hdr ); 04555 04556 return ERROR_SUCCESS; 04557 } 04558 04559 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package ) 04560 { 04561 static const WCHAR query[] = { 04562 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 04563 '`','S','e','l','f','R','e','g','`',0}; 04564 MSIQUERY *view; 04565 UINT rc; 04566 04567 rc = MSI_DatabaseOpenViewW( package->db, query, &view ); 04568 if (rc != ERROR_SUCCESS) 04569 return ERROR_SUCCESS; 04570 04571 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package ); 04572 msiobj_release( &view->hdr ); 04573 return rc; 04574 } 04575 04576 static UINT ACTION_PublishFeatures(MSIPACKAGE *package) 04577 { 04578 MSIFEATURE *feature; 04579 UINT rc; 04580 HKEY hkey = NULL, userdata = NULL; 04581 04582 if (!msi_check_publish(package)) 04583 return ERROR_SUCCESS; 04584 04585 rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context, 04586 &hkey, TRUE); 04587 if (rc != ERROR_SUCCESS) 04588 goto end; 04589 04590 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context, 04591 &userdata, TRUE); 04592 if (rc != ERROR_SUCCESS) 04593 goto end; 04594 04595 /* here the guids are base 85 encoded */ 04596 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 04597 { 04598 ComponentList *cl; 04599 LPWSTR data = NULL; 04600 GUID clsid; 04601 INT size; 04602 BOOL absent = FALSE; 04603 MSIRECORD *uirow; 04604 04605 if (feature->Action != INSTALLSTATE_LOCAL && 04606 feature->Action != INSTALLSTATE_SOURCE && 04607 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE; 04608 04609 size = 1; 04610 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) 04611 { 04612 size += 21; 04613 } 04614 if (feature->Feature_Parent) 04615 size += strlenW( feature->Feature_Parent )+2; 04616 04617 data = msi_alloc(size * sizeof(WCHAR)); 04618 04619 data[0] = 0; 04620 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) 04621 { 04622 MSICOMPONENT* component = cl->component; 04623 WCHAR buf[21]; 04624 04625 buf[0] = 0; 04626 if (component->ComponentId) 04627 { 04628 TRACE("From %s\n",debugstr_w(component->ComponentId)); 04629 CLSIDFromString(component->ComponentId, &clsid); 04630 encode_base85_guid(&clsid,buf); 04631 TRACE("to %s\n",debugstr_w(buf)); 04632 strcatW(data,buf); 04633 } 04634 } 04635 04636 if (feature->Feature_Parent) 04637 { 04638 static const WCHAR sep[] = {'\2',0}; 04639 strcatW(data,sep); 04640 strcatW(data,feature->Feature_Parent); 04641 } 04642 04643 msi_reg_set_val_str( userdata, feature->Feature, data ); 04644 msi_free(data); 04645 04646 size = 0; 04647 if (feature->Feature_Parent) 04648 size = strlenW(feature->Feature_Parent)*sizeof(WCHAR); 04649 if (!absent) 04650 { 04651 size += sizeof(WCHAR); 04652 RegSetValueExW(hkey,feature->Feature,0,REG_SZ, 04653 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size); 04654 } 04655 else 04656 { 04657 size += 2*sizeof(WCHAR); 04658 data = msi_alloc(size); 04659 data[0] = 0x6; 04660 data[1] = 0; 04661 if (feature->Feature_Parent) 04662 strcpyW( &data[1], feature->Feature_Parent ); 04663 RegSetValueExW(hkey,feature->Feature,0,REG_SZ, 04664 (LPBYTE)data,size); 04665 msi_free(data); 04666 } 04667 04668 /* the UI chunk */ 04669 uirow = MSI_CreateRecord( 1 ); 04670 MSI_RecordSetStringW( uirow, 1, feature->Feature ); 04671 msi_ui_actiondata( package, szPublishFeatures, uirow ); 04672 msiobj_release( &uirow->hdr ); 04673 /* FIXME: call msi_ui_progress? */ 04674 } 04675 04676 end: 04677 RegCloseKey(hkey); 04678 RegCloseKey(userdata); 04679 return rc; 04680 } 04681 04682 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature) 04683 { 04684 UINT r; 04685 HKEY hkey; 04686 MSIRECORD *uirow; 04687 04688 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature)); 04689 04690 r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context, 04691 &hkey, FALSE); 04692 if (r == ERROR_SUCCESS) 04693 { 04694 RegDeleteValueW(hkey, feature->Feature); 04695 RegCloseKey(hkey); 04696 } 04697 04698 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context, 04699 &hkey, FALSE); 04700 if (r == ERROR_SUCCESS) 04701 { 04702 RegDeleteValueW(hkey, feature->Feature); 04703 RegCloseKey(hkey); 04704 } 04705 04706 uirow = MSI_CreateRecord( 1 ); 04707 MSI_RecordSetStringW( uirow, 1, feature->Feature ); 04708 msi_ui_actiondata( package, szUnpublishFeatures, uirow ); 04709 msiobj_release( &uirow->hdr ); 04710 04711 return ERROR_SUCCESS; 04712 } 04713 04714 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package) 04715 { 04716 MSIFEATURE *feature; 04717 04718 if (!msi_check_unpublish(package)) 04719 return ERROR_SUCCESS; 04720 04721 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry) 04722 { 04723 msi_unpublish_feature(package, feature); 04724 } 04725 04726 return ERROR_SUCCESS; 04727 } 04728 04729 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey) 04730 { 04731 SYSTEMTIME systime; 04732 DWORD size, langid; 04733 WCHAR date[9], *val, *buffer; 04734 const WCHAR *prop, *key; 04735 04736 static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0}; 04737 static const WCHAR modpath_fmt[] = 04738 {'M','s','i','E','x','e','c','.','e','x','e',' ', 04739 '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0}; 04740 static const WCHAR szModifyPath[] = 04741 {'M','o','d','i','f','y','P','a','t','h',0}; 04742 static const WCHAR szUninstallString[] = 04743 {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0}; 04744 static const WCHAR szEstimatedSize[] = 04745 {'E','s','t','i','m','a','t','e','d','S','i','z','e',0}; 04746 static const WCHAR szDisplayVersion[] = 04747 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0}; 04748 static const WCHAR szInstallSource[] = 04749 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0}; 04750 static const WCHAR szARPAUTHORIZEDCDFPREFIX[] = 04751 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0}; 04752 static const WCHAR szAuthorizedCDFPrefix[] = 04753 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0}; 04754 static const WCHAR szARPCONTACT[] = 04755 {'A','R','P','C','O','N','T','A','C','T',0}; 04756 static const WCHAR szContact[] = 04757 {'C','o','n','t','a','c','t',0}; 04758 static const WCHAR szARPCOMMENTS[] = 04759 {'A','R','P','C','O','M','M','E','N','T','S',0}; 04760 static const WCHAR szComments[] = 04761 {'C','o','m','m','e','n','t','s',0}; 04762 static const WCHAR szProductName[] = 04763 {'P','r','o','d','u','c','t','N','a','m','e',0}; 04764 static const WCHAR szDisplayName[] = 04765 {'D','i','s','p','l','a','y','N','a','m','e',0}; 04766 static const WCHAR szARPHELPLINK[] = 04767 {'A','R','P','H','E','L','P','L','I','N','K',0}; 04768 static const WCHAR szHelpLink[] = 04769 {'H','e','l','p','L','i','n','k',0}; 04770 static const WCHAR szARPHELPTELEPHONE[] = 04771 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0}; 04772 static const WCHAR szHelpTelephone[] = 04773 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0}; 04774 static const WCHAR szARPINSTALLLOCATION[] = 04775 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0}; 04776 static const WCHAR szInstallLocation[] = 04777 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0}; 04778 static const WCHAR szManufacturer[] = 04779 {'M','a','n','u','f','a','c','t','u','r','e','r',0}; 04780 static const WCHAR szPublisher[] = 04781 {'P','u','b','l','i','s','h','e','r',0}; 04782 static const WCHAR szARPREADME[] = 04783 {'A','R','P','R','E','A','D','M','E',0}; 04784 static const WCHAR szReadme[] = 04785 {'R','e','a','d','M','e',0}; 04786 static const WCHAR szARPSIZE[] = 04787 {'A','R','P','S','I','Z','E',0}; 04788 static const WCHAR szSize[] = 04789 {'S','i','z','e',0}; 04790 static const WCHAR szARPURLINFOABOUT[] = 04791 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0}; 04792 static const WCHAR szURLInfoAbout[] = 04793 {'U','R','L','I','n','f','o','A','b','o','u','t',0}; 04794 static const WCHAR szARPURLUPDATEINFO[] = 04795 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0}; 04796 static const WCHAR szURLUpdateInfo[] = 04797 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0}; 04798 static const WCHAR szARPSYSTEMCOMPONENT[] = 04799 {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0}; 04800 static const WCHAR szSystemComponent[] = 04801 {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0}; 04802 04803 static const WCHAR *propval[] = { 04804 szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix, 04805 szARPCONTACT, szContact, 04806 szARPCOMMENTS, szComments, 04807 szProductName, szDisplayName, 04808 szARPHELPLINK, szHelpLink, 04809 szARPHELPTELEPHONE, szHelpTelephone, 04810 szARPINSTALLLOCATION, szInstallLocation, 04811 szSourceDir, szInstallSource, 04812 szManufacturer, szPublisher, 04813 szARPREADME, szReadme, 04814 szARPSIZE, szSize, 04815 szARPURLINFOABOUT, szURLInfoAbout, 04816 szARPURLUPDATEINFO, szURLUpdateInfo, 04817 NULL 04818 }; 04819 const WCHAR **p = propval; 04820 04821 while (*p) 04822 { 04823 prop = *p++; 04824 key = *p++; 04825 val = msi_dup_property(package->db, prop); 04826 msi_reg_set_val_str(hkey, key, val); 04827 msi_free(val); 04828 } 04829 04830 msi_reg_set_val_dword(hkey, szWindowsInstaller, 1); 04831 if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 )) 04832 { 04833 msi_reg_set_val_dword( hkey, szSystemComponent, 1 ); 04834 } 04835 size = deformat_string(package, modpath_fmt, &buffer); 04836 RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size); 04837 RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size); 04838 msi_free(buffer); 04839 04840 /* FIXME: Write real Estimated Size when we have it */ 04841 msi_reg_set_val_dword(hkey, szEstimatedSize, 0); 04842 04843 GetLocalTime(&systime); 04844 sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay); 04845 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date); 04846 04847 langid = msi_get_property_int(package->db, szProductLanguage, 0); 04848 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid); 04849 04850 buffer = msi_dup_property(package->db, szProductVersion); 04851 msi_reg_set_val_str(hkey, szDisplayVersion, buffer); 04852 if (buffer) 04853 { 04854 DWORD verdword = msi_version_str_to_dword(buffer); 04855 04856 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword); 04857 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24); 04858 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF); 04859 msi_free(buffer); 04860 } 04861 04862 return ERROR_SUCCESS; 04863 } 04864 04865 static UINT ACTION_RegisterProduct(MSIPACKAGE *package) 04866 { 04867 WCHAR squashed_pc[SQUISH_GUID_SIZE]; 04868 MSIRECORD *uirow; 04869 LPWSTR upgrade_code; 04870 HKEY hkey, props, upgrade_key; 04871 UINT rc; 04872 04873 /* FIXME: also need to publish if the product is in advertise mode */ 04874 if (!msi_check_publish(package)) 04875 return ERROR_SUCCESS; 04876 04877 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE); 04878 if (rc != ERROR_SUCCESS) 04879 return rc; 04880 04881 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE); 04882 if (rc != ERROR_SUCCESS) 04883 goto done; 04884 04885 rc = msi_publish_install_properties(package, hkey); 04886 if (rc != ERROR_SUCCESS) 04887 goto done; 04888 04889 rc = msi_publish_install_properties(package, props); 04890 if (rc != ERROR_SUCCESS) 04891 goto done; 04892 04893 upgrade_code = msi_dup_property(package->db, szUpgradeCode); 04894 if (upgrade_code) 04895 { 04896 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE ); 04897 if (rc == ERROR_SUCCESS) 04898 { 04899 squash_guid( package->ProductCode, squashed_pc ); 04900 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL ); 04901 RegCloseKey( upgrade_key ); 04902 } 04903 msi_free( upgrade_code ); 04904 } 04905 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile ); 04906 package->delete_on_close = FALSE; 04907 04908 done: 04909 uirow = MSI_CreateRecord( 1 ); 04910 MSI_RecordSetStringW( uirow, 1, package->ProductCode ); 04911 msi_ui_actiondata( package, szRegisterProduct, uirow ); 04912 msiobj_release( &uirow->hdr ); 04913 04914 RegCloseKey(hkey); 04915 return ERROR_SUCCESS; 04916 } 04917 04918 static UINT ACTION_InstallExecute(MSIPACKAGE *package) 04919 { 04920 return execute_script(package, SCRIPT_INSTALL); 04921 } 04922 04923 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param ) 04924 { 04925 MSIPACKAGE *package = param; 04926 const WCHAR *icon = MSI_RecordGetString( row, 1 ); 04927 WCHAR *p, *icon_path; 04928 04929 if (!icon) return ERROR_SUCCESS; 04930 if ((icon_path = msi_build_icon_path( package, icon ))) 04931 { 04932 TRACE("removing icon file %s\n", debugstr_w(icon_path)); 04933 DeleteFileW( icon_path ); 04934 if ((p = strrchrW( icon_path, '\\' ))) 04935 { 04936 *p = 0; 04937 RemoveDirectoryW( icon_path ); 04938 } 04939 msi_free( icon_path ); 04940 } 04941 return ERROR_SUCCESS; 04942 } 04943 04944 static UINT msi_unpublish_icons( MSIPACKAGE *package ) 04945 { 04946 static const WCHAR query[]= { 04947 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0}; 04948 MSIQUERY *view; 04949 UINT r; 04950 04951 r = MSI_DatabaseOpenViewW( package->db, query, &view ); 04952 if (r == ERROR_SUCCESS) 04953 { 04954 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package ); 04955 msiobj_release( &view->hdr ); 04956 if (r != ERROR_SUCCESS) 04957 return r; 04958 } 04959 return ERROR_SUCCESS; 04960 } 04961 04962 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove ) 04963 { 04964 static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0}; 04965 WCHAR *upgrade, **features; 04966 BOOL full_uninstall = TRUE; 04967 MSIFEATURE *feature; 04968 MSIPATCHINFO *patch; 04969 UINT i; 04970 04971 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) 04972 { 04973 if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE; 04974 } 04975 features = msi_split_string( remove, ',' ); 04976 for (i = 0; features && features[i]; i++) 04977 { 04978 if (!strcmpW( features[i], szAll )) full_uninstall = TRUE; 04979 } 04980 msi_free(features); 04981 04982 if (!full_uninstall) 04983 return ERROR_SUCCESS; 04984 04985 MSIREG_DeleteProductKey(package->ProductCode); 04986 MSIREG_DeleteUserDataProductKey(package->ProductCode); 04987 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform); 04988 04989 MSIREG_DeleteLocalClassesProductKey(package->ProductCode); 04990 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode); 04991 MSIREG_DeleteUserProductKey(package->ProductCode); 04992 MSIREG_DeleteUserFeaturesKey(package->ProductCode); 04993 04994 upgrade = msi_dup_property(package->db, szUpgradeCode); 04995 if (upgrade) 04996 { 04997 MSIREG_DeleteUserUpgradeCodesKey(upgrade); 04998 MSIREG_DeleteClassesUpgradeCodesKey(upgrade); 04999 msi_free(upgrade); 05000 } 05001 05002 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry) 05003 { 05004 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context); 05005 if (!strcmpW( package->ProductCode, patch->products )) 05006 { 05007 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile)); 05008 patch->delete_on_close = TRUE; 05009 } 05010 /* FIXME: remove local patch package if this is the last product */ 05011 } 05012 TRACE("removing local package %s\n", debugstr_w(package->localfile)); 05013 package->delete_on_close = TRUE; 05014 05015 msi_unpublish_icons( package ); 05016 return ERROR_SUCCESS; 05017 } 05018 05019 static UINT ACTION_InstallFinalize(MSIPACKAGE *package) 05020 { 05021 UINT rc; 05022 WCHAR *remove; 05023 05024 /* turn off scheduling */ 05025 package->script->CurrentlyScripting= FALSE; 05026 05027 /* first do the same as an InstallExecute */ 05028 rc = ACTION_InstallExecute(package); 05029 if (rc != ERROR_SUCCESS) 05030 return rc; 05031 05032 /* then handle commit actions */ 05033 rc = execute_script(package, SCRIPT_COMMIT); 05034 if (rc != ERROR_SUCCESS) 05035 return rc; 05036 05037 remove = msi_dup_property(package->db, szRemove); 05038 rc = msi_unpublish_product(package, remove); 05039 msi_free(remove); 05040 return rc; 05041 } 05042 05043 UINT ACTION_ForceReboot(MSIPACKAGE *package) 05044 { 05045 static const WCHAR RunOnce[] = { 05046 'S','o','f','t','w','a','r','e','\\', 05047 'M','i','c','r','o','s','o','f','t','\\', 05048 'W','i','n','d','o','w','s','\\', 05049 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 05050 'R','u','n','O','n','c','e',0}; 05051 static const WCHAR InstallRunOnce[] = { 05052 'S','o','f','t','w','a','r','e','\\', 05053 'M','i','c','r','o','s','o','f','t','\\', 05054 'W','i','n','d','o','w','s','\\', 05055 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 05056 'I','n','s','t','a','l','l','e','r','\\', 05057 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0}; 05058 05059 static const WCHAR msiexec_fmt[] = { 05060 '%','s', 05061 '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ', 05062 '\"','%','s','\"',0}; 05063 static const WCHAR install_fmt[] = { 05064 '/','I',' ','\"','%','s','\"',' ', 05065 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ', 05066 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0}; 05067 WCHAR buffer[256], sysdir[MAX_PATH]; 05068 HKEY hkey; 05069 WCHAR squished_pc[100]; 05070 05071 squash_guid(package->ProductCode,squished_pc); 05072 05073 GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0])); 05074 RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey); 05075 snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir, 05076 squished_pc); 05077 05078 msi_reg_set_val_str( hkey, squished_pc, buffer ); 05079 RegCloseKey(hkey); 05080 05081 TRACE("Reboot command %s\n",debugstr_w(buffer)); 05082 05083 RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey); 05084 sprintfW(buffer,install_fmt,package->ProductCode,squished_pc); 05085 05086 msi_reg_set_val_str( hkey, squished_pc, buffer ); 05087 RegCloseKey(hkey); 05088 05089 return ERROR_INSTALL_SUSPEND; 05090 } 05091 05092 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... ) 05093 { 05094 static const WCHAR query[] = 05095 {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ', 05096 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ', 05097 '`','E','r','r','o','r','`',' ','=',' ','%','i',0}; 05098 MSIRECORD *rec, *row; 05099 DWORD i, size = 0; 05100 va_list va; 05101 const WCHAR *str; 05102 WCHAR *data; 05103 05104 if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0; 05105 05106 rec = MSI_CreateRecord( count + 2 ); 05107 str = MSI_RecordGetString( row, 1 ); 05108 MSI_RecordSetStringW( rec, 0, str ); 05109 msiobj_release( &row->hdr ); 05110 MSI_RecordSetInteger( rec, 1, error ); 05111 05112 va_start( va, count ); 05113 for (i = 0; i < count; i++) 05114 { 05115 str = va_arg( va, const WCHAR *); 05116 MSI_RecordSetStringW( rec, i + 2, str ); 05117 } 05118 va_end( va ); 05119 05120 MSI_FormatRecordW( package, rec, NULL, &size ); 05121 size++; 05122 data = msi_alloc( size * sizeof(WCHAR) ); 05123 if (size > 1) MSI_FormatRecordW( package, rec, data, &size ); 05124 else data[0] = 0; 05125 msiobj_release( &rec->hdr ); 05126 return data; 05127 } 05128 05129 static UINT ACTION_ResolveSource(MSIPACKAGE* package) 05130 { 05131 DWORD attrib; 05132 UINT rc; 05133 05134 /* 05135 * We are currently doing what should be done here in the top level Install 05136 * however for Administrative and uninstalls this step will be needed 05137 */ 05138 if (!package->PackagePath) 05139 return ERROR_SUCCESS; 05140 05141 msi_set_sourcedir_props(package, TRUE); 05142 05143 attrib = GetFileAttributesW(package->db->path); 05144 if (attrib == INVALID_FILE_ATTRIBUTES) 05145 { 05146 LPWSTR prompt, msg; 05147 DWORD size = 0; 05148 05149 rc = MsiSourceListGetInfoW(package->ProductCode, NULL, 05150 package->Context, MSICODE_PRODUCT, 05151 INSTALLPROPERTY_DISKPROMPTW,NULL,&size); 05152 if (rc == ERROR_MORE_DATA) 05153 { 05154 prompt = msi_alloc(size * sizeof(WCHAR)); 05155 MsiSourceListGetInfoW(package->ProductCode, NULL, 05156 package->Context, MSICODE_PRODUCT, 05157 INSTALLPROPERTY_DISKPROMPTW,prompt,&size); 05158 } 05159 else 05160 prompt = strdupW(package->db->path); 05161 05162 msg = msi_build_error_string(package, 1302, 1, prompt); 05163 msi_free(prompt); 05164 while(attrib == INVALID_FILE_ATTRIBUTES) 05165 { 05166 rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL); 05167 if (rc == IDCANCEL) 05168 { 05169 msi_free(msg); 05170 return ERROR_INSTALL_USEREXIT; 05171 } 05172 attrib = GetFileAttributesW(package->db->path); 05173 } 05174 msi_free(msg); 05175 rc = ERROR_SUCCESS; 05176 } 05177 else 05178 return ERROR_SUCCESS; 05179 05180 return rc; 05181 } 05182 05183 static UINT ACTION_RegisterUser(MSIPACKAGE *package) 05184 { 05185 HKEY hkey = 0; 05186 LPWSTR buffer, productid = NULL; 05187 UINT i, rc = ERROR_SUCCESS; 05188 MSIRECORD *uirow; 05189 05190 static const WCHAR szPropKeys[][80] = 05191 { 05192 {'P','r','o','d','u','c','t','I','D',0}, 05193 {'U','S','E','R','N','A','M','E',0}, 05194 {'C','O','M','P','A','N','Y','N','A','M','E',0}, 05195 {0}, 05196 }; 05197 05198 static const WCHAR szRegKeys[][80] = 05199 { 05200 {'P','r','o','d','u','c','t','I','D',0}, 05201 {'R','e','g','O','w','n','e','r',0}, 05202 {'R','e','g','C','o','m','p','a','n','y',0}, 05203 {0}, 05204 }; 05205 05206 if (msi_check_unpublish(package)) 05207 { 05208 MSIREG_DeleteUserDataProductKey(package->ProductCode); 05209 goto end; 05210 } 05211 05212 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW ); 05213 if (!productid) 05214 goto end; 05215 05216 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, 05217 NULL, &hkey, TRUE); 05218 if (rc != ERROR_SUCCESS) 05219 goto end; 05220 05221 for( i = 0; szPropKeys[i][0]; i++ ) 05222 { 05223 buffer = msi_dup_property( package->db, szPropKeys[i] ); 05224 msi_reg_set_val_str( hkey, szRegKeys[i], buffer ); 05225 msi_free( buffer ); 05226 } 05227 05228 end: 05229 uirow = MSI_CreateRecord( 1 ); 05230 MSI_RecordSetStringW( uirow, 1, productid ); 05231 msi_ui_actiondata( package, szRegisterUser, uirow ); 05232 msiobj_release( &uirow->hdr ); 05233 05234 msi_free(productid); 05235 RegCloseKey(hkey); 05236 return rc; 05237 } 05238 05239 05240 static UINT ACTION_ExecuteAction(MSIPACKAGE *package) 05241 { 05242 UINT rc; 05243 05244 package->script->InWhatSequence |= SEQUENCE_EXEC; 05245 rc = ACTION_ProcessExecSequence(package,FALSE); 05246 return rc; 05247 } 05248 05249 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature ) 05250 { 05251 static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0}; 05252 WCHAR productid_85[21], component_85[21], *ret; 05253 GUID clsid; 05254 DWORD sz; 05255 05256 /* > is used if there is a component GUID and < if not. */ 05257 05258 productid_85[0] = 0; 05259 component_85[0] = 0; 05260 CLSIDFromString( package->ProductCode, &clsid ); 05261 05262 encode_base85_guid( &clsid, productid_85 ); 05263 if (component) 05264 { 05265 CLSIDFromString( component->ComponentId, &clsid ); 05266 encode_base85_guid( &clsid, component_85 ); 05267 } 05268 05269 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature), 05270 debugstr_w(component_85)); 05271 05272 sz = 20 + strlenW( feature ) + 20 + 3; 05273 ret = msi_alloc_zero( sz * sizeof(WCHAR) ); 05274 if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 ); 05275 return ret; 05276 } 05277 05278 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param) 05279 { 05280 MSIPACKAGE *package = param; 05281 LPCWSTR compgroupid, component, feature, qualifier, text; 05282 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q; 05283 HKEY hkey = NULL; 05284 UINT rc; 05285 MSICOMPONENT *comp; 05286 MSIFEATURE *feat; 05287 DWORD sz; 05288 MSIRECORD *uirow; 05289 int len; 05290 05291 feature = MSI_RecordGetString(rec, 5); 05292 feat = msi_get_loaded_feature(package, feature); 05293 if (!feat) 05294 return ERROR_SUCCESS; 05295 05296 feat->Action = msi_get_feature_action( package, feat ); 05297 if (feat->Action != INSTALLSTATE_LOCAL && 05298 feat->Action != INSTALLSTATE_SOURCE && 05299 feat->Action != INSTALLSTATE_ADVERTISED) 05300 { 05301 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature)); 05302 return ERROR_SUCCESS; 05303 } 05304 05305 component = MSI_RecordGetString(rec, 3); 05306 comp = msi_get_loaded_component(package, component); 05307 if (!comp) 05308 return ERROR_SUCCESS; 05309 05310 compgroupid = MSI_RecordGetString(rec,1); 05311 qualifier = MSI_RecordGetString(rec,2); 05312 05313 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE); 05314 if (rc != ERROR_SUCCESS) 05315 goto end; 05316 05317 advertise = msi_create_component_advertise_string( package, comp, feature ); 05318 text = MSI_RecordGetString( rec, 4 ); 05319 if (text) 05320 { 05321 p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) ); 05322 strcpyW( p, advertise ); 05323 strcatW( p, text ); 05324 msi_free( advertise ); 05325 advertise = p; 05326 } 05327 existing = msi_reg_get_val_str( hkey, qualifier ); 05328 05329 sz = strlenW( advertise ) + 1; 05330 if (existing) 05331 { 05332 for (p = existing; *p; p += len) 05333 { 05334 len = strlenW( p ) + 1; 05335 if (strcmpW( advertise, p )) sz += len; 05336 } 05337 } 05338 if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) ))) 05339 { 05340 rc = ERROR_OUTOFMEMORY; 05341 goto end; 05342 } 05343 q = output; 05344 if (existing) 05345 { 05346 for (p = existing; *p; p += len) 05347 { 05348 len = strlenW( p ) + 1; 05349 if (strcmpW( advertise, p )) 05350 { 05351 memcpy( q, p, len * sizeof(WCHAR) ); 05352 q += len; 05353 } 05354 } 05355 } 05356 strcpyW( q, advertise ); 05357 q[strlenW( q ) + 1] = 0; 05358 05359 msi_reg_set_val_multi_str( hkey, qualifier, output ); 05360 05361 end: 05362 RegCloseKey(hkey); 05363 msi_free( output ); 05364 msi_free( advertise ); 05365 msi_free( existing ); 05366 05367 /* the UI chunk */ 05368 uirow = MSI_CreateRecord( 2 ); 05369 MSI_RecordSetStringW( uirow, 1, compgroupid ); 05370 MSI_RecordSetStringW( uirow, 2, qualifier); 05371 msi_ui_actiondata( package, szPublishComponents, uirow ); 05372 msiobj_release( &uirow->hdr ); 05373 /* FIXME: call ui_progress? */ 05374 05375 return rc; 05376 } 05377 05378 /* 05379 * At present I am ignorning the advertised components part of this and only 05380 * focusing on the qualified component sets 05381 */ 05382 static UINT ACTION_PublishComponents(MSIPACKAGE *package) 05383 { 05384 static const WCHAR query[] = { 05385 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 05386 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0}; 05387 MSIQUERY *view; 05388 UINT rc; 05389 05390 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 05391 if (rc != ERROR_SUCCESS) 05392 return ERROR_SUCCESS; 05393 05394 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package); 05395 msiobj_release(&view->hdr); 05396 return rc; 05397 } 05398 05399 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param ) 05400 { 05401 static const WCHAR szInstallerComponents[] = { 05402 'S','o','f','t','w','a','r','e','\\', 05403 'M','i','c','r','o','s','o','f','t','\\', 05404 'I','n','s','t','a','l','l','e','r','\\', 05405 'C','o','m','p','o','n','e','n','t','s','\\',0}; 05406 05407 MSIPACKAGE *package = param; 05408 LPCWSTR compgroupid, component, feature, qualifier; 05409 MSICOMPONENT *comp; 05410 MSIFEATURE *feat; 05411 MSIRECORD *uirow; 05412 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH]; 05413 LONG res; 05414 05415 feature = MSI_RecordGetString( rec, 5 ); 05416 feat = msi_get_loaded_feature( package, feature ); 05417 if (!feat) 05418 return ERROR_SUCCESS; 05419 05420 feat->Action = msi_get_feature_action( package, feat ); 05421 if (feat->Action != INSTALLSTATE_ABSENT) 05422 { 05423 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature)); 05424 return ERROR_SUCCESS; 05425 } 05426 05427 component = MSI_RecordGetString( rec, 3 ); 05428 comp = msi_get_loaded_component( package, component ); 05429 if (!comp) 05430 return ERROR_SUCCESS; 05431 05432 compgroupid = MSI_RecordGetString( rec, 1 ); 05433 qualifier = MSI_RecordGetString( rec, 2 ); 05434 05435 squash_guid( compgroupid, squashed ); 05436 strcpyW( keypath, szInstallerComponents ); 05437 strcatW( keypath, squashed ); 05438 05439 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath ); 05440 if (res != ERROR_SUCCESS) 05441 { 05442 WARN("Unable to delete component key %d\n", res); 05443 } 05444 05445 uirow = MSI_CreateRecord( 2 ); 05446 MSI_RecordSetStringW( uirow, 1, compgroupid ); 05447 MSI_RecordSetStringW( uirow, 2, qualifier ); 05448 msi_ui_actiondata( package, szUnpublishComponents, uirow ); 05449 msiobj_release( &uirow->hdr ); 05450 05451 return ERROR_SUCCESS; 05452 } 05453 05454 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package ) 05455 { 05456 static const WCHAR query[] = { 05457 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 05458 '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0}; 05459 MSIQUERY *view; 05460 UINT rc; 05461 05462 rc = MSI_DatabaseOpenViewW( package->db, query, &view ); 05463 if (rc != ERROR_SUCCESS) 05464 return ERROR_SUCCESS; 05465 05466 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package ); 05467 msiobj_release( &view->hdr ); 05468 return rc; 05469 } 05470 05471 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param) 05472 { 05473 static const WCHAR query[] = 05474 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 05475 '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ', 05476 '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0}; 05477 MSIPACKAGE *package = param; 05478 MSICOMPONENT *component; 05479 MSIRECORD *row; 05480 MSIFILE *file; 05481 SC_HANDLE hscm = NULL, service = NULL; 05482 LPCWSTR comp, key; 05483 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL; 05484 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL; 05485 DWORD serv_type, start_type, err_control; 05486 SERVICE_DESCRIPTIONW sd = {NULL}; 05487 05488 comp = MSI_RecordGetString( rec, 12 ); 05489 component = msi_get_loaded_component( package, comp ); 05490 if (!component) 05491 { 05492 WARN("service component not found\n"); 05493 goto done; 05494 } 05495 component->Action = msi_get_component_action( package, component ); 05496 if (component->Action != INSTALLSTATE_LOCAL) 05497 { 05498 TRACE("component not scheduled for installation %s\n", debugstr_w(comp)); 05499 goto done; 05500 } 05501 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE); 05502 if (!hscm) 05503 { 05504 ERR("Failed to open the SC Manager!\n"); 05505 goto done; 05506 } 05507 05508 start_type = MSI_RecordGetInteger(rec, 5); 05509 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START) 05510 goto done; 05511 05512 deformat_string(package, MSI_RecordGetString(rec, 2), &name); 05513 deformat_string(package, MSI_RecordGetString(rec, 3), &disp); 05514 serv_type = MSI_RecordGetInteger(rec, 4); 05515 err_control = MSI_RecordGetInteger(rec, 6); 05516 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order); 05517 deformat_string(package, MSI_RecordGetString(rec, 8), &depends); 05518 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name); 05519 deformat_string(package, MSI_RecordGetString(rec, 10), &pass); 05520 deformat_string(package, MSI_RecordGetString(rec, 11), &args); 05521 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription); 05522 05523 /* fetch the service path */ 05524 row = MSI_QueryGetRecord(package->db, query, comp); 05525 if (!row) 05526 { 05527 ERR("Query failed\n"); 05528 goto done; 05529 } 05530 key = MSI_RecordGetString(row, 6); 05531 file = msi_get_loaded_file(package, key); 05532 msiobj_release(&row->hdr); 05533 if (!file) 05534 { 05535 ERR("Failed to load the service file\n"); 05536 goto done; 05537 } 05538 05539 if (!args || !args[0]) image_path = file->TargetPath; 05540 else 05541 { 05542 int len = strlenW(file->TargetPath) + strlenW(args) + 2; 05543 if (!(image_path = msi_alloc(len * sizeof(WCHAR)))) 05544 return ERROR_OUTOFMEMORY; 05545 05546 strcpyW(image_path, file->TargetPath); 05547 strcatW(image_path, szSpace); 05548 strcatW(image_path, args); 05549 } 05550 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type, 05551 start_type, err_control, image_path, load_order, 05552 NULL, depends, serv_name, pass); 05553 05554 if (!service) 05555 { 05556 if (GetLastError() != ERROR_SERVICE_EXISTS) 05557 ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError()); 05558 } 05559 else if (sd.lpDescription) 05560 { 05561 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd)) 05562 WARN("failed to set service description %u\n", GetLastError()); 05563 } 05564 05565 if (image_path != file->TargetPath) msi_free(image_path); 05566 done: 05567 CloseServiceHandle(service); 05568 CloseServiceHandle(hscm); 05569 msi_free(name); 05570 msi_free(disp); 05571 msi_free(sd.lpDescription); 05572 msi_free(load_order); 05573 msi_free(serv_name); 05574 msi_free(pass); 05575 msi_free(depends); 05576 msi_free(args); 05577 05578 return ERROR_SUCCESS; 05579 } 05580 05581 static UINT ACTION_InstallServices( MSIPACKAGE *package ) 05582 { 05583 static const WCHAR query[] = { 05584 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 05585 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0}; 05586 MSIQUERY *view; 05587 UINT rc; 05588 05589 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 05590 if (rc != ERROR_SUCCESS) 05591 return ERROR_SUCCESS; 05592 05593 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package); 05594 msiobj_release(&view->hdr); 05595 return rc; 05596 } 05597 05598 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */ 05599 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs) 05600 { 05601 LPCWSTR *vector, *temp_vector; 05602 LPWSTR p, q; 05603 DWORD sep_len; 05604 05605 static const WCHAR separator[] = {'[','~',']',0}; 05606 05607 *numargs = 0; 05608 sep_len = sizeof(separator) / sizeof(WCHAR) - 1; 05609 05610 if (!args) 05611 return NULL; 05612 05613 vector = msi_alloc(sizeof(LPWSTR)); 05614 if (!vector) 05615 return NULL; 05616 05617 p = args; 05618 do 05619 { 05620 (*numargs)++; 05621 vector[*numargs - 1] = p; 05622 05623 if ((q = strstrW(p, separator))) 05624 { 05625 *q = '\0'; 05626 05627 temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR)); 05628 if (!temp_vector) 05629 { 05630 msi_free(vector); 05631 return NULL; 05632 } 05633 vector = temp_vector; 05634 05635 p = q + sep_len; 05636 } 05637 } while (q); 05638 05639 return vector; 05640 } 05641 05642 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param) 05643 { 05644 MSIPACKAGE *package = param; 05645 MSICOMPONENT *comp; 05646 MSIRECORD *uirow; 05647 SC_HANDLE scm = NULL, service = NULL; 05648 LPCWSTR component, *vector = NULL; 05649 LPWSTR name, args, display_name = NULL; 05650 DWORD event, numargs, len, wait, dummy; 05651 UINT r = ERROR_FUNCTION_FAILED; 05652 SERVICE_STATUS_PROCESS status; 05653 ULONGLONG start_time; 05654 05655 component = MSI_RecordGetString(rec, 6); 05656 comp = msi_get_loaded_component(package, component); 05657 if (!comp) 05658 return ERROR_SUCCESS; 05659 05660 comp->Action = msi_get_component_action( package, comp ); 05661 if (comp->Action != INSTALLSTATE_LOCAL) 05662 { 05663 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 05664 return ERROR_SUCCESS; 05665 } 05666 05667 deformat_string(package, MSI_RecordGetString(rec, 2), &name); 05668 deformat_string(package, MSI_RecordGetString(rec, 4), &args); 05669 event = MSI_RecordGetInteger(rec, 3); 05670 wait = MSI_RecordGetInteger(rec, 5); 05671 05672 if (!(event & msidbServiceControlEventStart)) 05673 { 05674 r = ERROR_SUCCESS; 05675 goto done; 05676 } 05677 05678 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); 05679 if (!scm) 05680 { 05681 ERR("Failed to open the service control manager\n"); 05682 goto done; 05683 } 05684 05685 len = 0; 05686 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) && 05687 GetLastError() == ERROR_INSUFFICIENT_BUFFER) 05688 { 05689 if ((display_name = msi_alloc( ++len * sizeof(WCHAR )))) 05690 GetServiceDisplayNameW( scm, name, display_name, &len ); 05691 } 05692 05693 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS); 05694 if (!service) 05695 { 05696 ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError()); 05697 goto done; 05698 } 05699 05700 vector = msi_service_args_to_vector(args, &numargs); 05701 05702 if (!StartServiceW(service, numargs, vector) && 05703 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING) 05704 { 05705 ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError()); 05706 goto done; 05707 } 05708 05709 r = ERROR_SUCCESS; 05710 if (wait) 05711 { 05712 /* wait for at most 30 seconds for the service to be up and running */ 05713 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, 05714 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy)) 05715 { 05716 TRACE("failed to query service status (%u)\n", GetLastError()); 05717 goto done; 05718 } 05719 start_time = GetTickCount64(); 05720 while (status.dwCurrentState == SERVICE_START_PENDING) 05721 { 05722 if (GetTickCount64() - start_time > 30000) break; 05723 Sleep(1000); 05724 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, 05725 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy)) 05726 { 05727 TRACE("failed to query service status (%u)\n", GetLastError()); 05728 goto done; 05729 } 05730 } 05731 if (status.dwCurrentState != SERVICE_RUNNING) 05732 { 05733 WARN("service failed to start %u\n", status.dwCurrentState); 05734 r = ERROR_FUNCTION_FAILED; 05735 } 05736 } 05737 05738 done: 05739 uirow = MSI_CreateRecord( 2 ); 05740 MSI_RecordSetStringW( uirow, 1, display_name ); 05741 MSI_RecordSetStringW( uirow, 2, name ); 05742 msi_ui_actiondata( package, szStartServices, uirow ); 05743 msiobj_release( &uirow->hdr ); 05744 05745 CloseServiceHandle(service); 05746 CloseServiceHandle(scm); 05747 05748 msi_free(name); 05749 msi_free(args); 05750 msi_free(vector); 05751 msi_free(display_name); 05752 return r; 05753 } 05754 05755 static UINT ACTION_StartServices( MSIPACKAGE *package ) 05756 { 05757 static const WCHAR query[] = { 05758 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 05759 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0}; 05760 MSIQUERY *view; 05761 UINT rc; 05762 05763 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 05764 if (rc != ERROR_SUCCESS) 05765 return ERROR_SUCCESS; 05766 05767 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package); 05768 msiobj_release(&view->hdr); 05769 return rc; 05770 } 05771 05772 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service) 05773 { 05774 DWORD i, needed, count; 05775 ENUM_SERVICE_STATUSW *dependencies; 05776 SERVICE_STATUS ss; 05777 SC_HANDLE depserv; 05778 05779 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL, 05780 0, &needed, &count)) 05781 return TRUE; 05782 05783 if (GetLastError() != ERROR_MORE_DATA) 05784 return FALSE; 05785 05786 dependencies = msi_alloc(needed); 05787 if (!dependencies) 05788 return FALSE; 05789 05790 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies, 05791 needed, &needed, &count)) 05792 goto error; 05793 05794 for (i = 0; i < count; i++) 05795 { 05796 depserv = OpenServiceW(scm, dependencies[i].lpServiceName, 05797 SERVICE_STOP | SERVICE_QUERY_STATUS); 05798 if (!depserv) 05799 goto error; 05800 05801 if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss)) 05802 goto error; 05803 } 05804 05805 return TRUE; 05806 05807 error: 05808 msi_free(dependencies); 05809 return FALSE; 05810 } 05811 05812 static UINT stop_service( LPCWSTR name ) 05813 { 05814 SC_HANDLE scm = NULL, service = NULL; 05815 SERVICE_STATUS status; 05816 SERVICE_STATUS_PROCESS ssp; 05817 DWORD needed; 05818 05819 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); 05820 if (!scm) 05821 { 05822 WARN("Failed to open the SCM: %d\n", GetLastError()); 05823 goto done; 05824 } 05825 05826 service = OpenServiceW(scm, name, 05827 SERVICE_STOP | 05828 SERVICE_QUERY_STATUS | 05829 SERVICE_ENUMERATE_DEPENDENTS); 05830 if (!service) 05831 { 05832 WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError()); 05833 goto done; 05834 } 05835 05836 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, 05837 sizeof(SERVICE_STATUS_PROCESS), &needed)) 05838 { 05839 WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError()); 05840 goto done; 05841 } 05842 05843 if (ssp.dwCurrentState == SERVICE_STOPPED) 05844 goto done; 05845 05846 stop_service_dependents(scm, service); 05847 05848 if (!ControlService(service, SERVICE_CONTROL_STOP, &status)) 05849 WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError()); 05850 05851 done: 05852 CloseServiceHandle(service); 05853 CloseServiceHandle(scm); 05854 05855 return ERROR_SUCCESS; 05856 } 05857 05858 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param ) 05859 { 05860 MSIPACKAGE *package = param; 05861 MSICOMPONENT *comp; 05862 MSIRECORD *uirow; 05863 LPCWSTR component; 05864 LPWSTR name = NULL, display_name = NULL; 05865 DWORD event, len; 05866 SC_HANDLE scm; 05867 05868 event = MSI_RecordGetInteger( rec, 3 ); 05869 if (!(event & msidbServiceControlEventStop)) 05870 return ERROR_SUCCESS; 05871 05872 component = MSI_RecordGetString( rec, 6 ); 05873 comp = msi_get_loaded_component( package, component ); 05874 if (!comp) 05875 return ERROR_SUCCESS; 05876 05877 comp->Action = msi_get_component_action( package, comp ); 05878 if (comp->Action != INSTALLSTATE_ABSENT) 05879 { 05880 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 05881 return ERROR_SUCCESS; 05882 } 05883 05884 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT ); 05885 if (!scm) 05886 { 05887 ERR("Failed to open the service control manager\n"); 05888 goto done; 05889 } 05890 05891 len = 0; 05892 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) && 05893 GetLastError() == ERROR_INSUFFICIENT_BUFFER) 05894 { 05895 if ((display_name = msi_alloc( ++len * sizeof(WCHAR )))) 05896 GetServiceDisplayNameW( scm, name, display_name, &len ); 05897 } 05898 CloseServiceHandle( scm ); 05899 05900 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name ); 05901 stop_service( name ); 05902 05903 done: 05904 uirow = MSI_CreateRecord( 2 ); 05905 MSI_RecordSetStringW( uirow, 1, display_name ); 05906 MSI_RecordSetStringW( uirow, 2, name ); 05907 msi_ui_actiondata( package, szStopServices, uirow ); 05908 msiobj_release( &uirow->hdr ); 05909 05910 msi_free( name ); 05911 msi_free( display_name ); 05912 return ERROR_SUCCESS; 05913 } 05914 05915 static UINT ACTION_StopServices( MSIPACKAGE *package ) 05916 { 05917 static const WCHAR query[] = { 05918 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 05919 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0}; 05920 MSIQUERY *view; 05921 UINT rc; 05922 05923 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 05924 if (rc != ERROR_SUCCESS) 05925 return ERROR_SUCCESS; 05926 05927 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package); 05928 msiobj_release(&view->hdr); 05929 return rc; 05930 } 05931 05932 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param ) 05933 { 05934 MSIPACKAGE *package = param; 05935 MSICOMPONENT *comp; 05936 MSIRECORD *uirow; 05937 LPWSTR name = NULL, display_name = NULL; 05938 DWORD event, len; 05939 SC_HANDLE scm = NULL, service = NULL; 05940 05941 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) ); 05942 if (!comp) 05943 return ERROR_SUCCESS; 05944 05945 event = MSI_RecordGetInteger( rec, 3 ); 05946 deformat_string( package, MSI_RecordGetString(rec, 2), &name ); 05947 05948 comp->Action = msi_get_component_action( package, comp ); 05949 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) && 05950 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete))) 05951 { 05952 TRACE("service %s not scheduled for removal\n", debugstr_w(name)); 05953 msi_free( name ); 05954 return ERROR_SUCCESS; 05955 } 05956 stop_service( name ); 05957 05958 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS ); 05959 if (!scm) 05960 { 05961 WARN("Failed to open the SCM: %d\n", GetLastError()); 05962 goto done; 05963 } 05964 05965 len = 0; 05966 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) && 05967 GetLastError() == ERROR_INSUFFICIENT_BUFFER) 05968 { 05969 if ((display_name = msi_alloc( ++len * sizeof(WCHAR )))) 05970 GetServiceDisplayNameW( scm, name, display_name, &len ); 05971 } 05972 05973 service = OpenServiceW( scm, name, DELETE ); 05974 if (!service) 05975 { 05976 WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError()); 05977 goto done; 05978 } 05979 05980 if (!DeleteService( service )) 05981 WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError()); 05982 05983 done: 05984 uirow = MSI_CreateRecord( 2 ); 05985 MSI_RecordSetStringW( uirow, 1, display_name ); 05986 MSI_RecordSetStringW( uirow, 2, name ); 05987 msi_ui_actiondata( package, szDeleteServices, uirow ); 05988 msiobj_release( &uirow->hdr ); 05989 05990 CloseServiceHandle( service ); 05991 CloseServiceHandle( scm ); 05992 msi_free( name ); 05993 msi_free( display_name ); 05994 05995 return ERROR_SUCCESS; 05996 } 05997 05998 static UINT ACTION_DeleteServices( MSIPACKAGE *package ) 05999 { 06000 static const WCHAR query[] = { 06001 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 06002 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0}; 06003 MSIQUERY *view; 06004 UINT rc; 06005 06006 rc = MSI_DatabaseOpenViewW( package->db, query, &view ); 06007 if (rc != ERROR_SUCCESS) 06008 return ERROR_SUCCESS; 06009 06010 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package ); 06011 msiobj_release( &view->hdr ); 06012 return rc; 06013 } 06014 06015 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param ) 06016 { 06017 MSIPACKAGE *package = param; 06018 LPWSTR driver, driver_path, ptr; 06019 WCHAR outpath[MAX_PATH]; 06020 MSIFILE *driver_file = NULL, *setup_file = NULL; 06021 MSICOMPONENT *comp; 06022 MSIRECORD *uirow; 06023 LPCWSTR desc, file_key, component; 06024 DWORD len, usage; 06025 UINT r = ERROR_SUCCESS; 06026 06027 static const WCHAR driver_fmt[] = { 06028 'D','r','i','v','e','r','=','%','s',0}; 06029 static const WCHAR setup_fmt[] = { 06030 'S','e','t','u','p','=','%','s',0}; 06031 static const WCHAR usage_fmt[] = { 06032 'F','i','l','e','U','s','a','g','e','=','1',0}; 06033 06034 component = MSI_RecordGetString( rec, 2 ); 06035 comp = msi_get_loaded_component( package, component ); 06036 if (!comp) 06037 return ERROR_SUCCESS; 06038 06039 comp->Action = msi_get_component_action( package, comp ); 06040 if (comp->Action != INSTALLSTATE_LOCAL) 06041 { 06042 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 06043 return ERROR_SUCCESS; 06044 } 06045 desc = MSI_RecordGetString(rec, 3); 06046 06047 file_key = MSI_RecordGetString( rec, 4 ); 06048 if (file_key) driver_file = msi_get_loaded_file( package, file_key ); 06049 06050 file_key = MSI_RecordGetString( rec, 5 ); 06051 if (file_key) setup_file = msi_get_loaded_file( package, file_key ); 06052 06053 if (!driver_file) 06054 { 06055 ERR("ODBC Driver entry not found!\n"); 06056 return ERROR_FUNCTION_FAILED; 06057 } 06058 06059 len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName); 06060 if (setup_file) 06061 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName); 06062 len += lstrlenW(usage_fmt) + 2; /* \0\0 */ 06063 06064 driver = msi_alloc(len * sizeof(WCHAR)); 06065 if (!driver) 06066 return ERROR_OUTOFMEMORY; 06067 06068 ptr = driver; 06069 lstrcpyW(ptr, desc); 06070 ptr += lstrlenW(ptr) + 1; 06071 06072 len = sprintfW(ptr, driver_fmt, driver_file->FileName); 06073 ptr += len + 1; 06074 06075 if (setup_file) 06076 { 06077 len = sprintfW(ptr, setup_fmt, setup_file->FileName); 06078 ptr += len + 1; 06079 } 06080 06081 lstrcpyW(ptr, usage_fmt); 06082 ptr += lstrlenW(ptr) + 1; 06083 *ptr = '\0'; 06084 06085 if (!driver_file->TargetPath) 06086 { 06087 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory ); 06088 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName ); 06089 } 06090 driver_path = strdupW(driver_file->TargetPath); 06091 ptr = strrchrW(driver_path, '\\'); 06092 if (ptr) *ptr = '\0'; 06093 06094 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH, 06095 NULL, ODBC_INSTALL_COMPLETE, &usage)) 06096 { 06097 ERR("Failed to install SQL driver!\n"); 06098 r = ERROR_FUNCTION_FAILED; 06099 } 06100 06101 uirow = MSI_CreateRecord( 5 ); 06102 MSI_RecordSetStringW( uirow, 1, desc ); 06103 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); 06104 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory ); 06105 msi_ui_actiondata( package, szInstallODBC, uirow ); 06106 msiobj_release( &uirow->hdr ); 06107 06108 msi_free(driver); 06109 msi_free(driver_path); 06110 06111 return r; 06112 } 06113 06114 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param ) 06115 { 06116 MSIPACKAGE *package = param; 06117 LPWSTR translator, translator_path, ptr; 06118 WCHAR outpath[MAX_PATH]; 06119 MSIFILE *translator_file = NULL, *setup_file = NULL; 06120 MSICOMPONENT *comp; 06121 MSIRECORD *uirow; 06122 LPCWSTR desc, file_key, component; 06123 DWORD len, usage; 06124 UINT r = ERROR_SUCCESS; 06125 06126 static const WCHAR translator_fmt[] = { 06127 'T','r','a','n','s','l','a','t','o','r','=','%','s',0}; 06128 static const WCHAR setup_fmt[] = { 06129 'S','e','t','u','p','=','%','s',0}; 06130 06131 component = MSI_RecordGetString( rec, 2 ); 06132 comp = msi_get_loaded_component( package, component ); 06133 if (!comp) 06134 return ERROR_SUCCESS; 06135 06136 comp->Action = msi_get_component_action( package, comp ); 06137 if (comp->Action != INSTALLSTATE_LOCAL) 06138 { 06139 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 06140 return ERROR_SUCCESS; 06141 } 06142 desc = MSI_RecordGetString(rec, 3); 06143 06144 file_key = MSI_RecordGetString( rec, 4 ); 06145 if (file_key) translator_file = msi_get_loaded_file( package, file_key ); 06146 06147 file_key = MSI_RecordGetString( rec, 5 ); 06148 if (file_key) setup_file = msi_get_loaded_file( package, file_key ); 06149 06150 if (!translator_file) 06151 { 06152 ERR("ODBC Translator entry not found!\n"); 06153 return ERROR_FUNCTION_FAILED; 06154 } 06155 06156 len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */ 06157 if (setup_file) 06158 len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName); 06159 06160 translator = msi_alloc(len * sizeof(WCHAR)); 06161 if (!translator) 06162 return ERROR_OUTOFMEMORY; 06163 06164 ptr = translator; 06165 lstrcpyW(ptr, desc); 06166 ptr += lstrlenW(ptr) + 1; 06167 06168 len = sprintfW(ptr, translator_fmt, translator_file->FileName); 06169 ptr += len + 1; 06170 06171 if (setup_file) 06172 { 06173 len = sprintfW(ptr, setup_fmt, setup_file->FileName); 06174 ptr += len + 1; 06175 } 06176 *ptr = '\0'; 06177 06178 translator_path = strdupW(translator_file->TargetPath); 06179 ptr = strrchrW(translator_path, '\\'); 06180 if (ptr) *ptr = '\0'; 06181 06182 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH, 06183 NULL, ODBC_INSTALL_COMPLETE, &usage)) 06184 { 06185 ERR("Failed to install SQL translator!\n"); 06186 r = ERROR_FUNCTION_FAILED; 06187 } 06188 06189 uirow = MSI_CreateRecord( 5 ); 06190 MSI_RecordSetStringW( uirow, 1, desc ); 06191 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); 06192 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory ); 06193 msi_ui_actiondata( package, szInstallODBC, uirow ); 06194 msiobj_release( &uirow->hdr ); 06195 06196 msi_free(translator); 06197 msi_free(translator_path); 06198 06199 return r; 06200 } 06201 06202 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param ) 06203 { 06204 MSIPACKAGE *package = param; 06205 MSICOMPONENT *comp; 06206 LPWSTR attrs; 06207 LPCWSTR desc, driver, component; 06208 WORD request = ODBC_ADD_SYS_DSN; 06209 INT registration; 06210 DWORD len; 06211 UINT r = ERROR_SUCCESS; 06212 MSIRECORD *uirow; 06213 06214 static const WCHAR attrs_fmt[] = { 06215 'D','S','N','=','%','s',0 }; 06216 06217 component = MSI_RecordGetString( rec, 2 ); 06218 comp = msi_get_loaded_component( package, component ); 06219 if (!comp) 06220 return ERROR_SUCCESS; 06221 06222 comp->Action = msi_get_component_action( package, comp ); 06223 if (comp->Action != INSTALLSTATE_LOCAL) 06224 { 06225 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 06226 return ERROR_SUCCESS; 06227 } 06228 06229 desc = MSI_RecordGetString(rec, 3); 06230 driver = MSI_RecordGetString(rec, 4); 06231 registration = MSI_RecordGetInteger(rec, 5); 06232 06233 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN; 06234 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN; 06235 06236 len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */ 06237 attrs = msi_alloc(len * sizeof(WCHAR)); 06238 if (!attrs) 06239 return ERROR_OUTOFMEMORY; 06240 06241 len = sprintfW(attrs, attrs_fmt, desc); 06242 attrs[len + 1] = 0; 06243 06244 if (!SQLConfigDataSourceW(NULL, request, driver, attrs)) 06245 { 06246 ERR("Failed to install SQL data source!\n"); 06247 r = ERROR_FUNCTION_FAILED; 06248 } 06249 06250 uirow = MSI_CreateRecord( 5 ); 06251 MSI_RecordSetStringW( uirow, 1, desc ); 06252 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); 06253 MSI_RecordSetInteger( uirow, 3, request ); 06254 msi_ui_actiondata( package, szInstallODBC, uirow ); 06255 msiobj_release( &uirow->hdr ); 06256 06257 msi_free(attrs); 06258 06259 return r; 06260 } 06261 06262 static UINT ACTION_InstallODBC( MSIPACKAGE *package ) 06263 { 06264 static const WCHAR driver_query[] = { 06265 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 06266 'O','D','B','C','D','r','i','v','e','r',0}; 06267 static const WCHAR translator_query[] = { 06268 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 06269 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0}; 06270 static const WCHAR source_query[] = { 06271 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 06272 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0}; 06273 MSIQUERY *view; 06274 UINT rc; 06275 06276 rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view); 06277 if (rc == ERROR_SUCCESS) 06278 { 06279 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package); 06280 msiobj_release(&view->hdr); 06281 if (rc != ERROR_SUCCESS) 06282 return rc; 06283 } 06284 rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view); 06285 if (rc == ERROR_SUCCESS) 06286 { 06287 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package); 06288 msiobj_release(&view->hdr); 06289 if (rc != ERROR_SUCCESS) 06290 return rc; 06291 } 06292 rc = MSI_DatabaseOpenViewW(package->db, source_query, &view); 06293 if (rc == ERROR_SUCCESS) 06294 { 06295 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package); 06296 msiobj_release(&view->hdr); 06297 if (rc != ERROR_SUCCESS) 06298 return rc; 06299 } 06300 return ERROR_SUCCESS; 06301 } 06302 06303 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param ) 06304 { 06305 MSIPACKAGE *package = param; 06306 MSICOMPONENT *comp; 06307 MSIRECORD *uirow; 06308 DWORD usage; 06309 LPCWSTR desc, component; 06310 06311 component = MSI_RecordGetString( rec, 2 ); 06312 comp = msi_get_loaded_component( package, component ); 06313 if (!comp) 06314 return ERROR_SUCCESS; 06315 06316 comp->Action = msi_get_component_action( package, comp ); 06317 if (comp->Action != INSTALLSTATE_ABSENT) 06318 { 06319 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 06320 return ERROR_SUCCESS; 06321 } 06322 06323 desc = MSI_RecordGetString( rec, 3 ); 06324 if (!SQLRemoveDriverW( desc, FALSE, &usage )) 06325 { 06326 WARN("Failed to remove ODBC driver\n"); 06327 } 06328 else if (!usage) 06329 { 06330 FIXME("Usage count reached 0\n"); 06331 } 06332 06333 uirow = MSI_CreateRecord( 2 ); 06334 MSI_RecordSetStringW( uirow, 1, desc ); 06335 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); 06336 msi_ui_actiondata( package, szRemoveODBC, uirow ); 06337 msiobj_release( &uirow->hdr ); 06338 06339 return ERROR_SUCCESS; 06340 } 06341 06342 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param ) 06343 { 06344 MSIPACKAGE *package = param; 06345 MSICOMPONENT *comp; 06346 MSIRECORD *uirow; 06347 DWORD usage; 06348 LPCWSTR desc, component; 06349 06350 component = MSI_RecordGetString( rec, 2 ); 06351 comp = msi_get_loaded_component( package, component ); 06352 if (!comp) 06353 return ERROR_SUCCESS; 06354 06355 comp->Action = msi_get_component_action( package, comp ); 06356 if (comp->Action != INSTALLSTATE_ABSENT) 06357 { 06358 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 06359 return ERROR_SUCCESS; 06360 } 06361 06362 desc = MSI_RecordGetString( rec, 3 ); 06363 if (!SQLRemoveTranslatorW( desc, &usage )) 06364 { 06365 WARN("Failed to remove ODBC translator\n"); 06366 } 06367 else if (!usage) 06368 { 06369 FIXME("Usage count reached 0\n"); 06370 } 06371 06372 uirow = MSI_CreateRecord( 2 ); 06373 MSI_RecordSetStringW( uirow, 1, desc ); 06374 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); 06375 msi_ui_actiondata( package, szRemoveODBC, uirow ); 06376 msiobj_release( &uirow->hdr ); 06377 06378 return ERROR_SUCCESS; 06379 } 06380 06381 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param ) 06382 { 06383 MSIPACKAGE *package = param; 06384 MSICOMPONENT *comp; 06385 MSIRECORD *uirow; 06386 LPWSTR attrs; 06387 LPCWSTR desc, driver, component; 06388 WORD request = ODBC_REMOVE_SYS_DSN; 06389 INT registration; 06390 DWORD len; 06391 06392 static const WCHAR attrs_fmt[] = { 06393 'D','S','N','=','%','s',0 }; 06394 06395 component = MSI_RecordGetString( rec, 2 ); 06396 comp = msi_get_loaded_component( package, component ); 06397 if (!comp) 06398 return ERROR_SUCCESS; 06399 06400 comp->Action = msi_get_component_action( package, comp ); 06401 if (comp->Action != INSTALLSTATE_ABSENT) 06402 { 06403 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 06404 return ERROR_SUCCESS; 06405 } 06406 06407 desc = MSI_RecordGetString( rec, 3 ); 06408 driver = MSI_RecordGetString( rec, 4 ); 06409 registration = MSI_RecordGetInteger( rec, 5 ); 06410 06411 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN; 06412 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN; 06413 06414 len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */ 06415 attrs = msi_alloc( len * sizeof(WCHAR) ); 06416 if (!attrs) 06417 return ERROR_OUTOFMEMORY; 06418 06419 FIXME("Use ODBCSourceAttribute table\n"); 06420 06421 len = sprintfW( attrs, attrs_fmt, desc ); 06422 attrs[len + 1] = 0; 06423 06424 if (!SQLConfigDataSourceW( NULL, request, driver, attrs )) 06425 { 06426 WARN("Failed to remove ODBC data source\n"); 06427 } 06428 msi_free( attrs ); 06429 06430 uirow = MSI_CreateRecord( 3 ); 06431 MSI_RecordSetStringW( uirow, 1, desc ); 06432 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); 06433 MSI_RecordSetInteger( uirow, 3, request ); 06434 msi_ui_actiondata( package, szRemoveODBC, uirow ); 06435 msiobj_release( &uirow->hdr ); 06436 06437 return ERROR_SUCCESS; 06438 } 06439 06440 static UINT ACTION_RemoveODBC( MSIPACKAGE *package ) 06441 { 06442 static const WCHAR driver_query[] = { 06443 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 06444 'O','D','B','C','D','r','i','v','e','r',0}; 06445 static const WCHAR translator_query[] = { 06446 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 06447 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0}; 06448 static const WCHAR source_query[] = { 06449 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 06450 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0}; 06451 MSIQUERY *view; 06452 UINT rc; 06453 06454 rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view ); 06455 if (rc == ERROR_SUCCESS) 06456 { 06457 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package ); 06458 msiobj_release( &view->hdr ); 06459 if (rc != ERROR_SUCCESS) 06460 return rc; 06461 } 06462 rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view ); 06463 if (rc == ERROR_SUCCESS) 06464 { 06465 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package ); 06466 msiobj_release( &view->hdr ); 06467 if (rc != ERROR_SUCCESS) 06468 return rc; 06469 } 06470 rc = MSI_DatabaseOpenViewW( package->db, source_query, &view ); 06471 if (rc == ERROR_SUCCESS) 06472 { 06473 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package ); 06474 msiobj_release( &view->hdr ); 06475 if (rc != ERROR_SUCCESS) 06476 return rc; 06477 } 06478 return ERROR_SUCCESS; 06479 } 06480 06481 #define ENV_ACT_SETALWAYS 0x1 06482 #define ENV_ACT_SETABSENT 0x2 06483 #define ENV_ACT_REMOVE 0x4 06484 #define ENV_ACT_REMOVEMATCH 0x8 06485 06486 #define ENV_MOD_MACHINE 0x20000000 06487 #define ENV_MOD_APPEND 0x40000000 06488 #define ENV_MOD_PREFIX 0x80000000 06489 #define ENV_MOD_MASK 0xC0000000 06490 06491 #define check_flag_combo(x, y) ((x) & ~(y)) == (y) 06492 06493 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags ) 06494 { 06495 LPCWSTR cptr = *name; 06496 06497 static const WCHAR prefix[] = {'[','~',']',0}; 06498 static const int prefix_len = 3; 06499 06500 *flags = 0; 06501 while (*cptr) 06502 { 06503 if (*cptr == '=') 06504 *flags |= ENV_ACT_SETALWAYS; 06505 else if (*cptr == '+') 06506 *flags |= ENV_ACT_SETABSENT; 06507 else if (*cptr == '-') 06508 *flags |= ENV_ACT_REMOVE; 06509 else if (*cptr == '!') 06510 *flags |= ENV_ACT_REMOVEMATCH; 06511 else if (*cptr == '*') 06512 *flags |= ENV_MOD_MACHINE; 06513 else 06514 break; 06515 06516 cptr++; 06517 (*name)++; 06518 } 06519 06520 if (!*cptr) 06521 { 06522 ERR("Missing environment variable\n"); 06523 return ERROR_FUNCTION_FAILED; 06524 } 06525 06526 if (*value) 06527 { 06528 LPCWSTR ptr = *value; 06529 if (!strncmpW(ptr, prefix, prefix_len)) 06530 { 06531 if (ptr[prefix_len] == szSemiColon[0]) 06532 { 06533 *flags |= ENV_MOD_APPEND; 06534 *value += lstrlenW(prefix); 06535 } 06536 else 06537 { 06538 *value = NULL; 06539 } 06540 } 06541 else if (lstrlenW(*value) >= prefix_len) 06542 { 06543 ptr += lstrlenW(ptr) - prefix_len; 06544 if (!strcmpW( ptr, prefix )) 06545 { 06546 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0]) 06547 { 06548 *flags |= ENV_MOD_PREFIX; 06549 /* the "[~]" will be removed by deformat_string */; 06550 } 06551 else 06552 { 06553 *value = NULL; 06554 } 06555 } 06556 } 06557 } 06558 06559 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) || 06560 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) || 06561 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) || 06562 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK)) 06563 { 06564 ERR("Invalid flags: %08x\n", *flags); 06565 return ERROR_FUNCTION_FAILED; 06566 } 06567 06568 if (!*flags) 06569 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE; 06570 06571 return ERROR_SUCCESS; 06572 } 06573 06574 static UINT open_env_key( DWORD flags, HKEY *key ) 06575 { 06576 static const WCHAR user_env[] = 06577 {'E','n','v','i','r','o','n','m','e','n','t',0}; 06578 static const WCHAR machine_env[] = 06579 {'S','y','s','t','e','m','\\', 06580 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', 06581 'C','o','n','t','r','o','l','\\', 06582 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\', 06583 'E','n','v','i','r','o','n','m','e','n','t',0}; 06584 const WCHAR *env; 06585 HKEY root; 06586 LONG res; 06587 06588 if (flags & ENV_MOD_MACHINE) 06589 { 06590 env = machine_env; 06591 root = HKEY_LOCAL_MACHINE; 06592 } 06593 else 06594 { 06595 env = user_env; 06596 root = HKEY_CURRENT_USER; 06597 } 06598 06599 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key ); 06600 if (res != ERROR_SUCCESS) 06601 { 06602 WARN("Failed to open key %s (%d)\n", debugstr_w(env), res); 06603 return ERROR_FUNCTION_FAILED; 06604 } 06605 06606 return ERROR_SUCCESS; 06607 } 06608 06609 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param ) 06610 { 06611 MSIPACKAGE *package = param; 06612 LPCWSTR name, value, component; 06613 LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr; 06614 DWORD flags, type, size; 06615 UINT res; 06616 HKEY env = NULL; 06617 MSICOMPONENT *comp; 06618 MSIRECORD *uirow; 06619 int action = 0; 06620 06621 component = MSI_RecordGetString(rec, 4); 06622 comp = msi_get_loaded_component(package, component); 06623 if (!comp) 06624 return ERROR_SUCCESS; 06625 06626 comp->Action = msi_get_component_action( package, comp ); 06627 if (comp->Action != INSTALLSTATE_LOCAL) 06628 { 06629 TRACE("component not scheduled for installation %s\n", debugstr_w(component)); 06630 return ERROR_SUCCESS; 06631 } 06632 name = MSI_RecordGetString(rec, 2); 06633 value = MSI_RecordGetString(rec, 3); 06634 06635 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value)); 06636 06637 res = env_parse_flags(&name, &value, &flags); 06638 if (res != ERROR_SUCCESS || !value) 06639 goto done; 06640 06641 if (value && !deformat_string(package, value, &deformatted)) 06642 { 06643 res = ERROR_OUTOFMEMORY; 06644 goto done; 06645 } 06646 06647 value = deformatted; 06648 06649 res = open_env_key( flags, &env ); 06650 if (res != ERROR_SUCCESS) 06651 goto done; 06652 06653 if (flags & ENV_MOD_MACHINE) 06654 action |= 0x20000000; 06655 06656 size = 0; 06657 type = REG_SZ; 06658 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size); 06659 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) || 06660 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ)) 06661 goto done; 06662 06663 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK))) 06664 { 06665 action = 0x2; 06666 06667 /* Nothing to do. */ 06668 if (!value) 06669 { 06670 res = ERROR_SUCCESS; 06671 goto done; 06672 } 06673 06674 /* If we are appending but the string was empty, strip ; */ 06675 if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++; 06676 06677 size = (lstrlenW(value) + 1) * sizeof(WCHAR); 06678 newval = strdupW(value); 06679 if (!newval) 06680 { 06681 res = ERROR_OUTOFMEMORY; 06682 goto done; 06683 } 06684 } 06685 else 06686 { 06687 action = 0x1; 06688 06689 /* Contrary to MSDN, +-variable to [~];path works */ 06690 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK)) 06691 { 06692 res = ERROR_SUCCESS; 06693 goto done; 06694 } 06695 06696 data = msi_alloc(size); 06697 if (!data) 06698 { 06699 RegCloseKey(env); 06700 return ERROR_OUTOFMEMORY; 06701 } 06702 06703 res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size); 06704 if (res != ERROR_SUCCESS) 06705 goto done; 06706 06707 if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value ))) 06708 { 06709 action = 0x4; 06710 res = RegDeleteValueW(env, name); 06711 if (res != ERROR_SUCCESS) 06712 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res); 06713 goto done; 06714 } 06715 06716 size = (lstrlenW(data) + 1) * sizeof(WCHAR); 06717 if (flags & ENV_MOD_MASK) 06718 { 06719 DWORD mod_size; 06720 int multiplier = 0; 06721 if (flags & ENV_MOD_APPEND) multiplier++; 06722 if (flags & ENV_MOD_PREFIX) multiplier++; 06723 mod_size = lstrlenW(value) * multiplier; 06724 size += mod_size * sizeof(WCHAR); 06725 } 06726 06727 newval = msi_alloc(size); 06728 ptr = newval; 06729 if (!newval) 06730 { 06731 res = ERROR_OUTOFMEMORY; 06732 goto done; 06733 } 06734 06735 if (flags & ENV_MOD_PREFIX) 06736 { 06737 lstrcpyW(newval, value); 06738 ptr = newval + lstrlenW(value); 06739 action |= 0x80000000; 06740 } 06741 06742 lstrcpyW(ptr, data); 06743 06744 if (flags & ENV_MOD_APPEND) 06745 { 06746 lstrcatW(newval, value); 06747 action |= 0x40000000; 06748 } 06749 } 06750 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval)); 06751 res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size); 06752 if (res) 06753 { 06754 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res); 06755 } 06756 06757 done: 06758 uirow = MSI_CreateRecord( 3 ); 06759 MSI_RecordSetStringW( uirow, 1, name ); 06760 MSI_RecordSetStringW( uirow, 2, newval ); 06761 MSI_RecordSetInteger( uirow, 3, action ); 06762 msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow ); 06763 msiobj_release( &uirow->hdr ); 06764 06765 if (env) RegCloseKey(env); 06766 msi_free(deformatted); 06767 msi_free(data); 06768 msi_free(newval); 06769 return res; 06770 } 06771 06772 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package ) 06773 { 06774 static const WCHAR query[] = { 06775 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 06776 '`','E','n','v','i','r','o','n','m','e','n','t','`',0}; 06777 MSIQUERY *view; 06778 UINT rc; 06779 06780 rc = MSI_DatabaseOpenViewW(package->db, query, &view); 06781 if (rc != ERROR_SUCCESS) 06782 return ERROR_SUCCESS; 06783 06784 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package); 06785 msiobj_release(&view->hdr); 06786 return rc; 06787 } 06788 06789 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param ) 06790 { 06791 MSIPACKAGE *package = param; 06792 LPCWSTR name, value, component; 06793 LPWSTR deformatted = NULL; 06794 DWORD flags; 06795 HKEY env; 06796 MSICOMPONENT *comp; 06797 MSIRECORD *uirow; 06798 int action = 0; 06799 LONG res; 06800 UINT r; 06801 06802 component = MSI_RecordGetString( rec, 4 ); 06803 comp = msi_get_loaded_component( package, component ); 06804 if (!comp) 06805 return ERROR_SUCCESS; 06806 06807 comp->Action = msi_get_component_action( package, comp ); 06808 if (comp->Action != INSTALLSTATE_ABSENT) 06809 { 06810 TRACE("component not scheduled for removal %s\n", debugstr_w(component)); 06811 return ERROR_SUCCESS; 06812 } 06813 name = MSI_RecordGetString( rec, 2 ); 06814 value = MSI_RecordGetString( rec, 3 ); 06815 06816 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value)); 06817 06818 r = env_parse_flags( &name, &value, &flags ); 06819 if (r != ERROR_SUCCESS) 06820 return r; 06821 06822 if (!(flags & ENV_ACT_REMOVE)) 06823 { 06824 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name)); 06825 return ERROR_SUCCESS; 06826 } 06827 06828 if (value && !deformat_string( package, value, &deformatted )) 06829 return ERROR_OUTOFMEMORY; 06830 06831 value = deformatted; 06832 06833 r = open_env_key( flags, &env ); 06834 if (r != ERROR_SUCCESS) 06835 { 06836 r = ERROR_SUCCESS; 06837 goto done; 06838 } 06839 06840 if (flags & ENV_MOD_MACHINE) 06841 action |= 0x20000000; 06842 06843 TRACE("Removing %s\n", debugstr_w(name)); 06844 06845 res = RegDeleteValueW( env, name ); 06846 if (res != ERROR_SUCCESS) 06847 { 06848 WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res); 06849 r = ERROR_SUCCESS; 06850 } 06851 06852 done: 06853 uirow = MSI_CreateRecord( 3 ); 06854 MSI_RecordSetStringW( uirow, 1, name ); 06855 MSI_RecordSetStringW( uirow, 2, value ); 06856 MSI_RecordSetInteger( uirow, 3, action ); 06857 msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow ); 06858 msiobj_release( &uirow->hdr ); 06859 06860 if (env) RegCloseKey( env ); 06861 msi_free( deformatted ); 06862 return r; 06863 } 06864 06865 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package ) 06866 { 06867 static const WCHAR query[] = { 06868 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 06869 '`','E','n','v','i','r','o','n','m','e','n','t','`',0}; 06870 MSIQUERY *view; 06871 UINT rc; 06872 06873 rc = MSI_DatabaseOpenViewW( package->db, query, &view ); 06874 if (rc != ERROR_SUCCESS) 06875 return ERROR_SUCCESS; 06876 06877 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package ); 06878 msiobj_release( &view->hdr ); 06879 return rc; 06880 } 06881 06882 UINT msi_validate_product_id( MSIPACKAGE *package ) 06883 { 06884 LPWSTR key, template, id; 06885 UINT r = ERROR_SUCCESS; 06886 06887 id = msi_dup_property( package->db, szProductID ); 06888 if (id) 06889 { 06890 msi_free( id ); 06891 return ERROR_SUCCESS; 06892 } 06893 template = msi_dup_property( package->db, szPIDTemplate ); 06894 key = msi_dup_property( package->db, szPIDKEY ); 06895 if (key && template) 06896 { 06897 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) ); 06898 r = msi_set_property( package->db, szProductID, key ); 06899 } 06900 msi_free( template ); 06901 msi_free( key ); 06902 return r; 06903 } 06904 06905 static UINT ACTION_ValidateProductID( MSIPACKAGE *package ) 06906 { 06907 return msi_validate_product_id( package ); 06908 } 06909 06910 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package ) 06911 { 06912 TRACE("\n"); 06913 package->need_reboot_at_end = 1; 06914 return ERROR_SUCCESS; 06915 } 06916 06917 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package ) 06918 { 06919 static const WCHAR szAvailableFreeReg[] = 06920 {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0}; 06921 MSIRECORD *uirow; 06922 int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 ); 06923 06924 TRACE("%p %d kilobytes\n", package, space); 06925 06926 uirow = MSI_CreateRecord( 1 ); 06927 MSI_RecordSetInteger( uirow, 1, space ); 06928 msi_ui_actiondata( package, szAllocateRegistrySpace, uirow ); 06929 msiobj_release( &uirow->hdr ); 06930 06931 return ERROR_SUCCESS; 06932 } 06933 06934 static UINT ACTION_DisableRollback( MSIPACKAGE *package ) 06935 { 06936 TRACE("%p\n", package); 06937 06938 msi_set_property( package->db, szRollbackDisabled, szOne ); 06939 return ERROR_SUCCESS; 06940 } 06941 06942 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package ) 06943 { 06944 FIXME("%p\n", package); 06945 return ERROR_SUCCESS; 06946 } 06947 06948 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package ) 06949 { 06950 static const WCHAR driver_query[] = { 06951 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 06952 'O','D','B','C','D','r','i','v','e','r',0}; 06953 static const WCHAR translator_query[] = { 06954 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 06955 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0}; 06956 MSIQUERY *view; 06957 UINT r, count; 06958 06959 r = MSI_DatabaseOpenViewW( package->db, driver_query, &view ); 06960 if (r == ERROR_SUCCESS) 06961 { 06962 count = 0; 06963 r = MSI_IterateRecords( view, &count, NULL, package ); 06964 msiobj_release( &view->hdr ); 06965 if (r != ERROR_SUCCESS) 06966 return r; 06967 if (count) FIXME("ignored %u rows in ODBCDriver table\n", count); 06968 } 06969 r = MSI_DatabaseOpenViewW( package->db, translator_query, &view ); 06970 if (r == ERROR_SUCCESS) 06971 { 06972 count = 0; 06973 r = MSI_IterateRecords( view, &count, NULL, package ); 06974 msiobj_release( &view->hdr ); 06975 if (r != ERROR_SUCCESS) 06976 return r; 06977 if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count); 06978 } 06979 return ERROR_SUCCESS; 06980 } 06981 06982 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param ) 06983 { 06984 MSIPACKAGE *package = param; 06985 const WCHAR *property = MSI_RecordGetString( rec, 1 ); 06986 WCHAR *value; 06987 06988 if ((value = msi_dup_property( package->db, property ))) 06989 { 06990 FIXME("remove %s\n", debugstr_w(value)); 06991 msi_free( value ); 06992 } 06993 return ERROR_SUCCESS; 06994 } 06995 06996 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package ) 06997 { 06998 static const WCHAR query[] = { 06999 'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ', 07000 'F','R','O','M',' ','U','p','g','r','a','d','e',0}; 07001 MSIQUERY *view; 07002 UINT r; 07003 07004 r = MSI_DatabaseOpenViewW( package->db, query, &view ); 07005 if (r == ERROR_SUCCESS) 07006 { 07007 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package ); 07008 msiobj_release( &view->hdr ); 07009 if (r != ERROR_SUCCESS) 07010 return r; 07011 } 07012 return ERROR_SUCCESS; 07013 } 07014 07015 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param ) 07016 { 07017 MSIPACKAGE *package = param; 07018 int attributes = MSI_RecordGetInteger( rec, 5 ); 07019 07020 if (attributes & msidbUpgradeAttributesMigrateFeatures) 07021 { 07022 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 ); 07023 const WCHAR *version_min = MSI_RecordGetString( rec, 2 ); 07024 const WCHAR *version_max = MSI_RecordGetString( rec, 3 ); 07025 const WCHAR *language = MSI_RecordGetString( rec, 4 ); 07026 HKEY hkey; 07027 UINT r; 07028 07029 if (package->Context == MSIINSTALLCONTEXT_MACHINE) 07030 { 07031 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE ); 07032 if (r != ERROR_SUCCESS) 07033 return ERROR_SUCCESS; 07034 } 07035 else 07036 { 07037 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE ); 07038 if (r != ERROR_SUCCESS) 07039 return ERROR_SUCCESS; 07040 } 07041 RegCloseKey( hkey ); 07042 07043 FIXME("migrate feature states from %s version min %s version max %s language %s\n", 07044 debugstr_w(upgrade_code), debugstr_w(version_min), 07045 debugstr_w(version_max), debugstr_w(language)); 07046 } 07047 return ERROR_SUCCESS; 07048 } 07049 07050 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package ) 07051 { 07052 static const WCHAR query[] = { 07053 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 07054 'U','p','g','r','a','d','e',0}; 07055 MSIQUERY *view; 07056 UINT r; 07057 07058 if (msi_get_property_int( package->db, szInstalled, 0 )) 07059 { 07060 TRACE("product is installed, skipping action\n"); 07061 return ERROR_SUCCESS; 07062 } 07063 if (msi_get_property_int( package->db, szPreselected, 0 )) 07064 { 07065 TRACE("Preselected property is set, not migrating feature states\n"); 07066 return ERROR_SUCCESS; 07067 } 07068 r = MSI_DatabaseOpenViewW( package->db, query, &view ); 07069 if (r == ERROR_SUCCESS) 07070 { 07071 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package ); 07072 msiobj_release( &view->hdr ); 07073 if (r != ERROR_SUCCESS) 07074 return r; 07075 } 07076 return ERROR_SUCCESS; 07077 } 07078 07079 static void bind_image( const char *filename, const char *path ) 07080 { 07081 if (!BindImageEx( 0, filename, path, NULL, NULL )) 07082 { 07083 WARN("failed to bind image %u\n", GetLastError()); 07084 } 07085 } 07086 07087 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param ) 07088 { 07089 UINT i; 07090 MSIFILE *file; 07091 MSIPACKAGE *package = param; 07092 const WCHAR *key = MSI_RecordGetString( rec, 1 ); 07093 const WCHAR *paths = MSI_RecordGetString( rec, 2 ); 07094 char *filenameA, *pathA; 07095 WCHAR *pathW, **path_list; 07096 07097 if (!(file = msi_get_loaded_file( package, key ))) 07098 { 07099 WARN("file %s not found\n", debugstr_w(key)); 07100 return ERROR_SUCCESS; 07101 } 07102 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS; 07103 path_list = msi_split_string( paths, ';' ); 07104 if (!path_list) bind_image( filenameA, NULL ); 07105 else 07106 { 07107 for (i = 0; path_list[i] && path_list[i][0]; i++) 07108 { 07109 deformat_string( package, path_list[i], &pathW ); 07110 if ((pathA = strdupWtoA( pathW ))) 07111 { 07112 bind_image( filenameA, pathA ); 07113 msi_free( pathA ); 07114 } 07115 msi_free( pathW ); 07116 } 07117 } 07118 msi_free( path_list ); 07119 msi_free( filenameA ); 07120 return ERROR_SUCCESS; 07121 } 07122 07123 static UINT ACTION_BindImage( MSIPACKAGE *package ) 07124 { 07125 static const WCHAR query[] = { 07126 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 07127 'B','i','n','d','I','m','a','g','e',0}; 07128 MSIQUERY *view; 07129 UINT r; 07130 07131 r = MSI_DatabaseOpenViewW( package->db, query, &view ); 07132 if (r == ERROR_SUCCESS) 07133 { 07134 r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package ); 07135 msiobj_release( &view->hdr ); 07136 if (r != ERROR_SUCCESS) 07137 return r; 07138 } 07139 return ERROR_SUCCESS; 07140 } 07141 07142 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table ) 07143 { 07144 static const WCHAR query[] = { 07145 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0}; 07146 MSIQUERY *view; 07147 DWORD count = 0; 07148 UINT r; 07149 07150 r = MSI_OpenQuery( package->db, &view, query, table ); 07151 if (r == ERROR_SUCCESS) 07152 { 07153 r = MSI_IterateRecords(view, &count, NULL, package); 07154 msiobj_release(&view->hdr); 07155 if (r != ERROR_SUCCESS) 07156 return r; 07157 } 07158 if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table)); 07159 return ERROR_SUCCESS; 07160 } 07161 07162 static UINT ACTION_IsolateComponents( MSIPACKAGE *package ) 07163 { 07164 static const WCHAR table[] = { 07165 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 }; 07166 return msi_unimplemented_action_stub( package, "IsolateComponents", table ); 07167 } 07168 07169 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package ) 07170 { 07171 static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 }; 07172 return msi_unimplemented_action_stub( package, "RMCCPSearch", table ); 07173 } 07174 07175 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package ) 07176 { 07177 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 }; 07178 return msi_unimplemented_action_stub( package, "RegisterComPlus", table ); 07179 } 07180 07181 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package ) 07182 { 07183 static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 }; 07184 return msi_unimplemented_action_stub( package, "UnregisterComPlus", table ); 07185 } 07186 07187 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package ) 07188 { 07189 static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 }; 07190 return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table ); 07191 } 07192 07193 static const struct 07194 { 07195 const WCHAR *action; 07196 UINT (*handler)(MSIPACKAGE *); 07197 const WCHAR *action_rollback; 07198 } 07199 StandardActions[] = 07200 { 07201 { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL }, 07202 { szAppSearch, ACTION_AppSearch, NULL }, 07203 { szBindImage, ACTION_BindImage, NULL }, 07204 { szCCPSearch, ACTION_CCPSearch, NULL }, 07205 { szCostFinalize, ACTION_CostFinalize, NULL }, 07206 { szCostInitialize, ACTION_CostInitialize, NULL }, 07207 { szCreateFolders, ACTION_CreateFolders, szRemoveFolders }, 07208 { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts }, 07209 { szDeleteServices, ACTION_DeleteServices, szInstallServices }, 07210 { szDisableRollback, ACTION_DisableRollback, NULL }, 07211 { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles }, 07212 { szExecuteAction, ACTION_ExecuteAction, NULL }, 07213 { szFileCost, ACTION_FileCost, NULL }, 07214 { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL }, 07215 { szForceReboot, ACTION_ForceReboot, NULL }, 07216 { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL }, 07217 { szInstallExecute, ACTION_InstallExecute, NULL }, 07218 { szInstallExecuteAgain, ACTION_InstallExecute, NULL }, 07219 { szInstallFiles, ACTION_InstallFiles, szRemoveFiles }, 07220 { szInstallFinalize, ACTION_InstallFinalize, NULL }, 07221 { szInstallInitialize, ACTION_InstallInitialize, NULL }, 07222 { szInstallODBC, ACTION_InstallODBC, szRemoveODBC }, 07223 { szInstallServices, ACTION_InstallServices, szDeleteServices }, 07224 { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL }, 07225 { szInstallValidate, ACTION_InstallValidate, NULL }, 07226 { szIsolateComponents, ACTION_IsolateComponents, NULL }, 07227 { szLaunchConditions, ACTION_LaunchConditions, NULL }, 07228 { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL }, 07229 { szMoveFiles, ACTION_MoveFiles, NULL }, 07230 { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies }, 07231 { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies }, 07232 { szPatchFiles, ACTION_PatchFiles, NULL }, 07233 { szProcessComponents, ACTION_ProcessComponents, szProcessComponents }, 07234 { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents }, 07235 { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures }, 07236 { szPublishProduct, ACTION_PublishProduct, NULL }, 07237 { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo }, 07238 { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus }, 07239 { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo }, 07240 { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts }, 07241 { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo }, 07242 { szRegisterProduct, ACTION_RegisterProduct, NULL }, 07243 { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo }, 07244 { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries }, 07245 { szRegisterUser, ACTION_RegisterUser, NULL }, 07246 { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles }, 07247 { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings }, 07248 { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL }, 07249 { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles }, 07250 { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders }, 07251 { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues }, 07252 { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC }, 07253 { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues }, 07254 { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts }, 07255 { szResolveSource, ACTION_ResolveSource, NULL }, 07256 { szRMCCPSearch, ACTION_RMCCPSearch, NULL }, 07257 { szScheduleReboot, ACTION_ScheduleReboot, NULL }, 07258 { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules }, 07259 { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules }, 07260 { szSetODBCFolders, ACTION_SetODBCFolders, NULL }, 07261 { szStartServices, ACTION_StartServices, szStopServices }, 07262 { szStopServices, ACTION_StopServices, szStartServices }, 07263 { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents }, 07264 { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures }, 07265 { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo }, 07266 { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus }, 07267 { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo }, 07268 { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts }, 07269 { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo }, 07270 { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo }, 07271 { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries }, 07272 { szValidateProductID, ACTION_ValidateProductID, NULL }, 07273 { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings }, 07274 { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues }, 07275 { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues }, 07276 { NULL, NULL, NULL } 07277 }; 07278 07279 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc ) 07280 { 07281 BOOL ret = FALSE; 07282 UINT i; 07283 07284 i = 0; 07285 while (StandardActions[i].action != NULL) 07286 { 07287 if (!strcmpW( StandardActions[i].action, action )) 07288 { 07289 ui_actionstart( package, action ); 07290 if (StandardActions[i].handler) 07291 { 07292 ui_actioninfo( package, action, TRUE, 0 ); 07293 *rc = StandardActions[i].handler( package ); 07294 ui_actioninfo( package, action, FALSE, *rc ); 07295 07296 if (StandardActions[i].action_rollback && !package->need_rollback) 07297 { 07298 TRACE("scheduling rollback action\n"); 07299 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback ); 07300 } 07301 } 07302 else 07303 { 07304 FIXME("unhandled standard action %s\n", debugstr_w(action)); 07305 *rc = ERROR_SUCCESS; 07306 } 07307 ret = TRUE; 07308 break; 07309 } 07310 i++; 07311 } 07312 return ret; 07313 } 07314 07315 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script) 07316 { 07317 UINT rc = ERROR_SUCCESS; 07318 BOOL handled; 07319 07320 TRACE("Performing action (%s)\n", debugstr_w(action)); 07321 07322 handled = ACTION_HandleStandardAction(package, action, &rc); 07323 07324 if (!handled) 07325 handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE); 07326 07327 if (!handled) 07328 { 07329 WARN("unhandled msi action %s\n", debugstr_w(action)); 07330 rc = ERROR_FUNCTION_NOT_CALLED; 07331 } 07332 07333 return rc; 07334 } 07335 07336 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script) 07337 { 07338 UINT rc = ERROR_SUCCESS; 07339 BOOL handled = FALSE; 07340 07341 TRACE("Performing action (%s)\n", debugstr_w(action)); 07342 07343 handled = ACTION_HandleStandardAction(package, action, &rc); 07344 07345 if (!handled) 07346 handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE); 07347 07348 if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS ) 07349 handled = TRUE; 07350 07351 if (!handled) 07352 { 07353 WARN("unhandled msi action %s\n", debugstr_w(action)); 07354 rc = ERROR_FUNCTION_NOT_CALLED; 07355 } 07356 07357 return rc; 07358 } 07359 07360 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq) 07361 { 07362 UINT rc = ERROR_SUCCESS; 07363 MSIRECORD *row; 07364 07365 static const WCHAR query[] = 07366 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 07367 '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e', 07368 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ', 07369 '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0}; 07370 static const WCHAR ui_query[] = 07371 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', 07372 '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e', 07373 '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`', 07374 ' ', '=',' ','%','i',0}; 07375 07376 if (needs_ui_sequence(package)) 07377 row = MSI_QueryGetRecord(package->db, ui_query, seq); 07378 else 07379 row = MSI_QueryGetRecord(package->db, query, seq); 07380 07381 if (row) 07382 { 07383 LPCWSTR action, cond; 07384 07385 TRACE("Running the actions\n"); 07386 07387 /* check conditions */ 07388 cond = MSI_RecordGetString(row, 2); 07389 07390 /* this is a hack to skip errors in the condition code */ 07391 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE) 07392 { 07393 msiobj_release(&row->hdr); 07394 return ERROR_SUCCESS; 07395 } 07396 07397 action = MSI_RecordGetString(row, 1); 07398 if (!action) 07399 { 07400 ERR("failed to fetch action\n"); 07401 msiobj_release(&row->hdr); 07402 return ERROR_FUNCTION_FAILED; 07403 } 07404 07405 if (needs_ui_sequence(package)) 07406 rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE); 07407 else 07408 rc = ACTION_PerformAction(package, action, SCRIPT_NONE); 07409 07410 msiobj_release(&row->hdr); 07411 } 07412 07413 return rc; 07414 } 07415 07416 /**************************************************** 07417 * TOP level entry points 07418 *****************************************************/ 07419 07420 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath, 07421 LPCWSTR szCommandLine ) 07422 { 07423 static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0}; 07424 static const WCHAR szAction[] = {'A','C','T','I','O','N',0}; 07425 static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0}; 07426 WCHAR *reinstall = NULL; 07427 BOOL ui_exists; 07428 UINT rc; 07429 07430 msi_set_property( package->db, szAction, szInstall ); 07431 07432 package->script->InWhatSequence = SEQUENCE_INSTALL; 07433 07434 if (szPackagePath) 07435 { 07436 LPWSTR p, dir; 07437 LPCWSTR file; 07438 07439 dir = strdupW(szPackagePath); 07440 p = strrchrW(dir, '\\'); 07441 if (p) 07442 { 07443 *(++p) = 0; 07444 file = szPackagePath + (p - dir); 07445 } 07446 else 07447 { 07448 msi_free(dir); 07449 dir = msi_alloc(MAX_PATH * sizeof(WCHAR)); 07450 GetCurrentDirectoryW(MAX_PATH, dir); 07451 lstrcatW(dir, szBackSlash); 07452 file = szPackagePath; 07453 } 07454 07455 msi_free( package->PackagePath ); 07456 package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR)); 07457 if (!package->PackagePath) 07458 { 07459 msi_free(dir); 07460 return ERROR_OUTOFMEMORY; 07461 } 07462 07463 lstrcpyW(package->PackagePath, dir); 07464 lstrcatW(package->PackagePath, file); 07465 msi_free(dir); 07466 07467 msi_set_sourcedir_props(package, FALSE); 07468 } 07469 07470 rc = msi_parse_command_line( package, szCommandLine, FALSE ); 07471 if (rc != ERROR_SUCCESS) 07472 return rc; 07473 07474 msi_apply_transforms( package ); 07475 msi_apply_patches( package ); 07476 07477 if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 )) 07478 { 07479 TRACE("setting reinstall property\n"); 07480 msi_set_property( package->db, szReinstall, szAll ); 07481 } 07482 07483 /* properties may have been added by a transform */ 07484 msi_clone_properties( package ); 07485 07486 msi_parse_command_line( package, szCommandLine, FALSE ); 07487 msi_adjust_privilege_properties( package ); 07488 msi_set_context( package ); 07489 07490 if (msi_get_property_int( package->db, szDisableRollback, 0 )) 07491 { 07492 TRACE("disabling rollback\n"); 07493 msi_set_property( package->db, szRollbackDisabled, szOne ); 07494 } 07495 07496 if (needs_ui_sequence( package)) 07497 { 07498 package->script->InWhatSequence |= SEQUENCE_UI; 07499 rc = ACTION_ProcessUISequence(package); 07500 ui_exists = ui_sequence_exists(package); 07501 if (rc == ERROR_SUCCESS || !ui_exists) 07502 { 07503 package->script->InWhatSequence |= SEQUENCE_EXEC; 07504 rc = ACTION_ProcessExecSequence(package, ui_exists); 07505 } 07506 } 07507 else 07508 rc = ACTION_ProcessExecSequence(package, FALSE); 07509 07510 package->script->CurrentlyScripting = FALSE; 07511 07512 /* process the ending type action */ 07513 if (rc == ERROR_SUCCESS) 07514 ACTION_PerformActionSequence(package, -1); 07515 else if (rc == ERROR_INSTALL_USEREXIT) 07516 ACTION_PerformActionSequence(package, -2); 07517 else if (rc == ERROR_INSTALL_SUSPEND) 07518 ACTION_PerformActionSequence(package, -4); 07519 else /* failed */ 07520 { 07521 ACTION_PerformActionSequence(package, -3); 07522 if (!msi_get_property_int( package->db, szRollbackDisabled, 0 )) 07523 { 07524 package->need_rollback = TRUE; 07525 } 07526 } 07527 07528 /* finish up running custom actions */ 07529 ACTION_FinishCustomActions(package); 07530 07531 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall ))) 07532 { 07533 WARN("installation failed, running rollback script\n"); 07534 execute_script( package, SCRIPT_ROLLBACK ); 07535 } 07536 msi_free( reinstall ); 07537 07538 if (rc == ERROR_SUCCESS && package->need_reboot_at_end) 07539 return ERROR_SUCCESS_REBOOT_REQUIRED; 07540 07541 return rc; 07542 } Generated on Sun May 27 2012 04:25:11 for ReactOS by
1.7.6.1
|