xref: /reactos/modules/rostests/winetests/msi/patch.c (revision 8bb4f059)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Copyright 2010 Hans Leidekker for CodeWeavers
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * A test program for patching MSI products.
5c2c66affSColin Finck  *
6c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
7c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
8c2c66affSColin Finck  * License as published by the Free Software Foundation; either
9c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
10c2c66affSColin Finck  *
11c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
12c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14c2c66affSColin Finck  * Lesser General Public License for more details.
15c2c66affSColin Finck  *
16c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
17c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
18c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19c2c66affSColin Finck  */
20c2c66affSColin Finck 
2131139640SAmine Khaldi #define _WIN32_MSI 300
2231139640SAmine Khaldi #define COBJMACROS
2331139640SAmine Khaldi 
2431139640SAmine Khaldi #include <stdio.h>
2531139640SAmine Khaldi 
2631139640SAmine Khaldi #include <windows.h>
2731139640SAmine Khaldi #include <msiquery.h>
2831139640SAmine Khaldi #include <msidefs.h>
2931139640SAmine Khaldi #include <msi.h>
3031139640SAmine Khaldi #include <wtypes.h>
3131139640SAmine Khaldi 
3231139640SAmine Khaldi #include "wine/test.h"
33c2c66affSColin Finck 
34c2c66affSColin Finck static UINT (WINAPI *pMsiApplyPatchA)( LPCSTR, LPCSTR, INSTALLTYPE, LPCSTR );
35c2c66affSColin Finck static UINT (WINAPI *pMsiGetPatchInfoExA)( LPCSTR, LPCSTR, LPCSTR, MSIINSTALLCONTEXT,
36c2c66affSColin Finck                                            LPCSTR, LPSTR, DWORD * );
37c2c66affSColin Finck static UINT (WINAPI *pMsiEnumPatchesExA)( LPCSTR, LPCSTR, DWORD, DWORD, DWORD, LPSTR,
38c2c66affSColin Finck                                           LPSTR, MSIINSTALLCONTEXT *, LPSTR, LPDWORD );
39c2c66affSColin Finck 
40c2c66affSColin Finck static const char *msifile = "winetest-patch.msi";
41c2c66affSColin Finck static const char *mspfile = "winetest-patch.msp";
42c2c66affSColin Finck static const WCHAR msifileW[] =
43c2c66affSColin Finck     {'w','i','n','e','t','e','s','t','-','p','a','t','c','h','.','m','s','i',0};
44c2c66affSColin Finck static const WCHAR mspfileW[] =
45c2c66affSColin Finck     {'w','i','n','e','t','e','s','t','-','p','a','t','c','h','.','m','s','p',0};
46c2c66affSColin Finck 
47c2c66affSColin Finck static char CURR_DIR[MAX_PATH];
48c2c66affSColin Finck static char PROG_FILES_DIR[MAX_PATH];
49c2c66affSColin Finck static char COMMON_FILES_DIR[MAX_PATH];
50c2c66affSColin Finck 
51c2c66affSColin Finck /* msi database data */
52c2c66affSColin Finck 
53c2c66affSColin Finck static const char property_dat[] =
54c2c66affSColin Finck     "Property\tValue\n"
55c2c66affSColin Finck     "s72\tl0\n"
56c2c66affSColin Finck     "Property\tProperty\n"
57c2c66affSColin Finck     "Manufacturer\tWineHQ\n"
58c2c66affSColin Finck     "ProductCode\t{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}\n"
59c2c66affSColin Finck     "UpgradeCode\t{A2E3D643-4E2C-477F-A309-F76F552D5F43}\n"
60c2c66affSColin Finck     "ProductLanguage\t1033\n"
61c2c66affSColin Finck     "ProductName\tmsitest\n"
62c2c66affSColin Finck     "ProductVersion\t1.1.1\n"
63c2c66affSColin Finck     "PATCHNEWSUMMARYSUBJECT\tInstaller Database\n"
64c2c66affSColin Finck     "MSIFASTINSTALL\t1\n";
65c2c66affSColin Finck 
66c2c66affSColin Finck static const char media_dat[] =
67c2c66affSColin Finck     "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
68c2c66affSColin Finck     "i2\ti4\tL64\tS255\tS32\tS72\n"
69c2c66affSColin Finck     "Media\tDiskId\n"
70c2c66affSColin Finck     "1\t1\t\t\tDISK1\t\n";
71c2c66affSColin Finck 
72c2c66affSColin Finck static const char file_dat[] =
73c2c66affSColin Finck     "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
74c2c66affSColin Finck     "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
75c2c66affSColin Finck     "File\tFile\n"
76c2c66affSColin Finck     "patch.txt\tpatch\tpatch.txt\t1000\t\t\t0\t1\n";
77c2c66affSColin Finck 
78c2c66affSColin Finck static const char directory_dat[] =
79c2c66affSColin Finck     "Directory\tDirectory_Parent\tDefaultDir\n"
80c2c66affSColin Finck     "s72\tS72\tl255\n"
81c2c66affSColin Finck     "Directory\tDirectory\n"
82c2c66affSColin Finck     "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
83c2c66affSColin Finck     "ProgramFilesFolder\tTARGETDIR\t.\n"
84c2c66affSColin Finck     "TARGETDIR\t\tSourceDir";
85c2c66affSColin Finck 
86c2c66affSColin Finck static const char component_dat[] =
87c2c66affSColin Finck     "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
88c2c66affSColin Finck     "s72\tS38\ts72\ti2\tS255\tS72\n"
89c2c66affSColin Finck     "Component\tComponent\n"
90c2c66affSColin Finck     "patch\t{4B79D87E-6D28-4FD3-92D6-CD9B26AF64F1}\tMSITESTDIR\t0\t\tpatch.txt\n";
91c2c66affSColin Finck 
92c2c66affSColin Finck static const char feature_dat[] =
93c2c66affSColin Finck     "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
94c2c66affSColin Finck     "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
95c2c66affSColin Finck     "Feature\tFeature\n"
96c2c66affSColin Finck     "patch\t\t\tpatch feature\t1\t1\tMSITESTDIR\t0\n";
97c2c66affSColin Finck 
98c2c66affSColin Finck static const char feature_comp_dat[] =
99c2c66affSColin Finck     "Feature_\tComponent_\n"
100c2c66affSColin Finck     "s38\ts72\n"
101c2c66affSColin Finck     "FeatureComponents\tFeature_\tComponent_\n"
102c2c66affSColin Finck     "patch\tpatch\n";
103c2c66affSColin Finck 
104c2c66affSColin Finck static const char install_exec_seq_dat[] =
105c2c66affSColin Finck     "Action\tCondition\tSequence\n"
106c2c66affSColin Finck     "s72\tS255\tI2\n"
107c2c66affSColin Finck     "InstallExecuteSequence\tAction\n"
108c2c66affSColin Finck     "LaunchConditions\t\t100\n"
109c2c66affSColin Finck     "CostInitialize\t\t800\n"
110c2c66affSColin Finck     "FileCost\t\t900\n"
111c2c66affSColin Finck     "CostFinalize\t\t1000\n"
112c2c66affSColin Finck     "InstallValidate\t\t1400\n"
113c2c66affSColin Finck     "InstallInitialize\t\t1500\n"
114c2c66affSColin Finck     "ProcessComponents\t\t1600\n"
115c2c66affSColin Finck     "RemoveFiles\t\t1700\n"
116c2c66affSColin Finck     "InstallFiles\t\t2000\n"
117c2c66affSColin Finck     "RegisterUser\t\t3000\n"
118c2c66affSColin Finck     "RegisterProduct\t\t3100\n"
119c2c66affSColin Finck     "PublishFeatures\t\t5100\n"
120c2c66affSColin Finck     "PublishProduct\t\t5200\n"
1213b27d975Swinesync     "UnpublishFeatures\t\t5300\n"
122c2c66affSColin Finck     "InstallFinalize\t\t6000\n";
123c2c66affSColin Finck 
124c2c66affSColin Finck struct msi_table
125c2c66affSColin Finck {
126c2c66affSColin Finck     const char *filename;
127c2c66affSColin Finck     const char *data;
128c2c66affSColin Finck     int size;
129c2c66affSColin Finck };
130c2c66affSColin Finck 
131c2c66affSColin Finck #define ADD_TABLE( x ) { #x".idt", x##_dat, sizeof(x##_dat) }
132c2c66affSColin Finck 
133c2c66affSColin Finck static const struct msi_table tables[] =
134c2c66affSColin Finck {
135c2c66affSColin Finck     ADD_TABLE( directory ),
136c2c66affSColin Finck     ADD_TABLE( file ),
137c2c66affSColin Finck     ADD_TABLE( component ),
138c2c66affSColin Finck     ADD_TABLE( feature ),
139c2c66affSColin Finck     ADD_TABLE( feature_comp ),
140c2c66affSColin Finck     ADD_TABLE( property ),
141c2c66affSColin Finck     ADD_TABLE( install_exec_seq ),
142c2c66affSColin Finck     ADD_TABLE( media )
143c2c66affSColin Finck };
144c2c66affSColin Finck 
145c2c66affSColin Finck static void init_function_pointers( void )
146c2c66affSColin Finck {
147c2c66affSColin Finck     HMODULE hmsi = GetModuleHandleA( "msi.dll" );
148c2c66affSColin Finck 
149c2c66affSColin Finck #define GET_PROC( mod, func ) \
150c2c66affSColin Finck     p ## func = (void *)GetProcAddress( mod, #func ); \
151c2c66affSColin Finck     if (!p ## func) \
152c2c66affSColin Finck         trace( "GetProcAddress(%s) failed\n", #func );
153c2c66affSColin Finck 
154c2c66affSColin Finck     GET_PROC( hmsi, MsiApplyPatchA );
155c2c66affSColin Finck     GET_PROC( hmsi, MsiGetPatchInfoExA );
156c2c66affSColin Finck     GET_PROC( hmsi, MsiEnumPatchesExA );
157c2c66affSColin Finck 
158c2c66affSColin Finck #undef GET_PROC
159c2c66affSColin Finck }
160c2c66affSColin Finck 
161c2c66affSColin Finck static BOOL is_process_limited(void)
162c2c66affSColin Finck {
163c2c66affSColin Finck     HANDLE token;
164c2c66affSColin Finck 
165a4930636Swinesync     if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
166c2c66affSColin Finck     {
167c2c66affSColin Finck         BOOL ret;
168c2c66affSColin Finck         TOKEN_ELEVATION_TYPE type = TokenElevationTypeDefault;
169c2c66affSColin Finck         DWORD size;
170c2c66affSColin Finck 
171c2c66affSColin Finck         ret = GetTokenInformation(token, TokenElevationType, &type, sizeof(type), &size);
172c2c66affSColin Finck         CloseHandle(token);
173c2c66affSColin Finck         return (ret && type == TokenElevationTypeLimited);
174c2c66affSColin Finck     }
175c2c66affSColin Finck     return FALSE;
176c2c66affSColin Finck }
177c2c66affSColin Finck 
178c2c66affSColin Finck static BOOL get_program_files_dir( char *buf, char *buf2 )
179c2c66affSColin Finck {
180c2c66affSColin Finck     HKEY hkey;
181c2c66affSColin Finck     DWORD type, size;
182c2c66affSColin Finck 
183c2c66affSColin Finck     if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey ))
184c2c66affSColin Finck         return FALSE;
185c2c66affSColin Finck 
186c2c66affSColin Finck     size = MAX_PATH;
187c2c66affSColin Finck     if (RegQueryValueExA( hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size ) &&
188c2c66affSColin Finck         RegQueryValueExA( hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size ))
189c2c66affSColin Finck     {
190c2c66affSColin Finck         RegCloseKey( hkey );
191c2c66affSColin Finck         return FALSE;
192c2c66affSColin Finck     }
193c2c66affSColin Finck     size = MAX_PATH;
194c2c66affSColin Finck     if (RegQueryValueExA( hkey, "CommonFilesDir", 0, &type, (LPBYTE)buf2, &size ))
195c2c66affSColin Finck     {
196c2c66affSColin Finck         RegCloseKey( hkey );
197c2c66affSColin Finck         return FALSE;
198c2c66affSColin Finck     }
199c2c66affSColin Finck     RegCloseKey( hkey );
200c2c66affSColin Finck     return TRUE;
201c2c66affSColin Finck }
202c2c66affSColin Finck 
203c2c66affSColin Finck static void create_file_data( const char *filename, const char *data, DWORD size )
204c2c66affSColin Finck {
205c2c66affSColin Finck     HANDLE file;
206c2c66affSColin Finck     DWORD written;
207c2c66affSColin Finck 
208c2c66affSColin Finck     file = CreateFileA( filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
209c2c66affSColin Finck     if (file == INVALID_HANDLE_VALUE)
210c2c66affSColin Finck         return;
211c2c66affSColin Finck 
212c2c66affSColin Finck     WriteFile( file, data, strlen( data ), &written, NULL );
213c2c66affSColin Finck     if (size)
214c2c66affSColin Finck     {
215c2c66affSColin Finck         SetFilePointer( file, size, NULL, FILE_BEGIN );
216c2c66affSColin Finck         SetEndOfFile( file );
217c2c66affSColin Finck     }
218c2c66affSColin Finck     CloseHandle( file );
219c2c66affSColin Finck }
220c2c66affSColin Finck 
221c2c66affSColin Finck #define create_file( name, size ) create_file_data( name, name, size )
222c2c66affSColin Finck 
223c2c66affSColin Finck static BOOL delete_pf( const char *rel_path, BOOL is_file )
224c2c66affSColin Finck {
225c2c66affSColin Finck     char path[MAX_PATH];
226c2c66affSColin Finck 
227c2c66affSColin Finck     strcpy( path, PROG_FILES_DIR );
228c2c66affSColin Finck     strcat( path, "\\" );
229c2c66affSColin Finck     strcat( path, rel_path );
230c2c66affSColin Finck 
231c2c66affSColin Finck     if (is_file)
232c2c66affSColin Finck         return DeleteFileA( path );
233c2c66affSColin Finck     else
234c2c66affSColin Finck         return RemoveDirectoryA( path );
235c2c66affSColin Finck }
236c2c66affSColin Finck 
237c2c66affSColin Finck static DWORD get_pf_file_size( const char *filename )
238c2c66affSColin Finck {
239c2c66affSColin Finck     char path[MAX_PATH];
240c2c66affSColin Finck     HANDLE file;
241c2c66affSColin Finck     DWORD size;
242c2c66affSColin Finck 
243c2c66affSColin Finck     strcpy( path, PROG_FILES_DIR );
244c2c66affSColin Finck     strcat( path, "\\");
245c2c66affSColin Finck     strcat( path, filename );
246c2c66affSColin Finck 
247c2c66affSColin Finck     file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
248c2c66affSColin Finck     if (file == INVALID_HANDLE_VALUE)
249c2c66affSColin Finck         return INVALID_FILE_SIZE;
250c2c66affSColin Finck 
251c2c66affSColin Finck     size = GetFileSize( file, NULL );
252c2c66affSColin Finck     CloseHandle( file );
253c2c66affSColin Finck     return size;
254c2c66affSColin Finck }
255c2c66affSColin Finck 
256c2c66affSColin Finck static void write_file( const char *filename, const char *data, DWORD data_size )
257c2c66affSColin Finck {
258c2c66affSColin Finck     DWORD size;
259c2c66affSColin Finck     HANDLE file = CreateFileA( filename, GENERIC_WRITE, 0, NULL,
260c2c66affSColin Finck                                CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
261c2c66affSColin Finck     WriteFile( file, data, data_size, &size, NULL );
262c2c66affSColin Finck     CloseHandle( file );
263c2c66affSColin Finck }
264c2c66affSColin Finck 
265c2c66affSColin Finck static void set_suminfo( const WCHAR *filename )
266c2c66affSColin Finck {
267c2c66affSColin Finck     UINT r;
268c2c66affSColin Finck     MSIHANDLE hsi, hdb;
269c2c66affSColin Finck 
270c2c66affSColin Finck     r = MsiOpenDatabaseW( filename, MSIDBOPEN_DIRECT, &hdb );
271c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
272c2c66affSColin Finck 
273c2c66affSColin Finck     r = MsiGetSummaryInformationA( hdb, NULL, 7, &hsi );
274c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to open summaryinfo %u\n", r );
275c2c66affSColin Finck 
276c2c66affSColin Finck     r = MsiSummaryInfoSetPropertyA( hsi, 2, VT_LPSTR, 0, NULL, "Installation Database" );
277c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
278c2c66affSColin Finck 
279c2c66affSColin Finck     r = MsiSummaryInfoSetPropertyA( hsi, 3, VT_LPSTR, 0, NULL, "Installation Database" );
280c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
281c2c66affSColin Finck 
282c2c66affSColin Finck     r = MsiSummaryInfoSetPropertyA( hsi, 4, VT_LPSTR, 0, NULL, "WineHQ" );
283c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
284c2c66affSColin Finck 
285c2c66affSColin Finck     r = MsiSummaryInfoSetPropertyA( hsi, 7, VT_LPSTR, 0, NULL, ";1033" );
286c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
287c2c66affSColin Finck 
288c2c66affSColin Finck     r = MsiSummaryInfoSetPropertyA( hsi, 9, VT_LPSTR, 0, NULL, "{E528DDD6-4801-4BEC-BBB6-C5EE0FD097E9}" );
289c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
290c2c66affSColin Finck 
291c2c66affSColin Finck     r = MsiSummaryInfoSetPropertyA( hsi, 14, VT_I4, 100, NULL, NULL );
292c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
293c2c66affSColin Finck 
294c2c66affSColin Finck     r = MsiSummaryInfoSetPropertyA( hsi, 15, VT_I4, 0, NULL, NULL );
295c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
296c2c66affSColin Finck 
297c2c66affSColin Finck     r = MsiSummaryInfoPersist( hsi );
298c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to persist suminfo %u\n", r );
299c2c66affSColin Finck 
300c2c66affSColin Finck     r = MsiCloseHandle( hsi );
301c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to close suminfo %u\n", r );
302c2c66affSColin Finck 
303c2c66affSColin Finck     r = MsiCloseHandle( hdb );
304c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to close database %u\n", r );
305c2c66affSColin Finck }
306c2c66affSColin Finck 
307c2c66affSColin Finck static void create_database( const char *filename, const struct msi_table *tables, UINT num_tables )
308c2c66affSColin Finck {
309c2c66affSColin Finck     MSIHANDLE hdb;
310c2c66affSColin Finck     UINT r, i;
311c2c66affSColin Finck     WCHAR *filenameW;
312c2c66affSColin Finck     int len;
313c2c66affSColin Finck 
314c2c66affSColin Finck     len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
315c2c66affSColin Finck     if (!(filenameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return;
316c2c66affSColin Finck     MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
317c2c66affSColin Finck 
318c2c66affSColin Finck     r = MsiOpenDatabaseW( filenameW, MSIDBOPEN_CREATE, &hdb );
319c2c66affSColin Finck     ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
320c2c66affSColin Finck 
321c2c66affSColin Finck     /* import the tables into the database */
322c2c66affSColin Finck     for (i = 0; i < num_tables; i++)
323c2c66affSColin Finck     {
324c2c66affSColin Finck         const struct msi_table *table = &tables[i];
325c2c66affSColin Finck 
326c2c66affSColin Finck         write_file( table->filename, table->data, (table->size - 1) * sizeof(char) );
327c2c66affSColin Finck 
328c2c66affSColin Finck         r = MsiDatabaseImportA( hdb, CURR_DIR, table->filename );
329c2c66affSColin Finck         ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
330c2c66affSColin Finck 
331c2c66affSColin Finck         DeleteFileA( table->filename );
332c2c66affSColin Finck     }
333c2c66affSColin Finck 
334c2c66affSColin Finck     r = MsiDatabaseCommit( hdb );
335c2c66affSColin Finck     ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
336c2c66affSColin Finck 
337c2c66affSColin Finck     MsiCloseHandle( hdb );
338c2c66affSColin Finck     set_suminfo( filenameW );
339c2c66affSColin Finck     HeapFree( GetProcessHeap(), 0, filenameW );
340c2c66affSColin Finck }
341c2c66affSColin Finck 
342c2c66affSColin Finck /* data for generating a patch */
343c2c66affSColin Finck 
344c2c66affSColin Finck /* table names - encoded as in an msi database file */
345c2c66affSColin Finck static const WCHAR p_name0[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
346c2c66affSColin Finck static const WCHAR p_name1[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
347c2c66affSColin Finck static const WCHAR p_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
348c2c66affSColin Finck static const WCHAR p_name3[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
349c2c66affSColin Finck static const WCHAR p_name4[] = { 0x3a8c, 0x47cb, 0x45b0, 0x45ec, 0x45a8, 0x4837, 0}; /* CAB_msitest */
350c2c66affSColin Finck static const WCHAR p_name5[] = { 0x4840, 0x4596, 0x3e6c, 0x45e4, 0x42e6, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* MsiPatchSequence */
351c2c66affSColin Finck static const WCHAR p_name6[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
352c2c66affSColin Finck                                  0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
353c2c66affSColin Finck                                  0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
354c2c66affSColin Finck /* substorage names */
355c2c66affSColin Finck static const WCHAR p_name7[] = { 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075, 0x0070,
356c2c66affSColin Finck                                  0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* targetToupgraded */
357c2c66affSColin Finck static const WCHAR p_name8[] = { 0x0023, 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075,
358c2c66affSColin Finck                                  0x0070, 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* #targetToupgraded */
359c2c66affSColin Finck 
360c2c66affSColin Finck /* data in each table */
361c2c66affSColin Finck static const WCHAR p_data0[] = { /* _Columns */
362c2c66affSColin Finck     0x0001, 0x0001, 0x0001, 0x0001, 0x8001, 0x8002, 0x8003, 0x8004,
363c2c66affSColin Finck     0x0002, 0x0003, 0x0004, 0x0005, 0xad00, 0xbd26, 0x8d00, 0x9502
364c2c66affSColin Finck };
365c2c66affSColin Finck static const WCHAR p_data1[] = { /* _Tables */
366c2c66affSColin Finck     0x0001
367c2c66affSColin Finck };
368c2c66affSColin Finck static const char p_data2[] = { /* _StringData */
369c2c66affSColin Finck     "MsiPatchSequencePatchFamilyProductCodeSequenceAttributes1.1.19388.37230913B8D18FBB64CACA239C74C11E3FA74"
370c2c66affSColin Finck };
371c2c66affSColin Finck static const WCHAR p_data3[] = { /* _StringPool */
372c2c66affSColin Finck /* len, refs */
373c2c66affSColin Finck      0,  0,     /* string 0 '' */
374c2c66affSColin Finck     16,  5,     /* string 1 'MsiPatchSequence' */
375c2c66affSColin Finck     11,  1,     /* string 2 'PatchFamily' */
376c2c66affSColin Finck     11,  1,     /* string 3 'ProductCode' */
377c2c66affSColin Finck      8,  1,     /* string 4 'Sequence' */
378c2c66affSColin Finck     10,  1,     /* string 5 'Attributes' */
379c2c66affSColin Finck     15,  1,     /* string 6 '1.1.19388.37230' */
380c2c66affSColin Finck     32,  1,     /* string 7 '913B8D18FBB64CACA239C74C11E3FA74' */
381c2c66affSColin Finck };
382c2c66affSColin Finck static const char p_data4[] = { /* CAB_msitest */
383*8bb4f059Swinesync     0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00,
384c2c66affSColin Finck     0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00,
385*8bb4f059Swinesync     0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
386*8bb4f059Swinesync     0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
387c2c66affSColin Finck     0xea, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87,
388*8bb4f059Swinesync     0x3c, 0xd4, 0xb8, 0x20, 0x00, 0x70, 0x61, 0x74, 0x63, 0x68, 0x2e,
389*8bb4f059Swinesync     0x74, 0x78, 0x74, 0x00, 0xe8, 0x03, 0x00, 0x00, 0xea, 0x03, 0x00,
390*8bb4f059Swinesync     0x00, 0x00, 0x00, 0xcb, 0x50, 0x17, 0x7e, 0x20, 0x00, 0x66, 0x69,
391*8bb4f059Swinesync     0x6c, 0x65, 0x2e, 0x74, 0x78, 0x74, 0x00, 0xb0, 0xb2, 0xb2, 0x25,
392*8bb4f059Swinesync     0x2d, 0x00, 0xd2, 0x07, 0x43, 0x4b, 0xcb, 0x2d, 0xce, 0x2c, 0x49,
393*8bb4f059Swinesync     0x2d, 0x2e, 0x89, 0x29, 0x48, 0x2c, 0x49, 0xce, 0x48, 0x4d, 0xd1,
394*8bb4f059Swinesync     0x2b, 0xa9, 0x28, 0x51, 0x18, 0x05, 0xa3, 0x60, 0x14, 0x0c, 0x37,
395*8bb4f059Swinesync     0x90, 0x8b, 0x9c, 0xd3, 0x41, 0xf9, 0x9c, 0x61, 0x14, 0x8c, 0x82,
396*8bb4f059Swinesync     0x51, 0x30, 0xdc, 0x00, 0x00
397c2c66affSColin Finck };
398c2c66affSColin Finck static const WCHAR p_data5[] = { /* MsiPatchSequence */
399c2c66affSColin Finck     0x0007, 0x0000, 0x0006, 0x8000
400c2c66affSColin Finck };
401c2c66affSColin Finck static const char p_data6[] = { /* SummaryInformation */
402c2c66affSColin Finck     0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
403c2c66affSColin Finck     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
404c2c66affSColin Finck     0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
405c2c66affSColin Finck     0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
406c2c66affSColin Finck     0x30, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
407c2c66affSColin Finck     0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00,
408c2c66affSColin Finck     0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x90,
409c2c66affSColin Finck     0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
410c2c66affSColin Finck     0x0f, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
411c2c66affSColin Finck     0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x30, 0x46, 0x39, 0x36, 0x43,
412c2c66affSColin Finck     0x44, 0x43, 0x30, 0x2d, 0x34, 0x43, 0x44, 0x46, 0x2d, 0x34, 0x33,
413c2c66affSColin Finck     0x30, 0x34, 0x2d, 0x42, 0x32, 0x38, 0x33, 0x2d, 0x37, 0x42, 0x39,
414c2c66affSColin Finck     0x32, 0x36, 0x34, 0x38, 0x38, 0x39, 0x45, 0x46, 0x37, 0x7d, 0x00,
415c2c66affSColin Finck     0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x39,
416c2c66affSColin Finck     0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42,
417c2c66affSColin Finck     0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39,
418c2c66affSColin Finck     0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41,
419c2c66affSColin Finck     0x37, 0x34, 0x7d, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x25, 0x00,
420c2c66affSColin Finck     0x00, 0x00, 0x3a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f,
421c2c66affSColin Finck     0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x3b, 0x3a, 0x23,
422c2c66affSColin Finck     0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f, 0x75, 0x70, 0x67,
423c2c66affSColin Finck     0x72, 0x61, 0x64, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
424c2c66affSColin Finck     0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x50, 0x61, 0x74, 0x63, 0x68,
425c2c66affSColin Finck     0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x00,
426c2c66affSColin Finck     0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
427c2c66affSColin Finck };
428c2c66affSColin Finck 
429c2c66affSColin Finck struct table_data {
430c2c66affSColin Finck     LPCWSTR name;
431c2c66affSColin Finck     const void *data;
432c2c66affSColin Finck     DWORD size;
433c2c66affSColin Finck };
434c2c66affSColin Finck 
435c2c66affSColin Finck static const struct table_data table_patch_data[] = {
436c2c66affSColin Finck     { p_name0, p_data0, sizeof p_data0 },
437c2c66affSColin Finck     { p_name1, p_data1, sizeof p_data1 },
438c2c66affSColin Finck     { p_name2, p_data2, sizeof p_data2 - 1 },
439c2c66affSColin Finck     { p_name3, p_data3, sizeof p_data3 },
440c2c66affSColin Finck     { p_name4, p_data4, sizeof p_data4 },
441c2c66affSColin Finck     { p_name5, p_data5, sizeof p_data5 },
442c2c66affSColin Finck     { p_name6, p_data6, sizeof p_data6 }
443c2c66affSColin Finck };
444c2c66affSColin Finck 
445c2c66affSColin Finck static const WCHAR t1_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
446c2c66affSColin Finck static const WCHAR t1_name1[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
447c2c66affSColin Finck static const WCHAR t1_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
448c2c66affSColin Finck static const WCHAR t1_name3[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
449c2c66affSColin Finck                                   0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
450c2c66affSColin Finck                                   0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
451c2c66affSColin Finck 
452c2c66affSColin Finck static const WCHAR t1_data0[] = { /* File */
453c2c66affSColin Finck     0x0008, 0x0001, 0x03ea, 0x8000
454c2c66affSColin Finck };
455c2c66affSColin Finck static const char t1_data1[] = { /* _StringData */
456c2c66affSColin Finck     "patch.txt"
457c2c66affSColin Finck };
458c2c66affSColin Finck static const WCHAR t1_data2[] = { /* _StringPool */
459c2c66affSColin Finck /* len, refs */
460c2c66affSColin Finck      0,  0,     /* string 0 '' */
461c2c66affSColin Finck      9,  1,     /* string 1 'patch.txt' */
462c2c66affSColin Finck };
463c2c66affSColin Finck static const char t1_data3[] = { /* SummaryInformation */
464c2c66affSColin Finck     0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
465c2c66affSColin Finck     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
466c2c66affSColin Finck     0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
467c2c66affSColin Finck     0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
468c2c66affSColin Finck     0x30, 0x00, 0x00, 0x00, 0x9f, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00,
469c2c66affSColin Finck     0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00,
470c2c66affSColin Finck     0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa8,
471c2c66affSColin Finck     0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00,
472c2c66affSColin Finck     0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
473c2c66affSColin Finck     0x00, 0xd0, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x00,
474c2c66affSColin Finck     0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x08,
475c2c66affSColin Finck     0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
476c2c66affSColin Finck     0x07, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8f, 0x01, 0x00,
477c2c66affSColin Finck     0x00, 0x10, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00, 0x1e, 0x00,
478c2c66affSColin Finck     0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61,
479c2c66affSColin Finck     0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74,
480c2c66affSColin Finck     0x61, 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
481c2c66affSColin Finck     0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c,
482c2c66affSColin Finck     0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74, 0x61,
483c2c66affSColin Finck     0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
484c2c66affSColin Finck     0x07, 0x00, 0x00, 0x00, 0x57, 0x69, 0x6e, 0x65, 0x48, 0x51, 0x00,
485c2c66affSColin Finck     0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
486c2c66affSColin Finck     0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
487c2c66affSColin Finck     0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
488c2c66affSColin Finck     0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
489c2c66affSColin Finck     0x00, 0x1e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x78, 0x38,
490c2c66affSColin Finck     0x36, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x00,
491c2c66affSColin Finck     0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33,
492c2c66affSColin Finck     0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
493c2c66affSColin Finck     0x7b, 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46,
494c2c66affSColin Finck     0x42, 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32,
495c2c66affSColin Finck     0x33, 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33,
496c2c66affSColin Finck     0x46, 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b,
497c2c66affSColin Finck     0x7b, 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46,
498c2c66affSColin Finck     0x42, 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32,
499c2c66affSColin Finck     0x33, 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33,
500c2c66affSColin Finck     0x46, 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b,
501c2c66affSColin Finck     0x7b, 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34,
502c2c66affSColin Finck     0x45, 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33,
503c2c66affSColin Finck     0x30, 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44,
504c2c66affSColin Finck     0x35, 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
505c2c66affSColin Finck     0x64, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22,
506c2c66affSColin Finck     0x09
507c2c66affSColin Finck };
508c2c66affSColin Finck 
509c2c66affSColin Finck static const struct table_data table_transform1_data[] = {
510c2c66affSColin Finck     { t1_name0, t1_data0, sizeof t1_data0 },
511c2c66affSColin Finck     { t1_name1, t1_data1, sizeof t1_data1 - 1 },
512c2c66affSColin Finck     { t1_name2, t1_data2, sizeof t1_data2 },
513c2c66affSColin Finck     { t1_name3, t1_data3, sizeof t1_data3 }
514c2c66affSColin Finck };
515c2c66affSColin Finck 
516c2c66affSColin Finck static const WCHAR t2_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
517c2c66affSColin Finck static const WCHAR t2_name1[] = { 0x4840, 0x4216, 0x4327, 0x4824, 0 }; /* Media */
518c2c66affSColin Finck static const WCHAR t2_name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
519c2c66affSColin Finck static const WCHAR t2_name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
520c2c66affSColin Finck static const WCHAR t2_name4[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
521c2c66affSColin Finck static const WCHAR t2_name5[] = { 0x4840, 0x4119, 0x41b7, 0x3e6b, 0x41a4, 0x412e, 0x422a, 0 }; /* PatchPackage */
522c2c66affSColin Finck static const WCHAR t2_name6[] = { 0x4840, 0x4452, 0x45f6, 0x43e4, 0x3baf, 0x423b, 0x4626,
523c2c66affSColin Finck                                   0x4237, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* InstallExecuteSequence */
524c2c66affSColin Finck static const WCHAR t2_name7[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
525c2c66affSColin Finck static const WCHAR t2_name8[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
526c2c66affSColin Finck static const WCHAR t2_name9[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
527c2c66affSColin Finck                                   0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
528c2c66affSColin Finck                                   0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
529*8bb4f059Swinesync static const WCHAR t2_name10[] = { 0x4840, 0x420f, 0x45e4, 0x4578, 0x3b28, 0x4432, 0x44b3,
530*8bb4f059Swinesync                                    0x4231, 0x45f1, 0x4836, 0 }; /* FeatureComponents */
531*8bb4f059Swinesync static const WCHAR t2_name11[] = { 0x4840, 0x448c, 0x44f0, 0x4472, 0x4468, 0x4837, 0 }; /* Component */
532*8bb4f059Swinesync static const WCHAR t2_name12[] = { 0x4840, 0x420f, 0x45e4, 0x4578, 0x4828, 0 }; /* Feature */
533c2c66affSColin Finck 
534c2c66affSColin Finck static const WCHAR t2_data0[] = { /* File */
535*8bb4f059Swinesync     0x00c0, 0x0001, 0x9000, 0x83e8, 0x0801, 0x0002, 0x0003, 0x0002,
536*8bb4f059Swinesync     0x03e8, 0x8000, 0x0000, 0x0000, 0x9000, 0x83e9
537c2c66affSColin Finck };
538c2c66affSColin Finck static const WCHAR t2_data1[] = { /* Media */
539*8bb4f059Swinesync     0x0601, 0x8002, 0x03e9, 0x8000, 0x0000, 0x000d, 0x0000, 0x000e
540c2c66affSColin Finck };
541c2c66affSColin Finck static const WCHAR t2_data2[] = { /* _Columns */
542*8bb4f059Swinesync     0x0401, 0x000f, 0x0000, 0x0010, 0xad48, 0x0401, 0x000f, 0x0000, /* 0x0401 = add row (1), 4 shorts */
543*8bb4f059Swinesync     0x0011, 0xa502, 0x0401, 0x000f, 0x0000, 0x0012, 0x8104, 0x0401,
544*8bb4f059Swinesync     0x000f, 0x0000, 0x0013, 0x8502, 0x0401, 0x000f, 0x0000, 0x0014,
545*8bb4f059Swinesync     0x9900, 0x0401, 0x000f, 0x0000, 0x0015, 0x9d48, 0x0401, 0x0016,
546*8bb4f059Swinesync     0x0000, 0x0017, 0xad26, 0x0401, 0x0016, 0x0000, 0x0018, 0x8502,
547*8bb4f059Swinesync     0x0401, 0x001a, 0x0000, 0x001b, 0xad26, 0x0401, 0x001a, 0x0000,
548*8bb4f059Swinesync     0x0014, 0x8900
549c2c66affSColin Finck };
550c2c66affSColin Finck static const WCHAR t2_data3[] = { /* _Tables */
551*8bb4f059Swinesync     0x0101, 0x000f, 0x0101, 0x0016, 0x0101, 0x001a
552c2c66affSColin Finck };
553c2c66affSColin Finck static const WCHAR t2_data4[] = { /* Property */
554*8bb4f059Swinesync     0x0002, 0x0008, 0x0009, 0x0201, 0x000a, 0x000b
555c2c66affSColin Finck };
556c2c66affSColin Finck static const WCHAR t2_data5[] = { /* PatchPackage */
557*8bb4f059Swinesync     0x0201, 0x0019, 0x8002
558c2c66affSColin Finck };
559c2c66affSColin Finck static const WCHAR t2_data6[] = { /* InstallExecuteSequence */
560*8bb4f059Swinesync     0x0301, 0x000c, 0x0000, 0x87d1
561c2c66affSColin Finck };
562c2c66affSColin Finck static const char t2_data7[] = { /* _StringData */
563*8bb4f059Swinesync     "patch.txtfile.txtfile{327d9640-674f-4b9f-8b8a-547a0f6f8518}MSITESTDIRnewnew featurePATCHNEWSUMMARYSUBJECT"
564*8bb4f059Swinesync     "Installation DatabasePATCHNEWPACKAGECODE{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}PatchFiles#CAB_msitestprop"
565*8bb4f059Swinesync     "PatchFile_SequencePatchSizeAttributesHeaderStreamRef_PatchPackagePatchIdMedia_"
566c2c66affSColin Finck     "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}MsiPatchHeadersStreamRef"
567c2c66affSColin Finck };
568c2c66affSColin Finck static const WCHAR t2_data8[] = { /* _StringPool */
569c2c66affSColin Finck /* len, refs */
570c2c66affSColin Finck      0,  0,     /* string 0 '' */
571c2c66affSColin Finck      9,  1,     /* string 1 'patch.txt' */
572*8bb4f059Swinesync      8,  3,     /* string 2 'file.txt' */
573*8bb4f059Swinesync      4,  3,     /* string 3 'file' */
574*8bb4f059Swinesync     38,  1,     /* string 4 '{327d9640-674f-4b9f-8b8a-547a0f6f8518}' */
575*8bb4f059Swinesync     10,  2,     /* string 5 'MSITESTDIR' */
576*8bb4f059Swinesync      3,  2,     /* string 6 'new' */
577*8bb4f059Swinesync     11,  1,     /* string 7 'new feature' */
578*8bb4f059Swinesync     22,  1,     /* string 8 'PATCHNEWSUMMARYSUBJECT' */
579*8bb4f059Swinesync     21,  1,     /* string 9 'Installation Database' */
580*8bb4f059Swinesync     19,  1,     /* string 10 'PATCHNEWPACKAGECODE' */
581*8bb4f059Swinesync     38,  1,     /* string 11 '{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}' */
582*8bb4f059Swinesync     10,  1,     /* string 12 'PatchFiles' */
583*8bb4f059Swinesync     12,  1,     /* string 13 '#CAB_msitest' */
584*8bb4f059Swinesync      4,  1,     /* string 14 'prop' */
585*8bb4f059Swinesync      5,  7,     /* string 15 'Patch' */
586*8bb4f059Swinesync      5,  1,     /* string 16 'File_' */
587*8bb4f059Swinesync      8,  1,     /* string 17 'Sequence' */
588*8bb4f059Swinesync      9,  1,     /* string 18 'PatchSize' */
589*8bb4f059Swinesync     10,  1,     /* string 19 'Attributes' */
590*8bb4f059Swinesync      6,  2,     /* string 20 'Header' */
591*8bb4f059Swinesync     10,  1,     /* string 21 'StreamRef_' */
592*8bb4f059Swinesync     12,  3,     /* string 22 'PatchPackage' */
593*8bb4f059Swinesync      7,  1,     /* string 23 'PatchId' */
594*8bb4f059Swinesync      6,  1,     /* string 24 'Media_' */
595*8bb4f059Swinesync     38,  1,     /* string 25 '{0F96CDC0-4CDF-4304-B283-7B9264889EF7}' */
596*8bb4f059Swinesync     15,  3,     /* string 26 'MsiPatchHeaders' */
597*8bb4f059Swinesync      9,  1      /* string 27 'StreamRef' */
598c2c66affSColin Finck };
599c2c66affSColin Finck static const char t2_data9[] = { /* SummaryInformation */
600c2c66affSColin Finck     0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
601c2c66affSColin Finck     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
602c2c66affSColin Finck     0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
603c2c66affSColin Finck     0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
604c2c66affSColin Finck     0x30, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00,
605c2c66affSColin Finck     0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00,
606c2c66affSColin Finck     0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x78,
607c2c66affSColin Finck     0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
608c2c66affSColin Finck     0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
609c2c66affSColin Finck     0x00, 0x9c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00,
610c2c66affSColin Finck     0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x09,
611c2c66affSColin Finck     0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
612c2c66affSColin Finck     0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00,
613c2c66affSColin Finck     0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
614c2c66affSColin Finck     0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
615c2c66affSColin Finck     0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
616c2c66affSColin Finck     0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
617c2c66affSColin Finck     0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00,
618c2c66affSColin Finck     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01,
619c2c66affSColin Finck     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
620c2c66affSColin Finck     0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00,
621c2c66affSColin Finck     0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
622c2c66affSColin Finck     0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b,
623c2c66affSColin Finck     0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
624c2c66affSColin Finck     0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
625c2c66affSColin Finck     0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
626c2c66affSColin Finck     0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
627c2c66affSColin Finck     0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
628c2c66affSColin Finck     0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
629c2c66affSColin Finck     0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
630c2c66affSColin Finck     0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
631c2c66affSColin Finck     0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45,
632c2c66affSColin Finck     0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30,
633c2c66affSColin Finck     0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35,
634c2c66affSColin Finck     0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2d,
635c2c66affSColin Finck     0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x27, 0x09
636c2c66affSColin Finck };
637*8bb4f059Swinesync static const WCHAR t2_data10[] = { /* FeatureComponents */
638*8bb4f059Swinesync     0x0201, 0x0006, 0x0003
639*8bb4f059Swinesync };
640*8bb4f059Swinesync static const WCHAR t2_data11[] = { /* Component */
641*8bb4f059Swinesync     0x0601, 0x0003, 0x0004, 0x0005, 0x8000, 0x0000, 0x0002
642*8bb4f059Swinesync };
643*8bb4f059Swinesync static const WCHAR t2_data12[] = { /* Feature */
644*8bb4f059Swinesync     0x0801, 0x0006, 0x0000, 0x0000, 0x0007, 0x8001, 0x8001, 0x0005,
645*8bb4f059Swinesync     0x8000
646*8bb4f059Swinesync };
647c2c66affSColin Finck 
648c2c66affSColin Finck static const struct table_data table_transform2_data[] = {
649c2c66affSColin Finck     { t2_name0, t2_data0, sizeof t2_data0 },
650c2c66affSColin Finck     { t2_name1, t2_data1, sizeof t2_data1 },
651c2c66affSColin Finck     { t2_name2, t2_data2, sizeof t2_data2 },
652c2c66affSColin Finck     { t2_name3, t2_data3, sizeof t2_data3 },
653c2c66affSColin Finck     { t2_name4, t2_data4, sizeof t2_data4 },
654c2c66affSColin Finck     { t2_name5, t2_data5, sizeof t2_data5 },
655c2c66affSColin Finck     { t2_name6, t2_data6, sizeof t2_data6 },
656c2c66affSColin Finck     { t2_name7, t2_data7, sizeof t2_data7 - 1 },
657c2c66affSColin Finck     { t2_name8, t2_data8, sizeof t2_data8 },
658*8bb4f059Swinesync     { t2_name9, t2_data9, sizeof t2_data9 },
659*8bb4f059Swinesync     { t2_name10, t2_data10, sizeof t2_data10 },
660*8bb4f059Swinesync     { t2_name11, t2_data11, sizeof t2_data11 },
661*8bb4f059Swinesync     { t2_name12, t2_data12, sizeof t2_data12 },
662c2c66affSColin Finck };
663c2c66affSColin Finck 
664c2c66affSColin Finck static void write_tables( IStorage *stg, const struct table_data *tables, UINT num_tables )
665c2c66affSColin Finck {
666c2c66affSColin Finck     IStream *stm;
667c2c66affSColin Finck     DWORD i, count;
668c2c66affSColin Finck     HRESULT r;
669c2c66affSColin Finck 
670c2c66affSColin Finck     for (i = 0; i < num_tables; i++)
671c2c66affSColin Finck     {
672c2c66affSColin Finck         r = IStorage_CreateStream( stg, tables[i].name, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
673c2c66affSColin Finck         if (FAILED( r ))
674c2c66affSColin Finck         {
675c2c66affSColin Finck             ok( 0, "failed to create stream 0x%08x\n", r );
676c2c66affSColin Finck             continue;
677c2c66affSColin Finck         }
678c2c66affSColin Finck 
679c2c66affSColin Finck         r = IStream_Write( stm, tables[i].data, tables[i].size, &count );
680c2c66affSColin Finck         if (FAILED( r ) || count != tables[i].size)
681c2c66affSColin Finck             ok( 0, "failed to write stream\n" );
682c2c66affSColin Finck         IStream_Release( stm );
683c2c66affSColin Finck     }
684c2c66affSColin Finck }
685c2c66affSColin Finck 
686c2c66affSColin Finck static void create_patch( const char *filename )
687c2c66affSColin Finck {
688c2c66affSColin Finck     IStorage *stg = NULL, *stg1 = NULL, *stg2 = NULL;
689c2c66affSColin Finck     WCHAR *filenameW;
690c2c66affSColin Finck     HRESULT r;
691c2c66affSColin Finck     int len;
692c2c66affSColin Finck     const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
693c2c66affSColin Finck 
694c2c66affSColin Finck     const CLSID CLSID_MsiPatch = {0xc1086, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
695c2c66affSColin Finck     const CLSID CLSID_MsiTransform = {0xc1082, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
696c2c66affSColin Finck 
697c2c66affSColin Finck     len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
698c2c66affSColin Finck     filenameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
699c2c66affSColin Finck     MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
700c2c66affSColin Finck 
701c2c66affSColin Finck     r = StgCreateDocfile( filenameW, mode, 0, &stg );
702c2c66affSColin Finck     HeapFree( GetProcessHeap(), 0, filenameW );
703c2c66affSColin Finck     ok( r == S_OK, "failed to create storage 0x%08x\n", r );
704c2c66affSColin Finck     if (!stg)
705c2c66affSColin Finck         return;
706c2c66affSColin Finck 
707c2c66affSColin Finck     r = IStorage_SetClass( stg, &CLSID_MsiPatch );
708c2c66affSColin Finck     ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
709c2c66affSColin Finck 
71042961bd8Swinesync     write_tables( stg, table_patch_data, ARRAY_SIZE( table_patch_data ));
711c2c66affSColin Finck 
712c2c66affSColin Finck     r = IStorage_CreateStorage( stg, p_name7, mode, 0, 0, &stg1 );
713c2c66affSColin Finck     ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
714c2c66affSColin Finck 
715c2c66affSColin Finck     r = IStorage_SetClass( stg1, &CLSID_MsiTransform );
716c2c66affSColin Finck     ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
717c2c66affSColin Finck 
71842961bd8Swinesync     write_tables( stg1, table_transform1_data, ARRAY_SIZE( table_transform1_data ));
719c2c66affSColin Finck     IStorage_Release( stg1 );
720c2c66affSColin Finck 
721c2c66affSColin Finck     r = IStorage_CreateStorage( stg, p_name8, mode, 0, 0, &stg2 );
722c2c66affSColin Finck     ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
723c2c66affSColin Finck 
724c2c66affSColin Finck     r = IStorage_SetClass( stg2, &CLSID_MsiTransform );
725c2c66affSColin Finck     ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
726c2c66affSColin Finck 
72742961bd8Swinesync     write_tables( stg2, table_transform2_data, ARRAY_SIZE( table_transform2_data ));
728c2c66affSColin Finck     IStorage_Release( stg2 );
729c2c66affSColin Finck     IStorage_Release( stg );
730c2c66affSColin Finck }
731c2c66affSColin Finck 
732c2c66affSColin Finck static void test_simple_patch( void )
733c2c66affSColin Finck {
734c2c66affSColin Finck     UINT r;
735c2c66affSColin Finck     DWORD size;
736c2c66affSColin Finck     char path[MAX_PATH], install_source[MAX_PATH], buffer[32];
737c2c66affSColin Finck     const char *query;
738c2c66affSColin Finck     WCHAR pathW[MAX_PATH];
739c2c66affSColin Finck     MSIHANDLE hpackage, hdb, hview, hrec;
740c2c66affSColin Finck 
741c2c66affSColin Finck     if (!pMsiApplyPatchA)
742c2c66affSColin Finck     {
743c2c66affSColin Finck         win_skip("MsiApplyPatchA is not available\n");
744c2c66affSColin Finck         return;
745c2c66affSColin Finck     }
746c2c66affSColin Finck     if (is_process_limited())
747c2c66affSColin Finck     {
748c2c66affSColin Finck         skip("process is limited\n");
749c2c66affSColin Finck         return;
750c2c66affSColin Finck     }
751c2c66affSColin Finck 
752c2c66affSColin Finck     CreateDirectoryA( "msitest", NULL );
753c2c66affSColin Finck     create_file( "msitest\\patch.txt", 1000 );
754c2c66affSColin Finck 
75586676451Swinesync     create_database( msifile, tables, ARRAY_SIZE(tables) );
756c2c66affSColin Finck     create_patch( mspfile );
757c2c66affSColin Finck 
758c2c66affSColin Finck     MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
759c2c66affSColin Finck 
760c2c66affSColin Finck     r = MsiInstallProductA( msifile, NULL );
761c2c66affSColin Finck     if (r != ERROR_SUCCESS)
762c2c66affSColin Finck     {
763c2c66affSColin Finck         skip("Product installation failed with error code %u\n", r);
764c2c66affSColin Finck         goto cleanup;
765c2c66affSColin Finck     }
766c2c66affSColin Finck 
767c2c66affSColin Finck     size = get_pf_file_size( "msitest\\patch.txt" );
768c2c66affSColin Finck     ok( size == 1000, "expected 1000, got %u\n", size );
769c2c66affSColin Finck 
770c2c66affSColin Finck     size = sizeof(install_source);
771c2c66affSColin Finck     r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
772c2c66affSColin Finck                             "InstallSource", install_source, &size );
773c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
774c2c66affSColin Finck 
775c2c66affSColin Finck     strcpy( path, CURR_DIR );
776c2c66affSColin Finck     strcat( path, "\\" );
777c2c66affSColin Finck     strcat( path, msifile );
778c2c66affSColin Finck 
779c2c66affSColin Finck     r = MsiOpenPackageA( path, &hpackage );
780c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
781c2c66affSColin Finck 
782c2c66affSColin Finck     hdb = MsiGetActiveDatabase( hpackage );
783c2c66affSColin Finck     ok( hdb, "failed to get database handle\n" );
784c2c66affSColin Finck 
785c2c66affSColin Finck     query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
786c2c66affSColin Finck     r = MsiDatabaseOpenViewA( hdb, query, &hview );
787c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
788c2c66affSColin Finck 
789c2c66affSColin Finck     r = MsiViewExecute( hview, 0 );
790c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
791c2c66affSColin Finck 
792c2c66affSColin Finck     r = MsiViewFetch( hview, &hrec );
793c2c66affSColin Finck     ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
794c2c66affSColin Finck 
795c2c66affSColin Finck     MsiCloseHandle( hrec );
796c2c66affSColin Finck     MsiViewClose( hview );
797c2c66affSColin Finck     MsiCloseHandle( hview );
798c2c66affSColin Finck 
799c2c66affSColin Finck     query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
800c2c66affSColin Finck             "AND `Value` = 'Installer Database'";
801c2c66affSColin Finck     r = MsiDatabaseOpenViewA( hdb, query, &hview );
802c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
803c2c66affSColin Finck 
804c2c66affSColin Finck     r = MsiViewExecute( hview, 0 );
805c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
806c2c66affSColin Finck 
807c2c66affSColin Finck     r = MsiViewFetch( hview, &hrec );
808c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
809c2c66affSColin Finck 
810c2c66affSColin Finck     MsiCloseHandle( hrec );
811c2c66affSColin Finck     MsiViewClose( hview );
812c2c66affSColin Finck     MsiCloseHandle( hview );
813c2c66affSColin Finck 
814c2c66affSColin Finck     buffer[0] = 0;
815c2c66affSColin Finck     size = sizeof(buffer);
816c2c66affSColin Finck     r = MsiGetPropertyA( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
817c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
818c2c66affSColin Finck     ok( !strcmp( buffer, "Installer Database" ), "expected \'Installer Database\', got \'%s\'\n", buffer );
819c2c66affSColin Finck 
820c2c66affSColin Finck     MsiCloseHandle( hdb );
821c2c66affSColin Finck     MsiCloseHandle( hpackage );
822c2c66affSColin Finck 
823c2c66affSColin Finck     r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
824c2c66affSColin Finck     ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
825c2c66affSColin Finck         "expected ERROR_SUCCESS, got %u\n", r );
826c2c66affSColin Finck 
827c2c66affSColin Finck     if (r == ERROR_PATCH_PACKAGE_INVALID)
828c2c66affSColin Finck     {
829c2c66affSColin Finck         win_skip("Windows Installer < 3.0 detected\n");
830c2c66affSColin Finck         goto uninstall;
831c2c66affSColin Finck     }
832c2c66affSColin Finck 
833c2c66affSColin Finck     size = get_pf_file_size( "msitest\\patch.txt" );
834c2c66affSColin Finck     ok( size == 1002, "expected 1002, got %u\n", size );
835*8bb4f059Swinesync     size = get_pf_file_size( "msitest\\file.txt" );
836*8bb4f059Swinesync     todo_wine ok( size == 1000, "expected 1000, got %u\n", size );
837c2c66affSColin Finck 
838c2c66affSColin Finck     /* show that MsiOpenPackage applies registered patches */
839c2c66affSColin Finck     r = MsiOpenPackageA( path, &hpackage );
840c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
841c2c66affSColin Finck 
842c2c66affSColin Finck     hdb = MsiGetActiveDatabase( hpackage );
843c2c66affSColin Finck     ok( hdb, "failed to get database handle\n" );
844c2c66affSColin Finck 
845c2c66affSColin Finck     query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
846c2c66affSColin Finck     r = MsiDatabaseOpenViewA( hdb, query, &hview );
847c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
848c2c66affSColin Finck 
849c2c66affSColin Finck     r = MsiViewExecute( hview, 0 );
850c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
851c2c66affSColin Finck 
852c2c66affSColin Finck     r = MsiViewFetch( hview, &hrec );
853c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
854c2c66affSColin Finck 
855c2c66affSColin Finck     MsiCloseHandle( hrec );
856c2c66affSColin Finck     MsiViewClose( hview );
857c2c66affSColin Finck     MsiCloseHandle( hview );
858c2c66affSColin Finck 
859c2c66affSColin Finck     query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
860c2c66affSColin Finck             "AND `Value` = 'Installation Database'";
861c2c66affSColin Finck     r = MsiDatabaseOpenViewA( hdb, query, &hview );
862c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
863c2c66affSColin Finck 
864c2c66affSColin Finck     r = MsiViewExecute( hview, 0 );
865c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
866c2c66affSColin Finck 
867c2c66affSColin Finck     r = MsiViewFetch( hview, &hrec );
868c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
869c2c66affSColin Finck 
870c2c66affSColin Finck     MsiCloseHandle( hrec );
871c2c66affSColin Finck     MsiViewClose( hview );
872c2c66affSColin Finck     MsiCloseHandle( hview );
873c2c66affSColin Finck 
874c2c66affSColin Finck     buffer[0] = 0;
875c2c66affSColin Finck     size = sizeof(buffer);
876c2c66affSColin Finck     r = MsiGetPropertyA( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
877c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
878c2c66affSColin Finck     ok( !strcmp( buffer, "Installation Database" ), "expected \'Installation Database\', got \'%s\'\n", buffer );
879c2c66affSColin Finck 
880c2c66affSColin Finck     MsiCloseHandle( hdb );
881c2c66affSColin Finck     MsiCloseHandle( hpackage );
882c2c66affSColin Finck 
883c2c66affSColin Finck     /* show that patches are not committed to the local package database */
884c2c66affSColin Finck     size = sizeof(path);
885c2c66affSColin Finck     r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
886c2c66affSColin Finck                             "LocalPackage", path, &size );
887c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
888c2c66affSColin Finck 
889c2c66affSColin Finck     MultiByteToWideChar( CP_ACP, 0, path, -1, pathW, MAX_PATH );
890c2c66affSColin Finck     r = MsiOpenDatabaseW( pathW, MSIDBOPEN_READONLY, &hdb );
891c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
892c2c66affSColin Finck 
893c2c66affSColin Finck     r = MsiDatabaseOpenViewA( hdb, query, &hview );
894c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
895c2c66affSColin Finck 
896c2c66affSColin Finck     r = MsiViewExecute( hview, 0 );
897c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
898c2c66affSColin Finck 
899c2c66affSColin Finck     r = MsiViewFetch( hview, &hrec );
900c2c66affSColin Finck     ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
901c2c66affSColin Finck 
902c2c66affSColin Finck     MsiCloseHandle( hrec );
903c2c66affSColin Finck     MsiViewClose( hview );
904c2c66affSColin Finck     MsiCloseHandle( hview );
905c2c66affSColin Finck     MsiCloseHandle( hdb );
906c2c66affSColin Finck 
907c2c66affSColin Finck uninstall:
908c2c66affSColin Finck     size = sizeof(path);
909c2c66affSColin Finck     r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
910c2c66affSColin Finck                             "InstallSource", path, &size );
911c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
912c2c66affSColin Finck     ok( !strcasecmp( path, install_source ), "wrong path %s\n", path );
913c2c66affSColin Finck 
914c2c66affSColin Finck     r = MsiInstallProductA( msifile, "REMOVE=ALL" );
915c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
916c2c66affSColin Finck 
917c2c66affSColin Finck     ok( !delete_pf( "msitest\\patch.txt", TRUE ), "file not removed\n" );
918*8bb4f059Swinesync     ok( !delete_pf( "msitest\\file.txt", TRUE ), "file not removed\n" );
919c2c66affSColin Finck     ok( !delete_pf( "msitest", FALSE ), "directory not removed\n" );
920c2c66affSColin Finck 
921c2c66affSColin Finck cleanup:
922c2c66affSColin Finck     DeleteFileA( msifile );
923c2c66affSColin Finck     DeleteFileA( mspfile );
924c2c66affSColin Finck     DeleteFileA( "msitest\\patch.txt" );
925c2c66affSColin Finck     RemoveDirectoryA( "msitest" );
926c2c66affSColin Finck }
927c2c66affSColin Finck 
928c2c66affSColin Finck static void test_MsiOpenDatabase( void )
929c2c66affSColin Finck {
930c2c66affSColin Finck     UINT r;
931c2c66affSColin Finck     MSIHANDLE hdb;
932c2c66affSColin Finck 
933c2c66affSColin Finck     r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_CREATE, &hdb );
934c2c66affSColin Finck     ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
935c2c66affSColin Finck 
936c2c66affSColin Finck     r = MsiDatabaseCommit( hdb );
937c2c66affSColin Finck     ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
938c2c66affSColin Finck     MsiCloseHandle( hdb );
939c2c66affSColin Finck 
940c2c66affSColin Finck     r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
941c2c66affSColin Finck     ok(r == ERROR_OPEN_FAILED, "expected ERROR_OPEN_FAILED, got %u\n", r);
942c2c66affSColin Finck     DeleteFileA( mspfile );
943c2c66affSColin Finck 
944c2c66affSColin Finck     r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_CREATE + MSIDBOPEN_PATCHFILE, &hdb );
945c2c66affSColin Finck     ok(r == ERROR_SUCCESS , "failed to open database %u\n", r);
946c2c66affSColin Finck 
947c2c66affSColin Finck     r = MsiDatabaseCommit( hdb );
948c2c66affSColin Finck     ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
949c2c66affSColin Finck     MsiCloseHandle( hdb );
950c2c66affSColin Finck 
951c2c66affSColin Finck     r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
952c2c66affSColin Finck     ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
953c2c66affSColin Finck     MsiCloseHandle( hdb );
954c2c66affSColin Finck     DeleteFileA( mspfile );
955c2c66affSColin Finck 
95686676451Swinesync     create_database( msifile, tables, ARRAY_SIZE(tables) );
957c2c66affSColin Finck     create_patch( mspfile );
958c2c66affSColin Finck 
959c2c66affSColin Finck     r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
960c2c66affSColin Finck     ok(r == ERROR_OPEN_FAILED, "failed to open database %u\n", r );
961c2c66affSColin Finck 
962c2c66affSColin Finck     r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
963c2c66affSColin Finck     ok(r == ERROR_SUCCESS, "failed to open database %u\n", r );
964c2c66affSColin Finck     MsiCloseHandle( hdb );
965c2c66affSColin Finck 
966c2c66affSColin Finck     DeleteFileA( msifile );
967c2c66affSColin Finck     DeleteFileA( mspfile );
968c2c66affSColin Finck }
969c2c66affSColin Finck 
970c2c66affSColin Finck static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry )
971c2c66affSColin Finck {
972c2c66affSColin Finck     static const char fmt[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
973c2c66affSColin Finck     char query[0x100];
974c2c66affSColin Finck     UINT r;
975c2c66affSColin Finck     MSIHANDLE hview, hrec;
976c2c66affSColin Finck 
977c2c66affSColin Finck     sprintf( query, fmt, table, entry );
978c2c66affSColin Finck     r = MsiDatabaseOpenViewA( hdb, query, &hview );
979c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
980c2c66affSColin Finck 
981c2c66affSColin Finck     r = MsiViewExecute( hview, 0 );
982c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
983c2c66affSColin Finck 
984c2c66affSColin Finck     r = MsiViewFetch( hview, &hrec );
985c2c66affSColin Finck     MsiViewClose( hview );
986c2c66affSColin Finck     MsiCloseHandle( hview );
987c2c66affSColin Finck     MsiCloseHandle( hrec );
988c2c66affSColin Finck     return r;
989c2c66affSColin Finck }
990c2c66affSColin Finck 
991c2c66affSColin Finck static UINT find_entryW( MSIHANDLE hdb, const WCHAR *table, const WCHAR *entry )
992c2c66affSColin Finck {
993c2c66affSColin Finck     static const WCHAR fmt[] =
994c2c66affSColin Finck         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',' ',
995c2c66affSColin Finck          'W','H','E','R','E',' ','`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0};
996c2c66affSColin Finck     WCHAR query[0x100];
997c2c66affSColin Finck     MSIHANDLE hview, hrec;
998c2c66affSColin Finck     UINT r;
999c2c66affSColin Finck 
1000c2c66affSColin Finck     wsprintfW( query, fmt, table, entry );
1001c2c66affSColin Finck     r = MsiDatabaseOpenViewW( hdb, query, &hview );
1002c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1003c2c66affSColin Finck 
1004c2c66affSColin Finck     r = MsiViewExecute( hview, 0 );
1005c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1006c2c66affSColin Finck 
1007c2c66affSColin Finck     r = MsiViewFetch( hview, &hrec );
1008c2c66affSColin Finck     MsiViewClose( hview );
1009c2c66affSColin Finck     MsiCloseHandle( hview );
1010c2c66affSColin Finck     MsiCloseHandle( hrec );
1011c2c66affSColin Finck     return r;
1012c2c66affSColin Finck }
1013c2c66affSColin Finck 
1014c2c66affSColin Finck static INT get_integer( MSIHANDLE hdb, UINT field, const char *query)
1015c2c66affSColin Finck {
1016c2c66affSColin Finck     UINT r;
1017c2c66affSColin Finck     INT ret = -1;
1018c2c66affSColin Finck     MSIHANDLE hview, hrec;
1019c2c66affSColin Finck 
1020c2c66affSColin Finck     r = MsiDatabaseOpenViewA( hdb, query, &hview );
1021c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1022c2c66affSColin Finck 
1023c2c66affSColin Finck     r = MsiViewExecute( hview, 0 );
1024c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1025c2c66affSColin Finck 
1026c2c66affSColin Finck     r = MsiViewFetch( hview, &hrec );
1027c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1028c2c66affSColin Finck     if (r == ERROR_SUCCESS)
1029c2c66affSColin Finck     {
1030c2c66affSColin Finck         UINT r_tmp;
1031c2c66affSColin Finck         ret = MsiRecordGetInteger( hrec, field );
1032c2c66affSColin Finck         MsiCloseHandle( hrec );
1033c2c66affSColin Finck 
1034c2c66affSColin Finck         r_tmp = MsiViewFetch( hview, &hrec );
1035c2c66affSColin Finck         ok( r_tmp == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r);
1036c2c66affSColin Finck     }
1037c2c66affSColin Finck 
1038c2c66affSColin Finck     MsiViewClose( hview );
1039c2c66affSColin Finck     MsiCloseHandle( hview );
1040c2c66affSColin Finck     return ret;
1041c2c66affSColin Finck }
1042c2c66affSColin Finck 
1043c2c66affSColin Finck static char *get_string( MSIHANDLE hdb, UINT field, const char *query)
1044c2c66affSColin Finck {
1045c2c66affSColin Finck     UINT r;
1046c2c66affSColin Finck     static char ret[MAX_PATH];
1047c2c66affSColin Finck     MSIHANDLE hview, hrec;
1048c2c66affSColin Finck 
1049c2c66affSColin Finck     ret[0] = '\0';
1050c2c66affSColin Finck 
1051c2c66affSColin Finck     r = MsiDatabaseOpenViewA( hdb, query, &hview );
1052c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1053c2c66affSColin Finck 
1054c2c66affSColin Finck     r = MsiViewExecute( hview, 0 );
1055c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1056c2c66affSColin Finck 
1057c2c66affSColin Finck     r = MsiViewFetch( hview, &hrec );
1058c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1059c2c66affSColin Finck     if (r == ERROR_SUCCESS)
1060c2c66affSColin Finck     {
1061c2c66affSColin Finck         UINT size = MAX_PATH;
1062c2c66affSColin Finck         r = MsiRecordGetStringA( hrec, field, ret, &size );
1063c2c66affSColin Finck         ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
1064c2c66affSColin Finck         MsiCloseHandle( hrec );
1065c2c66affSColin Finck 
1066c2c66affSColin Finck         r = MsiViewFetch( hview, &hrec );
1067c2c66affSColin Finck         ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r);
1068c2c66affSColin Finck     }
1069c2c66affSColin Finck 
1070c2c66affSColin Finck     MsiViewClose( hview );
1071c2c66affSColin Finck     MsiCloseHandle( hview );
1072c2c66affSColin Finck     return ret;
1073c2c66affSColin Finck }
1074c2c66affSColin Finck 
1075c2c66affSColin Finck static void test_system_tables( void )
1076c2c66affSColin Finck {
1077c2c66affSColin Finck     static const char patchsource[] = "MSPSRC0F96CDC04CDF4304B2837B9264889EF7";
1078c2c66affSColin Finck     static const WCHAR streamsW[] = {'_','S','t','r','e','a','m','s',0};
1079c2c66affSColin Finck     static const WCHAR CAB_msitest_encodedW[] = {0x3a8c,0x47cb,0x45b0,0x45ec,0x45a8,0x4837,0};
1080c2c66affSColin Finck     UINT r;
1081c2c66affSColin Finck     char *cr;
1082c2c66affSColin Finck     const char *query;
1083c2c66affSColin Finck     MSIHANDLE hproduct, hdb, hview, hrec;
1084c2c66affSColin Finck 
1085c2c66affSColin Finck     if (!pMsiApplyPatchA)
1086c2c66affSColin Finck     {
1087c2c66affSColin Finck         win_skip("MsiApplyPatchA is not available\n");
1088c2c66affSColin Finck         return;
1089c2c66affSColin Finck     }
1090c2c66affSColin Finck     if (is_process_limited())
1091c2c66affSColin Finck     {
1092c2c66affSColin Finck         skip("process is limited\n");
1093c2c66affSColin Finck         return;
1094c2c66affSColin Finck     }
1095c2c66affSColin Finck 
1096c2c66affSColin Finck     CreateDirectoryA( "msitest", NULL );
1097c2c66affSColin Finck     create_file( "msitest\\patch.txt", 1000 );
1098c2c66affSColin Finck 
109986676451Swinesync     create_database( msifile, tables, ARRAY_SIZE(tables) );
1100c2c66affSColin Finck     create_patch( mspfile );
1101c2c66affSColin Finck 
1102c2c66affSColin Finck     MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1103c2c66affSColin Finck 
1104c2c66affSColin Finck     r = MsiInstallProductA( msifile, NULL );
1105c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1106c2c66affSColin Finck     {
1107c2c66affSColin Finck         skip("Product installation failed with error code %d\n", r);
1108c2c66affSColin Finck         goto cleanup;
1109c2c66affSColin Finck     }
1110c2c66affSColin Finck 
1111c2c66affSColin Finck     r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1112c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1113c2c66affSColin Finck 
1114c2c66affSColin Finck     hdb = MsiGetActiveDatabase( hproduct );
1115c2c66affSColin Finck     ok( hdb, "failed to get database handle\n" );
1116c2c66affSColin Finck 
1117c2c66affSColin Finck     r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1118c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1119c2c66affSColin Finck 
1120c2c66affSColin Finck     query = "SELECT * FROM `_Storages`";
1121c2c66affSColin Finck     r = MsiDatabaseOpenViewA( hdb, query, &hview );
1122c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1123c2c66affSColin Finck 
1124c2c66affSColin Finck     r = MsiViewExecute( hview, 0 );
1125c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1126c2c66affSColin Finck 
1127c2c66affSColin Finck     r = MsiViewFetch( hview, &hrec );
1128c2c66affSColin Finck     ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1129c2c66affSColin Finck 
1130c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "Directory" );
1131c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1132c2c66affSColin Finck 
1133c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "File" );
1134c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1135c2c66affSColin Finck 
1136c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "Component" );
1137c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1138c2c66affSColin Finck 
1139c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "Feature" );
1140c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1141c2c66affSColin Finck 
1142c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "FeatureComponents" );
1143c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1144c2c66affSColin Finck 
1145c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "Property" );
1146c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1147c2c66affSColin Finck 
1148c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1149c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1150c2c66affSColin Finck 
1151c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "Media" );
1152c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1153c2c66affSColin Finck 
1154c2c66affSColin Finck     r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1155c2c66affSColin Finck     ok( r == 1, "Got %u\n", r );
1156c2c66affSColin Finck 
1157c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "_Property" );
1158c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1159c2c66affSColin Finck 
1160c2c66affSColin Finck     MsiCloseHandle( hrec );
1161c2c66affSColin Finck     MsiViewClose( hview );
1162c2c66affSColin Finck     MsiCloseHandle( hview );
1163c2c66affSColin Finck     MsiCloseHandle( hdb );
1164c2c66affSColin Finck     MsiCloseHandle( hproduct );
1165c2c66affSColin Finck 
1166c2c66affSColin Finck     r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1167c2c66affSColin Finck     ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1168c2c66affSColin Finck         "expected ERROR_SUCCESS, got %u\n", r );
1169c2c66affSColin Finck 
1170c2c66affSColin Finck     if (r == ERROR_PATCH_PACKAGE_INVALID)
1171c2c66affSColin Finck     {
1172c2c66affSColin Finck         win_skip("Windows Installer < 3.0 detected\n");
1173c2c66affSColin Finck         goto uninstall;
1174c2c66affSColin Finck     }
1175c2c66affSColin Finck 
1176c2c66affSColin Finck     r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1177c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1178c2c66affSColin Finck 
1179c2c66affSColin Finck     hdb = MsiGetActiveDatabase( hproduct );
1180c2c66affSColin Finck     ok( hdb, "failed to get database handle\n" );
1181c2c66affSColin Finck 
1182c2c66affSColin Finck     r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1183c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1184c2c66affSColin Finck 
1185c2c66affSColin Finck     r = find_entryW( hdb, streamsW, CAB_msitest_encodedW );
1186c2c66affSColin Finck     ok( r == ERROR_NO_MORE_ITEMS, "failed to find entry %u\n", r );
1187c2c66affSColin Finck 
1188c2c66affSColin Finck     query = "SELECT * FROM `_Storages`";
1189c2c66affSColin Finck     r = MsiDatabaseOpenViewA( hdb, query, &hview );
1190c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1191c2c66affSColin Finck 
1192c2c66affSColin Finck     r = MsiViewExecute( hview, 0 );
1193c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1194c2c66affSColin Finck 
1195c2c66affSColin Finck     r = MsiViewFetch( hview, &hrec );
1196c2c66affSColin Finck     ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1197c2c66affSColin Finck 
1198c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "Directory" );
1199c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1200c2c66affSColin Finck 
1201c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "File" );
1202c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1203c2c66affSColin Finck 
1204c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "Component" );
1205c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1206c2c66affSColin Finck 
1207c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "Feature" );
1208c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1209c2c66affSColin Finck 
1210c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "FeatureComponents" );
1211c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1212c2c66affSColin Finck 
1213c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "Property" );
1214c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1215c2c66affSColin Finck 
1216c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1217c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1218c2c66affSColin Finck 
1219c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "Media" );
1220c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1221c2c66affSColin Finck 
1222c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "_Property" );
1223c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1224c2c66affSColin Finck 
1225c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "MsiPatchHeaders" );
1226c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1227c2c66affSColin Finck 
1228c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "Patch" );
1229c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1230c2c66affSColin Finck 
1231c2c66affSColin Finck     r = find_entry( hdb, "_Tables", "PatchPackage" );
1232c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1233c2c66affSColin Finck 
1234c2c66affSColin Finck     cr = get_string( hdb, 6, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1235c2c66affSColin Finck     todo_wine ok( !strcmp(cr, patchsource), "Expected \"%s\", got \"%s\"\n", patchsource, cr );
1236c2c66affSColin Finck 
1237c2c66affSColin Finck     r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1238c2c66affSColin Finck     todo_wine ok( r == 100, "Got %u\n", r );
1239c2c66affSColin Finck 
1240c2c66affSColin Finck     r = get_integer( hdb, 2, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1241*8bb4f059Swinesync     todo_wine ok( r == 10001, "Got %u\n", r );
1242c2c66affSColin Finck 
1243c2c66affSColin Finck     r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1244c2c66affSColin Finck     ok( r == 1, "Got %u\n", r );
1245c2c66affSColin Finck 
1246c2c66affSColin Finck     cr = get_string( hdb, 4, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1247c2c66affSColin Finck     ok( !strcmp(cr, "#CAB_msitest"), "Expected \"#CAB_msitest\", got \"%s\"\n", cr );
1248c2c66affSColin Finck 
1249c2c66affSColin Finck     r = get_integer( hdb, 8, "SELECT * FROM `File` WHERE `File` = 'patch.txt'");
1250c2c66affSColin Finck     ok( r == 10000, "Got %u\n", r );
1251c2c66affSColin Finck 
1252c2c66affSColin Finck     MsiCloseHandle( hrec );
1253c2c66affSColin Finck     MsiViewClose( hview );
1254c2c66affSColin Finck     MsiCloseHandle( hview );
1255c2c66affSColin Finck     MsiCloseHandle( hdb );
1256c2c66affSColin Finck     MsiCloseHandle( hproduct );
1257c2c66affSColin Finck 
1258c2c66affSColin Finck uninstall:
1259c2c66affSColin Finck     r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1260c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1261c2c66affSColin Finck 
1262c2c66affSColin Finck cleanup:
1263c2c66affSColin Finck     DeleteFileA( msifile );
1264c2c66affSColin Finck     DeleteFileA( mspfile );
1265c2c66affSColin Finck     DeleteFileA( "msitest\\patch.txt" );
1266c2c66affSColin Finck     RemoveDirectoryA( "msitest" );
1267c2c66affSColin Finck }
1268c2c66affSColin Finck 
1269c2c66affSColin Finck static void test_patch_registration( void )
1270c2c66affSColin Finck {
1271c2c66affSColin Finck     UINT r, size;
1272c2c66affSColin Finck     char buffer[MAX_PATH], patch_code[39];
1273c2c66affSColin Finck 
1274c2c66affSColin Finck     if (!pMsiApplyPatchA || !pMsiGetPatchInfoExA || !pMsiEnumPatchesExA)
1275c2c66affSColin Finck     {
1276c2c66affSColin Finck         win_skip("required functions not available\n");
1277c2c66affSColin Finck         return;
1278c2c66affSColin Finck     }
1279c2c66affSColin Finck     if (is_process_limited())
1280c2c66affSColin Finck     {
1281c2c66affSColin Finck         skip("process is limited\n");
1282c2c66affSColin Finck         return;
1283c2c66affSColin Finck     }
1284c2c66affSColin Finck 
1285c2c66affSColin Finck     CreateDirectoryA( "msitest", NULL );
1286c2c66affSColin Finck     create_file( "msitest\\patch.txt", 1000 );
1287c2c66affSColin Finck 
128886676451Swinesync     create_database( msifile, tables, ARRAY_SIZE(tables) );
1289c2c66affSColin Finck     create_patch( mspfile );
1290c2c66affSColin Finck 
1291c2c66affSColin Finck     MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1292c2c66affSColin Finck 
1293c2c66affSColin Finck     r = MsiInstallProductA( msifile, NULL );
1294c2c66affSColin Finck     if (r != ERROR_SUCCESS)
1295c2c66affSColin Finck     {
1296c2c66affSColin Finck         skip("Product installation failed with error code %d\n", r);
1297c2c66affSColin Finck         goto cleanup;
1298c2c66affSColin Finck     }
1299c2c66affSColin Finck 
1300c2c66affSColin Finck     r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1301c2c66affSColin Finck     ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1302c2c66affSColin Finck         "expected ERROR_SUCCESS, got %u\n", r );
1303c2c66affSColin Finck 
1304c2c66affSColin Finck     if (r == ERROR_PATCH_PACKAGE_INVALID)
1305c2c66affSColin Finck     {
1306c2c66affSColin Finck         win_skip("Windows Installer < 3.0 detected\n");
1307c2c66affSColin Finck         goto uninstall;
1308c2c66affSColin Finck     }
1309c2c66affSColin Finck 
1310c2c66affSColin Finck     buffer[0] = 0;
1311c2c66affSColin Finck     size = sizeof(buffer);
1312c2c66affSColin Finck     r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1313c2c66affSColin Finck                              "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1314c2c66affSColin Finck                               NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1315c2c66affSColin Finck                               INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1316c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1317c2c66affSColin Finck     ok( buffer[0], "buffer empty\n" );
1318c2c66affSColin Finck 
1319c2c66affSColin Finck     buffer[0] = 0;
1320c2c66affSColin Finck     size = sizeof(buffer);
1321c2c66affSColin Finck     r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1322c2c66affSColin Finck                              "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1323c2c66affSColin Finck                              NULL, MSIINSTALLCONTEXT_MACHINE,
1324c2c66affSColin Finck                              INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1325c2c66affSColin Finck     ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1326c2c66affSColin Finck 
1327c2c66affSColin Finck     buffer[0] = 0;
1328c2c66affSColin Finck     size = sizeof(buffer);
1329c2c66affSColin Finck     r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1330c2c66affSColin Finck                              "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1331c2c66affSColin Finck                              NULL, MSIINSTALLCONTEXT_USERMANAGED,
1332c2c66affSColin Finck                              INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1333c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1334c2c66affSColin Finck     ok( !buffer[0], "got %s\n", buffer );
1335c2c66affSColin Finck 
1336c2c66affSColin Finck     r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1337c2c66affSColin Finck                            NULL, MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_APPLIED,
1338c2c66affSColin Finck                            0, patch_code, NULL, NULL, NULL, NULL );
1339c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1340c2c66affSColin Finck     ok( !strcmp( patch_code, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" );
1341c2c66affSColin Finck 
1342c2c66affSColin Finck     r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1343c2c66affSColin Finck                            NULL, MSIINSTALLCONTEXT_MACHINE, MSIPATCHSTATE_APPLIED,
1344c2c66affSColin Finck                            0, patch_code, NULL, NULL, NULL, NULL );
1345c2c66affSColin Finck     ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1346c2c66affSColin Finck 
1347c2c66affSColin Finck     r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1348c2c66affSColin Finck                            NULL, MSIINSTALLCONTEXT_USERMANAGED, MSIPATCHSTATE_APPLIED,
1349c2c66affSColin Finck                            0, patch_code, NULL, NULL, NULL, NULL );
1350c2c66affSColin Finck     ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1351c2c66affSColin Finck 
1352c2c66affSColin Finck uninstall:
1353c2c66affSColin Finck     r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1354c2c66affSColin Finck     ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1355c2c66affSColin Finck 
1356c2c66affSColin Finck     buffer[0] = 0;
1357c2c66affSColin Finck     size = sizeof(buffer);
1358c2c66affSColin Finck     r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1359c2c66affSColin Finck                              "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1360c2c66affSColin Finck                               NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1361c2c66affSColin Finck                               INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1362c2c66affSColin Finck     ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1363c2c66affSColin Finck 
1364c2c66affSColin Finck cleanup:
1365c2c66affSColin Finck     DeleteFileA( msifile );
1366c2c66affSColin Finck     DeleteFileA( mspfile );
1367c2c66affSColin Finck     DeleteFileA( "msitest\\patch.txt" );
1368c2c66affSColin Finck     RemoveDirectoryA( "msitest" );
1369c2c66affSColin Finck }
1370c2c66affSColin Finck 
1371c2c66affSColin Finck START_TEST(patch)
1372c2c66affSColin Finck {
1373c2c66affSColin Finck     DWORD len;
1374c2c66affSColin Finck     char temp_path[MAX_PATH], prev_path[MAX_PATH];
1375c2c66affSColin Finck 
1376c2c66affSColin Finck     init_function_pointers();
1377c2c66affSColin Finck 
1378c2c66affSColin Finck     GetCurrentDirectoryA( MAX_PATH, prev_path );
1379c2c66affSColin Finck     GetTempPathA( MAX_PATH, temp_path );
1380c2c66affSColin Finck     SetCurrentDirectoryA( temp_path );
1381c2c66affSColin Finck 
1382c2c66affSColin Finck     strcpy( CURR_DIR, temp_path );
1383c2c66affSColin Finck     len = strlen( CURR_DIR );
1384c2c66affSColin Finck 
1385c2c66affSColin Finck     if (len && (CURR_DIR[len - 1] == '\\'))
1386c2c66affSColin Finck         CURR_DIR[len - 1] = 0;
1387c2c66affSColin Finck 
1388c2c66affSColin Finck     get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR );
1389c2c66affSColin Finck 
1390c2c66affSColin Finck     test_simple_patch();
1391c2c66affSColin Finck     test_MsiOpenDatabase();
1392c2c66affSColin Finck     test_system_tables();
1393c2c66affSColin Finck     test_patch_registration();
1394c2c66affSColin Finck 
1395c2c66affSColin Finck     SetCurrentDirectoryA( prev_path );
1396c2c66affSColin Finck }
1397