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
[] =
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
)
42 ExitProcess(ExitCode
);
45 static BOOL
GetProductCode(LPCSTR str
, LPGUID guid
)
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
);
63 static VOID
*LoadProc(LPCSTR DllName
, LPCSTR ProcName
, HMODULE
* DllHandle
)
67 *DllHandle
= LoadLibraryExA(DllName
, NULL
, LOAD_WITH_ALTERED_SEARCH_PATH
);
70 fprintf(stderr
, "Unable to load dll %s\n", DllName
);
73 proc
= (VOID
*) GetProcAddress(*DllHandle
, ProcName
);
76 fprintf(stderr
, "Dll %s does not implement function %s\n", DllName
, ProcName
);
77 FreeLibrary(*DllHandle
);
84 static void DllRegisterServer(LPCSTR DllName
)
87 DLLREGISTERSERVER pfDllRegisterServer
= NULL
;
88 HMODULE DllHandle
= NULL
;
90 pfDllRegisterServer
= LoadProc(DllName
, "DllRegisterServer", &DllHandle
);
92 hr
= pfDllRegisterServer();
95 fprintf(stderr
, "Failed to register dll %s\n", DllName
);
98 printf("Successfully registered dll %s\n", DllName
);
100 FreeLibrary(DllHandle
);
103 static void DllUnregisterServer(LPCSTR DllName
)
106 DLLUNREGISTERSERVER pfDllUnregisterServer
= NULL
;
107 HMODULE DllHandle
= NULL
;
109 pfDllUnregisterServer
= LoadProc(DllName
, "DllUnregisterServer", &DllHandle
);
111 hr
= pfDllUnregisterServer();
114 fprintf(stderr
, "Failed to unregister dll %s\n", DllName
);
117 printf("Successfully unregistered dll %s\n", DllName
);
119 FreeLibrary(DllHandle
);
122 int main(int argc
, char *argv
[])
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);
143 INSTALLUILEVEL InstallUILevel
= 0, retInstallUILevel
;
145 LPSTR DllName
= NULL
;
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
;
160 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
161 GotProductCode
= GetProductCode(argv
[i
], ProductCode
);
164 HeapFree(GetProcessHeap(), 0, ProductCode
);
166 PackageName
= argv
[i
];
169 else if(!strcasecmp(argv
[i
], "/a"))
171 FunctionInstall
= TRUE
;
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
));
180 WINE_ERR("Out of memory!\n");
183 Properties
= TempStr
;
184 strcat(Properties
, ActionAdmin
);
186 else if(!strncasecmp(argv
[i
], "/f", 2))
189 int len
= strlen(argv
[i
]);
190 FunctionRepair
= TRUE
;
191 for(j
= 2; j
< len
; j
++)
197 RepairMode
|= REINSTALLMODE_FILEMISSING
;
201 RepairMode
|= REINSTALLMODE_FILEOLDERVERSION
;
205 RepairMode
|= REINSTALLMODE_FILEEQUALVERSION
;
209 RepairMode
|= REINSTALLMODE_FILEEXACT
;
213 RepairMode
|= REINSTALLMODE_FILEVERIFY
;
217 RepairMode
|= REINSTALLMODE_FILEREPLACE
;
221 RepairMode
|= REINSTALLMODE_USERDATA
;
225 RepairMode
|= REINSTALLMODE_MACHINEDATA
;
229 RepairMode
|= REINSTALLMODE_SHORTCUT
;
233 RepairMode
|= REINSTALLMODE_PACKAGE
;
236 fprintf(stderr
, "Unknown option \"%c\" in Repair mode\n", argv
[i
][j
]);
242 RepairMode
= REINSTALLMODE_FILEMISSING
|
243 REINSTALLMODE_FILEEQUALVERSION
|
244 REINSTALLMODE_FILEVERIFY
|
245 REINSTALLMODE_MACHINEDATA
|
246 REINSTALLMODE_SHORTCUT
;
251 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
252 GotProductCode
= GetProductCode(argv
[i
], ProductCode
);
255 HeapFree(GetProcessHeap(), 0, ProductCode
);
257 PackageName
= argv
[i
];
260 else if(!strcasecmp(argv
[i
], "/x"))
262 FunctionInstall
= TRUE
;
266 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
267 GotProductCode
= GetProductCode(argv
[i
], ProductCode
);
270 HeapFree(GetProcessHeap(), 0, ProductCode
);
272 PackageName
= argv
[i
];
274 TempStr
= HeapReAlloc(GetProcessHeap(), 0, Properties
, HeapSize(GetProcessHeap(), 0, Properties
)+strlen(RemoveAll
));
277 WINE_ERR("Out of memory!\n");
280 Properties
= TempStr
;
281 strcat(Properties
, RemoveAll
);
283 else if(!strncasecmp(argv
[i
], "/j", 2))
286 int len
= strlen(argv
[i
]);
287 FunctionAdvertise
= TRUE
;
288 for(j
= 2; j
< len
; j
++)
294 AdvertiseMode
= ADVERTISEFLAGS_USERASSIGN
;
298 AdvertiseMode
= ADVERTISEFLAGS_MACHINEASSIGN
;
301 fprintf(stderr
, "Unknown option \"%c\" in Advertise mode\n", argv
[i
][j
]);
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
;
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
;
328 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
329 PackageName
= argv
[i
];
331 else if(!strcasecmp(argv
[i
], "/t"))
336 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
337 TempStr
= HeapReAlloc(GetProcessHeap(), 0, Transforms
, HeapSize(GetProcessHeap(), 0, Transforms
)+strlen(argv
[i
])+1);
340 WINE_ERR("Out of memory!\n");
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);
352 WINE_ERR("Out of memory!\n");
355 Transforms
= TempStr
;
356 strcat(Transforms
, argv
[i
]+11);
357 strcat(Transforms
, ";");
359 else if(!strcasecmp(argv
[i
], "/g"))
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))
372 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
373 WINE_FIXME("Logging not yet implemented\n");
376 else if(!strcasecmp(argv
[i
], "/p"))
381 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
382 WINE_FIXME("Patching not yet implemented\n");
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
;
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
);
426 else if(!strcasecmp(argv
[i
], "/y"))
428 FunctionDllRegisterServer
= TRUE
;
432 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
435 else if(!strcasecmp(argv
[i
], "/z"))
437 FunctionDllUnregisterServer
= TRUE
;
441 WINE_TRACE("argv[%d] = %s\n", i
, argv
[i
]);
444 else if(!strcasecmp(argv
[i
], "/h") || !strcasecmp(argv
[i
], "/?"))
450 if(Properties
[strlen(Properties
)-1] == ' ')
452 Properties
[strlen(Properties
)-1] = 0;
453 TempStr
= HeapReAlloc(GetProcessHeap(), 0, Properties
, HeapSize(GetProcessHeap(), 0, Properties
)-1);
456 fprintf(stderr
, "Out of memory!\n");
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);
467 fprintf(stderr
, "Out of memory!\n");
470 Transforms
= TempStr
;
477 WINE_FIXME("Product code treatment not implemented yet\n");
482 if(MsiInstallProductA(PackageName
, Properties
) != ERROR_SUCCESS
)
484 fprintf(stderr
, "Installation of %s (%s) failed.\n", PackageName
, Properties
);
489 else if(FunctionRepair
)
493 WINE_FIXME("Product code treatment not implemented yet\n");
498 if(MsiReinstallProductA(PackageName
, RepairMode
) != ERROR_SUCCESS
)
500 fprintf(stderr
, "Repair of %s (0x%08lx) failed.\n", PackageName
, RepairMode
);
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
);
513 else if(FunctionDllRegisterServer
)
515 DllRegisterServer(DllName
);
517 else if(FunctionDllUnregisterServer
)
519 DllUnregisterServer(DllName
);