msi/tests: Use CRT allocation functions.
[wine.git] / dlls / msi / tests / patch.c
blob8e8bd356e71dd5a0bb0929de3ec78bc2be98fac6
1 /*
2 * Copyright 2010 Hans Leidekker for CodeWeavers
4 * A test program for patching MSI products.
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.
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.
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
21 #define _WIN32_MSI 300
22 #define COBJMACROS
24 #include <stdio.h>
26 #include <windows.h>
27 #include <msiquery.h>
28 #include <msidefs.h>
29 #include <msi.h>
30 #include <wtypes.h>
32 #include "wine/test.h"
34 static UINT (WINAPI *pMsiApplyPatchA)( LPCSTR, LPCSTR, INSTALLTYPE, LPCSTR );
35 static UINT (WINAPI *pMsiGetPatchInfoExA)( LPCSTR, LPCSTR, LPCSTR, MSIINSTALLCONTEXT,
36 LPCSTR, LPSTR, DWORD * );
37 static UINT (WINAPI *pMsiEnumPatchesExA)( LPCSTR, LPCSTR, DWORD, DWORD, DWORD, LPSTR,
38 LPSTR, MSIINSTALLCONTEXT *, LPSTR, LPDWORD );
40 static const char *msifile = "winetest-patch.msi";
41 static const char *mspfile = "winetest-patch.msp";
42 static const WCHAR msifileW[] = L"winetest-patch.msi";
43 static const WCHAR mspfileW[] = L"winetest-patch.msp";
45 static char CURR_DIR[MAX_PATH];
46 static char PROG_FILES_DIR[MAX_PATH];
47 static char COMMON_FILES_DIR[MAX_PATH];
49 /* msi database data */
51 static const char property_dat[] =
52 "Property\tValue\n"
53 "s72\tl0\n"
54 "Property\tProperty\n"
55 "Manufacturer\tWineHQ\n"
56 "ProductCode\t{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}\n"
57 "UpgradeCode\t{A2E3D643-4E2C-477F-A309-F76F552D5F43}\n"
58 "ProductLanguage\t1033\n"
59 "ProductName\tmsitest\n"
60 "ProductVersion\t1.1.1\n"
61 "PATCHNEWSUMMARYSUBJECT\tInstaller Database\n"
62 "MSIFASTINSTALL\t1\n";
64 static const char media_dat[] =
65 "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
66 "i2\ti4\tL64\tS255\tS32\tS72\n"
67 "Media\tDiskId\n"
68 "1\t1\t\t\tDISK1\t\n";
70 static const char file_dat[] =
71 "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
72 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
73 "File\tFile\n"
74 "patch.txt\tpatch\tpatch.txt\t1000\t\t\t0\t1\n"
75 "disable.txt\tdisable\tdisable.txt\t1000\t\t\t0\t1\n";
77 static const char directory_dat[] =
78 "Directory\tDirectory_Parent\tDefaultDir\n"
79 "s72\tS72\tl255\n"
80 "Directory\tDirectory\n"
81 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
82 "ProgramFilesFolder\tTARGETDIR\t.\n"
83 "TARGETDIR\t\tSourceDir";
85 static const char component_dat[] =
86 "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
87 "s72\tS38\ts72\ti2\tS255\tS72\n"
88 "Component\tComponent\n"
89 "patch\t{4B79D87E-6D28-4FD3-92D6-CD9B26AF64F1}\tMSITESTDIR\t0\t\tpatch.txt\n"
90 "disable\t{BDDBA0EE-0031-4591-ADC0-33308175AC19}\tMSITESTDIR\t0\t\tdisable.txt\n";
92 static const char feature_dat[] =
93 "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
94 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
95 "Feature\tFeature\n"
96 "patch\t\t\tpatch feature\t1\t1\tMSITESTDIR\t0\n"
97 "disable\t\t\tdisabled feature\t1\t1\tMSITESTDIR\t0\n";
99 static const char feature_comp_dat[] =
100 "Feature_\tComponent_\n"
101 "s38\ts72\n"
102 "FeatureComponents\tFeature_\tComponent_\n"
103 "patch\tpatch\n"
104 "disable\tdisable\n";
106 static const char install_exec_seq_dat[] =
107 "Action\tCondition\tSequence\n"
108 "s72\tS255\tI2\n"
109 "InstallExecuteSequence\tAction\n"
110 "LaunchConditions\t\t100\n"
111 "CostInitialize\t\t800\n"
112 "FileCost\t\t900\n"
113 "CostFinalize\t\t1000\n"
114 "InstallValidate\t\t1400\n"
115 "InstallInitialize\t\t1500\n"
116 "ProcessComponents\t\t1600\n"
117 "RemoveFiles\t\t1700\n"
118 "InstallFiles\t\t2000\n"
119 "RegisterUser\t\t3000\n"
120 "RegisterProduct\t\t3100\n"
121 "PublishFeatures\t\t5100\n"
122 "PublishProduct\t\t5200\n"
123 "UnpublishFeatures\t\t5300\n"
124 "InstallFinalize\t\t6000\n";
126 static const char condition_dat[] =
127 "Feature_\tLevel\tCondition\n"
128 "s38\ti2\tS255\n"
129 "Condition\tFeature_\tLevel\n"
130 "disable\t0\tDISABLE_FEATURE\n";
132 struct msi_table
134 const char *filename;
135 const char *data;
136 int size;
139 #define ADD_TABLE( x ) { #x".idt", x##_dat, sizeof(x##_dat) }
141 static const struct msi_table tables[] =
143 ADD_TABLE( directory ),
144 ADD_TABLE( file ),
145 ADD_TABLE( component ),
146 ADD_TABLE( feature ),
147 ADD_TABLE( feature_comp ),
148 ADD_TABLE( property ),
149 ADD_TABLE( install_exec_seq ),
150 ADD_TABLE( media ),
151 ADD_TABLE( condition )
154 static void init_function_pointers( void )
156 HMODULE hmsi = GetModuleHandleA( "msi.dll" );
158 #define GET_PROC( mod, func ) \
159 p ## func = (void *)GetProcAddress( mod, #func ); \
160 if (!p ## func) \
161 trace( "GetProcAddress(%s) failed\n", #func );
163 GET_PROC( hmsi, MsiApplyPatchA );
164 GET_PROC( hmsi, MsiGetPatchInfoExA );
165 GET_PROC( hmsi, MsiEnumPatchesExA );
167 #undef GET_PROC
170 static BOOL is_process_limited(void)
172 HANDLE token;
174 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
176 BOOL ret;
177 TOKEN_ELEVATION_TYPE type = TokenElevationTypeDefault;
178 DWORD size;
180 ret = GetTokenInformation(token, TokenElevationType, &type, sizeof(type), &size);
181 CloseHandle(token);
182 return (ret && type == TokenElevationTypeLimited);
184 return FALSE;
187 static BOOL get_program_files_dir( char *buf, char *buf2 )
189 HKEY hkey;
190 DWORD type, size;
192 if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey ))
193 return FALSE;
195 size = MAX_PATH;
196 if (RegQueryValueExA( hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size ) &&
197 RegQueryValueExA( hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size ))
199 RegCloseKey( hkey );
200 return FALSE;
202 size = MAX_PATH;
203 if (RegQueryValueExA( hkey, "CommonFilesDir", 0, &type, (LPBYTE)buf2, &size ))
205 RegCloseKey( hkey );
206 return FALSE;
208 RegCloseKey( hkey );
209 return TRUE;
212 static void create_file_data( const char *filename, const char *data, DWORD size )
214 HANDLE file;
215 DWORD written;
217 file = CreateFileA( filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
218 if (file == INVALID_HANDLE_VALUE)
219 return;
221 WriteFile( file, data, strlen( data ), &written, NULL );
222 if (size)
224 SetFilePointer( file, size, NULL, FILE_BEGIN );
225 SetEndOfFile( file );
227 CloseHandle( file );
230 #define create_file( name, size ) create_file_data( name, name, size )
232 static BOOL delete_pf( const char *rel_path, BOOL is_file )
234 char path[MAX_PATH];
236 strcpy( path, PROG_FILES_DIR );
237 strcat( path, "\\" );
238 strcat( path, rel_path );
240 if (is_file)
241 return DeleteFileA( path );
242 else
243 return RemoveDirectoryA( path );
246 static DWORD get_pf_file_size( const char *filename )
248 char path[MAX_PATH];
249 HANDLE file;
250 DWORD size;
252 strcpy( path, PROG_FILES_DIR );
253 strcat( path, "\\");
254 strcat( path, filename );
256 file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
257 if (file == INVALID_HANDLE_VALUE)
258 return INVALID_FILE_SIZE;
260 size = GetFileSize( file, NULL );
261 CloseHandle( file );
262 return size;
265 static void write_file( const char *filename, const char *data, DWORD data_size )
267 DWORD size;
268 HANDLE file = CreateFileA( filename, GENERIC_WRITE, 0, NULL,
269 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
270 WriteFile( file, data, data_size, &size, NULL );
271 CloseHandle( file );
274 static void set_suminfo( const WCHAR *filename )
276 UINT r;
277 MSIHANDLE hsi, hdb;
279 r = MsiOpenDatabaseW( filename, MSIDBOPEN_DIRECT, &hdb );
280 ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
282 r = MsiGetSummaryInformationA( hdb, NULL, 7, &hsi );
283 ok( r == ERROR_SUCCESS, "failed to open summaryinfo %u\n", r );
285 r = MsiSummaryInfoSetPropertyA( hsi, 2, VT_LPSTR, 0, NULL, "Installation Database" );
286 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
288 r = MsiSummaryInfoSetPropertyA( hsi, 3, VT_LPSTR, 0, NULL, "Installation Database" );
289 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
291 r = MsiSummaryInfoSetPropertyA( hsi, 4, VT_LPSTR, 0, NULL, "WineHQ" );
292 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
294 r = MsiSummaryInfoSetPropertyA( hsi, 7, VT_LPSTR, 0, NULL, ";1033" );
295 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
297 r = MsiSummaryInfoSetPropertyA( hsi, 9, VT_LPSTR, 0, NULL, "{E528DDD6-4801-4BEC-BBB6-C5EE0FD097E9}" );
298 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
300 r = MsiSummaryInfoSetPropertyA( hsi, 14, VT_I4, 100, NULL, NULL );
301 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
303 r = MsiSummaryInfoSetPropertyA( hsi, 15, VT_I4, 0, NULL, NULL );
304 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
306 r = MsiSummaryInfoPersist( hsi );
307 ok( r == ERROR_SUCCESS, "failed to persist suminfo %u\n", r );
309 r = MsiCloseHandle( hsi );
310 ok( r == ERROR_SUCCESS, "failed to close suminfo %u\n", r );
312 r = MsiCloseHandle( hdb );
313 ok( r == ERROR_SUCCESS, "failed to close database %u\n", r );
316 static void create_database( const char *filename, const struct msi_table *tables, UINT num_tables )
318 MSIHANDLE hdb;
319 UINT r, i;
320 WCHAR *filenameW;
321 int len;
323 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
324 if (!(filenameW = malloc( len * sizeof(WCHAR) ))) return;
325 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
327 r = MsiOpenDatabaseW( filenameW, MSIDBOPEN_CREATE, &hdb );
328 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
330 /* import the tables into the database */
331 for (i = 0; i < num_tables; i++)
333 const struct msi_table *table = &tables[i];
335 write_file( table->filename, table->data, (table->size - 1) * sizeof(char) );
337 r = MsiDatabaseImportA( hdb, CURR_DIR, table->filename );
338 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
340 DeleteFileA( table->filename );
343 r = MsiDatabaseCommit( hdb );
344 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
346 MsiCloseHandle( hdb );
347 set_suminfo( filenameW );
348 free( filenameW );
351 /* data for generating a patch */
353 /* table names - encoded as in an msi database file */
354 static const WCHAR p_name0[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
355 static const WCHAR p_name1[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
356 static const WCHAR p_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
357 static const WCHAR p_name3[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
358 static const WCHAR p_name4[] = { 0x3a8c, 0x47cb, 0x45b0, 0x45ec, 0x45a8, 0x4837, 0}; /* CAB_msitest */
359 static const WCHAR p_name5[] = { 0x4840, 0x4596, 0x3e6c, 0x45e4, 0x42e6, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* MsiPatchSequence */
360 static const WCHAR p_name6[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
361 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
362 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
363 /* substorage names */
364 static const WCHAR p_name7[] = { 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075, 0x0070,
365 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* targetToupgraded */
366 static const WCHAR p_name8[] = { 0x0023, 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075,
367 0x0070, 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* #targetToupgraded */
369 /* data in each table */
370 static const WCHAR p_data0[] = { /* _Columns */
371 0x0001, 0x0001, 0x0001, 0x0001, 0x8001, 0x8002, 0x8003, 0x8004,
372 0x0002, 0x0003, 0x0004, 0x0005, 0xad00, 0xbd26, 0x8d00, 0x9502
374 static const WCHAR p_data1[] = { /* _Tables */
375 0x0001
377 static const char p_data2[] = { /* _StringData */
378 "MsiPatchSequencePatchFamilyProductCodeSequenceAttributes1.1.19388.37230913B8D18FBB64CACA239C74C11E3FA74"
380 static const WCHAR p_data3[] = { /* _StringPool */
381 /* len, refs */
382 0, 0, /* string 0 '' */
383 16, 5, /* string 1 'MsiPatchSequence' */
384 11, 1, /* string 2 'PatchFamily' */
385 11, 1, /* string 3 'ProductCode' */
386 8, 1, /* string 4 'Sequence' */
387 10, 1, /* string 5 'Attributes' */
388 15, 1, /* string 6 '1.1.19388.37230' */
389 32, 1, /* string 7 '913B8D18FBB64CACA239C74C11E3FA74' */
391 static const char p_data4[] = { /* CAB_msitest */
392 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00,
393 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00,
394 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
395 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
396 0xea, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87,
397 0x3c, 0xd4, 0xb8, 0x20, 0x00, 0x70, 0x61, 0x74, 0x63, 0x68, 0x2e,
398 0x74, 0x78, 0x74, 0x00, 0xe8, 0x03, 0x00, 0x00, 0xea, 0x03, 0x00,
399 0x00, 0x00, 0x00, 0xcb, 0x50, 0x17, 0x7e, 0x20, 0x00, 0x66, 0x69,
400 0x6c, 0x65, 0x2e, 0x74, 0x78, 0x74, 0x00, 0xb0, 0xb2, 0xb2, 0x25,
401 0x2d, 0x00, 0xd2, 0x07, 0x43, 0x4b, 0xcb, 0x2d, 0xce, 0x2c, 0x49,
402 0x2d, 0x2e, 0x89, 0x29, 0x48, 0x2c, 0x49, 0xce, 0x48, 0x4d, 0xd1,
403 0x2b, 0xa9, 0x28, 0x51, 0x18, 0x05, 0xa3, 0x60, 0x14, 0x0c, 0x37,
404 0x90, 0x8b, 0x9c, 0xd3, 0x41, 0xf9, 0x9c, 0x61, 0x14, 0x8c, 0x82,
405 0x51, 0x30, 0xdc, 0x00, 0x00
407 static const WCHAR p_data5[] = { /* MsiPatchSequence */
408 0x0007, 0x0000, 0x0006, 0x8000
410 static const char p_data6[] = { /* SummaryInformation */
411 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
412 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
413 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
414 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
415 0x30, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
416 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00,
417 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x90,
418 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
419 0x0f, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
420 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x30, 0x46, 0x39, 0x36, 0x43,
421 0x44, 0x43, 0x30, 0x2d, 0x34, 0x43, 0x44, 0x46, 0x2d, 0x34, 0x33,
422 0x30, 0x34, 0x2d, 0x42, 0x32, 0x38, 0x33, 0x2d, 0x37, 0x42, 0x39,
423 0x32, 0x36, 0x34, 0x38, 0x38, 0x39, 0x45, 0x46, 0x37, 0x7d, 0x00,
424 0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x39,
425 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42,
426 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39,
427 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41,
428 0x37, 0x34, 0x7d, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x25, 0x00,
429 0x00, 0x00, 0x3a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f,
430 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x3b, 0x3a, 0x23,
431 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f, 0x75, 0x70, 0x67,
432 0x72, 0x61, 0x64, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
433 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x50, 0x61, 0x74, 0x63, 0x68,
434 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x00,
435 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
438 struct table_data {
439 LPCWSTR name;
440 const void *data;
441 DWORD size;
444 static const struct table_data table_patch_data[] = {
445 { p_name0, p_data0, sizeof p_data0 },
446 { p_name1, p_data1, sizeof p_data1 },
447 { p_name2, p_data2, sizeof p_data2 - 1 },
448 { p_name3, p_data3, sizeof p_data3 },
449 { p_name4, p_data4, sizeof p_data4 },
450 { p_name5, p_data5, sizeof p_data5 },
451 { p_name6, p_data6, sizeof p_data6 }
454 static const WCHAR t1_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
455 static const WCHAR t1_name1[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
456 static const WCHAR t1_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
457 static const WCHAR t1_name3[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
458 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
459 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
461 static const WCHAR t1_data0[] = { /* File */
462 0x0008, 0x0001, 0x03ea, 0x8000
464 static const char t1_data1[] = { /* _StringData */
465 "patch.txt"
467 static const WCHAR t1_data2[] = { /* _StringPool */
468 /* len, refs */
469 0, 0, /* string 0 '' */
470 9, 1, /* string 1 'patch.txt' */
472 static const char t1_data3[] = { /* SummaryInformation */
473 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
474 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
475 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
476 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
477 0x30, 0x00, 0x00, 0x00, 0x9f, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00,
478 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00,
479 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa8,
480 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00,
481 0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
482 0x00, 0xd0, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x00,
483 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x08,
484 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
485 0x07, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8f, 0x01, 0x00,
486 0x00, 0x10, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00, 0x1e, 0x00,
487 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61,
488 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74,
489 0x61, 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
490 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c,
491 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74, 0x61,
492 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
493 0x07, 0x00, 0x00, 0x00, 0x57, 0x69, 0x6e, 0x65, 0x48, 0x51, 0x00,
494 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
495 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
496 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
497 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
498 0x00, 0x1e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x78, 0x38,
499 0x36, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x00,
500 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33,
501 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
502 0x7b, 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46,
503 0x42, 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32,
504 0x33, 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33,
505 0x46, 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b,
506 0x7b, 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46,
507 0x42, 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32,
508 0x33, 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33,
509 0x46, 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b,
510 0x7b, 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34,
511 0x45, 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33,
512 0x30, 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44,
513 0x35, 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
514 0x64, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22,
515 0x09
518 static const struct table_data table_transform1_data[] = {
519 { t1_name0, t1_data0, sizeof t1_data0 },
520 { t1_name1, t1_data1, sizeof t1_data1 - 1 },
521 { t1_name2, t1_data2, sizeof t1_data2 },
522 { t1_name3, t1_data3, sizeof t1_data3 }
525 static const WCHAR t2_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
526 static const WCHAR t2_name1[] = { 0x4840, 0x4216, 0x4327, 0x4824, 0 }; /* Media */
527 static const WCHAR t2_name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
528 static const WCHAR t2_name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
529 static const WCHAR t2_name4[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
530 static const WCHAR t2_name5[] = { 0x4840, 0x4119, 0x41b7, 0x3e6b, 0x41a4, 0x412e, 0x422a, 0 }; /* PatchPackage */
531 static const WCHAR t2_name6[] = { 0x4840, 0x4452, 0x45f6, 0x43e4, 0x3baf, 0x423b, 0x4626,
532 0x4237, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* InstallExecuteSequence */
533 static const WCHAR t2_name7[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
534 static const WCHAR t2_name8[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
535 static const WCHAR t2_name9[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
536 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
537 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
538 static const WCHAR t2_name10[] = { 0x4840, 0x420f, 0x45e4, 0x4578, 0x3b28, 0x4432, 0x44b3,
539 0x4231, 0x45f1, 0x4836, 0 }; /* FeatureComponents */
540 static const WCHAR t2_name11[] = { 0x4840, 0x448c, 0x44f0, 0x4472, 0x4468, 0x4837, 0 }; /* Component */
541 static const WCHAR t2_name12[] = { 0x4840, 0x420f, 0x45e4, 0x4578, 0x4828, 0 }; /* Feature */
543 static const WCHAR t2_data0[] = { /* File */
544 0x00c0, 0x0001, 0x9000, 0x83e8, 0x0801, 0x0002, 0x0003, 0x0002,
545 0x03e8, 0x8000, 0x0000, 0x0000, 0x9000, 0x83e9
547 static const WCHAR t2_data1[] = { /* Media */
548 0x0601, 0x8002, 0x03e9, 0x8000, 0x0000, 0x000d, 0x0000, 0x000e
550 static const WCHAR t2_data2[] = { /* _Columns */
551 0x0401, 0x000f, 0x0000, 0x0010, 0xad48, 0x0401, 0x000f, 0x0000, /* 0x0401 = add row (1), 4 shorts */
552 0x0011, 0xa502, 0x0401, 0x000f, 0x0000, 0x0012, 0x8104, 0x0401,
553 0x000f, 0x0000, 0x0013, 0x8502, 0x0401, 0x000f, 0x0000, 0x0014,
554 0x9900, 0x0401, 0x000f, 0x0000, 0x0015, 0x9d48, 0x0401, 0x0016,
555 0x0000, 0x0017, 0xad26, 0x0401, 0x0016, 0x0000, 0x0018, 0x8502,
556 0x0401, 0x001a, 0x0000, 0x001b, 0xad26, 0x0401, 0x001a, 0x0000,
557 0x0014, 0x8900
559 static const WCHAR t2_data3[] = { /* _Tables */
560 0x0101, 0x000f, 0x0101, 0x0016, 0x0101, 0x001a
562 static const WCHAR t2_data4[] = { /* Property */
563 0x0002, 0x0008, 0x0009, 0x0201, 0x000a, 0x000b
565 static const WCHAR t2_data5[] = { /* PatchPackage */
566 0x0201, 0x0019, 0x8002
568 static const WCHAR t2_data6[] = { /* InstallExecuteSequence */
569 0x0301, 0x000c, 0x0000, 0x87d1
571 static const char t2_data7[] = { /* _StringData */
572 "patch.txtfile.txtfile{327d9640-674f-4b9f-8b8a-547a0f6f8518}MSITESTDIRnewnew featurePATCHNEWSUMMARYSUBJECT"
573 "Installation DatabasePATCHNEWPACKAGECODE{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}PatchFiles#CAB_msitestprop"
574 "PatchFile_SequencePatchSizeAttributesHeaderStreamRef_PatchPackagePatchIdMedia_"
575 "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}MsiPatchHeadersStreamRef"
577 static const WCHAR t2_data8[] = { /* _StringPool */
578 /* len, refs */
579 0, 0, /* string 0 '' */
580 9, 1, /* string 1 'patch.txt' */
581 8, 3, /* string 2 'file.txt' */
582 4, 3, /* string 3 'file' */
583 38, 1, /* string 4 '{327d9640-674f-4b9f-8b8a-547a0f6f8518}' */
584 10, 2, /* string 5 'MSITESTDIR' */
585 3, 2, /* string 6 'new' */
586 11, 1, /* string 7 'new feature' */
587 22, 1, /* string 8 'PATCHNEWSUMMARYSUBJECT' */
588 21, 1, /* string 9 'Installation Database' */
589 19, 1, /* string 10 'PATCHNEWPACKAGECODE' */
590 38, 1, /* string 11 '{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}' */
591 10, 1, /* string 12 'PatchFiles' */
592 12, 1, /* string 13 '#CAB_msitest' */
593 4, 1, /* string 14 'prop' */
594 5, 7, /* string 15 'Patch' */
595 5, 1, /* string 16 'File_' */
596 8, 1, /* string 17 'Sequence' */
597 9, 1, /* string 18 'PatchSize' */
598 10, 1, /* string 19 'Attributes' */
599 6, 2, /* string 20 'Header' */
600 10, 1, /* string 21 'StreamRef_' */
601 12, 3, /* string 22 'PatchPackage' */
602 7, 1, /* string 23 'PatchId' */
603 6, 1, /* string 24 'Media_' */
604 38, 1, /* string 25 '{0F96CDC0-4CDF-4304-B283-7B9264889EF7}' */
605 15, 3, /* string 26 'MsiPatchHeaders' */
606 9, 1 /* string 27 'StreamRef' */
608 static const char t2_data9[] = { /* SummaryInformation */
609 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
610 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
612 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
613 0x30, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00,
614 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00,
615 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x78,
616 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
617 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
618 0x00, 0x9c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00,
619 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x09,
620 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
621 0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00,
622 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
623 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
624 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
625 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
626 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00,
627 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01,
628 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
629 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00,
630 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
631 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b,
632 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
633 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
634 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
635 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
636 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
637 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
638 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
639 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
640 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45,
641 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30,
642 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35,
643 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2d,
644 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x27, 0x09
646 static const WCHAR t2_data10[] = { /* FeatureComponents */
647 0x0201, 0x0006, 0x0003
649 static const WCHAR t2_data11[] = { /* Component */
650 0x0601, 0x0003, 0x0004, 0x0005, 0x8000, 0x0000, 0x0002
652 static const WCHAR t2_data12[] = { /* Feature */
653 0x0801, 0x0006, 0x0000, 0x0000, 0x0007, 0x8001, 0x8001, 0x0005,
654 0x8000
657 static const struct table_data table_transform2_data[] = {
658 { t2_name0, t2_data0, sizeof t2_data0 },
659 { t2_name1, t2_data1, sizeof t2_data1 },
660 { t2_name2, t2_data2, sizeof t2_data2 },
661 { t2_name3, t2_data3, sizeof t2_data3 },
662 { t2_name4, t2_data4, sizeof t2_data4 },
663 { t2_name5, t2_data5, sizeof t2_data5 },
664 { t2_name6, t2_data6, sizeof t2_data6 },
665 { t2_name7, t2_data7, sizeof t2_data7 - 1 },
666 { t2_name8, t2_data8, sizeof t2_data8 },
667 { t2_name9, t2_data9, sizeof t2_data9 },
668 { t2_name10, t2_data10, sizeof t2_data10 },
669 { t2_name11, t2_data11, sizeof t2_data11 },
670 { t2_name12, t2_data12, sizeof t2_data12 },
673 static void write_tables( IStorage *stg, const struct table_data *tables, UINT num_tables )
675 IStream *stm;
676 DWORD i, count;
677 HRESULT r;
679 for (i = 0; i < num_tables; i++)
681 r = IStorage_CreateStream( stg, tables[i].name, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
682 if (FAILED( r ))
684 ok( 0, "failed to create stream 0x%08x\n", r );
685 continue;
688 r = IStream_Write( stm, tables[i].data, tables[i].size, &count );
689 if (FAILED( r ) || count != tables[i].size)
690 ok( 0, "failed to write stream\n" );
691 IStream_Release( stm );
695 static void create_patch( const char *filename )
697 IStorage *stg = NULL, *stg1 = NULL, *stg2 = NULL;
698 WCHAR *filenameW;
699 HRESULT r;
700 int len;
701 const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
703 const CLSID CLSID_MsiPatch = {0xc1086, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
704 const CLSID CLSID_MsiTransform = {0xc1082, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
706 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
707 filenameW = malloc( len * sizeof(WCHAR) );
708 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
710 r = StgCreateDocfile( filenameW, mode, 0, &stg );
711 free( filenameW );
712 ok( r == S_OK, "failed to create storage 0x%08x\n", r );
713 if (!stg)
714 return;
716 r = IStorage_SetClass( stg, &CLSID_MsiPatch );
717 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
719 write_tables( stg, table_patch_data, ARRAY_SIZE( table_patch_data ));
721 r = IStorage_CreateStorage( stg, p_name7, mode, 0, 0, &stg1 );
722 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
724 r = IStorage_SetClass( stg1, &CLSID_MsiTransform );
725 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
727 write_tables( stg1, table_transform1_data, ARRAY_SIZE( table_transform1_data ));
728 IStorage_Release( stg1 );
730 r = IStorage_CreateStorage( stg, p_name8, mode, 0, 0, &stg2 );
731 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
733 r = IStorage_SetClass( stg2, &CLSID_MsiTransform );
734 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
736 write_tables( stg2, table_transform2_data, ARRAY_SIZE( table_transform2_data ));
737 IStorage_Release( stg2 );
738 IStorage_Release( stg );
741 static void test_simple_patch( void )
743 UINT r;
744 DWORD size;
745 char path[MAX_PATH], install_source[MAX_PATH], buffer[32];
746 const char *query;
747 WCHAR pathW[MAX_PATH];
748 MSIHANDLE hpackage, hdb, hview, hrec;
750 if (!pMsiApplyPatchA)
752 win_skip("MsiApplyPatchA is not available\n");
753 return;
755 if (is_process_limited())
757 skip("process is limited\n");
758 return;
761 CreateDirectoryA( "msitest", NULL );
762 create_file( "msitest\\patch.txt", 1000 );
764 create_database( msifile, tables, ARRAY_SIZE(tables) );
765 create_patch( mspfile );
767 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
769 r = MsiInstallProductA( msifile, "DISABLE_FEATURE=1" );
770 if (r != ERROR_SUCCESS)
772 skip("Product installation failed with error code %u\n", r);
773 goto cleanup;
776 size = get_pf_file_size( "msitest\\patch.txt" );
777 ok( size == 1000, "expected 1000, got %u\n", size );
779 size = sizeof(install_source);
780 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
781 "InstallSource", install_source, &size );
782 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
784 strcpy( path, CURR_DIR );
785 strcat( path, "\\" );
786 strcat( path, msifile );
788 r = MsiOpenPackageA( path, &hpackage );
789 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
791 hdb = MsiGetActiveDatabase( hpackage );
792 ok( hdb, "failed to get database handle\n" );
794 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
795 r = MsiDatabaseOpenViewA( hdb, query, &hview );
796 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
798 r = MsiViewExecute( hview, 0 );
799 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
801 r = MsiViewFetch( hview, &hrec );
802 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
804 MsiCloseHandle( hrec );
805 MsiViewClose( hview );
806 MsiCloseHandle( hview );
808 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
809 "AND `Value` = 'Installer Database'";
810 r = MsiDatabaseOpenViewA( hdb, query, &hview );
811 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
813 r = MsiViewExecute( hview, 0 );
814 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
816 r = MsiViewFetch( hview, &hrec );
817 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
819 MsiCloseHandle( hrec );
820 MsiViewClose( hview );
821 MsiCloseHandle( hview );
823 buffer[0] = 0;
824 size = sizeof(buffer);
825 r = MsiGetPropertyA( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
826 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
827 ok( !strcmp( buffer, "Installer Database" ), "expected \'Installer Database\', got \'%s\'\n", buffer );
829 MsiCloseHandle( hdb );
830 MsiCloseHandle( hpackage );
832 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
833 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
834 "expected ERROR_SUCCESS, got %u\n", r );
836 if (r == ERROR_PATCH_PACKAGE_INVALID)
838 win_skip("Windows Installer < 3.0 detected\n");
839 goto uninstall;
842 size = get_pf_file_size( "msitest\\patch.txt" );
843 ok( size == 1002, "expected 1002, got %u\n", size );
844 size = get_pf_file_size( "msitest\\file.txt" );
845 ok( size == 1000, "expected 1000, got %u\n", size );
847 /* show that MsiOpenPackage applies registered patches */
848 r = MsiOpenPackageA( path, &hpackage );
849 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
851 hdb = MsiGetActiveDatabase( hpackage );
852 ok( hdb, "failed to get database handle\n" );
854 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
855 r = MsiDatabaseOpenViewA( hdb, query, &hview );
856 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
858 r = MsiViewExecute( hview, 0 );
859 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
861 r = MsiViewFetch( hview, &hrec );
862 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
864 MsiCloseHandle( hrec );
865 MsiViewClose( hview );
866 MsiCloseHandle( hview );
868 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
869 "AND `Value` = 'Installation Database'";
870 r = MsiDatabaseOpenViewA( hdb, query, &hview );
871 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
873 r = MsiViewExecute( hview, 0 );
874 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
876 r = MsiViewFetch( hview, &hrec );
877 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
879 MsiCloseHandle( hrec );
880 MsiViewClose( hview );
881 MsiCloseHandle( hview );
883 buffer[0] = 0;
884 size = sizeof(buffer);
885 r = MsiGetPropertyA( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
886 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
887 ok( !strcmp( buffer, "Installation Database" ), "expected \'Installation Database\', got \'%s\'\n", buffer );
889 MsiCloseHandle( hdb );
890 MsiCloseHandle( hpackage );
892 /* show that patches are not committed to the local package database */
893 size = sizeof(path);
894 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
895 "LocalPackage", path, &size );
896 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
898 MultiByteToWideChar( CP_ACP, 0, path, -1, pathW, MAX_PATH );
899 r = MsiOpenDatabaseW( pathW, MSIDBOPEN_READONLY, &hdb );
900 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
902 r = MsiDatabaseOpenViewA( hdb, query, &hview );
903 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
905 r = MsiViewExecute( hview, 0 );
906 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
908 r = MsiViewFetch( hview, &hrec );
909 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
911 MsiCloseHandle( hrec );
912 MsiViewClose( hview );
913 MsiCloseHandle( hview );
914 MsiCloseHandle( hdb );
916 uninstall:
917 size = sizeof(path);
918 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
919 "InstallSource", path, &size );
920 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
921 ok( !strcasecmp( path, install_source ), "wrong path %s\n", path );
923 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
924 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
926 ok( !delete_pf( "msitest\\patch.txt", TRUE ), "file not removed\n" );
927 ok( !delete_pf( "msitest\\file.txt", TRUE ), "file not removed\n" );
928 ok( !delete_pf( "msitest", FALSE ), "directory not removed\n" );
930 cleanup:
931 DeleteFileA( msifile );
932 DeleteFileA( mspfile );
933 DeleteFileA( "msitest\\patch.txt" );
934 RemoveDirectoryA( "msitest" );
937 static void test_MsiOpenDatabase( void )
939 UINT r;
940 MSIHANDLE hdb;
942 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_CREATE, &hdb );
943 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
945 r = MsiDatabaseCommit( hdb );
946 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
947 MsiCloseHandle( hdb );
949 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
950 ok(r == ERROR_OPEN_FAILED, "expected ERROR_OPEN_FAILED, got %u\n", r);
951 DeleteFileA( mspfile );
953 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_CREATE + MSIDBOPEN_PATCHFILE, &hdb );
954 ok(r == ERROR_SUCCESS , "failed to open database %u\n", r);
956 r = MsiDatabaseCommit( hdb );
957 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
958 MsiCloseHandle( hdb );
960 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
961 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
962 MsiCloseHandle( hdb );
963 DeleteFileA( mspfile );
965 create_database( msifile, tables, ARRAY_SIZE(tables) );
966 create_patch( mspfile );
968 r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
969 ok(r == ERROR_OPEN_FAILED, "failed to open database %u\n", r );
971 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
972 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r );
973 MsiCloseHandle( hdb );
975 DeleteFileA( msifile );
976 DeleteFileA( mspfile );
979 static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry )
981 static const char fmt[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
982 char query[0x100];
983 UINT r;
984 MSIHANDLE hview, hrec;
986 sprintf( query, fmt, table, entry );
987 r = MsiDatabaseOpenViewA( hdb, query, &hview );
988 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
990 r = MsiViewExecute( hview, 0 );
991 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
993 r = MsiViewFetch( hview, &hrec );
994 MsiViewClose( hview );
995 MsiCloseHandle( hview );
996 MsiCloseHandle( hrec );
997 return r;
1000 static UINT find_entryW( MSIHANDLE hdb, const WCHAR *table, const WCHAR *entry )
1002 WCHAR query[0x100];
1003 MSIHANDLE hview, hrec;
1004 UINT r;
1006 wsprintfW( query, L"SELECT * FROM `%s` WHERE `Name` = '%s'", table, entry );
1007 r = MsiDatabaseOpenViewW( hdb, query, &hview );
1008 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1010 r = MsiViewExecute( hview, 0 );
1011 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1013 r = MsiViewFetch( hview, &hrec );
1014 MsiViewClose( hview );
1015 MsiCloseHandle( hview );
1016 MsiCloseHandle( hrec );
1017 return r;
1020 static INT get_integer( MSIHANDLE hdb, UINT field, const char *query)
1022 UINT r;
1023 INT ret = -1;
1024 MSIHANDLE hview, hrec;
1026 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1027 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1029 r = MsiViewExecute( hview, 0 );
1030 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1032 r = MsiViewFetch( hview, &hrec );
1033 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1034 if (r == ERROR_SUCCESS)
1036 UINT r_tmp;
1037 ret = MsiRecordGetInteger( hrec, field );
1038 MsiCloseHandle( hrec );
1040 r_tmp = MsiViewFetch( hview, &hrec );
1041 ok( r_tmp == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r);
1044 MsiViewClose( hview );
1045 MsiCloseHandle( hview );
1046 return ret;
1049 static char *get_string( MSIHANDLE hdb, UINT field, const char *query)
1051 UINT r;
1052 static char ret[MAX_PATH];
1053 MSIHANDLE hview, hrec;
1055 ret[0] = '\0';
1057 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1058 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1060 r = MsiViewExecute( hview, 0 );
1061 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1063 r = MsiViewFetch( hview, &hrec );
1064 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1065 if (r == ERROR_SUCCESS)
1067 UINT size = MAX_PATH;
1068 r = MsiRecordGetStringA( hrec, field, ret, &size );
1069 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
1070 MsiCloseHandle( hrec );
1072 r = MsiViewFetch( hview, &hrec );
1073 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r);
1076 MsiViewClose( hview );
1077 MsiCloseHandle( hview );
1078 return ret;
1081 static void test_system_tables( void )
1083 static const char patchsource[] = "MSPSRC0F96CDC04CDF4304B2837B9264889EF7";
1084 UINT r;
1085 char *cr;
1086 const char *query;
1087 MSIHANDLE hproduct, hdb, hview, hrec;
1089 if (!pMsiApplyPatchA)
1091 win_skip("MsiApplyPatchA is not available\n");
1092 return;
1094 if (is_process_limited())
1096 skip("process is limited\n");
1097 return;
1100 CreateDirectoryA( "msitest", NULL );
1101 create_file( "msitest\\patch.txt", 1000 );
1103 create_database( msifile, tables, ARRAY_SIZE(tables) );
1104 create_patch( mspfile );
1106 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1108 r = MsiInstallProductA( msifile, "DISABLE_FEATURE=1" );
1109 if (r != ERROR_SUCCESS)
1111 skip("Product installation failed with error code %d\n", r);
1112 goto cleanup;
1115 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1116 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1118 hdb = MsiGetActiveDatabase( hproduct );
1119 ok( hdb, "failed to get database handle\n" );
1121 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1122 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1124 query = "SELECT * FROM `_Storages`";
1125 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1126 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1128 r = MsiViewExecute( hview, 0 );
1129 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1131 r = MsiViewFetch( hview, &hrec );
1132 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1134 r = find_entry( hdb, "_Tables", "Directory" );
1135 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1137 r = find_entry( hdb, "_Tables", "File" );
1138 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1140 r = find_entry( hdb, "_Tables", "Component" );
1141 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1143 r = find_entry( hdb, "_Tables", "Feature" );
1144 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1146 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1147 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1149 r = find_entry( hdb, "_Tables", "Property" );
1150 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1152 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1153 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1155 r = find_entry( hdb, "_Tables", "Media" );
1156 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1158 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1159 ok( r == 1, "Got %u\n", r );
1161 r = find_entry( hdb, "_Tables", "_Property" );
1162 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1164 MsiCloseHandle( hrec );
1165 MsiViewClose( hview );
1166 MsiCloseHandle( hview );
1167 MsiCloseHandle( hdb );
1168 MsiCloseHandle( hproduct );
1170 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1171 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1172 "expected ERROR_SUCCESS, got %u\n", r );
1174 if (r == ERROR_PATCH_PACKAGE_INVALID)
1176 win_skip("Windows Installer < 3.0 detected\n");
1177 goto uninstall;
1180 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1181 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1183 hdb = MsiGetActiveDatabase( hproduct );
1184 ok( hdb, "failed to get database handle\n" );
1186 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1187 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1189 r = find_entryW( hdb, L"_Streams", L"\x3a8c\x47cb\x45b0\x45ec\x45a8\x4837" );
1190 ok( r == ERROR_NO_MORE_ITEMS, "failed to find entry %u\n", r );
1192 query = "SELECT * FROM `_Storages`";
1193 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1194 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1196 r = MsiViewExecute( hview, 0 );
1197 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1199 r = MsiViewFetch( hview, &hrec );
1200 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1202 r = find_entry( hdb, "_Tables", "Directory" );
1203 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1205 r = find_entry( hdb, "_Tables", "File" );
1206 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1208 r = find_entry( hdb, "_Tables", "Component" );
1209 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1211 r = find_entry( hdb, "_Tables", "Feature" );
1212 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1214 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1215 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1217 r = find_entry( hdb, "_Tables", "Property" );
1218 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1220 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1221 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1223 r = find_entry( hdb, "_Tables", "Media" );
1224 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1226 r = find_entry( hdb, "_Tables", "_Property" );
1227 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1229 r = find_entry( hdb, "_Tables", "MsiPatchHeaders" );
1230 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1232 r = find_entry( hdb, "_Tables", "Patch" );
1233 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1235 r = find_entry( hdb, "_Tables", "PatchPackage" );
1236 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1238 cr = get_string( hdb, 6, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1239 todo_wine ok( !strcmp(cr, patchsource), "Expected \"%s\", got \"%s\"\n", patchsource, cr );
1241 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1242 todo_wine ok( r == 100, "Got %u\n", r );
1244 r = get_integer( hdb, 2, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1245 todo_wine ok( r == 10001, "Got %u\n", r );
1247 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1248 ok( r == 1, "Got %u\n", r );
1250 cr = get_string( hdb, 4, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1251 ok( !strcmp(cr, "#CAB_msitest"), "Expected \"#CAB_msitest\", got \"%s\"\n", cr );
1253 r = get_integer( hdb, 8, "SELECT * FROM `File` WHERE `File` = 'patch.txt'");
1254 ok( r == 10000, "Got %u\n", r );
1256 MsiCloseHandle( hrec );
1257 MsiViewClose( hview );
1258 MsiCloseHandle( hview );
1259 MsiCloseHandle( hdb );
1260 MsiCloseHandle( hproduct );
1262 uninstall:
1263 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1264 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1266 cleanup:
1267 DeleteFileA( msifile );
1268 DeleteFileA( mspfile );
1269 DeleteFileA( "msitest\\patch.txt" );
1270 RemoveDirectoryA( "msitest" );
1273 static void test_patch_registration( void )
1275 UINT r, size;
1276 char buffer[MAX_PATH], patch_code[39];
1278 if (!pMsiApplyPatchA || !pMsiGetPatchInfoExA || !pMsiEnumPatchesExA)
1280 win_skip("required functions not available\n");
1281 return;
1283 if (is_process_limited())
1285 skip("process is limited\n");
1286 return;
1289 CreateDirectoryA( "msitest", NULL );
1290 create_file( "msitest\\patch.txt", 1000 );
1292 create_database( msifile, tables, ARRAY_SIZE(tables) );
1293 create_patch( mspfile );
1295 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1297 r = MsiInstallProductA( msifile, "DISABLE_FEATURE=1" );
1298 if (r != ERROR_SUCCESS)
1300 skip("Product installation failed with error code %d\n", r);
1301 goto cleanup;
1304 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1305 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1306 "expected ERROR_SUCCESS, got %u\n", r );
1308 if (r == ERROR_PATCH_PACKAGE_INVALID)
1310 win_skip("Windows Installer < 3.0 detected\n");
1311 goto uninstall;
1314 buffer[0] = 0;
1315 size = sizeof(buffer);
1316 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1317 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1318 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1319 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1320 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1321 ok( buffer[0], "buffer empty\n" );
1323 buffer[0] = 0;
1324 size = sizeof(buffer);
1325 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1326 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1327 NULL, MSIINSTALLCONTEXT_MACHINE,
1328 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1329 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1331 buffer[0] = 0;
1332 size = sizeof(buffer);
1333 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1334 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1335 NULL, MSIINSTALLCONTEXT_USERMANAGED,
1336 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1337 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1338 ok( !buffer[0], "got %s\n", buffer );
1340 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1341 NULL, MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_APPLIED,
1342 0, patch_code, NULL, NULL, NULL, NULL );
1343 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1344 ok( !strcmp( patch_code, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" );
1346 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1347 NULL, MSIINSTALLCONTEXT_MACHINE, MSIPATCHSTATE_APPLIED,
1348 0, patch_code, NULL, NULL, NULL, NULL );
1349 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1351 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1352 NULL, MSIINSTALLCONTEXT_USERMANAGED, MSIPATCHSTATE_APPLIED,
1353 0, patch_code, NULL, NULL, NULL, NULL );
1354 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1356 uninstall:
1357 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1358 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1360 buffer[0] = 0;
1361 size = sizeof(buffer);
1362 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1363 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1364 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1365 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1366 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1368 cleanup:
1369 DeleteFileA( msifile );
1370 DeleteFileA( mspfile );
1371 DeleteFileA( "msitest\\patch.txt" );
1372 RemoveDirectoryA( "msitest" );
1375 START_TEST(patch)
1377 DWORD len;
1378 char temp_path[MAX_PATH], prev_path[MAX_PATH];
1380 init_function_pointers();
1382 GetCurrentDirectoryA( MAX_PATH, prev_path );
1383 GetTempPathA( MAX_PATH, temp_path );
1384 SetCurrentDirectoryA( temp_path );
1386 strcpy( CURR_DIR, temp_path );
1387 len = strlen( CURR_DIR );
1389 if (len && (CURR_DIR[len - 1] == '\\'))
1390 CURR_DIR[len - 1] = 0;
1392 get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR );
1394 test_simple_patch();
1395 test_MsiOpenDatabase();
1396 test_system_tables();
1397 test_patch_registration();
1399 SetCurrentDirectoryA( prev_path );