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
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(msiexec
);
32 static const char UsageStr
[] =
34 " Install a product:\n"
35 " msiexec {package|productcode} [property]\n"
36 " msiexec /i {package|productcode} [property]\n"
37 " msiexec /a package [property]\n"
38 " Repair an installation:\n"
39 " msiexec /f[p|o|e|d|c|a|u|m|s|v] {package|productcode}\n"
40 " Uninstall a product:\n"
41 " msiexec /x {package|productcode} [property]\n"
42 " Advertise a product:\n"
43 " msiexec /j[u|m] package [/t transform] [/g languageid]\n"
44 " msiexec {u|m} package [/t transform] [/g languageid]\n"
46 " msiexec /p patchpackage [property]\n"
47 " msiexec /p patchpackage /a package [property]\n"
48 " Modifiers for above operations:\n"
49 " msiexec /l[*][i|w|e|a|r|u|c|m|o|p|v|][+|!] logfile\n"
50 " msiexec /q{|n|b|r|f|n+|b+|b-}\n"
51 " Register a module:\n"
52 " msiexec /y module\n"
53 " Unregister a module:\n"
54 " msiexec /z module\n"
55 " Display usage and copyright:\n"
57 "NOTE: Product code on commandline unimplemented as of yet\n"
59 "Copyright 2004 Vincent Béron\n";
61 static const char ActionAdmin
[] = "ACTION=ADMIN ";
62 static const char RemoveAll
[] = "REMOVE=ALL ";
64 static void ShowUsage(int ExitCode
)
67 ExitProcess(ExitCode
);
70 static BOOL
GetProductCode(LPCSTR str
, LPCSTR
*PackageName
, LPGUID
*ProductCode
)
78 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, wstr
, 0);
79 wstr
= HeapAlloc(GetProcessHeap(), 0, (len
+1)*sizeof(WCHAR
));
80 ret
= (CLSIDFromString(wstr
, *ProductCode
) == NOERROR
);
81 HeapFree(GetProcessHeap(), 0, wstr
);
87 HeapFree(GetProcessHeap(), 0, *ProductCode
);
95 static VOID
StringListAppend(LPSTR
*StringList
, LPCSTR StringAppend
)
97 LPSTR TempStr
= HeapReAlloc(GetProcessHeap(), 0, *StringList
, HeapSize(GetProcessHeap(), 0, *StringList
)+strlen(StringAppend
));
100 WINE_ERR("Out of memory!\n");
103 *StringList
= TempStr
;
104 strcat(*StringList
, StringAppend
);
107 static VOID
StringCompareRemoveLast(LPSTR String
, CHAR character
)
109 int len
= strlen(String
);
110 if(len
&& String
[len
-1] == character
) String
[len
-1] = 0;
113 static VOID
*LoadProc(LPCSTR DllName
, LPCSTR ProcName
, HMODULE
* DllHandle
)
117 *DllHandle
= LoadLibraryExA(DllName
, NULL
, LOAD_WITH_ALTERED_SEARCH_PATH
);
120 fprintf(stderr
, "Unable to load dll %s\n", DllName
);
123 proc
= (VOID
*) GetProcAddress(*DllHandle
, ProcName
);
126 fprintf(stderr
, "Dll %s does not implement function %s\n", DllName
, ProcName
);
127 FreeLibrary(*DllHandle
);
134 static void DllRegisterServer(LPCSTR DllName
)
137 DLLREGISTERSERVER pfDllRegisterServer
= NULL
;
138 HMODULE DllHandle
= NULL
;
140 pfDllRegisterServer
= LoadProc(DllName
, "DllRegisterServer", &DllHandle
);
142 hr
= pfDllRegisterServer();
145 fprintf(stderr
, "Failed to register dll %s\n", DllName
);
148 printf("Successfully registered dll %s\n", DllName
);
150 FreeLibrary(DllHandle
);
153 static void DllUnregisterServer(LPCSTR DllName
)
156 DLLUNREGISTERSERVER pfDllUnregisterServer
= NULL
;
157 HMODULE DllHandle
= NULL
;
159 pfDllUnregisterServer
= LoadProc(DllName
, "DllUnregisterServer", &DllHandle
);
161 hr
= pfDllUnregisterServer();
164 fprintf(stderr
, "Failed to unregister dll %s\n", DllName
);
167 printf("Successfully unregistered dll %s\n", DllName
);
169 FreeLibrary(DllHandle
);
172 int main(int argc
, char *argv
[])
175 BOOL FunctionInstall
= FALSE
;
176 BOOL FunctionInstallAdmin
= FALSE
;
177 BOOL FunctionRepair
= FALSE
;
178 BOOL FunctionAdvertise
= FALSE
;
179 BOOL FunctionPatch
= FALSE
;
180 BOOL FunctionDllRegisterServer
= FALSE
;
181 BOOL FunctionDllUnregisterServer
= FALSE
;
183 BOOL GotProductCode
= FALSE
;
184 LPCSTR PackageName
= NULL
;
185 LPGUID ProductCode
= HeapAlloc(GetProcessHeap(), 0, sizeof(GUID
));
186 LPSTR Properties
= HeapAlloc(GetProcessHeap(), 0, 1);
188 DWORD RepairMode
= 0;
190 DWORD AdvertiseMode
= 0;
191 LPSTR Transforms
= HeapAlloc(GetProcessHeap(), 0, 1);
195 LPSTR LogFileName
= NULL
;
196 DWORD LogAttributes
= 0;
198 LPSTR PatchFileName
= NULL
;
199 INSTALLTYPE InstallType
= INSTALLTYPE_DEFAULT
;
201 INSTALLUILEVEL InstallUILevel
= 0, retInstallUILevel
;
203 LPSTR DllName
= NULL
;
208 for(i
= 1; i
< argc
; i
++)
210 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
212 if(!strcasecmp(argv
[i
], "/i"))
214 FunctionInstall
= TRUE
;
218 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
219 GotProductCode
= GetProductCode(argv
[i
], &PackageName
, &ProductCode
);
221 else if(!strcasecmp(argv
[i
], "/a"))
223 FunctionInstall
= TRUE
;
224 FunctionInstallAdmin
= TRUE
;
225 InstallType
= INSTALLTYPE_NETWORK_IMAGE
;
229 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
230 PackageName
= argv
[i
];
231 StringListAppend(&Properties
, ActionAdmin
);
233 else if(!strncasecmp(argv
[i
], "/f", 2))
236 int len
= strlen(argv
[i
]);
237 FunctionRepair
= TRUE
;
238 for(j
= 2; j
< len
; j
++)
244 RepairMode
|= REINSTALLMODE_FILEMISSING
;
248 RepairMode
|= REINSTALLMODE_FILEOLDERVERSION
;
252 RepairMode
|= REINSTALLMODE_FILEEQUALVERSION
;
256 RepairMode
|= REINSTALLMODE_FILEEXACT
;
260 RepairMode
|= REINSTALLMODE_FILEVERIFY
;
264 RepairMode
|= REINSTALLMODE_FILEREPLACE
;
268 RepairMode
|= REINSTALLMODE_USERDATA
;
272 RepairMode
|= REINSTALLMODE_MACHINEDATA
;
276 RepairMode
|= REINSTALLMODE_SHORTCUT
;
280 RepairMode
|= REINSTALLMODE_PACKAGE
;
283 fprintf(stderr
, "Unknown option \"%c\" in Repair mode\n", argv
[i
][j
]);
289 RepairMode
= REINSTALLMODE_FILEMISSING
|
290 REINSTALLMODE_FILEEQUALVERSION
|
291 REINSTALLMODE_FILEVERIFY
|
292 REINSTALLMODE_MACHINEDATA
|
293 REINSTALLMODE_SHORTCUT
;
298 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
299 GotProductCode
= GetProductCode(argv
[i
], &PackageName
, &ProductCode
);
301 else if(!strcasecmp(argv
[i
], "/x"))
303 FunctionInstall
= TRUE
;
307 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
308 GotProductCode
= GetProductCode(argv
[i
], &PackageName
, &ProductCode
);
309 StringListAppend(&Properties
, RemoveAll
);
311 else if(!strncasecmp(argv
[i
], "/j", 2))
314 int len
= strlen(argv
[i
]);
315 FunctionAdvertise
= TRUE
;
316 for(j
= 2; j
< len
; j
++)
322 AdvertiseMode
= ADVERTISEFLAGS_USERASSIGN
;
326 AdvertiseMode
= ADVERTISEFLAGS_MACHINEASSIGN
;
329 fprintf(stderr
, "Unknown option \"%c\" in Advertise mode\n", argv
[i
][j
]);
336 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
337 PackageName
= argv
[i
];
339 else if(!strcasecmp(argv
[i
], "u"))
341 FunctionAdvertise
= TRUE
;
342 AdvertiseMode
= ADVERTISEFLAGS_USERASSIGN
;
346 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
347 PackageName
= argv
[i
];
349 else if(!strcasecmp(argv
[i
], "m"))
351 FunctionAdvertise
= TRUE
;
352 AdvertiseMode
= ADVERTISEFLAGS_MACHINEASSIGN
;
356 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
357 PackageName
= argv
[i
];
359 else if(!strcasecmp(argv
[i
], "/t"))
364 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
365 StringListAppend(&Transforms
, argv
[i
]);
366 StringListAppend(&Transforms
, ";");
368 else if(!strncasecmp(argv
[i
], "TRANSFORMS=", 11))
370 StringListAppend(&Transforms
, argv
[i
]+11);
371 StringListAppend(&Transforms
, ";");
373 else if(!strcasecmp(argv
[i
], "/g"))
378 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
379 Language
= strtol(argv
[i
], NULL
, 0);
381 else if(!strncasecmp(argv
[i
], "/l", 2))
384 int len
= strlen(argv
[i
]);
385 for(j
= 2; j
< len
; j
++)
391 LogMode
|= INSTALLLOGMODE_INFO
;
395 LogMode
|= INSTALLLOGMODE_WARNING
;
399 LogMode
|= INSTALLLOGMODE_ERROR
;
403 LogMode
|= INSTALLLOGMODE_ACTIONSTART
;
407 LogMode
|= INSTALLLOGMODE_ACTIONDATA
;
411 LogMode
|= INSTALLLOGMODE_USER
;
415 LogMode
|= INSTALLLOGMODE_COMMONDATA
;
419 LogMode
|= INSTALLLOGMODE_FATALEXIT
;
423 LogMode
|= INSTALLLOGMODE_OUTOFDISKSPACE
;
427 LogMode
|= INSTALLLOGMODE_PROPERTYDUMP
;
431 LogMode
|= INSTALLLOGMODE_VERBOSE
;
434 LogMode
= INSTALLLOGMODE_FATALEXIT
|
435 INSTALLLOGMODE_ERROR
|
436 INSTALLLOGMODE_WARNING
|
437 INSTALLLOGMODE_USER
|
438 INSTALLLOGMODE_INFO
|
439 INSTALLLOGMODE_RESOLVESOURCE
|
440 INSTALLLOGMODE_OUTOFDISKSPACE
|
441 INSTALLLOGMODE_ACTIONSTART
|
442 INSTALLLOGMODE_ACTIONDATA
|
443 INSTALLLOGMODE_COMMONDATA
|
444 INSTALLLOGMODE_PROPERTYDUMP
|
445 INSTALLLOGMODE_PROGRESS
|
446 INSTALLLOGMODE_INITIALIZE
|
447 INSTALLLOGMODE_TERMINATE
|
448 INSTALLLOGMODE_SHOWDIALOG
;
451 LogAttributes
|= INSTALLLOGATTRIBUTES_APPEND
;
454 LogAttributes
|= INSTALLLOGATTRIBUTES_FLUSHEACHLINE
;
463 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
464 LogFileName
= argv
[i
];
465 if(MsiEnableLogA(LogMode
, LogFileName
, LogAttributes
) != ERROR_SUCCESS
)
467 fprintf(stderr
, "Logging in %s (0x%08lx, %lu) failed\n", LogFileName
, LogMode
, LogAttributes
);
471 else if(!strcasecmp(argv
[i
], "/p"))
473 FunctionPatch
= TRUE
;
477 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
478 PatchFileName
= argv
[i
];
480 else if(!strncasecmp(argv
[i
], "/q", 2))
482 if(strlen(argv
[i
]) == 2 || !strcasecmp(argv
[i
]+2, "n"))
484 InstallUILevel
= INSTALLUILEVEL_NONE
;
486 else if(!strcasecmp(argv
[i
]+2, "b"))
488 InstallUILevel
= INSTALLUILEVEL_BASIC
;
490 else if(!strcasecmp(argv
[i
]+2, "r"))
492 InstallUILevel
= INSTALLUILEVEL_REDUCED
;
494 else if(!strcasecmp(argv
[i
]+2, "f"))
496 InstallUILevel
= INSTALLUILEVEL_FULL
|INSTALLUILEVEL_ENDDIALOG
;
498 else if(!strcasecmp(argv
[i
]+2, "n+"))
500 InstallUILevel
= INSTALLUILEVEL_NONE
|INSTALLUILEVEL_ENDDIALOG
;
502 else if(!strcasecmp(argv
[i
]+2, "b+"))
504 InstallUILevel
= INSTALLUILEVEL_BASIC
|INSTALLUILEVEL_ENDDIALOG
;
506 else if(!strcasecmp(argv
[i
]+2, "b-"))
508 InstallUILevel
= INSTALLUILEVEL_BASIC
|INSTALLUILEVEL_PROGRESSONLY
;
512 fprintf(stderr
, "Unknown option \"%s\" for UI level\n", argv
[i
]+2);
514 retInstallUILevel
= MsiSetInternalUI(InstallUILevel
, NULL
);
515 if(retInstallUILevel
== INSTALLUILEVEL_NOCHANGE
)
517 fprintf(stderr
, "Setting the UI level to 0x%x failed.\n", InstallUILevel
);
521 else if(!strcasecmp(argv
[i
], "/y"))
523 FunctionDllRegisterServer
= TRUE
;
527 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
530 else if(!strcasecmp(argv
[i
], "/z"))
532 FunctionDllUnregisterServer
= TRUE
;
536 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
539 else if(!strcasecmp(argv
[i
], "/h") || !strcasecmp(argv
[i
], "/?"))
543 else if(strchr(argv
[i
], '='))
545 StringListAppend(&Properties
, argv
[i
]);
546 StringListAppend(&Properties
, " ");
550 FunctionInstall
= TRUE
;
551 GotProductCode
= GetProductCode(argv
[i
], &PackageName
, &ProductCode
);
555 StringCompareRemoveLast(Properties
, ' ');
556 StringCompareRemoveLast(Transforms
, ';');
558 if(FunctionInstallAdmin
&& FunctionPatch
)
559 FunctionInstall
= FALSE
;
565 WINE_FIXME("Product code treatment not implemented yet\n");
570 if(MsiInstallProductA(PackageName
, Properties
) != ERROR_SUCCESS
)
572 fprintf(stderr
, "Installation of %s (%s) failed.\n", PackageName
, Properties
);
577 else if(FunctionRepair
)
581 WINE_FIXME("Product code treatment not implemented yet\n");
586 if(MsiReinstallProductA(PackageName
, RepairMode
) != ERROR_SUCCESS
)
588 fprintf(stderr
, "Repair of %s (0x%08lx) failed.\n", PackageName
, RepairMode
);
593 else if(FunctionAdvertise
)
595 if(MsiAdvertiseProductA(PackageName
, (LPSTR
) AdvertiseMode
, Transforms
, Language
) != ERROR_SUCCESS
)
597 fprintf(stderr
, "Advertising of %s (%lu, %s, 0x%04x) failed.\n", PackageName
, AdvertiseMode
, Transforms
, Language
);
601 else if(FunctionPatch
)
603 if(MsiApplyPatchA(PatchFileName
, PackageName
, InstallType
, Properties
) != ERROR_SUCCESS
)
605 fprintf(stderr
, "Patching with %s (%s, %d, %s)\n", PatchFileName
, PackageName
, InstallType
, Properties
);
609 else if(FunctionDllRegisterServer
)
611 DllRegisterServer(DllName
);
613 else if(FunctionDllUnregisterServer
)
615 DllUnregisterServer(DllName
);