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