Hi,
This is program can be used to test the MSI patch in my previous post. It's probably not clean enough to add to wine at the moment.
Sample queries:
SELECT * FROM _Columns WHERE Table = 'InstallExecuteSequence' SELECT * FROM _Columns SELECT * FROM InstallExecuteSequence ORDER BY Sequence SELECT DISTINCT Number FROM _Columns WHERE Number <> 3
have fun,
Mike
#include "config.h" #include <windows.h> #include <shlwapi.h> #include <stdio.h> #include <string.h> #include <readline/readline.h> #include <readline/history.h> #include <msi.h> #include <msiquery.h> #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(msiquery); #define E( X ) case X: return #X; static const char *error_to_string( UINT error ) { switch( error ) { E(ERROR_SUCCESS) E(ERROR_BAD_QUERY_SYNTAX) E(ERROR_FUNCTION_FAILED) E(ERROR_INVALID_PARAMETER) E(ERROR_CALL_NOT_IMPLEMENTED) E(ERROR_NO_MORE_ITEMS) E(ERROR_INVALID_HANDLE) default: return "UNKNOWN ERROR"; } } static UINT enum_tables( MSIHANDLE hdb, LPSTR query ) { UINT res, i, count; MSIHANDLE htable = 0; fprintf(stderr,"Enumerating tables:\n"); res = MsiDatabaseOpenViewA(hdb, query, &htable); if( res == ERROR_SUCCESS ) { CHAR buffer[0x100]; MSIHANDLE hrec = 0; DWORD sz,n=0; res = MsiViewExecute(htable, 0); if( res != ERROR_SUCCESS ) fprintf(stderr,"failed %d (%s)\n", res, error_to_string(res)); while( 1 ) { res = MsiViewFetch(htable, &hrec); if( res != ERROR_SUCCESS ) break; fprintf(stderr,"row %2d : ",n++); count = MsiRecordGetFieldCount( hrec ); for( i=1; i<=count; i++ ) { if( MsiRecordIsNull( hrec, i ) ) { strcpy( buffer, "nil" ); } else { sz = sizeof buffer; buffer[0]=0; res = MsiRecordGetStringA(hrec, i, buffer, &sz); if( res != ERROR_SUCCESS ) break; buffer[sz]=0; } fprintf(stderr,"%s%s",buffer,(i==count)?"\n":" , "); } MsiCloseHandle( hrec ); } res = MsiViewClose(htable); if( res != ERROR_SUCCESS ) fprintf(stderr,"failed to close view %d (%s)\n", res, error_to_string(res)); res = MsiCloseHandle( htable ); if( res != ERROR_SUCCESS ) fprintf(stderr,"failed to close view handle %d (%s)\n", res, error_to_string(res)); } else fprintf(stderr,"query failed %d (%s)\n", res, error_to_string(res)); return res; } static char * init_hist( void ) { char *hist_path , *hist = "msiquery_history", *home; int len; using_history(); home = getenv("HOME"); len = strlen( home ) + strlen( hist ) + 2; hist_path = malloc( len ); if( !hist_path ) return; sprintf( hist_path, "%s/%s", home, hist ); read_history( hist_path ); return hist_path; } int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show) { LPSTR szFilename = cmdline; UINT res; char *test = NULL, *hist; int len = 100; MSIHANDLE hdb = 0; hist = init_hist(); if( cmdline && *cmdline ) { res = MsiOpenDatabaseA(cmdline, MSIDBOPEN_READONLY, &hdb); if( res != ERROR_SUCCESS ) printf("Error %d\n", res); else printf("OK\n", res); } while( 1 ) { if( test ) free( test ); test = NULL; test = readline("SQL> "); if( !test ) break; add_history( test ); len = strlen(test); if(len && test[len-1]=='\n') test[--len] = 0; if( !strcmp( test, "quit") ) { if( hdb ) MsiCloseHandle(hdb); printf("Bye.\n", res ); break; } if( !strncmp( test, "keys ", 5) ) { MSIHANDLE hrec = 0; UINT count, i; DWORD sz; char buffer[0x40]; if( hdb ) { res = MsiDatabaseGetPrimaryKeysA( hdb, &test[5], &hrec ); if( res == ERROR_SUCCESS ) { count = MsiRecordGetFieldCount( hrec ); for( i=1; i<=count; i++ ) { sz = sizeof buffer; buffer[0]=0; res = MsiRecordGetStringA(hrec, i, buffer, &sz); if( res != ERROR_SUCCESS ) break; buffer[sz]=0; printf("Key %d : %s\n", buffer); } } else fprintf(stderr,"MsiDatabaseGetPrimaryKeysA " "failed %d (%s)\n", res, error_to_string( res ) ); } else printf("No database available.\n", res ); continue; } if( !strncmp( test, "open ", 5) ) { printf("Opening database %s... "); res = MsiOpenDatabaseA(&test[5], MSIDBOPEN_READONLY, &hdb); if( res != ERROR_SUCCESS ) printf("Error %d\n", res); else printf("OK\n", res); continue; } if( !strcmp( test, "close") ) { if( !hdb ) { printf("no current database\n", res); continue; } res = MsiCloseHandle(hdb); hdb = 0; printf("result %d\n", res ); continue; } res = enum_tables( hdb, test ); printf("result %d\n", res ); continue; } if( hist ) { write_history( hist ); free( hist ); } return 0; }
name msiquery.exe type win32 mode cuiexe init main import gdi32.dll import kernel32.dll import ntdll.dll import user32.dll
### Generated by Winemaker ### Generic autoconf variables TOPSRCDIR = @top_srcdir@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ SUBDIRS = DLLS = EXES = msiquery.exe ### Global settings DEFINES = EXTRAINCL = $(WINE_INCLUDE_PATH) DLL_PATH = LIBRARY_PATH = LIBRARIES = ### msiquery sources and settings msiquery_C_SRCS = msiquery.c msiquery_CXX_SRCS = msiquery_RC_SRCS = msiquery_SPEC_SRCS = msiquery_DLL_PATH = msiquery_LIBRARY_PATH = msiquery_LIBRARIES = readline history termcap msiquery_IMPORTS = ole32 advapi32 kernel32 user32 gdi32 msi msiquery_DEPENDS = msiquery_OBJS = $(msiquery_C_SRCS:.c=.o) \ msiquery.exe.dbg.o \ $(msiquery_CXX_SRCS:.cpp=.o) \ $(EXTRA_OBJS) ### Global source lists C_SRCS = $(msiquery_C_SRCS) CXX_SRCS = $(msiquery_CXX_SRCS) RC_SRCS = $(msiquery_RC_SRCS) SPEC_SRCS = $(msiquery_SPEC_SRCS) ### Generic autoconf targets all: $(SUBDIRS) $(DLLS) $(EXES:%=%.so) @MAKE_RULES@ install:: $(SUBDIRS:%=%/__install__) install-image:: $(SUBDIRS:%=%/__install-image__) install install-image:: $(EXES:%=%.so) dummy $(MKINSTALLDIRS) $(dlldir) _list="$(DLLS) $(EXES:%=%.so)"; for i in $$_list; do $(INSTALL_PROGRAM) $$i $(dlldir)/$$i; done uninstall:: $(SUBDIRS:%=%/__uninstall__) dummy $(RM) $(EXES:%=$(dlldir)/%.so) $(DLLS:%=$(dlldir)/%) ### Target specific build rules msiquery.exe.spec.c: $(msiquery_RC_SRCS:.rc=.res) $(msiquery_OBJS) $(WINEBUILD) $(LDPATH) $(WINEBUILD) -fPIC $(msiquery_DLL_PATH) $(WINE_DLL_PATH) -o $@ --exe msiquery.exe $(msiquery_OBJS) $(msiquery_RC_SRCS:.rc=.res) $(msiquery_IMPORTS:%=-l%) msiquery.exe.so: msiquery.exe.spec.o $(msiquery_OBJS) $(msiquery_DEPENDS) $(LDSHARED) $(LDDLLFLAGS) -o $@ msiquery.exe.spec.o $(msiquery_OBJS) $(msiquery_LIBRARY_PATH) $(msiquery_LIBRARIES:%=-l%) $(DLL_LINK) $(LIBS) $(LIBUUID) msiquery.exe.dbg.c: $(C_SRCS) $(C_SRCS16) $(WINEBUILD) $(LDPATH) $(WINEBUILD) $(DEFS) -o $@ --debug -C$(SRCDIR) $(C_SRCS) $(C_SRCS16)