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
;
182 BOOL FunctionRegServer
= FALSE
;
183 BOOL FunctionUnregServer
= FALSE
;
185 BOOL GotProductCode
= FALSE
;
186 LPCSTR PackageName
= NULL
;
187 LPGUID ProductCode
= HeapAlloc(GetProcessHeap(), 0, sizeof(GUID
));
188 LPSTR Properties
= HeapAlloc(GetProcessHeap(), 0, 1);
190 DWORD RepairMode
= 0;
192 DWORD AdvertiseMode
= 0;
193 LPSTR Transforms
= HeapAlloc(GetProcessHeap(), 0, 1);
197 LPSTR LogFileName
= NULL
;
198 DWORD LogAttributes
= 0;
200 LPSTR PatchFileName
= NULL
;
201 INSTALLTYPE InstallType
= INSTALLTYPE_DEFAULT
;
203 INSTALLUILEVEL InstallUILevel
= 0, retInstallUILevel
;
205 LPSTR DllName
= NULL
;
210 for(i
= 1; i
< argc
; i
++)
212 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
214 if (!strcasecmp(argv
[i
], "/regserver"))
216 FunctionRegServer
= TRUE
;
218 else if (!strcasecmp(argv
[i
], "/unregserver") || !strcasecmp(argv
[i
], "/unregister"))
220 FunctionUnregServer
= TRUE
;
222 else if(!strncasecmp(argv
[i
], "/i", 2))
224 char *argvi
= argv
[i
];
225 FunctionInstall
= TRUE
;
226 if(strlen(argvi
) > 2)
232 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
235 GotProductCode
= GetProductCode(argvi
, &PackageName
, &ProductCode
);
237 else if(!strcasecmp(argv
[i
], "/a"))
239 FunctionInstall
= TRUE
;
240 FunctionInstallAdmin
= TRUE
;
241 InstallType
= INSTALLTYPE_NETWORK_IMAGE
;
245 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
246 PackageName
= argv
[i
];
247 StringListAppend(&Properties
, ActionAdmin
);
249 else if(!strncasecmp(argv
[i
], "/f", 2))
252 int len
= strlen(argv
[i
]);
253 FunctionRepair
= TRUE
;
254 for(j
= 2; j
< len
; j
++)
260 RepairMode
|= REINSTALLMODE_FILEMISSING
;
264 RepairMode
|= REINSTALLMODE_FILEOLDERVERSION
;
268 RepairMode
|= REINSTALLMODE_FILEEQUALVERSION
;
272 RepairMode
|= REINSTALLMODE_FILEEXACT
;
276 RepairMode
|= REINSTALLMODE_FILEVERIFY
;
280 RepairMode
|= REINSTALLMODE_FILEREPLACE
;
284 RepairMode
|= REINSTALLMODE_USERDATA
;
288 RepairMode
|= REINSTALLMODE_MACHINEDATA
;
292 RepairMode
|= REINSTALLMODE_SHORTCUT
;
296 RepairMode
|= REINSTALLMODE_PACKAGE
;
299 fprintf(stderr
, "Unknown option \"%c\" in Repair mode\n", argv
[i
][j
]);
305 RepairMode
= REINSTALLMODE_FILEMISSING
|
306 REINSTALLMODE_FILEEQUALVERSION
|
307 REINSTALLMODE_FILEVERIFY
|
308 REINSTALLMODE_MACHINEDATA
|
309 REINSTALLMODE_SHORTCUT
;
314 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
315 GotProductCode
= GetProductCode(argv
[i
], &PackageName
, &ProductCode
);
317 else if(!strcasecmp(argv
[i
], "/x"))
319 FunctionInstall
= TRUE
;
323 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
324 GotProductCode
= GetProductCode(argv
[i
], &PackageName
, &ProductCode
);
325 StringListAppend(&Properties
, RemoveAll
);
327 else if(!strncasecmp(argv
[i
], "/j", 2))
330 int len
= strlen(argv
[i
]);
331 FunctionAdvertise
= TRUE
;
332 for(j
= 2; j
< len
; j
++)
338 AdvertiseMode
= ADVERTISEFLAGS_USERASSIGN
;
342 AdvertiseMode
= ADVERTISEFLAGS_MACHINEASSIGN
;
345 fprintf(stderr
, "Unknown option \"%c\" in Advertise mode\n", argv
[i
][j
]);
352 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
353 PackageName
= argv
[i
];
355 else if(!strcasecmp(argv
[i
], "u"))
357 FunctionAdvertise
= TRUE
;
358 AdvertiseMode
= ADVERTISEFLAGS_USERASSIGN
;
362 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
363 PackageName
= argv
[i
];
365 else if(!strcasecmp(argv
[i
], "m"))
367 FunctionAdvertise
= TRUE
;
368 AdvertiseMode
= ADVERTISEFLAGS_MACHINEASSIGN
;
372 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
373 PackageName
= argv
[i
];
375 else if(!strcasecmp(argv
[i
], "/t"))
380 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
381 StringListAppend(&Transforms
, argv
[i
]);
382 StringListAppend(&Transforms
, ";");
384 else if(!strncasecmp(argv
[i
], "TRANSFORMS=", 11))
386 StringListAppend(&Transforms
, argv
[i
]+11);
387 StringListAppend(&Transforms
, ";");
389 else if(!strcasecmp(argv
[i
], "/g"))
394 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
395 Language
= strtol(argv
[i
], NULL
, 0);
397 else if(!strncasecmp(argv
[i
], "/l", 2))
400 int len
= strlen(argv
[i
]);
401 for(j
= 2; j
< len
; j
++)
407 LogMode
|= INSTALLLOGMODE_INFO
;
411 LogMode
|= INSTALLLOGMODE_WARNING
;
415 LogMode
|= INSTALLLOGMODE_ERROR
;
419 LogMode
|= INSTALLLOGMODE_ACTIONSTART
;
423 LogMode
|= INSTALLLOGMODE_ACTIONDATA
;
427 LogMode
|= INSTALLLOGMODE_USER
;
431 LogMode
|= INSTALLLOGMODE_COMMONDATA
;
435 LogMode
|= INSTALLLOGMODE_FATALEXIT
;
439 LogMode
|= INSTALLLOGMODE_OUTOFDISKSPACE
;
443 LogMode
|= INSTALLLOGMODE_PROPERTYDUMP
;
447 LogMode
|= INSTALLLOGMODE_VERBOSE
;
450 LogMode
= INSTALLLOGMODE_FATALEXIT
|
451 INSTALLLOGMODE_ERROR
|
452 INSTALLLOGMODE_WARNING
|
453 INSTALLLOGMODE_USER
|
454 INSTALLLOGMODE_INFO
|
455 INSTALLLOGMODE_RESOLVESOURCE
|
456 INSTALLLOGMODE_OUTOFDISKSPACE
|
457 INSTALLLOGMODE_ACTIONSTART
|
458 INSTALLLOGMODE_ACTIONDATA
|
459 INSTALLLOGMODE_COMMONDATA
|
460 INSTALLLOGMODE_PROPERTYDUMP
|
461 INSTALLLOGMODE_PROGRESS
|
462 INSTALLLOGMODE_INITIALIZE
|
463 INSTALLLOGMODE_TERMINATE
|
464 INSTALLLOGMODE_SHOWDIALOG
;
467 LogAttributes
|= INSTALLLOGATTRIBUTES_APPEND
;
470 LogAttributes
|= INSTALLLOGATTRIBUTES_FLUSHEACHLINE
;
479 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
480 LogFileName
= argv
[i
];
481 if(MsiEnableLogA(LogMode
, LogFileName
, LogAttributes
) != ERROR_SUCCESS
)
483 fprintf(stderr
, "Logging in %s (0x%08lx, %lu) failed\n", LogFileName
, LogMode
, LogAttributes
);
487 else if(!strcasecmp(argv
[i
], "/p"))
489 FunctionPatch
= TRUE
;
493 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
494 PatchFileName
= argv
[i
];
496 else if(!strncasecmp(argv
[i
], "/q", 2))
498 if(strlen(argv
[i
]) == 2 || !strcasecmp(argv
[i
]+2, "n"))
500 InstallUILevel
= INSTALLUILEVEL_NONE
;
502 else if(!strcasecmp(argv
[i
]+2, "b"))
504 InstallUILevel
= INSTALLUILEVEL_BASIC
;
506 else if(!strcasecmp(argv
[i
]+2, "r"))
508 InstallUILevel
= INSTALLUILEVEL_REDUCED
;
510 else if(!strcasecmp(argv
[i
]+2, "f"))
512 InstallUILevel
= INSTALLUILEVEL_FULL
|INSTALLUILEVEL_ENDDIALOG
;
514 else if(!strcasecmp(argv
[i
]+2, "n+"))
516 InstallUILevel
= INSTALLUILEVEL_NONE
|INSTALLUILEVEL_ENDDIALOG
;
518 else if(!strcasecmp(argv
[i
]+2, "b+"))
520 InstallUILevel
= INSTALLUILEVEL_BASIC
|INSTALLUILEVEL_ENDDIALOG
;
522 else if(!strcasecmp(argv
[i
]+2, "b-"))
524 InstallUILevel
= INSTALLUILEVEL_BASIC
|INSTALLUILEVEL_PROGRESSONLY
;
528 fprintf(stderr
, "Unknown option \"%s\" for UI level\n", argv
[i
]+2);
530 retInstallUILevel
= MsiSetInternalUI(InstallUILevel
, NULL
);
531 if(retInstallUILevel
== INSTALLUILEVEL_NOCHANGE
)
533 fprintf(stderr
, "Setting the UI level to 0x%x failed.\n", InstallUILevel
);
537 else if(!strcasecmp(argv
[i
], "/y"))
539 FunctionDllRegisterServer
= TRUE
;
543 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
546 else if(!strcasecmp(argv
[i
], "/z"))
548 FunctionDllUnregisterServer
= TRUE
;
552 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
555 else if(!strcasecmp(argv
[i
], "/h") || !strcasecmp(argv
[i
], "/?"))
559 else if(strchr(argv
[i
], '='))
561 StringListAppend(&Properties
, argv
[i
]);
562 StringListAppend(&Properties
, " ");
566 FunctionInstall
= TRUE
;
567 GotProductCode
= GetProductCode(argv
[i
], &PackageName
, &ProductCode
);
571 StringCompareRemoveLast(Properties
, ' ');
572 StringCompareRemoveLast(Transforms
, ';');
574 if(FunctionInstallAdmin
&& FunctionPatch
)
575 FunctionInstall
= FALSE
;
581 WINE_FIXME("Product code treatment not implemented yet\n");
586 if(MsiInstallProductA(PackageName
, Properties
) != ERROR_SUCCESS
)
588 fprintf(stderr
, "Installation of %s (%s) failed.\n", PackageName
, Properties
);
593 else if(FunctionRepair
)
597 WINE_FIXME("Product code treatment not implemented yet\n");
602 if(MsiReinstallProductA(PackageName
, RepairMode
) != ERROR_SUCCESS
)
604 fprintf(stderr
, "Repair of %s (0x%08lx) failed.\n", PackageName
, RepairMode
);
609 else if(FunctionAdvertise
)
611 if(MsiAdvertiseProductA(PackageName
, (LPSTR
) AdvertiseMode
, Transforms
, Language
) != ERROR_SUCCESS
)
613 fprintf(stderr
, "Advertising of %s (%lu, %s, 0x%04x) failed.\n", PackageName
, AdvertiseMode
, Transforms
, Language
);
617 else if(FunctionPatch
)
619 if(MsiApplyPatchA(PatchFileName
, PackageName
, InstallType
, Properties
) != ERROR_SUCCESS
)
621 fprintf(stderr
, "Patching with %s (%s, %d, %s)\n", PatchFileName
, PackageName
, InstallType
, Properties
);
625 else if(FunctionDllRegisterServer
)
627 DllRegisterServer(DllName
);
629 else if(FunctionDllUnregisterServer
)
631 DllUnregisterServer(DllName
);
633 else if (FunctionRegServer
)
635 WINE_FIXME( "/regserver not implemented yet, ignoring\n" );
637 else if (FunctionUnregServer
)
639 WINE_FIXME( "/unregserver not implemented yet, ignoring\n" );