Implement the UI level change part of msiexec.
[wine.git] / programs / msiexec / msiexec.c
blob0128bb549e50580a7001501a1ff59b130a9eccb1
1 /*
2 * msiexec.exe implementation
4 * Copyright 2004 Vincent Béron
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <windows.h>
22 #include <msi.h>
23 #include <objbase.h>
24 #include <stdio.h>
26 #include "msiexec.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(msiexec);
32 static const char UsageStr[] =
33 "Usage: msiexec ...\n\n"
34 "Copyright 2004 Vincent Béron\n";
36 static const char ActionAdmin[] = "ACTION=ADMIN ";
37 static const char RemoveAll[] = "REMOVE=ALL ";
39 static void ShowUsage(int ExitCode)
41 printf(UsageStr);
42 ExitProcess(ExitCode);
45 static BOOL GetProductCode(LPCSTR str, LPGUID guid)
47 BOOL ret = FALSE;
48 int len = 0;
49 LPWSTR wstr = NULL;
51 if(strlen(str) == 38)
53 len = MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, 0);
54 wstr = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
55 ret = (CLSIDFromString(wstr, guid) == NOERROR);
56 HeapFree(GetProcessHeap(), 0, wstr);
57 wstr = NULL;
60 return ret;
63 static VOID *LoadProc(LPCSTR DllName, LPCSTR ProcName, HMODULE* DllHandle)
65 VOID* (*proc)(void);
67 *DllHandle = LoadLibraryExA(DllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
68 if(!*DllHandle)
70 fprintf(stderr, "Unable to load dll %s\n", DllName);
71 ExitProcess(1);
73 proc = (VOID *) GetProcAddress(*DllHandle, ProcName);
74 if(!proc)
76 fprintf(stderr, "Dll %s does not implement function %s\n", DllName, ProcName);
77 FreeLibrary(*DllHandle);
78 ExitProcess(1);
81 return proc;
84 static void DllRegisterServer(LPCSTR DllName)
86 HRESULT hr;
87 DLLREGISTERSERVER pfDllRegisterServer = NULL;
88 HMODULE DllHandle = NULL;
90 pfDllRegisterServer = LoadProc(DllName, "DllRegisterServer", &DllHandle);
92 hr = pfDllRegisterServer();
93 if(FAILED(hr))
95 fprintf(stderr, "Failed to register dll %s\n", DllName);
96 ExitProcess(1);
98 printf("Successfully registered dll %s\n", DllName);
99 if(DllHandle)
100 FreeLibrary(DllHandle);
103 static void DllUnregisterServer(LPCSTR DllName)
105 HRESULT hr;
106 DLLUNREGISTERSERVER pfDllUnregisterServer = NULL;
107 HMODULE DllHandle = NULL;
109 pfDllUnregisterServer = LoadProc(DllName, "DllUnregisterServer", &DllHandle);
111 hr = pfDllUnregisterServer();
112 if(FAILED(hr))
114 fprintf(stderr, "Failed to unregister dll %s\n", DllName);
115 ExitProcess(1);
117 printf("Successfully unregistered dll %s\n", DllName);
118 if(DllHandle)
119 FreeLibrary(DllHandle);
122 int main(int argc, char *argv[])
124 int i;
125 BOOL FunctionInstall = FALSE;
126 BOOL FunctionRepair = FALSE;
127 BOOL FunctionAdvertise = FALSE;
128 BOOL FunctionDllRegisterServer = FALSE;
129 BOOL FunctionDllUnregisterServer = FALSE;
131 BOOL GotProductCode = FALSE;
132 LPSTR PackageName = NULL;
133 LPGUID ProductCode = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID));
134 LPSTR Properties = HeapAlloc(GetProcessHeap(), 0, 1);
135 LPSTR TempStr = NULL;
137 DWORD RepairMode = 0;
139 DWORD AdvertiseMode = 0;
140 LPSTR Transforms = HeapAlloc(GetProcessHeap(), 0, 1);
141 LANGID Language = 0;
143 INSTALLUILEVEL InstallUILevel = 0, retInstallUILevel;
145 LPSTR DllName = NULL;
147 Properties[0] = 0;
148 Transforms[0] = 0;
150 for(i = 1; i < argc; i++)
152 WINE_TRACE("argv[%d] = %s\n", i, argv[i]);
154 if(!strcasecmp(argv[i], "/i"))
156 FunctionInstall = TRUE;
157 i++;
158 if(i >= argc)
159 ShowUsage(1);
160 WINE_TRACE("argv[%d] = %s\n", i, argv[i]);
161 GotProductCode = GetProductCode(argv[i], ProductCode);
162 if(!GotProductCode)
164 HeapFree(GetProcessHeap(), 0, ProductCode);
165 ProductCode = NULL;
166 PackageName = argv[i];
169 else if(!strcasecmp(argv[i], "/a"))
171 FunctionInstall = TRUE;
172 i++;
173 if(i >= argc)
174 ShowUsage(1);
175 WINE_TRACE("argv[%d] = %s\n", i, argv[i]);
176 PackageName = argv[i];
177 TempStr = HeapReAlloc(GetProcessHeap(), 0, Properties, HeapSize(GetProcessHeap(), 0, Properties)+strlen(ActionAdmin));
178 if(!TempStr)
180 WINE_ERR("Out of memory!\n");
181 ExitProcess(1);
183 Properties = TempStr;
184 strcat(Properties, ActionAdmin);
186 else if(!strncasecmp(argv[i], "/f", 2))
188 int j;
189 int len = strlen(argv[i]);
190 FunctionRepair = TRUE;
191 for(j = 2; j < len; j++)
193 switch(argv[i][j])
195 case 'P':
196 case 'p':
197 RepairMode |= REINSTALLMODE_FILEMISSING;
198 break;
199 case 'O':
200 case 'o':
201 RepairMode |= REINSTALLMODE_FILEOLDERVERSION;
202 break;
203 case 'E':
204 case 'e':
205 RepairMode |= REINSTALLMODE_FILEEQUALVERSION;
206 break;
207 case 'D':
208 case 'd':
209 RepairMode |= REINSTALLMODE_FILEEXACT;
210 break;
211 case 'C':
212 case 'c':
213 RepairMode |= REINSTALLMODE_FILEVERIFY;
214 break;
215 case 'A':
216 case 'a':
217 RepairMode |= REINSTALLMODE_FILEREPLACE;
218 break;
219 case 'U':
220 case 'u':
221 RepairMode |= REINSTALLMODE_USERDATA;
222 break;
223 case 'M':
224 case 'm':
225 RepairMode |= REINSTALLMODE_MACHINEDATA;
226 break;
227 case 'S':
228 case 's':
229 RepairMode |= REINSTALLMODE_SHORTCUT;
230 break;
231 case 'V':
232 case 'v':
233 RepairMode |= REINSTALLMODE_PACKAGE;
234 break;
235 default:
236 fprintf(stderr, "Unknown option \"%c\" in Repair mode\n", argv[i][j]);
237 break;
240 if(len == 2)
242 RepairMode = REINSTALLMODE_FILEMISSING |
243 REINSTALLMODE_FILEEQUALVERSION |
244 REINSTALLMODE_FILEVERIFY |
245 REINSTALLMODE_MACHINEDATA |
246 REINSTALLMODE_SHORTCUT;
248 i++;
249 if(i >= argc)
250 ShowUsage(1);
251 WINE_TRACE("argv[%d] = %s\n", i, argv[i]);
252 GotProductCode = GetProductCode(argv[i], ProductCode);
253 if(!GotProductCode)
255 HeapFree(GetProcessHeap(), 0, ProductCode);
256 ProductCode = NULL;
257 PackageName = argv[i];
260 else if(!strcasecmp(argv[i], "/x"))
262 FunctionInstall = TRUE;
263 i++;
264 if(i >= argc)
265 ShowUsage(1);
266 WINE_TRACE("argv[%d] = %s\n", i, argv[i]);
267 GotProductCode = GetProductCode(argv[i], ProductCode);
268 if(!GotProductCode)
270 HeapFree(GetProcessHeap(), 0, ProductCode);
271 ProductCode = NULL;
272 PackageName = argv[i];
274 TempStr = HeapReAlloc(GetProcessHeap(), 0, Properties, HeapSize(GetProcessHeap(), 0, Properties)+strlen(RemoveAll));
275 if(!TempStr)
277 WINE_ERR("Out of memory!\n");
278 ExitProcess(1);
280 Properties = TempStr;
281 strcat(Properties, RemoveAll);
283 else if(!strncasecmp(argv[i], "/j", 2))
285 int j;
286 int len = strlen(argv[i]);
287 FunctionAdvertise = TRUE;
288 for(j = 2; j < len; j++)
290 switch(argv[i][j])
292 case 'U':
293 case 'u':
294 AdvertiseMode = ADVERTISEFLAGS_USERASSIGN;
295 break;
296 case 'M':
297 case 'm':
298 AdvertiseMode = ADVERTISEFLAGS_MACHINEASSIGN;
299 break;
300 default:
301 fprintf(stderr, "Unknown option \"%c\" in Advertise mode\n", argv[i][j]);
302 break;
305 i++;
306 if(i >= argc)
307 ShowUsage(1);
308 WINE_TRACE("argv[%d] = %s\n", i, argv[i]);
309 PackageName = argv[i];
311 else if(!strcasecmp(argv[i], "u"))
313 FunctionAdvertise = TRUE;
314 AdvertiseMode = ADVERTISEFLAGS_USERASSIGN;
315 i++;
316 if(i >= argc)
317 ShowUsage(1);
318 WINE_TRACE("argv[%d] = %s\n", i, argv[i]);
319 PackageName = argv[i];
321 else if(!strcasecmp(argv[i], "m"))
323 FunctionAdvertise = TRUE;
324 AdvertiseMode = ADVERTISEFLAGS_MACHINEASSIGN;
325 i++;
326 if(i >= argc)
327 ShowUsage(1);
328 WINE_TRACE("argv[%d] = %s\n", i, argv[i]);
329 PackageName = argv[i];
331 else if(!strcasecmp(argv[i], "/t"))
333 i++;
334 if(i >= argc)
335 ShowUsage(1);
336 WINE_TRACE("argv[%d] = %s\n", i, argv[i]);
337 TempStr = HeapReAlloc(GetProcessHeap(), 0, Transforms, HeapSize(GetProcessHeap(), 0, Transforms)+strlen(argv[i])+1);
338 if(!TempStr)
340 WINE_ERR("Out of memory!\n");
341 ExitProcess(1);
343 Transforms = TempStr;
344 strcat(Transforms, argv[i]);
345 strcat(Transforms, ";");
347 else if(!strncasecmp(argv[i], "TRANSFORMS=", 11))
349 TempStr = HeapReAlloc(GetProcessHeap(), 0, Transforms, HeapSize(GetProcessHeap(), 0, Transforms)+strlen(argv[i])+1-11);
350 if(!TempStr)
352 WINE_ERR("Out of memory!\n");
353 ExitProcess(1);
355 Transforms = TempStr;
356 strcat(Transforms, argv[i]+11);
357 strcat(Transforms, ";");
359 else if(!strcasecmp(argv[i], "/g"))
361 i++;
362 if(i >= argc)
363 ShowUsage(1);
364 WINE_TRACE("argv[%d] = %s\n", i, argv[i]);
365 Language = strtol(argv[i], NULL, 0);
367 else if(!strncasecmp(argv[i], "/l", 2))
369 i++;
370 if(i >= argc)
371 ShowUsage(1);
372 WINE_TRACE("argv[%d] = %s\n", i, argv[i]);
373 WINE_FIXME("Logging not yet implemented\n");
374 ExitProcess(1);
376 else if(!strcasecmp(argv[i], "/p"))
378 i++;
379 if(i >= argc)
380 ShowUsage(1);
381 WINE_TRACE("argv[%d] = %s\n", i, argv[i]);
382 WINE_FIXME("Patching not yet implemented\n");
383 ExitProcess(1);
385 else if(!strncasecmp(argv[i], "/q", 2))
387 if(strlen(argv[i]) == 2 || !strcasecmp(argv[i]+2, "n"))
389 InstallUILevel = INSTALLUILEVEL_NONE;
391 else if(!strcasecmp(argv[i]+2, "b"))
393 InstallUILevel = INSTALLUILEVEL_BASIC;
395 else if(!strcasecmp(argv[i]+2, "r"))
397 InstallUILevel = INSTALLUILEVEL_REDUCED;
399 else if(!strcasecmp(argv[i]+2, "f"))
401 InstallUILevel = INSTALLUILEVEL_FULL|INSTALLUILEVEL_ENDDIALOG;
403 else if(!strcasecmp(argv[i]+2, "n+"))
405 InstallUILevel = INSTALLUILEVEL_NONE|INSTALLUILEVEL_ENDDIALOG;
407 else if(!strcasecmp(argv[i]+2, "b+"))
409 InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_ENDDIALOG;
411 else if(!strcasecmp(argv[i]+2, "b-"))
413 InstallUILevel = INSTALLUILEVEL_BASIC|INSTALLUILEVEL_PROGRESSONLY;
415 else
417 fprintf(stderr, "Unknown option \"%s\" for UI level\n", argv[i]+2);
419 retInstallUILevel = MsiSetInternalUI(InstallUILevel, NULL);
420 if(retInstallUILevel == INSTALLUILEVEL_NOCHANGE)
422 fprintf(stderr, "Setting the UI level to 0x%x failed.\n", InstallUILevel);
423 ExitProcess(1);
426 else if(!strcasecmp(argv[i], "/y"))
428 FunctionDllRegisterServer = TRUE;
429 i++;
430 if(i >= argc)
431 ShowUsage(1);
432 WINE_TRACE("argv[%d] = %s\n", i, argv[i]);
433 DllName = argv[i];
435 else if(!strcasecmp(argv[i], "/z"))
437 FunctionDllUnregisterServer = TRUE;
438 i++;
439 if(i >= argc)
440 ShowUsage(1);
441 WINE_TRACE("argv[%d] = %s\n", i, argv[i]);
442 DllName = argv[i];
444 else if(!strcasecmp(argv[i], "/h") || !strcasecmp(argv[i], "/?"))
446 ShowUsage(0);
450 if(Properties[strlen(Properties)-1] == ' ')
452 Properties[strlen(Properties)-1] = 0;
453 TempStr = HeapReAlloc(GetProcessHeap(), 0, Properties, HeapSize(GetProcessHeap(), 0, Properties)-1);
454 if(!TempStr)
456 fprintf(stderr, "Out of memory!\n");
457 ExitProcess(1);
459 Properties = TempStr;
461 if(Transforms[strlen(Transforms)-1] == ';')
463 Transforms[strlen(Transforms)-1] = 0;
464 TempStr = HeapReAlloc(GetProcessHeap(), 0, Transforms, HeapSize(GetProcessHeap(), 0, Transforms)-1);
465 if(!TempStr)
467 fprintf(stderr, "Out of memory!\n");
468 ExitProcess(1);
470 Transforms = TempStr;
473 if(FunctionInstall)
475 if(GotProductCode)
477 WINE_FIXME("Product code treatment not implemented yet\n");
478 ExitProcess(1);
480 else
482 if(MsiInstallProductA(PackageName, Properties) != ERROR_SUCCESS)
484 fprintf(stderr, "Installation of %s (%s) failed.\n", PackageName, Properties);
485 ExitProcess(1);
489 else if(FunctionRepair)
491 if(GotProductCode)
493 WINE_FIXME("Product code treatment not implemented yet\n");
494 ExitProcess(1);
496 else
498 if(MsiReinstallProductA(PackageName, RepairMode) != ERROR_SUCCESS)
500 fprintf(stderr, "Repair of %s (0x%08lx) failed.\n", PackageName, RepairMode);
501 ExitProcess(1);
505 else if(FunctionAdvertise)
507 if(MsiAdvertiseProductA(PackageName, (LPSTR) AdvertiseMode, Transforms, Language) != ERROR_SUCCESS)
509 fprintf(stderr, "Advertising of %s (%lu, %s, 0x%04x) failed.\n", PackageName, AdvertiseMode, Transforms, Language);
510 ExitProcess(1);
513 else if(FunctionDllRegisterServer)
515 DllRegisterServer(DllName);
517 else if(FunctionDllUnregisterServer)
519 DllUnregisterServer(DllName);
521 else
522 ShowUsage(1);
524 return 0;