msi: Implement deferral for standard and custom actions.
[wine.git] / dlls / msi / tests / patch.c
blobb577982443002d066125f23a56800bd90f4dd901
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 );
39 static BOOL (WINAPI *pOpenProcessToken)( HANDLE, DWORD, PHANDLE );
41 static const char *msifile = "winetest-patch.msi";
42 static const char *mspfile = "winetest-patch.msp";
43 static const WCHAR msifileW[] =
44 {'w','i','n','e','t','e','s','t','-','p','a','t','c','h','.','m','s','i',0};
45 static const WCHAR mspfileW[] =
46 {'w','i','n','e','t','e','s','t','-','p','a','t','c','h','.','m','s','p',0};
48 static char CURR_DIR[MAX_PATH];
49 static char PROG_FILES_DIR[MAX_PATH];
50 static char COMMON_FILES_DIR[MAX_PATH];
52 /* msi database data */
54 static const char property_dat[] =
55 "Property\tValue\n"
56 "s72\tl0\n"
57 "Property\tProperty\n"
58 "Manufacturer\tWineHQ\n"
59 "ProductCode\t{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}\n"
60 "UpgradeCode\t{A2E3D643-4E2C-477F-A309-F76F552D5F43}\n"
61 "ProductLanguage\t1033\n"
62 "ProductName\tmsitest\n"
63 "ProductVersion\t1.1.1\n"
64 "PATCHNEWSUMMARYSUBJECT\tInstaller Database\n"
65 "MSIFASTINSTALL\t1\n";
67 static const char media_dat[] =
68 "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
69 "i2\ti4\tL64\tS255\tS32\tS72\n"
70 "Media\tDiskId\n"
71 "1\t1\t\t\tDISK1\t\n";
73 static const char file_dat[] =
74 "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
75 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
76 "File\tFile\n"
77 "patch.txt\tpatch\tpatch.txt\t1000\t\t\t0\t1\n";
79 static const char directory_dat[] =
80 "Directory\tDirectory_Parent\tDefaultDir\n"
81 "s72\tS72\tl255\n"
82 "Directory\tDirectory\n"
83 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
84 "ProgramFilesFolder\tTARGETDIR\t.\n"
85 "TARGETDIR\t\tSourceDir";
87 static const char component_dat[] =
88 "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
89 "s72\tS38\ts72\ti2\tS255\tS72\n"
90 "Component\tComponent\n"
91 "patch\t{4B79D87E-6D28-4FD3-92D6-CD9B26AF64F1}\tMSITESTDIR\t0\t\tpatch.txt\n";
93 static const char feature_dat[] =
94 "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
95 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
96 "Feature\tFeature\n"
97 "patch\t\t\tpatch 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";
105 static const char install_exec_seq_dat[] =
106 "Action\tCondition\tSequence\n"
107 "s72\tS255\tI2\n"
108 "InstallExecuteSequence\tAction\n"
109 "LaunchConditions\t\t100\n"
110 "CostInitialize\t\t800\n"
111 "FileCost\t\t900\n"
112 "CostFinalize\t\t1000\n"
113 "InstallValidate\t\t1400\n"
114 "InstallInitialize\t\t1500\n"
115 "ProcessComponents\t\t1600\n"
116 "RemoveFiles\t\t1700\n"
117 "InstallFiles\t\t2000\n"
118 "RegisterUser\t\t3000\n"
119 "RegisterProduct\t\t3100\n"
120 "PublishFeatures\t\t5100\n"
121 "PublishProduct\t\t5200\n"
122 "InstallFinalize\t\t6000\n";
124 struct msi_table
126 const char *filename;
127 const char *data;
128 int size;
131 #define ADD_TABLE( x ) { #x".idt", x##_dat, sizeof(x##_dat) }
133 static const struct msi_table tables[] =
135 ADD_TABLE( directory ),
136 ADD_TABLE( file ),
137 ADD_TABLE( component ),
138 ADD_TABLE( feature ),
139 ADD_TABLE( feature_comp ),
140 ADD_TABLE( property ),
141 ADD_TABLE( install_exec_seq ),
142 ADD_TABLE( media )
145 static void init_function_pointers( void )
147 HMODULE hmsi = GetModuleHandleA( "msi.dll" );
148 HMODULE hadvapi32 = GetModuleHandleA( "advapi32.dll" );
150 #define GET_PROC( mod, func ) \
151 p ## func = (void *)GetProcAddress( mod, #func ); \
152 if (!p ## func) \
153 trace( "GetProcAddress(%s) failed\n", #func );
155 GET_PROC( hmsi, MsiApplyPatchA );
156 GET_PROC( hmsi, MsiGetPatchInfoExA );
157 GET_PROC( hmsi, MsiEnumPatchesExA );
159 GET_PROC( hadvapi32, OpenProcessToken );
160 #undef GET_PROC
163 static BOOL is_process_limited(void)
165 HANDLE token;
167 if (!pOpenProcessToken) return FALSE;
169 if (pOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
171 BOOL ret;
172 TOKEN_ELEVATION_TYPE type = TokenElevationTypeDefault;
173 DWORD size;
175 ret = GetTokenInformation(token, TokenElevationType, &type, sizeof(type), &size);
176 CloseHandle(token);
177 return (ret && type == TokenElevationTypeLimited);
179 return FALSE;
182 static BOOL get_program_files_dir( char *buf, char *buf2 )
184 HKEY hkey;
185 DWORD type, size;
187 if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey ))
188 return FALSE;
190 size = MAX_PATH;
191 if (RegQueryValueExA( hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size ) &&
192 RegQueryValueExA( hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size ))
194 RegCloseKey( hkey );
195 return FALSE;
197 size = MAX_PATH;
198 if (RegQueryValueExA( hkey, "CommonFilesDir", 0, &type, (LPBYTE)buf2, &size ))
200 RegCloseKey( hkey );
201 return FALSE;
203 RegCloseKey( hkey );
204 return TRUE;
207 static void create_file_data( const char *filename, const char *data, DWORD size )
209 HANDLE file;
210 DWORD written;
212 file = CreateFileA( filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
213 if (file == INVALID_HANDLE_VALUE)
214 return;
216 WriteFile( file, data, strlen( data ), &written, NULL );
217 if (size)
219 SetFilePointer( file, size, NULL, FILE_BEGIN );
220 SetEndOfFile( file );
222 CloseHandle( file );
225 #define create_file( name, size ) create_file_data( name, name, size )
227 static BOOL delete_pf( const char *rel_path, BOOL is_file )
229 char path[MAX_PATH];
231 strcpy( path, PROG_FILES_DIR );
232 strcat( path, "\\" );
233 strcat( path, rel_path );
235 if (is_file)
236 return DeleteFileA( path );
237 else
238 return RemoveDirectoryA( path );
241 static DWORD get_pf_file_size( const char *filename )
243 char path[MAX_PATH];
244 HANDLE file;
245 DWORD size;
247 strcpy( path, PROG_FILES_DIR );
248 strcat( path, "\\");
249 strcat( path, filename );
251 file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
252 if (file == INVALID_HANDLE_VALUE)
253 return INVALID_FILE_SIZE;
255 size = GetFileSize( file, NULL );
256 CloseHandle( file );
257 return size;
260 static void write_file( const char *filename, const char *data, DWORD data_size )
262 DWORD size;
263 HANDLE file = CreateFileA( filename, GENERIC_WRITE, 0, NULL,
264 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
265 WriteFile( file, data, data_size, &size, NULL );
266 CloseHandle( file );
269 static void set_suminfo( const WCHAR *filename )
271 UINT r;
272 MSIHANDLE hsi, hdb;
274 r = MsiOpenDatabaseW( filename, MSIDBOPEN_DIRECT, &hdb );
275 ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
277 r = MsiGetSummaryInformationA( hdb, NULL, 7, &hsi );
278 ok( r == ERROR_SUCCESS, "failed to open summaryinfo %u\n", r );
280 r = MsiSummaryInfoSetPropertyA( hsi, 2, VT_LPSTR, 0, NULL, "Installation Database" );
281 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
283 r = MsiSummaryInfoSetPropertyA( hsi, 3, VT_LPSTR, 0, NULL, "Installation Database" );
284 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
286 r = MsiSummaryInfoSetPropertyA( hsi, 4, VT_LPSTR, 0, NULL, "WineHQ" );
287 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
289 r = MsiSummaryInfoSetPropertyA( hsi, 7, VT_LPSTR, 0, NULL, ";1033" );
290 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
292 r = MsiSummaryInfoSetPropertyA( hsi, 9, VT_LPSTR, 0, NULL, "{E528DDD6-4801-4BEC-BBB6-C5EE0FD097E9}" );
293 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
295 r = MsiSummaryInfoSetPropertyA( hsi, 14, VT_I4, 100, NULL, NULL );
296 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
298 r = MsiSummaryInfoSetPropertyA( hsi, 15, VT_I4, 0, NULL, NULL );
299 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
301 r = MsiSummaryInfoPersist( hsi );
302 ok( r == ERROR_SUCCESS, "failed to persist suminfo %u\n", r );
304 r = MsiCloseHandle( hsi );
305 ok( r == ERROR_SUCCESS, "failed to close suminfo %u\n", r );
307 r = MsiCloseHandle( hdb );
308 ok( r == ERROR_SUCCESS, "failed to close database %u\n", r );
311 static void create_database( const char *filename, const struct msi_table *tables, UINT num_tables )
313 MSIHANDLE hdb;
314 UINT r, i;
315 WCHAR *filenameW;
316 int len;
318 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
319 if (!(filenameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return;
320 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
322 r = MsiOpenDatabaseW( filenameW, MSIDBOPEN_CREATE, &hdb );
323 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
325 /* import the tables into the database */
326 for (i = 0; i < num_tables; i++)
328 const struct msi_table *table = &tables[i];
330 write_file( table->filename, table->data, (table->size - 1) * sizeof(char) );
332 r = MsiDatabaseImportA( hdb, CURR_DIR, table->filename );
333 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
335 DeleteFileA( table->filename );
338 r = MsiDatabaseCommit( hdb );
339 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
341 MsiCloseHandle( hdb );
342 set_suminfo( filenameW );
343 HeapFree( GetProcessHeap(), 0, filenameW );
346 /* data for generating a patch */
348 /* table names - encoded as in an msi database file */
349 static const WCHAR p_name0[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
350 static const WCHAR p_name1[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
351 static const WCHAR p_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
352 static const WCHAR p_name3[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
353 static const WCHAR p_name4[] = { 0x3a8c, 0x47cb, 0x45b0, 0x45ec, 0x45a8, 0x4837, 0}; /* CAB_msitest */
354 static const WCHAR p_name5[] = { 0x4840, 0x4596, 0x3e6c, 0x45e4, 0x42e6, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* MsiPatchSequence */
355 static const WCHAR p_name6[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
356 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
357 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
358 /* substorage names */
359 static const WCHAR p_name7[] = { 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075, 0x0070,
360 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* targetToupgraded */
361 static const WCHAR p_name8[] = { 0x0023, 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075,
362 0x0070, 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* #targetToupgraded */
364 /* data in each table */
365 static const WCHAR p_data0[] = { /* _Columns */
366 0x0001, 0x0001, 0x0001, 0x0001, 0x8001, 0x8002, 0x8003, 0x8004,
367 0x0002, 0x0003, 0x0004, 0x0005, 0xad00, 0xbd26, 0x8d00, 0x9502
369 static const WCHAR p_data1[] = { /* _Tables */
370 0x0001
372 static const char p_data2[] = { /* _StringData */
373 "MsiPatchSequencePatchFamilyProductCodeSequenceAttributes1.1.19388.37230913B8D18FBB64CACA239C74C11E3FA74"
375 static const WCHAR p_data3[] = { /* _StringPool */
376 /* len, refs */
377 0, 0, /* string 0 '' */
378 16, 5, /* string 1 'MsiPatchSequence' */
379 11, 1, /* string 2 'PatchFamily' */
380 11, 1, /* string 3 'ProductCode' */
381 8, 1, /* string 4 'Sequence' */
382 10, 1, /* string 5 'Attributes' */
383 15, 1, /* string 6 '1.1.19388.37230' */
384 32, 1, /* string 7 '913B8D18FBB64CACA239C74C11E3FA74' */
386 static const char p_data4[] = { /* CAB_msitest */
387 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00,
388 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00,
389 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9e,
390 0x03, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x12,
391 0xea, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87,
392 0x3c, 0xd4, 0x80, 0x20, 0x00, 0x70, 0x61, 0x74, 0x63, 0x68, 0x2e,
393 0x74, 0x78, 0x74, 0x00, 0x0b, 0x3c, 0xd6, 0xc1, 0x4a, 0x00, 0xea,
394 0x03, 0x5b, 0x80, 0x80, 0x8d, 0x00, 0x10, 0xa1, 0x3e, 0x00, 0x00,
395 0x00, 0x00, 0x03, 0x00, 0x40, 0x30, 0x0c, 0x43, 0xf8, 0xb4, 0x85,
396 0x4d, 0x96, 0x08, 0x0a, 0x92, 0xf0, 0x52, 0xfb, 0xbb, 0x82, 0xf9,
397 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0e, 0x31, 0x7d,
398 0x56, 0xdf, 0xf7, 0x48, 0x7c, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x00, 0x41, 0x80, 0xdf, 0xf7, 0xd8, 0x72, 0xbf, 0xb9, 0x63,
400 0x91, 0x0e, 0x57, 0x1f, 0xfa, 0x1a, 0x66, 0x54, 0x55
402 static const WCHAR p_data5[] = { /* MsiPatchSequence */
403 0x0007, 0x0000, 0x0006, 0x8000
405 static const char p_data6[] = { /* SummaryInformation */
406 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
407 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
408 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
409 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
410 0x30, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
411 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00,
412 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x90,
413 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
414 0x0f, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
415 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x30, 0x46, 0x39, 0x36, 0x43,
416 0x44, 0x43, 0x30, 0x2d, 0x34, 0x43, 0x44, 0x46, 0x2d, 0x34, 0x33,
417 0x30, 0x34, 0x2d, 0x42, 0x32, 0x38, 0x33, 0x2d, 0x37, 0x42, 0x39,
418 0x32, 0x36, 0x34, 0x38, 0x38, 0x39, 0x45, 0x46, 0x37, 0x7d, 0x00,
419 0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x39,
420 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42,
421 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39,
422 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41,
423 0x37, 0x34, 0x7d, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x25, 0x00,
424 0x00, 0x00, 0x3a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f,
425 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x3b, 0x3a, 0x23,
426 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f, 0x75, 0x70, 0x67,
427 0x72, 0x61, 0x64, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
428 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x50, 0x61, 0x74, 0x63, 0x68,
429 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x00,
430 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
433 struct table_data {
434 LPCWSTR name;
435 const void *data;
436 DWORD size;
439 static const struct table_data table_patch_data[] = {
440 { p_name0, p_data0, sizeof p_data0 },
441 { p_name1, p_data1, sizeof p_data1 },
442 { p_name2, p_data2, sizeof p_data2 - 1 },
443 { p_name3, p_data3, sizeof p_data3 },
444 { p_name4, p_data4, sizeof p_data4 },
445 { p_name5, p_data5, sizeof p_data5 },
446 { p_name6, p_data6, sizeof p_data6 }
449 static const WCHAR t1_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
450 static const WCHAR t1_name1[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
451 static const WCHAR t1_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
452 static const WCHAR t1_name3[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
453 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
454 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
456 static const WCHAR t1_data0[] = { /* File */
457 0x0008, 0x0001, 0x03ea, 0x8000
459 static const char t1_data1[] = { /* _StringData */
460 "patch.txt"
462 static const WCHAR t1_data2[] = { /* _StringPool */
463 /* len, refs */
464 0, 0, /* string 0 '' */
465 9, 1, /* string 1 'patch.txt' */
467 static const char t1_data3[] = { /* SummaryInformation */
468 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
469 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
470 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
471 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
472 0x30, 0x00, 0x00, 0x00, 0x9f, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00,
473 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00,
474 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa8,
475 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00,
476 0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
477 0x00, 0xd0, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x00,
478 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x08,
479 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
480 0x07, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8f, 0x01, 0x00,
481 0x00, 0x10, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00, 0x1e, 0x00,
482 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61,
483 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74,
484 0x61, 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
485 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c,
486 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74, 0x61,
487 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
488 0x07, 0x00, 0x00, 0x00, 0x57, 0x69, 0x6e, 0x65, 0x48, 0x51, 0x00,
489 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
490 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
491 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
492 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
493 0x00, 0x1e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x78, 0x38,
494 0x36, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x00,
495 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33,
496 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
497 0x7b, 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46,
498 0x42, 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32,
499 0x33, 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33,
500 0x46, 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b,
501 0x7b, 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46,
502 0x42, 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32,
503 0x33, 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33,
504 0x46, 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b,
505 0x7b, 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34,
506 0x45, 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33,
507 0x30, 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44,
508 0x35, 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
509 0x64, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22,
510 0x09
513 static const struct table_data table_transform1_data[] = {
514 { t1_name0, t1_data0, sizeof t1_data0 },
515 { t1_name1, t1_data1, sizeof t1_data1 - 1 },
516 { t1_name2, t1_data2, sizeof t1_data2 },
517 { t1_name3, t1_data3, sizeof t1_data3 }
520 static const WCHAR t2_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
521 static const WCHAR t2_name1[] = { 0x4840, 0x4216, 0x4327, 0x4824, 0 }; /* Media */
522 static const WCHAR t2_name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
523 static const WCHAR t2_name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
524 static const WCHAR t2_name4[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
525 static const WCHAR t2_name5[] = { 0x4840, 0x4119, 0x41b7, 0x3e6b, 0x41a4, 0x412e, 0x422a, 0 }; /* PatchPackage */
526 static const WCHAR t2_name6[] = { 0x4840, 0x4452, 0x45f6, 0x43e4, 0x3baf, 0x423b, 0x4626,
527 0x4237, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* InstallExecuteSequence */
528 static const WCHAR t2_name7[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
529 static const WCHAR t2_name8[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
530 static const WCHAR t2_name9[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
531 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
532 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
534 static const WCHAR t2_data0[] = { /* File */
535 0x00c0, 0x0001, 0x9000, 0x83e8
537 static const WCHAR t2_data1[] = { /* Media */
538 0x0601, 0x8002, 0x03e9, 0x8000, 0x0000, 0x0007, 0x0000, 0x0008
540 static const WCHAR t2_data2[] = { /* _Columns */
541 0x0401, 0x0009, 0x0000, 0x000a, 0xad48, 0x0401, 0x0009, 0x0000, /* 0x0401 = add row (1), 4 shorts */
542 0x000b, 0xa502, 0x0401, 0x0009, 0x0000, 0x000c, 0x8104, 0x0401,
543 0x0009, 0x0000, 0x000d, 0x8502, 0x0401, 0x0009, 0x0000, 0x000e,
544 0x9900, 0x0401, 0x0009, 0x0000, 0x000f, 0x9d48, 0x0401, 0x0010,
545 0x0000, 0x0011, 0xad26, 0x0401, 0x0010, 0x0000, 0x0012, 0x8502,
546 0x0401, 0x0014, 0x0000, 0x0015, 0xad26, 0x0401, 0x0014, 0x0000,
547 0x000e, 0x8900
549 static const WCHAR t2_data3[] = { /* _Tables */
550 0x0101, 0x0009, 0x0101, 0x0010, 0x0101, 0x0014
552 static const WCHAR t2_data4[] = { /* Property */
553 0x0201, 0x0002, 0x0003, 0x0201, 0x0004, 0x0005
555 static const WCHAR t2_data5[] = { /* PatchPackage */
556 0x0201, 0x0013, 0x8002
558 static const WCHAR t2_data6[] = { /* InstallExecuteSequence */
559 0x0301, 0x0006, 0x0000, 0x87d1
561 static const char t2_data7[] = { /* _StringData */
562 "patch.txtPATCHNEWSUMMARYSUBJECTInstallation DatabasePATCHNEWPACKAGECODE{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}"
563 "PatchFiles#CAB_msitestpropPatchFile_SequencePatchSizeAttributesHeaderStreamRef_PatchPackagePatchIdMedia_"
564 "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}MsiPatchHeadersStreamRef"
566 static const WCHAR t2_data8[] = { /* _StringPool */
567 /* len, refs */
568 0, 0, /* string 0 '' */
569 9, 1, /* string 1 'patch.txt' */
570 22, 1, /* string 2 'PATCHNEWSUMMARYSUBJECT' */
571 21, 1, /* string 3 'Installation Database' */
572 19, 1, /* string 4 'PATCHNEWPACKAGECODE' */
573 38, 1, /* string 5 '{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}' */
574 10, 1, /* string 6 'PatchFiles' */
575 12, 1, /* string 7 '#CAB_msitest' */
576 4, 1, /* string 8 'prop' */
577 5, 7, /* string 9 'Patch' */
578 5, 1, /* string 10 'File_' */
579 8, 1, /* string 11 'Sequence' */
580 9, 1, /* string 12 'PatchSize' */
581 10, 1, /* string 13 'Attributes' */
582 6, 2, /* string 14 'Header' */
583 10, 1, /* string 15 'StreamRef_' */
584 12, 3, /* string 16 'PatchPackage' */
585 7, 1, /* string 17 'PatchId' */
586 6, 1, /* string 18 'Media_' */
587 38, 1, /* string 19 '{0F96CDC0-4CDF-4304-B283-7B9264889EF7}' */
588 15, 3, /* string 20 'MsiPatchHeaders' */
589 9, 1 /* string 21 'StreamRef' */
591 static const char t2_data9[] = { /* SummaryInformation */
592 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
593 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
595 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
596 0x30, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00,
597 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00,
598 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x78,
599 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
600 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
601 0x00, 0x9c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00,
602 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x09,
603 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
604 0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00,
605 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
606 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
607 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
608 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
609 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00,
610 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01,
611 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
612 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00,
613 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
614 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b,
615 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
616 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
617 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
618 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
619 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
620 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
621 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
622 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
623 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45,
624 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30,
625 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35,
626 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2d,
627 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x27, 0x09
630 static const struct table_data table_transform2_data[] = {
631 { t2_name0, t2_data0, sizeof t2_data0 },
632 { t2_name1, t2_data1, sizeof t2_data1 },
633 { t2_name2, t2_data2, sizeof t2_data2 },
634 { t2_name3, t2_data3, sizeof t2_data3 },
635 { t2_name4, t2_data4, sizeof t2_data4 },
636 { t2_name5, t2_data5, sizeof t2_data5 },
637 { t2_name6, t2_data6, sizeof t2_data6 },
638 { t2_name7, t2_data7, sizeof t2_data7 - 1 },
639 { t2_name8, t2_data8, sizeof t2_data8 },
640 { t2_name9, t2_data9, sizeof t2_data9 }
643 static void write_tables( IStorage *stg, const struct table_data *tables, UINT num_tables )
645 IStream *stm;
646 DWORD i, count;
647 HRESULT r;
649 for (i = 0; i < num_tables; i++)
651 r = IStorage_CreateStream( stg, tables[i].name, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
652 if (FAILED( r ))
654 ok( 0, "failed to create stream 0x%08x\n", r );
655 continue;
658 r = IStream_Write( stm, tables[i].data, tables[i].size, &count );
659 if (FAILED( r ) || count != tables[i].size)
660 ok( 0, "failed to write stream\n" );
661 IStream_Release( stm );
665 static void create_patch( const char *filename )
667 IStorage *stg = NULL, *stg1 = NULL, *stg2 = NULL;
668 WCHAR *filenameW;
669 HRESULT r;
670 int len;
671 const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
673 const CLSID CLSID_MsiPatch = {0xc1086, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
674 const CLSID CLSID_MsiTransform = {0xc1082, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
676 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
677 filenameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
678 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
680 r = StgCreateDocfile( filenameW, mode, 0, &stg );
681 HeapFree( GetProcessHeap(), 0, filenameW );
682 ok( r == S_OK, "failed to create storage 0x%08x\n", r );
683 if (!stg)
684 return;
686 r = IStorage_SetClass( stg, &CLSID_MsiPatch );
687 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
689 write_tables( stg, table_patch_data, ARRAY_SIZE( table_patch_data ));
691 r = IStorage_CreateStorage( stg, p_name7, mode, 0, 0, &stg1 );
692 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
694 r = IStorage_SetClass( stg1, &CLSID_MsiTransform );
695 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
697 write_tables( stg1, table_transform1_data, ARRAY_SIZE( table_transform1_data ));
698 IStorage_Release( stg1 );
700 r = IStorage_CreateStorage( stg, p_name8, mode, 0, 0, &stg2 );
701 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
703 r = IStorage_SetClass( stg2, &CLSID_MsiTransform );
704 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
706 write_tables( stg2, table_transform2_data, ARRAY_SIZE( table_transform2_data ));
707 IStorage_Release( stg2 );
708 IStorage_Release( stg );
711 static void test_simple_patch( void )
713 UINT r;
714 DWORD size;
715 char path[MAX_PATH], install_source[MAX_PATH], buffer[32];
716 const char *query;
717 WCHAR pathW[MAX_PATH];
718 MSIHANDLE hpackage, hdb, hview, hrec;
720 if (!pMsiApplyPatchA)
722 win_skip("MsiApplyPatchA is not available\n");
723 return;
725 if (is_process_limited())
727 skip("process is limited\n");
728 return;
731 CreateDirectoryA( "msitest", NULL );
732 create_file( "msitest\\patch.txt", 1000 );
734 create_database( msifile, tables, ARRAY_SIZE(tables) );
735 create_patch( mspfile );
737 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
739 r = MsiInstallProductA( msifile, NULL );
740 if (r != ERROR_SUCCESS)
742 skip("Product installation failed with error code %u\n", r);
743 goto cleanup;
746 size = get_pf_file_size( "msitest\\patch.txt" );
747 ok( size == 1000, "expected 1000, got %u\n", size );
749 size = sizeof(install_source);
750 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
751 "InstallSource", install_source, &size );
752 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
754 strcpy( path, CURR_DIR );
755 strcat( path, "\\" );
756 strcat( path, msifile );
758 r = MsiOpenPackageA( path, &hpackage );
759 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
761 hdb = MsiGetActiveDatabase( hpackage );
762 ok( hdb, "failed to get database handle\n" );
764 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
765 r = MsiDatabaseOpenViewA( hdb, query, &hview );
766 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
768 r = MsiViewExecute( hview, 0 );
769 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
771 r = MsiViewFetch( hview, &hrec );
772 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
774 MsiCloseHandle( hrec );
775 MsiViewClose( hview );
776 MsiCloseHandle( hview );
778 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
779 "AND `Value` = 'Installer Database'";
780 r = MsiDatabaseOpenViewA( hdb, query, &hview );
781 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
783 r = MsiViewExecute( hview, 0 );
784 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
786 r = MsiViewFetch( hview, &hrec );
787 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
789 MsiCloseHandle( hrec );
790 MsiViewClose( hview );
791 MsiCloseHandle( hview );
793 buffer[0] = 0;
794 size = sizeof(buffer);
795 r = MsiGetPropertyA( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
796 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
797 ok( !strcmp( buffer, "Installer Database" ), "expected \'Installer Database\', got \'%s\'\n", buffer );
799 MsiCloseHandle( hdb );
800 MsiCloseHandle( hpackage );
802 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
803 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
804 "expected ERROR_SUCCESS, got %u\n", r );
806 if (r == ERROR_PATCH_PACKAGE_INVALID)
808 win_skip("Windows Installer < 3.0 detected\n");
809 goto uninstall;
812 size = get_pf_file_size( "msitest\\patch.txt" );
813 ok( size == 1002, "expected 1002, got %u\n", size );
815 /* show that MsiOpenPackage applies registered patches */
816 r = MsiOpenPackageA( path, &hpackage );
817 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
819 hdb = MsiGetActiveDatabase( hpackage );
820 ok( hdb, "failed to get database handle\n" );
822 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
823 r = MsiDatabaseOpenViewA( hdb, query, &hview );
824 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
826 r = MsiViewExecute( hview, 0 );
827 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
829 r = MsiViewFetch( hview, &hrec );
830 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
832 MsiCloseHandle( hrec );
833 MsiViewClose( hview );
834 MsiCloseHandle( hview );
836 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
837 "AND `Value` = 'Installation Database'";
838 r = MsiDatabaseOpenViewA( hdb, query, &hview );
839 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
841 r = MsiViewExecute( hview, 0 );
842 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
844 r = MsiViewFetch( hview, &hrec );
845 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
847 MsiCloseHandle( hrec );
848 MsiViewClose( hview );
849 MsiCloseHandle( hview );
851 buffer[0] = 0;
852 size = sizeof(buffer);
853 r = MsiGetPropertyA( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
854 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
855 ok( !strcmp( buffer, "Installation Database" ), "expected \'Installation Database\', got \'%s\'\n", buffer );
857 MsiCloseHandle( hdb );
858 MsiCloseHandle( hpackage );
860 /* show that patches are not committed to the local package database */
861 size = sizeof(path);
862 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
863 "LocalPackage", path, &size );
864 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
866 MultiByteToWideChar( CP_ACP, 0, path, -1, pathW, MAX_PATH );
867 r = MsiOpenDatabaseW( pathW, MSIDBOPEN_READONLY, &hdb );
868 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
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_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
879 MsiCloseHandle( hrec );
880 MsiViewClose( hview );
881 MsiCloseHandle( hview );
882 MsiCloseHandle( hdb );
884 uninstall:
885 size = sizeof(path);
886 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
887 "InstallSource", path, &size );
888 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
889 ok( !strcasecmp( path, install_source ), "wrong path %s\n", path );
891 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
892 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
894 ok( !delete_pf( "msitest\\patch.txt", TRUE ), "file not removed\n" );
895 ok( !delete_pf( "msitest", FALSE ), "directory not removed\n" );
897 cleanup:
898 DeleteFileA( msifile );
899 DeleteFileA( mspfile );
900 DeleteFileA( "msitest\\patch.txt" );
901 RemoveDirectoryA( "msitest" );
904 static void test_MsiOpenDatabase( void )
906 UINT r;
907 MSIHANDLE hdb;
909 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_CREATE, &hdb );
910 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
912 r = MsiDatabaseCommit( hdb );
913 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
914 MsiCloseHandle( hdb );
916 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
917 ok(r == ERROR_OPEN_FAILED, "expected ERROR_OPEN_FAILED, got %u\n", r);
918 DeleteFileA( mspfile );
920 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_CREATE + MSIDBOPEN_PATCHFILE, &hdb );
921 ok(r == ERROR_SUCCESS , "failed to open database %u\n", r);
923 r = MsiDatabaseCommit( hdb );
924 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
925 MsiCloseHandle( hdb );
927 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
928 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
929 MsiCloseHandle( hdb );
930 DeleteFileA( mspfile );
932 create_database( msifile, tables, ARRAY_SIZE(tables) );
933 create_patch( mspfile );
935 r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
936 ok(r == ERROR_OPEN_FAILED, "failed to open database %u\n", r );
938 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
939 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r );
940 MsiCloseHandle( hdb );
942 DeleteFileA( msifile );
943 DeleteFileA( mspfile );
946 static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry )
948 static const char fmt[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
949 char query[0x100];
950 UINT r;
951 MSIHANDLE hview, hrec;
953 sprintf( query, fmt, table, entry );
954 r = MsiDatabaseOpenViewA( hdb, query, &hview );
955 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
957 r = MsiViewExecute( hview, 0 );
958 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
960 r = MsiViewFetch( hview, &hrec );
961 MsiViewClose( hview );
962 MsiCloseHandle( hview );
963 MsiCloseHandle( hrec );
964 return r;
967 static UINT find_entryW( MSIHANDLE hdb, const WCHAR *table, const WCHAR *entry )
969 static const WCHAR fmt[] =
970 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',' ',
971 'W','H','E','R','E',' ','`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0};
972 WCHAR query[0x100];
973 MSIHANDLE hview, hrec;
974 UINT r;
976 wsprintfW( query, fmt, table, entry );
977 r = MsiDatabaseOpenViewW( hdb, query, &hview );
978 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
980 r = MsiViewExecute( hview, 0 );
981 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
983 r = MsiViewFetch( hview, &hrec );
984 MsiViewClose( hview );
985 MsiCloseHandle( hview );
986 MsiCloseHandle( hrec );
987 return r;
990 static INT get_integer( MSIHANDLE hdb, UINT field, const char *query)
992 UINT r;
993 INT ret = -1;
994 MSIHANDLE hview, hrec;
996 r = MsiDatabaseOpenViewA( hdb, query, &hview );
997 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
999 r = MsiViewExecute( hview, 0 );
1000 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1002 r = MsiViewFetch( hview, &hrec );
1003 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1004 if (r == ERROR_SUCCESS)
1006 UINT r_tmp;
1007 ret = MsiRecordGetInteger( hrec, field );
1008 MsiCloseHandle( hrec );
1010 r_tmp = MsiViewFetch( hview, &hrec );
1011 ok( r_tmp == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r);
1014 MsiViewClose( hview );
1015 MsiCloseHandle( hview );
1016 return ret;
1019 static char *get_string( MSIHANDLE hdb, UINT field, const char *query)
1021 UINT r;
1022 static char ret[MAX_PATH];
1023 MSIHANDLE hview, hrec;
1025 ret[0] = '\0';
1027 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1028 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1030 r = MsiViewExecute( hview, 0 );
1031 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1033 r = MsiViewFetch( hview, &hrec );
1034 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1035 if (r == ERROR_SUCCESS)
1037 UINT size = MAX_PATH;
1038 r = MsiRecordGetStringA( hrec, field, ret, &size );
1039 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
1040 MsiCloseHandle( hrec );
1042 r = MsiViewFetch( hview, &hrec );
1043 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r);
1046 MsiViewClose( hview );
1047 MsiCloseHandle( hview );
1048 return ret;
1051 static void test_system_tables( void )
1053 static const char patchsource[] = "MSPSRC0F96CDC04CDF4304B2837B9264889EF7";
1054 static const WCHAR streamsW[] = {'_','S','t','r','e','a','m','s',0};
1055 static const WCHAR CAB_msitest_encodedW[] = {0x3a8c,0x47cb,0x45b0,0x45ec,0x45a8,0x4837,0};
1056 UINT r;
1057 char *cr;
1058 const char *query;
1059 MSIHANDLE hproduct, hdb, hview, hrec;
1061 if (!pMsiApplyPatchA)
1063 win_skip("MsiApplyPatchA is not available\n");
1064 return;
1066 if (is_process_limited())
1068 skip("process is limited\n");
1069 return;
1072 CreateDirectoryA( "msitest", NULL );
1073 create_file( "msitest\\patch.txt", 1000 );
1075 create_database( msifile, tables, ARRAY_SIZE(tables) );
1076 create_patch( mspfile );
1078 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1080 r = MsiInstallProductA( msifile, NULL );
1081 if (r != ERROR_SUCCESS)
1083 skip("Product installation failed with error code %d\n", r);
1084 goto cleanup;
1087 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1088 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1090 hdb = MsiGetActiveDatabase( hproduct );
1091 ok( hdb, "failed to get database handle\n" );
1093 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1094 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1096 query = "SELECT * FROM `_Storages`";
1097 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1098 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1100 r = MsiViewExecute( hview, 0 );
1101 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1103 r = MsiViewFetch( hview, &hrec );
1104 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1106 r = find_entry( hdb, "_Tables", "Directory" );
1107 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1109 r = find_entry( hdb, "_Tables", "File" );
1110 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1112 r = find_entry( hdb, "_Tables", "Component" );
1113 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1115 r = find_entry( hdb, "_Tables", "Feature" );
1116 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1118 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1119 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1121 r = find_entry( hdb, "_Tables", "Property" );
1122 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1124 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1125 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1127 r = find_entry( hdb, "_Tables", "Media" );
1128 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1130 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1131 ok( r == 1, "Got %u\n", r );
1133 r = find_entry( hdb, "_Tables", "_Property" );
1134 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1136 MsiCloseHandle( hrec );
1137 MsiViewClose( hview );
1138 MsiCloseHandle( hview );
1139 MsiCloseHandle( hdb );
1140 MsiCloseHandle( hproduct );
1142 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1143 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1144 "expected ERROR_SUCCESS, got %u\n", r );
1146 if (r == ERROR_PATCH_PACKAGE_INVALID)
1148 win_skip("Windows Installer < 3.0 detected\n");
1149 goto uninstall;
1152 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1153 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1155 hdb = MsiGetActiveDatabase( hproduct );
1156 ok( hdb, "failed to get database handle\n" );
1158 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1159 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1161 r = find_entryW( hdb, streamsW, CAB_msitest_encodedW );
1162 ok( r == ERROR_NO_MORE_ITEMS, "failed to find entry %u\n", r );
1164 query = "SELECT * FROM `_Storages`";
1165 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1166 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1168 r = MsiViewExecute( hview, 0 );
1169 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1171 r = MsiViewFetch( hview, &hrec );
1172 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1174 r = find_entry( hdb, "_Tables", "Directory" );
1175 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1177 r = find_entry( hdb, "_Tables", "File" );
1178 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1180 r = find_entry( hdb, "_Tables", "Component" );
1181 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1183 r = find_entry( hdb, "_Tables", "Feature" );
1184 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1186 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1187 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1189 r = find_entry( hdb, "_Tables", "Property" );
1190 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1192 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1193 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1195 r = find_entry( hdb, "_Tables", "Media" );
1196 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1198 r = find_entry( hdb, "_Tables", "_Property" );
1199 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1201 r = find_entry( hdb, "_Tables", "MsiPatchHeaders" );
1202 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1204 r = find_entry( hdb, "_Tables", "Patch" );
1205 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1207 r = find_entry( hdb, "_Tables", "PatchPackage" );
1208 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1210 cr = get_string( hdb, 6, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1211 todo_wine ok( !strcmp(cr, patchsource), "Expected \"%s\", got \"%s\"\n", patchsource, cr );
1213 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1214 todo_wine ok( r == 100, "Got %u\n", r );
1216 r = get_integer( hdb, 2, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1217 todo_wine ok( r == 10000, "Got %u\n", r );
1219 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1220 ok( r == 1, "Got %u\n", r );
1222 cr = get_string( hdb, 4, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1223 ok( !strcmp(cr, "#CAB_msitest"), "Expected \"#CAB_msitest\", got \"%s\"\n", cr );
1225 r = get_integer( hdb, 8, "SELECT * FROM `File` WHERE `File` = 'patch.txt'");
1226 ok( r == 10000, "Got %u\n", r );
1228 MsiCloseHandle( hrec );
1229 MsiViewClose( hview );
1230 MsiCloseHandle( hview );
1231 MsiCloseHandle( hdb );
1232 MsiCloseHandle( hproduct );
1234 uninstall:
1235 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1236 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1238 cleanup:
1239 DeleteFileA( msifile );
1240 DeleteFileA( mspfile );
1241 DeleteFileA( "msitest\\patch.txt" );
1242 RemoveDirectoryA( "msitest" );
1245 static void test_patch_registration( void )
1247 UINT r, size;
1248 char buffer[MAX_PATH], patch_code[39];
1250 if (!pMsiApplyPatchA || !pMsiGetPatchInfoExA || !pMsiEnumPatchesExA)
1252 win_skip("required functions not available\n");
1253 return;
1255 if (is_process_limited())
1257 skip("process is limited\n");
1258 return;
1261 CreateDirectoryA( "msitest", NULL );
1262 create_file( "msitest\\patch.txt", 1000 );
1264 create_database( msifile, tables, ARRAY_SIZE(tables) );
1265 create_patch( mspfile );
1267 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1269 r = MsiInstallProductA( msifile, NULL );
1270 if (r != ERROR_SUCCESS)
1272 skip("Product installation failed with error code %d\n", r);
1273 goto cleanup;
1276 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1277 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1278 "expected ERROR_SUCCESS, got %u\n", r );
1280 if (r == ERROR_PATCH_PACKAGE_INVALID)
1282 win_skip("Windows Installer < 3.0 detected\n");
1283 goto uninstall;
1286 buffer[0] = 0;
1287 size = sizeof(buffer);
1288 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1289 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1290 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1291 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1292 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1293 ok( buffer[0], "buffer empty\n" );
1295 buffer[0] = 0;
1296 size = sizeof(buffer);
1297 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1298 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1299 NULL, MSIINSTALLCONTEXT_MACHINE,
1300 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1301 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1303 buffer[0] = 0;
1304 size = sizeof(buffer);
1305 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1306 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1307 NULL, MSIINSTALLCONTEXT_USERMANAGED,
1308 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1309 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1310 ok( !buffer[0], "got %s\n", buffer );
1312 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1313 NULL, MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_APPLIED,
1314 0, patch_code, NULL, NULL, NULL, NULL );
1315 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1316 ok( !strcmp( patch_code, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" );
1318 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1319 NULL, MSIINSTALLCONTEXT_MACHINE, MSIPATCHSTATE_APPLIED,
1320 0, patch_code, NULL, NULL, NULL, NULL );
1321 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1323 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1324 NULL, MSIINSTALLCONTEXT_USERMANAGED, MSIPATCHSTATE_APPLIED,
1325 0, patch_code, NULL, NULL, NULL, NULL );
1326 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1328 uninstall:
1329 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1330 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1332 buffer[0] = 0;
1333 size = sizeof(buffer);
1334 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1335 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1336 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1337 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1338 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1340 cleanup:
1341 DeleteFileA( msifile );
1342 DeleteFileA( mspfile );
1343 DeleteFileA( "msitest\\patch.txt" );
1344 RemoveDirectoryA( "msitest" );
1347 START_TEST(patch)
1349 DWORD len;
1350 char temp_path[MAX_PATH], prev_path[MAX_PATH];
1352 init_function_pointers();
1354 GetCurrentDirectoryA( MAX_PATH, prev_path );
1355 GetTempPathA( MAX_PATH, temp_path );
1356 SetCurrentDirectoryA( temp_path );
1358 strcpy( CURR_DIR, temp_path );
1359 len = strlen( CURR_DIR );
1361 if (len && (CURR_DIR[len - 1] == '\\'))
1362 CURR_DIR[len - 1] = 0;
1364 get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR );
1366 test_simple_patch();
1367 test_MsiOpenDatabase();
1368 test_system_tables();
1369 test_patch_registration();
1371 SetCurrentDirectoryA( prev_path );