29 added files
- FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
- FIXME: remove values from the string table on error */
- FIXME: strdupW it? */
- FIXME("don't support persist files yet\b");
- FIXME("open failed r = %08lx!\n",r);
- FIXME("Failed to stat storage\n");
- FIXME("Failed to allocate a handle\n");
- FIXME("%s %s %s 0x%08x\n",debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
- FIXME("%s %s %s 0x%08x\n",debugstr_w(szPackagePath), debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
- FIXME("%s %s %s 0x%08x 0x%08lx 0x%08lx\n",
- FIXME("%s %s %s 0x%08x 0x%08lx 0x%08lx\n",
- FIXME: check return code */
- FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
- FIXME("%s 0x%08lx\n", debugstr_a(szProduct), dwReinstallMode);
- FIXME("%s 0x%08lx\n", debugstr_w(szProduct), dwReinstallMode);
- FIXME("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage), eInstallType, debugstr_a(szCommandLine));
- FIXME("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage), eInstallType, debugstr_w(szCommandLine));
- FIXME("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
- FIXME("%s %d %d\n",debugstr_w(szProduct), iInstallLevel, eInstallState);
- FIXME("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer));
- FIXME("%s %s\n",debugstr_w(szComponent), debugstr_w(szBuffer));
- FIXME("%s %s %p %p\n",debugstr_a(szProduct), debugstr_a(szAttribute), szBuffer, pcchValueBuf);
- FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute), szBuffer, pcchValueBuf);
- FIXME("%s %s\n",debugstr_a(szFolderPath), debugstr_a(szFilename));
- FIXME("%s %s\n",debugstr_w(szFolderPath), debugstr_w(szFilename));
- FIXME("%08lx %s %08lx\n", dwLogMode, debugstr_a(szLogFile), attributes);
- FIXME("%s\n", debugstr_a(szProduct));
- FIXME("%s\n", debugstr_w(szProduct));
- FIXME("%08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e);*/
- FIXME("%p %u %p %d %08lx\n",hInstance,uID,lpBuffer,nBufferMax,e);
- FIXME("%p %u %p %d %08lx\n",hInstance,uID,lpBuffer,nBufferMax,e);
- FIXME("%s\n",debugstr_w(lpBuffer));
- FIXME("%s %p %08lx\n", debugstr_a(szComponent), lpPathBuf, *pcchBuf);
- FIXME("%s %p %08lx\n", debugstr_w(szComponent), lpPathBuf, *pcchBuf);
- FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption),uType,wLanguageId,f);
- FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);*/
- FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption),uType,wLanguageId,f);
- FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName));
- FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName));
- FIXME("%ld %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
- FIXME("%ld %s %d\n", hdb, debugstr_w(szTransformFile), iErrorCond);
- FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
- FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
- FIXME: lock the database */
- FIXME: unlock the database */
- FIXME("%ld %s %p\n", hdb, debugstr_a(table), rec);
- FIXME("%ld %s %p\n", hdb, debugstr_w(table), rec);
- FIXME("%ld %x %ld\n",hView, eModifyMode, hRecord);
- FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage);
- FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
- FIXME("%ld %d\n", hRecord, iField);
- FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
- FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
- FIXME("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename));
- FIXME("%ld %d %s\n", hRecord, iField, debugstr_w(szFilename));
- FIXME: free $1 */
- FIXME("LOCALIZABLE ignored\n");
- FIXME */
- FIXME("%ld %p\n",hSummaryInfo, pCount);
- FIXME("Unknown property variant type\n");
- FIXME("%ld %d %p %p %p %p %p\n",
- FIXME: memory leak */
- FIXME: memory leak */
- FIXME: check we're comparing a string to a column */
reactos/lib/msi
diff -N .cvsignore
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ .cvsignore 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,8 @@
+*.coff
+*.dll
+*.d
+*.a
+*.o
+*.sym
+*.map
+*.tmp
reactos/lib/msi
diff -N Makefile
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Makefile 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,9 @@
+# $Id: Makefile,v 1.1 2004/11/30 19:10:50 jimtabor Exp $
+
+PATH_TO_TOP = ../..
+
+TARGET_TYPE = winedll
+
+include $(PATH_TO_TOP)/rules.mak
+
+include $(TOOLS_PATH)/helper.mk
reactos/lib/msi
diff -N Makefile.in
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Makefile.in 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,50 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR = @srcdir@
+VPATH = @srcdir@
+MODULE = msi.dll
+IMPORTS = shell32 cabinet oleaut32 ole32 version user32 advapi32 kernel32
+EXTRALIBS = -luuid $(LIBUNICODE)
+
+C_SRCS = \
+ action.c \
+ create.c \
+ distinct.c \
+ handle.c \
+ insert.c \
+ msi.c \
+ msiquery.c \
+ order.c \
+ package.c \
+ record.c \
+ regsvr.c \
+ select.c \
+ string.c \
+ suminfo.c \
+ table.c \
+ tokenize.c \
+ update.c \
+ where.c
+
+RC_SRCS = version.rc
+
+EXTRA_SRCS = sql.y cond.y
+EXTRA_OBJS = sql.tab.o cond.tab.o
+
+@MAKE_DLL_RULES@
+
+sql.tab.c sql.tab.h: sql.y
+ $(BISON) -p SQL_ -d $(SRCDIR)/sql.y -o sql.tab.c
+
+cond.tab.c cond.tab.h: cond.y
+ $(BISON) -p COND_ -d $(SRCDIR)/cond.y -o cond.tab.c
+
+# hack to allow parallel make
+sql.tab.h: sql.tab.c
+sql.tab.o: sql.tab.h
+cond.tab.h: cond.tab.c
+cond.tab.o: cond.tab.h
+
+tokenize.o: sql.tab.h
+
+### Dependencies:
reactos/lib/msi
diff -N Makefile.ros-template
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Makefile.ros-template 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,35 @@
+# $Id: Makefile.ros-template
+
+TARGET_NAME = msi
+
+TARGET_OBJECTS = @C_SRCS@ @EXTRA_OBJS@
+
+TARGET_CFLAGS = -D__REACTOS__ @EXTRADEFS@
+
+TARGET_SDKLIBS = @IMPORTS@ libwine.a wine_uuid.a ntdll.a
+
+TARGET_BASE = $(TARGET_BASE_LIB_WINMM)
+
+TARGET_RC_SRCS = @RC_SRCS@
+TARGET_RC_BINSRC = @RC_BINSRC@
+TARGET_RC_BINARIES = @RC_BINARIES@
+
+TARGET_CLEAN = *.tab.c *.tab.h
+
+default: all
+
+DEP_OBJECTS = $(TARGET_OBJECTS)
+
+include $(TOOLS_PATH)/depend.mk
+
+#
+# Bison is requiered for building msi.dll. If MingW32 for windows,
+# download bison from http://gnuwin32.sourceforge.net/
+# Make sure bison.exe is placed in your command path for execution.
+#
+#
+sql.tab.c sql.tab.h: sql.y
+ bison -p SQL_ -d ./sql.y -o sql.tab.c
+
+cond.tab.c cond.tab.h: cond.y
+ bison -p COND_ -d ./cond.y -o cond.tab.c
reactos/lib/msi
diff -N action.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ action.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,4733 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2004 Aric Stewart for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Pages I need
+ *
+http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
+
+http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winreg.h"
+#include "wine/debug.h"
+#include "fdi.h"
+#include "msi.h"
+#include "msiquery.h"
+//#include "msvcrt/fcntl.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+#include "winuser.h"
+#include "shlobj.h"
+#include "wine/unicode.h"
+#include "ver.h"
+
+#define CUSTOM_ACTION_TYPE_MASK 0x3F
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+typedef struct tagMSIFEATURE
+{
+ WCHAR Feature[96];
+ WCHAR Feature_Parent[96];
+ WCHAR Title[0x100];
+ WCHAR Description[0x100];
+ INT Display;
+ INT Level;
+ WCHAR Directory[96];
+ INT Attributes;
+
+ INSTALLSTATE State;
+ BOOL Enabled;
+ INT ComponentCount;
+ INT Components[1024]; /* yes hardcoded limit.... I am bad */
+ INT Cost;
+} MSIFEATURE;
+
+typedef struct tagMSICOMPONENT
+{
+ WCHAR Component[96];
+ WCHAR ComponentId[96];
+ WCHAR Directory[96];
+ INT Attributes;
+ WCHAR Condition[0x100];
+ WCHAR KeyPath[96];
+
+ INSTALLSTATE State;
+ BOOL FeatureState;
+ BOOL Enabled;
+ INT Cost;
+} MSICOMPONENT;
+
+typedef struct tagMSIFOLDER
+{
+ WCHAR Directory[96];
+ WCHAR TargetDefault[96];
+ WCHAR SourceDefault[96];
+
+ WCHAR ResolvedTarget[MAX_PATH];
+ WCHAR ResolvedSource[MAX_PATH];
+ WCHAR Property[MAX_PATH]; /* initially set property */
+ INT ParentIndex;
+ INT State;
+ /* 0 = uninitialized */
+ /* 1 = existing */
+ /* 2 = created remove if empty */
+ /* 3 = created persist if empty */
+ INT Cost;
+ INT Space;
+}MSIFOLDER;
+
+typedef struct tagMSIFILE
+{
+ WCHAR File[72];
+ INT ComponentIndex;
+ WCHAR FileName[MAX_PATH];
+ INT FileSize;
+ WCHAR Version[72];
+ WCHAR Language[20];
+ INT Attributes;
+ INT Sequence;
+
+ INT State;
+ /* 0 = uninitialize */
+ /* 1 = not present */
+ /* 2 = present but replace */
+ /* 3 = present do not replace */
+ /* 4 = Installed */
+ WCHAR SourcePath[MAX_PATH];
+ WCHAR TargetPath[MAX_PATH];
+ BOOL Temporary;
+}MSIFILE;
+
+/*
+ * Prototypes
+ */
+static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
+static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
+
+UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action);
+
+static UINT ACTION_LaunchConditions(MSIPACKAGE *package);
+static UINT ACTION_CostInitialize(MSIPACKAGE *package);
+static UINT ACTION_CreateFolders(MSIPACKAGE *package);
+static UINT ACTION_CostFinalize(MSIPACKAGE *package);
+static UINT ACTION_FileCost(MSIPACKAGE *package);
+static UINT ACTION_InstallFiles(MSIPACKAGE *package);
+static UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
+static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package);
+static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action);
+static UINT ACTION_InstallInitialize(MSIPACKAGE *package);
+static UINT ACTION_InstallValidate(MSIPACKAGE *package);
+static UINT ACTION_ProcessComponents(MSIPACKAGE *package);
+static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package);
+static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
+static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
+static UINT ACTION_CreateShortcuts(MSIPACKAGE *package);
+static UINT ACTION_PublishProduct(MSIPACKAGE *package);
+
+static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source,
+ const LPWSTR target, const INT type);
+static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source,
+ const LPWSTR target, const INT type);
+
+static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data);
+static UINT resolve_folder(MSIPACKAGE *package, LPCWSTR name, LPWSTR path,
+ BOOL source, BOOL set_prop, MSIFOLDER **folder);
+
+static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);
+
+/*
+ * consts and values used
+ */
+static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
+static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
+static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
+static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
+static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
+static const WCHAR c_collen[] = {'C',':','\\',0};
+
+static const WCHAR cszlsb[]={'[',0};
+static const WCHAR cszrsb[]={']',0};
+static const WCHAR cszbs[]={'\\',0};
+
+const static WCHAR szCreateFolders[] =
+ {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
+const static WCHAR szCostFinalize[] =
+ {'C','o','s','t','F','i','n','a','l','i','z','e',0};
+const static WCHAR szInstallFiles[] =
+ {'I','n','s','t','a','l','l','F','i','l','e','s',0};
+const static WCHAR szDuplicateFiles[] =
+ {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
+const static WCHAR szWriteRegistryValues[] =
+{'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
+const static WCHAR szCostInitialize[] =
+ {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
+const static WCHAR szFileCost[] = {'F','i','l','e','C','o','s','t',0};
+const static WCHAR szInstallInitialize[] =
+ {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
+const static WCHAR szInstallValidate[] =
+ {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
+const static WCHAR szLaunchConditions[] =
+ {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
+const static WCHAR szProcessComponents[] =
+ {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
+const static WCHAR szRegisterTypeLibraries[] =
+{'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r',
+'i','e','s',0};
+const static WCHAR szRegisterClassInfo[] =
+{'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
+const static WCHAR szRegisterProgIdInfo[] =
+{'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
+const static WCHAR szCreateShortcuts[] =
+{'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
+const static WCHAR szPublishProduct[] =
+{'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
+
+/********************************************************
+ * helper functions to get around current HACKS and such
+ ********************************************************/
+inline static void reduce_to_longfilename(WCHAR* filename)
+{
+ if (strchrW(filename,'|'))
+ {
+ WCHAR newname[MAX_PATH];
+ strcpyW(newname,strchrW(filename,'|')+1);
+ strcpyW(filename,newname);
+ }
+}
+
+inline static char *strdupWtoA( const WCHAR *str )
+{
+ char *ret = NULL;
+ if (str)
+ {
+ DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL
+);
+ if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
+ WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
+ }
+ return ret;
+}
+
+inline static WCHAR *strdupAtoW( const char *str )
+{
+ WCHAR *ret = NULL;
+ if (str)
+ {
+ DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
+ if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
+ MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
+ }
+ return ret;
+}
+
+inline static WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
+{
+ UINT rc;
+ DWORD sz;
+ LPWSTR ret;
+
+ sz = 0;
+ rc = MSI_RecordGetStringW(row,index,NULL,&sz);
+ if (sz <= 0)
+ return NULL;
+
+ sz ++;
+ ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
+ rc = MSI_RecordGetStringW(row,index,ret,&sz);
+ return ret;
+}
+
+inline static int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
+{
+ int rc = -1;
+ DWORD i;
+
+ for (i = 0; i < package->loaded_components; i++)
+ {
+ if (strcmpW(Component,package->components[i].Component)==0)
+ {
+ rc = i;
+ break;
+ }
+ }
+ return rc;
+}
+
+inline static int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
+{
+ int rc = -1;
+ DWORD i;
+
+ for (i = 0; i < package->loaded_features; i++)
+ {
+ if (strcmpW(Feature,package->features[i].Feature)==0)
+ {
+ rc = i;
+ break;
+ }
+ }
+ return rc;
+}
+
+inline static int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
+{
+ int rc = -1;
+ DWORD i;
+
+ for (i = 0; i < package->loaded_files; i++)
+ {
+ if (strcmpW(file,package->files[i].File)==0)
+ {
+ rc = i;
+ break;
+ }
+ }
+ return rc;
+}
+
+static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
+{
+ DWORD i;
+ DWORD index;
+
+ if (!package)
+ return -2;
+
+ for (i=0; i < package->loaded_files; i++)
+ if (strcmpW(package->files[i].File,name)==0)
+ return -1;
+
+ index = package->loaded_files;
+ package->loaded_files++;
+ if (package->loaded_files== 1)
+ package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
+ else
+ package->files = HeapReAlloc(GetProcessHeap(),0,
+ package->files , package->loaded_files * sizeof(MSIFILE));
+
+ memset(&package->files[index],0,sizeof(MSIFILE));
+
+ strcpyW(package->files[index].File,name);
+ strcpyW(package->files[index].TargetPath,path);
+ package->files[index].Temporary = TRUE;
+
+ TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));
+
+ return 0;
+}
+
+void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package)
+{
+ DWORD i;
+
+ if (!package)
+ return;
+
+ for (i = 0; i < package->loaded_files; i++)
+ {
+ if (package->files[i].Temporary)
+ DeleteFileW(package->files[i].TargetPath);
+
+ }
+}
+
+static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
+{
+ MSIRECORD * row;
+
+ row = MSI_CreateRecord(4);
+ MSI_RecordSetInteger(row,1,a);
+ MSI_RecordSetInteger(row,2,b);
+ MSI_RecordSetInteger(row,3,c);
+ MSI_RecordSetInteger(row,4,d);
+ MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
+ msiobj_release(&row->hdr);
+}
+
+static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
+{
+ static const WCHAR Query_t[] =
+{'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
+'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
+' ','\'','%','s','\'',0};
+ WCHAR message[1024];
+ UINT rc;
+ MSIQUERY * view;
+ MSIRECORD * row = 0;
+ static WCHAR *ActionFormat=NULL;
+ static WCHAR LastAction[0x100] = {0};
+ WCHAR Query[1024];
+ LPWSTR ptr;
+
+ if (strcmpW(LastAction,action)!=0)
+ {
+ sprintfW(Query,Query_t,action);
+ rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
+ if (rc != ERROR_SUCCESS)
+ return;
+ rc = MSI_ViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MSI_ViewClose(view);
+ return;
+ }
+ rc = MSI_ViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ MSI_ViewClose(view);
+ return;
+ }
+
+ if (MSI_RecordIsNull(row,3))
+ {
+ msiobj_release(&row->hdr);
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ return;
+ }
+
+ if (ActionFormat)
+ HeapFree(GetProcessHeap(),0,ActionFormat);
+
+ ActionFormat = load_dynamic_stringW(row,3);
+ strcpyW(LastAction,action);
+ msiobj_release(&row->hdr);
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ }
+
+ message[0]=0;
+ ptr = ActionFormat;
+ while (*ptr)
+ {
+ LPWSTR ptr2;
+ LPWSTR data=NULL;
+ WCHAR tmp[1023];
+ INT field;
+
+ ptr2 = strchrW(ptr,'[');
+ if (ptr2)
+ {
+ strncpyW(tmp,ptr,ptr2-ptr);
+ tmp[ptr2-ptr]=0;
+ strcatW(message,tmp);
+ ptr2++;
+ field = atoiW(ptr2);
+ data = load_dynamic_stringW(record,field);
+ if (data)
+ {
+ strcatW(message,data);
+ HeapFree(GetProcessHeap(),0,data);
+ }
+ ptr=strchrW(ptr2,']');
+ ptr++;
+ }
+ else
+ {
+ strcatW(message,ptr);
+ break;
+ }
+ }
+
+ row = MSI_CreateRecord(1);
+ MSI_RecordSetStringW(row,1,message);
+
+ MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
+ msiobj_release(&row->hdr);
+}
+
+
+static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
+{
+ static const WCHAR template_s[]=
+{'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ','%','s','.',0};
+ static const WCHAR format[] =
+{'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
+ static const WCHAR Query_t[] =
+{'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',
+'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',
+' ','\'','%','s','\'',0};
+ WCHAR message[1024];
+ WCHAR timet[0x100];
+ UINT rc;
+ MSIQUERY * view;
+ MSIRECORD * row = 0;
+ WCHAR *ActionText=NULL;
+ WCHAR Query[1024];
+
+ GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
+
+ sprintfW(Query,Query_t,action);
+ rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
+ if (rc != ERROR_SUCCESS)
+ return;
+ rc = MSI_ViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ return;
+ }
+ rc = MSI_ViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ return;
+ }
+
+ ActionText = load_dynamic_stringW(row,2);
+ msiobj_release(&row->hdr);
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+
+ sprintfW(message,template_s,timet,action,ActionText);
+
+ row = MSI_CreateRecord(1);
+ MSI_RecordSetStringW(row,1,message);
+
+ MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
+ msiobj_release(&row->hdr);
+ HeapFree(GetProcessHeap(),0,ActionText);
+}
+
+static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
+ UINT rc)
+{
+ MSIRECORD * row;
+ static const WCHAR template_s[]=
+{'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s',
+'.',0};
+ static const WCHAR template_e[]=
+{'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ','%','s',
+'.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ','%','i','.',0};
+ static const WCHAR format[] =
+{'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
+ WCHAR message[1024];
+ WCHAR timet[0x100];
+
+ GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
+ if (start)
+ sprintfW(message,template_s,timet,action);
+ else
+ sprintfW(message,template_e,timet,action,rc);
+
+ row = MSI_CreateRecord(1);
+ MSI_RecordSetStringW(row,1,message);
+
+ MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
+ msiobj_release(&row->hdr);
+}
+
+/****************************************************
+ * TOP level entry points
+ *****************************************************/
+
+UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
+ LPCWSTR szCommandLine)
+{
+ DWORD sz;
+ WCHAR buffer[10];
+ UINT rc;
+ static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
+
+ if (szPackagePath)
+ {
+ LPWSTR p;
+ WCHAR check[MAX_PATH];
+ WCHAR pth[MAX_PATH];
+ DWORD size;
+
+ strcpyW(pth,szPackagePath);
+ p = strrchrW(pth,'\\');
+ if (p)
+ {
+ p++;
+ *p=0;
+ }
+
+ size = MAX_PATH;
+ if (MSI_GetPropertyW(package,cszSourceDir,check,&size)
+ != ERROR_SUCCESS )
+ MSI_SetPropertyW(package, cszSourceDir, pth);
+ }
+
+ if (szCommandLine)
+ {
+ LPWSTR ptr,ptr2;
+ ptr = (LPWSTR)szCommandLine;
+
+ while (*ptr)
+ {
+ WCHAR prop[0x100];
+ WCHAR val[0x100];
+
+ TRACE("Looking at %s\n",debugstr_w(ptr));
+
+ ptr2 = strchrW(ptr,'=');
+ if (ptr2)
+ {
+ BOOL quote=FALSE;
+ DWORD len = 0;
+
+ while (*ptr == ' ') ptr++;
+ strncpyW(prop,ptr,ptr2-ptr);
+ prop[ptr2-ptr]=0;
+ ptr2++;
+
+ ptr = ptr2;
+ while (*ptr && (quote || (!quote && *ptr!=' ')))
+ {
+ if (*ptr == '"')
+ quote = !quote;
+ ptr++;
+ len++;
+ }
+
+ if (*ptr2=='"')
+ {
+ ptr2++;
+ len -= 2;
+ }
+ strncpyW(val,ptr2,len);
+ val[len]=0;
+
+ if (strlenW(prop) > 0)
+ {
+ TRACE("Found commandline property (%s) = (%s)\n", debugstr_w(prop), debugstr_w(val));
+ MSI_SetPropertyW(package,prop,val);
+ }
+ }
+ ptr++;
+ }
+ }
+
+ sz = 10;
+ if (MSI_GetPropertyW(package,szUILevel,buffer,&sz) == ERROR_SUCCESS)
+ {
+ if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED)
+ {
+ rc = ACTION_ProcessUISequence(package);
+ if (rc == ERROR_SUCCESS)
+ rc = ACTION_ProcessExecSequence(package,TRUE);
+ }
+ else
+ rc = ACTION_ProcessExecSequence(package,FALSE);
+ }
+ else
+ rc = ACTION_ProcessExecSequence(package,FALSE);
+
+ return rc;
+}
+
+
+static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
+{
+ MSIQUERY * view;
+ UINT rc;
+ static const WCHAR ExecSeqQuery[] = {
+ 's','e','l','e','c','t',' ','*',' ',
+ 'f','r','o','m',' ',
+ 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
+ 'S','e','q','u','e','n','c','e',' ',
+ 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',
+ '>',' ','%','i',' ','o','r','d','e','r',' ',
+ 'b','y',' ','S','e','q','u','e','n','c','e',0 };
+ WCHAR Query[1024];
+ MSIRECORD * row = 0;
+ static const WCHAR IVQuery[] = {
+ 's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ',
+ 'f','r','o','m',' ','I','n','s','t','a','l','l',
+ 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ',
+ 'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ',
+ '`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`',
+ 0};
+
+ if (UIran)
+ {
+ INT seq = 0;
+
+ rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+ rc = MSI_ViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ return rc;
+ }
+ rc = MSI_ViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ return rc;
+ }
+ seq = MSI_RecordGetInteger(row,1);
+ msiobj_release(&row->hdr);
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ sprintfW(Query,ExecSeqQuery,seq);
+ }
+ else
+ sprintfW(Query,ExecSeqQuery,0);
+
+ rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
+ if (rc == ERROR_SUCCESS)
+ {
+ rc = MSI_ViewExecute(view, 0);
+
+ if (rc != ERROR_SUCCESS)
+ {
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ goto end;
+ }
+
+ TRACE("Running the actions \n");
+
+ while (1)
+ {
+ WCHAR buffer[0x100];
+ DWORD sz = 0x100;
+
+ rc = MSI_ViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+
+ /* check conditions */
+ if (!MSI_RecordIsNull(row,2))
+ {
+ LPWSTR cond = NULL;
+ cond = load_dynamic_stringW(row,2);
+
+ if (cond)
+ {
+ /* this is a hack to skip errors in the condition code */
+ if (MSI_EvaluateConditionW(package, cond) ==
+ MSICONDITION_FALSE)
+ {
+ HeapFree(GetProcessHeap(),0,cond);
+ msiobj_release(&row->hdr);
+ continue;
+ }
+ else
+ HeapFree(GetProcessHeap(),0,cond);
+ }
+ }
+
+ sz=0x100;
+ rc = MSI_RecordGetStringW(row,1,buffer,&sz);
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Error is %x\n",rc);
+ msiobj_release(&row->hdr);
+ break;
+ }
+
+ rc = ACTION_PerformAction(package,buffer);
+
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Execution halted due to error (%i)\n",rc);
+ msiobj_release(&row->hdr);
+ break;
+ }
+
+ msiobj_release(&row->hdr);
+ }
+
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ }
+
+end:
+ return rc;
+}
+
+
+static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
+{
+ MSIQUERY * view;
+ UINT rc;
+ static const WCHAR ExecSeqQuery [] = {
+ 's','e','l','e','c','t',' ','*',' ',
+ 'f','r','o','m',' ','I','n','s','t','a','l','l',
+ 'U','I','S','e','q','u','e','n','c','e',' ',
+ 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '>',' ','0',' ',
+ 'o','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e',0};
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+
+ if (rc == ERROR_SUCCESS)
+ {
+ rc = MSI_ViewExecute(view, 0);
+
+ if (rc != ERROR_SUCCESS)
+ {
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ goto end;
+ }
+
+ TRACE("Running the actions \n");
+
+ while (1)
+ {
+ WCHAR buffer[0x100];
+ DWORD sz = 0x100;
+ MSIRECORD * row = 0;
+
+ rc = MSI_ViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+
+ /* check conditions */
+ if (!MSI_RecordIsNull(row,2))
+ {
+ LPWSTR cond = NULL;
+ cond = load_dynamic_stringW(row,2);
+
+ if (cond)
+ {
+ /* this is a hack to skip errors in the condition code */
+ if (MSI_EvaluateConditionW(package, cond) ==
+ MSICONDITION_FALSE)
+ {
+ HeapFree(GetProcessHeap(),0,cond);
+ msiobj_release(&row->hdr);
+ continue;
+ }
+ else
+ HeapFree(GetProcessHeap(),0,cond);
+ }
+ }
+
+ sz=0x100;
+ rc = MSI_RecordGetStringW(row,1,buffer,&sz);
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Error is %x\n",rc);
+ msiobj_release(&row->hdr);
+ break;
+ }
+
+ rc = ACTION_PerformAction(package,buffer);
+
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Execution halted due to error (%i)\n",rc);
+ msiobj_release(&row->hdr);
+ break;
+ }
+
+ msiobj_release(&row->hdr);
+ }
+
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ }
+
+end:
+ return rc;
+}
+
+/********************************************************
+ * ACTION helper functions and functions that perform the actions
+ *******************************************************/
+
+/*
+ * Alot of actions are really important even if they don't do anything
+ * explicit.. Lots of properties are set at the beginning of the installation
+ * CostFinalize does a bunch of work to translated the directories and such
+ *
+ * But until I get write access to the database that is hard, so I am going to
+ * hack it to see if I can get something to run.
+ */
+UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action)
+{
+ UINT rc = ERROR_SUCCESS;
+
+ TRACE("Performing action (%s)\n",debugstr_w(action));
+ ui_actioninfo(package, action, TRUE, 0);
+ ui_actionstart(package, action);
+ ui_progress(package,2,1,0,0);
+
+ /* pre install, setup and configuration block */
+ if (strcmpW(action,szLaunchConditions)==0)
+ rc = ACTION_LaunchConditions(package);
+ else if (strcmpW(action,szCostInitialize)==0)
+ rc = ACTION_CostInitialize(package);
+ else if (strcmpW(action,szFileCost)==0)
+ rc = ACTION_FileCost(package);
+ else if (strcmpW(action,szCostFinalize)==0)
+ rc = ACTION_CostFinalize(package);
+ else if (strcmpW(action,szInstallValidate)==0)
+ rc = ACTION_InstallValidate(package);
+
+ /* install block */
+ else if (strcmpW(action,szProcessComponents)==0)
+ rc = ACTION_ProcessComponents(package);
+ else if (strcmpW(action,szInstallInitialize)==0)
+ rc = ACTION_InstallInitialize(package);
+ else if (strcmpW(action,szCreateFolders)==0)
+ rc = ACTION_CreateFolders(package);
+ else if (strcmpW(action,szInstallFiles)==0)
+ rc = ACTION_InstallFiles(package);
+ else if (strcmpW(action,szDuplicateFiles)==0)
+ rc = ACTION_DuplicateFiles(package);
+ else if (strcmpW(action,szWriteRegistryValues)==0)
+ rc = ACTION_WriteRegistryValues(package);
+ else if (strcmpW(action,szRegisterTypeLibraries)==0)
+ rc = ACTION_RegisterTypeLibraries(package);
+ else if (strcmpW(action,szRegisterClassInfo)==0)
+ rc = ACTION_RegisterClassInfo(package);
+ else if (strcmpW(action,szRegisterProgIdInfo)==0)
+ rc = ACTION_RegisterProgIdInfo(package);
+ else if (strcmpW(action,szCreateShortcuts)==0)
+ rc = ACTION_CreateShortcuts(package);
+ else if (strcmpW(action,szPublishProduct)==0)
+ rc = ACTION_PublishProduct(package);
+
+ /*
+ Called during iTunes but unimplemented and seem important
+
+ ResolveSource (sets SourceDir)
+ RegisterProduct
+ InstallFinalize
+ */
+ else if ((rc = ACTION_CustomAction(package,action)) != ERROR_SUCCESS)
+ {
+ FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
+ rc = ERROR_SUCCESS;
+ }
+
+ ui_actioninfo(package, action, FALSE, rc);
+ return rc;
+}
+
+
+static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIQUERY * view;
+ MSIRECORD * row = 0;
+ WCHAR ExecSeqQuery[1024] =
+ {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','u','s','t','o'
+,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i'
+,'o','n','`',' ','=',' ','`',0};
+ static const WCHAR end[]={'`',0};
+ UINT type;
+ LPWSTR source;
+ LPWSTR target;
+ WCHAR *deformated=NULL;
+
+ strcatW(ExecSeqQuery,action);
+ strcatW(ExecSeqQuery,end);
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MSI_ViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ return rc;
+ }
+
+ rc = MSI_ViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ return rc;
+ }
+
+ type = MSI_RecordGetInteger(row,2);
+
+ source = load_dynamic_stringW(row,3);
+ target = load_dynamic_stringW(row,4);
+
+ TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type,
+ debugstr_w(source), debugstr_w(target));
+
+ /* we are ignoring ALOT of flags and important synchronization stuff */
+ switch (type & CUSTOM_ACTION_TYPE_MASK)
+ {
[truncated at 1000 lines; 3737 more skipped]
reactos/lib/msi
diff -N cond.y
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ cond.y 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,774 @@
+%{
+
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2003 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+#include "msi.h"
+#include "msiquery.h"
+#include "msipriv.h"
+
+#define YYLEX_PARAM info
+#define YYPARSE_PARAM info
+
+static int COND_error(char *str);
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+typedef struct tag_yyinput
+{
+ MSIPACKAGE *package;
+ LPCWSTR str;
+ INT n;
+ MSICONDITION result;
+} COND_input;
+
+struct cond_str {
+ LPCWSTR data;
+ INT len;
+};
+
+static LPWSTR COND_GetString( struct cond_str *str );
+static LPWSTR COND_GetLiteral( struct cond_str *str );
+static int COND_lex( void *COND_lval, COND_input *info);
+
+typedef INT (*comp_int)(INT a, INT b);
+typedef INT (*comp_str)(LPWSTR a, LPWSTR b, BOOL caseless);
+typedef INT (*comp_m1)(LPWSTR a,int b);
+typedef INT (*comp_m2)(int a,LPWSTR b);
+
+static INT comp_lt_i(INT a, INT b);
+static INT comp_gt_i(INT a, INT b);
+static INT comp_le_i(INT a, INT b);
+static INT comp_ge_i(INT a, INT b);
+static INT comp_eq_i(INT a, INT b);
+static INT comp_ne_i(INT a, INT b);
+static INT comp_bitand(INT a, INT b);
+static INT comp_highcomp(INT a, INT b);
+static INT comp_lowcomp(INT a, INT b);
+
+static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless);
+static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless);
+static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless);
+static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless);
+static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless);
+static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless);
+static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless);
+static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless);
+static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless);
+
+static INT comp_eq_m1(LPWSTR a, INT b);
+static INT comp_ne_m1(LPWSTR a, INT b);
+static INT comp_lt_m1(LPWSTR a, INT b);
+static INT comp_gt_m1(LPWSTR a, INT b);
+static INT comp_le_m1(LPWSTR a, INT b);
+static INT comp_ge_m1(LPWSTR a, INT b);
+
+static INT comp_eq_m2(INT a, LPWSTR b);
+static INT comp_ne_m2(INT a, LPWSTR b);
+static INT comp_lt_m2(INT a, LPWSTR b);
+static INT comp_gt_m2(INT a, LPWSTR b);
+static INT comp_le_m2(INT a, LPWSTR b);
+static INT comp_ge_m2(INT a, LPWSTR b);
+
+%}
+
+%pure-parser
+
+%union
+{
+ struct cond_str str;
+ LPWSTR string;
+ INT value;
+ comp_int fn_comp_int;
+ comp_str fn_comp_str;
+ comp_m1 fn_comp_m1;
+ comp_m2 fn_comp_m2;
+}
+
+%token COND_SPACE COND_EOF COND_SPACE
+%token COND_OR COND_AND COND_NOT
+%token COND_LT COND_GT COND_EQ
+%token COND_LPAR COND_RPAR COND_TILDA
+%token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM
+%token <str> COND_IDENT <str> COND_NUMBER <str> COND_LITER
+
+%nonassoc COND_EOF COND_ERROR
+
+%type <value> expression boolean_term boolean_factor
+%type <value> term value_i symbol_i integer
+%type <string> identifier value_s symbol_s literal
+%type <fn_comp_int> comp_op_i
+%type <fn_comp_str> comp_op_s
+%type <fn_comp_m1> comp_op_m1
+%type <fn_comp_m2> comp_op_m2
+
+%%
+
+condition:
+ expression
+ {
+ COND_input* cond = (COND_input*) info;
+ cond->result = $1;
+ }
+ ;
+
+expression:
+ boolean_term
+ {
+ $$ = $1;
+ }
+ | boolean_term COND_OR expression
+ {
+ $$ = $1 || $3;
+ }
+ ;
+
+boolean_term:
+ boolean_factor
+ {
+ $$ = $1;
+ }
+ | boolean_term COND_AND boolean_factor
+ {
+ $$ = $1 && $3;
+ }
+ ;
+
+boolean_factor:
+ term
+ {
+ $$ = $1;
+ }
+ | COND_NOT term
+ {
+ $$ = ! $2;
+ }
+ ;
+
+
+term:
+ value_i
+ {
+ $$ = $1;
+ }
+ | value_s
+ {
+ $$ = atoiW($1);
+ }
+ | value_i comp_op_i value_i
+ {
+ $$ = $2( $1, $3 );
+ }
+ | value_s comp_op_s value_s
+ {
+ $$ = $2( $1, $3, FALSE );
+ }
+ | value_s COND_TILDA comp_op_s value_s
+ {
+ $$ = $3( $1, $4, TRUE );
+ }
+ | value_s comp_op_m1 value_i
+ {
+ $$ = $2( $1, $3 );
+ }
+ | value_i comp_op_m2 value_s
+ {
+ $$ = $2( $1, $3 );
+ }
+ | COND_LPAR expression COND_RPAR
+ {
+ $$ = $2;
+ }
+ ;
+
+comp_op_i:
+ /* common functions */
+ COND_EQ
+ {
+ $$ = comp_eq_i;
+ }
+ | COND_LT COND_GT
+ {
+ $$ = comp_ne_i;
+ }
+ | COND_LT
+ {
+ $$ = comp_lt_i;
+ }
+ | COND_GT
+ {
+ $$ = comp_gt_i;
+ }
+ | COND_LT COND_EQ
+ {
+ $$ = comp_le_i;
+ }
+ | COND_GT COND_EQ
+ {
+ $$ = comp_ge_i;
+ }
+ /*Int only*/
+ | COND_GT COND_LT
+ {
+ $$ = comp_bitand;
+ }
+ | COND_LT COND_LT
+ {
+ $$ = comp_highcomp;
+ }
+ | COND_GT COND_GT
+ {
+ $$ = comp_lowcomp;
+ }
+ ;
+
+comp_op_s:
+ /* common functions */
+ COND_EQ
+ {
+ $$ = comp_eq_s;
+ }
+ | COND_LT COND_GT
+ {
+ $$ = comp_ne_s;
+ }
+ | COND_LT
+ {
+ $$ = comp_lt_s;
+ }
+ | COND_GT
+ {
+ $$ = comp_gt_s;
+ }
+ | COND_LT COND_EQ
+ {
+ $$ = comp_le_s;
+ }
+ | COND_GT COND_EQ
+ {
+ $$ = comp_ge_s;
+ }
+ /*string only*/
+ | COND_GT COND_LT
+ {
+ $$ = comp_substring;
+ }
+ | COND_LT COND_LT
+ {
+ $$ = comp_start;
+ }
+ | COND_GT COND_GT
+ {
+ $$ = comp_end;
+ }
+ ;
+
+comp_op_m1:
+ /* common functions */
+ COND_EQ
+ {
+ $$ = comp_eq_m1;
+ }
+ | COND_LT COND_GT
+ {
+ $$ = comp_ne_m1;
+ }
+ | COND_LT
+ {
+ $$ = comp_lt_m1;
+ }
+ | COND_GT
+ {
+ $$ = comp_gt_m1;
+ }
+ | COND_LT COND_EQ
+ {
+ $$ = comp_le_m1;
+ }
+ | COND_GT COND_EQ
+ {
+ $$ = comp_ge_m1;
+ }
+ /*Not valid for mixed compares*/
+ | COND_GT COND_LT
+ {
+ $$ = 0;
+ }
+ | COND_LT COND_LT
+ {
+ $$ = 0;
+ }
+ | COND_GT COND_GT
+ {
+ $$ = 0;
+ }
+ ;
+
+comp_op_m2:
+ /* common functions */
+ COND_EQ
+ {
+ $$ = comp_eq_m2;
+ }
+ | COND_LT COND_GT
+ {
+ $$ = comp_ne_m2;
+ }
+ | COND_LT
+ {
+ $$ = comp_lt_m2;
+ }
+ | COND_GT
+ {
+ $$ = comp_gt_m2;
+ }
+ | COND_LT COND_EQ
+ {
+ $$ = comp_le_m2;
+ }
+ | COND_GT COND_EQ
+ {
+ $$ = comp_ge_m2;
+ }
+ /*Not valid for mixed compares*/
+ | COND_GT COND_LT
+ {
+ $$ = 0;
+ }
+ | COND_LT COND_LT
+ {
+ $$ = 0;
+ }
+ | COND_GT COND_GT
+ {
+ $$ = 0;
+ }
+ ;
+
+value_i:
+ symbol_i
+ {
+ $$ = $1;
+ }
+ | integer
+ {
+ $$ = $1;
+ }
+ ;
+
+value_s:
+ symbol_s
+ {
+ $$ = $1;
+ }
+ | literal
+ {
+ $$ = $1;
+ }
+ ;
+
+literal:
+ COND_LITER
+ {
+ $$ = COND_GetLiteral(&$1);
+ if( !$$ )
+ YYABORT;
+ }
+ ;
+
+symbol_i:
+ COND_DOLLARS identifier
+ {
+ COND_input* cond = (COND_input*) info;
+ INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
+
+ MSI_GetComponentStateW(cond->package, $2, &install, &action );
+ $$ = action;
+ HeapFree( GetProcessHeap(), 0, $2 );
+ }
+ | COND_QUESTION identifier
+ {
+ COND_input* cond = (COND_input*) info;
+ INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
+
+ MSI_GetComponentStateW(cond->package, $2, &install, &action );
+ $$ = install;
+ HeapFree( GetProcessHeap(), 0, $2 );
+ }
+ | COND_AMPER identifier
+ {
+ COND_input* cond = (COND_input*) info;
+ INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
+
+ MSI_GetFeatureStateW(cond->package, $2, &install, &action );
+ $$ = action;
+ HeapFree( GetProcessHeap(), 0, $2 );
+ }
+ | COND_EXCLAM identifier
+ {
+ COND_input* cond = (COND_input*) info;
+ INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
+
+ MSI_GetFeatureStateW(cond->package, $2, &install, &action );
+ $$ = install;
+ HeapFree( GetProcessHeap(), 0, $2 );
+ }
+ ;
+
+symbol_s:
+ identifier
+ {
+ DWORD sz;
+ COND_input* cond = (COND_input*) info;
+ $$ = HeapAlloc( GetProcessHeap(), 0, 0x100*sizeof (WCHAR) );
+
+ /* Lookup the identifier */
+
+ sz=0x100;
+ if (MSI_GetPropertyW(cond->package,$1,$$,&sz) != ERROR_SUCCESS)
+ {
+ $$[0]=0;
+ }
+ HeapFree( GetProcessHeap(), 0, $1 );
+ }
+ | COND_PERCENT identifier
+ {
+ UINT len = GetEnvironmentVariableW( $2, NULL, 0 );
+ if( len++ )
+ {
+ $$ = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
+ if( $$ )
+ GetEnvironmentVariableW( $2, $$, len );
+ }
+ HeapFree( GetProcessHeap(), 0, $2 );
+ }
+ ;
+
+identifier:
+ COND_IDENT
+ {
+ $$ = COND_GetString(&$1);
+ if( !$$ )
+ YYABORT;
+ }
+ ;
+
+integer:
+ COND_NUMBER
+ {
+ LPWSTR szNum = COND_GetString(&$1);
+ if( !szNum )
+ YYABORT;
+ $$ = atoiW( szNum );
+ HeapFree( GetProcessHeap(), 0, szNum );
+ }
+ ;
+
+%%
+
+
+static int COND_IsAlpha( WCHAR x )
+{
+ return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) ||
+ ( ( x >= 'a' ) && ( x <= 'z' ) ) ||
+ ( ( x == '_' ) ) );
+}
+
+static int COND_IsNumber( WCHAR x )
+{
+ return( (( x >= '0' ) && ( x <= '9' )) || (x =='-') || (x =='.') );
+}
+
+
+/* the mess of comparison functions */
+
+static INT comp_lt_i(INT a, INT b)
+{ return (a < b); }
+static INT comp_gt_i(INT a, INT b)
+{ return (a > b); }
+static INT comp_le_i(INT a, INT b)
+{ return (a <= b); }
+static INT comp_ge_i(INT a, INT b)
+{ return (a >= b); }
+static INT comp_eq_i(INT a, INT b)
+{ return (a == b); }
+static INT comp_ne_i(INT a, INT b)
+{ return (a != b); }
+static INT comp_bitand(INT a, INT b)
+{ return a & b;}
+static INT comp_highcomp(INT a, INT b)
+{ return HIWORD(a)==b; }
+static INT comp_lowcomp(INT a, INT b)
+{ return LOWORD(a)==b; }
+
+static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless)
+{ if (casless) return !strcmpiW(a,b); else return !strcmpW(a,b);}
+static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless)
+{ if (casless) return strcmpiW(a,b); else return strcmpW(a,b);}
+static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless)
+{ if (casless) return strcmpiW(a,b)<0; else return strcmpW(a,b)<0;}
+static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless)
+{ if (casless) return strcmpiW(a,b)>0; else return strcmpW(a,b)>0;}
+static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless)
+{ if (casless) return strcmpiW(a,b)<=0; else return strcmpW(a,b)<=0;}
+static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless)
+{ if (casless) return strcmpiW(a,b)>=0; else return strcmpW(a,b)>=0;}
+static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless)
+/* ERROR NOT WORKING REWRITE */
+{ if (casless) return strstrW(a,b)!=NULL; else return strstrW(a,b)!=NULL;}
+static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless)
+{ if (casless) return strncmpiW(a,b,strlenW(b))==0;
+ else return strncmpW(a,b,strlenW(b))==0;}
+static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless)
+{
+ int i = strlenW(a);
+ int j = strlenW(b);
+ if (j>i)
+ return 0;
+ if (casless) return (!strcmpiW(&a[i-j-1],b));
+ else return (!strcmpW(&a[i-j-1],b));
+}
+
+
+static INT comp_eq_m1(LPWSTR a, INT b)
+{ if (COND_IsNumber(a[0])) return atoiW(a)==b; else return 0;}
+static INT comp_ne_m1(LPWSTR a, INT b)
+{ if (COND_IsNumber(a[0])) return atoiW(a)!=b; else return 1;}
+static INT comp_lt_m1(LPWSTR a, INT b)
+{ if (COND_IsNumber(a[0])) return atoiW(a)<b; else return 0;}
+static INT comp_gt_m1(LPWSTR a, INT b)
+{ if (COND_IsNumber(a[0])) return atoiW(a)>b; else return 0;}
+static INT comp_le_m1(LPWSTR a, INT b)
+{ if (COND_IsNumber(a[0])) return atoiW(a)<=b; else return 0;}
+static INT comp_ge_m1(LPWSTR a, INT b)
+{ if (COND_IsNumber(a[0])) return atoiW(a)>=b; else return 0;}
+
+static INT comp_eq_m2(INT a, LPWSTR b)
+{ if (COND_IsNumber(b[0])) return a == atoiW(b); else return 0;}
+static INT comp_ne_m2(INT a, LPWSTR b)
+{ if (COND_IsNumber(b[0])) return a != atoiW(b); else return 1;}
+static INT comp_lt_m2(INT a, LPWSTR b)
+{ if (COND_IsNumber(b[0])) return a < atoiW(b); else return 0;}
+static INT comp_gt_m2(INT a, LPWSTR b)
+{ if (COND_IsNumber(b[0])) return a > atoiW(b); else return 0;}
+static INT comp_le_m2(INT a, LPWSTR b)
+{ if (COND_IsNumber(b[0])) return a <= atoiW(b); else return 0;}
+static INT comp_ge_m2(INT a, LPWSTR b)
+{ if (COND_IsNumber(b[0])) return a >= atoiW(b); else return 0;}
+
+
+
+static int COND_IsIdent( WCHAR x )
+{
+ return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' )
+ || ( x == '#' ) || (x == '.') );
+}
+
+static int COND_GetOne( struct cond_str *str, COND_input *cond )
+{
+ static const WCHAR szNot[] = {'N','O','T',0};
+ static const WCHAR szAnd[] = {'A','N','D',0};
+ static const WCHAR szOr[] = {'O','R',0};
+ WCHAR ch;
+ int rc, len = 1;
+
+ str->data = &cond->str[cond->n];
+
+ ch = str->data[0];
+ switch( ch )
+ {
+ case 0: return 0;
+ case '(': rc = COND_LPAR; break;
+ case ')': rc = COND_RPAR; break;
+ case '&': rc = COND_AMPER; break;
+ case '!': rc = COND_EXCLAM; break;
+ case '$': rc = COND_DOLLARS; break;
+ case '?': rc = COND_QUESTION; break;
+ case '%': rc = COND_PERCENT; break;
+ case ' ': rc = COND_SPACE; break;
+ case '=': rc = COND_EQ; break;
+ case '~': rc = COND_TILDA; break;
+ case '<': rc = COND_LT; break;
+ case '>': rc = COND_GT; break;
+ case '"':
+ {
+ const WCHAR *ch2 = str->data + 1;
+
+
+ while ( *ch2 && *ch2 != '"' )
+ ++ch2;
+ if (*ch2 == '"')
+ {
+ len = ch2 - str->data + 1;
+ rc = COND_LITER;
+ break;
+ }
+ }
+ ERR("Unterminated string\n");
+ rc = COND_ERROR;
+ break;
+ default:
+ if( COND_IsAlpha( ch ) )
+ {
+ while( COND_IsIdent( str->data[len] ) )
+ len++;
+ rc = COND_IDENT;
+ break;
+ }
+
+ if( COND_IsNumber( ch ) )
+ {
+ while( COND_IsNumber( str->data[len] ) )
+ len++;
+ rc = COND_NUMBER;
+ break;
+ }
+
+ ERR("Got unknown character %c(%x)\n",ch,ch);
+ rc = COND_ERROR;
+ break;
+ }
+
+ /* keyword identifiers */
+ if( rc == COND_IDENT )
+ {
+ if( (len==3) && (strncmpiW(str->data,szNot,len)==0) )
+ rc = COND_NOT;
+ else if( (len==3) && (strncmpiW(str->data,szAnd,len)==0) )
+ rc = COND_AND;
+ else if( (len==2) && (strncmpiW(str->data,szOr,len)==0) )
+ rc = COND_OR;
+ }
+
+ cond->n += len;
+ str->len = len;
+
+ return rc;
+}
+
+static int COND_lex( void *COND_lval, COND_input *cond )
+{
+ int rc;
+ struct cond_str *str = COND_lval;
+
+ do {
+ rc = COND_GetOne( str, cond );
+ } while (rc == COND_SPACE);
+
+ return rc;
+}
+
+static LPWSTR COND_GetString( struct cond_str *str )
+{
+ LPWSTR ret;
+
+ ret = HeapAlloc( GetProcessHeap(), 0, (str->len+1) * sizeof (WCHAR) );
+ if( ret )
+ {
+ strncpyW( ret, str->data, str->len );
+ ret[str->len]=0;
+ }
+ TRACE("Got identifier %s\n",debugstr_w(ret));
+ return ret;
+}
+
+static LPWSTR COND_GetLiteral( struct cond_str *str )
+{
+ LPWSTR ret;
+
+ ret = HeapAlloc( GetProcessHeap(), 0, (str->len-1) * sizeof (WCHAR) );
+ if( ret )
+ {
+ memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) );
+ ret[str->len - 2]=0;
+ }
+ TRACE("Got literal %s\n",debugstr_w(ret));
+ return ret;
+}
+
+static int COND_error(char *str)
+{
+ return 0;
+}
+
+MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition )
+{
+ COND_input cond;
+ MSICONDITION r;
+
+ cond.package = package;
+ cond.str = szCondition;
+ cond.n = 0;
+ cond.result = -1;
+
+ TRACE("Evaluating %s\n",debugstr_w(szCondition));
+
+ if( !COND_parse( &cond ) )
+ r = cond.result;
+ else
+ r = MSICONDITION_ERROR;
+
+ TRACE("Evaluates to %i\n",r);
+ return r;
+}
+
+MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition )
+{
+ MSIPACKAGE *package;
+ UINT ret;
+
+ package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
+ if( !package)
+ return ERROR_INVALID_HANDLE;
+ ret = MSI_EvaluateConditionW( package, szCondition );
+ msiobj_release( &package->hdr );
+ return ret;
+}
+
+MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition )
+{
+ LPWSTR szwCond = NULL;
+ MSICONDITION r;
+
+ if( szCondition )
+ {
+ UINT len = MultiByteToWideChar( CP_ACP, 0, szCondition, -1, NULL, 0 );
+ szwCond = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
+ MultiByteToWideChar( CP_ACP, 0, szCondition, -1, szwCond, len );
+ }
+
+ r = MsiEvaluateConditionW( hInstall, szwCond );
+
+ if( szwCond )
+ HeapFree( GetProcessHeap(), 0, szwCond );
+
+ return r;
+}
reactos/lib/msi
diff -N create.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ create.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,258 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002-2004 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+
+#include "query.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+
+/* below is the query interface to a table */
+
+typedef struct tagMSICREATEVIEW
+{
+ MSIVIEW view;
+ MSIDATABASE *db;
+ LPWSTR name;
+ BOOL bIsTemp;
+ create_col_info *col_info;
+} MSICREATEVIEW;
+
+static UINT CREATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
+{
+ MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
+
+ TRACE("%p %d %d %p\n", cv, row, col, val );
+
+ return ERROR_FUNCTION_FAILED;
+}
+
+static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
+{
+ MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
+ create_col_info *col;
+ UINT r, nField, row, table_val, column_val;
+ static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 };
+ static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 };
+ MSIVIEW *tv = NULL;
+
+ TRACE("%p Table %s (%s)\n", cv, debugstr_w(cv->name),
+ cv->bIsTemp?"temporary":"permanent");
+
+ /* only add tables that don't exist already */
+ if( TABLE_Exists(cv->db, cv->name ) )
+ return ERROR_BAD_QUERY_SYNTAX;
+
+ /* add the name to the _Tables table */
+ table_val = msi_addstringW( cv->db->strings, 0, cv->name, -1, 1 );
+ TRACE("New string %s -> %d\n", debugstr_w( cv->name ), table_val );
+ if( table_val < 0 )
+ return ERROR_FUNCTION_FAILED;
+
+ r = TABLE_CreateView( cv->db, szTables, &tv );
+ TRACE("CreateView returned %x\n", r);
+ if( r )
+ return r;
+
+ r = tv->ops->execute( tv, 0 );
+ TRACE("tv execute returned %x\n", r);
+ if( r )
+ return r;
+
+ row = -1;
+ r = tv->ops->insert_row( tv, &row );
+ TRACE("insert_row returned %x\n", r);
+ if( r )
+ goto err;
+
+ r = tv->ops->set_int( tv, row, 1, table_val );
+ if( r )
+ goto err;
+ tv->ops->delete( tv );
+ tv = NULL;
+
+ /* add each column to the _Columns table */
+ r = TABLE_CreateView( cv->db, szColumns, &tv );
+ if( r )
+ return r;
+
+ r = tv->ops->execute( tv, 0 );
+ TRACE("tv execute returned %x\n", r);
+ if( r )
+ return r;
+
+ /*
+ * need to set the table, column number, col name and type
+ * for each column we enter in the table
+ */
+ nField = 1;
+ for( col = cv->col_info; col; col = col->next )
+ {
+ row = -1;
+ r = tv->ops->insert_row( tv, &row );
+ if( r )
+ goto err;
+
+ column_val = msi_addstringW( cv->db->strings, 0, col->colname, -1, 1 );
+ TRACE("New string %s -> %d\n", debugstr_w( col->colname ), column_val );
+ if( column_val < 0 )
+ break;
+
+ /* add the string again here so we increase the reference count */
+ table_val = msi_addstringW( cv->db->strings, 0, cv->name, -1, 1 );
+ if( table_val < 0 )
+ break;
+
+ r = tv->ops->set_int( tv, row, 1, table_val );
+ if( r )
+ break;
+
+ r = tv->ops->set_int( tv, row, 2, 0x8000|nField );
+ if( r )
+ break;
+
+ r = tv->ops->set_int( tv, row, 3, column_val );
+ if( r )
+ break;
+
+ r = tv->ops->set_int( tv, row, 4, 0x8000|col->type );
+ if( r )
+ break;
+
+ nField++;
+ }
+ if( !col )
+ r = ERROR_SUCCESS;
+
+err:
+ /* FIXME: remove values from the string table on error */
+ if( tv )
+ tv->ops->delete( tv );
+ return r;
+}
+
+static UINT CREATE_close( struct tagMSIVIEW *view )
+{
+ MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
+
+ TRACE("%p\n", cv);
+
+ return ERROR_SUCCESS;
+}
+
+static UINT CREATE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
+{
+ MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
+
+ TRACE("%p %p %p\n", cv, rows, cols );
+
+ return ERROR_FUNCTION_FAILED;
+}
+
+static UINT CREATE_get_column_info( struct tagMSIVIEW *view,
+ UINT n, LPWSTR *name, UINT *type )
+{
+ MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
+
+ TRACE("%p %d %p %p\n", cv, n, name, type );
+
+ return ERROR_FUNCTION_FAILED;
+}
+
+static UINT CREATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
+{
+ MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
+
+ TRACE("%p %d %ld\n", cv, eModifyMode, hrec );
+
+ return ERROR_FUNCTION_FAILED;
+}
+
+static UINT CREATE_delete( struct tagMSIVIEW *view )
+{
+ MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
+ create_col_info *col;
+
+ TRACE("%p\n", cv );
+
+ col = cv->col_info;
+ while( col )
+ {
+ create_col_info *t = col;
+ col = col->next;
+ HeapFree( GetProcessHeap(), 0, t->colname );
+ HeapFree( GetProcessHeap(), 0, t );
+ }
+ msiobj_release( &cv->db->hdr );
+ HeapFree( GetProcessHeap(), 0, cv->name );
+ HeapFree( GetProcessHeap(), 0, cv );
+
+ return ERROR_SUCCESS;
+}
+
+
+MSIVIEWOPS create_ops =
+{
+ CREATE_fetch_int,
+ NULL,
+ NULL,
+ NULL,
+ CREATE_execute,
+ CREATE_close,
+ CREATE_get_dimensions,
+ CREATE_get_column_info,
+ CREATE_modify,
+ CREATE_delete
+};
+
+UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
+ create_col_info *col_info, BOOL temp )
+{
+ MSICREATEVIEW *cv = NULL;
+
+ TRACE("%p\n", cv );
+
+ cv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *cv );
+ if( !cv )
+ return ERROR_FUNCTION_FAILED;
+
+ /* fill the structure */
+ cv->view.ops = &create_ops;
+ msiobj_addref( &db->hdr );
+ cv->db = db;
+ cv->name = table; /* FIXME: strdupW it? */
+ cv->col_info = col_info;
+ cv->bIsTemp = temp;
+ *view = (MSIVIEW*) cv;
+
+ return ERROR_SUCCESS;
+}
reactos/lib/msi
diff -N distinct.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ distinct.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,293 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+
+#include "query.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+typedef struct tagDISTINCTSET
+{
+ UINT val;
+ UINT count;
+ UINT row;
+ struct tagDISTINCTSET *nextrow;
+ struct tagDISTINCTSET *nextcol;
+} DISTINCTSET;
+
+typedef struct tagMSIDISTINCTVIEW
+{
+ MSIVIEW view;
+ MSIDATABASE *db;
+ MSIVIEW *table;
+ UINT row_count;
+ UINT *translation;
+} MSIDISTINCTVIEW;
+
+static DISTINCTSET ** distinct_insert( DISTINCTSET **x, UINT val, UINT row )
+{
+ /* horrible O(n) find */
+ while( *x )
+ {
+ if( (*x)->val == val )
+ {
+ (*x)->count++;
+ return x;
+ }
+ x = &(*x)->nextrow;
+ }
+
+ /* nothing found, so add one */
+ *x = HeapAlloc( GetProcessHeap(), 0, sizeof (DISTINCTSET) );
+ if( *x )
+ {
+ (*x)->val = val;
+ (*x)->count = 1;
+ (*x)->row = row;
+ (*x)->nextrow = NULL;
+ (*x)->nextcol = NULL;
+ }
+ return x;
+}
+
+static void distinct_free( DISTINCTSET *x )
+{
+ while( x )
+ {
+ DISTINCTSET *next = x->nextrow;
+ distinct_free( x->nextcol );
+ HeapFree( GetProcessHeap(), 0, x );
+ x = next;
+ }
+}
+
+static UINT DISTINCT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
+{
+ MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+
+ TRACE("%p %d %d %p\n", dv, row, col, val );
+
+ if( !dv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( row >= dv->row_count )
+ return ERROR_INVALID_PARAMETER;
+
+ row = dv->translation[ row ];
+
+ return dv->table->ops->fetch_int( dv->table, row, col, val );
+}
+
+static UINT DISTINCT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
+{
+ MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+ UINT r, i, j, r_count, c_count;
+ DISTINCTSET *rowset = NULL;
+
+ TRACE("%p %p\n", dv, record);
+
+ if( !dv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ r = dv->table->ops->execute( dv->table, record );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ r = dv->table->ops->get_dimensions( dv->table, &r_count, &c_count );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ dv->translation = HeapAlloc( GetProcessHeap(), 0, r_count*sizeof(UINT) );
+ if( !dv->translation )
+ return ERROR_FUNCTION_FAILED;
+
+ /* build it */
+ for( i=0; i<r_count; i++ )
+ {
+ DISTINCTSET **x = &rowset;
+
+ for( j=1; j<=c_count; j++ )
+ {
+ UINT val = 0;
+ r = dv->table->ops->fetch_int( dv->table, i, j, &val );
+ if( r != ERROR_SUCCESS )
+ {
+ ERR("Failed to fetch int at %d %d\n", i, j );
+ distinct_free( rowset );
+ return r;
+ }
+ x = distinct_insert( x, val, i );
+ if( !*x )
+ {
+ ERR("Failed to insert at %d %d\n", i, j );
+ distinct_free( rowset );
+ return ERROR_FUNCTION_FAILED;
+ }
+ if( j != c_count )
+ x = &(*x)->nextcol;
+ }
+
+ /* check if it was distinct and if so, include it */
+ if( (*x)->row == i )
+ {
+ TRACE("Row %d -> %d\n", dv->row_count, i);
+ dv->translation[dv->row_count++] = i;
+ }
+ }
+
+ distinct_free( rowset );
+
+ return ERROR_SUCCESS;
+}
+
+static UINT DISTINCT_close( struct tagMSIVIEW *view )
+{
+ MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+
+ TRACE("%p\n", dv );
+
+ if( !dv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( dv->translation )
+ HeapFree( GetProcessHeap(), 0, dv->translation );
+ dv->translation = NULL;
+ dv->row_count = 0;
+
+ return dv->table->ops->close( dv->table );
+}
+
+static UINT DISTINCT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
+{
+ MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+
+ TRACE("%p %p %p\n", dv, rows, cols );
+
+ if( !dv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( rows )
+ {
+ if( !dv->translation )
+ return ERROR_FUNCTION_FAILED;
+ *rows = dv->row_count;
+ }
+
+ return dv->table->ops->get_dimensions( dv->table, NULL, cols );
+}
+
+static UINT DISTINCT_get_column_info( struct tagMSIVIEW *view,
+ UINT n, LPWSTR *name, UINT *type )
+{
+ MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+
+ TRACE("%p %d %p %p\n", dv, n, name, type );
+
+ if( !dv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ return dv->table->ops->get_column_info( dv->table, n, name, type );
+}
+
+static UINT DISTINCT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
+{
+ MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+
+ TRACE("%p %d %ld\n", dv, eModifyMode, hrec );
+
+ if( !dv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ return dv->table->ops->modify( dv->table, eModifyMode, hrec );
+}
+
+static UINT DISTINCT_delete( struct tagMSIVIEW *view )
+{
+ MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
+
+ TRACE("%p\n", dv );
+
+ if( dv->table )
+ dv->table->ops->delete( dv->table );
+
+ if( dv->translation )
+ HeapFree( GetProcessHeap(), 0, dv->translation );
+ msiobj_release( &dv->db->hdr );
+ HeapFree( GetProcessHeap(), 0, dv );
+
+ return ERROR_SUCCESS;
+}
+
+
+MSIVIEWOPS distinct_ops =
+{
+ DISTINCT_fetch_int,
+ NULL,
+ NULL,
+ NULL,
+ DISTINCT_execute,
+ DISTINCT_close,
+ DISTINCT_get_dimensions,
+ DISTINCT_get_column_info,
+ DISTINCT_modify,
+ DISTINCT_delete
+};
+
+UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
+{
+ MSIDISTINCTVIEW *dv = NULL;
+ UINT count = 0, r;
+
+ TRACE("%p\n", dv );
+
+ r = table->ops->get_dimensions( table, NULL, &count );
+ if( r != ERROR_SUCCESS )
+ {
+ ERR("can't get table dimensions\n");
+ return r;
+ }
+
+ dv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *dv );
+ if( !dv )
+ return ERROR_FUNCTION_FAILED;
+
+ /* fill the structure */
+ dv->view.ops = &distinct_ops;
+ msiobj_addref( &db->hdr );
+ dv->db = db;
+ dv->table = table;
+ dv->translation = NULL;
+ dv->row_count = 0;
+ *view = (MSIVIEW*) dv;
+
+ return ERROR_SUCCESS;
+}
reactos/lib/msi
diff -N handle.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ handle.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,215 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002-2004 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "shlwapi.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "msipriv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+static CRITICAL_SECTION MSI_handle_cs;
+static CRITICAL_SECTION_DEBUG MSI_handle_cs_debug =
+{
+ 0, 0, &MSI_handle_cs,
+ { &MSI_handle_cs_debug.ProcessLocksList,
+ &MSI_handle_cs_debug.ProcessLocksList },
+ 0, 0, { 0, (DWORD)(__FILE__ ": MSI_handle_cs") }
+};
+static CRITICAL_SECTION MSI_handle_cs = { &MSI_handle_cs_debug, -1, 0, 0, 0, 0 };
+
+MSIOBJECTHDR *msihandletable[MSIMAXHANDLES];
+
+MSIHANDLE alloc_msihandle( MSIOBJECTHDR *obj )
+{
+ MSIHANDLE ret = 0;
+ UINT i;
+
+ EnterCriticalSection( &MSI_handle_cs );
+
+ /* find a slot */
+ for(i=0; i<MSIMAXHANDLES; i++)
+ if( !msihandletable[i] )
+ break;
+ if( (i>=MSIMAXHANDLES) || msihandletable[i] )
+ goto out;
+
+ msiobj_addref( obj );
+ msihandletable[i] = obj;
+ ret = (MSIHANDLE) (i+1);
+out:
+ TRACE("%p -> %ld\n", obj, ret );
+
+ LeaveCriticalSection( &MSI_handle_cs );
+ return ret;
+}
+
+void *msihandle2msiinfo(MSIHANDLE handle, UINT type)
+{
+ MSIOBJECTHDR *ret = NULL;
+
+ EnterCriticalSection( &MSI_handle_cs );
+ handle--;
+ if( handle<0 )
+ goto out;
+ if( handle>=MSIMAXHANDLES )
+ goto out;
+ if( !msihandletable[handle] )
+ goto out;
+ if( msihandletable[handle]->magic != MSIHANDLE_MAGIC )
+ goto out;
+ if( type && (msihandletable[handle]->type != type) )
+ goto out;
+ ret = msihandletable[handle];
+ msiobj_addref( ret );
+
+out:
+ LeaveCriticalSection( &MSI_handle_cs );
+
+ return (void*) ret;
+}
+
+MSIHANDLE msiobj_findhandle( MSIOBJECTHDR *hdr )
+{
+ MSIHANDLE ret = 0;
+ UINT i;
+
+ TRACE("%p\n", hdr);
+
+ EnterCriticalSection( &MSI_handle_cs );
+ for(i=0; (i<MSIMAXHANDLES) && !ret; i++)
+ if( msihandletable[i] == hdr )
+ ret = i+1;
+ LeaveCriticalSection( &MSI_handle_cs );
+
+ TRACE("%p -> %ld\n", hdr, ret);
+
+ msiobj_addref( hdr );
+ return ret;
+}
+
+void *alloc_msiobject(UINT type, UINT size, msihandledestructor destroy )
+{
+ MSIOBJECTHDR *info;
+
+ info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
+ if( info )
+ {
+ info->magic = MSIHANDLE_MAGIC;
+ info->type = type;
+ info->refcount = 1;
+ info->destructor = destroy;
+ }
+
+ return info;
+}
+
+void msiobj_addref( MSIOBJECTHDR *info )
+{
+ TRACE("%p\n", info);
+
+ if( !info )
+ return;
+
+ if( info->magic != MSIHANDLE_MAGIC )
+ {
+ ERR("Invalid handle!\n");
+ return;
+ }
+
+ info->refcount++;
+}
+
+int msiobj_release( MSIOBJECTHDR *info )
+{
+ int ret;
+
+ TRACE("%p\n",info);
+
+ if( !info )
+ return -1;
+
+ if( info->magic != MSIHANDLE_MAGIC )
+ {
+ ERR("Invalid handle!\n");
+ return -1;
+ }
+
+ ret = info->refcount--;
+ if (info->refcount == 0)
+ {
+ if( info->destructor )
+ info->destructor( info );
+ HeapFree( GetProcessHeap(), 0, info );
+ TRACE("object %p destroyed\n", info);
+ }
+
+ return ret;
+}
+
+UINT WINAPI MsiCloseHandle(MSIHANDLE handle)
+{
+ MSIOBJECTHDR *info;
+ UINT ret = ERROR_INVALID_HANDLE;
+
+ TRACE("%lx\n",handle);
+
+ EnterCriticalSection( &MSI_handle_cs );
+
+ info = msihandle2msiinfo(handle, 0);
+ if( !info )
+ goto out;
+
+ if( info->magic != MSIHANDLE_MAGIC )
+ {
+ ERR("Invalid handle!\n");
+ goto out;
+ }
+
+ msiobj_release( info );
+ msihandletable[handle-1] = NULL;
+ ret = ERROR_SUCCESS;
+
+ TRACE("handle %lx Destroyed\n", handle);
+out:
+ LeaveCriticalSection( &MSI_handle_cs );
+ if( info )
+ msiobj_release( info );
+
+ return ret;
+}
+
+UINT WINAPI MsiCloseAllHandles(void)
+{
+ UINT i;
+
+ TRACE("\n");
+
+ for(i=0; i<MSIMAXHANDLES; i++)
+ MsiCloseHandle( i+1 );
+
+ return 0;
+}
reactos/lib/msi
diff -N insert.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ insert.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,238 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2004 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+
+#include "query.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+
+/* below is the query interface to a table */
+
+typedef struct tagMSIINSERTVIEW
+{
+ MSIVIEW view;
+ MSIDATABASE *db;
+ BOOL bIsTemp;
+ MSIVIEW *sv;
+ value_list *vals; /* looks like these may be ignored... */
+} MSIINSERTVIEW;
+
+static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
+{
+ MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
+
+ TRACE("%p %d %d %p\n", iv, row, col, val );
+
+ return ERROR_FUNCTION_FAILED;
+}
+
+static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
+{
+ MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
+ UINT n, type, val, r, row, col_count = 0;
+ MSIVIEW *sv;
+
+ TRACE("%p %p\n", iv, record );
+
+ sv = iv->sv;
+ if( !sv )
+ return ERROR_FUNCTION_FAILED;
+
+ r = sv->ops->execute( sv, 0 );
+ TRACE("tv execute returned %x\n", r);
+ if( r )
+ return r;
+
+ r = sv->ops->get_dimensions( sv, NULL, &col_count );
+ if( r )
+ goto err;
+
+ n = MSI_RecordGetFieldCount( record );
+ if( n != col_count )
+ {
+ ERR("Number of fields do not match\n");
+ goto err;
+ }
+
+ row = -1;
+ r = sv->ops->insert_row( sv, &row );
+ TRACE("insert_row returned %x\n", r);
+ if( r )
+ goto err;
+
+ for( n = 1; n <= col_count; n++ )
+ {
+ r = sv->ops->get_column_info( sv, n, NULL, &type );
+ if( r )
+ break;
+
+ if( type & MSITYPE_STRING )
+ {
+ const WCHAR *str = MSI_RecordGetString( record, n );
+ val = msi_addstringW( iv->db->strings, 0, str, -1, 1 );
+ }
+ else
+ {
+ val = MSI_RecordGetInteger( record, n );
+ val |= 0x8000;
+ }
+ r = sv->ops->set_int( sv, row, n, val );
+ if( r )
+ break;
+ }
+
+err:
+ return ERROR_SUCCESS;
+}
+
+
+static UINT INSERT_close( struct tagMSIVIEW *view )
+{
+ MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
+ MSIVIEW *sv;
+
+ TRACE("%p\n", iv);
+
+ sv = iv->sv;
+ if( !sv )
+ return ERROR_FUNCTION_FAILED;
+
+ return sv->ops->close( sv );
+}
+
+static UINT INSERT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
+{
+ MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
+ MSIVIEW *sv;
+
+ TRACE("%p %p %p\n", iv, rows, cols );
+
+ sv = iv->sv;
+ if( !sv )
+ return ERROR_FUNCTION_FAILED;
+
+ return sv->ops->get_dimensions( sv, rows, cols );
+}
+
+static UINT INSERT_get_column_info( struct tagMSIVIEW *view,
+ UINT n, LPWSTR *name, UINT *type )
+{
+ MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
+ MSIVIEW *sv;
+
+ TRACE("%p %d %p %p\n", iv, n, name, type );
+
+ sv = iv->sv;
+ if( !sv )
+ return ERROR_FUNCTION_FAILED;
+
+ return sv->ops->get_column_info( sv, n, name, type );
+}
+
+static UINT INSERT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
+{
+ MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
+
+ TRACE("%p %d %ld\n", iv, eModifyMode, hrec );
+
+ return ERROR_FUNCTION_FAILED;
+}
+
+static UINT INSERT_delete( struct tagMSIVIEW *view )
+{
+ MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
+ MSIVIEW *sv;
+
+ TRACE("%p\n", iv );
+
+ sv = iv->sv;
+ if( sv )
+ sv->ops->delete( sv );
+ delete_value_list( iv->vals );
+ msiobj_release( &iv->db->hdr );
+ HeapFree( GetProcessHeap(), 0, iv );
+
+ return ERROR_SUCCESS;
+}
+
+
+MSIVIEWOPS insert_ops =
+{
+ INSERT_fetch_int,
+ NULL,
+ NULL,
+ NULL,
+ INSERT_execute,
+ INSERT_close,
+ INSERT_get_dimensions,
+ INSERT_get_column_info,
+ INSERT_modify,
+ INSERT_delete
+};
+
+UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
+ string_list *columns, value_list *values, BOOL temp )
+{
+ MSIINSERTVIEW *iv = NULL;
+ UINT r;
+ MSIVIEW *tv = NULL, *sv = NULL;
+
+ TRACE("%p\n", iv );
+
+ r = TABLE_CreateView( db, table, &tv );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ r = SELECT_CreateView( db, &sv, tv, columns );
+ if( r != ERROR_SUCCESS )
+ {
+ if( tv )
+ tv->ops->delete( tv );
+ return r;
+ }
+
+ iv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *iv );
+ if( !iv )
+ return ERROR_FUNCTION_FAILED;
+
+ /* fill the structure */
+ iv->view.ops = &insert_ops;
+ msiobj_addref( &db->hdr );
+ iv->db = db;
+ iv->vals = values;
+ iv->bIsTemp = temp;
+ iv->sv = sv;
+ *view = (MSIVIEW*) iv;
+
+ return ERROR_SUCCESS;
+}
reactos/lib/msi
diff -N msi.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ msi.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,1584 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002,2003,2004 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winnls.h"
+#include "shlwapi.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "msipriv.h"
+#include "objidl.h"
+#include "wincrypt.h"
+#include "wine/unicode.h"
+#include "objbase.h"
+#include "winver.h"
+
+#include "initguid.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+/*
+ * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
+ * which is a problem because LPCTSTR isn't defined when compiling wine.
+ * To work around this problem, we need to define LPCTSTR as LPCWSTR here,
+ * and make sure to only use it in W functions.
+ */
+#define LPCTSTR LPCWSTR
+
+DEFINE_GUID( CLSID_MsiDatabase, 0x000c1084, 0x0000, 0x0000, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
+
+static const WCHAR szInstaller[] = {
+'S','o','f','t','w','a','r','e','\\',
+'M','i','c','r','o','s','o','f','t','\\',
+'W','i','n','d','o','w','s','\\',
+'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+'I','n','s','t','a','l','l','e','r',0 };
+
+static const WCHAR szFeatures[] = {
+'F','e','a','t','u','r','e','s',0 };
+static const WCHAR szComponents[] = {
+'C','o','m','p','o','n','e','n','t','s',0 };
+
+/* the UI level */
+INSTALLUILEVEL gUILevel;
+HWND gUIhwnd;
+INSTALLUI_HANDLERA gUIHandler;
+DWORD gUIFilter;
+LPVOID gUIContext;
+WCHAR gszLogFile[MAX_PATH];
+
+/*
+ * .MSI file format
+ *
+ * A .msi file is a structured storage file.
+ * It should contain a number of streams.
+ */
+
+BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
+{
+ DWORD i,n=0;
+
+ out[n++]='{';
+ for(i=0; i<8; i++)
+ out[n++] = in[7-i];
+ out[n++]='-';
+ for(i=0; i<4; i++)
+ out[n++] = in[11-i];
+ out[n++]='-';
+ for(i=0; i<4; i++)
+ out[n++] = in[15-i];
+ out[n++]='-';
+ for(i=0; i<2; i++)
+ {
+ out[n++] = in[17+i*2];
+ out[n++] = in[16+i*2];
+ }
+ out[n++]='-';
+ for( ; i<8; i++)
+ {
+ out[n++] = in[17+i*2];
+ out[n++] = in[16+i*2];
+ }
+ out[n++]='}';
+ out[n]=0;
+ return TRUE;
+}
+
+BOOL squash_guid(LPCWSTR in, LPWSTR out)
+{
+ DWORD i,n=0;
+
+ if(in[n++] != '{')
+ return FALSE;
+ for(i=0; i<8; i++)
+ out[7-i] = in[n++];
+ if(in[n++] != '-')
+ return FALSE;
+ for(i=0; i<4; i++)
+ out[11-i] = in[n++];
+ if(in[n++] != '-')
+ return FALSE;
+ for(i=0; i<4; i++)
+ out[15-i] = in[n++];
+ if(in[n++] != '-')
+ return FALSE;
+ for(i=0; i<2; i++)
+ {
+ out[17+i*2] = in[n++];
+ out[16+i*2] = in[n++];
+ }
+ if(in[n++] != '-')
+ return FALSE;
+ for( ; i<8; i++)
+ {
+ out[17+i*2] = in[n++];
+ out[16+i*2] = in[n++];
+ }
+ out[32]=0;
+ if(in[n++] != '}')
+ return FALSE;
+ if(in[n])
+ return FALSE;
+ return TRUE;
+}
+
+/* tables for encoding and decoding base85 */
+static const unsigned char table_dec85[0x80] = {
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
+0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
+0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
+0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
+0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
+0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
+};
+
+static const char table_enc85[] =
+"!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO"
+"PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx"
+"yz{}~";
+
+/*
+ * Converts a base85 encoded guid into a GUID pointer
+ * Base85 encoded GUIDs should be 20 characters long.
+ *
+ * returns TRUE if successful, FALSE if not
+ */
+BOOL decode_base85_guid( LPCWSTR str, GUID *guid )
+{
+ DWORD i, val = 0, base = 1, *p;
+
+ p = (DWORD*) guid;
+ for( i=0; i<20; i++ )
+ {
+ if( (i%5) == 0 )
+ {
+ val = 0;
+ base = 1;
+ }
+ val += table_dec85[str[i]] * base;
+ if( str[i] >= 0x80 )
+ return FALSE;
+ if( table_dec85[str[i]] == 0xff )
+ return FALSE;
+ if( (i%5) == 4 )
+ p[i/5] = val;
+ base *= 85;
+ }
+ return TRUE;
+}
+
+/*
+ * Encodes a base85 guid given a GUID pointer
+ * Caller should provide a 21 character buffer for the encoded string.
+ *
+ * returns TRUE if successful, FALSE if not
+ */
+BOOL encode_base85_guid( GUID *guid, LPWSTR str )
+{
+ unsigned int x, *p, i;
+
+ p = (unsigned int*) guid;
+ for( i=0; i<4; i++ )
+ {
+ x = p[i];
+ *str++ = table_enc85[x%85];
+ x = x/85;
+ *str++ = table_enc85[x%85];
+ x = x/85;
+ *str++ = table_enc85[x%85];
+ x = x/85;
+ *str++ = table_enc85[x%85];
+ x = x/85;
+ *str++ = table_enc85[x%85];
+ }
+ *str = 0;
+
+ return TRUE;
+}
+
+
+VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
+{
+ MSIDATABASE *db = (MSIDATABASE *) arg;
+
+ free_cached_tables( db );
+ IStorage_Release( db->storage );
+}
+
+UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
+{
+ IStorage *stg = NULL;
+ HRESULT r;
+ MSIDATABASE *db = NULL;
+ UINT ret = ERROR_FUNCTION_FAILED;
+ LPWSTR szMode;
+ STATSTG stat;
+
+ TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) );
+
+ if( !pdb )
+ return ERROR_INVALID_PARAMETER;
+
+ szMode = (LPWSTR) szPersist;
+ if( HIWORD( szPersist ) )
+ {
+ /* UINT len = lstrlenW( szPerist ) + 1; */
+ FIXME("don't support persist files yet\b");
+ return ERROR_INVALID_PARAMETER;
+ /* szMode = HeapAlloc( GetProcessHeap(), 0, len * sizeof (DWORD) ); */
+ }
+ else if( szPersist == MSIDBOPEN_READONLY )
+ {
+ r = StgOpenStorage( szDBPath, NULL,
+ STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
+ }
+ else if( szPersist == MSIDBOPEN_CREATE )
+ {
+ r = StgCreateDocfile( szDBPath,
+ STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg);
+ if( r == ERROR_SUCCESS )
+ {
+ IStorage_SetClass( stg, &CLSID_MsiDatabase );
+ r = init_string_table( stg );
+ }
+ }
+ else if( szPersist == MSIDBOPEN_TRANSACT )
+ {
+ r = StgOpenStorage( szDBPath, NULL,
+ STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
+ }
+ else
+ {
+ ERR("unknown flag %p\n",szPersist);
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if( FAILED( r ) )
+ {
+ FIXME("open failed r = %08lx!\n",r);
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
+ if( FAILED( r ) )
+ {
+ FIXME("Failed to stat storage\n");
+ goto end;
+ }
+
+ if( memcmp( &stat.clsid, &CLSID_MsiDatabase, sizeof (GUID) ) )
+ {
+ ERR("storage GUID is not a MSI database GUID %s\n",
+ debugstr_guid(&stat.clsid) );
+ goto end;
+ }
+
+
+ db = alloc_msiobject( MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE),
+ MSI_CloseDatabase );
+ if( !db )
+ {
+ FIXME("Failed to allocate a handle\n");
+ goto end;
+ }
+
+ if( TRACE_ON( msi ) )
+ enum_stream_names( stg );
+
+ db->storage = stg;
+ db->mode = szMode;
+
+ ret = load_string_table( db );
+ if( ret != ERROR_SUCCESS )
+ goto end;
+
+ msiobj_addref( &db->hdr );
+ IStorage_AddRef( stg );
+ *pdb = db;
+
+end:
+ if( db )
+ msiobj_release( &db->hdr );
+ if( stg )
+ IStorage_Release( stg );
+
+ return ret;
+}
+
+UINT WINAPI MsiOpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB)
+{
+ MSIDATABASE *db;
+ UINT ret;
+
+ TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB);
+
+ ret = MSI_OpenDatabaseW( szDBPath, szPersist, &db );
+ if( ret == ERROR_SUCCESS )
+ {
+ *phDB = alloc_msihandle( &db->hdr );
+ msiobj_release( &db->hdr );
+ }
+
+ return ret;
+}
+
+UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
+{
+ HRESULT r = ERROR_FUNCTION_FAILED;
+ LPWSTR szwDBPath = NULL, szwPersist = NULL;
+ UINT len;
+
+ TRACE("%s %s %p\n", debugstr_a(szDBPath), debugstr_a(szPersist), phDB);
+
+ if( szDBPath )
+ {
+ len = MultiByteToWideChar( CP_ACP, 0, szDBPath, -1, NULL, 0 );
+ szwDBPath = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ if( !szwDBPath )
+ goto end;
+ MultiByteToWideChar( CP_ACP, 0, szDBPath, -1, szwDBPath, len );
+ }
+
+ if( HIWORD(szPersist) )
+ {
+ len = MultiByteToWideChar( CP_ACP, 0, szPersist, -1, NULL, 0 );
+ szwPersist = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ if( !szwPersist )
+ goto end;
+ MultiByteToWideChar( CP_ACP, 0, szPersist, -1, szwPersist, len );
+ }
+ else
+ szwPersist = (LPWSTR) szPersist;
+
+ r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
+
+end:
+ if( szwPersist )
+ HeapFree( GetProcessHeap(), 0, szwPersist );
+ if( szwDBPath )
+ HeapFree( GetProcessHeap(), 0, szwDBPath );
+
+ return r;
+}
+
+UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
+{
+ UINT len, ret;
+ LPWSTR szwProd = NULL;
+
+ TRACE("%s %p\n",debugstr_a(szProduct), phProduct);
+
+ if( szProduct )
+ {
+ len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 );
+ szwProd = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
+ if( szwProd )
+ MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProd, len );
+ }
+
+ ret = MsiOpenProductW( szwProd, phProduct );
+
+ if( szwProd )
+ HeapFree( GetProcessHeap(), 0, szwProd );
+
+ return ret;
+}
+
+UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct)
+{
+ static const WCHAR szKey[] = {
+ 'S','o','f','t','w','a','r','e','\\',
+ 'M','i','c','r','o','s','o','f','t','\\',
+ 'W','i','n','d','o','w','s','\\',
+ 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+ 'U','n','i','n','s','t','a','l','l',0 };
+ static const WCHAR szLocalPackage[] = {
+ 'L','o','c','a','l','P','a','c','k','a','g','e', 0
+ };
+ LPWSTR path = NULL;
+ UINT r;
+ HKEY hKeyProduct = NULL, hKeyUninstall = NULL;
+ DWORD count, type;
+
+ TRACE("%s %p\n",debugstr_w(szProduct), phProduct);
+
+ r = RegOpenKeyW( HKEY_LOCAL_MACHINE, szKey, &hKeyUninstall );
+ if( r != ERROR_SUCCESS )
+ return ERROR_UNKNOWN_PRODUCT;
+
+ r = RegOpenKeyW( hKeyUninstall, szProduct, &hKeyProduct );
+ if( r != ERROR_SUCCESS )
+ {
+ r = ERROR_UNKNOWN_PRODUCT;
+ goto end;
+ }
+
+ /* find the size of the path */
+ type = count = 0;
+ r = RegQueryValueExW( hKeyProduct, szLocalPackage,
+ NULL, &type, NULL, &count );
+ if( r != ERROR_SUCCESS )
+ {
+ r = ERROR_UNKNOWN_PRODUCT;
+ goto end;
+ }
+
+ /* now alloc and fetch the path of the database to open */
+ path = HeapAlloc( GetProcessHeap(), 0, count );
+ if( !path )
+ goto end;
+
+ r = RegQueryValueExW( hKeyProduct, szLocalPackage,
+ NULL, &type, (LPBYTE) path, &count );
+ if( r != ERROR_SUCCESS )
+ {
+ r = ERROR_UNKNOWN_PRODUCT;
+ goto end;
+ }
+
+ r = MsiOpenPackageW( path, phProduct );
+
+end:
+ if( path )
+ HeapFree( GetProcessHeap(), 0, path );
+ if( hKeyProduct )
+ RegCloseKey( hKeyProduct );
+ RegCloseKey( hKeyUninstall );
+
+ return r;
+}
+
+UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, LPCSTR szTransforms, LANGID lgidLanguage)
+{
+ FIXME("%s %s %s 0x%08x\n",debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, LPCWSTR szTransforms, LANGID lgidLanguage)
+{
+ FIXME("%s %s %s 0x%08x\n",debugstr_w(szPackagePath), debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
+{
+ FIXME("%s %s %s 0x%08x 0x%08lx 0x%08lx\n",
+ debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage, dwPlatform, dwOptions);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions)
+{
+ FIXME("%s %s %s 0x%08x 0x%08lx 0x%08lx\n",
+ debugstr_w(szPackagePath), debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage, dwPlatform, dwOptions);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
+{
+ LPWSTR szwPath = NULL, szwCommand = NULL;
+ UINT r = ERROR_FUNCTION_FAILED; /* FIXME: check return code */
+
+ TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
+
+ if( szPackagePath )
+ {
+ UINT len = MultiByteToWideChar( CP_ACP, 0, szPackagePath, -1, NULL, 0 );
+ szwPath = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ if( !szwPath )
+ goto end;
+ MultiByteToWideChar( CP_ACP, 0, szPackagePath, -1, szwPath, len );
+ }
+
+ if( szCommandLine )
+ {
+ UINT len = MultiByteToWideChar( CP_ACP, 0, szCommandLine, -1, NULL, 0 );
+ szwCommand = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ if( !szwCommand )
+ goto end;
+ MultiByteToWideChar( CP_ACP, 0, szCommandLine, -1, szwCommand, len );
+ }
+
+ r = MsiInstallProductW( szwPath, szwCommand );
+
+end:
+ if( szwPath )
+ HeapFree( GetProcessHeap(), 0, szwPath );
+
+ if( szwCommand )
+ HeapFree( GetProcessHeap(), 0, szwCommand );
+
+ return r;
+}
+
+UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
+{
+ MSIPACKAGE *package = NULL;
+ UINT rc = ERROR_SUCCESS;
+ MSIHANDLE handle;
+
+ FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
+
+ rc = MsiVerifyPackageW(szPackagePath);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MSI_OpenPackageW(szPackagePath,&package);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ handle = alloc_msihandle( &package->hdr );
+
+ rc = ACTION_DoTopLevelINSTALL(package, szPackagePath, szCommandLine);
+
+ MsiCloseHandle(handle);
+ msiobj_release( &package->hdr );
+ return rc;
+}
+
+UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode)
+{
+ FIXME("%s 0x%08lx\n", debugstr_a(szProduct), dwReinstallMode);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode)
+{
+ FIXME("%s 0x%08lx\n", debugstr_w(szProduct), dwReinstallMode);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage, INSTALLTYPE eInstallType, LPCSTR szCommandLine)
+{
+ FIXME("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage), eInstallType, debugstr_a(szCommandLine));
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage, INSTALLTYPE eInstallType, LPCWSTR szCommandLine)
+{
+ FIXME("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage), eInstallType, debugstr_w(szCommandLine));
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState)
+{
+ LPWSTR szwProduct = NULL;
+ UINT hr = ERROR_SUCCESS;
+
+ FIXME("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
+
+ if( szProduct )
+ {
+ UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 );
+ szwProduct = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ if( !szwProduct )
+ goto end;
+ MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len );
+ }
+
+ hr = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState );
+
+end:
+ if( szwProduct )
+ HeapFree( GetProcessHeap(), 0, szwProduct );
+
+ return hr;
+}
+
+UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState)
+{
+ FIXME("%s %d %d\n",debugstr_w(szProduct), iInstallLevel, eInstallState);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
+{
+ LPWSTR szwComponent = NULL, szwBuffer = NULL;
+ UINT hr = ERROR_INSTALL_FAILURE;
+
+ FIXME("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer));
+
+ if( szComponent )
+ {
+ UINT len = MultiByteToWideChar( CP_ACP, 0, szComponent, -1, NULL, 0 );
+ szwComponent = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ if( !szwComponent )
+ goto end;
+ MultiByteToWideChar( CP_ACP, 0, szComponent, -1, szwComponent, len );
+ } else {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ {
+ szwBuffer = HeapAlloc( GetProcessHeap(), 0, GUID_SIZE * sizeof(WCHAR) );
+ if( !szwBuffer )
+ goto end;
+ }
+
+ hr = MsiGetProductCodeW( szwComponent, szwBuffer );
+
+ if( ERROR_SUCCESS == hr )
+ {
+ WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL);
+ }
+
+end:
+ if( szwComponent )
+ HeapFree( GetProcessHeap(), 0, szwComponent );
+ if( szwBuffer )
+ HeapFree( GetProcessHeap(), 0, szwBuffer );
+
+ return hr;
+}
+
+UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
+{
+ FIXME("%s %s\n",debugstr_w(szComponent), debugstr_w(szBuffer));
+ if (NULL == szComponent) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+
+
+UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, LPSTR szBuffer, DWORD *pcchValueBuf)
+{
+ LPWSTR szwProduct = NULL, szwAttribute = NULL, szwBuffer = NULL;
+ UINT hr = ERROR_INSTALL_FAILURE;
+
+ FIXME("%s %s %p %p\n",debugstr_a(szProduct), debugstr_a(szAttribute), szBuffer, pcchValueBuf);
+
+ if (NULL != szBuffer && NULL == pcchValueBuf) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ if( szProduct )
+ {
+ UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 );
+ szwProduct = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ if( !szwProduct )
+ goto end;
+ MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len );
+ } else {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if( szAttribute )
+ {
+ UINT len = MultiByteToWideChar( CP_ACP, 0, szAttribute, -1, NULL, 0 );
+ szwAttribute = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ if( !szwAttribute )
+ goto end;
+ MultiByteToWideChar( CP_ACP, 0, szAttribute, -1, szwAttribute, len );
+ } else {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if( szBuffer )
+ {
+ szwBuffer = HeapAlloc( GetProcessHeap(), 0, (*pcchValueBuf) * sizeof(WCHAR) );
+ if( !szwBuffer )
+ goto end;
+ }
+
+ hr = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer, pcchValueBuf );
+
+ if( ERROR_SUCCESS == hr )
+ {
+ WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, *pcchValueBuf, NULL, NULL);
+ }
+
+end:
+ if( szwProduct )
+ HeapFree( GetProcessHeap(), 0, szwProduct );
+ if( szwAttribute )
+ HeapFree( GetProcessHeap(), 0, szwAttribute );
+ if( szwBuffer )
+ HeapFree( GetProcessHeap(), 0, szwBuffer );
+
+ return hr;
+}
+
+UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szBuffer, DWORD *pcchValueBuf)
+{
+ MSIHANDLE hProduct;
+ UINT hr;
+
+ FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute), szBuffer, pcchValueBuf);
+
+ if (NULL != szBuffer && NULL == pcchValueBuf) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ if (NULL == szProduct || NULL == szAttribute) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ hr = MsiOpenProductW(szProduct, &hProduct);
+ if (ERROR_SUCCESS != hr) return hr;
+
+ hr = MsiGetPropertyW(hProduct, szAttribute, szBuffer, pcchValueBuf);
+ MsiCloseHandle(hProduct);
+ return hr;
+}
+
+UINT WINAPI MsiDatabaseImportA(LPCSTR szFolderPath, LPCSTR szFilename)
+{
+ FIXME("%s %s\n",debugstr_a(szFolderPath), debugstr_a(szFilename));
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiDatabaseImportW(LPCWSTR szFolderPath, LPCWSTR szFilename)
+{
+ FIXME("%s %s\n",debugstr_w(szFolderPath), debugstr_w(szFilename));
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes)
+{
+ LPWSTR szwLogFile = NULL;
+ UINT hr = ERROR_INSTALL_FAILURE;
+
+ FIXME("%08lx %s %08lx\n", dwLogMode, debugstr_a(szLogFile), attributes);
+
+ if( szLogFile )
+ {
+ UINT len = MultiByteToWideChar( CP_ACP, 0, szLogFile, -1, NULL, 0 );
+ szwLogFile = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ if( !szwLogFile )
+ goto end;
+ MultiByteToWideChar( CP_ACP, 0, szLogFile, -1, szwLogFile, len );
+ } else {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ hr = MsiEnableLogW( dwLogMode, szwLogFile, attributes );
+
+end:
+ if( szwLogFile )
+ HeapFree( GetProcessHeap(), 0, szwLogFile );
+
+ return hr;
+}
+
+UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes)
+{
+ HANDLE the_file = INVALID_HANDLE_VALUE;
+ TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_w(szLogFile), attributes);
+ strcpyW(gszLogFile,szLogFile);
+ if (!(attributes & INSTALLLOGATTRIBUTES_APPEND))
+ DeleteFileW(szLogFile);
+ the_file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (the_file != INVALID_HANDLE_VALUE)
+ CloseHandle(the_file);
+ else
+ ERR("Unable to enable log %s\n",debugstr_w(szLogFile));
+
+ return ERROR_SUCCESS;
+}
+
+INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
+{
+ FIXME("%s\n", debugstr_a(szProduct));
+ return INSTALLSTATE_UNKNOWN;
+}
+
+INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
+{
+ FIXME("%s\n", debugstr_w(szProduct));
+ return INSTALLSTATE_UNKNOWN;
+}
+
+INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
+{
+ INSTALLUILEVEL old = gUILevel;
+ HWND oldwnd = gUIhwnd;
+ TRACE("%08x %p\n", dwUILevel, phWnd);
+
+ gUILevel = dwUILevel;
+ if (phWnd)
+ {
+ gUIhwnd = *phWnd;
+ *phWnd = oldwnd;
+ }
+ return old;
+}
+
+INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
+ DWORD dwMessageFilter, LPVOID pvContext)
+{
+ INSTALLUI_HANDLERA prev = gUIHandler;
+
+ TRACE("(%p %lx %p)\n",puiHandler,dwMessageFilter,pvContext);
+ gUIHandler = puiHandler;
+ gUIFilter = dwMessageFilter;
+ gUIContext = pvContext;
+
+ return prev;
+}
+
+UINT WINAPI MsiLoadStringA(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int nBufferMax, DWORD e)
+{
+ /*FIXME("%08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e);*/
+ FIXME("%p %u %p %d %08lx\n",hInstance,uID,lpBuffer,nBufferMax,e);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiLoadStringW(HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int nBufferMax, DWORD e)
+{
+ FIXME("%p %u %p %d %08lx\n",hInstance,uID,lpBuffer,nBufferMax,e);
+ /*
+ int ret = LoadStringW(hInstance,uID,lpBuffer,nBufferMax);
+ FIXME("%s\n",debugstr_w(lpBuffer));
+ return ret;
+ */
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf, DWORD *pcchBuf)
+{
+ FIXME("%s %p %08lx\n", debugstr_a(szComponent), lpPathBuf, *pcchBuf);
+ return INSTALLSTATE_UNKNOWN;
+}
+
+INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPSTR lpPathBuf, DWORD *pcchBuf)
+{
+ FIXME("%s %p %08lx\n", debugstr_w(szComponent), lpPathBuf, *pcchBuf);
+ return INSTALLSTATE_UNKNOWN;
+}
+
+#include "winuser.h"
+
+UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, WORD wLanguageId, DWORD f)
+{
+ FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption),uType,wLanguageId,f);
+ /*
+ MessageBoxExA(hWnd,lpText,lpCaption,uType|MB_OK,wLanguageId);
+ */
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType, WORD wLanguageId, DWORD f)
+{
+ /*FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);*/
+ FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption),uType,wLanguageId,f);
+ /*
+ MessageBoxExW(hWnd,lpText,lpCaption,uType|MB_OK,wLanguageId);
+ */
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
+{
+ DWORD r;
+ WCHAR szwGuid[GUID_SIZE];
+
+ TRACE("%ld %p\n",index,lpguid);
+
+ if (NULL == lpguid) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ r = MsiEnumProductsW(index, szwGuid);
+ if( r == ERROR_SUCCESS )
+ WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
+
+ return r;
+}
+
+UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
+{
+ HKEY hkey = 0, hkeyFeatures = 0;
+ DWORD r;
+ WCHAR szKeyName[33];
+
+ TRACE("%ld %p\n",index,lpguid);
+
+ if (NULL == lpguid) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
+ if( r != ERROR_SUCCESS )
+ goto end;
+
+ r = RegOpenKeyW(hkey, szFeatures, &hkeyFeatures);
+ if( r != ERROR_SUCCESS )
+ goto end;
+
+ r = RegEnumKeyW(hkeyFeatures, index, szKeyName, GUID_SIZE);
+
+ unsquash_guid(szKeyName, lpguid);
+
+end:
+
+ if( hkeyFeatures )
+ RegCloseKey(hkeyFeatures);
+ if( hkey )
+ RegCloseKey(hkey);
+
+ return r;
+}
+
+UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index,
+ LPSTR szFeature, LPSTR szParent)
+{
+ DWORD r;
+ WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
+ LPWSTR szwProduct = NULL;
+
+ TRACE("%s %ld %p %p\n",debugstr_a(szProduct),index,szFeature,szParent);
+
+ if( szProduct )
+ {
+ UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 );
+ szwProduct = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
+ if( szwProduct )
+ MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len );
+ else
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent);
+ if( r == ERROR_SUCCESS )
+ {
+ WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
+ szFeature, GUID_SIZE, NULL, NULL);
+ WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
+ szParent, GUID_SIZE, NULL, NULL);
+ }
+
+ if( szwProduct )
+ HeapFree( GetProcessHeap(), 0, szwProduct);
+
+ return r;
+}
+
+UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index,
+ LPWSTR szFeature, LPWSTR szParent)
+{
+ HKEY hkey = 0, hkeyFeatures = 0, hkeyProduct = 0;
+ DWORD r, sz;
+ WCHAR szRegName[GUID_SIZE];
+
+ TRACE("%s %ld %p %p\n",debugstr_w(szProduct),index,szFeature,szParent);
+
+ if( !squash_guid(szProduct, szRegName) )
+ return ERROR_INVALID_PARAMETER;
+
+ r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
+ if( r != ERROR_SUCCESS )
[truncated at 1000 lines; 588 more skipped]
reactos/lib/msi
diff -N msi.spec
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ msi.spec 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,236 @@
+1 stdcall -private DllCanUnloadNow() MSI_DllCanUnloadNow
+2 stdcall -private DllGetClassObject(ptr ptr ptr) MSI_DllGetClassObject
+3 stdcall -private DllRegisterServer() MSI_DllRegisterServer
+4 stdcall -private DllUnregisterServer() MSI_DllUnregisterServer
+5 stdcall MsiAdvertiseProductA(str str str long)
+6 stdcall MsiAdvertiseProductW(wstr wstr wstr long)
+7 stdcall MsiCloseAllHandles()
+8 stdcall MsiCloseHandle(long)
+9 stub MsiCollectUserInfoA
+10 stub MsiCollectUserInfoW
+11 stub MsiConfigureFeatureA
+12 stub MsiConfigureFeatureFromDescriptorA
+13 stub MsiConfigureFeatureFromDescriptorW
+14 stub MsiConfigureFeatureW
+15 stdcall MsiConfigureProductA(str long long)
+16 stdcall MsiConfigureProductW(wstr long long)
+17 stdcall MsiCreateRecord(long)
+18 stdcall MsiDatabaseApplyTransformA(long str long)
+19 stdcall MsiDatabaseApplyTransformW(long wstr long)
+20 stdcall MsiDatabaseCommit(long)
+21 stub MsiDatabaseExportA
+22 stub MsiDatabaseExportW
+23 stdcall MsiDatabaseGenerateTransformA(long long str long long)
+24 stdcall MsiDatabaseGenerateTransformW(long long wstr long long)
+25 stdcall MsiDatabaseGetPrimaryKeysA(long str ptr)
+26 stdcall MsiDatabaseGetPrimaryKeysW(long wstr ptr)
+27 stdcall MsiDatabaseImportA(str str)
+28 stdcall MsiDatabaseImportW(wstr wstr)
+29 stub MsiDatabaseMergeA
+30 stub MsiDatabaseMergeW
+31 stdcall MsiDatabaseOpenViewA(long str ptr)
+32 stdcall MsiDatabaseOpenViewW(long wstr ptr)
+33 stdcall MsiDoActionA(long str)
+34 stdcall MsiDoActionW(long wstr)
+35 stub MsiEnableUIPreview
+36 stdcall MsiEnumClientsA(str long ptr)
+37 stdcall MsiEnumClientsW(wstr long ptr)
+38 stdcall MsiEnumComponentQualifiersA(str long str ptr str ptr)
+39 stdcall MsiEnumComponentQualifiersW(wstr long wstr ptr wstr ptr)
+40 stdcall MsiEnumComponentsA(long ptr)
+41 stdcall MsiEnumComponentsW(long ptr)
+42 stdcall MsiEnumFeaturesA(str long ptr ptr)
+43 stdcall MsiEnumFeaturesW(wstr long ptr ptr)
+44 stdcall MsiEnumProductsA(long ptr)
+45 stdcall MsiEnumProductsW(long ptr)
+46 stdcall MsiEvaluateConditionA(long str)
+47 stdcall MsiEvaluateConditionW(long wstr)
+48 stub MsiGetLastErrorRecord
+49 stdcall MsiGetActiveDatabase(long)
+50 stdcall MsiGetComponentStateA(long str ptr ptr)
+51 stdcall MsiGetComponentStateW(long wstr ptr ptr)
+52 stub MsiGetDatabaseState
+53 stub MsiGetFeatureCostA
+54 stub MsiGetFeatureCostW
+55 stub MsiGetFeatureInfoA
+56 stub MsiGetFeatureInfoW
+57 stdcall MsiGetFeatureStateA(long str ptr ptr)
+58 stdcall MsiGetFeatureStateW(long wstr ptr ptr)
+59 stub MsiGetFeatureUsageA
+60 stub MsiGetFeatureUsageW
+61 stub MsiGetFeatureValidStatesA
+62 stub MsiGetFeatureValidStatesW
+63 stub MsiGetLanguage
+64 stdcall MsiGetMode(long long)
+65 stdcall MsiGetProductCodeA(str str)
+66 stdcall MsiGetProductCodeW(wstr wstr)
+67 stdcall MsiGetProductInfoA(str str str long)
+68 stub MsiGetProductInfoFromScriptA
+69 stub MsiGetProductInfoFromScriptW
+70 stdcall MsiGetProductInfoW(wstr wstr wstr long)
+71 stdcall MsiGetProductPropertyA(long str ptr ptr)
+72 stdcall MsiGetProductPropertyW(long wstr ptr ptr)
+73 stdcall MsiGetPropertyA(ptr str str ptr)
+74 stdcall MsiGetPropertyW(ptr wstr wstr ptr)
+75 stdcall MsiGetSourcePathA(long str ptr ptr)
+76 stdcall MsiGetSourcePathW(long wstr ptr ptr)
+77 stdcall MsiGetSummaryInformationA(long str long ptr)
+78 stdcall MsiGetSummaryInformationW(long wstr long ptr)
+79 stdcall MsiGetTargetPathA(long str ptr ptr)
+80 stdcall MsiGetTargetPathW(long wstr ptr ptr)
+81 stub MsiGetUserInfoA
+82 stub MsiGetUserInfoW
+83 stub MsiInstallMissingComponentA
+84 stub MsiInstallMissingComponentW
+85 stub MsiInstallMissingFileA
+86 stub MsiInstallMissingFileW
+87 stdcall MsiInstallProductA(str str)
+88 stdcall MsiInstallProductW(wstr wstr)
+89 stdcall MsiLocateComponentA(str ptr long)
+90 stdcall MsiLocateComponentW(wstr ptr long)
+91 stdcall MsiOpenDatabaseA(str str ptr)
+92 stdcall MsiOpenDatabaseW(wstr wstr ptr)
+93 stdcall MsiOpenPackageA(str ptr)
+94 stdcall MsiOpenPackageW(wstr ptr)
+95 stdcall MsiOpenProductA(str ptr)
+96 stdcall MsiOpenProductW(wstr ptr)
+97 stub MsiPreviewBillboardA
+98 stub MsiPreviewBillboardW
+99 stub MsiPreviewDialogA
+100 stub MsiPreviewDialogW
+101 stub MsiProcessAdvertiseScriptA
+102 stub MsiProcessAdvertiseScriptW
+103 stdcall MsiProcessMessage(long long long)
+104 stub MsiProvideComponentA
+105 stdcall MsiProvideComponentFromDescriptorA(str ptr ptr ptr)
+106 stdcall MsiProvideComponentFromDescriptorW(wstr ptr ptr ptr)
+107 stub MsiProvideComponentW
+108 stub MsiProvideQualifiedComponentA
+109 stub MsiProvideQualifiedComponentW
+110 stdcall MsiQueryFeatureStateA(str str)
+111 stdcall MsiQueryFeatureStateW(wstr wstr)
+112 stdcall MsiQueryProductStateA(str)
+113 stdcall MsiQueryProductStateW(wstr)
+114 stdcall MsiRecordDataSize(long long)
+115 stdcall MsiRecordGetFieldCount(long)
+116 stdcall MsiRecordGetInteger(long long)
+117 stdcall MsiRecordGetStringA(long long ptr ptr)
+118 stdcall MsiRecordGetStringW(long long ptr ptr)
+119 stdcall MsiRecordIsNull(long long)
+120 stdcall MsiRecordReadStream(long long ptr ptr)
+121 stdcall MsiRecordSetInteger(long long long)
+122 stdcall MsiRecordSetStreamA(long long str)
+123 stdcall MsiRecordSetStreamW(long long wstr)
+124 stdcall MsiRecordSetStringA(long long str)
+125 stdcall MsiRecordSetStringW(long long wstr)
+126 stub MsiReinstallFeatureA
+127 stub MsiReinstallFeatureFromDescriptorA
+128 stub MsiReinstallFeatureFromDescriptorW
+129 stub MsiReinstallFeatureW
+130 stdcall MsiReinstallProductA(str long)
+131 stdcall MsiReinstallProductW(wstr long)
+132 stub MsiSequenceA
+133 stub MsiSequenceW
+134 stub MsiSetComponentStateA
+135 stub MsiSetComponentStateW
+136 stdcall MsiSetExternalUIA(ptr long ptr)
+137 stub MsiSetExternalUIW
+138 stdcall MsiSetFeatureStateA(long str long)
+139 stdcall MsiSetFeatureStateW(long wstr long)
+140 stub MsiSetInstallLevel
+141 stdcall MsiSetInternalUI(long ptr)
+142 stub MsiVerifyDiskSpace
+143 stub MsiSetMode
+144 stdcall MsiSetPropertyA(long str str)
+145 stdcall MsiSetPropertyW(long wstr wstr)
+146 stdcall MsiSetTargetPathA(long str str)
+147 stdcall MsiSetTargetPathW(long wstr wstr)
+148 stdcall MsiSummaryInfoGetPropertyA(long long ptr ptr ptr ptr ptr)
+149 stdcall MsiSummaryInfoGetPropertyCount(long ptr)
+150 stdcall MsiSummaryInfoGetPropertyW(long long ptr ptr ptr ptr ptr)
+151 stub MsiSummaryInfoPersist
+152 stub MsiSummaryInfoSetPropertyA
+153 stub MsiSummaryInfoSetPropertyW
+154 stub MsiUseFeatureA
+155 stub MsiUseFeatureW
+156 stdcall MsiVerifyPackageA(str)
+157 stdcall MsiVerifyPackageW(wstr)
+158 stdcall MsiViewClose(long)
+159 stdcall MsiViewExecute(long long)
+160 stdcall MsiViewFetch(long ptr)
+161 stub MsiViewGetErrorA
+162 stub MsiViewGetErrorW
+163 stdcall MsiViewModify(long long long)
+164 stdcall MsiDatabaseIsTablePersistentA(long str)
+165 stdcall MsiDatabaseIsTablePersistentW(long wstr)
+166 stdcall MsiViewGetColumnInfo(long long ptr)
+167 stdcall MsiRecordClearData(long)
+168 stdcall MsiEnableLogA(long str long)
+169 stdcall MsiEnableLogW(long wstr long)
+170 stdcall MsiFormatRecordA(long long ptr ptr)
+171 stdcall MsiFormatRecordW(long long ptr ptr)
+172 stdcall MsiGetComponentPathA(str str ptr ptr)
+173 stdcall MsiGetComponentPathW(wstr wstr ptr ptr)
+174 stdcall MsiApplyPatchA(str str long str)
+175 stdcall MsiApplyPatchW(wstr wstr long wstr)
+176 stub MsiAdvertiseScriptA
+177 stub MsiAdvertiseScriptW
+178 stub MsiGetPatchInfoA
+179 stub MsiGetPatchInfoW
+180 stub MsiEnumPatchesA
+181 stub MsiEnumPatchesW
+182 stdcall DllGetVersion(ptr) MSI_DllGetVersion
+183 stub MsiGetProductCodeFromPackageCodeA
+184 stub MsiGetProductCodeFromPackageCodeW
+185 stub MsiCreateTransformSummaryInfoA
+186 stub MsiCreateTransformSummaryInfoW
+187 stub MsiQueryFeatureStateFromDescriptorA
+188 stub MsiQueryFeatureStateFromDescriptorW
+189 stub MsiConfigureProductExA
+190 stub MsiConfigureProductExW
+191 stub MsiInvalidateFeatureCache
+192 stub MsiUseFeatureExA
+193 stub MsiUseFeatureExW
+194 stdcall MsiGetFileVersionA(str str ptr str ptr)
+195 stdcall MsiGetFileVersionW(wstr wstr ptr wstr ptr)
+196 stdcall MsiLoadStringA(long long long long long)
+197 stdcall MsiLoadStringW(long long long long long)
+198 stdcall MsiMessageBoxA(long long long long long long)
+199 stdcall MsiMessageBoxW(long long long long long long)
+200 stub MsiDecomposeDescriptorA
+201 stub MsiDecomposeDescriptorW
+202 stub MsiProvideQualifiedComponentExA
+203 stub MsiProvideQualifiedComponentExW
+204 stdcall MsiEnumRelatedProductsA(str long long str)
+205 stub MsiEnumRelatedProductsW
+206 stub MsiSetFeatureAttributesA
+207 stub MsiSetFeatureAttributesW
+208 stub MsiSourceListClearAllA
+209 stub MsiSourceListClearAllW
+210 stub MsiSourceListAddSourceA
+211 stub MsiSourceListAddSourceW
+212 stub MsiSourceListForceResolutionA
+213 stub MsiSourceListForceResolutionW
+214 stub MsiIsProductElevatedA
+215 stub MsiIsProductElevatedW
+216 stub MsiGetShortcutTargetA
+217 stub MsiGetShortcutTargetW
+218 stub MsiGetFileHashA
+219 stub MsiGetFileHashW
+220 stub MsiEnumComponentCostsA
+221 stub MsiEnumComponentCostsW
+222 stub MsiCreateAndVerifyInstallerDirectory
+223 stdcall MsiGetFileSignatureInformationA(str long ptr ptr ptr)
+224 stdcall MsiGetFileSignatureInformationW(wstr long ptr ptr ptr)
+225 stdcall MsiProvideAssemblyA(str str long long str ptr)
+226 stdcall MsiProvideAssemblyW(wstr wstr long long wstr ptr)
+227 stdcall MsiAdvertiseProductExA(str str str long long long)
+228 stdcall MsiAdvertiseProductExW(wstr wstr wstr long long long)
+229 stub MsiNotifySidChangeA
+230 stub MsiNotifySidChangeW
+231 stdcall MsiOpenPackageExA(str long ptr)
+232 stdcall MsiOpenPackageExW(wstr long ptr)
+233 stub MsiDeleteUserDataA
+234 stub MsiDeleteUserDataW
+235 stub Migrate10CachedPackagesA
+236 stub Migrate10CachedPackagesW
reactos/lib/msi
diff -N msipriv.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ msipriv.h 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,325 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __WINE_MSI_PRIVATE__
+#define __WINE_MSI_PRIVATE__
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+
+#define MSI_DATASIZEMASK 0x00ff
+#define MSITYPE_VALID 0x0100
+#define MSITYPE_STRING 0x0800
+#define MSITYPE_NULLABLE 0x1000
+#define MSITYPE_KEY 0x2000
+
+#define MSITYPE_BINARY 0x8900
+
+struct tagMSITABLE;
+typedef struct tagMSITABLE MSITABLE;
+
+struct string_table;
+typedef struct string_table string_table;
+
+struct tagMSIOBJECTHDR;
+typedef struct tagMSIOBJECTHDR MSIOBJECTHDR;
+
+typedef VOID (*msihandledestructor)( MSIOBJECTHDR * );
+
+struct tagMSIOBJECTHDR
+{
+ UINT magic;
+ UINT type;
+ UINT refcount;
+ msihandledestructor destructor;
+ struct tagMSIOBJECTHDR *next;
+ struct tagMSIOBJECTHDR *prev;
+};
+
+typedef struct tagMSIDATABASE
+{
+ MSIOBJECTHDR hdr;
+ IStorage *storage;
+ string_table *strings;
+ LPWSTR mode;
+ MSITABLE *first_table, *last_table;
+} MSIDATABASE;
+
+typedef struct tagMSIVIEW MSIVIEW;
+
+typedef struct tagMSIQUERY
+{
+ MSIOBJECTHDR hdr;
+ MSIVIEW *view;
+ UINT row;
+ MSIDATABASE *db;
+} MSIQUERY;
+
+/* maybe we can use a Variant instead of doing it ourselves? */
+typedef struct tagMSIFIELD
+{
+ UINT type;
+ union
+ {
+ INT iVal;
+ LPWSTR szwVal;
+ IStream *stream;
+ } u;
+} MSIFIELD;
+
+typedef struct tagMSIRECORD
+{
+ MSIOBJECTHDR hdr;
+ UINT count; /* as passed to MsiCreateRecord */
+ MSIFIELD fields[1]; /* nb. array size is count+1 */
+} MSIRECORD;
+
+typedef struct tagMSIVIEWOPS
+{
+ /*
+ * fetch_int - reads one integer from {row,col} in the table
+ *
+ * This function should be called after the execute method.
+ * Data returned by the function should not change until
+ * close or delete is called.
+ * To get a string value, query the database's string table with
+ * the integer value returned from this function.
+ */
+ UINT (*fetch_int)( struct tagMSIVIEW *, UINT row, UINT col, UINT *val );
+
+ /*
+ * fetch_int - reads one integer from {row,col} in the table
+ *
+ * This function is similar to fetch_int, except fetches a
+ * stream instead of an integer.
+ */
+ UINT (*fetch_stream)( struct tagMSIVIEW *, UINT row, UINT col, IStream **stm );
+
+ /*
+ * get_int - sets one integer at {row,col} in the table
+ *
+ * Similar semantics to fetch_int
+ */
+ UINT (*set_int)( struct tagMSIVIEW *, UINT row, UINT col, UINT val );
+
+ /*
+ * Inserts a new, blank row into the database
+ * *row receives the number of the new row
+ */
+ UINT (*insert_row)( struct tagMSIVIEW *, UINT *row );
+
+ /*
+ * execute - loads the underlying data into memory so it can be read
+ */
+ UINT (*execute)( struct tagMSIVIEW *, MSIRECORD * );
+
+ /*
+ * close - clears the data read by execute from memory
+ */
+ UINT (*close)( struct tagMSIVIEW * );
+
+ /*
+ * get_dimensions - returns the number of rows or columns in a table.
+ *
+ * The number of rows can only be queried after the execute method
+ * is called. The number of columns can be queried at any time.
+ */
+ UINT (*get_dimensions)( struct tagMSIVIEW *, UINT *rows, UINT *cols );
+
+ /*
+ * get_column_info - returns the name and type of a specific column
+ *
+ * The name is HeapAlloc'ed by this function and should be freed by
+ * the caller.
+ * The column information can be queried at any time.
+ */
+ UINT (*get_column_info)( struct tagMSIVIEW *, UINT n, LPWSTR *name, UINT *type );
+
+ /*
+ * modify - not yet implemented properly
+ */
+ UINT (*modify)( struct tagMSIVIEW *, MSIMODIFY, MSIHANDLE );
+
+ /*
+ * delete - destroys the structure completely
+ */
+ UINT (*delete)( struct tagMSIVIEW * );
+
+} MSIVIEWOPS;
+
+typedef struct tagMSISUMMARYINFO
+{
+ MSIOBJECTHDR hdr;
+ IPropertyStorage *propstg;
+} MSISUMMARYINFO;
+
+struct tagMSIVIEW
+{
+ MSIOBJECTHDR hdr;
+ MSIVIEWOPS *ops;
+};
+
+typedef struct tagMSIPACKAGE
+{
+ MSIOBJECTHDR hdr;
+ MSIDATABASE *db;
+ struct tagMSIFEATURE *features;
+ UINT loaded_features;
+ struct tagMSIFOLDER *folders;
+ UINT loaded_folders;
+ struct tagMSICOMPONENT *components;
+ UINT loaded_components;
+ struct tagMSIFILE *files;
+ UINT loaded_files;
+} MSIPACKAGE;
+
+#define MSIHANDLETYPE_ANY 0
+#define MSIHANDLETYPE_DATABASE 1
+#define MSIHANDLETYPE_SUMMARYINFO 2
+#define MSIHANDLETYPE_VIEW 3
+#define MSIHANDLETYPE_RECORD 4
+#define MSIHANDLETYPE_PACKAGE 5
+
+#define MSI_MAJORVERSION 2
+#define MSI_MINORVERSION 0
+#define MSI_BUILDNUMBER 2600
+
+#define GUID_SIZE 39
+
+#define MSIHANDLE_MAGIC 0x4d434923
+#define MSIMAXHANDLES 0x80
+
+#define MSISUMINFO_OFFSET 0x30LL
+
+DEFINE_GUID(CLSID_IMsiServer, 0x000C101C,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
+DEFINE_GUID(CLSID_IMsiServerX1, 0x000C103E,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
+DEFINE_GUID(CLSID_IMsiServerX2, 0x000C1090,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
+DEFINE_GUID(CLSID_IMsiServerX3, 0x000C1094,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
+
+DEFINE_GUID(CLSID_IMsiServerMessage, 0x000C101D,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
+
+
+/* handle functions */
+extern void *msihandle2msiinfo(MSIHANDLE handle, UINT type);
+extern MSIHANDLE alloc_msihandle( MSIOBJECTHDR * );
+extern void *alloc_msiobject(UINT type, UINT size, msihandledestructor destroy );
+extern void msiobj_addref(MSIOBJECTHDR *);
+extern int msiobj_release(MSIOBJECTHDR *);
+extern MSIHANDLE msiobj_findhandle( MSIOBJECTHDR *hdr );
+
+/* add this table to the list of cached tables in the database */
+extern void add_table(MSIDATABASE *db, MSITABLE *table);
+extern void remove_table( MSIDATABASE *db, MSITABLE *table );
+extern void free_table( MSIDATABASE *db, MSITABLE *table );
+extern void free_cached_tables( MSIDATABASE *db );
+extern UINT find_cached_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **table);
+extern UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **table);
+extern UINT load_string_table( MSIDATABASE *db );
+extern UINT MSI_CommitTables( MSIDATABASE *db );
+extern HRESULT init_string_table( IStorage *stg );
+
+
+/* string table functions */
+extern BOOL msi_addstring( string_table *st, int string_no, const CHAR *data, int len, UINT refcount );
+extern BOOL msi_addstringW( string_table *st, int string_no, const WCHAR *data, int len, UINT refcount );
+extern UINT msi_id2stringW( string_table *st, UINT string_no, LPWSTR buffer, UINT *sz );
+extern UINT msi_id2stringA( string_table *st, UINT string_no, LPSTR buffer, UINT *sz );
+
+extern LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid);
+extern UINT msi_string2idW( string_table *st, LPCWSTR buffer, UINT *id );
+extern UINT msi_string2idA( string_table *st, LPCSTR str, UINT *id );
+extern string_table *msi_init_stringtable( int entries, UINT codepage );
+extern VOID msi_destroy_stringtable( string_table *st );
+extern UINT msi_string_count( string_table *st );
+extern UINT msi_id_refcount( string_table *st, UINT i );
+extern UINT msi_string_totalsize( string_table *st, UINT *last );
+extern UINT msi_strcmp( string_table *st, UINT lval, UINT rval, UINT *res );
+extern const WCHAR *msi_string_lookup_id( string_table *st, UINT id );
+extern UINT msi_string_get_codepage( string_table *st );
+
+
+extern UINT VIEW_find_column( MSIVIEW *view, LPWSTR name, UINT *n );
+
+extern BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name );
+
+extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname,
+ USHORT **pdata, UINT *psz );
+extern UINT ACTION_DoTopLevelINSTALL( MSIPACKAGE *, LPCWSTR, LPCWSTR );
+extern void ACTION_remove_tracked_tempfiles( MSIPACKAGE* );
+
+/* record internals */
+extern UINT MSI_RecordSetIStream( MSIRECORD *, unsigned int, IStream *);
+extern const WCHAR *MSI_RecordGetString( MSIRECORD *, unsigned int );
+extern MSIRECORD *MSI_CreateRecord( unsigned int );
+extern UINT MSI_RecordSetInteger( MSIRECORD *, unsigned int, int );
+extern UINT MSI_RecordSetStringW( MSIRECORD *, unsigned int, LPCWSTR );
+extern BOOL MSI_RecordIsNull( MSIRECORD *, unsigned int );
+extern UINT MSI_RecordGetStringW( MSIRECORD * , unsigned int, LPWSTR, DWORD *);
+extern UINT MSI_RecordGetStringA( MSIRECORD *, unsigned int, LPSTR, DWORD *);
+extern int MSI_RecordGetInteger( MSIRECORD *, unsigned int );
+extern UINT MSI_RecordReadStream( MSIRECORD *, unsigned int, char *, DWORD *);
+extern unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec );
+
+/* stream internals */
+extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm );
+extern UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm );
+extern void enum_stream_names( IStorage *stg );
+
+/* database internals */
+extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** );
+extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** );
+
+/* view internals */
+extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * );
+extern UINT MSI_ViewFetch( MSIQUERY*, MSIRECORD ** );
+extern UINT MSI_ViewClose( MSIQUERY* );
+
+/* package internals */
+extern UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE ** );
+extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR);
+extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
+extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD* );
+extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD*);
+extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR );
+extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
+extern UINT MSI_GetComponentStateW(MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE *);
+extern UINT MSI_GetFeatureStateW(MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE *);
+
+/* registry data encoding/decoding functions */
+BOOL unsquash_guid(LPCWSTR in, LPWSTR out);
+BOOL squash_guid(LPCWSTR in, LPWSTR out);
+BOOL encode_base85_guid(GUID *,LPWSTR);
+BOOL decode_base85_guid(LPCWSTR,GUID*);
+
+/* UI globals */
+extern INSTALLUILEVEL gUILevel;
+extern HWND gUIhwnd;
+extern INSTALLUI_HANDLERA gUIHandler;
+extern DWORD gUIFilter;
+extern LPVOID gUIContext;
+extern WCHAR gszLogFile[MAX_PATH];
+
+#endif /* __WINE_MSI_PRIVATE__ */
reactos/lib/msi
diff -N msiquery.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ msiquery.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,485 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002-2004 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+
+#include "query.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+#if 0
+typedef struct tagMSIQUERY
+{
+ MSIOBJECTHDR hdr;
+ MSIVIEW *view;
+ UINT row;
+ MSIDATABASE *db;
+} MSIQUERY;
+#endif
+
+UINT WINAPI MsiDatabaseIsTablePersistentA(
+ MSIHANDLE hDatabase, LPSTR szTableName)
+{
+ FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName));
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiDatabaseIsTablePersistentW(
+ MSIHANDLE hDatabase, LPWSTR szTableName)
+{
+ FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName));
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+void MSI_CloseView( MSIOBJECTHDR *arg )
+{
+ MSIQUERY *query = (MSIQUERY*) arg;
+
+ if( query->view && query->view->ops->delete )
+ query->view->ops->delete( query->view );
+ msiobj_release( &query->db->hdr );
+}
+
+UINT VIEW_find_column( MSIVIEW *table, LPWSTR name, UINT *n )
+{
+ LPWSTR col_name;
+ UINT i, count, r;
+
+ r = table->ops->get_dimensions( table, NULL, &count );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ for( i=1; i<=count; i++ )
+ {
+ INT x;
+
+ col_name = NULL;
+ r = table->ops->get_column_info( table, i, &col_name, NULL );
+ if( r != ERROR_SUCCESS )
+ return r;
+ x = lstrcmpW( name, col_name );
+ HeapFree( GetProcessHeap(), 0, col_name );
+ if( !x )
+ {
+ *n = i;
+ return ERROR_SUCCESS;
+ }
+ }
+
+ return ERROR_INVALID_PARAMETER;
+}
+
+UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE hdb,
+ LPCSTR szQuery, MSIHANDLE *phView)
+{
+ UINT r;
+ LPWSTR szwQuery;
+
+ TRACE("%ld %s %p\n", hdb, debugstr_a(szQuery), phView);
+
+ if( szQuery )
+ {
+ UINT len = MultiByteToWideChar( CP_ACP, 0, szQuery, -1, NULL, 0 );
+ szwQuery = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
+ if( !szwQuery )
+ return ERROR_FUNCTION_FAILED;
+ MultiByteToWideChar( CP_ACP, 0, szQuery, -1, szwQuery, len );
+ }
+ else
+ szwQuery = NULL;
+
+ r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
+
+ return r;
+}
+
+UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
+ LPCWSTR szQuery, MSIQUERY **pView)
+{
+ MSIQUERY *query;
+ UINT r;
+
+ TRACE("%s %p\n", debugstr_w(szQuery), pView);
+
+ if( !szQuery)
+ return ERROR_INVALID_PARAMETER;
+
+ /* pre allocate a handle to hold a pointer to the view */
+ query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY),
+ MSI_CloseView );
+ if( !query )
+ return ERROR_FUNCTION_FAILED;
+
+ msiobj_addref( &db->hdr );
+ query->row = 0;
+ query->db = db;
+ query->view = NULL;
+
+ r = MSI_ParseSQL( db, szQuery, &query->view );
+ if( r == ERROR_SUCCESS )
+ {
+ msiobj_addref( &query->hdr );
+ *pView = query;
+ }
+
+ msiobj_release( &query->hdr );
+ return r;
+}
+
+UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
+ LPCWSTR szQuery, MSIHANDLE *phView)
+{
+ MSIDATABASE *db;
+ MSIQUERY *query = NULL;
+ UINT ret;
+
+ TRACE("%s %p\n", debugstr_w(szQuery), phView);
+
+ db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
+ if( !db )
+ return ERROR_INVALID_HANDLE;
+
+ ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
+ if( ret == ERROR_SUCCESS )
+ {
+ *phView = alloc_msihandle( &query->hdr );
+ msiobj_release( &query->hdr );
+ }
+ msiobj_release( &db->hdr );
+
+ return ret;
+}
+
+UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
+{
+ MSIVIEW *view;
+ MSIRECORD *rec;
+ UINT row_count = 0, col_count = 0, i, ival, ret, type;
+
+ TRACE("%p %p\n", query, prec );
+
+ view = query->view;
+ if( !view )
+ return ERROR_FUNCTION_FAILED;
+
+ ret = view->ops->get_dimensions( view, &row_count, &col_count );
+ if( ret )
+ return ret;
+ if( !col_count )
+ return ERROR_INVALID_PARAMETER;
+
+ if( query->row >= row_count )
+ return ERROR_NO_MORE_ITEMS;
+
+ rec = MSI_CreateRecord( col_count );
+ if( !rec )
+ return ERROR_FUNCTION_FAILED;
+
+ for( i=1; i<=col_count; i++ )
+ {
+ ret = view->ops->get_column_info( view, i, NULL, &type );
+ if( ret )
+ {
+ ERR("Error getting column type for %d\n", i );
+ continue;
+ }
+ if (( type != MSITYPE_BINARY) && (type != (MSITYPE_BINARY |
+ MSITYPE_NULLABLE)))
+ {
+ ret = view->ops->fetch_int( view, query->row, i, &ival );
+ if( ret )
+ {
+ ERR("Error fetching data for %d\n", i );
+ continue;
+ }
+ if( ! (type & MSITYPE_VALID ) )
+ ERR("Invalid type!\n");
+
+ /* check if it's nul (0) - if so, don't set anything */
+ if( !ival )
+ continue;
+
+ if( type & MSITYPE_STRING )
+ {
+ LPWSTR sval;
+
+ sval = MSI_makestring( query->db, ival );
+ MSI_RecordSetStringW( rec, i, sval );
+ HeapFree( GetProcessHeap(), 0, sval );
+ }
+ else
+ {
+ if( (type & MSI_DATASIZEMASK) == 2 )
+ MSI_RecordSetInteger( rec, i, ival - (1<<15) );
+ else
+ MSI_RecordSetInteger( rec, i, ival - (1<<31) );
+ }
+ }
+ else
+ {
+ IStream *stm = NULL;
+
+ ret = view->ops->fetch_stream( view, query->row, i, &stm );
+ if( ( ret == ERROR_SUCCESS ) && stm )
+ {
+ MSI_RecordSetIStream( rec, i, stm );
+ IStream_Release( stm );
+ }
+ else
+ ERR("failed to get stream\n");
+ }
+ }
+ query->row ++;
+
+ *prec = rec;
+
+ return ERROR_SUCCESS;
+}
+
+UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
+{
+ MSIQUERY *query;
+ MSIRECORD *rec = NULL;
+ UINT ret;
+
+ TRACE("%ld %p\n", hView, record);
+
+ query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
+ if( !query )
+ return ERROR_INVALID_HANDLE;
+ ret = MSI_ViewFetch( query, &rec );
+ if( ret == ERROR_SUCCESS )
+ {
+ *record = alloc_msihandle( &rec->hdr );
+ msiobj_release( &rec->hdr );
+ }
+ msiobj_release( &query->hdr );
+ return ret;
+}
+
+UINT MSI_ViewClose(MSIQUERY *query)
+{
+ MSIVIEW *view;
+
+ TRACE("%p\n", query );
+
+ view = query->view;
+ if( !view )
+ return ERROR_FUNCTION_FAILED;
+ if( !view->ops->close )
+ return ERROR_FUNCTION_FAILED;
+
+ return view->ops->close( view );
+}
+
+UINT WINAPI MsiViewClose(MSIHANDLE hView)
+{
+ MSIQUERY *query;
+ UINT ret;
+
+ TRACE("%ld\n", hView );
+
+ query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
+ if( !query )
+ return ERROR_INVALID_HANDLE;
+
+ ret = MSI_ViewClose( query );
+ msiobj_release( &query->hdr );
+ return ret;
+}
+
+UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
+{
+ MSIVIEW *view;
+
+ TRACE("%p %p\n", query, rec);
+
+ view = query->view;
+ if( !view )
+ return ERROR_FUNCTION_FAILED;
+ if( !view->ops->execute )
+ return ERROR_FUNCTION_FAILED;
+ query->row = 0;
+
+ return view->ops->execute( view, rec );
+}
+
+UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
+{
+ MSIQUERY *query;
+ MSIRECORD *rec = NULL;
+ UINT ret;
+
+ TRACE("%ld %ld\n", hView, hRec);
+
+ query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
+ if( !query )
+ return ERROR_INVALID_HANDLE;
+
+ if( hRec )
+ {
+ rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
+ if( !rec )
+ {
+ ret = ERROR_INVALID_HANDLE;
+ goto out;
+ }
+ }
+
+ ret = MSI_ViewExecute( query, rec );
+out:
+ if( query )
+ msiobj_release( &query->hdr );
+ if( rec )
+ msiobj_release( &rec->hdr );
+
+ return ret;
+}
+
+UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
+{
+ MSIVIEW *view;
+ MSIQUERY *query;
+ MSIHANDLE handle;
+ UINT ret, i, count = 0, type;
+ LPWSTR name;
+
+ TRACE("%ld %d %p\n", hView, info, hRec);
+
+ query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
+ if( !query )
+ return ERROR_INVALID_HANDLE;
+
+ view = query->view;
+ if( !view )
+ return ERROR_FUNCTION_FAILED;
+
+ if( !view->ops->get_dimensions )
+ return ERROR_FUNCTION_FAILED;
+
+ ret = view->ops->get_dimensions( view, NULL, &count );
+ if( ret )
+ return ret;
+ if( !count )
+ return ERROR_INVALID_PARAMETER;
+
+ handle = MsiCreateRecord( count );
+ if( !handle )
+ return ERROR_FUNCTION_FAILED;
+
+ for( i=0; i<count; i++ )
+ {
+ name = NULL;
+ ret = view->ops->get_column_info( view, i+1, &name, &type );
+ if( ret != ERROR_SUCCESS )
+ continue;
+ MsiRecordSetStringW( handle, i+1, name );
+ HeapFree( GetProcessHeap(), 0, name );
+ }
+
+ *hRec = handle;
+
+ return ERROR_SUCCESS;
+}
+
+UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
+ LPCSTR szTransformFile, int iErrorCond)
+{
+ FIXME("%ld %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb,
+ LPCWSTR szTransformFile, int iErrorCond)
+{
+ FIXME("%ld %s %d\n", hdb, debugstr_w(szTransformFile), iErrorCond);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
+ LPCSTR szTransformFile, int iReserved1, int iReserved2 )
+{
+ FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
+ debugstr_a(szTransformFile), iReserved1, iReserved2);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
+ LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
+{
+ FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
+ debugstr_w(szTransformFile), iReserved1, iReserved2);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
+{
+ MSIDATABASE *db;
+ UINT r;
+
+ TRACE("%ld\n", hdb);
+
+ db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
+ if( !db )
+ return ERROR_INVALID_HANDLE;
+
+ /* FIXME: lock the database */
+
+ r = MSI_CommitTables( db );
+
+ /* FIXME: unlock the database */
+
+ return r;
+}
+
+UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
+ LPCSTR table, MSIHANDLE* rec)
+{
+ FIXME("%ld %s %p\n", hdb, debugstr_a(table), rec);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiDatabaseGetPrimaryKeysW(MSIHANDLE hdb,
+ LPCWSTR table, MSIHANDLE* rec)
+{
+ FIXME("%ld %s %p\n", hdb, debugstr_w(table), rec);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiViewModify(MSIHANDLE hView, MSIMODIFY eModifyMode, MSIHANDLE
+hRecord)
+{
+ FIXME("%ld %x %ld\n",hView, eModifyMode, hRecord);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
reactos/lib/msi
diff -N order.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ order.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,335 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+
+#include "query.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+
+/* below is the query interface to a table */
+
+typedef struct tagMSIORDERVIEW
+{
+ MSIVIEW view;
+ MSIDATABASE *db;
+ MSIVIEW *table;
+ UINT *reorder;
+ UINT num_cols;
+ UINT cols[1];
+} MSIORDERVIEW;
+
+static UINT ORDER_compare( MSIORDERVIEW *ov, UINT a, UINT b, UINT *swap )
+{
+ UINT r, i, a_val = 0, b_val = 0;
+
+ *swap = 0;
+ for( i=0; i<ov->num_cols; i++ )
+ {
+ r = ov->table->ops->fetch_int( ov->table, a, ov->cols[i], &a_val );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ r = ov->table->ops->fetch_int( ov->table, b, ov->cols[i], &b_val );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ if( a_val != b_val )
+ {
+ if( a_val > b_val )
+ *swap = 1;
+ break;
+ }
+ }
+
+ return ERROR_SUCCESS;
+}
+
+static UINT ORDER_mergesort( MSIORDERVIEW *ov, UINT left, UINT right )
+{
+ UINT r, centre = (left + right)/2, temp, swap = 0, i, j;
+ UINT *array = ov->reorder;
+
+ if( left == right )
+ return ERROR_SUCCESS;
+
+ /* sort the left half */
+ r = ORDER_mergesort( ov, left, centre );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ /* sort the right half */
+ r = ORDER_mergesort( ov, centre+1, right );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ for( i=left, j=centre+1; (i<=centre) && (j<=right); i++ )
+ {
+ r = ORDER_compare( ov, array[i], array[j], &swap );
+ if( r != ERROR_SUCCESS )
+ return r;
+ if( swap )
+ {
+ temp = array[j];
+ memmove( &array[i+1], &array[i], (j-i)*sizeof (UINT) );
+ array[i] = temp;
+ j++;
+ centre++;
+ }
+ }
+
+ return ERROR_SUCCESS;
+}
+
+static UINT ORDER_verify( MSIORDERVIEW *ov, UINT num_rows )
+{
+ UINT i, swap, r;
+
+ for( i=1; i<num_rows; i++ )
+ {
+ r = ORDER_compare( ov, ov->reorder[i-1], ov->reorder[i], &swap );
+ if( r != ERROR_SUCCESS )
+ return r;
+ if( !swap )
+ continue;
+ ERR("Bad order! %d\n", i);
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+static UINT ORDER_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
+{
+ MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
+
+ TRACE("%p %d %d %p\n", ov, row, col, val );
+
+ if( !ov->table )
+ return ERROR_FUNCTION_FAILED;
+
+ row = ov->reorder[ row ];
+
+ return ov->table->ops->fetch_int( ov->table, row, col, val );
+}
+
+static UINT ORDER_execute( struct tagMSIVIEW *view, MSIRECORD *record )
+{
+ MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
+ UINT r, num_rows = 0, i;
+
+ TRACE("%p %p\n", ov, record);
+
+ if( !ov->table )
+ return ERROR_FUNCTION_FAILED;
+
+ r = ov->table->ops->execute( ov->table, record );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ r = ov->table->ops->get_dimensions( ov->table, &num_rows, NULL );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ ov->reorder = HeapAlloc( GetProcessHeap(), 0, num_rows*sizeof(UINT) );
+ if( !ov->reorder )
+ return ERROR_FUNCTION_FAILED;
+
+ for( i=0; i<num_rows; i++ )
+ ov->reorder[i] = i;
+
+ r = ORDER_mergesort( ov, 0, num_rows - 1 );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ r = ORDER_verify( ov, num_rows );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ return ERROR_SUCCESS;
+}
+
+static UINT ORDER_close( struct tagMSIVIEW *view )
+{
+ MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
+
+ TRACE("%p\n", ov );
+
+ if( !ov->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( ov->reorder )
+ HeapFree( GetProcessHeap(), 0, ov->reorder );
+ ov->reorder = NULL;
+
+ return ov->table->ops->close( ov->table );
+}
+
+static UINT ORDER_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
+{
+ MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
+
+ TRACE("%p %p %p\n", ov, rows, cols );
+
+ if( !ov->table )
+ return ERROR_FUNCTION_FAILED;
+
+ return ov->table->ops->get_dimensions( ov->table, rows, cols );
+}
+
+static UINT ORDER_get_column_info( struct tagMSIVIEW *view,
+ UINT n, LPWSTR *name, UINT *type )
+{
+ MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
+
+ TRACE("%p %d %p %p\n", ov, n, name, type );
+
+ if( !ov->table )
+ return ERROR_FUNCTION_FAILED;
+
+ return ov->table->ops->get_column_info( ov->table, n, name, type );
+}
+
+static UINT ORDER_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
+{
+ MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
+
+ TRACE("%p %d %ld\n", ov, eModifyMode, hrec );
+
+ if( !ov->table )
+ return ERROR_FUNCTION_FAILED;
+
+ return ov->table->ops->modify( ov->table, eModifyMode, hrec );
+}
+
+static UINT ORDER_delete( struct tagMSIVIEW *view )
+{
+ MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
+
+ TRACE("%p\n", ov );
+
+ if( ov->table )
+ ov->table->ops->delete( ov->table );
+
+ if( ov->reorder )
+ HeapFree( GetProcessHeap(), 0, ov->reorder );
+ ov->reorder = NULL;
+
+ msiobj_release( &ov->db->hdr );
+ HeapFree( GetProcessHeap(), 0, ov );
+
+ return ERROR_SUCCESS;
+}
+
+
+MSIVIEWOPS order_ops =
+{
+ ORDER_fetch_int,
+ NULL,
+ NULL,
+ NULL,
+ ORDER_execute,
+ ORDER_close,
+ ORDER_get_dimensions,
+ ORDER_get_column_info,
+ ORDER_modify,
+ ORDER_delete
+};
+
+UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
+{
+ MSIORDERVIEW *ov = NULL;
+ UINT count = 0, r;
+
+ TRACE("%p\n", ov );
+
+ r = table->ops->get_dimensions( table, NULL, &count );
+ if( r != ERROR_SUCCESS )
+ {
+ ERR("can't get table dimensions\n");
+ return r;
+ }
+
+ ov = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof *ov + sizeof (UINT) * count );
+ if( !ov )
+ return ERROR_FUNCTION_FAILED;
+
+ /* fill the structure */
+ ov->view.ops = &order_ops;
+ msiobj_addref( &db->hdr );
+ ov->db = db;
+ ov->table = table;
+ ov->reorder = NULL;
+ ov->num_cols = 0;
+ *view = (MSIVIEW*) ov;
+
+ return ERROR_SUCCESS;
+}
+
+UINT ORDER_AddColumn( MSIVIEW *view, LPWSTR name )
+{
+ MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
+ UINT n, count, r;
+ MSIVIEW *table;
+
+ TRACE("%p adding %s\n", ov, debugstr_w( name ) );
+
+ if( ov->view.ops != &order_ops )
+ return ERROR_FUNCTION_FAILED;
+
+ table = ov->table;
+ if( !table )
+ return ERROR_FUNCTION_FAILED;
+ if( !table->ops->get_dimensions )
+ return ERROR_FUNCTION_FAILED;
+ if( !table->ops->get_column_info )
+ return ERROR_FUNCTION_FAILED;
+
+ r = table->ops->get_dimensions( table, NULL, &count );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ if( ov->num_cols >= count )
+ return ERROR_FUNCTION_FAILED;
+
+ r = VIEW_find_column( table, name, &n );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ ov->cols[ov->num_cols] = n;
+ TRACE("Ordering by column %s (%d)\n", debugstr_w( name ), n);
+
+ ov->num_cols++;
+
+ return ERROR_SUCCESS;
+}
reactos/lib/msi
diff -N package.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ package.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,843 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2004 Aric Stewart for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define NONAMELESSUNION
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winnls.h"
+#include "shlwapi.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "msipriv.h"
+#include "objidl.h"
+#include "wincrypt.h"
+#include "winuser.h"
+#include "shlobj.h"
+#include "wine/unicode.h"
+#include "objbase.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+/*
+ * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
+ * which is a problem because LPCTSTR isn't defined when compiling wine.
+ * To work around this problem, we need to define LPCTSTR as LPCWSTR here,
+ * and make sure to only use it in W functions.
+ */
+#define LPCTSTR LPCWSTR
+
+void MSI_FreePackage( MSIOBJECTHDR *arg)
+{
+ MSIPACKAGE *package= (MSIPACKAGE*) arg;
+
+ ACTION_remove_tracked_tempfiles(package);
+
+ if (package->features && package->loaded_features > 0)
+ HeapFree(GetProcessHeap(),0,package->features);
+
+ if (package->folders && package->loaded_folders > 0)
+ HeapFree(GetProcessHeap(),0,package->folders);
+
+ if (package->components && package->loaded_components > 0)
+ HeapFree(GetProcessHeap(),0,package->components);
+
+ if (package->files && package->loaded_files > 0)
+ HeapFree(GetProcessHeap(),0,package->files);
+ msiobj_release( &package->db->hdr );
+}
+
+UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
+{
+ LPWSTR szwPack = NULL;
+ UINT len, ret;
+
+ TRACE("%s %p\n",debugstr_a(szPackage), phPackage);
+
+ if( szPackage )
+ {
+ len = MultiByteToWideChar( CP_ACP, 0, szPackage, -1, NULL, 0 );
+ szwPack = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
+ if( szwPack )
+ MultiByteToWideChar( CP_ACP, 0, szPackage, -1, szwPack, len );
+ }
+
+ ret = MsiOpenPackageW( szwPack, phPackage );
+
+ if( szwPack )
+ HeapFree( GetProcessHeap(), 0, szwPack );
+
+ return ret;
+}
+
+
+static const UINT clone_properties(MSIDATABASE *db)
+{
+ MSIQUERY * view = NULL;
+ UINT rc;
+ static const WCHAR CreateSql[] = {
+ 'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','_','P','r','o',
+ 'p','e','r','t','y','`',' ','(',' ','`','_','P','r','o','p','e','r','t',
+ 'y','`',' ','C','H','A','R','(','5','6',')',' ','N','O','T',' ','N','U',
+ 'L','L',',',' ','`','V','a','l','u','e','`',' ','C','H','A','R','(','9',
+ '8',')',' ','N','O','T',' ','N','U','L','L',' ','P','R','I','M','A','R',
+ 'Y',' ','K','E','Y',' ','`','_','P','r','o','p','e','r','t','y','`',')',0};
+ static const WCHAR Query[] = {
+ 'S','E','L','E','C','T',' ','*',' ',
+ 'f','r','o','m',' ','P','r','o','p','e','r','t','y',0};
+ static const WCHAR Insert[] = {
+ 'I','N','S','E','R','T',' ','i','n','t','o',' ',
+ '`','_','P','r','o','p','e','r','t','y','`',' ',
+ '(','`','_','P','r','o','p','e','r','t','y','`',',',
+ '`','V','a','l','u','e','`',')',' ',
+ 'V','A','L','U','E','S',' ','(','?',')',0};
+
+ /* create the temporary properties table */
+ rc = MSI_DatabaseOpenViewW(db, CreateSql, &view);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+ rc = MSI_ViewExecute(view,0);
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ /* clone the existing properties */
+ rc = MSI_DatabaseOpenViewW(db, Query, &view);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MSI_ViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ return rc;
+ }
+ while (1)
+ {
+ MSIRECORD * row;
+ MSIQUERY * view2;
+
+ rc = MSI_ViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ break;
+
+ rc = MSI_DatabaseOpenViewW(db,Insert,&view2);
+ if (rc!= ERROR_SUCCESS)
+ continue;
+ rc = MSI_ViewExecute(view2,row);
+ MSI_ViewClose(view2);
+ msiobj_release(&view2->hdr);
+
+ if (rc == ERROR_SUCCESS)
+ msiobj_release(&row->hdr);
+ }
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+
+ return rc;
+}
+
+/*
+ * There are a whole slew of these we need to set
+ *
+ *
+http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
+ */
+static VOID set_installer_properties(MSIPACKAGE *package)
+{
+ WCHAR pth[MAX_PATH];
+ OSVERSIONINFOA OSVersion;
+ DWORD verval;
+ WCHAR verstr[10], msiver[10];
+
+ static const WCHAR cszbs[]={'\\',0};
+ static const WCHAR CFF[] =
+{'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
+ static const WCHAR PFF[] =
+{'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
+ static const WCHAR CADF[] =
+{'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
+ static const WCHAR FaF[] =
+{'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0};
+ static const WCHAR FoF[] =
+{'F','o','n','t','s','F','o','l','d','e','r',0};
+ static const WCHAR SendTF[] =
+{'S','e','n','d','T','o','F','o','l','d','e','r',0};
+ static const WCHAR SMF[] =
+{'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0};
+ static const WCHAR StF[] =
+{'S','t','a','r','t','u','p','F','o','l','d','e','r',0};
+ static const WCHAR TemplF[] =
+{'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0};
+ static const WCHAR DF[] =
+{'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
+ static const WCHAR PMF[] =
+{'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0};
+ static const WCHAR ATF[] =
+{'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
+ static const WCHAR ADF[] =
+{'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
+ static const WCHAR SF[] =
+{'S','y','s','t','e','m','F','o','l','d','e','r',0};
+ static const WCHAR LADF[] =
+{'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
+ static const WCHAR MPF[] =
+{'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
+ static const WCHAR PF[] =
+{'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
+ static const WCHAR WF[] =
+{'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
+ static const WCHAR TF[]=
+{'T','e','m','p','F','o','l','d','e','r',0};
+ static const WCHAR szAdminUser[] =
+{'A','d','m','i','n','U','s','e','r',0};
+ static const WCHAR szPriv[] =
+{'P','r','i','v','i','l','e','g','e','d',0};
+ static const WCHAR szOne[] =
+{'1',0};
+ static const WCHAR v9x[] = { 'V','e','r','s','i','o','n','9','X',0 };
+ static const WCHAR vNT[] = { 'V','e','r','s','i','o','n','N','T',0 };
+ static const WCHAR szFormat[] = {'%','l','i',0};
+ static const WCHAR szWinBuild[] =
+{'W','i','n','d','o','w','s','B','u','i','l','d', 0 };
+ static const WCHAR szSPL[] =
+{'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0 };
+ static const WCHAR szSix[] = {'6',0 };
+
+ static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 };
+ static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0};
+
+/*
+ * Other things I notice set
+ *
+ScreenY
+ScreenX
+SystemLanguageID
+ComputerName
+UserLanguageID
+LogonUser
+VirtualMemory
+PhysicalMemory
+Intel
+ShellAdvSupport
+DefaultUIFont
+VersionDatabase
+PackagecodeChanging
+ProductState
+CaptionHeight
+BorderTop
+BorderSide
+TextHeight
+ColorBits
+RedirectedDllSupport
+Time
+Date
+Privileged
+*/
+
+ SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, CFF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, PFF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, CADF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_FAVORITES,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, FaF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_FONTS,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, FoF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_SENDTO,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, SendTF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_STARTMENU,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, SMF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_STARTUP,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, StF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_TEMPLATES,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, TemplF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_DESKTOP,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, DF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_PROGRAMS,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, PMF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, ATF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, ADF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, SF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, LADF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, MPF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, PF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
+ strcatW(pth,cszbs);
+ MSI_SetPropertyW(package, WF, pth);
+
+ GetTempPathW(MAX_PATH,pth);
+ MSI_SetPropertyW(package, TF, pth);
+
+
+ /* in a wine environment the user is always admin and privileged */
+ MSI_SetPropertyW(package,szAdminUser,szOne);
+ MSI_SetPropertyW(package,szPriv,szOne);
+
+ /* set the os things */
+ OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
+ GetVersionExA(&OSVersion);
+ verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100;
+ sprintfW(verstr,szFormat,verval);
+ switch (OSVersion.dwPlatformId)
+ {
+ case VER_PLATFORM_WIN32_WINDOWS:
+ MSI_SetPropertyW(package,v9x,verstr);
+ break;
+ case VER_PLATFORM_WIN32_NT:
+ MSI_SetPropertyW(package,vNT,verstr);
+ break;
+ }
+ sprintfW(verstr,szFormat,OSVersion.dwBuildNumber);
+ MSI_SetPropertyW(package,szWinBuild,verstr);
+ /* just fudge this */
+ MSI_SetPropertyW(package,szSPL,szSix);
+
+ sprintfW( msiver, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);
+ MSI_SetPropertyW( package, szVersionMsi, msiver );
+}
+
+UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
+{
+ UINT rc;
+ MSIDATABASE *db = NULL;
+ MSIPACKAGE *package = NULL;
+ WCHAR uilevel[10];
+ UINT ret = ERROR_FUNCTION_FAILED;
+
+ static const WCHAR OriginalDatabase[] =
+{'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
+ static const WCHAR Database[] =
+{'D','A','T','A','B','A','S','E',0};
+ static const WCHAR szpi[] = {'%','i',0};
+ static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
+
+ TRACE("%s %p\n",debugstr_w(szPackage), pPackage);
+
+ if (szPackage[0] == '#')
+ {
+ INT handle = atoiW(&szPackage[1]);
+ db = msihandle2msiinfo( handle , MSIHANDLETYPE_DATABASE);
+ }
+ else
+ {
+ rc = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
+ if (rc != ERROR_SUCCESS)
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
+ MSI_FreePackage );
+
+ if (package)
+ {
+ msiobj_addref( &db->hdr );
+
+ package->db = db;
+ package->features = NULL;
+ package->folders = NULL;
+ package->components = NULL;
+ package->files = NULL;
+ package->loaded_features = 0;
+ package->loaded_folders = 0;
+ package->loaded_components= 0;
+ package->loaded_files = 0;
+
+ /* OK, here is where we do a slew of things to the database to
+ * prep for all that is to come as a package */
+
+ clone_properties(db);
+ set_installer_properties(package);
+ MSI_SetPropertyW(package, OriginalDatabase, szPackage);
+ MSI_SetPropertyW(package, Database, szPackage);
+ sprintfW(uilevel,szpi,gUILevel);
+ MSI_SetPropertyW(package, szLevel, uilevel);
+
+ msiobj_addref( &package->hdr );
+ *pPackage = package;
+ ret = ERROR_SUCCESS;
+ }
+
+ if( package )
+ msiobj_release( &package->hdr );
+ if( db )
+ msiobj_release( &db->hdr );
+
+ return ret;
+}
+
+UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
+{
+ MSIPACKAGE *package = NULL;
+ UINT ret;
+
+ ret = MSI_OpenPackageW( szPackage, &package);
+ if( ret == ERROR_SUCCESS )
+ {
+ *phPackage = alloc_msihandle( &package->hdr );
+ msiobj_release( &package->hdr );
+ }
+ return ret;
+}
+
+UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
+{
+ FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
+{
+ FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
+{
+ MSIPACKAGE *package;
+ MSIHANDLE handle = 0;
+
+ TRACE("(%ld)\n",hInstall);
+
+ package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
+ if( package)
+ {
+ handle = alloc_msihandle( &package->db->hdr );
+ msiobj_release( &package->hdr );
+ }
+
+ return handle;
+}
+
+INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
+ MSIRECORD *record)
+{
+ DWORD log_type = 0;
+ LPWSTR message;
+ DWORD sz;
+ DWORD total_size = 0;
+ INT msg_field=1;
+ INT i;
+ INT rc;
+ char *msg;
+ int len;
+
+ TRACE("%x \n",eMessageType);
+ rc = 0;
+
+ if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
+ log_type |= INSTALLLOGMODE_ERROR;
+ if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
+ log_type |= INSTALLLOGMODE_WARNING;
+ if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
+ log_type |= INSTALLLOGMODE_USER;
+ if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
+ log_type |= INSTALLLOGMODE_INFO;
+ if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
+ log_type |= INSTALLLOGMODE_COMMONDATA;
+ if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
+ log_type |= INSTALLLOGMODE_ACTIONSTART;
+ if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
+ log_type |= INSTALLLOGMODE_ACTIONDATA;
+ /* just a guess */
+ if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
+ log_type |= 0x800;
+
+ message = HeapAlloc(GetProcessHeap(),0,1*sizeof (WCHAR));
+ message[0]=0;
+ msg_field = MSI_RecordGetFieldCount(record);
+ for (i = 1; i <= msg_field; i++)
+ {
+ LPWSTR tmp;
+ WCHAR number[3];
+ const static WCHAR format[] = { '%','i',':',' ',0};
+ const static WCHAR space[] = { ' ',0};
+ sz = 0;
+ MSI_RecordGetStringW(record,i,NULL,&sz);
+ sz+=4;
+ total_size+=sz*sizeof(WCHAR);
+ tmp = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
+ message = HeapReAlloc(GetProcessHeap(),0,message,total_size*sizeof (WCHAR));
+
+ MSI_RecordGetStringW(record,i,tmp,&sz);
+
+ if (msg_field > 1)
+ {
+ sprintfW(number,format,i);
+ strcatW(message,number);
+ }
+ strcatW(message,tmp);
+ if (msg_field > 1)
+ strcatW(message,space);
+
+ HeapFree(GetProcessHeap(),0,tmp);
+ }
+
+ TRACE("(%p %lx %lx %s)\n",gUIHandler, gUIFilter, log_type,
+ debugstr_w(message));
+
+ /* convert it to ASCII */
+ len = WideCharToMultiByte( CP_ACP, 0, message, -1,
+ NULL, 0, NULL, NULL );
+ msg = HeapAlloc( GetProcessHeap(), 0, len );
+ WideCharToMultiByte( CP_ACP, 0, message, -1,
+ msg, len, NULL, NULL );
+
+ if (gUIHandler && (gUIFilter & log_type))
+ {
+ rc = gUIHandler(gUIContext,eMessageType,msg);
+ }
+
+ if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
+ INSTALLMESSAGE_PROGRESS))
+ {
+ DWORD write;
+ HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (log_file != INVALID_HANDLE_VALUE)
+ {
+ SetFilePointer(log_file,0, NULL, FILE_END);
+ WriteFile(log_file,msg,strlen(msg),&write,NULL);
+ WriteFile(log_file,"\n",1,&write,NULL);
+ CloseHandle(log_file);
+ }
+ }
+ HeapFree( GetProcessHeap(), 0, msg );
+
+ HeapFree(GetProcessHeap(),0,message);
+ return ERROR_SUCCESS;
+}
+
+INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
+ MSIHANDLE hRecord)
+{
+ UINT ret = ERROR_INVALID_HANDLE;
+ MSIPACKAGE *package = NULL;
+ MSIRECORD *record = NULL;
+
+ package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
+ if( !package )
+ goto out;
+
+ record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
+ if( !record )
+ goto out;
+
+ ret = MSI_ProcessMessage( package, eMessageType, record );
+
+out:
+ if( package )
+ msiobj_release( &package->hdr );
+ if( record )
+ msiobj_release( &record->hdr );
+
+ return ret;
+}
+
+/* property code */
+UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
+{
+ LPWSTR szwName = NULL, szwValue = NULL;
+ UINT hr = ERROR_INSTALL_FAILURE;
+ UINT len;
+
+ if (0 == hInstall) {
+ return ERROR_INVALID_HANDLE;
+ }
+ if (NULL == szName) {
+ return ERROR_INVALID_PARAMETER;
+ }
+ if (NULL == szValue) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
+ szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ if( !szwName )
+ goto end;
+ MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
+
+ len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
+ szwValue = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ if( !szwValue)
+ goto end;
+ MultiByteToWideChar( CP_ACP, 0, szValue , -1, szwValue, len );
+
+ hr = MsiSetPropertyW( hInstall, szwName, szwValue);
+
+end:
+ if( szwName )
+ HeapFree( GetProcessHeap(), 0, szwName );
+ if( szwValue )
+ HeapFree( GetProcessHeap(), 0, szwValue );
+
+ return hr;
+}
+
+UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
+{
+ MSIQUERY *view;
+ MSIRECORD *row;
+ UINT rc;
+ DWORD sz = 0;
+ static const WCHAR Insert[]=
+ {'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p'
+,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`'
+,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
+,' ','(','?',')',0};
+ static const WCHAR Update[]=
+ {'U','P','D','A','T','E',' ','_','P','r','o','p','e'
+,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
+,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p'
+,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
+ WCHAR Query[1024];
+
+ TRACE("Setting property (%s %s)\n",debugstr_w(szName),
+ debugstr_w(szValue));
+
+ rc = MSI_GetPropertyW(package,szName,0,&sz);
+ if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS)
+ {
+ sprintfW(Query,Update,szName);
+
+ row = MSI_CreateRecord(1);
+ MSI_RecordSetStringW(row,1,szValue);
+
+ }
+ else
+ {
+ strcpyW(Query,Insert);
+
+ row = MSI_CreateRecord(2);
+ MSI_RecordSetStringW(row,1,szName);
+ MSI_RecordSetStringW(row,2,szValue);
+ }
+
+
+ rc = MSI_DatabaseOpenViewW(package->db,Query,&view);
+ if (rc!= ERROR_SUCCESS)
+ {
+ msiobj_release(&row->hdr);
+ return rc;
+ }
+
+ rc = MSI_ViewExecute(view,row);
+
+ msiobj_release(&row->hdr);
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+
+ return rc;
+}
+
+UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
+{
+ MSIPACKAGE *package;
+ UINT ret;
+
+ package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
+ if( !package)
+ return ERROR_INVALID_HANDLE;
+ ret = MSI_SetPropertyW( package, szName, szValue);
+ msiobj_release( &package->hdr );
+ return ret;
+}
+
+static UINT MSI_GetPropertyRow(MSIPACKAGE *package, LPCWSTR szName, MSIRECORD **row)
+{
+ MSIQUERY *view;
+ UINT rc, sz;
+ static const WCHAR select[]=
+ {'s','e','l','e','c','t',' ','V','a','l','u','e',' ','f','r','o','m',' '
+ ,'_','P','r','o','p','e','r','t','y',' ','w','h','e','r','e',' '
+ ,'_','P','r','o','p','e','r','t','y','=','`','%','s','`',0};
+ LPWSTR query;
+
+ if (!szName)
+ return ERROR_INVALID_PARAMETER;
+
+ sz = sizeof select + strlenW(szName)*sizeof(WCHAR);
+ query = HeapAlloc(GetProcessHeap(), 0, sz);
+ sprintfW(query,select,szName);
+
+ rc = MSI_DatabaseOpenViewW(package->db, query, &view);
+ HeapFree(GetProcessHeap(), 0, query);
+ if (rc == ERROR_SUCCESS)
+ {
+ rc = MSI_ViewExecute(view, 0);
+ if (rc == ERROR_SUCCESS)
+ rc = MSI_ViewFetch(view,row);
+
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
+ }
+
+ return rc;
+}
+
+UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName,
+ LPWSTR szValueBuf, DWORD* pchValueBuf)
+{
+ MSIRECORD *row;
+ UINT rc;
+
+ rc = MSI_GetPropertyRow(package, szName, &row);
+ if (rc == ERROR_SUCCESS)
+ {
+ rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf);
+ msiobj_release(&row->hdr);
+ }
+
+ if (rc == ERROR_SUCCESS)
+ TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
+ debugstr_w(szName));
+ else
+ {
+ *pchValueBuf = 0;
+ TRACE("property not found\n");
+ }
+
+ return rc;
+}
+
+UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName,
+ LPSTR szValueBuf, DWORD* pchValueBuf)
+{
+ MSIRECORD *row;
+ UINT rc, len;
+ LPWSTR szwName;
+
+ len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
+ szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ if (!szwName)
+ return ERROR_NOT_ENOUGH_MEMORY;
+ MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
+
+ rc = MSI_GetPropertyRow(package, szwName, &row);
+ if (rc == ERROR_SUCCESS)
+ {
+ rc = MSI_RecordGetStringA(row,1,szValueBuf,pchValueBuf);
+ msiobj_release(&row->hdr);
+ }
+
+ if (rc == ERROR_SUCCESS)
+ TRACE("returning %s for property %s\n", debugstr_a(szValueBuf),
+ debugstr_a(szName));
+ else
+ {
+ *pchValueBuf = 0;
+ TRACE("property not found\n");
+ }
+ HeapFree( GetProcessHeap(), 0, szwName );
+
+ return rc;
+}
+
+UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf)
+{
+ MSIPACKAGE *package;
+ UINT ret;
+
+ TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
+
+ if (0 == hInstall)
+ return ERROR_INVALID_HANDLE;
+ if (NULL == szName)
+ return ERROR_INVALID_PARAMETER;
+ if (NULL != szValueBuf && NULL == pchValueBuf)
+ return ERROR_INVALID_PARAMETER;
+
+ package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+ ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf );
+ msiobj_release( &package->hdr );
+ return ret;
+}
+
+
+UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName,
+ LPWSTR szValueBuf, DWORD* pchValueBuf)
+{
+ MSIPACKAGE *package;
+ UINT ret;
+
+ if (0 == hInstall)
+ return ERROR_INVALID_HANDLE;
+ if (NULL == szName)
+ return ERROR_INVALID_PARAMETER;
+ if (NULL != szValueBuf && NULL == pchValueBuf)
+ return ERROR_INVALID_PARAMETER;
+
+ package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+ ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
+ msiobj_release( &package->hdr );
+ return ret;
+}
reactos/lib/msi
diff -N query.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ query.h 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,139 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __WINE_MSI_QUERY_H
+#define __WINE_MSI_QUERY_H
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "msipriv.h"
+
+
+#define OP_EQ 1
+#define OP_AND 2
+#define OP_OR 3
+#define OP_GT 4
+#define OP_LT 5
+#define OP_LE 6
+#define OP_GE 7
+#define OP_NE 8
+#define OP_ISNULL 9
+#define OP_NOTNULL 10
+
+#define EXPR_COMPLEX 1
+#define EXPR_COLUMN 2
+#define EXPR_COL_NUMBER 3
+#define EXPR_IVAL 4
+#define EXPR_SVAL 5
+#define EXPR_UVAL 6
+#define EXPR_STRCMP 7
+#define EXPR_UTF8 8
+#define EXPR_WILDCARD 9
+
+struct sql_str {
+ LPCWSTR data;
+ INT len;
+};
+
+typedef struct _string_list
+{
+ LPWSTR string;
+ struct _string_list *next;
+} string_list;
+
+struct complex_expr
+{
+ UINT op;
+ struct expr *left;
+ struct expr *right;
+};
+
+struct expr
+{
+ int type;
+ union
+ {
+ struct complex_expr expr;
+ INT ival;
+ UINT uval;
+ LPWSTR sval;
+ LPWSTR column;
+ UINT col_number;
+ char *utf8;
+ } u;
+};
+
+typedef struct _create_col_info
+{
+ LPWSTR colname;
+ UINT type;
+ struct _create_col_info *next;
+} create_col_info;
+
+typedef struct _value_list
+{
+ struct expr *val;
+ struct _value_list *next;
+} value_list;
+
+typedef struct _column_assignment
+{
+ string_list *col_list;
+ value_list *val_list;
+} column_assignment;
+
+
+UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phView);
+
+UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view );
+
+UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
+ string_list *columns );
+
+UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
+
+UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
+UINT ORDER_AddColumn( MSIVIEW *group, LPWSTR name );
+
+UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
+ struct expr *cond );
+
+UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
+ create_col_info *col_info, BOOL temp );
+
+UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
+ string_list *columns, value_list *values, BOOL temp );
+
+UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **, LPWSTR table,
+ column_assignment *list, struct expr *expr );
+
+void delete_expr( struct expr *e );
+void delete_string_list( string_list *sl );
+void delete_value_list( value_list *vl );
+
+int sqliteGetToken(const WCHAR *z, int *tokenType);
+
+#endif /* __WINE_MSI_QUERY_H */
reactos/lib/msi
diff -N record.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ record.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,573 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002-2004 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "msipriv.h"
+#include "objidl.h"
+#include "winnls.h"
+
+#include "query.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+#define MSIFIELD_NULL 0
+#define MSIFIELD_INT 1
+#define MSIFIELD_STR 2
+#define MSIFIELD_WSTR 3
+#define MSIFIELD_STREAM 4
+
+void MSI_FreeField( MSIFIELD *field )
+{
+ switch( field->type )
+ {
+ case MSIFIELD_NULL:
+ case MSIFIELD_INT:
+ break;
+ case MSIFIELD_WSTR:
+ HeapFree( GetProcessHeap(), 0, field->u.szwVal);
+ break;
+ case MSIFIELD_STREAM:
+ IStream_Release( field->u.stream );
+ break;
+ default:
+ ERR("Invalid field type %d\n", field->type);
+ }
+}
+
+void MSI_CloseRecord( MSIOBJECTHDR *arg )
+{
+ MSIRECORD *rec = (MSIRECORD *) arg;
+ UINT i;
+
+ for( i=0; i<=rec->count; i++ )
+ MSI_FreeField( &rec->fields[i] );
+}
+
+MSIRECORD *MSI_CreateRecord( unsigned int cParams )
+{
+ MSIRECORD *rec;
+ UINT len;
+
+ TRACE("%d\n", cParams);
+
+ len = sizeof (MSIRECORD) + sizeof (MSIFIELD)*cParams;
+ rec = alloc_msiobject( MSIHANDLETYPE_RECORD, len, MSI_CloseRecord );
+ if( rec )
+ rec->count = cParams;
+ return rec;
+}
+
+MSIHANDLE WINAPI MsiCreateRecord( unsigned int cParams )
+{
+ MSIRECORD *rec;
+ MSIHANDLE ret = 0;
+
+ TRACE("%d\n", cParams);
+
+ rec = MSI_CreateRecord( cParams );
+ if( rec )
+ ret = alloc_msihandle( &rec->hdr );
+ return ret;
+}
+
+unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec )
+{
+ return rec->count;
+}
+
+unsigned int WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
+{
+ MSIRECORD *rec;
+ UINT ret;
+
+ TRACE("%ld\n", handle );
+
+ rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
+ if( !rec )
+ {
+ ERR("Record not found!\n");
+ return 0;
+ }
+
+ ret = MSI_RecordGetFieldCount( rec );
+ msiobj_release( &rec->hdr );
+
+ return ret;
+}
+
+static BOOL string2intW( LPCWSTR str, int *out )
+{
+ int x = 0;
+ LPCWSTR p = str;
+
+ if( *p == '-' ) /* skip the minus sign */
+ p++;
+ while ( *p )
+ {
+ if( (*p < '0') || (*p > '9') )
+ return FALSE;
+ x *= 10;
+ x += (*p - '0');
+ p++;
+ }
+
+ if( str[0] == '-' ) /* check if it's negative */
+ x = -x;
+ *out = x;
+
+ return TRUE;
+}
+
+int MSI_RecordGetInteger( MSIRECORD *rec, unsigned int iField)
+{
+ int ret = 0;
+
+ TRACE("%p %d\n", rec, iField );
+
+ if( iField > rec->count )
+ return MSI_NULL_INTEGER;
+
+ switch( rec->fields[iField].type )
+ {
+ case MSIFIELD_INT:
+ return rec->fields[iField].u.iVal;
+ case MSIFIELD_WSTR:
+ if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
+ return ret;
+ return MSI_NULL_INTEGER;
+ default:
+ break;
+ }
+
+ return MSI_NULL_INTEGER;
+}
+
+int WINAPI MsiRecordGetInteger( MSIHANDLE handle, unsigned int iField)
+{
+ MSIRECORD *rec;
+ UINT ret;
+
+ TRACE("%ld %d\n", handle, iField );
+
+ rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
+ if( !rec )
+ return MSI_NULL_INTEGER;
+
+ ret = MSI_RecordGetInteger( rec, iField );
+ msiobj_release( &rec->hdr );
+
+ return ret;
+}
+
+UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
+{
+ MSIRECORD *rec;
+ UINT i;
+
+ TRACE("%ld\n", handle );
+
+ rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
+ if( !rec )
+ return ERROR_INVALID_HANDLE;
+
+ for( i=0; i<=rec->count; i++)
+ {
+ MSI_FreeField( &rec->fields[i] );
+ rec->fields[i].type = MSIFIELD_NULL;
+ rec->fields[i].u.iVal = 0;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+UINT MSI_RecordSetInteger( MSIRECORD *rec, unsigned int iField, int iVal )
+{
+ TRACE("%p %u %d\n", rec, iField, iVal);
+
+ if( iField <= rec->count )
+ {
+ MSI_FreeField( &rec->fields[iField] );
+ rec->fields[iField].type = MSIFIELD_INT;
+ rec->fields[iField].u.iVal = iVal;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, unsigned int iField, int iVal )
+{
+ MSIRECORD *rec;
+ UINT ret;
+
+ TRACE("%ld %u %d\n", handle, iField, iVal);
+
+ rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
+ if( !rec )
+ return ERROR_INVALID_HANDLE;
+
+ ret = MSI_RecordSetInteger( rec, iField, iVal );
+ msiobj_release( &rec->hdr );
+ return ret;
+}
+
+BOOL MSI_RecordIsNull( MSIRECORD *rec, unsigned int iField )
+{
+ BOOL r = TRUE;
+
+ TRACE("%p %d\n", rec, iField );
+
+ r = ( iField > rec->count ) ||
+ ( rec->fields[iField].type == MSIFIELD_NULL );
+
+ return r;
+}
+
+BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, unsigned int iField )
+{
+ MSIRECORD *rec;
+ UINT ret;
+
+ TRACE("%ld %d\n", handle, iField );
+
+ rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
+ if( !rec )
+ return ERROR_INVALID_HANDLE;
+ ret = MSI_RecordIsNull( rec, iField );
+ msiobj_release( &rec->hdr );
+ return ret;
+
+}
+
+UINT MSI_RecordGetStringA(MSIRECORD *rec, unsigned int iField,
+ LPSTR szValue, DWORD *pcchValue)
+{
+ UINT len=0, ret;
+ CHAR buffer[16];
+
+ TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
+
+ if( iField > rec->count )
+ return ERROR_INVALID_PARAMETER;
+
+ ret = ERROR_SUCCESS;
+ switch( rec->fields[iField].type )
+ {
+ case MSIFIELD_INT:
+ wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
+ len = lstrlenA( buffer );
+ lstrcpynA(szValue, buffer, *pcchValue);
+ break;
+ case MSIFIELD_WSTR:
+ len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
+ NULL, 0 , NULL, NULL);
+ WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
+ szValue, *pcchValue, NULL, NULL);
+ break;
+ case MSIFIELD_NULL:
+ len = 1;
+ if( *pcchValue > 0 )
+ szValue[0] = 0;
+ break;
+ default:
+ ret = ERROR_INVALID_PARAMETER;
+ break;
+ }
+
+ if( *pcchValue < len )
+ ret = ERROR_MORE_DATA;
+ *pcchValue = len;
+
+ return ret;
+}
+
+UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, unsigned int iField,
+ LPSTR szValue, DWORD *pcchValue)
+{
+ MSIRECORD *rec;
+ UINT ret;
+
+ TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue);
+
+ rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
+ if( !rec )
+ return ERROR_INVALID_HANDLE;
+ ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
+ msiobj_release( &rec->hdr );
+ return ret;
+}
+
+const WCHAR *MSI_RecordGetString( MSIRECORD *rec, unsigned int iField )
+{
+ if( iField > rec->count )
+ return NULL;
+
+ if( rec->fields[iField].type != MSIFIELD_WSTR )
+ return NULL;
+
+ return rec->fields[iField].u.szwVal;
+}
+
+UINT MSI_RecordGetStringW(MSIRECORD *rec, unsigned int iField,
+ LPWSTR szValue, DWORD *pcchValue)
+{
+ UINT len=0, ret;
+ WCHAR buffer[16];
+ static const WCHAR szFormat[] = { '%','d',0 };
+
+ TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
+
+ if( iField > rec->count )
+ return ERROR_INVALID_PARAMETER;
+
+ ret = ERROR_SUCCESS;
+ switch( rec->fields[iField].type )
+ {
+ case MSIFIELD_INT:
+ wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal);
+ len = lstrlenW( buffer );
+ lstrcpynW(szValue, buffer, *pcchValue);
+ break;
+ case MSIFIELD_WSTR:
+ len = lstrlenW( rec->fields[iField].u.szwVal );
+ lstrcpynW(szValue, rec->fields[iField].u.szwVal, *pcchValue);
+ break;
+ case MSIFIELD_NULL:
+ len = 1;
+ if( *pcchValue > 0 )
+ szValue[0] = 0;
+ default:
+ break;
+ }
+
+ if( *pcchValue < len )
+ ret = ERROR_MORE_DATA;
+ *pcchValue = len;
+
+ return ret;
+}
+
+UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, unsigned int iField,
+ LPWSTR szValue, DWORD *pcchValue)
+{
+ MSIRECORD *rec;
+ UINT ret;
+
+ TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue);
+
+ rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
+ if( !rec )
+ return ERROR_INVALID_HANDLE;
+
+ ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
+ msiobj_release( &rec->hdr );
+ return ret;
+}
+
+UINT WINAPI MsiRecordDataSize(MSIHANDLE hRecord, unsigned int iField)
+{
+ FIXME("%ld %d\n", hRecord, iField);
+ return 0;
+}
+
+UINT MSI_RecordSetStringA( MSIRECORD *rec, unsigned int iField, LPCSTR szValue )
+{
+ LPWSTR str;
+ UINT len;
+
+ TRACE("%p %d %s\n", rec, iField, debugstr_a(szValue));
+
+ if( iField > rec->count )
+ return ERROR_INVALID_FIELD;
+
+ len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
+ str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
+ MultiByteToWideChar( CP_ACP, 0, szValue, -1, str, len );
+ MSI_FreeField( &rec->fields[iField] );
+ rec->fields[iField].type = MSIFIELD_WSTR;
+ rec->fields[iField].u.szwVal = str;
+
+ return 0;
+}
+
+UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, unsigned int iField, LPCSTR szValue )
+{
+ MSIRECORD *rec;
+ UINT ret;
+
+ TRACE("%ld %d %s\n", handle, iField, debugstr_a(szValue));
+
+ rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
+ if( !rec )
+ return ERROR_INVALID_HANDLE;
+ ret = MSI_RecordSetStringA( rec, iField, szValue );
+ msiobj_release( &rec->hdr );
+ return ret;
+}
+
+UINT MSI_RecordSetStringW( MSIRECORD *rec, unsigned int iField, LPCWSTR szValue )
+{
+ LPWSTR str;
+ UINT len;
+
+ TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
+
+ if( iField > rec->count )
+ return ERROR_INVALID_FIELD;
+
+ len = lstrlenW(szValue) + 1;
+ str = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR));
+ lstrcpyW( str, szValue );
+
+ MSI_FreeField( &rec->fields[iField] );
+ rec->fields[iField].type = MSIFIELD_WSTR;
+ rec->fields[iField].u.szwVal = str;
+
+ return 0;
+}
+
+UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR szValue )
+{
+ MSIRECORD *rec;
+ UINT ret;
+
+ TRACE("%ld %d %s\n", handle, iField, debugstr_w(szValue));
+
+ rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
+ if( !rec )
+ return ERROR_INVALID_HANDLE;
+
+ ret = MSI_RecordSetStringW( rec, iField, szValue );
+ msiobj_release( &rec->hdr );
+ return ret;
+}
+
+UINT WINAPI MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, LPSTR szResult, DWORD *sz)
+{
+ FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, LPWSTR szResult, DWORD *sz)
+{
+ FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, unsigned int iField, LPCSTR szFilename)
+{
+ FIXME("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename));
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiRecordSetStreamW(MSIHANDLE hRecord, unsigned int iField, LPCWSTR szFilename)
+{
+ FIXME("%ld %d %s\n", hRecord, iField, debugstr_w(szFilename));
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT MSI_RecordReadStream(MSIRECORD *rec, unsigned int iField, char *buf, DWORD *sz)
+{
+ ULONG count;
+ HRESULT r;
+ IStream *stm;
+
+ TRACE("%p %d %p %p\n", rec, iField, buf, sz);
+
+ if( iField > rec->count )
+ return ERROR_INVALID_FIELD;
+
+ if( rec->fields[iField].type != MSIFIELD_STREAM )
+ {
+ *sz = 0;
+ return ERROR_INVALID_FIELD;
+ }
+
+ stm = rec->fields[iField].u.stream;
+ if( !stm )
+ return ERROR_INVALID_FIELD;
+
+ /* if there's no buffer pointer, calculate the length to the end */
+ if( !buf )
+ {
+ LARGE_INTEGER ofs;
+ ULARGE_INTEGER end, cur;
+
+ ofs.QuadPart = cur.QuadPart = 0;
+ end.QuadPart = 0;
+ r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
+ IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
+ ofs.QuadPart = cur.QuadPart;
+ IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
+ *sz = end.QuadPart - cur.QuadPart;
+
+ return ERROR_SUCCESS;
+ }
+
+ /* read the data */
+ count = 0;
+ r = IStream_Read( stm, buf, *sz, &count );
+ if( FAILED( r ) )
+ return ERROR_FUNCTION_FAILED;
+
+ *sz = count;
+
+ return ERROR_SUCCESS;
+}
+
+UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, unsigned int iField, char *buf, DWORD *sz)
+{
+ MSIRECORD *rec;
+ UINT ret;
+
+ TRACE("%ld %d %p %p\n", handle, iField, buf, sz);
+
+ rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
+ if( !rec )
+ return ERROR_INVALID_HANDLE;
+ ret = MSI_RecordReadStream( rec, iField, buf, sz );
+ msiobj_release( &rec->hdr );
+ return ret;
+}
+
+UINT MSI_RecordSetIStream( MSIRECORD *rec, unsigned int iField, IStream *stm )
+{
+ TRACE("%p %d %p\n", rec, iField, stm);
+
+ if( iField > rec->count )
+ return ERROR_INVALID_FIELD;
+
+ MSI_FreeField( &rec->fields[iField] );
+
+ rec->fields[iField].type = MSIFIELD_STREAM;
+ rec->fields[iField].u.stream = stm;
+ IStream_AddRef( stm );
+
+ return ERROR_SUCCESS;
+}
reactos/lib/msi
diff -N regsvr.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ regsvr.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,624 @@
+/*
+ * self-registerable dll functions for msi.dll
+ *
+ * Copyright (C) 2004 Raphael Junqueira
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "winerror.h"
+
+#include "ole2.h"
+#include "olectl.h"
+
+#include "wine/debug.h"
+
+#include "msi.h"
+#include "initguid.h"
+#include "msipriv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+/*
+ * Near the bottom of this file are the exported DllRegisterServer and
+ * DllUnregisterServer, which make all this worthwhile.
+ */
+
+/***********************************************************************
+ * interface for self-registering
+ */
+struct regsvr_interface {
+ IID const *iid; /* NULL for end of list */
+ LPCSTR name; /* can be NULL to omit */
+ IID const *base_iid; /* can be NULL to omit */
+ int num_methods; /* can be <0 to omit */
+ CLSID const *ps_clsid; /* can be NULL to omit */
+ CLSID const *ps_clsid32; /* can be NULL to omit */
+};
+
+static HRESULT register_interfaces(struct regsvr_interface const *list);
+static HRESULT unregister_interfaces(struct regsvr_interface const *list);
+
+/**
+ * @todo: maybe adding typelibs support here
+ * [Software\\Classes\\CLSID\\{000C1090-0000-0000-C000-000000000046}\\TypeLib] 1080380217
+ * @="{000C1092-0000-0000-C000-000000000046}"
+ */
+struct regsvr_coclass {
+ CLSID const *clsid; /* NULL for end of list */
+ LPCSTR name; /* can be NULL to omit */
+ LPCSTR iph32; /* can be NULL to omit */
+ LPCSTR ips; /* can be NULL to omit */
+ LPCSTR ips32; /* can be NULL to omit */
+ LPCSTR ips32_tmodel; /* can be NULL to omit, if apartment, iph32 must be set */
+ LPCSTR progid; /* can be NULL to omit */
+ LPCSTR viprogid; /* can be NULL to omit */
+ LPCSTR progid_extra; /* can be NULL to omit */
+};
+
+static HRESULT register_coclasses(struct regsvr_coclass const *list);
+static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
+
+/***********************************************************************
+ * static string constants
+ */
+static WCHAR const interface_keyname[10] = {
+ 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
+static WCHAR const base_ifa_keyname[14] = {
+ 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
+ 'e', 0 };
+static WCHAR const num_methods_keyname[11] = {
+ 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
+static WCHAR const ps_clsid_keyname[15] = {
+ 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
+ 'i', 'd', 0 };
+static WCHAR const ps_clsid32_keyname[17] = {
+ 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
+ 'i', 'd', '3', '2', 0 };
+static WCHAR const clsid_keyname[6] = {
+ 'C', 'L', 'S', 'I', 'D', 0 };
+static WCHAR const curver_keyname[7] = {
+ 'C', 'u', 'r', 'V', 'e', 'r', 0 };
+static WCHAR const iph32_keyname[] = {
+ 'I', 'n', 'P', 'r', 'o', 'c', 'H', 'a', 'n', 'd', 'l', 'e', 'r',
+ '3', '2', 0 };
+static WCHAR const ips_keyname[13] = {
+ 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
+ 0 };
+static WCHAR const ips32_keyname[15] = {
+ 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
+ '3', '2', 0 };
+static WCHAR const progid_keyname[7] = {
+ 'P', 'r', 'o', 'g', 'I', 'D', 0 };
+static WCHAR const viprogid_keyname[25] = {
+ 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
+ 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
+ 0 };
+static char const tmodel_valuename[] = "ThreadingModel";
+
+/***********************************************************************
+ * static helper functions
+ */
+static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
+static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
+ WCHAR const *value);
+static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
+ char const *value);
+static LONG register_progid(WCHAR const *clsid,
+ char const *progid, char const *curver_progid,
+ char const *name, char const *extra);
+static LONG recursive_delete_key(HKEY key);
+static LONG recursive_delete_keyA(HKEY base, char const *name);
+static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
+
+/***********************************************************************
+ * register_interfaces
+ */
+static HRESULT register_interfaces(struct regsvr_interface const *list) {
+ LONG res = ERROR_SUCCESS;
+ HKEY interface_key;
+
+ res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->iid; ++list) {
+ WCHAR buf[39];
+ HKEY iid_key;
+
+ StringFromGUID2(list->iid, buf, 39);
+ res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_interface_key;
+
+ if (list->name) {
+ res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)(list->name),
+ strlen(list->name) + 1);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (list->base_iid) {
+ register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (0 <= list->num_methods) {
+ static WCHAR const fmt[3] = { '%', 'd', 0 };
+ HKEY key;
+
+ res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+
+ wsprintfW(buf, fmt, list->num_methods);
+ res = RegSetValueExW(key, NULL, 0, REG_SZ,
+ (CONST BYTE*)buf,
+ (lstrlenW(buf) + 1) * sizeof(WCHAR));
+ RegCloseKey(key);
+
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (list->ps_clsid) {
+ register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (list->ps_clsid32) {
+ register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ error_close_iid_key:
+ RegCloseKey(iid_key);
+ }
+
+error_close_interface_key:
+ RegCloseKey(interface_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * unregister_interfaces
+ */
+static HRESULT unregister_interfaces(struct regsvr_interface const *list) {
+ LONG res = ERROR_SUCCESS;
+ HKEY interface_key;
+
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
+ KEY_READ | KEY_WRITE, &interface_key);
+ if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->iid; ++list) {
+ WCHAR buf[39];
+
+ StringFromGUID2(list->iid, buf, 39);
+ res = recursive_delete_keyW(interface_key, buf);
+ }
+
+ RegCloseKey(interface_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * register_coclasses
+ */
+static HRESULT register_coclasses(struct regsvr_coclass const *list) {
+ LONG res = ERROR_SUCCESS;
+ HKEY coclass_key;
+
+ res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+ WCHAR buf[39];
+ HKEY clsid_key;
+
+ StringFromGUID2(list->clsid, buf, 39);
+ res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+ if (list->name) {
+ res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)(list->name),
+ strlen(list->name) + 1);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->iph32) {
+ HKEY iph32_key;
+
+ res = RegCreateKeyExW(clsid_key, iph32_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL,
+ &iph32_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+ res = RegSetValueExA(iph32_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)list->iph32,
+ lstrlenA(list->iph32) + 1);
+ RegCloseKey(iph32_key);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->ips) {
+ res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->ips32) {
+ HKEY ips32_key;
+
+ res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL,
+ &ips32_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+ res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)list->ips32,
+ lstrlenA(list->ips32) + 1);
+ if (res == ERROR_SUCCESS && list->ips32_tmodel)
+ res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
+ (CONST BYTE*)list->ips32_tmodel,
+ strlen(list->ips32_tmodel) + 1);
+ RegCloseKey(ips32_key);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->progid) {
+ res = register_key_defvalueA(clsid_key, progid_keyname,
+ list->progid);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+ res = register_progid(buf, list->progid, NULL,
+ list->name, list->progid_extra);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->viprogid) {
+ res = register_key_defvalueA(clsid_key, viprogid_keyname,
+ list->viprogid);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+ res = register_progid(buf, list->viprogid, list->progid,
+ list->name, list->progid_extra);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ error_close_clsid_key:
+ RegCloseKey(clsid_key);
+ }
+
+error_close_coclass_key:
+ RegCloseKey(coclass_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * unregister_coclasses
+ */
+static HRESULT unregister_coclasses(struct regsvr_coclass const *list) {
+ LONG res = ERROR_SUCCESS;
+ HKEY coclass_key;
+
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
+ KEY_READ | KEY_WRITE, &coclass_key);
+ if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+ WCHAR buf[39];
+
+ StringFromGUID2(list->clsid, buf, 39);
+ res = recursive_delete_keyW(coclass_key, buf);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+ if (list->progid) {
+ res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+ }
+
+ if (list->viprogid) {
+ res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+ }
+ }
+
+error_close_coclass_key:
+ RegCloseKey(coclass_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * regsvr_key_guid
+ */
+static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) {
+ WCHAR buf[39];
+
+ StringFromGUID2(guid, buf, 39);
+ return register_key_defvalueW(base, name, buf);
+}
+
+/***********************************************************************
+ * regsvr_key_defvalueW
+ */
+static LONG register_key_defvalueW(
+ HKEY base,
+ WCHAR const *name,
+ WCHAR const *value) {
+ LONG res;
+ HKEY key;
+
+ res = RegCreateKeyExW(base, name, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &key, NULL);
+ if (res != ERROR_SUCCESS) return res;
+ res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
+ (lstrlenW(value) + 1) * sizeof(WCHAR));
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * regsvr_key_defvalueA
+ */
+static LONG register_key_defvalueA(
+ HKEY base,
+ WCHAR const *name,
+ char const *value) {
+ LONG res;
+ HKEY key;
+
+ res = RegCreateKeyExW(base, name, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &key, NULL);
+ if (res != ERROR_SUCCESS) return res;
+ res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
+ lstrlenA(value) + 1);
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * regsvr_progid
+ */
+static LONG register_progid(
+ WCHAR const *clsid,
+ char const *progid,
+ char const *curver_progid,
+ char const *name,
+ char const *extra) {
+ LONG res;
+ HKEY progid_key;
+
+ res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
+ NULL, 0, KEY_READ | KEY_WRITE, NULL,
+ &progid_key, NULL);
+ if (res != ERROR_SUCCESS) return res;
+
+ if (name) {
+ res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)name, strlen(name) + 1);
+ if (res != ERROR_SUCCESS) goto error_close_progid_key;
+ }
+
+ if (clsid) {
+ res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
+ if (res != ERROR_SUCCESS) goto error_close_progid_key;
+ }
+
+ if (curver_progid) {
+ res = register_key_defvalueA(progid_key, curver_keyname,
+ curver_progid);
+ if (res != ERROR_SUCCESS) goto error_close_progid_key;
+ }
+
+ if (extra) {
+ HKEY extra_key;
+
+ res = RegCreateKeyExA(progid_key, extra, 0,
+ NULL, 0, KEY_READ | KEY_WRITE, NULL,
+ &extra_key, NULL);
+ if (res == ERROR_SUCCESS)
+ RegCloseKey(extra_key);
+ }
+
+error_close_progid_key:
+ RegCloseKey(progid_key);
+ return res;
+}
+
+/***********************************************************************
+ * recursive_delete_key
+ */
+static LONG recursive_delete_key(HKEY key) {
+ LONG res;
+ WCHAR subkey_name[MAX_PATH];
+ DWORD cName;
+ HKEY subkey;
+
+ for (;;) {
+ cName = sizeof(subkey_name) / sizeof(WCHAR);
+ res = RegEnumKeyExW(key, 0, subkey_name, &cName,
+ NULL, NULL, NULL, NULL);
+ if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
+ res = ERROR_SUCCESS; /* presumably we're done enumerating */
+ break;
+ }
+ res = RegOpenKeyExW(key, subkey_name, 0,
+ KEY_READ | KEY_WRITE, &subkey);
+ if (res == ERROR_FILE_NOT_FOUND) continue;
+ if (res != ERROR_SUCCESS) break;
+
+ res = recursive_delete_key(subkey);
+ RegCloseKey(subkey);
+ if (res != ERROR_SUCCESS) break;
+ }
+
+ if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
+ return res;
+}
+
+/***********************************************************************
+ * recursive_delete_keyA
+ */
+static LONG recursive_delete_keyA(HKEY base, char const *name) {
+ LONG res;
+ HKEY key;
+
+ res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
+ if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
+ if (res != ERROR_SUCCESS) return res;
+ res = recursive_delete_key(key);
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * recursive_delete_keyW
+ */
+static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) {
+ LONG res;
+ HKEY key;
+
+ res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
+ if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
+ if (res != ERROR_SUCCESS) return res;
+ res = recursive_delete_key(key);
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * coclass list
+ */
+static struct regsvr_coclass const coclass_list[] = {
+ {
+ &CLSID_IMsiServer,
+ "Msi install server",
+ "ole32.dll",
+ NULL,
+ "msi.dll",
+ "Apartment",
+ "WindowsInstaller.Installer",
+ NULL
+ },
+ {
+ &CLSID_IMsiServerMessage,
+ "Wine Installer Message RPC",
+ NULL,
+ NULL,
+ "msi.dll",
+ NULL,
+ "WindowsInstaller.Message",
+ NULL
+ },
+ {
+ &CLSID_IMsiServerX1,
+ "Msi install server",
+ "ole32.dll",
+ NULL,
+ "msi.dll",
+ "Apartment",
+ "WindowsInstaller.Installer",
+ NULL
+ },
+ {
+ &CLSID_IMsiServerX2,
+ "Msi install server",
+ "ole32.dll",
+ NULL,
+ "msi.dll",
+ "Apartment",
+ "WindowsInstaller.Installer",
+ NULL
+ },
+ {
+ &CLSID_IMsiServerX3,
+ "Msi install server",
+ "ole32.dll",
+ NULL,
+ "msi.dll",
+ "Apartment",
+ "WindowsInstaller.Installer",
+ NULL
+ },
+ { NULL } /* list terminator */
+};
+
+/***********************************************************************
+ * interface list
+ */
+/*
+ * we should declare: (@see ole32/regsvr.c for examples)
+ [-HKEY_CLASSES_ROOT\Interface\{000C101C-0000-0000-C000-000000000046}]
+ [-HKEY_CLASSES_ROOT\Interface\{000C101D-0000-0000-C000-000000000046}]
+ [-HKEY_CLASSES_ROOT\Interface\{000C1025-0000-0000-C000-000000000046}]
+ [-HKEY_CLASSES_ROOT\Interface\{000C1033-0000-0000-C000-000000000046}]
+ [-HKEY_CLASSES_ROOT\Interface\{000C1090-0000-0000-C000-000000000046}]
+ [-HKEY_CLASSES_ROOT\Interface\{000C1093-0000-0000-C000-000000000046}]
+ [-HKEY_CLASSES_ROOT\Interface\{000C1095-0000-0000-C000-000000000046}]
+ [-HKEY_CLASSES_ROOT\Interface\{000C109A-0000-0000-C000-000000000046}]
+ [-HKEY_CLASSES_ROOT\Interface\{000C109B-0000-0000-C000-000000000046}]
+ [-HKEY_CLASSES_ROOT\Interface\{000C109C-0000-0000-C000-000000000046}]
+ [-HKEY_CLASSES_ROOT\Interface\{000C109D-0000-0000-C000-000000000046}]
+ [-HKEY_CLASSES_ROOT\Interface\{000C109E-0000-0000-C000-000000000046}]
+ [-HKEY_CLASSES_ROOT\Interface\{000C109F-0000-0000-C000-000000000046}]
+*/
+static struct regsvr_interface const interface_list[] = {
+ { NULL } /* list terminator */
+};
+
+/***********************************************************************
+ * DllRegisterServer
+ */
+HRESULT WINAPI MSI_DllRegisterServer(void) {
+ HRESULT hr;
+
+ TRACE("\n");
+
+ hr = register_coclasses(coclass_list);
+ if (SUCCEEDED(hr))
+ hr = register_interfaces(interface_list);
+ return hr;
+}
+
+/***********************************************************************
+ * DllUnregisterServer
+ */
+HRESULT WINAPI MSI_DllUnregisterServer(void) {
+ HRESULT hr;
+
+ TRACE("\n");
+
+ hr = unregister_coclasses(coclass_list);
+ if (SUCCEEDED(hr))
+ hr = unregister_interfaces(interface_list);
+ return hr;
+}
reactos/lib/msi
diff -N select.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ select.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,290 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002-2004 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+
+#include "query.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+
+/* below is the query interface to a table */
+
+typedef struct tagMSISELECTVIEW
+{
+ MSIVIEW view;
+ MSIDATABASE *db;
+ MSIVIEW *table;
+ UINT num_cols;
+ UINT max_cols;
+ UINT cols[1];
+} MSISELECTVIEW;
+
+static UINT SELECT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
+{
+ MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
+
+ TRACE("%p %d %d %p\n", sv, row, col, val );
+
+ if( !sv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( (col==0) || (col>sv->num_cols) )
+ return ERROR_FUNCTION_FAILED;
+
+ col = sv->cols[ col - 1 ];
+
+ return sv->table->ops->fetch_int( sv->table, row, col, val );
+}
+
+static UINT SELECT_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm)
+{
+ MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
+
+ TRACE("%p %d %d %p\n", sv, row, col, stm );
+
+ if( !sv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( (col==0) || (col>sv->num_cols) )
+ return ERROR_FUNCTION_FAILED;
+
+ col = sv->cols[ col - 1 ];
+
+ return sv->table->ops->fetch_stream( sv->table, row, col, stm );
+}
+
+static UINT SELECT_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
+{
+ MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
+
+ TRACE("%p %d %d %04x\n", sv, row, col, val );
+
+ if( !sv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( (col==0) || (col>sv->num_cols) )
+ return ERROR_FUNCTION_FAILED;
+
+ col = sv->cols[ col - 1 ];
+
+ return sv->table->ops->set_int( sv->table, row, col, val );
+}
+
+static UINT SELECT_insert_row( struct tagMSIVIEW *view, UINT *num )
+{
+ MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
+
+ TRACE("%p %p\n", sv, num );
+
+ if( !sv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ return sv->table->ops->insert_row( sv->table, num );
+}
+
+static UINT SELECT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
+{
+ MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
+
+ TRACE("%p %p\n", sv, record);
+
+ if( !sv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ return sv->table->ops->execute( sv->table, record );
+}
+
+static UINT SELECT_close( struct tagMSIVIEW *view )
+{
+ MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
+
+ TRACE("%p\n", sv );
+
+ if( !sv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ return sv->table->ops->close( sv->table );
+}
+
+static UINT SELECT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
+{
+ MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
+
+ TRACE("%p %p %p\n", sv, rows, cols );
+
+ if( !sv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( cols )
+ *cols = sv->num_cols;
+
+ return sv->table->ops->get_dimensions( sv->table, rows, NULL );
+}
+
+static UINT SELECT_get_column_info( struct tagMSIVIEW *view,
+ UINT n, LPWSTR *name, UINT *type )
+{
+ MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
+
+ TRACE("%p %d %p %p\n", sv, n, name, type );
+
+ if( !sv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( (n==0) || (n>sv->num_cols) )
+ return ERROR_FUNCTION_FAILED;
+
+ n = sv->cols[ n - 1 ];
+
+ return sv->table->ops->get_column_info( sv->table, n, name, type );
+}
+
+static UINT SELECT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
+{
+ MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
+
+ TRACE("%p %d %ld\n", sv, eModifyMode, hrec );
+
+ if( !sv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ return sv->table->ops->modify( sv->table, eModifyMode, hrec );
+}
+
+static UINT SELECT_delete( struct tagMSIVIEW *view )
+{
+ MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
+
+ TRACE("%p\n", sv );
+
+ if( sv->table )
+ sv->table->ops->delete( sv->table );
+
+ HeapFree( GetProcessHeap(), 0, sv );
+
+ return ERROR_SUCCESS;
+}
+
+
+MSIVIEWOPS select_ops =
+{
+ SELECT_fetch_int,
+ SELECT_fetch_stream,
+ SELECT_set_int,
+ SELECT_insert_row,
+ SELECT_execute,
+ SELECT_close,
+ SELECT_get_dimensions,
+ SELECT_get_column_info,
+ SELECT_modify,
+ SELECT_delete
+};
+
+static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPWSTR name )
+{
+ UINT r, n=0;
+ MSIVIEW *table;
+
+ TRACE("%p adding %s\n", sv, debugstr_w( name ) );
+
+ if( sv->view.ops != &select_ops )
+ return ERROR_FUNCTION_FAILED;
+
+ table = sv->table;
+ if( !table )
+ return ERROR_FUNCTION_FAILED;
+ if( !table->ops->get_dimensions )
+ return ERROR_FUNCTION_FAILED;
+ if( !table->ops->get_column_info )
+ return ERROR_FUNCTION_FAILED;
+
+ if( sv->num_cols >= sv->max_cols )
+ return ERROR_FUNCTION_FAILED;
+
+ r = VIEW_find_column( table, name, &n );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ sv->cols[sv->num_cols] = n;
+ TRACE("Translating column %s from %d -> %d\n",
+ debugstr_w( name ), sv->num_cols, n);
+
+ sv->num_cols++;
+
+ return ERROR_SUCCESS;
+}
+
+UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
+ string_list *columns )
+{
+ MSISELECTVIEW *sv = NULL;
+ UINT count = 0, r;
+
+ TRACE("%p\n", sv );
+
+ r = table->ops->get_dimensions( table, NULL, &count );
+ if( r != ERROR_SUCCESS )
+ {
+ ERR("can't get table dimensions\n");
+ return r;
+ }
+
+ sv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof *sv + count*sizeof (UINT) );
+ if( !sv )
+ return ERROR_FUNCTION_FAILED;
+
+ /* fill the structure */
+ sv->view.ops = &select_ops;
+ sv->db = db;
+ sv->table = table;
+ sv->num_cols = 0;
+ sv->max_cols = count;
+
+ while( columns )
+ {
+ r = SELECT_AddColumn( sv, columns->string );
+ if( r )
+ break;
+ columns = columns->next;
+ }
+
+ if( r != ERROR_SUCCESS )
+ {
+ sv->view.ops->delete( &sv->view );
+ sv = NULL;
+ }
+
+ *view = &sv->view;
+
+ return r;
+}
reactos/lib/msi
diff -N sql.y
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sql.y 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,828 @@
+%{
+
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002-2004 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "query.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+#define YYLEX_PARAM info
+#define YYPARSE_PARAM info
+
+extern int SQL_error(const char *str);
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+typedef struct tag_SQL_input
+{
+ MSIDATABASE *db;
+ LPCWSTR command;
+ DWORD n, len;
+ MSIVIEW **view; /* view structure for the resulting query */
+} SQL_input;
+
+static LPWSTR SQL_getstring( struct sql_str *str );
+static INT SQL_getint( SQL_input *sql );
+static int SQL_lex( void *SQL_lval, SQL_input *info);
+
+static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
+ string_list *columns );
+static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in,
+ string_list *columns );
+
+static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
+ string_list *keys);
+
+static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r );
+static struct expr * EXPR_column( LPWSTR );
+static struct expr * EXPR_ival( struct sql_str *);
+static struct expr * EXPR_sval( struct sql_str *);
+static struct expr * EXPR_wildcard();
+
+%}
+
+%pure-parser
+
+%union
+{
+ struct sql_str str;
+ LPWSTR string;
+ string_list *column_list;
+ value_list *val_list;
+ MSIVIEW *query;
+ struct expr *expr;
+ USHORT column_type;
+ create_col_info *column_info;
+ column_assignment update_col_info;
+}
+
+%token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_AND TK_AS TK_ASC
+%token TK_BEFORE TK_BEGIN TK_BETWEEN TK_BITAND TK_BITNOT TK_BITOR TK_BY
+%token TK_CASCADE TK_CASE TK_CHAR TK_CHECK TK_CLUSTER TK_COLLATE TK_COLUMN
+%token TK_COMMA TK_COMMENT TK_COMMIT TK_CONCAT TK_CONFLICT
+%token TK_CONSTRAINT TK_COPY TK_CREATE
+%token TK_DEFAULT TK_DEFERRABLE TK_DEFERRED TK_DELETE TK_DELIMITERS TK_DESC
+%token TK_DISTINCT TK_DOT TK_DROP TK_EACH
+%token TK_ELSE TK_END TK_END_OF_FILE TK_EQ TK_EXCEPT TK_EXPLAIN
+%token TK_FAIL TK_FLOAT TK_FOR TK_FOREIGN TK_FROM TK_FUNCTION
+%token TK_GE TK_GLOB TK_GROUP TK_GT
+%token TK_HAVING TK_HOLD
+%token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY
+%token <str> TK_ID
+%token TK_INSERT TK_INSTEAD TK_INT
+%token <str> TK_INTEGER
+%token TK_INTERSECT TK_INTO TK_IS
+%token TK_ISNULL
+%token TK_JOIN TK_JOIN_KW
+%token TK_KEY
+%token TK_LE TK_LIKE TK_LIMIT TK_LONG TK_LONGCHAR TK_LP TK_LSHIFT TK_LT
+%token TK_LOCALIZABLE
+%token TK_MATCH TK_MINUS
+%token TK_NE TK_NOT TK_NOTNULL TK_NULL
+%token TK_OBJECT TK_OF TK_OFFSET TK_ON TK_OR TK_ORACLE_OUTER_JOIN TK_ORDER
+%token TK_PLUS TK_PRAGMA TK_PRIMARY
+%token TK_RAISE TK_REFERENCES TK_REM TK_REPLACE TK_RESTRICT TK_ROLLBACK
+%token TK_ROW TK_RP TK_RSHIFT
+%token TK_SELECT TK_SEMI TK_SET TK_SHORT TK_SLASH TK_SPACE TK_STAR TK_STATEMENT
+%token <str> TK_STRING
+%token TK_TABLE TK_TEMP TK_THEN TK_TRANSACTION TK_TRIGGER
+%token TK_UMINUS TK_UNCLOSED_STRING TK_UNION TK_UNIQUE
+%token TK_UPDATE TK_UPLUS TK_USING
+%token TK_VACUUM TK_VALUES TK_VIEW
+%token TK_WHEN TK_WHERE TK_WILDCARD
+
+/*
+ * These are extra tokens used by the lexer but never seen by the
+ * parser. We put them in a rule so that the parser generator will
+ * add them to the parse.h output file.
+ *
+ */
+%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
+ COLUMN AGG_FUNCTION.
+
+%type <string> column table string_or_id
+%type <column_list> selcollist
+%type <query> from unorderedsel oneselect onequery onecreate oneinsert oneupdate
+%type <expr> expr val column_val const_val
+%type <column_type> column_type data_type data_type_l data_count
+%type <column_info> column_def table_def
+%type <val_list> constlist
+%type <update_col_info> column_assignment update_assign_list
+
+%%
+
+onequery:
+ oneselect
+ {
+ SQL_input* sql = (SQL_input*) info;
+ *sql->view = $1;
+ }
+ | onecreate
+ {
+ SQL_input* sql = (SQL_input*) info;
+ *sql->view = $1;
+ }
+ | oneinsert
+ {
+ SQL_input* sql = (SQL_input*) info;
+ *sql->view = $1;
+ }
+ | oneupdate
+ {
+ SQL_input* sql = (SQL_input*) info;
+ *sql->view = $1;
+ }
+ ;
+
+oneinsert:
+ TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP
+ {
+ SQL_input *sql = (SQL_input*) info;
+ MSIVIEW *insert = NULL;
+
+ INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE );
+ $$ = insert;
+ }
+ | TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMP
+ {
+ SQL_input *sql = (SQL_input*) info;
+ MSIVIEW *insert = NULL;
+
+ INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE );
+ $$ = insert;
+ }
+ ;
+
+onecreate:
+ TK_CREATE TK_TABLE table TK_LP table_def TK_RP
+ {
+ SQL_input* sql = (SQL_input*) info;
+ MSIVIEW *create = NULL;
+
+ if( !$5 )
+ YYABORT;
+ CREATE_CreateView( sql->db, &create, $3, $5, FALSE );
+ $$ = create;
+ }
+ | TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD
+ {
+ SQL_input* sql = (SQL_input*) info;
+ MSIVIEW *create = NULL;
+
+ if( !$5 )
+ YYABORT;
+ CREATE_CreateView( sql->db, &create, $3, $5, TRUE );
+ $$ = create;
+ }
+ ;
+
+oneupdate:
+ TK_UPDATE table TK_SET update_assign_list TK_WHERE expr
+ {
+ SQL_input* sql = (SQL_input*) info;
+ MSIVIEW *update = NULL;
+
+ UPDATE_CreateView( sql->db, &update, $2, &$4, $6 );
+ $$ = update;
+ }
+ ;
+
+table_def:
+ column_def TK_PRIMARY TK_KEY selcollist
+ {
+ if( SQL_MarkPrimaryKeys( $1, $4 ) )
+ $$ = $1;
+ else
+ $$ = NULL;
+ }
+ ;
+
+column_def:
+ column_def TK_COMMA column column_type
+ {
+ create_col_info *ci;
+
+ for( ci = $1; ci->next; ci = ci->next )
+ ;
+
+ ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
+ if( !ci->next )
+ {
+ /* FIXME: free $1 */
+ YYABORT;
+ }
+ ci->next->colname = $3;
+ ci->next->type = $4;
+ ci->next->next = NULL;
+
+ $$ = $1;
+ }
+ | column column_type
+ {
+ $$ = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
+ if( ! $$ )
+ YYABORT;
+ $$->colname = $1;
+ $$->type = $2;
+ $$->next = NULL;
+ }
+ ;
+
+column_type:
+ data_type_l
+ {
+ $$ = $1 | MSITYPE_VALID;
+ }
+ | data_type_l TK_LOCALIZABLE
+ {
+ FIXME("LOCALIZABLE ignored\n");
+ $$ = $1 | MSITYPE_VALID;
+ }
+ ;
+
+data_type_l:
+ data_type
+ {
+ $$ |= MSITYPE_NULLABLE;
+ }
+ | data_type TK_NOT TK_NULL
+ {
+ $$ = $1;
+ }
+ ;
+
+data_type:
+ TK_CHAR
+ {
+ $$ = MSITYPE_STRING | 1;
+ }
+ | TK_CHAR TK_LP data_count TK_RP
+ {
+ $$ = MSITYPE_STRING | 0x400 | $3;
+ }
+ | TK_LONGCHAR
+ {
+ $$ = 2;
+ }
+ | TK_SHORT
+ {
+ $$ = 2;
+ }
+ | TK_INT
+ {
+ $$ = 2;
+ }
+ | TK_LONG
+ {
+ $$ = 4;
+ }
+ | TK_OBJECT
+ {
+ $$ = 0;
+ }
+ ;
+
+data_count:
+ TK_INTEGER
+ {
+ SQL_input* sql = (SQL_input*) info;
+ int val = SQL_getint(sql);
+ if( ( val > 255 ) || ( val < 0 ) )
+ YYABORT;
+ $$ = val;
+ }
+ ;
+
+oneselect:
+ unorderedsel TK_ORDER TK_BY selcollist
+ {
+ SQL_input* sql = (SQL_input*) info;
+
+ if( !$1 )
+ YYABORT;
+ if( $4 )
+ $$ = do_order_by( sql->db, $1, $4 );
+ else
+ $$ = $1;
+ }
+ | unorderedsel
+ ;
+
+unorderedsel:
+ TK_SELECT selcollist from
+ {
+ SQL_input* sql = (SQL_input*) info;
+ if( !$3 )
+ YYABORT;
+ if( $2 )
+ {
+ $$ = do_one_select( sql->db, $3, $2 );
+ if( !$$ )
+ YYABORT;
+ }
+ else
+ $$ = $3;
+ }
+ | TK_SELECT TK_DISTINCT selcollist from
+ {
+ SQL_input* sql = (SQL_input*) info;
+ MSIVIEW *view = $4;
+
+ if( !view )
+ YYABORT;
+ if( $3 )
+ {
+ view = do_one_select( sql->db, view, $3 );
+ if( !view )
+ YYABORT;
+ }
+ DISTINCT_CreateView( sql->db, & $$, view );
+ }
+ ;
+
+selcollist:
+ column
+ {
+ string_list *list;
+
+ list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
+ if( !list )
+ YYABORT;
+ list->string = $1;
+ list->next = NULL;
+
+ $$ = list;
+ TRACE("Collist %s\n",debugstr_w($$->string));
+ }
+ | column TK_COMMA selcollist
+ {
+ string_list *list;
+
+ list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
+ if( !list )
+ YYABORT;
+ list->string = $1;
+ list->next = $3;
+
+ $$ = list;
+ TRACE("From table: %s\n",debugstr_w($$->string));
+ }
+ | TK_STAR
+ {
+ $$ = NULL;
+ }
+ ;
+
+from:
+ TK_FROM table
+ {
+ SQL_input* sql = (SQL_input*) info;
+ UINT r;
+
+ $$ = NULL;
+ TRACE("From table: %s\n",debugstr_w($2));
+ r = TABLE_CreateView( sql->db, $2, & $$ );
+ if( r != ERROR_SUCCESS )
+ YYABORT;
+ }
+ | TK_FROM table TK_WHERE expr
+ {
+ SQL_input* sql = (SQL_input*) info;
+ MSIVIEW *view = NULL;
+ UINT r;
+
+ $$ = NULL;
+ TRACE("From table: %s\n",debugstr_w($2));
+ r = TABLE_CreateView( sql->db, $2, &view );
+ if( r != ERROR_SUCCESS )
+ YYABORT;
+ r = WHERE_CreateView( sql->db, &view, view, $4 );
+ if( r != ERROR_SUCCESS )
+ YYABORT;
+ $$ = view;
+ }
+ ;
+
+expr:
+ TK_LP expr TK_RP
+ {
+ $$ = $2;
+ }
+ | column_val TK_EQ column_val
+ {
+ $$ = EXPR_complex( $1, OP_EQ, $3 );
+ }
+ | expr TK_AND expr
+ {
+ $$ = EXPR_complex( $1, OP_AND, $3 );
+ }
+ | expr TK_OR expr
+ {
+ $$ = EXPR_complex( $1, OP_OR, $3 );
+ }
+ | column_val TK_EQ val
+ {
+ $$ = EXPR_complex( $1, OP_EQ, $3 );
+ }
+ | column_val TK_GT val
+ {
+ $$ = EXPR_complex( $1, OP_GT, $3 );
+ }
+ | column_val TK_LT val
+ {
+ $$ = EXPR_complex( $1, OP_LT, $3 );
+ }
+ | column_val TK_LE val
+ {
+ $$ = EXPR_complex( $1, OP_LE, $3 );
+ }
+ | column_val TK_GE val
+ {
+ $$ = EXPR_complex( $1, OP_GE, $3 );
+ }
+ | column_val TK_NE val
+ {
+ $$ = EXPR_complex( $1, OP_NE, $3 );
+ }
+ | column_val TK_IS TK_NULL
+ {
+ $$ = EXPR_complex( $1, OP_ISNULL, NULL );
+ }
+ | column_val TK_IS TK_NOT TK_NULL
+ {
+ $$ = EXPR_complex( $1, OP_NOTNULL, NULL );
+ }
+ ;
+
+val:
+ column_val
+ | const_val
+ ;
+
+constlist:
+ const_val
+ {
+ value_list *vals;
+
+ vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
+ if( vals )
+ {
+ vals->val = $1;
+ vals->next = NULL;
+ }
+ $$ = vals;
+ }
+ | constlist TK_COMMA const_val
+ {
+ value_list *vals;
+
+ vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
+ if( vals )
+ {
+ vals->val = $3;
+ vals->next = NULL;
+ }
+ $1->next = vals;
+ $$ = $1;
+ }
+ ;
+
+update_assign_list:
+ column_assignment
+ | column_assignment TK_COMMA update_assign_list
+ {
+ $1.col_list->next = $3.col_list;
+ $1.val_list->next = $3.val_list;
+ $$ = $1;
+ }
+ ;
+
+column_assignment:
+ column TK_EQ const_val
+ {
+ $$.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.col_list );
+ if( !$$.col_list )
+ YYABORT;
+ $$.col_list->string = $1;
+ $$.col_list->next = NULL;
+ $$.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.val_list );
+ if( !$$.val_list )
+ YYABORT;
+ $$.val_list->val = $3;
+ $$.val_list->next = 0;
+ }
+ ;
+
+const_val:
+ TK_INTEGER
+ {
+ $$ = EXPR_ival( &$1 );
+ }
+ | TK_STRING
+ {
+ $$ = EXPR_sval( &$1 );
+ }
+ | TK_WILDCARD
+ {
+ $$ = EXPR_wildcard();
+ }
+ ;
+
+column_val:
+ column
+ {
+ $$ = EXPR_column( $1 );
+ }
+ ;
+
+column:
+ table TK_DOT string_or_id
+ {
+ $$ = $3; /* FIXME */
+ }
+ | string_or_id
+ {
+ $$ = $1;
+ }
+ ;
+
+table:
+ string_or_id
+ {
+ $$ = $1;
+ }
+ ;
+
+string_or_id:
+ TK_ID
+ {
+ $$ = SQL_getstring( &$1 );
+ }
+ | TK_STRING
+ {
+ $$ = SQL_getstring( &$1 );
+ }
+ ;
+
+%%
+
+int SQL_lex( void *SQL_lval, SQL_input *sql)
+{
+ int token;
+ struct sql_str * str = SQL_lval;
+
+ do
+ {
+ sql->n += sql->len;
+ if( ! sql->command[sql->n] )
+ return 0; /* end of input */
+
+ TRACE("string : %s\n", debugstr_w(&sql->command[sql->n]));
+ sql->len = sqliteGetToken( &sql->command[sql->n], &token );
+ if( sql->len==0 )
+ break;
+ str->data = &sql->command[sql->n];
+ str->len = sql->len;
+ }
+ while( token == TK_SPACE );
+
+ TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len));
+
+ return token;
+}
+
+LPWSTR SQL_getstring( struct sql_str *strdata)
+{
+ LPCWSTR p = strdata->data;
+ UINT len = strdata->len;
+ LPWSTR str;
+
+ /* if there's quotes, remove them */
+ if( ( (p[0]=='`') && (p[len-1]=='`') ) ||
+ ( (p[0]=='\'') && (p[len-1]=='\'') ) )
+ {
+ p++;
+ len -= 2;
+ }
+ str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
+ if(!str )
+ return str;
+ memcpy(str, p, len*sizeof(WCHAR) );
+ str[len]=0;
+
+ return str;
+}
+
+INT SQL_getint( SQL_input *sql )
+{
+ LPCWSTR p = &sql->command[sql->n];
+
+ return atoiW( p );
+}
+
+int SQL_error(const char *str)
+{
+ return 0;
+}
+
+static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
+ string_list *columns )
+{
+ MSIVIEW *view = NULL;
+
+ SELECT_CreateView( db, &view, in, columns );
+ delete_string_list( columns );
+ if( !view )
+ ERR("Error creating select query\n");
+ return view;
+}
+
+static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in,
+ string_list *columns )
+{
+ MSIVIEW *view = NULL;
+
+ ORDER_CreateView( db, &view, in );
+ if( view )
+ {
+ string_list *x = columns;
+
+ for( x = columns; x ; x = x->next )
+ ORDER_AddColumn( view, x->string );
+ }
+ else
+ ERR("Error creating select query\n");
+ delete_string_list( columns );
+ return view;
+}
+
+static struct expr * EXPR_wildcard()
+{
+ struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+ if( e )
+ {
+ e->type = EXPR_WILDCARD;
+ }
+ return e;
+}
+
+static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
+{
+ struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+ if( e )
+ {
+ e->type = EXPR_COMPLEX;
+ e->u.expr.left = l;
+ e->u.expr.op = op;
+ e->u.expr.right = r;
+ }
+ return e;
+}
+
+static struct expr * EXPR_column( LPWSTR str )
+{
+ struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+ if( e )
+ {
+ e->type = EXPR_COLUMN;
+ e->u.sval = str;
+ }
+ return e;
+}
+
+static struct expr * EXPR_ival( struct sql_str *str )
+{
+ struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+ if( e )
+ {
+ e->type = EXPR_IVAL;
+ e->u.ival = atoiW( str->data );
+ }
+ return e;
+}
+
+static struct expr * EXPR_sval( struct sql_str *str )
+{
+ struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
+ if( e )
+ {
+ e->type = EXPR_SVAL;
+ e->u.sval = SQL_getstring( str );
+ }
+ return e;
+}
+
+void delete_expr( struct expr *e )
+{
+ if( !e )
+ return;
+ if( e->type == EXPR_COMPLEX )
+ {
+ delete_expr( e->u.expr.left );
+ delete_expr( e->u.expr.right );
+ }
+ else if( e->type == EXPR_UTF8 )
+ HeapFree( GetProcessHeap(), 0, e->u.utf8 );
+ else if( e->type == EXPR_SVAL )
+ HeapFree( GetProcessHeap(), 0, e->u.sval );
+ HeapFree( GetProcessHeap(), 0, e );
+}
+
+void delete_string_list( string_list *sl )
+{
+ while( sl )
+ {
+ string_list *t = sl->next;
+ HeapFree( GetProcessHeap(), 0, sl->string );
+ HeapFree( GetProcessHeap(), 0, sl );
+ sl = t;
+ }
+}
+
+void delete_value_list( value_list *vl )
+{
+ while( vl )
+ {
+ value_list *t = vl->next;
+ delete_expr( vl->val );
+ HeapFree( GetProcessHeap(), 0, vl );
+ vl = t;
+ }
+}
+
+static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
+ string_list *keys )
+{
+ string_list *k;
+ BOOL found = TRUE;
+
+ for( k = keys; k && found; k = k->next )
+ {
+ create_col_info *c;
+
+ found = FALSE;
+ for( c = cols; c && !found; c = c->next )
+ {
+ if( lstrcmpW( k->string, c->colname ) )
+ continue;
+ c->type |= MSITYPE_KEY;
+ found = TRUE;
+ }
+ }
+
+ return found;
+}
+
+UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )
+{
+ SQL_input sql;
+ int r;
+
+ *phview = NULL;
+
+ sql.db = db;
+ sql.command = command;
+ sql.n = 0;
+ sql.len = 0;
+ sql.view = phview;
+
+ r = SQL_parse(&sql);
+
+ TRACE("Parse returned %d\n", r);
+ if( r )
+ {
+ if( *sql.view )
+ (*sql.view)->ops->delete( *sql.view );
+ *sql.view = NULL;
+ return ERROR_BAD_QUERY_SYNTAX;
+ }
+
+ return ERROR_SUCCESS;
+}
reactos/lib/msi
diff -N string.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ string.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,459 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002-2004, Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+#include <assert.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+
+#include "query.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+typedef struct _msistring
+{
+ UINT hash;
+ UINT refcount;
+ LPWSTR str;
+} msistring;
+
+struct string_table
+{
+ UINT maxcount; /* the number of strings */
+ UINT freeslot;
+ UINT codepage;
+ msistring *strings; /* an array of strings (in the tree) */
+};
+
+static UINT msistring_makehash( const WCHAR *str )
+{
+ UINT hash = 0;
+
+ if (str==NULL)
+ return hash;
+
+ while( *str )
+ {
+ hash ^= *str++;
+ hash *= 53;
+ hash = (hash<<5) | (hash>>27);
+ }
+ return hash;
+}
+
+string_table *msi_init_stringtable( int entries, UINT codepage )
+{
+ string_table *st;
+
+ st = HeapAlloc( GetProcessHeap(), 0, sizeof (string_table) );
+ if( !st )
+ return NULL;
+ st->strings = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+ sizeof (msistring) * entries );
+ if( !st )
+ {
+ HeapFree( GetProcessHeap(), 0, st );
+ return NULL;
+ }
+ if( entries < 1 )
+ entries = 1;
+ st->maxcount = entries;
+ st->freeslot = 1;
+ st->codepage = codepage;
+
+ return st;
+}
+
+VOID msi_destroy_stringtable( string_table *st )
+{
+ UINT i;
+
+ for( i=0; i<st->maxcount; i++ )
+ {
+ if( st->strings[i].refcount )
+ HeapFree( GetProcessHeap(), 0, st->strings[i].str );
+ }
+ HeapFree( GetProcessHeap(), 0, st->strings );
+ HeapFree( GetProcessHeap(), 0, st );
+}
+
+static int st_find_free_entry( string_table *st )
+{
+ UINT i, sz;
+ msistring *p;
+
+ TRACE("%p\n", st);
+
+ if( st->freeslot )
+ {
+ for( i = st->freeslot; i < st->maxcount; i++ )
+ if( !st->strings[i].refcount )
+ return i;
+ }
+ for( i = 1; i < st->maxcount; i++ )
+ if( !st->strings[i].refcount )
+ return i;
+
+ /* dynamically resize */
+ sz = st->maxcount + 1 + st->maxcount/2;
+ p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+ st->strings, sz*sizeof(msistring) );
+ if( !p )
+ return -1;
+ st->strings = p;
+ st->freeslot = st->maxcount;
+ st->maxcount = sz;
+ if( st->strings[st->freeslot].refcount )
+ ERR("oops. expected freeslot to be free...\n");
+ return st->freeslot;
+}
+
+static void st_mark_entry_used( string_table *st, UINT n )
+{
+ if( n >= st->maxcount )
+ return;
+ st->freeslot = n + 1;
+}
+
+int msi_addstring( string_table *st, int n, const CHAR *data, int len, UINT refcount )
+{
+ int sz;
+
+ if( !data )
+ return 0;
+ if( !data[0] )
+ return 0;
+ if( n > 0 )
+ {
+ if( st->strings[n].refcount )
+ return -1;
+ }
+ else
+ {
+ if( ERROR_SUCCESS == msi_string2idA( st, data, &n ) )
+ {
+ st->strings[n].refcount++;
+ return n;
+ }
+ n = st_find_free_entry( st );
+ if( n < 0 )
+ return -1;
+ }
+
+ if( n < 1 )
+ {
+ ERR("invalid index adding %s (%d)\n", debugstr_a( data ), n );
+ return -1;
+ }
+
+ /* allocate a new string */
+ if( len < 0 )
+ len = strlen(data);
+ sz = MultiByteToWideChar( st->codepage, 0, data, len, NULL, 0 );
+ st->strings[n].str = HeapAlloc( GetProcessHeap(), 0, (sz+1)*sizeof(WCHAR) );
+ if( !st->strings[n].str )
+ return -1;
+ MultiByteToWideChar( st->codepage, 0, data, len, st->strings[n].str, sz );
+ st->strings[n].str[sz] = 0;
+ st->strings[n].refcount = 1;
+ st->strings[n].hash = msistring_makehash( st->strings[n].str );
+
+ st_mark_entry_used( st, n );
+
+ return n;
+}
+
+int msi_addstringW( string_table *st, int n, const WCHAR *data, int len, UINT refcount )
+{
+ /* TRACE("[%2d] = %s\n", string_no, debugstr_an(data,len) ); */
+
+ if( !data )
+ return 0;
+ if( !data[0] )
+ return 0;
+ if( n > 0 )
+ {
+ if( st->strings[n].refcount )
+ return -1;
+ }
+ else
+ {
+ if( ERROR_SUCCESS == msi_string2idW( st, data, &n ) )
+ {
+ st->strings[n].refcount++;
+ return n;
+ }
+ n = st_find_free_entry( st );
+ if( n < 0 )
+ return -1;
+ }
+
+ if( n < 1 )
+ {
+ ERR("invalid index adding %s (%d)\n", debugstr_w( data ), n );
+ return -1;
+ }
+
+ /* allocate a new string */
+ if(len<0)
+ len = strlenW(data);
+ TRACE("%s, n = %d len = %d\n", debugstr_w(data), n, len );
+
+ st->strings[n].str = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof(WCHAR) );
+ if( !st->strings[n].str )
+ return -1;
+ TRACE("%d\n",__LINE__);
+ memcpy( st->strings[n].str, data, len*sizeof(WCHAR) );
+ st->strings[n].str[len] = 0;
+ st->strings[n].refcount = 1;
+ st->strings[n].hash = msistring_makehash( st->strings[n].str );
+
+ st_mark_entry_used( st, n );
+
+ return n;
+}
+
+/* find the string identified by an id - return null if there's none */
+const WCHAR *msi_string_lookup_id( string_table *st, UINT id )
+{
+ static const WCHAR zero[] = { 0 };
+ if( id == 0 )
+ return zero;
+
+ if( id >= st->maxcount )
+ return NULL;
+
+ if( id && !st->strings[id].refcount )
+ return NULL;
+
+ return st->strings[id].str;
+}
+
+/*
+ * msi_id2stringW
+ *
+ * [in] st - pointer to the string table
+ * [in] id - id of the string to retrieve
+ * [out] buffer - destination of the string
+ * [in/out] sz - number of bytes available in the buffer on input
+ * number of bytes used on output
+ *
+ * The size includes the terminating nul character. Short buffers
+ * will be filled, but not nul terminated.
+ */
+UINT msi_id2stringW( string_table *st, UINT id, LPWSTR buffer, UINT *sz )
+{
+ UINT len;
+ const WCHAR *str;
+
+ TRACE("Finding string %d of %d\n", id, st->maxcount);
+
+ str = msi_string_lookup_id( st, id );
+ if( !str )
+ return ERROR_FUNCTION_FAILED;
+
+ len = strlenW( str ) + 1;
+
+ if( !buffer )
+ {
+ *sz = len;
+ return ERROR_SUCCESS;
+ }
+
+ if( *sz < len )
+ *sz = len;
+ memcpy( buffer, str, (*sz)*sizeof(WCHAR) );
+ *sz = len;
+
+ return ERROR_SUCCESS;
+}
+
+/*
+ * msi_id2stringA
+ *
+ * [in] st - pointer to the string table
+ * [in] id - id of the string to retrieve
+ * [out] buffer - destination of the UTF8 string
+ * [in/out] sz - number of bytes available in the buffer on input
+ * number of bytes used on output
+ *
+ * The size includes the terminating nul character. Short buffers
+ * will be filled, but not nul terminated.
+ */
+UINT msi_id2stringA( string_table *st, UINT id, LPSTR buffer, UINT *sz )
+{
+ UINT len;
+ const WCHAR *str;
+ int n;
+
+ TRACE("Finding string %d of %d\n", id, st->maxcount);
+
+ str = msi_string_lookup_id( st, id );
+ if( !str )
+ return ERROR_FUNCTION_FAILED;
+
+ len = WideCharToMultiByte( st->codepage, 0, str, -1, NULL, 0, NULL, NULL );
+
+ if( !buffer )
+ {
+ *sz = len;
+ return ERROR_SUCCESS;
+ }
+
+ if( len > *sz )
+ {
+ n = strlenW( str ) + 1;
+ while( n && (len > *sz) )
+ len = WideCharToMultiByte( st->codepage, 0,
+ str, --n, NULL, 0, NULL, NULL );
+ }
+ else
+ n = -1;
+
+ *sz = WideCharToMultiByte( st->codepage, 0, str, n, buffer, len, NULL, NULL );
+
+ return ERROR_SUCCESS;
+}
+
+/*
+ * msi_string2idW
+ *
+ * [in] st - pointer to the string table
+ * [in] str - string to find in the string table
+ * [out] id - id of the string, if found
+ */
+UINT msi_string2idW( string_table *st, LPCWSTR str, UINT *id )
+{
+ UINT hash;
+ UINT i, r = ERROR_INVALID_PARAMETER;
+
+ hash = msistring_makehash( str );
+ for( i=0; i<st->maxcount; i++ )
+ {
+ if ( (str == NULL && st->strings[i].str == NULL) ||
+ ( ( st->strings[i].hash == hash ) &&
+ !strcmpW( st->strings[i].str, str ) ))
+ {
+ r = ERROR_SUCCESS;
+ *id = i;
+ break;
+ }
+ }
+
+ return r;
+}
+
+UINT msi_string2idA( string_table *st, LPCSTR buffer, UINT *id )
+{
+ DWORD sz;
+ UINT r = ERROR_INVALID_PARAMETER;
+ LPWSTR str;
+
+ TRACE("Finding string %s in string table\n", debugstr_a(buffer) );
+
+ if( buffer[0] == 0 )
+ {
+ *id = 0;
+ return ERROR_SUCCESS;
+ }
+
+ sz = MultiByteToWideChar( st->codepage, 0, buffer, -1, NULL, 0 );
+ if( sz <= 0 )
+ return r;
+ str = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) );
+ if( !str )
+ return ERROR_NOT_ENOUGH_MEMORY;
+ MultiByteToWideChar( st->codepage, 0, buffer, -1, str, sz );
+
+ r = msi_string2idW( st, str, id );
+ if( str )
+ HeapFree( GetProcessHeap(), 0, str );
+
+ return r;
+}
+
+UINT msi_strcmp( string_table *st, UINT lval, UINT rval, UINT *res )
+{
+ const WCHAR *l_str, *r_str;
+
+ l_str = msi_string_lookup_id( st, lval );
+ if( !l_str )
+ return ERROR_INVALID_PARAMETER;
+
+ r_str = msi_string_lookup_id( st, rval );
+ if( !r_str )
+ return ERROR_INVALID_PARAMETER;
+
+ /* does this do the right thing for all UTF-8 strings? */
+ *res = strcmpW( l_str, r_str );
+
+ return ERROR_SUCCESS;
+}
+
+UINT msi_string_count( string_table *st )
+{
+ return st->maxcount;
+}
+
+UINT msi_id_refcount( string_table *st, UINT i )
+{
+ if( i >= st->maxcount )
+ return 0;
+ return st->strings[i].refcount;
+}
+
+UINT msi_string_totalsize( string_table *st, UINT *total )
+{
+ UINT size = 0, i, len;
+
+ if( st->strings[0].str || st->strings[0].refcount )
+ ERR("oops. element 0 has a string\n");
+ *total = 0;
+ for( i=1; i<st->maxcount; i++ )
+ {
+ if( st->strings[i].str )
+ {
+ TRACE("[%u] = %s\n", i, debugstr_w(st->strings[i].str));
+ len = WideCharToMultiByte( st->codepage, 0,
+ st->strings[i].str, -1, NULL, 0, NULL, NULL);
+ if( len )
+ len--;
+ size += len;
+ *total = (i+1);
+ }
+ }
+ TRACE("%u/%u strings %u bytes codepage %x\n", *total, st->maxcount, size, st->codepage );
+ return size;
+}
+
+UINT msi_string_get_codepage( string_table *st )
+{
+ return st->codepage;
+}
reactos/lib/msi
diff -N suminfo.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ suminfo.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,233 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+
+#define PRSPEC_PROPID (1)
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winnls.h"
+#include "shlwapi.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "msipriv.h"
+#include "objidl.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+static const WCHAR szSumInfo[] = { 5 ,'S','u','m','m','a','r','y',
+ 'I','n','f','o','r','m','a','t','i','o','n',0 };
+
+static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg )
+{
+ MSISUMMARYINFO *suminfo = (MSISUMMARYINFO *) arg;
+ IPropertyStorage_Release( suminfo->propstg );
+}
+
+UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase,
+ LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *phSummaryInfo)
+{
+ LPWSTR szwDatabase = NULL;
+ UINT ret;
+
+ TRACE("%ld %s %d %p\n", hDatabase, debugstr_a(szDatabase),
+ uiUpdateCount, phSummaryInfo);
+
+ if( szDatabase )
+ {
+ UINT len = MultiByteToWideChar( CP_ACP, 0, szDatabase, -1, NULL, 0 );
+ szwDatabase = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
+ if( !szwDatabase )
+ return ERROR_FUNCTION_FAILED;
+ MultiByteToWideChar( CP_ACP, 0, szDatabase, -1, szwDatabase, len );
+ }
+
+ ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, phSummaryInfo);
+
+ if( szwDatabase )
+ HeapFree( GetProcessHeap(), 0, szwDatabase );
+
+ return ret;
+}
+
+UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE hDatabase,
+ LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *phSummaryInfo)
+{
+ HRESULT r;
+ MSIHANDLE handle;
+ MSISUMMARYINFO *suminfo;
+ MSIDATABASE *db;
+ UINT ret = ERROR_SUCCESS;
+ IPropertySetStorage *psstg = NULL;
+ IPropertyStorage *ps = NULL;
+ DWORD grfMode;
+
+ TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase),
+ uiUpdateCount, phSummaryInfo);
+
+ if( !phSummaryInfo )
+ return ERROR_INVALID_PARAMETER;
+
+ if( szDatabase )
+ {
+ UINT res;
+
+ res = MSI_OpenDatabaseW(szDatabase, NULL, &db);
+ if( res != ERROR_SUCCESS )
+ return res;
+ }
+ else
+ {
+ db = msihandle2msiinfo(hDatabase, MSIHANDLETYPE_DATABASE);
+ if( !db )
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ r = IStorage_QueryInterface( db->storage,
+ &IID_IPropertySetStorage, (LPVOID)&psstg);
+ if( FAILED( r ) )
+ {
+ ERR("IStorage -> IPropertySetStorage failed\n");
+ if (db)
+ msiobj_release(&db->hdr);
+ return ERROR_FUNCTION_FAILED;
+ }
+ ERR("storage = %p propertysetstorage = %p\n", db->storage, psstg);
+
+ grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE;
+ r = IPropertySetStorage_Open( psstg, &FMTID_SummaryInformation, grfMode, &ps );
+ if( FAILED( r ) )
+ {
+ ERR("failed to get IPropertyStorage r=%08lx\n",r);
+ ret = ERROR_FUNCTION_FAILED;
+ goto end;
+ }
+
+ suminfo = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO,
+ sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
+ if( !suminfo )
+ {
+ ret = ERROR_FUNCTION_FAILED;
+ goto end;
+ }
+
+ IPropertyStorage_AddRef(ps);
+ suminfo->propstg = ps;
+ handle = alloc_msihandle( &suminfo->hdr );
+ if( handle )
+ *phSummaryInfo = handle;
+ else
+ ret = ERROR_FUNCTION_FAILED;
+ msiobj_release( &suminfo->hdr );
+
+end:
+ if( ps )
+ IPropertyStorage_Release(ps);
+ if( psstg )
+ IPropertySetStorage_Release(psstg);
+ if (db)
+ msiobj_release(&db->hdr);
+
+ return ret;
+}
+
+UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, UINT *pCount)
+{
+ MSISUMMARYINFO *suminfo;
+
+ FIXME("%ld %p\n",hSummaryInfo, pCount);
+
+ suminfo = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
+ if( !suminfo )
+ return ERROR_INVALID_HANDLE;
+
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+UINT WINAPI MsiSummaryInfoGetPropertyA(
+ MSIHANDLE hSummaryInfo, UINT uiProperty, UINT *puiDataType, INT *piValue,
+ FILETIME *pftValue, LPSTR szValueBuf, DWORD *pcchValueBuf)
+{
+ MSISUMMARYINFO *suminfo;
+ HRESULT r;
+ PROPSPEC spec;
+ PROPVARIANT var;
+
+ TRACE("%ld %d %p %p %p %p %p\n",
+ hSummaryInfo, uiProperty, puiDataType, piValue,
+ pftValue, szValueBuf, pcchValueBuf);
+
+ suminfo = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
+ if( !suminfo )
+ return ERROR_INVALID_HANDLE;
+
+ spec.ulKind = PRSPEC_PROPID;
+ spec.u.propid = uiProperty;
+
+ r = IPropertyStorage_ReadMultiple( suminfo->propstg, 1, &spec, &var);
+ if( FAILED(r) )
+ return ERROR_FUNCTION_FAILED;
+
+ if( puiDataType )
+ *puiDataType = var.vt;
+
+ switch( var.vt )
+ {
+ case VT_I4:
+ if( piValue )
+ *piValue = var.u.lVal;
+ break;
+ case VT_LPSTR:
+ if( pcchValueBuf && szValueBuf )
+ {
+ lstrcpynA(szValueBuf, var.u.pszVal, *pcchValueBuf );
+ *pcchValueBuf = lstrlenA( var.u.pszVal );
+ }
+ break;
+ case VT_FILETIME:
+ if( pftValue )
+ memcpy(pftValue, &var.u.filetime, sizeof (FILETIME) );
+ break;
+ case VT_EMPTY:
+ break;
+ default:
+ FIXME("Unknown property variant type\n");
+ break;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+UINT WINAPI MsiSummaryInfoGetPropertyW(
+ MSIHANDLE hSummaryInfo, UINT uiProperty, UINT *puiDataType, INT *piValue,
+ FILETIME *pftValue, LPWSTR szValueBuf, DWORD *pcchValueBuf)
+{
+ FIXME("%ld %d %p %p %p %p %p\n",
+ hSummaryInfo, uiProperty, puiDataType, piValue,
+ pftValue, szValueBuf, pcchValueBuf);
+
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
reactos/lib/msi
diff -N table.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ table.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,1425 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002-2004 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+
+#include "wine/unicode.h"
+
+#include "query.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+typedef struct tagMSICOLUMNINFO
+{
+ LPWSTR tablename;
+ UINT number;
+ LPWSTR colname;
+ UINT type;
+ UINT offset;
+} MSICOLUMNINFO;
+
+struct tagMSITABLE
+{
+ USHORT **data;
+ UINT ref_count;
+ UINT row_count;
+ struct tagMSITABLE *next;
+ struct tagMSITABLE *prev;
+ WCHAR name[1];
+};
+
+#define MAX_STREAM_NAME 0x1f
+
+static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name,
+ MSICOLUMNINFO **pcols, UINT *pcount );
+static UINT get_tablecolumns( MSIDATABASE *db,
+ LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz);
+
+static inline UINT bytes_per_column( MSICOLUMNINFO *col )
+{
+ if( col->type & MSITYPE_STRING )
+ return 2;
+ if( (col->type & 0xff) > 4 )
+ ERR("Invalid column size!\n");
+ return col->type & 0xff;
+}
+
+static int utf2mime(int x)
+{
+ if( (x>='0') && (x<='9') )
+ return x-'0';
+ if( (x>='A') && (x<='Z') )
+ return x-'A'+10;
+ if( (x>='a') && (x<='z') )
+ return x-'a'+10+26;
+ if( x=='.' )
+ return 10+26+26;
+ if( x=='_' )
+ return 10+26+26+1;
+ return -1;
+}
+
+static LPWSTR encode_streamname(BOOL bTable, LPCWSTR in)
+{
+ DWORD count = MAX_STREAM_NAME;
+ DWORD ch, next;
+ LPWSTR out, p;
+
+ if( !bTable )
+ count = strlenW( in )+2;
+ out = HeapAlloc( GetProcessHeap(), 0, count*sizeof(WCHAR) );
+ p = out;
+
+ if( bTable )
+ {
+ *p++ = 0x4840;
+ count --;
+ }
+ while( count -- )
+ {
+ ch = *in++;
+ if( !ch )
+ {
+ *p = ch;
+ return out;
+ }
+ if( ( ch < 0x80 ) && ( utf2mime(ch) >= 0 ) )
+ {
+ ch = utf2mime(ch) + 0x4800;
+ next = *in;
+ if( next && (next<0x80) )
+ {
+ next = utf2mime(next);
+ if( next >= 0 )
+ {
+ next += 0x3ffffc0;
+ ch += (next<<6);
+ in++;
+ }
+ }
+ }
+ *p++ = ch;
+ }
+ ERR("Failed to encode stream name (%s)\n",debugstr_w(in));
+ HeapFree( GetProcessHeap(), 0, out );
+ return NULL;
+}
+
+static int mime2utf(int x)
+{
+ if( x<10 )
+ return x + '0';
+ if( x<(10+26))
+ return x - 10 + 'A';
+ if( x<(10+26+26))
+ return x - 10 - 26 + 'a';
+ if( x == (10+26+26) )
+ return '.';
+ return '_';
+}
+
+static BOOL decode_streamname(LPWSTR in, LPWSTR out)
+{
+ WCHAR ch;
+ DWORD count = 0;
+
+ while ( (ch = *in++) )
+ {
+ if( (ch >= 0x3800 ) && (ch < 0x4840 ) )
+ {
+ if( ch >= 0x4800 )
+ ch = mime2utf(ch-0x4800);
+ else
+ {
+ ch -= 0x3800;
+ *out++ = mime2utf(ch&0x3f);
+ count++;
+ ch = mime2utf((ch>>6)&0x3f);
+ }
+ }
+ *out++ = ch;
+ count++;
+ }
+ *out = 0;
+ return count;
+}
+
+void enum_stream_names( IStorage *stg )
+{
+ IEnumSTATSTG *stgenum = NULL;
+ HRESULT r;
+ STATSTG stat;
+ ULONG n, count;
+ WCHAR name[0x40];
+
+ r = IStorage_EnumElements( stg, 0, NULL, 0, &stgenum );
+ if( FAILED( r ) )
+ return;
+
+ n = 0;
+ while( 1 )
+ {
+ count = 0;
+ r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
+ if( FAILED( r ) || !count )
+ break;
+ decode_streamname( stat.pwcsName, name );
+ ERR("stream %2ld -> %s %s\n", n,
+ debugstr_w(stat.pwcsName), debugstr_w(name) );
+ n++;
+ }
+
+ IEnumSTATSTG_Release( stgenum );
+}
+
+static UINT read_stream_data( IStorage *stg, LPCWSTR stname,
+ USHORT **pdata, UINT *psz )
+{
+ HRESULT r;
+ UINT ret = ERROR_FUNCTION_FAILED;
+ VOID *data;
+ ULONG sz, count;
+ IStream *stm = NULL;
+ STATSTG stat;
+ LPWSTR encname;
+
+ encname = encode_streamname(TRUE, stname);
+
+ TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname));
+
+ r = IStorage_OpenStream(stg, encname, NULL,
+ STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
+ HeapFree( GetProcessHeap(), 0, encname );
+ if( FAILED( r ) )
+ {
+ WARN("open stream failed r = %08lx - empty table?\n",r);
+ return ret;
+ }
+
+ r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
+ if( FAILED( r ) )
+ {
+ ERR("open stream failed r = %08lx!\n",r);
+ goto end;
+ }
+
+ if( stat.cbSize.QuadPart >> 32 )
+ {
+ ERR("Too big!\n");
+ goto end;
+ }
+
+ sz = stat.cbSize.QuadPart;
+ data = HeapAlloc( GetProcessHeap(), 0, sz );
+ if( !data )
+ {
+ ERR("couldn't allocate memory r=%08lx!\n",r);
+ ret = ERROR_NOT_ENOUGH_MEMORY;
+ goto end;
+ }
+
+ r = IStream_Read(stm, data, sz, &count );
+ if( FAILED( r ) || ( count != sz ) )
+ {
+ HeapFree( GetProcessHeap(), 0, data );
+ ERR("read stream failed r = %08lx!\n",r);
+ goto end;
+ }
+
+ *pdata = data;
+ *psz = sz;
+ ret = ERROR_SUCCESS;
+
+end:
+ IStream_Release( stm );
+
+ return ret;
+}
+
+UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
+{
+ LPWSTR encname;
+ HRESULT r;
+
+ encname = encode_streamname(FALSE, stname);
+
+ TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname));
+
+ r = IStorage_OpenStream(db->storage, encname, NULL,
+ STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm);
+ HeapFree( GetProcessHeap(), 0, encname );
+ if( FAILED( r ) )
+ {
+ WARN("open stream failed r = %08lx - empty table?\n",r);
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname,
+ USHORT **pdata, UINT *psz )
+{
+ HRESULT r;
+ UINT ret = ERROR_FUNCTION_FAILED;
+ VOID *data;
+ ULONG sz, count;
+ IStream *stm = NULL;
+ STATSTG stat;
+
+ r = db_get_raw_stream( db, stname, &stm );
+ if( r != ERROR_SUCCESS)
+ return ret;
+ r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
+ if( FAILED( r ) )
+ {
+ ERR("open stream failed r = %08lx!\n",r);
+ goto end;
+ }
+
+ if( stat.cbSize.QuadPart >> 32 )
+ {
+ ERR("Too big!\n");
+ goto end;
+ }
+
+ sz = stat.cbSize.QuadPart;
+ data = HeapAlloc( GetProcessHeap(), 0, sz );
+ if( !data )
+ {
+ ERR("couldn't allocate memory r=%08lx!\n",r);
+ ret = ERROR_NOT_ENOUGH_MEMORY;
+ goto end;
+ }
+
+ r = IStream_Read(stm, data, sz, &count );
+ if( FAILED( r ) || ( count != sz ) )
+ {
+ HeapFree( GetProcessHeap(), 0, data );
+ ERR("read stream failed r = %08lx!\n",r);
+ goto end;
+ }
+
+ *pdata = data;
+ *psz = sz;
+ ret = ERROR_SUCCESS;
+
+end:
+ IStream_Release( stm );
+
+ return ret;
+}
+
+static UINT write_stream_data( IStorage *stg, LPCWSTR stname,
+ LPVOID data, UINT sz )
+{
+ HRESULT r;
+ UINT ret = ERROR_FUNCTION_FAILED;
+ ULONG count;
+ IStream *stm = NULL;
+ ULARGE_INTEGER size;
+ LARGE_INTEGER pos;
+ LPWSTR encname;
+
+ encname = encode_streamname(TRUE, stname );
+ r = IStorage_OpenStream( stg, encname, NULL,
+ STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
+ HeapFree( GetProcessHeap(), 0, encname );
+ if( FAILED(r) )
+ {
+ r = IStorage_CreateStream( stg, encname,
+ STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
+ }
+ if( FAILED( r ) )
+ {
+ ERR("open stream failed r = %08lx\n",r);
+ return ret;
+ }
+
+ size.QuadPart = sz;
+ r = IStream_SetSize( stm, size );
+ if( FAILED( r ) )
+ {
+ ERR("Failed to SetSize\n");
+ goto end;
+ }
+
+ pos.QuadPart = 0;
+ r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
+ if( FAILED( r ) )
+ {
+ ERR("Failed to Seek\n");
+ goto end;
+ }
+
+ r = IStream_Write(stm, data, sz, &count );
+ if( FAILED( r ) || ( count != sz ) )
+ {
+ ERR("Failed to Write\n");
+ goto end;
+ }
+
+ ret = ERROR_SUCCESS;
+
+end:
+ IStream_Release( stm );
+
+ return ret;
+}
+
+UINT read_table_from_storage( MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable)
+{
+ MSITABLE *t;
+ USHORT *rawdata = NULL;
+ UINT rawsize = 0, r, i, j, row_size = 0, num_cols = 0;
+ MSICOLUMNINFO *cols, *last_col;
+
+ TRACE("%s\n",debugstr_w(name));
+
+ /* non-existing tables should be interpretted as empty tables */
+ t = HeapAlloc( GetProcessHeap(), 0,
+ sizeof (MSITABLE) + lstrlenW(name)*sizeof (WCHAR) );
+ if( !t )
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ r = table_get_column_info( db, name, &cols, &num_cols );
+ if( r != ERROR_SUCCESS )
+ {
+ HeapFree( GetProcessHeap(), 0, t );
+ return r;
+ }
+ last_col = &cols[num_cols-1];
+ row_size = last_col->offset + bytes_per_column( last_col );
+
+ t->row_count = 0;
+ t->data = NULL;
+ lstrcpyW( t->name, name );
+ t->ref_count = 1;
+ *ptable = t;
+
+ /* if we can't read the table, just assume that it's empty */
+ read_stream_data( db->storage, name, &rawdata, &rawsize );
+ if( !rawdata )
+ return ERROR_SUCCESS;
+
+ TRACE("Read %d bytes\n", rawsize );
+
+ if( rawsize % row_size )
+ {
+ ERR("Table size is invalid %d/%d\n", rawsize, row_size );
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ t->row_count = rawsize / row_size;
+ t->data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+ t->row_count * sizeof (USHORT*) );
+ if( !t->data )
+ return ERROR_NOT_ENOUGH_MEMORY; /* FIXME: memory leak */
+
+ /* transpose all the data */
+ TRACE("Transposing data from %d columns\n", t->row_count );
+ for( i=0; i<t->row_count; i++ )
+ {
+ t->data[i] = HeapAlloc( GetProcessHeap(), 0, row_size );
+ if( !t->data[i] )
+ return ERROR_NOT_ENOUGH_MEMORY; /* FIXME: memory leak */
+ for( j=0; j<num_cols; j++ )
+ {
+ UINT ofs = cols[j].offset/2;
+ UINT n = bytes_per_column( &cols[j] );
+
+ switch( n )
+ {
+ case 2:
+ t->data[i][ofs] = rawdata[ofs*t->row_count + i ];
+ break;
+ case 4:
+ t->data[i][ofs] = rawdata[ofs*t->row_count + i ];
+ t->data[i][ofs+1] = rawdata[ofs*t->row_count + i + 1];
+ break;
+ default:
+ ERR("oops - unknown column width %d\n", n);
+ return ERROR_FUNCTION_FAILED;
+ }
+ }
+ }
+
+ HeapFree( GetProcessHeap(), 0, cols );
+ HeapFree( GetProcessHeap(), 0, rawdata );
+
+ return ERROR_SUCCESS;
+}
+
+/* add this table to the list of cached tables in the database */
+void add_table(MSIDATABASE *db, MSITABLE *table)
+{
+ table->next = db->first_table;
+ table->prev = NULL;
+ if( db->first_table )
+ db->first_table->prev = table;
+ else
+ db->last_table = table;
+ db->first_table = table;
+}
+
+/* remove from the list of cached tables */
+void remove_table( MSIDATABASE *db, MSITABLE *table )
+{
+ if( table->next )
+ table->next->prev = table->prev;
+ else
+ db->last_table = table->prev;
+ if( table->prev )
+ table->prev->next = table->next;
+ else
+ db->first_table = table->next;
+ table->next = NULL;
+ table->prev = NULL;
+}
+
+void release_table( MSIDATABASE *db, MSITABLE *table )
+{
+ if( !table->ref_count )
+ ERR("Trying to destroy table with refcount 0\n");
+ table->ref_count --;
+ if( !table->ref_count )
+ {
+ remove_table( db, table );
+ HeapFree( GetProcessHeap(), 0, table->data );
+ HeapFree( GetProcessHeap(), 0, table );
+ TRACE("Destroyed table %s\n", debugstr_w(table->name));
+ }
+}
+
+void free_cached_tables( MSIDATABASE *db )
+{
+ while( db->first_table )
+ {
+ MSITABLE *t = db->first_table;
+
+ if ( --t->ref_count )
+ ERR("table ref count not zero for %s\n", debugstr_w(t->name));
+ remove_table( db, t );
+ HeapFree( GetProcessHeap(), 0, t->data );
+ HeapFree( GetProcessHeap(), 0, t );
+ }
+}
+
+UINT find_cached_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable)
+{
+ MSITABLE *t;
+
+ for( t = db->first_table; t; t=t->next )
+ {
+ if( !lstrcmpW( name, t->name ) )
+ {
+ *ptable = t;
+ return ERROR_SUCCESS;
+ }
+ }
+
+ return ERROR_FUNCTION_FAILED;
+}
+
+static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO **pcols, UINT *pcount )
+{
+ UINT r, column_count;
+ MSICOLUMNINFO *columns;
+
+ /* get the number of columns in this table */
+ column_count = 0;
+ r = get_tablecolumns( db, name, NULL, &column_count );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ /* if there's no columns, there's no table */
+ if( column_count == 0 )
+ return ERROR_INVALID_PARAMETER;
+
+ TRACE("Table %s found\n", debugstr_w(name) );
+
+ columns = HeapAlloc( GetProcessHeap(), 0, column_count*sizeof (MSICOLUMNINFO));
+ if( !columns )
+ return ERROR_FUNCTION_FAILED;
+
+ r = get_tablecolumns( db, name, columns, &column_count );
+ if( r != ERROR_SUCCESS )
+ {
+ HeapFree( GetProcessHeap(), 0, columns );
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ *pcols = columns;
+ *pcount = column_count;
+
+ return r;
+}
+
+UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable)
+{
+ UINT r;
+
+ *ptable = NULL;
+
+ /* first, see if the table is cached */
+ r = find_cached_table( db, name, ptable );
+ if( r == ERROR_SUCCESS )
+ {
+ (*ptable)->ref_count++;
+ return r;
+ }
+
+ r = read_table_from_storage( db, name, ptable );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ /* add the table to the list */
+ add_table( db, *ptable );
+ (*ptable)->ref_count++;
+
+ return ERROR_SUCCESS;
+}
+
+UINT save_table( MSIDATABASE *db, MSITABLE *t )
+{
+ USHORT *rawdata = NULL, *p;
+ UINT rawsize, r, i, j, row_size, num_cols = 0;
+ MSICOLUMNINFO *cols, *last_col;
+
+ TRACE("Saving %s\n", debugstr_w( t->name ) );
+
+ r = table_get_column_info( db, t->name, &cols, &num_cols );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ last_col = &cols[num_cols-1];
+ row_size = last_col->offset + bytes_per_column( last_col );
+
+ rawsize = t->row_count * row_size;
+ rawdata = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, rawsize );
+ if( !rawdata )
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ p = rawdata;
+ for( i=0; i<num_cols; i++ )
+ {
+ for( j=0; j<t->row_count; j++ )
+ {
+ UINT offset = cols[i].offset;
+
+ *p++ = t->data[j][offset/2];
+ if( 4 == bytes_per_column( &cols[i] ) )
+ *p++ = t->data[j][offset/2+1];
+ }
+ }
+
+ TRACE("writing %d bytes\n", rawsize);
+ r = write_stream_data( db->storage, t->name, rawdata, rawsize );
+
+ HeapFree( GetProcessHeap(), 0, rawdata );
+
+ return r;
+}
+
+HRESULT init_string_table( IStorage *stg )
+{
+ HRESULT r;
+ static const WCHAR szStringData[] = {
+ '_','S','t','r','i','n','g','D','a','t','a',0 };
+ static const WCHAR szStringPool[] = {
+ '_','S','t','r','i','n','g','P','o','o','l',0 };
+ USHORT zero[2] = { 0, 0 };
+ ULONG count = 0;
+ IStream *stm = NULL;
+ LPWSTR encname;
+
+ encname = encode_streamname(TRUE, szStringPool );
+
+ /* create the StringPool stream... add the zero string to it*/
+ r = IStorage_CreateStream( stg, encname,
+ STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
+ HeapFree( GetProcessHeap(), 0, encname );
+ if( r )
+ {
+ TRACE("Failed\n");
+ return r;
+ }
+
+ r = IStream_Write(stm, zero, sizeof zero, &count );
+ IStream_Release( stm );
+
+ if( FAILED( r ) || ( count != sizeof zero ) )
+ {
+ TRACE("Failed\n");
+ return E_FAIL;
+ }
+
+ /* create the StringData stream... make it zero length */
+ encname = encode_streamname(TRUE, szStringData );
+ r = IStorage_CreateStream( stg, encname,
+ STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
+ HeapFree( GetProcessHeap(), 0, encname );
+ if( r )
+ {
+ TRACE("Failed\n");
+ return E_FAIL;
+ }
+ IStream_Release( stm );
+
+ return r;
+}
+
+UINT load_string_table( MSIDATABASE *db )
+{
+ CHAR *data;
+ USHORT *pool;
+ UINT r, ret = ERROR_FUNCTION_FAILED, datasize = 0, poolsize = 0, codepage;
+ DWORD i, count, offset, len, n;
+ static const WCHAR szStringData[] = {
+ '_','S','t','r','i','n','g','D','a','t','a',0 };
+ static const WCHAR szStringPool[] = {
+ '_','S','t','r','i','n','g','P','o','o','l',0 };
+
+ if( db->strings )
+ {
+ msi_destroy_stringtable( db->strings );
+ db->strings = NULL;
+ }
+
+ r = read_stream_data( db->storage, szStringPool, &pool, &poolsize );
+ if( r != ERROR_SUCCESS)
+ goto end;
+ r = read_stream_data( db->storage, szStringData, (USHORT**)&data, &datasize );
+ if( r != ERROR_SUCCESS)
+ goto end;
+
+ count = poolsize/4;
+ if( poolsize > 4 )
+ codepage = pool[0] | ( pool[1] << 16 );
+ else
+ codepage = CP_ACP;
+ db->strings = msi_init_stringtable( count, codepage );
+
+ offset = 0;
+ for( i=1; i<count; i++ )
+ {
+ len = pool[i*2];
+ n = msi_addstring( db->strings, i, data+offset, len, pool[i*2+1] );
+ if( n != i )
+ ERR("Failed to add string %ld\n", i );
+ offset += len;
+ }
+
+ TRACE("Loaded %ld strings\n", count);
+
+ ret = ERROR_SUCCESS;
+
+end:
+ if( pool )
+ HeapFree( GetProcessHeap(), 0, pool );
+ if( data )
+ HeapFree( GetProcessHeap(), 0, data );
+
+ return ret;
+}
+
+UINT save_string_table( MSIDATABASE *db )
+{
+ UINT i, count, datasize, poolsize, sz, used, r, codepage;
+ UINT ret = ERROR_FUNCTION_FAILED;
+ static const WCHAR szStringData[] = {
+ '_','S','t','r','i','n','g','D','a','t','a',0 };
+ static const WCHAR szStringPool[] = {
+ '_','S','t','r','i','n','g','P','o','o','l',0 };
+ CHAR *data = NULL;
+ USHORT *pool = NULL;
+
+ TRACE("\n");
+
+ /* construct the new table in memory first */
+ datasize = msi_string_totalsize( db->strings, &count );
+ poolsize = count*2*sizeof(USHORT);
+
+ pool = HeapAlloc( GetProcessHeap(), 0, poolsize );
+ if( ! pool )
+ {
+ ERR("Failed to alloc pool %d bytes\n", poolsize );
+ goto err;
+ }
+ data = HeapAlloc( GetProcessHeap(), 0, datasize );
+ if( ! data )
+ {
+ ERR("Failed to alloc data %d bytes\n", poolsize );
+ goto err;
+ }
+
+ used = 0;
+ codepage = msi_string_get_codepage( db->strings );
+ pool[0]=codepage&0xffff;
+ pool[1]=(codepage>>16);
+ for( i=1; i<count; i++ )
+ {
+ sz = datasize - used;
+ r = msi_id2stringA( db->strings, i, data+used, &sz );
+ if( r != ERROR_SUCCESS )
+ {
+ ERR("failed to fetch string\n");
+ sz = 0;
+ }
+ if( sz && (sz < (datasize - used ) ) )
+ sz--;
+ TRACE("adding %u bytes %s\n", sz, data+used );
+ pool[ i*2 ] = sz;
+ pool[ i*2 + 1 ] = msi_id_refcount( db->strings, i );
+ used += sz;
+ if( used > datasize )
+ {
+ ERR("oops overran %d >= %d\n", used, datasize);
+ goto err;
+ }
+ }
+
+ if( used != datasize )
+ {
+ ERR("oops used %d != datasize %d\n", used, datasize);
+ goto err;
+ }
+
+ /* write the streams */
+ r = write_stream_data( db->storage, szStringData, data, datasize );
+ TRACE("Wrote StringData r=%08x\n", r);
+ if( r )
+ goto err;
+ r = write_stream_data( db->storage, szStringPool, pool, poolsize );
+ TRACE("Wrote StringPool r=%08x\n", r);
+ if( r )
+ goto err;
+
+ ret = ERROR_SUCCESS;
+
+err:
+ if( data )
+ HeapFree( GetProcessHeap(), 0, data );
+ if( pool )
+ HeapFree( GetProcessHeap(), 0, pool );
+
+ return ret;
+}
+
+static LPWSTR strdupW( LPCWSTR str )
+{
+ UINT len = lstrlenW( str ) + 1;
+ LPWSTR ret = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
+ if( ret )
+ lstrcpyW( ret, str );
+ return ret;
+}
+
+/* information for default tables */
+static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 };
+static const WCHAR szTable[] = { 'T','a','b','l','e',0 };
+static const WCHAR szName[] = { 'N','a','m','e',0 };
+static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 };
+static const WCHAR szColumn[] = { 'C','o','l','u','m','n',0 };
+static const WCHAR szNumber[] = { 'N','u','m','b','e','r',0 };
+static const WCHAR szType[] = { 'T','y','p','e',0 };
+
+struct standard_table {
+ LPCWSTR tablename;
+ LPCWSTR columnname;
+ UINT number;
+ UINT type;
+} MSI_standard_tables[] =
+{
+ { szTables, szName, 1, MSITYPE_VALID | MSITYPE_STRING | 32},
+ { szColumns, szTable, 1, MSITYPE_VALID | MSITYPE_STRING | 32},
+ { szColumns, szNumber, 2, MSITYPE_VALID | 2},
+ { szColumns, szName, 3, MSITYPE_VALID | MSITYPE_STRING | 32},
+ { szColumns, szType, 4, MSITYPE_VALID | 2},
+};
+
+#define STANDARD_TABLE_COUNT \
+ (sizeof(MSI_standard_tables)/sizeof(struct standard_table))
+
+UINT get_defaulttablecolumns( LPCWSTR szTable, MSICOLUMNINFO *colinfo, UINT *sz)
+{
+ DWORD i, n=0;
+
+ for(i=0; i<STANDARD_TABLE_COUNT; i++)
+ {
+ if( lstrcmpW( szTable, MSI_standard_tables[i].tablename ) )
+ continue;
+ if(colinfo && (n < *sz) )
+ {
+ colinfo[n].tablename = strdupW(MSI_standard_tables[i].tablename);
+ colinfo[n].colname = strdupW(MSI_standard_tables[i].columnname);
+ colinfo[n].number = MSI_standard_tables[i].number;
+ colinfo[n].type = MSI_standard_tables[i].type;
+ /* ERR("Table %s has column %s\n",debugstr_w(colinfo[n].tablename),
+ debugstr_w(colinfo[n].colname)); */
+ if( n )
+ colinfo[n].offset = colinfo[n-1].offset
+ + bytes_per_column( &colinfo[n-1] );
+ else
+ colinfo[n].offset = 0;
+ }
+ n++;
+ if( colinfo && (n >= *sz) )
+ break;
+ }
+ *sz = n;
+ return ERROR_SUCCESS;
+}
+
+LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid)
+{
+ UINT sz=0, r;
+ LPWSTR str;
+
+ r = msi_id2stringW( db->strings, stringid, NULL, &sz );
+ if( r != ERROR_SUCCESS )
+ return NULL;
+ str = HeapAlloc( GetProcessHeap(), 0, sz*sizeof (WCHAR));
+ if( !str )
+ return str;
+ r = msi_id2stringW( db->strings, stringid, str, &sz );
+ if( r == ERROR_SUCCESS )
+ return str;
+ HeapFree( GetProcessHeap(), 0, str );
+ return NULL;
+}
+
+static UINT get_tablecolumns( MSIDATABASE *db,
+ LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz)
+{
+ UINT r, i, n=0, table_id, count, maxcount = *sz;
+ MSITABLE *table = NULL;
+ static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 };
+
+ /* first check if there is a default table with that name */
+ r = get_defaulttablecolumns( szTableName, colinfo, sz );
+ if( ( r == ERROR_SUCCESS ) && *sz )
+ return r;
+
+ r = get_table( db, szColumns, &table);
+ if( r != ERROR_SUCCESS )
+ {
+ ERR("table %s not available\n", debugstr_w(szColumns));
+ return r;
+ }
+
+ /* convert table and column names to IDs from the string table */
+ r = msi_string2idW( db->strings, szTableName, &table_id );
+ if( r != ERROR_SUCCESS )
+ {
+ release_table( db, table );
+ ERR("Couldn't find id for %s\n", debugstr_w(szTableName));
+ return r;
+ }
+
+ TRACE("Table id is %d\n", table_id);
+
+ count = table->row_count;
+ for( i=0; i<count; i++ )
+ {
+ if( table->data[ i ][ 0 ] != table_id )
+ continue;
+ if( colinfo )
+ {
+ UINT id = table->data[ i ] [ 2 ];
+ colinfo[n].tablename = MSI_makestring( db, table_id );
+ colinfo[n].number = table->data[ i ][ 1 ] - (1<<15);
+ colinfo[n].colname = MSI_makestring( db, id );
+ colinfo[n].type = table->data[ i ] [ 3 ];
+ /* this assumes that columns are in order in the table */
+ if( n )
+ colinfo[n].offset = colinfo[n-1].offset
+ + bytes_per_column( &colinfo[n-1] );
+ else
+ colinfo[n].offset = 0;
+ TRACE("table %s column %d is [%s] (%d) with type %08x "
+ "offset %d at row %d\n", debugstr_w(szTableName),
+ colinfo[n].number, debugstr_w(colinfo[n].colname),
+ id, colinfo[n].type, colinfo[n].offset, i);
+ if( n != (colinfo[n].number-1) )
+ {
+ ERR("oops. data in the _Columns table isn't in the right "
+ "order for table %s\n", debugstr_w(szTableName));
+ return ERROR_FUNCTION_FAILED;
+ }
+ }
+ n++;
+ if( colinfo && ( n >= maxcount ) )
+ break;
+ }
+ *sz = n;
+
+ release_table( db, table );
+
+ return ERROR_SUCCESS;
+}
+
+/* try to find the table name in the _Tables table */
+BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name )
+{
[truncated at 1000 lines; 429 more skipped]
reactos/lib/msi
diff -N tokenize.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tokenize.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,397 @@
+/*
+** 2001 September 15
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** An tokenizer for SQL
+**
+** This file contains C code that splits an SQL input string up into
+** individual tokens and sends those tokens one-by-one over to the
+** parser for analysis.
+*/
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wine/debug.h"
+#include "winnls.h"
+#include "query.h"
+#include "sql.tab.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+/*
+** All the keywords of the SQL language are stored as in a hash
+** table composed of instances of the following structure.
+*/
+typedef struct Keyword Keyword;
+struct Keyword {
+ const char *zName; /* The keyword name */
+ int tokenType; /* The token value for this keyword */
+};
+
+/*
+** These are the keywords
+*/
+static const Keyword aKeywordTable[] = {
+ { "ABORT", TK_ABORT },
+ { "AFTER", TK_AFTER },
+ { "ALL", TK_ALL },
+ { "AND", TK_AND },
+ { "AS", TK_AS },
+ { "ASC", TK_ASC },
+ { "BEFORE", TK_BEFORE },
+ { "BEGIN", TK_BEGIN },
+ { "BETWEEN", TK_BETWEEN },
+ { "BY", TK_BY },
+ { "CASCADE", TK_CASCADE },
+ { "CASE", TK_CASE },
+ { "CHAR", TK_CHAR },
+ { "CHARACTER", TK_CHAR },
+ { "CHECK", TK_CHECK },
+ { "CLUSTER", TK_CLUSTER },
+ { "COLLATE", TK_COLLATE },
+ { "COMMIT", TK_COMMIT },
+ { "CONFLICT", TK_CONFLICT },
+ { "CONSTRAINT", TK_CONSTRAINT },
+ { "COPY", TK_COPY },
+ { "CREATE", TK_CREATE },
+ { "CROSS", TK_JOIN_KW },
+ { "DEFAULT", TK_DEFAULT },
+ { "DEFERRED", TK_DEFERRED },
+ { "DEFERRABLE", TK_DEFERRABLE },
+ { "DELETE", TK_DELETE },
+ { "DELIMITERS", TK_DELIMITERS },
+ { "DESC", TK_DESC },
+ { "DISTINCT", TK_DISTINCT },
+ { "DROP", TK_DROP },
+ { "END", TK_END },
+ { "EACH", TK_EACH },
+ { "ELSE", TK_ELSE },
+ { "EXCEPT", TK_EXCEPT },
+ { "EXPLAIN", TK_EXPLAIN },
+ { "FAIL", TK_FAIL },
+ { "FOR", TK_FOR },
+ { "FOREIGN", TK_FOREIGN },
+ { "FROM", TK_FROM },
+ { "FULL", TK_JOIN_KW },
+ { "GLOB", TK_GLOB },
+ { "GROUP", TK_GROUP },
+ { "HAVING", TK_HAVING },
+ { "HOLD", TK_HOLD },
+ { "IGNORE", TK_IGNORE },
+ { "IMMEDIATE", TK_IMMEDIATE },
+ { "IN", TK_IN },
+ { "INDEX", TK_INDEX },
+ { "INITIALLY", TK_INITIALLY },
+ { "INNER", TK_JOIN_KW },
+ { "INSERT", TK_INSERT },
+ { "INSTEAD", TK_INSTEAD },
+ { "INT", TK_INT },
+ { "INTERSECT", TK_INTERSECT },
+ { "INTO", TK_INTO },
+ { "IS", TK_IS },
+ { "ISNULL", TK_ISNULL },
+ { "JOIN", TK_JOIN },
+ { "KEY", TK_KEY },
+ { "LEFT", TK_JOIN_KW },
+ { "LIKE", TK_LIKE },
+ { "LIMIT", TK_LIMIT },
+ { "LOCALIZABLE", TK_LOCALIZABLE },
+ { "LONG", TK_LONG },
+ { "LONGCHAR", TK_LONGCHAR },
+ { "MATCH", TK_MATCH },
+ { "NATURAL", TK_JOIN_KW },
+ { "NOT", TK_NOT },
+ { "NOTNULL", TK_NOTNULL },
+ { "NULL", TK_NULL },
+ { "OBJECT", TK_OBJECT },
+ { "OF", TK_OF },
+ { "OFFSET", TK_OFFSET },
+ { "ON", TK_ON },
+ { "OR", TK_OR },
+ { "ORDER", TK_ORDER },
+ { "OUTER", TK_JOIN_KW },
+ { "PRAGMA", TK_PRAGMA },
+ { "PRIMARY", TK_PRIMARY },
+ { "RAISE", TK_RAISE },
+ { "REFERENCES", TK_REFERENCES },
+ { "REPLACE", TK_REPLACE },
+ { "RESTRICT", TK_RESTRICT },
+ { "RIGHT", TK_JOIN_KW },
+ { "ROLLBACK", TK_ROLLBACK },
+ { "ROW", TK_ROW },
+ { "SELECT", TK_SELECT },
+ { "SET", TK_SET },
+ { "SHORT", TK_SHORT },
+ { "STATEMENT", TK_STATEMENT },
+ { "TABLE", TK_TABLE },
+ { "TEMP", TK_TEMP },
+ { "TEMPORARY", TK_TEMP },
+ { "THEN", TK_THEN },
+ { "TRANSACTION", TK_TRANSACTION },
+ { "TRIGGER", TK_TRIGGER },
+ { "UNION", TK_UNION },
+ { "UNIQUE", TK_UNIQUE },
+ { "UPDATE", TK_UPDATE },
+ { "USING", TK_USING },
+ { "VACUUM", TK_VACUUM },
+ { "VALUES", TK_VALUES },
+ { "VIEW", TK_VIEW },
+ { "WHEN", TK_WHEN },
+ { "WHERE", TK_WHERE },
+};
+
+#define KEYWORD_COUNT ( sizeof aKeywordTable/sizeof (Keyword) )
+
+/*
+** This function looks up an identifier to determine if it is a
+** keyword. If it is a keyword, the token code of that keyword is
+** returned. If the input is not a keyword, TK_ID is returned.
+*/
+int sqliteKeywordCode(const WCHAR *z, int n){
+ UINT i, len;
+ char buffer[0x10];
+
+ len = WideCharToMultiByte( CP_ACP, 0, z, n, buffer, sizeof buffer, NULL, NULL );
+ for(i=0; i<len; i++)
+ buffer[i] = toupper(buffer[i]);
+ for(i=0; i<KEYWORD_COUNT; i++)
+ {
+ if(memcmp(buffer, aKeywordTable[i].zName, len))
+ continue;
+ if(strlen(aKeywordTable[i].zName) == len )
+ return aKeywordTable[i].tokenType;
+ }
+ return TK_ID;
+}
+
+
+/*
+** If X is a character that can be used in an identifier then
+** isIdChar[X] will be 1. Otherwise isIdChar[X] will be 0.
+**
+** In this implementation, an identifier can be a string of
+** alphabetic characters, digits, and "_" plus any character
+** with the high-order bit set. The latter rule means that
+** any sequence of UTF-8 characters or characters taken from
+** an extended ISO8859 character set can form an identifier.
+*/
+static const char isIdChar[] = {
+/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8x */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9x */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Ax */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Bx */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Cx */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Dx */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Ex */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Fx */
+};
+
+
+/*
+** Return the length of the token that begins at z[0]. Return
+** -1 if the token is (or might be) incomplete. Store the token
+** type in *tokenType before returning.
+*/
+int sqliteGetToken(const WCHAR *z, int *tokenType){
+ int i;
+ switch( *z ){
+ case ' ': case '\t': case '\n': case '\f': case '\r': {
+ for(i=1; isspace(z[i]); i++){}
+ *tokenType = TK_SPACE;
+ return i;
+ }
+ case '-': {
+ if( z[1]==0 ) return -1;
+ if( z[1]=='-' ){
+ for(i=2; z[i] && z[i]!='\n'; i++){}
+ *tokenType = TK_COMMENT;
+ return i;
+ }
+ *tokenType = TK_MINUS;
+ return 1;
+ }
+ case '(': {
+ if( z[1]=='+' && z[2]==')' ){
+ *tokenType = TK_ORACLE_OUTER_JOIN;
+ return 3;
+ }else{
+ *tokenType = TK_LP;
+ return 1;
+ }
+ }
+ case ')': {
+ *tokenType = TK_RP;
+ return 1;
+ }
+ case ';': {
+ *tokenType = TK_SEMI;
+ return 1;
+ }
+ case '+': {
+ *tokenType = TK_PLUS;
+ return 1;
+ }
+ case '*': {
+ *tokenType = TK_STAR;
+ return 1;
+ }
+ case '/': {
+ if( z[1]!='*' || z[2]==0 ){
+ *tokenType = TK_SLASH;
+ return 1;
+ }
+ for(i=3; z[i] && (z[i]!='/' || z[i-1]!='*'); i++){}
+ if( z[i] ) i++;
+ *tokenType = TK_COMMENT;
+ return i;
+ }
+ case '%': {
+ *tokenType = TK_REM;
+ return 1;
+ }
+ case '=': {
+ *tokenType = TK_EQ;
+ return 1 + (z[1]=='=');
+ }
+ case '<': {
+ if( z[1]=='=' ){
+ *tokenType = TK_LE;
+ return 2;
+ }else if( z[1]=='>' ){
+ *tokenType = TK_NE;
+ return 2;
+ }else if( z[1]=='<' ){
+ *tokenType = TK_LSHIFT;
+ return 2;
+ }else{
+ *tokenType = TK_LT;
+ return 1;
+ }
+ }
+ case '>': {
+ if( z[1]=='=' ){
+ *tokenType = TK_GE;
+ return 2;
+ }else if( z[1]=='>' ){
+ *tokenType = TK_RSHIFT;
+ return 2;
+ }else{
+ *tokenType = TK_GT;
+ return 1;
+ }
+ }
+ case '!': {
+ if( z[1]!='=' ){
+ *tokenType = TK_ILLEGAL;
+ return 2;
+ }else{
+ *tokenType = TK_NE;
+ return 2;
+ }
+ }
+ case '|': {
+ if( z[1]!='|' ){
+ *tokenType = TK_BITOR;
+ return 1;
+ }else{
+ *tokenType = TK_CONCAT;
+ return 2;
+ }
+ }
+ case '?': {
+ *tokenType = TK_WILDCARD;
+ return 1;
+ }
+ case ',': {
+ *tokenType = TK_COMMA;
+ return 1;
+ }
+ case '&': {
+ *tokenType = TK_BITAND;
+ return 1;
+ }
+ case '~': {
+ *tokenType = TK_BITNOT;
+ return 1;
+ }
+ case '`': case '\'': case '"': {
+ int delim = z[0];
+ for(i=1; z[i]; i++){
+ if( z[i]==delim ){
+ if( z[i+1]==delim ){
+ i++;
+ }else{
+ break;
+ }
+ }
+ }
+ if( z[i] ) i++;
+ *tokenType = TK_STRING;
+ return i;
+ }
+ case '.': {
+ if( !isdigit(z[1]) ){
+ *tokenType = TK_DOT;
+ return 1;
+ }
+ /* Fall thru into the next case */
+ }
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': {
+ *tokenType = TK_INTEGER;
+ for(i=1; isdigit(z[i]); i++){}
+ if( z[i]=='.' ){
+ i++;
+ while( isdigit(z[i]) ){ i++; }
+ *tokenType = TK_FLOAT;
+ }
+ if( (z[i]=='e' || z[i]=='E') &&
+ ( isdigit(z[i+1])
+ || ((z[i+1]=='+' || z[i+1]=='-') && isdigit(z[i+2]))
+ )
+ ){
+ i += 2;
+ while( isdigit(z[i]) ){ i++; }
+ *tokenType = TK_FLOAT;
+ }else if( z[0]=='.' ){
+ *tokenType = TK_FLOAT;
+ }
+ return i;
+ }
+ case '[': {
+ for(i=1; z[i] && z[i-1]!=']'; i++){}
+ *tokenType = TK_ID;
+ return i;
+ }
+ default: {
+ if( !isIdChar[*z] ){
+ break;
+ }
+ for(i=1; isIdChar[z[i]]; i++){}
+ *tokenType = sqliteKeywordCode(z, i);
+ return i;
+ }
+ }
+ *tokenType = TK_ILLEGAL;
+ return 1;
+}
reactos/lib/msi
diff -N update.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ update.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,239 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2004 Mike McCormack for CodeWeavers
+ *
+ * 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 receuved a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+
+#include "query.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+
+/* below is the query interface to a table */
+
+typedef struct tagMSIUPDATEVIEW
+{
+ MSIVIEW view;
+ MSIDATABASE *db;
+ MSIVIEW *wv;
+ value_list *vals;
+} MSIUPDATEVIEW;
+
+static UINT UPDATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
+{
+ MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
+
+ TRACE("%p %d %d %p\n", uv, row, col, val );
+
+ return ERROR_FUNCTION_FAILED;
+}
+
+static UINT UPDATE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
+{
+ MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
+ UINT n, type, val, r, row, col_count = 0, row_count = 0;
+ MSIVIEW *wv;
+
+ TRACE("%p %p\n", uv, record );
+
+ if( !record )
+ return ERROR_FUNCTION_FAILED;
+
+ wv = uv->wv;
+ if( !wv )
+ return ERROR_FUNCTION_FAILED;
+
+ r = wv->ops->execute( wv, 0 );
+ TRACE("tv execute returned %x\n", r);
+ if( r )
+ return r;
+
+ r = wv->ops->get_dimensions( wv, &row_count, &col_count );
+ if( r )
+ goto err;
+
+ for( row = 0; row < row_count; row++ )
+ {
+ for( n = 1; n <= col_count; n++ )
+ {
+ r = wv->ops->get_column_info( wv, n, NULL, &type );
+ if( r )
+ break;
+
+ if( type & MSITYPE_STRING )
+ {
+ const WCHAR *str = MSI_RecordGetString( record, n );
+ val = msi_addstringW( uv->db->strings, 0, str, -1, 1 );
+ }
+ else
+ {
+ val = MSI_RecordGetInteger( record, n );
+ val |= 0x8000;
+ }
+ r = wv->ops->set_int( wv, row, n, val );
+ if( r )
+ break;
+ }
+ }
+
+err:
+ return ERROR_SUCCESS;
+}
+
+
+static UINT UPDATE_close( struct tagMSIVIEW *view )
+{
+ MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
+ MSIVIEW *wv;
+
+ TRACE("%p\n", uv);
+
+ wv = uv->wv;
+ if( !wv )
+ return ERROR_FUNCTION_FAILED;
+
+ return wv->ops->close( wv );
+}
+
+static UINT UPDATE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
+{
+ MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
+ MSIVIEW *wv;
+
+ TRACE("%p %p %p\n", uv, rows, cols );
+
+ wv = uv->wv;
+ if( !wv )
+ return ERROR_FUNCTION_FAILED;
+
+ return wv->ops->get_dimensions( wv, rows, cols );
+}
+
+static UINT UPDATE_get_column_info( struct tagMSIVIEW *view,
+ UINT n, LPWSTR *name, UINT *type )
+{
+ MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
+ MSIVIEW *wv;
+
+ TRACE("%p %d %p %p\n", uv, n, name, type );
+
+ wv = uv->wv;
+ if( !wv )
+ return ERROR_FUNCTION_FAILED;
+
+ return wv->ops->get_column_info( wv, n, name, type );
+}
+
+static UINT UPDATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
+{
+ MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
+
+ TRACE("%p %d %ld\n", uv, eModifyMode, hrec );
+
+ return ERROR_FUNCTION_FAILED;
+}
+
+static UINT UPDATE_delete( struct tagMSIVIEW *view )
+{
+ MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
+ MSIVIEW *wv;
+
+ TRACE("%p\n", uv );
+
+ wv = uv->wv;
+ if( wv )
+ wv->ops->delete( wv );
+ delete_value_list( uv->vals );
+ msiobj_release( &uv->db->hdr );
+ HeapFree( GetProcessHeap(), 0, uv );
+
+ return ERROR_SUCCESS;
+}
+
+
+static MSIVIEWOPS update_ops =
+{
+ UPDATE_fetch_int,
+ NULL,
+ NULL,
+ NULL,
+ UPDATE_execute,
+ UPDATE_close,
+ UPDATE_get_dimensions,
+ UPDATE_get_column_info,
+ UPDATE_modify,
+ UPDATE_delete
+};
+
+UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
+ column_assignment *list, struct expr *expr )
+{
+ MSIUPDATEVIEW *uv = NULL;
+ UINT r;
+ MSIVIEW *tv = NULL, *sv = NULL, *wv = NULL;
+
+ TRACE("%p\n", uv );
+
+ r = TABLE_CreateView( db, table, &tv );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ /* add conditions first */
+ r = WHERE_CreateView( db, &wv, tv, expr );
+ if( r != ERROR_SUCCESS )
+ {
+ if( sv )
+ sv->ops->delete( tv );
+ return r;
+ }
+
+ /* then select the columns we want */
+ r = SELECT_CreateView( db, &sv, wv, list->col_list );
+ if( r != ERROR_SUCCESS )
+ {
+ if( tv )
+ tv->ops->delete( sv );
+ return r;
+ }
+
+ uv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *uv );
+ if( !uv )
+ return ERROR_FUNCTION_FAILED;
+
+ /* fill the structure */
+ uv->view.ops = &update_ops;
+ msiobj_addref( &db->hdr );
+ uv->db = db;
+ uv->vals = list->val_list;
+ uv->wv = sv;
+ *view = (MSIVIEW*) uv;
+
+ return ERROR_SUCCESS;
+}
reactos/lib/msi
diff -N version.rc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ version.rc 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2004 Christian Costa
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define WINE_FILEDESCRIPTION_STR "Wine MSI dll"
+#define WINE_FILENAME_STR "msi.dll"
+#define WINE_FILEVERSION 2,0,2600,0
+#define WINE_FILEVERSION_STR "2.0.2600.0"
+#define WINE_PRODUCTVERSION 2,0,2600,0
+#define WINE_PRODUCTVERSION_STR "2.0.2600.0"
+
+#include "wine/wine_common_ver.rc"
reactos/lib/msi
diff -N where.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ where.c 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,471 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2002 Mike McCormack for CodeWeavers
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+
+#include "query.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+
+/* below is the query interface to a table */
+
+typedef struct tagMSIWHEREVIEW
+{
+ MSIVIEW view;
+ MSIDATABASE *db;
+ MSIVIEW *table;
+ UINT row_count;
+ UINT *reorder;
+ struct expr *cond;
+} MSIWHEREVIEW;
+
+static UINT WHERE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
+{
+ MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
+
+ TRACE("%p %d %d %p\n", wv, row, col, val );
+
+ if( !wv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( row > wv->row_count )
+ return ERROR_NO_MORE_ITEMS;
+
+ row = wv->reorder[ row ];
+
+ return wv->table->ops->fetch_int( wv->table, row, col, val );
+}
+
+static UINT WHERE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm )
+{
+ MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
+
+ TRACE("%p %d %d %p\n", wv, row, col, stm );
+
+ if( !wv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( row > wv->row_count )
+ return ERROR_NO_MORE_ITEMS;
+
+ row = wv->reorder[ row ];
+
+ return wv->table->ops->fetch_stream( wv->table, row, col, stm );
+}
+
+static UINT WHERE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
+{
+ MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
+
+ TRACE("%p %d %d %04x\n", wv, row, col, val );
+
+ if( !wv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( row > wv->row_count )
+ return ERROR_NO_MORE_ITEMS;
+
+ row = wv->reorder[ row ];
+
+ return wv->table->ops->set_int( wv->table, row, col, val );
+}
+
+static UINT INT_evaluate( UINT lval, UINT op, UINT rval )
+{
+ switch( op )
+ {
+ case OP_EQ:
+ return ( lval == rval );
+ case OP_AND:
+ return ( lval && rval );
+ case OP_OR:
+ return ( lval || rval );
+ case OP_GT:
+ return ( lval > rval );
+ case OP_LT:
+ return ( lval < rval );
+ case OP_LE:
+ return ( lval <= rval );
+ case OP_GE:
+ return ( lval >= rval );
+ case OP_NE:
+ return ( lval != rval );
+ case OP_ISNULL:
+ return ( !lval );
+ case OP_NOTNULL:
+ return ( lval );
+ default:
+ ERR("Unknown operator %d\n", op );
+ }
+ return 0;
+}
+
+static const WCHAR *STRING_evaluate( string_table *st,
+ MSIVIEW *table, UINT row, struct expr *expr, MSIRECORD *record )
+{
+ UINT val = 0, r;
+
+ switch( expr->type )
+ {
+ case EXPR_COL_NUMBER:
+ r = table->ops->fetch_int( table, row, expr->u.col_number, &val );
+ if( r != ERROR_SUCCESS )
+ return NULL;
+ return msi_string_lookup_id( st, val );
+
+ case EXPR_SVAL:
+ return expr->u.sval;
+
+ case EXPR_WILDCARD:
+ return MSI_RecordGetString( record, 1 );
+
+ default:
+ ERR("Invalid expression type\n");
+ break;
+ }
+ return NULL;
+}
+
+static UINT STRCMP_Evaluate( string_table *st, MSIVIEW *table, UINT row,
+ struct expr *cond, UINT *val, MSIRECORD *record )
+{
+ int sr;
+ const WCHAR *l_str, *r_str;
+
+ l_str = STRING_evaluate( st, table, row, cond->u.expr.left, record );
+ r_str = STRING_evaluate( st, table, row, cond->u.expr.right, record );
+ if( l_str == r_str )
+ sr = 0;
+ else if( l_str && ! r_str )
+ sr = 1;
+ else if( r_str && ! l_str )
+ sr = -1;
+ else
+ sr = strcmpW( l_str, r_str );
+
+ *val = ( cond->u.expr.op == OP_EQ && ( sr == 0 ) ) ||
+ ( cond->u.expr.op == OP_LT && ( sr < 0 ) ) ||
+ ( cond->u.expr.op == OP_GT && ( sr > 0 ) );
+
+ return ERROR_SUCCESS;
+}
+
+static UINT WHERE_evaluate( MSIDATABASE *db, MSIVIEW *table, UINT row,
+ struct expr *cond, UINT *val, MSIRECORD *record )
+{
+ UINT r, lval, rval;
+
+ if( !cond )
+ return ERROR_SUCCESS;
+
+ switch( cond->type )
+ {
+ case EXPR_COL_NUMBER:
+ return table->ops->fetch_int( table, row, cond->u.col_number, val );
+
+ case EXPR_UVAL:
+ *val = cond->u.uval;
+ return ERROR_SUCCESS;
+
+ case EXPR_COMPLEX:
+ r = WHERE_evaluate( db, table, row, cond->u.expr.left, &lval, record );
+ if( r != ERROR_SUCCESS )
+ return r;
+ r = WHERE_evaluate( db, table, row, cond->u.expr.right, &rval, record );
+ if( r != ERROR_SUCCESS )
+ return r;
+ *val = INT_evaluate( lval, cond->u.expr.op, rval );
+ return ERROR_SUCCESS;
+
+ case EXPR_STRCMP:
+ return STRCMP_Evaluate( db->strings, table, row, cond, val, record );
+
+ case EXPR_WILDCARD:
+ *val = MSI_RecordGetInteger( record, 1 );
+ return ERROR_SUCCESS;
+
+ default:
+ ERR("Invalid expression type\n");
+ break;
+ }
+
+ return ERROR_SUCCESS;
+
+}
+
+static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
+{
+ MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
+ UINT count = 0, r, val, i;
+ MSIVIEW *table = wv->table;
+
+ TRACE("%p %p\n", wv, record);
+
+ if( !table )
+ return ERROR_FUNCTION_FAILED;
+
+ r = table->ops->execute( table, record );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ r = table->ops->get_dimensions( table, &count, NULL );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ wv->reorder = HeapAlloc( GetProcessHeap(), 0, count*sizeof(UINT) );
+ if( !wv->reorder )
+ return ERROR_FUNCTION_FAILED;
+
+ for( i=0; i<count; i++ )
+ {
+ val = 0;
+ r = WHERE_evaluate( wv->db, table, i, wv->cond, &val, record );
+ if( r != ERROR_SUCCESS )
+ return r;
+ if( val )
+ wv->reorder[ wv->row_count ++ ] = i;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+static UINT WHERE_close( struct tagMSIVIEW *view )
+{
+ MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
+
+ TRACE("%p\n", wv );
+
+ if( !wv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( wv->reorder )
+ HeapFree( GetProcessHeap(), 0, wv->reorder );
+ wv->reorder = NULL;
+
+ return wv->table->ops->close( wv->table );
+}
+
+static UINT WHERE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
+{
+ MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
+
+ TRACE("%p %p %p\n", wv, rows, cols );
+
+ if( !wv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ if( rows )
+ {
+ if( !wv->reorder )
+ return ERROR_FUNCTION_FAILED;
+ *rows = wv->row_count;
+ }
+
+ return wv->table->ops->get_dimensions( wv->table, NULL, cols );
+}
+
+static UINT WHERE_get_column_info( struct tagMSIVIEW *view,
+ UINT n, LPWSTR *name, UINT *type )
+{
+ MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
+
+ TRACE("%p %d %p %p\n", wv, n, name, type );
+
+ if( !wv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ return wv->table->ops->get_column_info( wv->table, n, name, type );
+}
+
+static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
+{
+ MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
+
+ TRACE("%p %d %ld\n", wv, eModifyMode, hrec );
+
+ if( !wv->table )
+ return ERROR_FUNCTION_FAILED;
+
+ return wv->table->ops->modify( wv->table, eModifyMode, hrec );
+}
+
+static UINT WHERE_delete( struct tagMSIVIEW *view )
+{
+ MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
+
+ TRACE("%p\n", wv );
+
+ if( wv->table )
+ wv->table->ops->delete( wv->table );
+
+ if( wv->reorder )
+ HeapFree( GetProcessHeap(), 0, wv->reorder );
+ wv->reorder = NULL;
+ wv->row_count = 0;
+
+ if( wv->cond )
+ delete_expr( wv->cond );
+
+ msiobj_release( &wv->db->hdr );
+ HeapFree( GetProcessHeap(), 0, wv );
+
+ return ERROR_SUCCESS;
+}
+
+
+MSIVIEWOPS where_ops =
+{
+ WHERE_fetch_int,
+ WHERE_fetch_stream,
+ WHERE_set_int,
+ NULL,
+ WHERE_execute,
+ WHERE_close,
+ WHERE_get_dimensions,
+ WHERE_get_column_info,
+ WHERE_modify,
+ WHERE_delete
+};
+
+static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond,
+ UINT *valid )
+{
+ UINT r, val = 0;
+
+ switch( cond->type )
+ {
+ case EXPR_COLUMN:
+ r = VIEW_find_column( table, cond->u.column, &val );
+ if( r == ERROR_SUCCESS )
+ {
+ *valid = 1;
+ cond->type = EXPR_COL_NUMBER;
+ cond->u.col_number = val;
+ }
+ else
+ {
+ *valid = 0;
+ ERR("Couldn't find column %s\n", debugstr_w( cond->u.column ) );
+ }
+ break;
+ case EXPR_COMPLEX:
+ r = WHERE_VerifyCondition( db, table, cond->u.expr.left, valid );
+ if( r != ERROR_SUCCESS )
+ return r;
+ if( !*valid )
+ return ERROR_SUCCESS;
+ r = WHERE_VerifyCondition( db, table, cond->u.expr.right, valid );
+ if( r != ERROR_SUCCESS )
+ return r;
+
+ /* check the type of the comparison */
+ if( ( cond->u.expr.left->type == EXPR_SVAL ) ||
+ ( cond->u.expr.right->type == EXPR_SVAL ) )
+ {
+ switch( cond->u.expr.op )
+ {
+ case OP_EQ:
+ case OP_GT:
+ case OP_LT:
+ break;
+ default:
+ *valid = FALSE;
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /* FIXME: check we're comparing a string to a column */
+
+ cond->type = EXPR_STRCMP;
+ }
+
+ break;
+ case EXPR_IVAL:
+ *valid = 1;
+ cond->type = EXPR_UVAL;
+ cond->u.uval = cond->u.ival + (1<<15);
+ break;
+ case EXPR_WILDCARD:
+ *valid = 1;
+ break;
+ case EXPR_SVAL:
+ *valid = 1;
+ break;
+ default:
+ ERR("Invalid expression type\n");
+ *valid = 0;
+ break;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
+ struct expr *cond )
+{
+ MSIWHEREVIEW *wv = NULL;
+ UINT count = 0, r, valid = 0;
+
+ TRACE("%p\n", wv );
+
+ r = table->ops->get_dimensions( table, NULL, &count );
+ if( r != ERROR_SUCCESS )
+ {
+ ERR("can't get table dimensions\n");
+ return r;
+ }
+
+ if( cond )
+ {
+ r = WHERE_VerifyCondition( db, table, cond, &valid );
+ if( r != ERROR_SUCCESS )
+ return r;
+ if( !valid )
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ wv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *wv );
+ if( !wv )
+ return ERROR_FUNCTION_FAILED;
+
+ /* fill the structure */
+ wv->view.ops = &where_ops;
+ msiobj_addref( &db->hdr );
+ wv->db = db;
+ wv->table = table;
+ wv->row_count = 0;
+ wv->reorder = NULL;
+ wv->cond = cond;
+ *view = (MSIVIEW*) wv;
+
+ return ERROR_SUCCESS;
+}
reactos/lib/msi
diff -N winehq2ros.patch
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ winehq2ros.patch 30 Nov 2004 19:10:50 -0000 1.1
@@ -0,0 +1,67 @@
+Only in /root/wine/wine/dlls/msi: .cvsignore
+Only in /root/wine/wine/dlls/msi: CVS
+Only in ./: Makefile
+Only in ./: Makefile.ros-template
+diff -u /root/wine/wine/dlls/msi/action.c ./action.c
+--- /root/wine/wine/dlls/msi/action.c 2004-10-27 20:43:05.000000000 -0500
++++ ./action.c 2004-10-30 12:14:17.000000000 -0500
+@@ -28,6 +28,7 @@
+
+ #include <stdarg.h>
+ #include <stdio.h>
++#include <fcntl.h>
+
+ #define COBJMACROS
+
+@@ -39,7 +40,7 @@
+ #include "fdi.h"
+ #include "msi.h"
+ #include "msiquery.h"
+-#include "msvcrt/fcntl.h"
++//#include "msvcrt/fcntl.h"
+ #include "objbase.h"
+ #include "objidl.h"
+ #include "msipriv.h"
+@@ -3477,7 +3478,7 @@
+ continue;
+ }
+
+- res = LoadTypeLib(package->files[index].TargetPath,&ptLib);
++// res = LoadTypeLib(package->files[index].TargetPath,&ptLib);
+ if (SUCCEEDED(res))
+ {
+ WCHAR help[MAX_PATH];
+@@ -3488,7 +3489,7 @@
+
+ resolve_folder(package,helpid,help,FALSE,FALSE,NULL);
+
+- res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help);
++// res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help);
+ if (!SUCCEEDED(res))
+ ERR("Failed to register type library %s\n",
+ debugstr_w(package->files[index].TargetPath));
+@@ -3503,8 +3504,9 @@
+ debugstr_w(package->files[index].TargetPath));
+ }
+
+- if (ptLib)
+- ITypeLib_Release(ptLib);
++ if (ptLib){
++ //ITypeLib_Release(ptLib);
++ }
+ }
+ else
+ ERR("Failed to load type library %s\n",
+Only in ./: patch.diff
+diff -u /root/wine/wine/dlls/msi/suminfo.c ./suminfo.c
+--- /root/wine/wine/dlls/msi/suminfo.c 2004-10-18 13:20:12.000000000 -0500
++++ ./suminfo.c 2004-10-30 00:09:12.000000000 -0500
+@@ -23,6 +23,8 @@
+ #define COBJMACROS
+ #define NONAMELESSUNION
+
++#define PRSPEC_PROPID (1)
++
+ #include "windef.h"
+ #include "winbase.h"
+ #include "winreg.h"
CVSspam 0.2.8