reg: Avoid an uninitialized variable warning.
[wine.git] / programs / msiexec / msiexec.c
blob8dcd216380eac40d29b34964f2e08d851a3d1aea
1 /*
2 * msiexec.exe implementation
4 * Copyright 2004 Vincent BĂ©ron
5 * Copyright 2005 Mike McCormack
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define WIN32_LEAN_AND_MEAN
24 #include <windows.h>
25 #include <msi.h>
26 #include <winsvc.h>
27 #include <objbase.h>
28 #include <stdio.h>
30 #include "wine/debug.h"
31 #include "wine/unicode.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(msiexec);
35 typedef HRESULT (WINAPI *DLLREGISTERSERVER)(void);
36 typedef HRESULT (WINAPI *DLLUNREGISTERSERVER)(void);
38 DWORD DoService(void);
40 struct string_list
42 struct string_list *next;
43 WCHAR str[1];
46 static const WCHAR ActionAdmin[] = {
47 'A','C','T','I','O','N','=','A','D','M','I','N',0 };
48 static const WCHAR RemoveAll[] = {
49 'R','E','M','O','V','E','=','A','L','L',0 };
51 static const WCHAR InstallRunOnce[] = {
52 'S','o','f','t','w','a','r','e','\\',
53 'M','i','c','r','o','s','o','f','t','\\',
54 'W','i','n','d','o','w','s','\\',
55 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
56 'I','n','s','t','a','l','l','e','r','\\',
57 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
59 static void ShowUsage(int ExitCode)
61 WCHAR msiexec_version[40];
62 WCHAR filename[MAX_PATH];
63 LPWSTR msi_res;
64 LPWSTR msiexec_help;
65 HMODULE hmsi = GetModuleHandleA("msi.dll");
66 DWORD len;
67 DWORD res;
69 /* MsiGetFileVersion need the full path */
70 *filename = 0;
71 res = GetModuleFileNameW(hmsi, filename, sizeof(filename) / sizeof(filename[0]));
72 if (!res)
73 WINE_ERR("GetModuleFileName failed: %d\n", GetLastError());
75 len = sizeof(msiexec_version) / sizeof(msiexec_version[0]);
76 *msiexec_version = 0;
77 res = MsiGetFileVersionW(filename, msiexec_version, &len, NULL, NULL);
78 if (res)
79 WINE_ERR("MsiGetFileVersion failed with %d\n", res);
81 /* Return the length of the resource.
82 No typo: The LPWSTR parameter must be a LPWSTR * for this mode */
83 len = LoadStringW(hmsi, 10, (LPWSTR) &msi_res, 0);
85 msi_res = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
86 msiexec_help = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) + sizeof(msiexec_version));
87 if (msi_res && msiexec_help) {
88 *msi_res = 0;
89 LoadStringW(hmsi, 10, msi_res, len + 1);
91 sprintfW(msiexec_help, msi_res, msiexec_version);
92 MsiMessageBoxW(0, msiexec_help, NULL, 0, GetUserDefaultLangID(), 0);
94 HeapFree(GetProcessHeap(), 0, msi_res);
95 HeapFree(GetProcessHeap(), 0, msiexec_help);
96 ExitProcess(ExitCode);
99 static BOOL IsProductCode(LPWSTR str)
101 GUID ProductCode;
103 if(lstrlenW(str) != 38)
104 return FALSE;
105 return ( (CLSIDFromString(str, &ProductCode) == NOERROR) );
109 static VOID StringListAppend(struct string_list **list, LPCWSTR str)
111 struct string_list *entry;
113 entry = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(struct string_list, str[lstrlenW(str) + 1]));
114 if(!entry)
116 WINE_ERR("Out of memory!\n");
117 ExitProcess(1);
119 lstrcpyW(entry->str, str);
120 entry->next = NULL;
123 * Ignoring o(n^2) time complexity to add n strings for simplicity,
124 * add the string to the end of the list to preserve the order.
126 while( *list )
127 list = &(*list)->next;
128 *list = entry;
131 static LPWSTR build_properties(struct string_list *property_list)
133 struct string_list *list;
134 LPWSTR ret, p, value;
135 DWORD len;
136 BOOL needs_quote;
138 if(!property_list)
139 return NULL;
141 /* count the space we need */
142 len = 1;
143 for(list = property_list; list; list = list->next)
144 len += lstrlenW(list->str) + 3;
146 ret = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
148 /* add a space before each string, and quote the value */
149 p = ret;
150 for(list = property_list; list; list = list->next)
152 value = strchrW(list->str,'=');
153 if(!value)
154 continue;
155 len = value - list->str;
156 *p++ = ' ';
157 memcpy(p, list->str, len * sizeof(WCHAR));
158 p += len;
159 *p++ = '=';
161 /* check if the value contains spaces and maybe quote it */
162 value++;
163 needs_quote = strchrW(value,' ') ? 1 : 0;
164 if(needs_quote)
165 *p++ = '"';
166 len = lstrlenW(value);
167 memcpy(p, value, len * sizeof(WCHAR));
168 p += len;
169 if(needs_quote)
170 *p++ = '"';
172 *p = 0;
174 WINE_TRACE("properties -> %s\n", wine_dbgstr_w(ret) );
176 return ret;
179 static LPWSTR build_transforms(struct string_list *transform_list)
181 struct string_list *list;
182 LPWSTR ret, p;
183 DWORD len;
185 /* count the space we need */
186 len = 1;
187 for(list = transform_list; list; list = list->next)
188 len += lstrlenW(list->str) + 1;
190 ret = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
192 /* add all the transforms with a semicolon between each one */
193 p = ret;
194 for(list = transform_list; list; list = list->next)
196 len = lstrlenW(list->str);
197 lstrcpynW(p, list->str, len );
198 p += len;
199 if(list->next)
200 *p++ = ';';
202 *p = 0;
204 return ret;
207 static DWORD msi_atou(LPCWSTR str)
209 DWORD ret = 0;
210 while(*str >= '0' && *str <= '9')
212 ret *= 10;
213 ret += (*str - '0');
214 str++;
216 return ret;
219 /* str1 is the same as str2, ignoring case */
220 static BOOL msi_strequal(LPCWSTR str1, LPCSTR str2)
222 DWORD len, ret;
223 LPWSTR strW;
225 len = MultiByteToWideChar( CP_ACP, 0, str2, -1, NULL, 0);
226 if( !len )
227 return FALSE;
228 if( lstrlenW(str1) != (len-1) )
229 return FALSE;
230 strW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len);
231 MultiByteToWideChar( CP_ACP, 0, str2, -1, strW, len);
232 ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str1, len, strW, len);
233 HeapFree(GetProcessHeap(), 0, strW);
234 return (ret == CSTR_EQUAL);
237 /* prefix is hyphen or dash, and str1 is the same as str2, ignoring case */
238 static BOOL msi_option_equal(LPCWSTR str1, LPCSTR str2)
240 if (str1[0] != '/' && str1[0] != '-')
241 return FALSE;
243 /* skip over the hyphen or slash */
244 return msi_strequal(str1 + 1, str2);
247 /* str2 is at the beginning of str1, ignoring case */
248 static BOOL msi_strprefix(LPCWSTR str1, LPCSTR str2)
250 DWORD len, ret;
251 LPWSTR strW;
253 len = MultiByteToWideChar( CP_ACP, 0, str2, -1, NULL, 0);
254 if( !len )
255 return FALSE;
256 if( lstrlenW(str1) < (len-1) )
257 return FALSE;
258 strW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len);
259 MultiByteToWideChar( CP_ACP, 0, str2, -1, strW, len);
260 ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str1, len-1, strW, len-1);
261 HeapFree(GetProcessHeap(), 0, strW);
262 return (ret == CSTR_EQUAL);
265 /* prefix is hyphen or dash, and str2 is at the beginning of str1, ignoring case */
266 static BOOL msi_option_prefix(LPCWSTR str1, LPCSTR str2)
268 if (str1[0] != '/' && str1[0] != '-')
269 return FALSE;
271 /* skip over the hyphen or slash */
272 return msi_strprefix(str1 + 1, str2);
275 static VOID *LoadProc(LPCWSTR DllName, LPCSTR ProcName, HMODULE* DllHandle)
277 VOID* (*proc)(void);
279 *DllHandle = LoadLibraryExW(DllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
280 if(!*DllHandle)
282 fprintf(stderr, "Unable to load dll %s\n", wine_dbgstr_w(DllName));
283 ExitProcess(1);
285 proc = (VOID *) GetProcAddress(*DllHandle, ProcName);
286 if(!proc)
288 fprintf(stderr, "Dll %s does not implement function %s\n",
289 wine_dbgstr_w(DllName), ProcName);
290 FreeLibrary(*DllHandle);
291 ExitProcess(1);
294 return proc;
297 static DWORD DoDllRegisterServer(LPCWSTR DllName)
299 HRESULT hr;
300 DLLREGISTERSERVER pfDllRegisterServer = NULL;
301 HMODULE DllHandle = NULL;
303 pfDllRegisterServer = LoadProc(DllName, "DllRegisterServer", &DllHandle);
305 hr = pfDllRegisterServer();
306 if(FAILED(hr))
308 fprintf(stderr, "Failed to register dll %s\n", wine_dbgstr_w(DllName));
309 return 1;
311 printf("Successfully registered dll %s\n", wine_dbgstr_w(DllName));
312 if(DllHandle)
313 FreeLibrary(DllHandle);
314 return 0;
317 static DWORD DoDllUnregisterServer(LPCWSTR DllName)
319 HRESULT hr;
320 DLLUNREGISTERSERVER pfDllUnregisterServer = NULL;
321 HMODULE DllHandle = NULL;
323 pfDllUnregisterServer = LoadProc(DllName, "DllUnregisterServer", &DllHandle);
325 hr = pfDllUnregisterServer();
326 if(FAILED(hr))
328 fprintf(stderr, "Failed to unregister dll %s\n", wine_dbgstr_w(DllName));
329 return 1;
331 printf("Successfully unregistered dll %s\n", wine_dbgstr_w(DllName));
332 if(DllHandle)
333 FreeLibrary(DllHandle);
334 return 0;
337 static DWORD DoRegServer(void)
339 static const WCHAR msiserverW[] = {'M','S','I','S','e','r','v','e','r',0};
340 static const WCHAR msiexecW[] = {'\\','m','s','i','e','x','e','c',' ','/','V',0};
341 SC_HANDLE scm, service;
342 WCHAR path[MAX_PATH+12];
343 DWORD len, ret = 0;
345 if (!(scm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, SC_MANAGER_CREATE_SERVICE)))
347 fprintf(stderr, "Failed to open the service control manager.\n");
348 return 1;
350 len = GetSystemDirectoryW(path, MAX_PATH);
351 lstrcpyW(path + len, msiexecW);
352 if ((service = CreateServiceW(scm, msiserverW, msiserverW, GENERIC_ALL,
353 SERVICE_WIN32_SHARE_PROCESS, SERVICE_DEMAND_START,
354 SERVICE_ERROR_NORMAL, path, NULL, NULL, NULL, NULL, NULL)))
356 CloseServiceHandle(service);
358 else if (GetLastError() != ERROR_SERVICE_EXISTS)
360 fprintf(stderr, "Failed to create MSI service\n");
361 ret = 1;
363 CloseServiceHandle(scm);
364 return ret;
367 static DWORD DoUnregServer(void)
369 static const WCHAR msiserverW[] = {'M','S','I','S','e','r','v','e','r',0};
370 SC_HANDLE scm, service;
371 DWORD ret = 0;
373 if (!(scm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, SC_MANAGER_CONNECT)))
375 fprintf(stderr, "Failed to open service control manager\n");
376 return 1;
378 if ((service = OpenServiceW(scm, msiserverW, DELETE)))
380 if (!DeleteService(service))
382 fprintf(stderr, "Failed to delete MSI service\n");
383 ret = 1;
385 CloseServiceHandle(service);
387 else if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
389 fprintf(stderr, "Failed to open MSI service\n");
390 ret = 1;
392 CloseServiceHandle(scm);
393 return ret;
396 static INT DoEmbedding( LPWSTR key )
398 printf("Remote custom actions are not supported yet\n");
399 return 1;
403 * state machine to break up the command line properly
406 enum chomp_state
408 CS_WHITESPACE,
409 CS_TOKEN,
410 CS_QUOTE
413 static int chomp( const WCHAR *in, WCHAR *out )
415 enum chomp_state state = CS_TOKEN;
416 const WCHAR *p;
417 int count = 1;
418 BOOL ignore;
420 for (p = in; *p; p++)
422 ignore = TRUE;
423 switch (state)
425 case CS_WHITESPACE:
426 switch (*p)
428 case ' ':
429 break;
430 case '"':
431 state = CS_QUOTE;
432 count++;
433 break;
434 default:
435 count++;
436 ignore = FALSE;
437 state = CS_TOKEN;
439 break;
441 case CS_TOKEN:
442 switch (*p)
444 case '"':
445 state = CS_QUOTE;
446 break;
447 case ' ':
448 state = CS_WHITESPACE;
449 if (out) *out++ = 0;
450 break;
451 default:
452 if (p > in && p[-1] == '"')
454 if (out) *out++ = 0;
455 count++;
457 ignore = FALSE;
459 break;
461 case CS_QUOTE:
462 switch (*p)
464 case '"':
465 state = CS_TOKEN;
466 break;
467 default:
468 ignore = FALSE;
470 break;
472 if (!ignore && out) *out++ = *p;
474 if (out) *out = 0;
475 return count;
478 static void process_args( WCHAR *cmdline, int *pargc, WCHAR ***pargv )
480 WCHAR **argv, *p;
481 int i, count;
483 *pargc = 0;
484 *pargv = NULL;
486 count = chomp( cmdline, NULL );
487 if (!(p = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(cmdline) + count + 1) * sizeof(WCHAR) )))
488 return;
490 count = chomp( cmdline, p );
491 if (!(argv = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(WCHAR *) )))
493 HeapFree( GetProcessHeap(), 0, p );
494 return;
496 for (i = 0; i < count; i++)
498 argv[i] = p;
499 p += lstrlenW( p ) + 1;
501 argv[i] = NULL;
503 *pargc = count;
504 *pargv = argv;
507 static BOOL process_args_from_reg( const WCHAR *ident, int *pargc, WCHAR ***pargv )
509 LONG r;
510 HKEY hkey;
511 DWORD sz = 0, type = 0;
512 WCHAR *buf;
513 BOOL ret = FALSE;
515 r = RegOpenKeyW(HKEY_LOCAL_MACHINE, InstallRunOnce, &hkey);
516 if(r != ERROR_SUCCESS)
517 return FALSE;
518 r = RegQueryValueExW(hkey, ident, 0, &type, 0, &sz);
519 if(r == ERROR_SUCCESS && type == REG_SZ)
521 int len = lstrlenW( *pargv[0] );
522 if (!(buf = HeapAlloc( GetProcessHeap(), 0, sz + (len + 1) * sizeof(WCHAR) )))
524 RegCloseKey( hkey );
525 return FALSE;
527 memcpy( buf, *pargv[0], len * sizeof(WCHAR) );
528 buf[len++] = ' ';
529 r = RegQueryValueExW(hkey, ident, 0, &type, (LPBYTE)(buf + len), &sz);
530 if( r == ERROR_SUCCESS )
532 process_args(buf, pargc, pargv);
533 ret = TRUE;
535 HeapFree(GetProcessHeap(), 0, buf);
537 RegCloseKey(hkey);
538 return ret;
541 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
543 int i;
544 BOOL FunctionInstall = FALSE;
545 BOOL FunctionInstallAdmin = FALSE;
546 BOOL FunctionRepair = FALSE;
547 BOOL FunctionAdvertise = FALSE;
548 BOOL FunctionPatch = FALSE;
549 BOOL FunctionDllRegisterServer = FALSE;
550 BOOL FunctionDllUnregisterServer = FALSE;
551 BOOL FunctionRegServer = FALSE;
552 BOOL FunctionUnregServer = FALSE;
553 BOOL FunctionServer = FALSE;
554 BOOL FunctionUnknown = FALSE;
556 LPWSTR PackageName = NULL;
557 LPWSTR Properties = NULL;
558 struct string_list *property_list = NULL;
560 DWORD RepairMode = 0;
562 DWORD_PTR AdvertiseMode = 0;
563 struct string_list *transform_list = NULL;
564 LANGID Language = 0;
566 DWORD LogMode = 0;
567 LPWSTR LogFileName = NULL;
568 DWORD LogAttributes = 0;
570 LPWSTR PatchFileName = NULL;
571 INSTALLTYPE InstallType = INSTALLTYPE_DEFAULT;
573 INSTALLUILEVEL InstallUILevel = INSTALLUILEVEL_FULL;
575 LPWSTR DllName = NULL;
576 DWORD ReturnCode;
577 int argc;
578 LPWSTR *argvW = NULL;
580 /* parse the command line */
581 process_args( GetCommandLineW(), &argc, &argvW );
584 * If the args begin with /@ IDENT then we need to load the real
585 * command line out of the RunOnceEntries key in the registry.
586 * We do that before starting to process the real commandline,
587 * then overwrite the commandline again.
589 if(argc>1 && msi_option_equal(argvW[1], "@"))
591 if(!process_args_from_reg( argvW[2], &argc, &argvW ))
592 return 1;
595 if (argc == 3 && msi_option_equal(argvW[1], "Embedding"))
596 return DoEmbedding( argvW[2] );
598 for(i = 1; i < argc; i++)
600 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
602 if (msi_option_equal(argvW[i], "regserver"))
604 FunctionRegServer = TRUE;
606 else if (msi_option_equal(argvW[i], "unregserver") || msi_option_equal(argvW[i], "unregister")
607 || msi_option_equal(argvW[i], "unreg"))
609 FunctionUnregServer = TRUE;
611 else if(msi_option_prefix(argvW[i], "i") || msi_option_prefix(argvW[i], "package"))
613 LPWSTR argvWi = argvW[i];
614 int argLen = (msi_option_prefix(argvW[i], "i") ? 2 : 8);
615 FunctionInstall = TRUE;
616 if(lstrlenW(argvW[i]) > argLen)
617 argvWi += argLen;
618 else
620 i++;
621 if(i >= argc)
622 ShowUsage(1);
623 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
624 argvWi = argvW[i];
626 PackageName = argvWi;
628 else if(msi_option_equal(argvW[i], "a"))
630 FunctionInstall = TRUE;
631 FunctionInstallAdmin = TRUE;
632 InstallType = INSTALLTYPE_NETWORK_IMAGE;
633 i++;
634 if(i >= argc)
635 ShowUsage(1);
636 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
637 PackageName = argvW[i];
638 StringListAppend(&property_list, ActionAdmin);
639 WINE_FIXME("Administrative installs are not currently supported\n");
641 else if(msi_option_prefix(argvW[i], "f"))
643 int j;
644 int len = lstrlenW(argvW[i]);
645 FunctionRepair = TRUE;
646 for(j = 2; j < len; j++)
648 switch(argvW[i][j])
650 case 'P':
651 case 'p':
652 RepairMode |= REINSTALLMODE_FILEMISSING;
653 break;
654 case 'O':
655 case 'o':
656 RepairMode |= REINSTALLMODE_FILEOLDERVERSION;
657 break;
658 case 'E':
659 case 'e':
660 RepairMode |= REINSTALLMODE_FILEEQUALVERSION;
661 break;
662 case 'D':
663 case 'd':
664 RepairMode |= REINSTALLMODE_FILEEXACT;
665 break;
666 case 'C':
667 case 'c':
668 RepairMode |= REINSTALLMODE_FILEVERIFY;
669 break;
670 case 'A':
671 case 'a':
672 RepairMode |= REINSTALLMODE_FILEREPLACE;
673 break;
674 case 'U':
675 case 'u':
676 RepairMode |= REINSTALLMODE_USERDATA;
677 break;
678 case 'M':
679 case 'm':
680 RepairMode |= REINSTALLMODE_MACHINEDATA;
681 break;
682 case 'S':
683 case 's':
684 RepairMode |= REINSTALLMODE_SHORTCUT;
685 break;
686 case 'V':
687 case 'v':
688 RepairMode |= REINSTALLMODE_PACKAGE;
689 break;
690 default:
691 fprintf(stderr, "Unknown option \"%c\" in Repair mode\n", argvW[i][j]);
692 break;
695 if(len == 2)
697 RepairMode = REINSTALLMODE_FILEMISSING |
698 REINSTALLMODE_FILEEQUALVERSION |
699 REINSTALLMODE_FILEVERIFY |
700 REINSTALLMODE_MACHINEDATA |
701 REINSTALLMODE_SHORTCUT;
703 i++;
704 if(i >= argc)
705 ShowUsage(1);
706 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
707 PackageName = argvW[i];
709 else if(msi_option_prefix(argvW[i], "x") || msi_option_equal(argvW[i], "uninstall"))
711 FunctionInstall = TRUE;
712 if(msi_option_prefix(argvW[i], "x")) PackageName = argvW[i]+2;
713 if(!PackageName || !PackageName[0])
715 i++;
716 if (i >= argc)
717 ShowUsage(1);
718 PackageName = argvW[i];
720 WINE_TRACE("PackageName = %s\n", wine_dbgstr_w(PackageName));
721 StringListAppend(&property_list, RemoveAll);
723 else if(msi_option_prefix(argvW[i], "j"))
725 int j;
726 int len = lstrlenW(argvW[i]);
727 FunctionAdvertise = TRUE;
728 for(j = 2; j < len; j++)
730 switch(argvW[i][j])
732 case 'U':
733 case 'u':
734 AdvertiseMode = ADVERTISEFLAGS_USERASSIGN;
735 break;
736 case 'M':
737 case 'm':
738 AdvertiseMode = ADVERTISEFLAGS_MACHINEASSIGN;
739 break;
740 default:
741 fprintf(stderr, "Unknown option \"%c\" in Advertise mode\n", argvW[i][j]);
742 break;
745 i++;
746 if(i >= argc)
747 ShowUsage(1);
748 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
749 PackageName = argvW[i];
751 else if(msi_strequal(argvW[i], "u"))
753 FunctionAdvertise = TRUE;
754 AdvertiseMode = ADVERTISEFLAGS_USERASSIGN;
755 i++;
756 if(i >= argc)
757 ShowUsage(1);
758 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
759 PackageName = argvW[i];
761 else if(msi_strequal(argvW[i], "m"))
763 FunctionAdvertise = TRUE;
764 AdvertiseMode = ADVERTISEFLAGS_MACHINEASSIGN;
765 i++;
766 if(i >= argc)
767 ShowUsage(1);
768 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
769 PackageName = argvW[i];
771 else if(msi_option_equal(argvW[i], "t"))
773 i++;
774 if(i >= argc)
775 ShowUsage(1);
776 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
777 StringListAppend(&transform_list, argvW[i]);
779 else if(msi_option_equal(argvW[i], "g"))
781 i++;
782 if(i >= argc)
783 ShowUsage(1);
784 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
785 Language = msi_atou(argvW[i]);
787 else if(msi_option_prefix(argvW[i], "l"))
789 int j;
790 int len = lstrlenW(argvW[i]);
791 for(j = 2; j < len; j++)
793 switch(argvW[i][j])
795 case 'I':
796 case 'i':
797 LogMode |= INSTALLLOGMODE_INFO;
798 break;
799 case 'W':
800 case 'w':
801 LogMode |= INSTALLLOGMODE_WARNING;
802 break;
803 case 'E':
804 case 'e':
805 LogMode |= INSTALLLOGMODE_ERROR;
806 break;
807 case 'A':
808 case 'a':
809 LogMode |= INSTALLLOGMODE_ACTIONSTART;
810 break;
811 case 'R':
812 case 'r':
813 LogMode |= INSTALLLOGMODE_ACTIONDATA;
814 break;
815 case 'U':
816 case 'u':
817 LogMode |= INSTALLLOGMODE_USER;
818 break;
819 case 'C':
820 case 'c':
821 LogMode |= INSTALLLOGMODE_COMMONDATA;
822 break;
823 case 'M':
824 case 'm':
825 LogMode |= INSTALLLOGMODE_FATALEXIT;
826 break;
827 case 'O':
828 case 'o':
829 LogMode |= INSTALLLOGMODE_OUTOFDISKSPACE;
830 break;
831 case 'P':
832 case 'p':
833 LogMode |= INSTALLLOGMODE_PROPERTYDUMP;
834 break;
835 case 'V':
836 case 'v':
837 LogMode |= INSTALLLOGMODE_VERBOSE;
838 break;
839 case '*':
840 LogMode = INSTALLLOGMODE_FATALEXIT |
841 INSTALLLOGMODE_ERROR |
842 INSTALLLOGMODE_WARNING |
843 INSTALLLOGMODE_USER |
844 INSTALLLOGMODE_INFO |
845 INSTALLLOGMODE_RESOLVESOURCE |
846 INSTALLLOGMODE_OUTOFDISKSPACE |
847 INSTALLLOGMODE_ACTIONSTART |
848 INSTALLLOGMODE_ACTIONDATA |
849 INSTALLLOGMODE_COMMONDATA |
850 INSTALLLOGMODE_PROPERTYDUMP |
851 INSTALLLOGMODE_PROGRESS |
852 INSTALLLOGMODE_INITIALIZE |
853 INSTALLLOGMODE_TERMINATE |
854 INSTALLLOGMODE_SHOWDIALOG;
855 break;
856 case '+':
857 LogAttributes |= INSTALLLOGATTRIBUTES_APPEND;
858 break;
859 case '!':
860 LogAttributes |= INSTALLLOGATTRIBUTES_FLUSHEACHLINE;
861 break;
862 default:
863 break;
866 i++;
867 if(i >= argc)
868 ShowUsage(1);
869 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
870 LogFileName = argvW[i];
871 if(MsiEnableLogW(LogMode, LogFileName, LogAttributes) != ERROR_SUCCESS)
873 fprintf(stderr, "Logging in %s (0x%08x, %u) failed\n",
874 wine_dbgstr_w(LogFileName), LogMode, LogAttributes);
875 ExitProcess(1);
878 else if(msi_option_equal(argvW[i], "p") || msi_option_equal(argvW[i], "update"))
880 FunctionPatch = TRUE;
881 i++;
882 if(i >= argc)
883 ShowUsage(1);
884 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
885 PatchFileName = argvW[i];
887 else if(msi_option_prefix(argvW[i], "q"))
889 if(lstrlenW(argvW[i]) == 2 || msi_strequal(argvW[i]+2, "n") ||
890 msi_strequal(argvW[i] + 2, "uiet"))
892 InstallUILevel = INSTALLUILEVEL_NONE;
894 else if(msi_strequal(argvW[i]+2, "r"))
896 InstallUILevel = INSTALLUILEVEL_REDUCED;
898 else if(msi_strequal(argvW[i]+2, "f"))
900 InstallUILevel = INSTALLUILEVEL_FULL|INSTALLUILEVEL_ENDDIALOG;
902 else if(msi_strequal(argvW[i]+2, "n+"))
904 InstallUILevel = INSTALLUILEVEL_NONE|INSTALLUILEVEL_ENDDIALOG;
906 else if(msi_strprefix(argvW[i]+2, "b"))
908 const WCHAR *ptr = argvW[i] + 3;
910 InstallUILevel = INSTALLUILEVEL_BASIC;
912 while (*ptr)
914 if (msi_strprefix(ptr, "+"))
915 InstallUILevel |= INSTALLUILEVEL_ENDDIALOG;
916 if (msi_strprefix(ptr, "-"))
917 InstallUILevel |= INSTALLUILEVEL_PROGRESSONLY;
918 if (msi_strprefix(ptr, "!"))
920 WINE_FIXME("Unhandled modifier: !\n");
921 InstallUILevel |= INSTALLUILEVEL_HIDECANCEL;
923 ptr++;
926 else
928 fprintf(stderr, "Unknown option \"%s\" for UI level\n",
929 wine_dbgstr_w(argvW[i]+2));
932 else if(msi_option_equal(argvW[i], "passive"))
934 static const WCHAR rebootpromptW[] =
935 {'R','E','B','O','O','T','P','R','O','M','P','T','=','"','S','"',0};
937 InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_PROGRESSONLY|INSTALLUILEVEL_HIDECANCEL;
938 StringListAppend(&property_list, rebootpromptW);
940 else if(msi_option_equal(argvW[i], "y"))
942 FunctionDllRegisterServer = TRUE;
943 i++;
944 if(i >= argc)
945 ShowUsage(1);
946 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
947 DllName = argvW[i];
949 else if(msi_option_equal(argvW[i], "z"))
951 FunctionDllUnregisterServer = TRUE;
952 i++;
953 if(i >= argc)
954 ShowUsage(1);
955 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
956 DllName = argvW[i];
958 else if(msi_option_equal(argvW[i], "help") || msi_option_equal(argvW[i], "?"))
960 ShowUsage(0);
962 else if(msi_option_equal(argvW[i], "m"))
964 FunctionUnknown = TRUE;
965 WINE_FIXME("Unknown parameter /m\n");
967 else if(msi_option_equal(argvW[i], "D"))
969 FunctionUnknown = TRUE;
970 WINE_FIXME("Unknown parameter /D\n");
972 else if (msi_option_equal(argvW[i], "V"))
974 FunctionServer = TRUE;
976 else
977 StringListAppend(&property_list, argvW[i]);
980 /* start the GUI */
981 MsiSetInternalUI(InstallUILevel, NULL);
983 Properties = build_properties( property_list );
985 if(FunctionInstallAdmin && FunctionPatch)
986 FunctionInstall = FALSE;
988 ReturnCode = 1;
989 if(FunctionInstall)
991 if(IsProductCode(PackageName))
992 ReturnCode = MsiConfigureProductExW(PackageName, 0, INSTALLSTATE_DEFAULT, Properties);
993 else
994 ReturnCode = MsiInstallProductW(PackageName, Properties);
996 else if(FunctionRepair)
998 if(IsProductCode(PackageName))
999 WINE_FIXME("Product code treatment not implemented yet\n");
1000 else
1001 ReturnCode = MsiReinstallProductW(PackageName, RepairMode);
1003 else if(FunctionAdvertise)
1005 LPWSTR Transforms = build_transforms( property_list );
1006 ReturnCode = MsiAdvertiseProductW(PackageName, (LPWSTR) AdvertiseMode, Transforms, Language);
1008 else if(FunctionPatch)
1010 ReturnCode = MsiApplyPatchW(PatchFileName, PackageName, InstallType, Properties);
1012 else if(FunctionDllRegisterServer)
1014 ReturnCode = DoDllRegisterServer(DllName);
1016 else if(FunctionDllUnregisterServer)
1018 ReturnCode = DoDllUnregisterServer(DllName);
1020 else if (FunctionRegServer)
1022 ReturnCode = DoRegServer();
1024 else if (FunctionUnregServer)
1026 ReturnCode = DoUnregServer();
1028 else if (FunctionServer)
1030 ReturnCode = DoService();
1032 else if (FunctionUnknown)
1034 WINE_FIXME( "Unknown function, ignoring\n" );
1036 else
1037 ShowUsage(1);
1039 return ReturnCode;