MSI query tool

Mike McCormack mike at codeweavers.com
Wed Aug 6 09:55:01 CDT 2003


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

-------------- next part --------------

#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;
}

-------------- next part --------------
name    msiquery.exe
type    win32
mode    cuiexe
init    main

import gdi32.dll
import kernel32.dll
import ntdll.dll
import user32.dll

-------------- next part --------------
### 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)



More information about the wine-patches mailing list