configure: Make the font warning more explicit about what package is missing.
[wine/multimedia.git] / programs / msiexec / msiexec.c
blob809b38fb58b419a7345af66873c8133ae1fdbb2f
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 <objbase.h>
27 #include <stdio.h>
29 #include "wine/debug.h"
30 #include "wine/unicode.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(msiexec);
34 typedef HRESULT (WINAPI *DLLREGISTERSERVER)(void);
35 typedef HRESULT (WINAPI *DLLUNREGISTERSERVER)(void);
37 struct string_list
39 struct string_list *next;
40 WCHAR str[1];
43 static const char UsageStr[] =
44 "Usage:\n"
45 " Install a product:\n"
46 " msiexec {package|productcode} [property]\n"
47 " msiexec /i {package|productcode} [property]\n"
48 " msiexec /a package [property]\n"
49 " Repair an installation:\n"
50 " msiexec /f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n"
51 " Uninstall a product:\n"
52 " msiexec /x {package|productcode} [property]\n"
53 " Advertise a product:\n"
54 " msiexec /j[u|m] package [/t transform] [/g languageid]\n"
55 " msiexec {u|m} package [/t transform] [/g languageid]\n"
56 " Apply a patch:\n"
57 " msiexec /p patchpackage [property]\n"
58 " msiexec /p patchpackage /a package [property]\n"
59 " Modifiers for above operations:\n"
60 " msiexec /l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n"
61 " msiexec /q{|n|b|r|f|n+|b+|b-}\n"
62 " Register a module:\n"
63 " msiexec /y module\n"
64 " Unregister a module:\n"
65 " msiexec /z module\n"
66 " Display usage and copyright:\n"
67 " msiexec {/h|/?}\n"
68 "NOTE: Product code on commandline unimplemented as of yet\n"
69 "\n"
70 "Copyright 2004 Vincent Béron\n";
72 static const WCHAR ActionAdmin[] = {
73 'A','C','T','I','O','N','=','A','D','M','I','N',0 };
74 static const WCHAR RemoveAll[] = {
75 'R','E','M','O','V','E','=','A','L','L',0 };
77 static const WCHAR InstallRunOnce[] = {
78 'S','o','f','t','w','a','r','e','\\',
79 'M','i','c','r','o','s','o','f','t','\\',
80 'W','i','n','d','o','w','s','\\',
81 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
82 'I','n','s','t','a','l','l','e','r','\\',
83 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
85 static void ShowUsage(int ExitCode)
87 printf(UsageStr);
88 ExitProcess(ExitCode);
91 static BOOL IsProductCode(LPWSTR str)
93 GUID ProductCode;
95 if(lstrlenW(str) != 38)
96 return FALSE;
97 return ( (CLSIDFromString(str, &ProductCode) == NOERROR) );
101 static VOID StringListAppend(struct string_list **list, LPCWSTR str)
103 struct string_list *entry;
104 DWORD size;
106 size = sizeof *entry + lstrlenW(str) * sizeof (WCHAR);
107 entry = HeapAlloc(GetProcessHeap(), 0, size);
108 if(!entry)
110 WINE_ERR("Out of memory!\n");
111 ExitProcess(1);
113 lstrcpyW(entry->str, str);
114 entry->next = NULL;
117 * Ignoring o(n^2) time complexity to add n strings for simplicity,
118 * add the string to the end of the list to preserve the order.
120 while( *list )
121 list = &(*list)->next;
122 *list = entry;
125 static LPWSTR build_properties(struct string_list *property_list)
127 struct string_list *list;
128 LPWSTR ret, p, value;
129 DWORD len;
130 BOOL needs_quote;
132 if(!property_list)
133 return NULL;
135 /* count the space we need */
136 len = 1;
137 for(list = property_list; list; list = list->next)
138 len += lstrlenW(list->str) + 3;
140 ret = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
142 /* add a space before each string, and quote the value */
143 p = ret;
144 for(list = property_list; list; list = list->next)
146 value = strchrW(list->str,'=');
147 if(!value)
148 continue;
149 len = value - list->str;
150 *p++ = ' ';
151 memcpy(p, list->str, len * sizeof(WCHAR));
152 p += len;
153 *p++ = '=';
155 /* check if the value contains spaces and maybe quote it */
156 value++;
157 needs_quote = strchrW(value,' ') ? 1 : 0;
158 if(needs_quote)
159 *p++ = '"';
160 len = lstrlenW(value);
161 memcpy(p, value, len * sizeof(WCHAR));
162 p += len;
163 if(needs_quote)
164 *p++ = '"';
166 *p = 0;
168 WINE_TRACE("properties -> %s\n", wine_dbgstr_w(ret) );
170 return ret;
173 static LPWSTR build_transforms(struct string_list *transform_list)
175 struct string_list *list;
176 LPWSTR ret, p;
177 DWORD len;
179 /* count the space we need */
180 len = 1;
181 for(list = transform_list; list; list = list->next)
182 len += lstrlenW(list->str) + 1;
184 ret = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
186 /* add all the transforms with a semicolon between each one */
187 p = ret;
188 for(list = transform_list; list; list = list->next)
190 len = lstrlenW(list->str);
191 lstrcpynW(p, list->str, len );
192 p += len;
193 if(list->next)
194 *p++ = ';';
196 *p = 0;
198 return ret;
201 static DWORD msi_atou(LPCWSTR str)
203 DWORD ret = 0;
204 while(*str >= '0' && *str <= '9')
206 ret *= 10;
207 ret += (*str - '0');
208 str++;
210 return 0;
213 static LPWSTR msi_strdup(LPCWSTR str)
215 DWORD len = lstrlenW(str)+1;
216 LPWSTR ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len);
217 lstrcpyW(ret, str);
218 return ret;
221 /* str1 is the same as str2, ignoring case */
222 static BOOL msi_strequal(LPCWSTR str1, LPCSTR str2)
224 DWORD len, ret;
225 LPWSTR strW;
227 len = MultiByteToWideChar( CP_ACP, 0, str2, -1, NULL, 0);
228 if( !len )
229 return TRUE;
230 if( lstrlenW(str1) != (len-1) )
231 return TRUE;
232 strW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len);
233 MultiByteToWideChar( CP_ACP, 0, str2, -1, strW, len);
234 ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str1, len, strW, len);
235 HeapFree(GetProcessHeap(), 0, strW);
236 return (ret != CSTR_EQUAL);
239 /* str2 is at the beginning of str1, ignoring case */
240 static BOOL msi_strprefix(LPCWSTR str1, LPCSTR str2)
242 DWORD len, ret;
243 LPWSTR strW;
245 len = MultiByteToWideChar( CP_ACP, 0, str2, -1, NULL, 0);
246 if( !len )
247 return TRUE;
248 if( lstrlenW(str1) < (len-1) )
249 return TRUE;
250 strW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len);
251 MultiByteToWideChar( CP_ACP, 0, str2, -1, strW, len);
252 ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str1, len-1, strW, len-1);
253 HeapFree(GetProcessHeap(), 0, strW);
254 return (ret != CSTR_EQUAL);
257 static VOID *LoadProc(LPCWSTR DllName, LPCSTR ProcName, HMODULE* DllHandle)
259 VOID* (*proc)(void);
261 *DllHandle = LoadLibraryExW(DllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
262 if(!*DllHandle)
264 fprintf(stderr, "Unable to load dll %s\n", wine_dbgstr_w(DllName));
265 ExitProcess(1);
267 proc = (VOID *) GetProcAddress(*DllHandle, ProcName);
268 if(!proc)
270 fprintf(stderr, "Dll %s does not implement function %s\n",
271 wine_dbgstr_w(DllName), ProcName);
272 FreeLibrary(*DllHandle);
273 ExitProcess(1);
276 return proc;
279 static DWORD DoDllRegisterServer(LPCWSTR DllName)
281 HRESULT hr;
282 DLLREGISTERSERVER pfDllRegisterServer = NULL;
283 HMODULE DllHandle = NULL;
285 pfDllRegisterServer = LoadProc(DllName, "DllRegisterServer", &DllHandle);
287 hr = pfDllRegisterServer();
288 if(FAILED(hr))
290 fprintf(stderr, "Failed to register dll %s\n", wine_dbgstr_w(DllName));
291 return 1;
293 printf("Successfully registered dll %s\n", wine_dbgstr_w(DllName));
294 if(DllHandle)
295 FreeLibrary(DllHandle);
296 return 0;
299 static DWORD DoDllUnregisterServer(LPCWSTR DllName)
301 HRESULT hr;
302 DLLUNREGISTERSERVER pfDllUnregisterServer = NULL;
303 HMODULE DllHandle = NULL;
305 pfDllUnregisterServer = LoadProc(DllName, "DllUnregisterServer", &DllHandle);
307 hr = pfDllUnregisterServer();
308 if(FAILED(hr))
310 fprintf(stderr, "Failed to unregister dll %s\n", wine_dbgstr_w(DllName));
311 return 1;
313 printf("Successfully unregistered dll %s\n", wine_dbgstr_w(DllName));
314 if(DllHandle)
315 FreeLibrary(DllHandle);
316 return 0;
320 * state machine to break up the command line properly
323 enum chomp_state
325 cs_whitespace,
326 cs_token,
327 cs_quote
330 static int chomp( WCHAR *str )
332 enum chomp_state state = cs_whitespace;
333 WCHAR *p, *out;
334 int count = 0, ignore;
336 for( p = str, out = str; *p; p++ )
338 ignore = 1;
339 switch( state )
341 case cs_whitespace:
342 switch( *p )
344 case ' ':
345 break;
346 case '"':
347 state = cs_quote;
348 count++;
349 break;
350 default:
351 count++;
352 ignore = 0;
353 state = cs_token;
355 break;
357 case cs_token:
358 switch( *p )
360 case '"':
361 state = cs_quote;
362 break;
363 case ' ':
364 state = cs_whitespace;
365 *out++ = 0;
366 break;
367 default:
368 ignore = 0;
370 break;
372 case cs_quote:
373 switch( *p )
375 case '"':
376 state = cs_token;
377 break;
378 default:
379 ignore = 0;
381 break;
383 if( !ignore )
384 *out++ = *p;
387 *out = 0;
389 return count;
392 static void process_args( WCHAR *cmdline, int *pargc, WCHAR ***pargv )
394 WCHAR **argv, *p = msi_strdup(cmdline);
395 int i, n;
397 n = chomp( p );
398 argv = HeapAlloc(GetProcessHeap(), 0, sizeof (WCHAR*)*(n+1));
399 for( i=0; i<n; i++ )
401 argv[i] = p;
402 p += lstrlenW(p) + 1;
404 argv[i] = NULL;
406 *pargc = n;
407 *pargv = argv;
410 static BOOL process_args_from_reg( LPWSTR ident, int *pargc, WCHAR ***pargv )
412 LONG r;
413 HKEY hkey = 0, hkeyArgs = 0;
414 DWORD sz = 0, type = 0;
415 LPWSTR buf = NULL;
416 BOOL ret = FALSE;
418 r = RegOpenKeyW(HKEY_LOCAL_MACHINE, InstallRunOnce, &hkey);
419 if(r != ERROR_SUCCESS)
420 return FALSE;
421 r = RegQueryValueExW(hkey, ident, 0, &type, 0, &sz);
422 if(r == ERROR_SUCCESS && type == REG_SZ)
424 buf = HeapAlloc(GetProcessHeap(), 0, sz);
425 r = RegQueryValueExW(hkey, ident, 0, &type, (LPBYTE)buf, &sz);
426 if( r == ERROR_SUCCESS )
428 process_args(buf, pargc, pargv);
429 ret = TRUE;
432 RegCloseKey(hkeyArgs);
433 return ret;
436 int main(int argc, char **argv)
438 int i;
439 BOOL FunctionInstall = FALSE;
440 BOOL FunctionInstallAdmin = FALSE;
441 BOOL FunctionRepair = FALSE;
442 BOOL FunctionAdvertise = FALSE;
443 BOOL FunctionPatch = FALSE;
444 BOOL FunctionDllRegisterServer = FALSE;
445 BOOL FunctionDllUnregisterServer = FALSE;
446 BOOL FunctionRegServer = FALSE;
447 BOOL FunctionUnregServer = FALSE;
448 BOOL FunctionUnknown = FALSE;
450 LPWSTR PackageName = NULL;
451 LPWSTR Properties = NULL;
452 struct string_list *property_list = NULL;
454 DWORD RepairMode = 0;
456 DWORD_PTR AdvertiseMode = 0;
457 struct string_list *transform_list = NULL;
458 LANGID Language = 0;
460 DWORD LogMode = 0;
461 LPWSTR LogFileName = NULL;
462 DWORD LogAttributes = 0;
464 LPWSTR PatchFileName = NULL;
465 INSTALLTYPE InstallType = INSTALLTYPE_DEFAULT;
467 INSTALLUILEVEL InstallUILevel = INSTALLUILEVEL_FULL;
469 LPWSTR DllName = NULL;
470 DWORD ReturnCode;
471 LPWSTR *argvW = NULL;
473 /* overwrite the command line */
474 process_args( GetCommandLineW(), &argc, &argvW );
477 * If the args begin with /@ IDENT then we need to load the real
478 * command line out of the RunOnceEntries key in the registry.
479 * We do that before starting to process the real commandline,
480 * then overwrite the commandline again.
482 if(!msi_strequal(argvW[1], "/@"))
484 if(!process_args_from_reg( argvW[2], &argc, &argvW ))
485 return 1;
488 for(i = 1; i < argc; i++)
490 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
492 if (!msi_strequal(argvW[i], "/regserver"))
494 FunctionRegServer = TRUE;
496 else if (!msi_strequal(argvW[i], "/unregserver") || !msi_strequal(argvW[i], "/unregister"))
498 FunctionUnregServer = TRUE;
500 else if(!msi_strprefix(argvW[i], "/i"))
502 LPWSTR argvWi = argvW[i];
503 FunctionInstall = TRUE;
504 if(lstrlenW(argvWi) > 2)
505 argvWi += 2;
506 else
508 i++;
509 if(i >= argc)
510 ShowUsage(1);
511 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
512 argvWi = argvW[i];
514 PackageName = argvWi;
516 else if(!msi_strequal(argvW[i], "/a"))
518 FunctionInstall = TRUE;
519 FunctionInstallAdmin = TRUE;
520 InstallType = INSTALLTYPE_NETWORK_IMAGE;
521 i++;
522 if(i >= argc)
523 ShowUsage(1);
524 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
525 PackageName = argvW[i];
526 StringListAppend(&property_list, ActionAdmin);
528 else if(!msi_strprefix(argvW[i], "/f"))
530 int j;
531 int len = lstrlenW(argvW[i]);
532 FunctionRepair = TRUE;
533 for(j = 2; j < len; j++)
535 switch(argvW[i][j])
537 case 'P':
538 case 'p':
539 RepairMode |= REINSTALLMODE_FILEMISSING;
540 break;
541 case 'O':
542 case 'o':
543 RepairMode |= REINSTALLMODE_FILEOLDERVERSION;
544 break;
545 case 'E':
546 case 'e':
547 RepairMode |= REINSTALLMODE_FILEEQUALVERSION;
548 break;
549 case 'D':
550 case 'd':
551 RepairMode |= REINSTALLMODE_FILEEXACT;
552 break;
553 case 'C':
554 case 'c':
555 RepairMode |= REINSTALLMODE_FILEVERIFY;
556 break;
557 case 'A':
558 case 'a':
559 RepairMode |= REINSTALLMODE_FILEREPLACE;
560 break;
561 case 'U':
562 case 'u':
563 RepairMode |= REINSTALLMODE_USERDATA;
564 break;
565 case 'M':
566 case 'm':
567 RepairMode |= REINSTALLMODE_MACHINEDATA;
568 break;
569 case 'S':
570 case 's':
571 RepairMode |= REINSTALLMODE_SHORTCUT;
572 break;
573 case 'V':
574 case 'v':
575 RepairMode |= REINSTALLMODE_PACKAGE;
576 break;
577 default:
578 fprintf(stderr, "Unknown option \"%c\" in Repair mode\n", argvW[i][j]);
579 break;
582 if(len == 2)
584 RepairMode = REINSTALLMODE_FILEMISSING |
585 REINSTALLMODE_FILEEQUALVERSION |
586 REINSTALLMODE_FILEVERIFY |
587 REINSTALLMODE_MACHINEDATA |
588 REINSTALLMODE_SHORTCUT;
590 i++;
591 if(i >= argc)
592 ShowUsage(1);
593 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
594 PackageName = argvW[i];
596 else if(!msi_strequal(argvW[i], "/x"))
598 FunctionInstall = TRUE;
599 i++;
600 if(i >= argc)
601 ShowUsage(1);
602 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
603 PackageName = argvW[i];
604 StringListAppend(&property_list, RemoveAll);
606 else if(!msi_strprefix(argvW[i], "/j"))
608 int j;
609 int len = lstrlenW(argvW[i]);
610 FunctionAdvertise = TRUE;
611 for(j = 2; j < len; j++)
613 switch(argvW[i][j])
615 case 'U':
616 case 'u':
617 AdvertiseMode = ADVERTISEFLAGS_USERASSIGN;
618 break;
619 case 'M':
620 case 'm':
621 AdvertiseMode = ADVERTISEFLAGS_MACHINEASSIGN;
622 break;
623 default:
624 fprintf(stderr, "Unknown option \"%c\" in Advertise mode\n", argvW[i][j]);
625 break;
628 i++;
629 if(i >= argc)
630 ShowUsage(1);
631 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
632 PackageName = argvW[i];
634 else if(!msi_strequal(argvW[i], "u"))
636 FunctionAdvertise = TRUE;
637 AdvertiseMode = ADVERTISEFLAGS_USERASSIGN;
638 i++;
639 if(i >= argc)
640 ShowUsage(1);
641 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
642 PackageName = argvW[i];
644 else if(!msi_strequal(argvW[i], "m"))
646 FunctionAdvertise = TRUE;
647 AdvertiseMode = ADVERTISEFLAGS_MACHINEASSIGN;
648 i++;
649 if(i >= argc)
650 ShowUsage(1);
651 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
652 PackageName = argvW[i];
654 else if(!msi_strequal(argvW[i], "/t"))
656 i++;
657 if(i >= argc)
658 ShowUsage(1);
659 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
660 StringListAppend(&transform_list, argvW[i]);
662 else if(!msi_strequal(argvW[i], "/g"))
664 i++;
665 if(i >= argc)
666 ShowUsage(1);
667 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
668 Language = msi_atou(argvW[i]);
670 else if(!msi_strprefix(argvW[i], "/l"))
672 int j;
673 int len = lstrlenW(argvW[i]);
674 for(j = 2; j < len; j++)
676 switch(argvW[i][j])
678 case 'I':
679 case 'i':
680 LogMode |= INSTALLLOGMODE_INFO;
681 break;
682 case 'W':
683 case 'w':
684 LogMode |= INSTALLLOGMODE_WARNING;
685 break;
686 case 'E':
687 case 'e':
688 LogMode |= INSTALLLOGMODE_ERROR;
689 break;
690 case 'A':
691 case 'a':
692 LogMode |= INSTALLLOGMODE_ACTIONSTART;
693 break;
694 case 'R':
695 case 'r':
696 LogMode |= INSTALLLOGMODE_ACTIONDATA;
697 break;
698 case 'U':
699 case 'u':
700 LogMode |= INSTALLLOGMODE_USER;
701 break;
702 case 'C':
703 case 'c':
704 LogMode |= INSTALLLOGMODE_COMMONDATA;
705 break;
706 case 'M':
707 case 'm':
708 LogMode |= INSTALLLOGMODE_FATALEXIT;
709 break;
710 case 'O':
711 case 'o':
712 LogMode |= INSTALLLOGMODE_OUTOFDISKSPACE;
713 break;
714 case 'P':
715 case 'p':
716 LogMode |= INSTALLLOGMODE_PROPERTYDUMP;
717 break;
718 case 'V':
719 case 'v':
720 LogMode |= INSTALLLOGMODE_VERBOSE;
721 break;
722 case '*':
723 LogMode = INSTALLLOGMODE_FATALEXIT |
724 INSTALLLOGMODE_ERROR |
725 INSTALLLOGMODE_WARNING |
726 INSTALLLOGMODE_USER |
727 INSTALLLOGMODE_INFO |
728 INSTALLLOGMODE_RESOLVESOURCE |
729 INSTALLLOGMODE_OUTOFDISKSPACE |
730 INSTALLLOGMODE_ACTIONSTART |
731 INSTALLLOGMODE_ACTIONDATA |
732 INSTALLLOGMODE_COMMONDATA |
733 INSTALLLOGMODE_PROPERTYDUMP |
734 INSTALLLOGMODE_PROGRESS |
735 INSTALLLOGMODE_INITIALIZE |
736 INSTALLLOGMODE_TERMINATE |
737 INSTALLLOGMODE_SHOWDIALOG;
738 break;
739 case '+':
740 LogAttributes |= INSTALLLOGATTRIBUTES_APPEND;
741 break;
742 case '!':
743 LogAttributes |= INSTALLLOGATTRIBUTES_FLUSHEACHLINE;
744 break;
745 default:
746 break;
749 i++;
750 if(i >= argc)
751 ShowUsage(1);
752 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
753 LogFileName = argvW[i];
754 if(MsiEnableLogW(LogMode, LogFileName, LogAttributes) != ERROR_SUCCESS)
756 fprintf(stderr, "Logging in %s (0x%08lx, %lu) failed\n",
757 wine_dbgstr_w(LogFileName), LogMode, LogAttributes);
758 ExitProcess(1);
761 else if(!msi_strequal(argvW[i], "/p"))
763 FunctionPatch = TRUE;
764 i++;
765 if(i >= argc)
766 ShowUsage(1);
767 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
768 PatchFileName = argvW[i];
770 else if(!msi_strprefix(argvW[i], "/q"))
772 if(lstrlenW(argvW[i]) == 2 || !msi_strequal(argvW[i]+2, "n"))
774 InstallUILevel = INSTALLUILEVEL_NONE;
776 else if(!msi_strequal(argvW[i]+2, "b"))
778 InstallUILevel = INSTALLUILEVEL_BASIC;
780 else if(!msi_strequal(argvW[i]+2, "r"))
782 InstallUILevel = INSTALLUILEVEL_REDUCED;
784 else if(!msi_strequal(argvW[i]+2, "f"))
786 InstallUILevel = INSTALLUILEVEL_FULL|INSTALLUILEVEL_ENDDIALOG;
788 else if(!msi_strequal(argvW[i]+2, "n+"))
790 InstallUILevel = INSTALLUILEVEL_NONE|INSTALLUILEVEL_ENDDIALOG;
792 else if(!msi_strequal(argvW[i]+2, "b+"))
794 InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_ENDDIALOG;
796 else if(!msi_strequal(argvW[i]+2, "b-"))
798 InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_PROGRESSONLY;
800 else if(!msi_strequal(argvW[i]+2, "b+!"))
802 InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_ENDDIALOG;
803 WINE_FIXME("Unknown modifier: !\n");
805 else
807 fprintf(stderr, "Unknown option \"%s\" for UI level\n",
808 wine_dbgstr_w(argvW[i]+2));
811 else if(!msi_strequal(argvW[i], "/y"))
813 FunctionDllRegisterServer = TRUE;
814 i++;
815 if(i >= argc)
816 ShowUsage(1);
817 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
818 DllName = argvW[i];
820 else if(!msi_strequal(argvW[i], "/z"))
822 FunctionDllUnregisterServer = TRUE;
823 i++;
824 if(i >= argc)
825 ShowUsage(1);
826 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
827 DllName = argvW[i];
829 else if(!msi_strequal(argvW[i], "/h") || !msi_strequal(argvW[i], "/?"))
831 ShowUsage(0);
833 else if(!msi_strequal(argvW[i], "/m"))
835 FunctionUnknown = TRUE;
836 WINE_FIXME("Unknown parameter /m\n");
838 else if(!msi_strequal(argvW[i], "/D"))
840 FunctionUnknown = TRUE;
841 WINE_FIXME("Unknown parameter /D\n");
843 else
844 StringListAppend(&property_list, argvW[i]);
847 /* start the GUI */
848 MsiSetInternalUI(InstallUILevel, NULL);
850 Properties = build_properties( property_list );
852 if(FunctionInstallAdmin && FunctionPatch)
853 FunctionInstall = FALSE;
855 ReturnCode = 1;
856 if(FunctionInstall)
858 if(IsProductCode(PackageName))
859 ReturnCode = MsiConfigureProductExW(PackageName, 0, INSTALLSTATE_DEFAULT, Properties);
860 else
861 ReturnCode = MsiInstallProductW(PackageName, Properties);
863 else if(FunctionRepair)
865 if(IsProductCode(PackageName))
866 WINE_FIXME("Product code treatment not implemented yet\n");
867 else
868 ReturnCode = MsiReinstallProductW(PackageName, RepairMode);
870 else if(FunctionAdvertise)
872 LPWSTR Transforms = build_transforms( property_list );
873 ReturnCode = MsiAdvertiseProductW(PackageName, (LPWSTR) AdvertiseMode, Transforms, Language);
875 else if(FunctionPatch)
877 ReturnCode = MsiApplyPatchW(PatchFileName, PackageName, InstallType, Properties);
879 else if(FunctionDllRegisterServer)
881 ReturnCode = DoDllRegisterServer(DllName);
883 else if(FunctionDllUnregisterServer)
885 ReturnCode = DoDllUnregisterServer(DllName);
887 else if (FunctionRegServer)
889 WINE_FIXME( "/regserver not implemented yet, ignoring\n" );
891 else if (FunctionUnregServer)
893 WINE_FIXME( "/unregserver not implemented yet, ignoring\n" );
895 else if (FunctionUnknown)
897 WINE_FIXME( "Unknown function, ignoring\n" );
899 else
900 ShowUsage(1);
902 return ReturnCode;