Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmsiexec.c
Go to the documentation of this file.
00001 /* 00002 * msiexec.exe implementation 00003 * 00004 * Copyright 2004 Vincent Béron 00005 * Copyright 2005 Mike McCormack 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 #define WIN32_LEAN_AND_MEAN 00023 00024 #include <windows.h> 00025 #include <msi.h> 00026 #include <objbase.h> 00027 #include <stdio.h> 00028 00029 #include "wine/debug.h" 00030 #include "wine/unicode.h" 00031 00032 WINE_DEFAULT_DEBUG_CHANNEL(msiexec); 00033 00034 typedef HRESULT (WINAPI *DLLREGISTERSERVER)(void); 00035 typedef HRESULT (WINAPI *DLLUNREGISTERSERVER)(void); 00036 00037 DWORD DoService(void); 00038 00039 struct string_list 00040 { 00041 struct string_list *next; 00042 WCHAR str[1]; 00043 }; 00044 00045 static const WCHAR ActionAdmin[] = { 00046 'A','C','T','I','O','N','=','A','D','M','I','N',0 }; 00047 static const WCHAR RemoveAll[] = { 00048 'R','E','M','O','V','E','=','A','L','L',0 }; 00049 00050 static const WCHAR InstallRunOnce[] = { 00051 'S','o','f','t','w','a','r','e','\\', 00052 'M','i','c','r','o','s','o','f','t','\\', 00053 'W','i','n','d','o','w','s','\\', 00054 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 00055 'I','n','s','t','a','l','l','e','r','\\', 00056 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0}; 00057 00058 static void ShowUsage(int ExitCode) 00059 { 00060 WCHAR msiexec_version[40]; 00061 WCHAR filename[MAX_PATH]; 00062 LPWSTR msi_res; 00063 LPWSTR msiexec_help; 00064 HMODULE hmsi = GetModuleHandleA("msi.dll"); 00065 DWORD len; 00066 DWORD res; 00067 00068 /* MsiGetFileVersion need the full path */ 00069 *filename = 0; 00070 res = GetModuleFileNameW(hmsi, filename, sizeof(filename) / sizeof(filename[0])); 00071 if (!res) 00072 WINE_ERR("GetModuleFileName failed: %d\n", GetLastError()); 00073 00074 len = sizeof(msiexec_version) / sizeof(msiexec_version[0]); 00075 *msiexec_version = 0; 00076 res = MsiGetFileVersionW(filename, msiexec_version, &len, NULL, NULL); 00077 if (res) 00078 WINE_ERR("MsiGetFileVersion failed with %d\n", res); 00079 00080 /* Return the length of the resource. 00081 No typo: The LPWSTR parameter must be a LPWSTR * for this mode */ 00082 len = LoadStringW(hmsi, 10, (LPWSTR) &msi_res, 0); 00083 00084 msi_res = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); 00085 msiexec_help = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) + sizeof(msiexec_version)); 00086 if (msi_res && msiexec_help) { 00087 *msi_res = 0; 00088 LoadStringW(hmsi, 10, msi_res, len + 1); 00089 00090 sprintfW(msiexec_help, msi_res, msiexec_version); 00091 MsiMessageBoxW(0, msiexec_help, NULL, 0, GetUserDefaultLangID(), 0); 00092 } 00093 HeapFree(GetProcessHeap(), 0, msi_res); 00094 HeapFree(GetProcessHeap(), 0, msiexec_help); 00095 ExitProcess(ExitCode); 00096 } 00097 00098 static BOOL IsProductCode(LPWSTR str) 00099 { 00100 GUID ProductCode; 00101 00102 if(lstrlenW(str) != 38) 00103 return FALSE; 00104 return ( (CLSIDFromString(str, &ProductCode) == NOERROR) ); 00105 00106 } 00107 00108 static VOID StringListAppend(struct string_list **list, LPCWSTR str) 00109 { 00110 struct string_list *entry; 00111 DWORD size; 00112 00113 size = sizeof *entry + lstrlenW(str) * sizeof (WCHAR); 00114 entry = HeapAlloc(GetProcessHeap(), 0, size); 00115 if(!entry) 00116 { 00117 WINE_ERR("Out of memory!\n"); 00118 ExitProcess(1); 00119 } 00120 lstrcpyW(entry->str, str); 00121 entry->next = NULL; 00122 00123 /* 00124 * Ignoring o(n^2) time complexity to add n strings for simplicity, 00125 * add the string to the end of the list to preserve the order. 00126 */ 00127 while( *list ) 00128 list = &(*list)->next; 00129 *list = entry; 00130 } 00131 00132 static LPWSTR build_properties(struct string_list *property_list) 00133 { 00134 struct string_list *list; 00135 LPWSTR ret, p, value; 00136 DWORD len; 00137 BOOL needs_quote; 00138 00139 if(!property_list) 00140 return NULL; 00141 00142 /* count the space we need */ 00143 len = 1; 00144 for(list = property_list; list; list = list->next) 00145 len += lstrlenW(list->str) + 3; 00146 00147 ret = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); 00148 00149 /* add a space before each string, and quote the value */ 00150 p = ret; 00151 for(list = property_list; list; list = list->next) 00152 { 00153 value = strchrW(list->str,'='); 00154 if(!value) 00155 continue; 00156 len = value - list->str; 00157 *p++ = ' '; 00158 memcpy(p, list->str, len * sizeof(WCHAR)); 00159 p += len; 00160 *p++ = '='; 00161 00162 /* check if the value contains spaces and maybe quote it */ 00163 value++; 00164 needs_quote = strchrW(value,' ') ? 1 : 0; 00165 if(needs_quote) 00166 *p++ = '"'; 00167 len = lstrlenW(value); 00168 memcpy(p, value, len * sizeof(WCHAR)); 00169 p += len; 00170 if(needs_quote) 00171 *p++ = '"'; 00172 } 00173 *p = 0; 00174 00175 WINE_TRACE("properties -> %s\n", wine_dbgstr_w(ret) ); 00176 00177 return ret; 00178 } 00179 00180 static LPWSTR build_transforms(struct string_list *transform_list) 00181 { 00182 struct string_list *list; 00183 LPWSTR ret, p; 00184 DWORD len; 00185 00186 /* count the space we need */ 00187 len = 1; 00188 for(list = transform_list; list; list = list->next) 00189 len += lstrlenW(list->str) + 1; 00190 00191 ret = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); 00192 00193 /* add all the transforms with a semicolon between each one */ 00194 p = ret; 00195 for(list = transform_list; list; list = list->next) 00196 { 00197 len = lstrlenW(list->str); 00198 lstrcpynW(p, list->str, len ); 00199 p += len; 00200 if(list->next) 00201 *p++ = ';'; 00202 } 00203 *p = 0; 00204 00205 return ret; 00206 } 00207 00208 static DWORD msi_atou(LPCWSTR str) 00209 { 00210 DWORD ret = 0; 00211 while(*str >= '0' && *str <= '9') 00212 { 00213 ret *= 10; 00214 ret += (*str - '0'); 00215 str++; 00216 } 00217 return ret; 00218 } 00219 00220 static LPWSTR msi_strdup(LPCWSTR str) 00221 { 00222 DWORD len = lstrlenW(str)+1; 00223 LPWSTR ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len); 00224 lstrcpyW(ret, str); 00225 return ret; 00226 } 00227 00228 /* str1 is the same as str2, ignoring case */ 00229 static BOOL msi_strequal(LPCWSTR str1, LPCSTR str2) 00230 { 00231 DWORD len, ret; 00232 LPWSTR strW; 00233 00234 len = MultiByteToWideChar( CP_ACP, 0, str2, -1, NULL, 0); 00235 if( !len ) 00236 return FALSE; 00237 if( lstrlenW(str1) != (len-1) ) 00238 return FALSE; 00239 strW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len); 00240 MultiByteToWideChar( CP_ACP, 0, str2, -1, strW, len); 00241 ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str1, len, strW, len); 00242 HeapFree(GetProcessHeap(), 0, strW); 00243 return (ret == CSTR_EQUAL); 00244 } 00245 00246 /* prefix is hyphen or dash, and str1 is the same as str2, ignoring case */ 00247 static BOOL msi_option_equal(LPCWSTR str1, LPCSTR str2) 00248 { 00249 if (str1[0] != '/' && str1[0] != '-') 00250 return FALSE; 00251 00252 /* skip over the hyphen or slash */ 00253 return msi_strequal(str1 + 1, str2); 00254 } 00255 00256 /* str2 is at the beginning of str1, ignoring case */ 00257 static BOOL msi_strprefix(LPCWSTR str1, LPCSTR str2) 00258 { 00259 DWORD len, ret; 00260 LPWSTR strW; 00261 00262 len = MultiByteToWideChar( CP_ACP, 0, str2, -1, NULL, 0); 00263 if( !len ) 00264 return FALSE; 00265 if( lstrlenW(str1) < (len-1) ) 00266 return FALSE; 00267 strW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len); 00268 MultiByteToWideChar( CP_ACP, 0, str2, -1, strW, len); 00269 ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str1, len-1, strW, len-1); 00270 HeapFree(GetProcessHeap(), 0, strW); 00271 return (ret == CSTR_EQUAL); 00272 } 00273 00274 /* prefix is hyphen or dash, and str2 is at the beginning of str1, ignoring case */ 00275 static BOOL msi_option_prefix(LPCWSTR str1, LPCSTR str2) 00276 { 00277 if (str1[0] != '/' && str1[0] != '-') 00278 return FALSE; 00279 00280 /* skip over the hyphen or slash */ 00281 return msi_strprefix(str1 + 1, str2); 00282 } 00283 00284 static VOID *LoadProc(LPCWSTR DllName, LPCSTR ProcName, HMODULE* DllHandle) 00285 { 00286 VOID* (*proc)(void); 00287 00288 *DllHandle = LoadLibraryExW(DllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); 00289 if(!*DllHandle) 00290 { 00291 fprintf(stderr, "Unable to load dll %s\n", wine_dbgstr_w(DllName)); 00292 ExitProcess(1); 00293 } 00294 proc = (VOID *) GetProcAddress(*DllHandle, ProcName); 00295 if(!proc) 00296 { 00297 fprintf(stderr, "Dll %s does not implement function %s\n", 00298 wine_dbgstr_w(DllName), ProcName); 00299 FreeLibrary(*DllHandle); 00300 ExitProcess(1); 00301 } 00302 00303 return proc; 00304 } 00305 00306 static DWORD DoDllRegisterServer(LPCWSTR DllName) 00307 { 00308 HRESULT hr; 00309 DLLREGISTERSERVER pfDllRegisterServer = NULL; 00310 HMODULE DllHandle = NULL; 00311 00312 pfDllRegisterServer = LoadProc(DllName, "DllRegisterServer", &DllHandle); 00313 00314 hr = pfDllRegisterServer(); 00315 if(FAILED(hr)) 00316 { 00317 fprintf(stderr, "Failed to register dll %s\n", wine_dbgstr_w(DllName)); 00318 return 1; 00319 } 00320 printf("Successfully registered dll %s\n", wine_dbgstr_w(DllName)); 00321 if(DllHandle) 00322 FreeLibrary(DllHandle); 00323 return 0; 00324 } 00325 00326 static DWORD DoDllUnregisterServer(LPCWSTR DllName) 00327 { 00328 HRESULT hr; 00329 DLLUNREGISTERSERVER pfDllUnregisterServer = NULL; 00330 HMODULE DllHandle = NULL; 00331 00332 pfDllUnregisterServer = LoadProc(DllName, "DllUnregisterServer", &DllHandle); 00333 00334 hr = pfDllUnregisterServer(); 00335 if(FAILED(hr)) 00336 { 00337 fprintf(stderr, "Failed to unregister dll %s\n", wine_dbgstr_w(DllName)); 00338 return 1; 00339 } 00340 printf("Successfully unregistered dll %s\n", wine_dbgstr_w(DllName)); 00341 if(DllHandle) 00342 FreeLibrary(DllHandle); 00343 return 0; 00344 } 00345 00346 static DWORD DoRegServer(void) 00347 { 00348 SC_HANDLE scm, service; 00349 CHAR path[MAX_PATH+12]; 00350 DWORD ret = 0; 00351 00352 scm = OpenSCManagerA(NULL, SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CREATE_SERVICE); 00353 if (!scm) 00354 { 00355 fprintf(stderr, "Failed to open the service control manager.\n"); 00356 return 1; 00357 } 00358 00359 GetSystemDirectoryA(path, MAX_PATH); 00360 lstrcatA(path, "\\msiexec.exe /V"); 00361 00362 service = CreateServiceA(scm, "MSIServer", "MSIServer", GENERIC_ALL, 00363 SERVICE_WIN32_SHARE_PROCESS, SERVICE_DEMAND_START, 00364 SERVICE_ERROR_NORMAL, path, NULL, NULL, 00365 NULL, NULL, NULL); 00366 00367 if (service) CloseServiceHandle(service); 00368 else if (GetLastError() != ERROR_SERVICE_EXISTS) 00369 { 00370 fprintf(stderr, "Failed to create MSI service\n"); 00371 ret = 1; 00372 } 00373 CloseServiceHandle(scm); 00374 return ret; 00375 } 00376 00377 static INT DoEmbedding( LPWSTR key ) 00378 { 00379 printf("Remote custom actions are not supported yet\n"); 00380 return 1; 00381 } 00382 00383 /* 00384 * state machine to break up the command line properly 00385 */ 00386 00387 enum chomp_state 00388 { 00389 cs_whitespace, 00390 cs_token, 00391 cs_quote 00392 }; 00393 00394 static int chomp( WCHAR *str ) 00395 { 00396 enum chomp_state state = cs_token; 00397 WCHAR *p, *out; 00398 int count = 1, ignore; 00399 00400 for( p = str, out = str; *p; p++ ) 00401 { 00402 ignore = 1; 00403 switch( state ) 00404 { 00405 case cs_whitespace: 00406 switch( *p ) 00407 { 00408 case ' ': 00409 break; 00410 case '"': 00411 state = cs_quote; 00412 count++; 00413 break; 00414 default: 00415 count++; 00416 ignore = 0; 00417 state = cs_token; 00418 } 00419 break; 00420 00421 case cs_token: 00422 switch( *p ) 00423 { 00424 case '"': 00425 state = cs_quote; 00426 break; 00427 case ' ': 00428 state = cs_whitespace; 00429 *out++ = 0; 00430 break; 00431 default: 00432 ignore = 0; 00433 } 00434 break; 00435 00436 case cs_quote: 00437 switch( *p ) 00438 { 00439 case '"': 00440 state = cs_token; 00441 break; 00442 default: 00443 ignore = 0; 00444 } 00445 break; 00446 } 00447 if( !ignore ) 00448 *out++ = *p; 00449 } 00450 00451 *out = 0; 00452 00453 return count; 00454 } 00455 00456 static void process_args( WCHAR *cmdline, int *pargc, WCHAR ***pargv ) 00457 { 00458 WCHAR **argv, *p = msi_strdup(cmdline); 00459 int i, n; 00460 00461 n = chomp( p ); 00462 argv = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR*)*(n+1)); 00463 for( i=0; i<n; i++ ) 00464 { 00465 argv[i] = p; 00466 p += lstrlenW(p) + 1; 00467 } 00468 argv[i] = NULL; 00469 00470 *pargc = n; 00471 *pargv = argv; 00472 } 00473 00474 static BOOL process_args_from_reg( LPWSTR ident, int *pargc, WCHAR ***pargv ) 00475 { 00476 LONG r; 00477 HKEY hkey = 0, hkeyArgs = 0; 00478 DWORD sz = 0, type = 0; 00479 LPWSTR buf = NULL; 00480 BOOL ret = FALSE; 00481 00482 r = RegOpenKeyW(HKEY_LOCAL_MACHINE, InstallRunOnce, &hkey); 00483 if(r != ERROR_SUCCESS) 00484 return FALSE; 00485 r = RegQueryValueExW(hkey, ident, 0, &type, 0, &sz); 00486 if(r == ERROR_SUCCESS && type == REG_SZ) 00487 { 00488 buf = HeapAlloc(GetProcessHeap(), 0, sz); 00489 r = RegQueryValueExW(hkey, ident, 0, &type, (LPBYTE)buf, &sz); 00490 if( r == ERROR_SUCCESS ) 00491 { 00492 process_args(buf, pargc, pargv); 00493 ret = TRUE; 00494 } 00495 HeapFree(GetProcessHeap(), 0, buf); 00496 } 00497 RegCloseKey(hkeyArgs); 00498 return ret; 00499 } 00500 00501 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 00502 { 00503 int i; 00504 BOOL FunctionInstall = FALSE; 00505 BOOL FunctionInstallAdmin = FALSE; 00506 BOOL FunctionRepair = FALSE; 00507 BOOL FunctionAdvertise = FALSE; 00508 BOOL FunctionPatch = FALSE; 00509 BOOL FunctionDllRegisterServer = FALSE; 00510 BOOL FunctionDllUnregisterServer = FALSE; 00511 BOOL FunctionRegServer = FALSE; 00512 BOOL FunctionUnregServer = FALSE; 00513 BOOL FunctionServer = FALSE; 00514 BOOL FunctionUnknown = FALSE; 00515 00516 LPWSTR PackageName = NULL; 00517 LPWSTR Properties = NULL; 00518 struct string_list *property_list = NULL; 00519 00520 DWORD RepairMode = 0; 00521 00522 DWORD_PTR AdvertiseMode = 0; 00523 struct string_list *transform_list = NULL; 00524 LANGID Language = 0; 00525 00526 DWORD LogMode = 0; 00527 LPWSTR LogFileName = NULL; 00528 DWORD LogAttributes = 0; 00529 00530 LPWSTR PatchFileName = NULL; 00531 INSTALLTYPE InstallType = INSTALLTYPE_DEFAULT; 00532 00533 INSTALLUILEVEL InstallUILevel = INSTALLUILEVEL_FULL; 00534 00535 LPWSTR DllName = NULL; 00536 DWORD ReturnCode; 00537 int argc; 00538 LPWSTR *argvW = NULL; 00539 00540 /* parse the command line */ 00541 process_args( GetCommandLineW(), &argc, &argvW ); 00542 00543 /* 00544 * If the args begin with /@ IDENT then we need to load the real 00545 * command line out of the RunOnceEntries key in the registry. 00546 * We do that before starting to process the real commandline, 00547 * then overwrite the commandline again. 00548 */ 00549 if(argc>1 && msi_option_equal(argvW[1], "@")) 00550 { 00551 if(!process_args_from_reg( argvW[2], &argc, &argvW )) 00552 return 1; 00553 } 00554 00555 if (argc == 3 && msi_option_equal(argvW[1], "Embedding")) 00556 return DoEmbedding( argvW[2] ); 00557 00558 for(i = 1; i < argc; i++) 00559 { 00560 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i])); 00561 00562 if (msi_option_equal(argvW[i], "regserver")) 00563 { 00564 FunctionRegServer = TRUE; 00565 } 00566 else if (msi_option_equal(argvW[i], "unregserver") || msi_option_equal(argvW[i], "unregister")) 00567 { 00568 FunctionUnregServer = TRUE; 00569 } 00570 else if(msi_option_prefix(argvW[i], "i") || msi_option_prefix(argvW[i], "package")) 00571 { 00572 LPWSTR argvWi = argvW[i]; 00573 int argLen = (msi_option_prefix(argvW[i], "i") ? 2 : 8); 00574 FunctionInstall = TRUE; 00575 if(lstrlenW(argvW[i]) > argLen) 00576 argvWi += argLen; 00577 else 00578 { 00579 i++; 00580 if(i >= argc) 00581 ShowUsage(1); 00582 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i])); 00583 argvWi = argvW[i]; 00584 } 00585 PackageName = argvWi; 00586 } 00587 else if(msi_option_equal(argvW[i], "a")) 00588 { 00589 FunctionInstall = TRUE; 00590 FunctionInstallAdmin = TRUE; 00591 InstallType = INSTALLTYPE_NETWORK_IMAGE; 00592 i++; 00593 if(i >= argc) 00594 ShowUsage(1); 00595 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i])); 00596 PackageName = argvW[i]; 00597 StringListAppend(&property_list, ActionAdmin); 00598 } 00599 else if(msi_option_prefix(argvW[i], "f")) 00600 { 00601 int j; 00602 int len = lstrlenW(argvW[i]); 00603 FunctionRepair = TRUE; 00604 for(j = 2; j < len; j++) 00605 { 00606 switch(argvW[i][j]) 00607 { 00608 case 'P': 00609 case 'p': 00610 RepairMode |= REINSTALLMODE_FILEMISSING; 00611 break; 00612 case 'O': 00613 case 'o': 00614 RepairMode |= REINSTALLMODE_FILEOLDERVERSION; 00615 break; 00616 case 'E': 00617 case 'e': 00618 RepairMode |= REINSTALLMODE_FILEEQUALVERSION; 00619 break; 00620 case 'D': 00621 case 'd': 00622 RepairMode |= REINSTALLMODE_FILEEXACT; 00623 break; 00624 case 'C': 00625 case 'c': 00626 RepairMode |= REINSTALLMODE_FILEVERIFY; 00627 break; 00628 case 'A': 00629 case 'a': 00630 RepairMode |= REINSTALLMODE_FILEREPLACE; 00631 break; 00632 case 'U': 00633 case 'u': 00634 RepairMode |= REINSTALLMODE_USERDATA; 00635 break; 00636 case 'M': 00637 case 'm': 00638 RepairMode |= REINSTALLMODE_MACHINEDATA; 00639 break; 00640 case 'S': 00641 case 's': 00642 RepairMode |= REINSTALLMODE_SHORTCUT; 00643 break; 00644 case 'V': 00645 case 'v': 00646 RepairMode |= REINSTALLMODE_PACKAGE; 00647 break; 00648 default: 00649 fprintf(stderr, "Unknown option \"%c\" in Repair mode\n", argvW[i][j]); 00650 break; 00651 } 00652 } 00653 if(len == 2) 00654 { 00655 RepairMode = REINSTALLMODE_FILEMISSING | 00656 REINSTALLMODE_FILEEQUALVERSION | 00657 REINSTALLMODE_FILEVERIFY | 00658 REINSTALLMODE_MACHINEDATA | 00659 REINSTALLMODE_SHORTCUT; 00660 } 00661 i++; 00662 if(i >= argc) 00663 ShowUsage(1); 00664 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i])); 00665 PackageName = argvW[i]; 00666 } 00667 else if(msi_option_prefix(argvW[i], "x") || msi_option_equal(argvW[i], "uninstall")) 00668 { 00669 FunctionInstall = TRUE; 00670 if(msi_option_prefix(argvW[i], "x")) PackageName = argvW[i]+2; 00671 if(!PackageName || !PackageName[0]) 00672 { 00673 i++; 00674 if (i >= argc) 00675 ShowUsage(1); 00676 PackageName = argvW[i]; 00677 } 00678 WINE_TRACE("PackageName = %s\n", wine_dbgstr_w(PackageName)); 00679 StringListAppend(&property_list, RemoveAll); 00680 } 00681 else if(msi_option_prefix(argvW[i], "j")) 00682 { 00683 int j; 00684 int len = lstrlenW(argvW[i]); 00685 FunctionAdvertise = TRUE; 00686 for(j = 2; j < len; j++) 00687 { 00688 switch(argvW[i][j]) 00689 { 00690 case 'U': 00691 case 'u': 00692 AdvertiseMode = ADVERTISEFLAGS_USERASSIGN; 00693 break; 00694 case 'M': 00695 case 'm': 00696 AdvertiseMode = ADVERTISEFLAGS_MACHINEASSIGN; 00697 break; 00698 default: 00699 fprintf(stderr, "Unknown option \"%c\" in Advertise mode\n", argvW[i][j]); 00700 break; 00701 } 00702 } 00703 i++; 00704 if(i >= argc) 00705 ShowUsage(1); 00706 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i])); 00707 PackageName = argvW[i]; 00708 } 00709 else if(msi_strequal(argvW[i], "u")) 00710 { 00711 FunctionAdvertise = TRUE; 00712 AdvertiseMode = ADVERTISEFLAGS_USERASSIGN; 00713 i++; 00714 if(i >= argc) 00715 ShowUsage(1); 00716 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i])); 00717 PackageName = argvW[i]; 00718 } 00719 else if(msi_strequal(argvW[i], "m")) 00720 { 00721 FunctionAdvertise = TRUE; 00722 AdvertiseMode = ADVERTISEFLAGS_MACHINEASSIGN; 00723 i++; 00724 if(i >= argc) 00725 ShowUsage(1); 00726 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i])); 00727 PackageName = argvW[i]; 00728 } 00729 else if(msi_option_equal(argvW[i], "t")) 00730 { 00731 i++; 00732 if(i >= argc) 00733 ShowUsage(1); 00734 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i])); 00735 StringListAppend(&transform_list, argvW[i]); 00736 } 00737 else if(msi_option_equal(argvW[i], "g")) 00738 { 00739 i++; 00740 if(i >= argc) 00741 ShowUsage(1); 00742 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i])); 00743 Language = msi_atou(argvW[i]); 00744 } 00745 else if(msi_option_prefix(argvW[i], "l")) 00746 { 00747 int j; 00748 int len = lstrlenW(argvW[i]); 00749 for(j = 2; j < len; j++) 00750 { 00751 switch(argvW[i][j]) 00752 { 00753 case 'I': 00754 case 'i': 00755 LogMode |= INSTALLLOGMODE_INFO; 00756 break; 00757 case 'W': 00758 case 'w': 00759 LogMode |= INSTALLLOGMODE_WARNING; 00760 break; 00761 case 'E': 00762 case 'e': 00763 LogMode |= INSTALLLOGMODE_ERROR; 00764 break; 00765 case 'A': 00766 case 'a': 00767 LogMode |= INSTALLLOGMODE_ACTIONSTART; 00768 break; 00769 case 'R': 00770 case 'r': 00771 LogMode |= INSTALLLOGMODE_ACTIONDATA; 00772 break; 00773 case 'U': 00774 case 'u': 00775 LogMode |= INSTALLLOGMODE_USER; 00776 break; 00777 case 'C': 00778 case 'c': 00779 LogMode |= INSTALLLOGMODE_COMMONDATA; 00780 break; 00781 case 'M': 00782 case 'm': 00783 LogMode |= INSTALLLOGMODE_FATALEXIT; 00784 break; 00785 case 'O': 00786 case 'o': 00787 LogMode |= INSTALLLOGMODE_OUTOFDISKSPACE; 00788 break; 00789 case 'P': 00790 case 'p': 00791 LogMode |= INSTALLLOGMODE_PROPERTYDUMP; 00792 break; 00793 case 'V': 00794 case 'v': 00795 LogMode |= INSTALLLOGMODE_VERBOSE; 00796 break; 00797 case '*': 00798 LogMode = INSTALLLOGMODE_FATALEXIT | 00799 INSTALLLOGMODE_ERROR | 00800 INSTALLLOGMODE_WARNING | 00801 INSTALLLOGMODE_USER | 00802 INSTALLLOGMODE_INFO | 00803 INSTALLLOGMODE_RESOLVESOURCE | 00804 INSTALLLOGMODE_OUTOFDISKSPACE | 00805 INSTALLLOGMODE_ACTIONSTART | 00806 INSTALLLOGMODE_ACTIONDATA | 00807 INSTALLLOGMODE_COMMONDATA | 00808 INSTALLLOGMODE_PROPERTYDUMP | 00809 INSTALLLOGMODE_PROGRESS | 00810 INSTALLLOGMODE_INITIALIZE | 00811 INSTALLLOGMODE_TERMINATE | 00812 INSTALLLOGMODE_SHOWDIALOG; 00813 break; 00814 case '+': 00815 LogAttributes |= INSTALLLOGATTRIBUTES_APPEND; 00816 break; 00817 case '!': 00818 LogAttributes |= INSTALLLOGATTRIBUTES_FLUSHEACHLINE; 00819 break; 00820 default: 00821 break; 00822 } 00823 } 00824 i++; 00825 if(i >= argc) 00826 ShowUsage(1); 00827 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i])); 00828 LogFileName = argvW[i]; 00829 if(MsiEnableLogW(LogMode, LogFileName, LogAttributes) != ERROR_SUCCESS) 00830 { 00831 fprintf(stderr, "Logging in %s (0x%08x, %u) failed\n", 00832 wine_dbgstr_w(LogFileName), LogMode, LogAttributes); 00833 ExitProcess(1); 00834 } 00835 } 00836 else if(msi_option_equal(argvW[i], "p")) 00837 { 00838 FunctionPatch = TRUE; 00839 i++; 00840 if(i >= argc) 00841 ShowUsage(1); 00842 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i])); 00843 PatchFileName = argvW[i]; 00844 } 00845 else if(msi_option_prefix(argvW[i], "q")) 00846 { 00847 if(lstrlenW(argvW[i]) == 2 || msi_strequal(argvW[i]+2, "n") || 00848 msi_strequal(argvW[i] + 2, "uiet")) 00849 { 00850 InstallUILevel = INSTALLUILEVEL_NONE; 00851 } 00852 else if(msi_strequal(argvW[i]+2, "b")) 00853 { 00854 InstallUILevel = INSTALLUILEVEL_BASIC; 00855 } 00856 else if(msi_strequal(argvW[i]+2, "r")) 00857 { 00858 InstallUILevel = INSTALLUILEVEL_REDUCED; 00859 } 00860 else if(msi_strequal(argvW[i]+2, "f")) 00861 { 00862 InstallUILevel = INSTALLUILEVEL_FULL|INSTALLUILEVEL_ENDDIALOG; 00863 } 00864 else if(msi_strequal(argvW[i]+2, "n+")) 00865 { 00866 InstallUILevel = INSTALLUILEVEL_NONE|INSTALLUILEVEL_ENDDIALOG; 00867 } 00868 else if(msi_strequal(argvW[i]+2, "b+")) 00869 { 00870 InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_ENDDIALOG; 00871 } 00872 else if(msi_strequal(argvW[i]+2, "b-")) 00873 { 00874 InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_PROGRESSONLY; 00875 } 00876 else if(msi_strequal(argvW[i]+2, "b+!")) 00877 { 00878 InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_ENDDIALOG; 00879 WINE_FIXME("Unknown modifier: !\n"); 00880 } 00881 else 00882 { 00883 fprintf(stderr, "Unknown option \"%s\" for UI level\n", 00884 wine_dbgstr_w(argvW[i]+2)); 00885 } 00886 } 00887 else if(msi_option_equal(argvW[i], "y")) 00888 { 00889 FunctionDllRegisterServer = TRUE; 00890 i++; 00891 if(i >= argc) 00892 ShowUsage(1); 00893 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i])); 00894 DllName = argvW[i]; 00895 } 00896 else if(msi_option_equal(argvW[i], "z")) 00897 { 00898 FunctionDllUnregisterServer = TRUE; 00899 i++; 00900 if(i >= argc) 00901 ShowUsage(1); 00902 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i])); 00903 DllName = argvW[i]; 00904 } 00905 else if(msi_option_equal(argvW[i], "help") || msi_option_equal(argvW[i], "?")) 00906 { 00907 ShowUsage(0); 00908 } 00909 else if(msi_option_equal(argvW[i], "m")) 00910 { 00911 FunctionUnknown = TRUE; 00912 WINE_FIXME("Unknown parameter /m\n"); 00913 } 00914 else if(msi_option_equal(argvW[i], "D")) 00915 { 00916 FunctionUnknown = TRUE; 00917 WINE_FIXME("Unknown parameter /D\n"); 00918 } 00919 else if (msi_option_equal(argvW[i], "V")) 00920 { 00921 FunctionServer = TRUE; 00922 } 00923 else 00924 StringListAppend(&property_list, argvW[i]); 00925 } 00926 00927 /* start the GUI */ 00928 MsiSetInternalUI(InstallUILevel, NULL); 00929 00930 Properties = build_properties( property_list ); 00931 00932 if(FunctionInstallAdmin && FunctionPatch) 00933 FunctionInstall = FALSE; 00934 00935 ReturnCode = 1; 00936 if(FunctionInstall) 00937 { 00938 if(IsProductCode(PackageName)) 00939 ReturnCode = MsiConfigureProductExW(PackageName, 0, INSTALLSTATE_DEFAULT, Properties); 00940 else 00941 ReturnCode = MsiInstallProductW(PackageName, Properties); 00942 } 00943 else if(FunctionRepair) 00944 { 00945 if(IsProductCode(PackageName)) 00946 WINE_FIXME("Product code treatment not implemented yet\n"); 00947 else 00948 ReturnCode = MsiReinstallProductW(PackageName, RepairMode); 00949 } 00950 else if(FunctionAdvertise) 00951 { 00952 LPWSTR Transforms = build_transforms( property_list ); 00953 ReturnCode = MsiAdvertiseProductW(PackageName, (LPWSTR) AdvertiseMode, Transforms, Language); 00954 } 00955 else if(FunctionPatch) 00956 { 00957 ReturnCode = MsiApplyPatchW(PatchFileName, PackageName, InstallType, Properties); 00958 } 00959 else if(FunctionDllRegisterServer) 00960 { 00961 ReturnCode = DoDllRegisterServer(DllName); 00962 } 00963 else if(FunctionDllUnregisterServer) 00964 { 00965 ReturnCode = DoDllUnregisterServer(DllName); 00966 } 00967 else if (FunctionRegServer) 00968 { 00969 ReturnCode = DoRegServer(); 00970 } 00971 else if (FunctionUnregServer) 00972 { 00973 WINE_FIXME( "/unregserver not implemented yet, ignoring\n" ); 00974 } 00975 else if (FunctionServer) 00976 { 00977 ReturnCode = DoService(); 00978 } 00979 else if (FunctionUnknown) 00980 { 00981 WINE_FIXME( "Unknown function, ignoring\n" ); 00982 } 00983 else 00984 ShowUsage(1); 00985 00986 return ReturnCode; 00987 } Generated on Thu May 24 2012 04:18:59 for ReactOS by
1.7.6.1
|