nsiproxy: Include sys/socket.h.
[wine.git] / programs / msiexec / msiexec.c
blobe25cc2659e606791f1c18da2153d7623fdeff5e4
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 <commctrl.h>
26 #include <msi.h>
27 #include <winsvc.h>
28 #include <objbase.h>
29 #include <stdio.h>
31 #include "wine/debug.h"
32 #include "wine/heap.h"
34 #include "initguid.h"
35 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
37 WINE_DEFAULT_DEBUG_CHANNEL(msiexec);
39 typedef HRESULT (WINAPI *DLLREGISTERSERVER)(void);
40 typedef HRESULT (WINAPI *DLLUNREGISTERSERVER)(void);
42 DWORD DoService(void);
44 struct string_list
46 struct string_list *next;
47 WCHAR str[1];
50 static void ShowUsage(int ExitCode)
52 WCHAR msiexec_version[40];
53 WCHAR filename[MAX_PATH];
54 LPWSTR msi_res;
55 LPWSTR msiexec_help;
56 HMODULE hmsi = GetModuleHandleA("msi.dll");
57 DWORD len;
58 DWORD res;
60 /* MsiGetFileVersion need the full path */
61 *filename = 0;
62 res = GetModuleFileNameW(hmsi, filename, ARRAY_SIZE(filename));
63 if (!res)
64 WINE_ERR("GetModuleFileName failed: %d\n", GetLastError());
66 len = ARRAY_SIZE(msiexec_version);
67 *msiexec_version = 0;
68 res = MsiGetFileVersionW(filename, msiexec_version, &len, NULL, NULL);
69 if (res)
70 WINE_ERR("MsiGetFileVersion failed with %d\n", res);
72 /* Return the length of the resource.
73 No typo: The LPWSTR parameter must be a LPWSTR * for this mode */
74 len = LoadStringW(hmsi, 10, (LPWSTR) &msi_res, 0);
76 msi_res = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
77 msiexec_help = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) + sizeof(msiexec_version));
78 if (msi_res && msiexec_help) {
79 *msi_res = 0;
80 LoadStringW(hmsi, 10, msi_res, len + 1);
82 swprintf(msiexec_help, len + 1 + ARRAY_SIZE(msiexec_version), msi_res, msiexec_version);
83 MsiMessageBoxW(0, msiexec_help, NULL, 0, GetUserDefaultLangID(), 0);
85 HeapFree(GetProcessHeap(), 0, msi_res);
86 HeapFree(GetProcessHeap(), 0, msiexec_help);
87 ExitProcess(ExitCode);
90 static BOOL IsProductCode(LPWSTR str)
92 GUID ProductCode;
94 if(lstrlenW(str) != 38)
95 return FALSE;
96 return ( (CLSIDFromString(str, &ProductCode) == NOERROR) );
100 static VOID StringListAppend(struct string_list **list, LPCWSTR str)
102 struct string_list *entry;
104 entry = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(struct string_list, str[lstrlenW(str) + 1]));
105 if(!entry)
107 WINE_ERR("Out of memory!\n");
108 ExitProcess(1);
110 lstrcpyW(entry->str, str);
111 entry->next = NULL;
114 * Ignoring o(n^2) time complexity to add n strings for simplicity,
115 * add the string to the end of the list to preserve the order.
117 while( *list )
118 list = &(*list)->next;
119 *list = entry;
122 static LPWSTR build_properties(struct string_list *property_list)
124 struct string_list *list;
125 LPWSTR ret, p, value;
126 DWORD len;
127 BOOL needs_quote;
129 if(!property_list)
130 return NULL;
132 /* count the space we need */
133 len = 1;
134 for(list = property_list; list; list = list->next)
135 len += lstrlenW(list->str) + 3;
137 ret = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
139 /* add a space before each string, and quote the value */
140 p = ret;
141 for(list = property_list; list; list = list->next)
143 value = wcschr(list->str,'=');
144 if(!value)
145 continue;
146 len = value - list->str;
147 *p++ = ' ';
148 memcpy(p, list->str, len * sizeof(WCHAR));
149 p += len;
150 *p++ = '=';
152 /* check if the value contains spaces and maybe quote it */
153 value++;
154 needs_quote = wcschr(value,' ') ? 1 : 0;
155 if(needs_quote)
156 *p++ = '"';
157 len = lstrlenW(value);
158 memcpy(p, value, len * sizeof(WCHAR));
159 p += len;
160 if(needs_quote)
161 *p++ = '"';
163 *p = 0;
165 WINE_TRACE("properties -> %s\n", wine_dbgstr_w(ret) );
167 return ret;
170 static LPWSTR build_transforms(struct string_list *transform_list)
172 struct string_list *list;
173 LPWSTR ret, p;
174 DWORD len;
176 /* count the space we need */
177 len = 1;
178 for(list = transform_list; list; list = list->next)
179 len += lstrlenW(list->str) + 1;
181 ret = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
183 /* add all the transforms with a semicolon between each one */
184 p = ret;
185 for(list = transform_list; list; list = list->next)
187 len = lstrlenW(list->str);
188 lstrcpynW(p, list->str, len );
189 p += len;
190 if(list->next)
191 *p++ = ';';
193 *p = 0;
195 return ret;
198 static DWORD msi_atou(LPCWSTR str)
200 DWORD ret = 0;
201 while(*str >= '0' && *str <= '9')
203 ret *= 10;
204 ret += (*str - '0');
205 str++;
207 return ret;
210 /* str1 is the same as str2, ignoring case */
211 static BOOL msi_strequal(LPCWSTR str1, LPCSTR str2)
213 DWORD len, ret;
214 LPWSTR strW;
216 len = MultiByteToWideChar( CP_ACP, 0, str2, -1, NULL, 0);
217 if( !len )
218 return FALSE;
219 if( lstrlenW(str1) != (len-1) )
220 return FALSE;
221 strW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len);
222 MultiByteToWideChar( CP_ACP, 0, str2, -1, strW, len);
223 ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str1, len, strW, len);
224 HeapFree(GetProcessHeap(), 0, strW);
225 return (ret == CSTR_EQUAL);
228 /* prefix is hyphen or dash, and str1 is the same as str2, ignoring case */
229 static BOOL msi_option_equal(LPCWSTR str1, LPCSTR str2)
231 if (str1[0] != '/' && str1[0] != '-')
232 return FALSE;
234 /* skip over the hyphen or slash */
235 return msi_strequal(str1 + 1, str2);
238 /* str2 is at the beginning of str1, ignoring case */
239 static BOOL msi_strprefix(LPCWSTR str1, LPCSTR str2)
241 DWORD len, ret;
242 LPWSTR strW;
244 len = MultiByteToWideChar( CP_ACP, 0, str2, -1, NULL, 0);
245 if( !len )
246 return FALSE;
247 if( lstrlenW(str1) < (len-1) )
248 return FALSE;
249 strW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len);
250 MultiByteToWideChar( CP_ACP, 0, str2, -1, strW, len);
251 ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str1, len-1, strW, len-1);
252 HeapFree(GetProcessHeap(), 0, strW);
253 return (ret == CSTR_EQUAL);
256 /* prefix is hyphen or dash, and str2 is at the beginning of str1, ignoring case */
257 static BOOL msi_option_prefix(LPCWSTR str1, LPCSTR str2)
259 if (str1[0] != '/' && str1[0] != '-')
260 return FALSE;
262 /* skip over the hyphen or slash */
263 return msi_strprefix(str1 + 1, str2);
266 static VOID *LoadProc(LPCWSTR DllName, LPCSTR ProcName, HMODULE* DllHandle)
268 VOID* (*proc)(void);
270 *DllHandle = LoadLibraryExW(DllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
271 if(!*DllHandle)
273 fprintf(stderr, "Unable to load dll %s\n", wine_dbgstr_w(DllName));
274 ExitProcess(1);
276 proc = (VOID *) GetProcAddress(*DllHandle, ProcName);
277 if(!proc)
279 fprintf(stderr, "Dll %s does not implement function %s\n",
280 wine_dbgstr_w(DllName), ProcName);
281 FreeLibrary(*DllHandle);
282 ExitProcess(1);
285 return proc;
288 static DWORD DoDllRegisterServer(LPCWSTR DllName)
290 HRESULT hr;
291 DLLREGISTERSERVER pfDllRegisterServer = NULL;
292 HMODULE DllHandle = NULL;
294 pfDllRegisterServer = LoadProc(DllName, "DllRegisterServer", &DllHandle);
296 hr = pfDllRegisterServer();
297 if(FAILED(hr))
299 fprintf(stderr, "Failed to register dll %s\n", wine_dbgstr_w(DllName));
300 return 1;
302 printf("Successfully registered dll %s\n", wine_dbgstr_w(DllName));
303 if(DllHandle)
304 FreeLibrary(DllHandle);
305 return 0;
308 static DWORD DoDllUnregisterServer(LPCWSTR DllName)
310 HRESULT hr;
311 DLLUNREGISTERSERVER pfDllUnregisterServer = NULL;
312 HMODULE DllHandle = NULL;
314 pfDllUnregisterServer = LoadProc(DllName, "DllUnregisterServer", &DllHandle);
316 hr = pfDllUnregisterServer();
317 if(FAILED(hr))
319 fprintf(stderr, "Failed to unregister dll %s\n", wine_dbgstr_w(DllName));
320 return 1;
322 printf("Successfully unregistered dll %s\n", wine_dbgstr_w(DllName));
323 if(DllHandle)
324 FreeLibrary(DllHandle);
325 return 0;
328 static DWORD DoRegServer(void)
330 SC_HANDLE scm, service;
331 WCHAR path[MAX_PATH+12];
332 DWORD len, ret = 0;
334 if (!(scm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, SC_MANAGER_CREATE_SERVICE)))
336 fprintf(stderr, "Failed to open the service control manager.\n");
337 return 1;
339 len = GetSystemDirectoryW(path, MAX_PATH);
340 lstrcpyW(path + len, L"\\msiexec /V");
341 if ((service = CreateServiceW(scm, L"MSIServer", L"MSIServer", GENERIC_ALL,
342 SERVICE_WIN32_SHARE_PROCESS, SERVICE_DEMAND_START,
343 SERVICE_ERROR_NORMAL, path, NULL, NULL, NULL, NULL, NULL)))
345 CloseServiceHandle(service);
347 else if (GetLastError() != ERROR_SERVICE_EXISTS)
349 fprintf(stderr, "Failed to create MSI service\n");
350 ret = 1;
352 CloseServiceHandle(scm);
353 return ret;
356 static DWORD DoUnregServer(void)
358 SC_HANDLE scm, service;
359 DWORD ret = 0;
361 if (!(scm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, SC_MANAGER_CONNECT)))
363 fprintf(stderr, "Failed to open service control manager\n");
364 return 1;
366 if ((service = OpenServiceW(scm, L"MSIServer", DELETE)))
368 if (!DeleteService(service))
370 fprintf(stderr, "Failed to delete MSI service\n");
371 ret = 1;
373 CloseServiceHandle(service);
375 else if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST)
377 fprintf(stderr, "Failed to open MSI service\n");
378 ret = 1;
380 CloseServiceHandle(scm);
381 return ret;
384 extern UINT CDECL __wine_msi_call_dll_function(DWORD client_pid, const GUID *guid);
386 static DWORD client_pid;
388 static DWORD CALLBACK custom_action_thread(void *arg)
390 GUID guid = *(GUID *)arg;
391 heap_free(arg);
392 return __wine_msi_call_dll_function(client_pid, &guid);
395 static int custom_action_server(const WCHAR *arg)
397 GUID guid, *thread_guid;
398 DWORD64 thread64;
399 WCHAR buffer[24];
400 HANDLE thread;
401 HANDLE pipe;
402 DWORD size;
404 TRACE("%s\n", debugstr_w(arg));
406 if (!(client_pid = wcstol(arg, NULL, 10)))
408 ERR("Invalid parameter %s\n", debugstr_w(arg));
409 return 1;
412 swprintf(buffer, ARRAY_SIZE(buffer), L"\\\\.\\pipe\\msica_%x_%d", client_pid, sizeof(void *) * 8);
413 pipe = CreateFileW(buffer, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
414 if (pipe == INVALID_HANDLE_VALUE)
416 ERR("Failed to create custom action server pipe: %u\n", GetLastError());
417 return GetLastError();
420 /* We need this to unmarshal streams, and some apps expect it to be present. */
421 CoInitializeEx(NULL, COINIT_MULTITHREADED);
423 while (ReadFile(pipe, &guid, sizeof(guid), &size, NULL) && size == sizeof(guid))
425 if (IsEqualGUID(&guid, &GUID_NULL))
427 /* package closed; time to shut down */
428 CoUninitialize();
429 return 0;
432 thread_guid = heap_alloc(sizeof(GUID));
433 memcpy(thread_guid, &guid, sizeof(GUID));
434 thread = CreateThread(NULL, 0, custom_action_thread, thread_guid, 0, NULL);
436 /* give the thread handle to the client to wait on, since we might have
437 * to run a nested action and can't block during this one */
438 thread64 = (DWORD_PTR)thread;
439 if (!WriteFile(pipe, &thread64, sizeof(thread64), &size, NULL) || size != sizeof(thread64))
441 ERR("Failed to write to custom action server pipe: %u\n", GetLastError());
442 CoUninitialize();
443 return GetLastError();
446 ERR("Failed to read from custom action server pipe: %u\n", GetLastError());
447 CoUninitialize();
448 return GetLastError();
452 * state machine to break up the command line properly
455 enum chomp_state
457 CS_WHITESPACE,
458 CS_TOKEN,
459 CS_QUOTE
462 static int chomp( const WCHAR *in, WCHAR *out )
464 enum chomp_state state = CS_TOKEN;
465 const WCHAR *p;
466 int count = 1;
467 BOOL ignore;
469 for (p = in; *p; p++)
471 ignore = TRUE;
472 switch (state)
474 case CS_WHITESPACE:
475 switch (*p)
477 case ' ':
478 break;
479 case '"':
480 state = CS_QUOTE;
481 count++;
482 break;
483 default:
484 count++;
485 ignore = FALSE;
486 state = CS_TOKEN;
488 break;
490 case CS_TOKEN:
491 switch (*p)
493 case '"':
494 state = CS_QUOTE;
495 break;
496 case ' ':
497 state = CS_WHITESPACE;
498 if (out) *out++ = 0;
499 break;
500 default:
501 if (p > in && p[-1] == '"')
503 if (out) *out++ = 0;
504 count++;
506 ignore = FALSE;
508 break;
510 case CS_QUOTE:
511 switch (*p)
513 case '"':
514 state = CS_TOKEN;
515 break;
516 default:
517 ignore = FALSE;
519 break;
521 if (!ignore && out) *out++ = *p;
523 if (out) *out = 0;
524 return count;
527 static void process_args( WCHAR *cmdline, int *pargc, WCHAR ***pargv )
529 WCHAR **argv, *p;
530 int i, count;
532 *pargc = 0;
533 *pargv = NULL;
535 count = chomp( cmdline, NULL );
536 if (!(p = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(cmdline) + count + 1) * sizeof(WCHAR) )))
537 return;
539 count = chomp( cmdline, p );
540 if (!(argv = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(WCHAR *) )))
542 HeapFree( GetProcessHeap(), 0, p );
543 return;
545 for (i = 0; i < count; i++)
547 argv[i] = p;
548 p += lstrlenW( p ) + 1;
550 argv[i] = NULL;
552 *pargc = count;
553 *pargv = argv;
556 static BOOL process_args_from_reg( const WCHAR *ident, int *pargc, WCHAR ***pargv )
558 LONG r;
559 HKEY hkey;
560 DWORD sz = 0, type = 0;
561 WCHAR *buf;
562 BOOL ret = FALSE;
564 r = RegOpenKeyW(HKEY_LOCAL_MACHINE,
565 L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\RunOnceEntries", &hkey);
566 if(r != ERROR_SUCCESS)
567 return FALSE;
568 r = RegQueryValueExW(hkey, ident, 0, &type, 0, &sz);
569 if(r == ERROR_SUCCESS && type == REG_SZ)
571 int len = lstrlenW( *pargv[0] );
572 if (!(buf = HeapAlloc( GetProcessHeap(), 0, sz + (len + 1) * sizeof(WCHAR) )))
574 RegCloseKey( hkey );
575 return FALSE;
577 memcpy( buf, *pargv[0], len * sizeof(WCHAR) );
578 buf[len++] = ' ';
579 r = RegQueryValueExW(hkey, ident, 0, &type, (LPBYTE)(buf + len), &sz);
580 if( r == ERROR_SUCCESS )
582 process_args(buf, pargc, pargv);
583 ret = TRUE;
585 HeapFree(GetProcessHeap(), 0, buf);
587 RegCloseKey(hkey);
588 return ret;
591 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
593 int i;
594 BOOL FunctionInstall = FALSE;
595 BOOL FunctionInstallAdmin = FALSE;
596 BOOL FunctionRepair = FALSE;
597 BOOL FunctionAdvertise = FALSE;
598 BOOL FunctionPatch = FALSE;
599 BOOL FunctionDllRegisterServer = FALSE;
600 BOOL FunctionDllUnregisterServer = FALSE;
601 BOOL FunctionRegServer = FALSE;
602 BOOL FunctionUnregServer = FALSE;
603 BOOL FunctionServer = FALSE;
604 BOOL FunctionUnknown = FALSE;
606 LPWSTR PackageName = NULL;
607 LPWSTR Properties = NULL;
608 struct string_list *property_list = NULL;
610 DWORD RepairMode = 0;
612 DWORD_PTR AdvertiseMode = 0;
613 struct string_list *transform_list = NULL;
614 LANGID Language = 0;
616 DWORD LogMode = 0;
617 LPWSTR LogFileName = NULL;
618 DWORD LogAttributes = 0;
620 LPWSTR PatchFileName = NULL;
621 INSTALLTYPE InstallType = INSTALLTYPE_DEFAULT;
623 INSTALLUILEVEL InstallUILevel = INSTALLUILEVEL_FULL;
625 LPWSTR DllName = NULL;
626 DWORD ReturnCode;
627 int argc;
628 LPWSTR *argvW = NULL;
630 InitCommonControls();
632 /* parse the command line */
633 process_args( GetCommandLineW(), &argc, &argvW );
636 * If the args begin with /@ IDENT then we need to load the real
637 * command line out of the RunOnceEntries key in the registry.
638 * We do that before starting to process the real commandline,
639 * then overwrite the commandline again.
641 if(argc>1 && msi_option_equal(argvW[1], "@"))
643 if(!process_args_from_reg( argvW[2], &argc, &argvW ))
644 return 1;
647 if (argc == 3 && msi_option_equal(argvW[1], "Embedding"))
648 return custom_action_server(argvW[2]);
650 for(i = 1; i < argc; i++)
652 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
654 if (msi_option_equal(argvW[i], "regserver"))
656 FunctionRegServer = TRUE;
658 else if (msi_option_equal(argvW[i], "unregserver") || msi_option_equal(argvW[i], "unregister")
659 || msi_option_equal(argvW[i], "unreg"))
661 FunctionUnregServer = TRUE;
663 else if(msi_option_prefix(argvW[i], "i") || msi_option_prefix(argvW[i], "package"))
665 LPWSTR argvWi = argvW[i];
666 int argLen = (msi_option_prefix(argvW[i], "i") ? 2 : 8);
667 FunctionInstall = TRUE;
668 if(lstrlenW(argvW[i]) > argLen)
669 argvWi += argLen;
670 else
672 i++;
673 if(i >= argc)
674 ShowUsage(1);
675 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
676 argvWi = argvW[i];
678 PackageName = argvWi;
680 else if(msi_option_equal(argvW[i], "a"))
682 FunctionInstall = TRUE;
683 FunctionInstallAdmin = TRUE;
684 InstallType = INSTALLTYPE_NETWORK_IMAGE;
685 i++;
686 if(i >= argc)
687 ShowUsage(1);
688 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
689 PackageName = argvW[i];
690 StringListAppend(&property_list, L"ACTION=ADMIN");
691 WINE_FIXME("Administrative installs are not currently supported\n");
693 else if(msi_option_prefix(argvW[i], "f"))
695 int j;
696 int len = lstrlenW(argvW[i]);
697 FunctionRepair = TRUE;
698 for(j = 2; j < len; j++)
700 switch(argvW[i][j])
702 case 'P':
703 case 'p':
704 RepairMode |= REINSTALLMODE_FILEMISSING;
705 break;
706 case 'O':
707 case 'o':
708 RepairMode |= REINSTALLMODE_FILEOLDERVERSION;
709 break;
710 case 'E':
711 case 'e':
712 RepairMode |= REINSTALLMODE_FILEEQUALVERSION;
713 break;
714 case 'D':
715 case 'd':
716 RepairMode |= REINSTALLMODE_FILEEXACT;
717 break;
718 case 'C':
719 case 'c':
720 RepairMode |= REINSTALLMODE_FILEVERIFY;
721 break;
722 case 'A':
723 case 'a':
724 RepairMode |= REINSTALLMODE_FILEREPLACE;
725 break;
726 case 'U':
727 case 'u':
728 RepairMode |= REINSTALLMODE_USERDATA;
729 break;
730 case 'M':
731 case 'm':
732 RepairMode |= REINSTALLMODE_MACHINEDATA;
733 break;
734 case 'S':
735 case 's':
736 RepairMode |= REINSTALLMODE_SHORTCUT;
737 break;
738 case 'V':
739 case 'v':
740 RepairMode |= REINSTALLMODE_PACKAGE;
741 break;
742 default:
743 fprintf(stderr, "Unknown option \"%c\" in Repair mode\n", argvW[i][j]);
744 break;
747 if(len == 2)
749 RepairMode = REINSTALLMODE_FILEMISSING |
750 REINSTALLMODE_FILEEQUALVERSION |
751 REINSTALLMODE_FILEVERIFY |
752 REINSTALLMODE_MACHINEDATA |
753 REINSTALLMODE_SHORTCUT;
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_option_prefix(argvW[i], "x") || msi_option_equal(argvW[i], "uninstall"))
763 FunctionInstall = TRUE;
764 if(msi_option_prefix(argvW[i], "x")) PackageName = argvW[i]+2;
765 if(!PackageName || !PackageName[0])
767 i++;
768 if (i >= argc)
769 ShowUsage(1);
770 PackageName = argvW[i];
772 WINE_TRACE("PackageName = %s\n", wine_dbgstr_w(PackageName));
773 StringListAppend(&property_list, L"REMOVE=ALL");
775 else if(msi_option_prefix(argvW[i], "j"))
777 int j;
778 int len = lstrlenW(argvW[i]);
779 FunctionAdvertise = TRUE;
780 for(j = 2; j < len; j++)
782 switch(argvW[i][j])
784 case 'U':
785 case 'u':
786 AdvertiseMode = ADVERTISEFLAGS_USERASSIGN;
787 break;
788 case 'M':
789 case 'm':
790 AdvertiseMode = ADVERTISEFLAGS_MACHINEASSIGN;
791 break;
792 default:
793 fprintf(stderr, "Unknown option \"%c\" in Advertise mode\n", argvW[i][j]);
794 break;
797 i++;
798 if(i >= argc)
799 ShowUsage(1);
800 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
801 PackageName = argvW[i];
803 else if(msi_strequal(argvW[i], "u"))
805 FunctionAdvertise = TRUE;
806 AdvertiseMode = ADVERTISEFLAGS_USERASSIGN;
807 i++;
808 if(i >= argc)
809 ShowUsage(1);
810 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
811 PackageName = argvW[i];
813 else if(msi_strequal(argvW[i], "m"))
815 FunctionAdvertise = TRUE;
816 AdvertiseMode = ADVERTISEFLAGS_MACHINEASSIGN;
817 i++;
818 if(i >= argc)
819 ShowUsage(1);
820 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
821 PackageName = argvW[i];
823 else if(msi_option_equal(argvW[i], "t"))
825 i++;
826 if(i >= argc)
827 ShowUsage(1);
828 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
829 StringListAppend(&transform_list, argvW[i]);
831 else if(msi_option_equal(argvW[i], "g"))
833 i++;
834 if(i >= argc)
835 ShowUsage(1);
836 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
837 Language = msi_atou(argvW[i]);
839 else if(msi_option_prefix(argvW[i], "l"))
841 int j;
842 int len = lstrlenW(argvW[i]);
843 for(j = 2; j < len; j++)
845 switch(argvW[i][j])
847 case 'I':
848 case 'i':
849 LogMode |= INSTALLLOGMODE_INFO;
850 break;
851 case 'W':
852 case 'w':
853 LogMode |= INSTALLLOGMODE_WARNING;
854 break;
855 case 'E':
856 case 'e':
857 LogMode |= INSTALLLOGMODE_ERROR;
858 break;
859 case 'A':
860 case 'a':
861 LogMode |= INSTALLLOGMODE_ACTIONSTART;
862 break;
863 case 'R':
864 case 'r':
865 LogMode |= INSTALLLOGMODE_ACTIONDATA;
866 break;
867 case 'U':
868 case 'u':
869 LogMode |= INSTALLLOGMODE_USER;
870 break;
871 case 'C':
872 case 'c':
873 LogMode |= INSTALLLOGMODE_COMMONDATA;
874 break;
875 case 'M':
876 case 'm':
877 LogMode |= INSTALLLOGMODE_FATALEXIT;
878 break;
879 case 'O':
880 case 'o':
881 LogMode |= INSTALLLOGMODE_OUTOFDISKSPACE;
882 break;
883 case 'P':
884 case 'p':
885 LogMode |= INSTALLLOGMODE_PROPERTYDUMP;
886 break;
887 case 'V':
888 case 'v':
889 LogMode |= INSTALLLOGMODE_VERBOSE;
890 break;
891 case '*':
892 LogMode = INSTALLLOGMODE_FATALEXIT |
893 INSTALLLOGMODE_ERROR |
894 INSTALLLOGMODE_WARNING |
895 INSTALLLOGMODE_USER |
896 INSTALLLOGMODE_INFO |
897 INSTALLLOGMODE_RESOLVESOURCE |
898 INSTALLLOGMODE_OUTOFDISKSPACE |
899 INSTALLLOGMODE_ACTIONSTART |
900 INSTALLLOGMODE_ACTIONDATA |
901 INSTALLLOGMODE_COMMONDATA |
902 INSTALLLOGMODE_PROPERTYDUMP |
903 INSTALLLOGMODE_PROGRESS |
904 INSTALLLOGMODE_INITIALIZE |
905 INSTALLLOGMODE_TERMINATE |
906 INSTALLLOGMODE_SHOWDIALOG;
907 break;
908 case '+':
909 LogAttributes |= INSTALLLOGATTRIBUTES_APPEND;
910 break;
911 case '!':
912 LogAttributes |= INSTALLLOGATTRIBUTES_FLUSHEACHLINE;
913 break;
914 default:
915 break;
918 i++;
919 if(i >= argc)
920 ShowUsage(1);
921 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
922 LogFileName = argvW[i];
923 if(MsiEnableLogW(LogMode, LogFileName, LogAttributes) != ERROR_SUCCESS)
925 fprintf(stderr, "Logging in %s (0x%08x, %u) failed\n",
926 wine_dbgstr_w(LogFileName), LogMode, LogAttributes);
927 ExitProcess(1);
930 else if(msi_option_equal(argvW[i], "p") || msi_option_equal(argvW[i], "update"))
932 FunctionPatch = TRUE;
933 i++;
934 if(i >= argc)
935 ShowUsage(1);
936 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
937 PatchFileName = argvW[i];
939 else if(msi_option_prefix(argvW[i], "q"))
941 if(lstrlenW(argvW[i]) == 2 || msi_strequal(argvW[i]+2, "n") ||
942 msi_strequal(argvW[i] + 2, "uiet"))
944 InstallUILevel = INSTALLUILEVEL_NONE;
946 else if(msi_strequal(argvW[i]+2, "r"))
948 InstallUILevel = INSTALLUILEVEL_REDUCED;
950 else if(msi_strequal(argvW[i]+2, "f"))
952 InstallUILevel = INSTALLUILEVEL_FULL|INSTALLUILEVEL_ENDDIALOG;
954 else if(msi_strequal(argvW[i]+2, "n+"))
956 InstallUILevel = INSTALLUILEVEL_NONE|INSTALLUILEVEL_ENDDIALOG;
958 else if(msi_strprefix(argvW[i]+2, "b"))
960 const WCHAR *ptr = argvW[i] + 3;
962 InstallUILevel = INSTALLUILEVEL_BASIC;
964 while (*ptr)
966 if (msi_strprefix(ptr, "+"))
967 InstallUILevel |= INSTALLUILEVEL_ENDDIALOG;
968 if (msi_strprefix(ptr, "-"))
969 InstallUILevel |= INSTALLUILEVEL_PROGRESSONLY;
970 if (msi_strprefix(ptr, "!"))
972 WINE_FIXME("Unhandled modifier: !\n");
973 InstallUILevel |= INSTALLUILEVEL_HIDECANCEL;
975 ptr++;
978 else
980 fprintf(stderr, "Unknown option \"%s\" for UI level\n",
981 wine_dbgstr_w(argvW[i]+2));
984 else if(msi_option_equal(argvW[i], "passive"))
986 InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_PROGRESSONLY|INSTALLUILEVEL_HIDECANCEL;
987 StringListAppend(&property_list, L"REBOOTPROMPT=\"S\"");
989 else if(msi_option_equal(argvW[i], "y"))
991 FunctionDllRegisterServer = TRUE;
992 i++;
993 if(i >= argc)
994 ShowUsage(1);
995 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
996 DllName = argvW[i];
998 else if(msi_option_equal(argvW[i], "z"))
1000 FunctionDllUnregisterServer = TRUE;
1001 i++;
1002 if(i >= argc)
1003 ShowUsage(1);
1004 WINE_TRACE("argvW[%d] = %s\n", i, wine_dbgstr_w(argvW[i]));
1005 DllName = argvW[i];
1007 else if(msi_option_equal(argvW[i], "help") || msi_option_equal(argvW[i], "?"))
1009 ShowUsage(0);
1011 else if(msi_option_equal(argvW[i], "m"))
1013 FunctionUnknown = TRUE;
1014 WINE_FIXME("Unknown parameter /m\n");
1016 else if(msi_option_equal(argvW[i], "D"))
1018 FunctionUnknown = TRUE;
1019 WINE_FIXME("Unknown parameter /D\n");
1021 else if (msi_option_equal(argvW[i], "V"))
1023 FunctionServer = TRUE;
1025 else
1026 StringListAppend(&property_list, argvW[i]);
1029 /* start the GUI */
1030 MsiSetInternalUI(InstallUILevel, NULL);
1032 Properties = build_properties( property_list );
1034 if(FunctionInstallAdmin && FunctionPatch)
1035 FunctionInstall = FALSE;
1037 ReturnCode = 1;
1038 if(FunctionInstall)
1040 if(IsProductCode(PackageName))
1041 ReturnCode = MsiConfigureProductExW(PackageName, 0, INSTALLSTATE_DEFAULT, Properties);
1042 else
1043 ReturnCode = MsiInstallProductW(PackageName, Properties);
1045 else if(FunctionRepair)
1047 if(IsProductCode(PackageName))
1048 WINE_FIXME("Product code treatment not implemented yet\n");
1049 else
1050 ReturnCode = MsiReinstallProductW(PackageName, RepairMode);
1052 else if(FunctionAdvertise)
1054 LPWSTR Transforms = build_transforms( property_list );
1055 ReturnCode = MsiAdvertiseProductW(PackageName, (LPWSTR) AdvertiseMode, Transforms, Language);
1057 else if(FunctionPatch)
1059 ReturnCode = MsiApplyPatchW(PatchFileName, PackageName, InstallType, Properties);
1061 else if(FunctionDllRegisterServer)
1063 ReturnCode = DoDllRegisterServer(DllName);
1065 else if(FunctionDllUnregisterServer)
1067 ReturnCode = DoDllUnregisterServer(DllName);
1069 else if (FunctionRegServer)
1071 ReturnCode = DoRegServer();
1073 else if (FunctionUnregServer)
1075 ReturnCode = DoUnregServer();
1077 else if (FunctionServer)
1079 ReturnCode = DoService();
1081 else if (FunctionUnknown)
1083 WINE_FIXME( "Unknown function, ignoring\n" );
1085 else
1086 ShowUsage(1);
1088 return ReturnCode;