From 3d5b606ddea7ede27eb2320e2755666bdbed1f33 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Tue, 15 Sep 2015 17:44:33 -0600 Subject: [PATCH] msidb: Add stub tool for manipulating MSI databases. The "Windows SDK Components for Windows Installer Developers" has a command line tool called msidb that is incredibly useful for creating, editing, and exporting MSI installer databases, think of it as winemsibuilder on steroids. This patch series implements much of the functionality of the msidb tool, maintains compatible CLI flags, and the underlying MSI functionality necessary to support these features. Jacek expressed an interest in having these patches resurrected for use by the Gecko build scripts and Austin's VS builds of Valgrind. With this patch series all the existing winemsibuilder functionality is available, plus the ability to drop streams, export the _SummaryInformation table, and export binary streams (Binary/Icon tables). A big feature of the implementation is that it allows you to edit existing installer databases, rather than just creating new ones. Signed-off-by: Erich E. Hoover Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- configure | 3 + configure.ac | 2 + programs/msidb/Makefile.in | 5 ++ programs/msidb/main.c | 153 +++++++++++++++++++++++++++++++++++++ 4 files changed, 163 insertions(+) create mode 100644 programs/msidb/Makefile.in create mode 100644 programs/msidb/main.c diff --git a/configure b/configure index 9988dcddffc..8a07748a67d 100755 --- a/configure +++ b/configure @@ -1715,6 +1715,7 @@ enable_ipconfig enable_lodctr enable_mofcomp enable_mshta +enable_msidb enable_msiexec enable_msinfo32 enable_net @@ -20292,6 +20293,7 @@ wine_fn_config_makefile programs/ipconfig enable_ipconfig wine_fn_config_makefile programs/lodctr enable_lodctr wine_fn_config_makefile programs/mofcomp enable_mofcomp wine_fn_config_makefile programs/mshta enable_mshta +wine_fn_config_makefile programs/msidb enable_msidb wine_fn_config_makefile programs/msiexec enable_msiexec wine_fn_config_makefile programs/msinfo32 enable_msinfo32 wine_fn_config_makefile programs/net enable_net @@ -20443,6 +20445,7 @@ else fonts \ loader/l_intl.nls \ loader/wine.inf \ +programs/msidb/msidb \ programs/msiexec/msiexec \ programs/notepad/notepad \ programs/regedit/regedit \ diff --git a/configure.ac b/configure.ac index 25581a9d670..db8bb6ce09f 100644 --- a/configure.ac +++ b/configure.ac @@ -3938,6 +3938,7 @@ WINE_CONFIG_MAKEFILE(programs/ipconfig) WINE_CONFIG_MAKEFILE(programs/lodctr) WINE_CONFIG_MAKEFILE(programs/mofcomp) WINE_CONFIG_MAKEFILE(programs/mshta) +WINE_CONFIG_MAKEFILE(programs/msidb) WINE_CONFIG_MAKEFILE(programs/msiexec) WINE_CONFIG_MAKEFILE(programs/msinfo32) WINE_CONFIG_MAKEFILE(programs/net) @@ -4106,6 +4107,7 @@ else fonts \ loader/l_intl.nls \ loader/wine.inf \ +programs/msidb/msidb \ programs/msiexec/msiexec \ programs/notepad/notepad \ programs/regedit/regedit \ diff --git a/programs/msidb/Makefile.in b/programs/msidb/Makefile.in new file mode 100644 index 00000000000..bb740416745 --- /dev/null +++ b/programs/msidb/Makefile.in @@ -0,0 +1,5 @@ +MODULE = msidb.exe +APPMODE = -mconsole -municode +IMPORTS = msi + +C_SRCS = main.c diff --git a/programs/msidb/main.c b/programs/msidb/main.c new file mode 100644 index 00000000000..a431fd510be --- /dev/null +++ b/programs/msidb/main.c @@ -0,0 +1,153 @@ +/* + * msidb - command line tool for assembling MSI packages + * + * Copyright 2015 Erich E. Hoover + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include + +#include "wine/debug.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msidb); + +struct msidb_state +{ + WCHAR *database_file; + WCHAR *table_folder; + MSIHANDLE database_handle; + BOOL create_database; +}; + +static void show_usage( void ) +{ + WINE_MESSAGE( + "Usage: msidb [OPTION]...[OPTION]...\n" + "Options:\n" + " -? Show this usage message and exit.\n" + " -c Create database file (instead of opening existing file).\n" + " -d package.msi Path to the database file.\n" + " -f folder Folder in which to open/save the tables.\n" + ); +} + +static int valid_state( struct msidb_state *state ) +{ + if (state->database_file == NULL) + { + FIXME( "GUI operation is not currently supported.\n" ); + return 0; + } + if (state->table_folder == NULL) + { + ERR( "No table folder specified (-f option).\n" ); + show_usage(); + return 0; + } + return 1; +} + +static int process_argument( struct msidb_state *state, int i, int argc, WCHAR *argv[] ) +{ + /* msidb accepts either "-" or "/" style flags */ + if (strlenW(argv[i]) != 2 || (argv[i][0] != '-' && argv[i][0] != '/')) + { + WINE_FIXME( "Table names are not currently supported.\n" ); + show_usage(); + exit( 1 ); + } + switch( argv[i][1] ) + { + case '?': + show_usage(); + exit( 0 ); + case 'c': + state->create_database = TRUE; + return 1; + case 'd': + if (i + 1 >= argc) return 0; + state->database_file = argv[i + 1]; + return 2; + case 'f': + if (i + 1 >= argc) return 0; + state->table_folder = argv[i + 1]; + return 2; + default: + break; + } + show_usage(); + exit( 1 ); +} + +static int open_database( struct msidb_state *state ) +{ + LPCWSTR db_mode = state->create_database ? MSIDBOPEN_CREATE : MSIDBOPEN_TRANSACT; + UINT ret; + + ret = MsiOpenDatabaseW( state->database_file, db_mode, &state->database_handle ); + if (ret != ERROR_SUCCESS) + { + ERR( "Failed to open database '%s', error %d\n", wine_dbgstr_w(state->database_file), ret ); + return 0; + } + return 1; +} + +static void close_database( struct msidb_state *state ) +{ + UINT ret; + + ret = MsiDatabaseCommit( state->database_handle ); + if (ret != ERROR_SUCCESS) + { + ERR( "Failed to commit changes to database.\n" ); + return; + } + ret = MsiCloseHandle( state->database_handle ); + if (ret != ERROR_SUCCESS) + { + WARN( "Failed to close database handle.\n" ); + return; + } +} + +int wmain( int argc, WCHAR *argv[] ) +{ + struct msidb_state state; + int i, n = 1; + + memset( &state, 0x0, sizeof(state) ); + /* process and validate all the command line flags */ + for (i = 1; n && i < argc; i += n) + n = process_argument( &state, i, argc, argv ); + if (!valid_state( &state )) + return 1; + + /* perform the requested operations */ + if (!open_database( &state )) + { + ERR( "Failed to open database '%s'.\n", wine_dbgstr_w(state.database_file) ); + return 1; + } + close_database( &state ); + return 0; +}