wmp: Add IWMPControls stub implementation.
[wine.git] / dlls / msi / tests / patch.c
blobb6e990b461e0ad8ec909be685e65d1cd84f94cff
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 #define NUM_PATCH_TABLES (sizeof table_patch_data/sizeof table_patch_data[0])
451 static const WCHAR t1_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
452 static const WCHAR t1_name1[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
453 static const WCHAR t1_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
454 static const WCHAR t1_name3[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
455 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
456 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
458 static const WCHAR t1_data0[] = { /* File */
459 0x0008, 0x0001, 0x03ea, 0x8000
461 static const char t1_data1[] = { /* _StringData */
462 "patch.txt"
464 static const WCHAR t1_data2[] = { /* _StringPool */
465 /* len, refs */
466 0, 0, /* string 0 '' */
467 9, 1, /* string 1 'patch.txt' */
469 static const char t1_data3[] = { /* SummaryInformation */
470 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
471 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
472 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
473 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
474 0x30, 0x00, 0x00, 0x00, 0x9f, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00,
475 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00,
476 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa8,
477 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00,
478 0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
479 0x00, 0xd0, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x00,
480 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x08,
481 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
482 0x07, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8f, 0x01, 0x00,
483 0x00, 0x10, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00, 0x1e, 0x00,
484 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61,
485 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74,
486 0x61, 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
487 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c,
488 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74, 0x61,
489 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
490 0x07, 0x00, 0x00, 0x00, 0x57, 0x69, 0x6e, 0x65, 0x48, 0x51, 0x00,
491 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
492 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
493 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
494 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
495 0x00, 0x1e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x78, 0x38,
496 0x36, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x00,
497 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33,
498 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
499 0x7b, 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46,
500 0x42, 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32,
501 0x33, 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33,
502 0x46, 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b,
503 0x7b, 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46,
504 0x42, 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32,
505 0x33, 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33,
506 0x46, 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b,
507 0x7b, 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34,
508 0x45, 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33,
509 0x30, 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44,
510 0x35, 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
511 0x64, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22,
512 0x09
515 static const struct table_data table_transform1_data[] = {
516 { t1_name0, t1_data0, sizeof t1_data0 },
517 { t1_name1, t1_data1, sizeof t1_data1 - 1 },
518 { t1_name2, t1_data2, sizeof t1_data2 },
519 { t1_name3, t1_data3, sizeof t1_data3 }
522 #define NUM_TRANSFORM1_TABLES (sizeof table_transform1_data/sizeof table_transform1_data[0])
524 static const WCHAR t2_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
525 static const WCHAR t2_name1[] = { 0x4840, 0x4216, 0x4327, 0x4824, 0 }; /* Media */
526 static const WCHAR t2_name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
527 static const WCHAR t2_name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
528 static const WCHAR t2_name4[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
529 static const WCHAR t2_name5[] = { 0x4840, 0x4119, 0x41b7, 0x3e6b, 0x41a4, 0x412e, 0x422a, 0 }; /* PatchPackage */
530 static const WCHAR t2_name6[] = { 0x4840, 0x4452, 0x45f6, 0x43e4, 0x3baf, 0x423b, 0x4626,
531 0x4237, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* InstallExecuteSequence */
532 static const WCHAR t2_name7[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
533 static const WCHAR t2_name8[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
534 static const WCHAR t2_name9[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
535 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
536 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
538 static const WCHAR t2_data0[] = { /* File */
539 0x00c0, 0x0001, 0x9000, 0x83e8
541 static const WCHAR t2_data1[] = { /* Media */
542 0x0601, 0x8002, 0x03e9, 0x8000, 0x0000, 0x0007, 0x0000, 0x0008
544 static const WCHAR t2_data2[] = { /* _Columns */
545 0x0401, 0x0009, 0x0000, 0x000a, 0xad48, 0x0401, 0x0009, 0x0000, /* 0x0401 = add row (1), 4 shorts */
546 0x000b, 0xa502, 0x0401, 0x0009, 0x0000, 0x000c, 0x8104, 0x0401,
547 0x0009, 0x0000, 0x000d, 0x8502, 0x0401, 0x0009, 0x0000, 0x000e,
548 0x9900, 0x0401, 0x0009, 0x0000, 0x000f, 0x9d48, 0x0401, 0x0010,
549 0x0000, 0x0011, 0xad26, 0x0401, 0x0010, 0x0000, 0x0012, 0x8502,
550 0x0401, 0x0014, 0x0000, 0x0015, 0xad26, 0x0401, 0x0014, 0x0000,
551 0x000e, 0x8900
553 static const WCHAR t2_data3[] = { /* _Tables */
554 0x0101, 0x0009, 0x0101, 0x0010, 0x0101, 0x0014
556 static const WCHAR t2_data4[] = { /* Property */
557 0x0201, 0x0002, 0x0003, 0x0201, 0x0004, 0x0005
559 static const WCHAR t2_data5[] = { /* PatchPackage */
560 0x0201, 0x0013, 0x8002
562 static const WCHAR t2_data6[] = { /* InstallExecuteSequence */
563 0x0301, 0x0006, 0x0000, 0x87d1
565 static const char t2_data7[] = { /* _StringData */
566 "patch.txtPATCHNEWSUMMARYSUBJECTInstallation DatabasePATCHNEWPACKAGECODE{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}"
567 "PatchFiles#CAB_msitestpropPatchFile_SequencePatchSizeAttributesHeaderStreamRef_PatchPackagePatchIdMedia_"
568 "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}MsiPatchHeadersStreamRef"
570 static const WCHAR t2_data8[] = { /* _StringPool */
571 /* len, refs */
572 0, 0, /* string 0 '' */
573 9, 1, /* string 1 'patch.txt' */
574 22, 1, /* string 2 'PATCHNEWSUMMARYSUBJECT' */
575 21, 1, /* string 3 'Installation Database' */
576 19, 1, /* string 4 'PATCHNEWPACKAGECODE' */
577 38, 1, /* string 5 '{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}' */
578 10, 1, /* string 6 'PatchFiles' */
579 12, 1, /* string 7 '#CAB_msitest' */
580 4, 1, /* string 8 'prop' */
581 5, 7, /* string 9 'Patch' */
582 5, 1, /* string 10 'File_' */
583 8, 1, /* string 11 'Sequence' */
584 9, 1, /* string 12 'PatchSize' */
585 10, 1, /* string 13 'Attributes' */
586 6, 2, /* string 14 'Header' */
587 10, 1, /* string 15 'StreamRef_' */
588 12, 3, /* string 16 'PatchPackage' */
589 7, 1, /* string 17 'PatchId' */
590 6, 1, /* string 18 'Media_' */
591 38, 1, /* string 19 '{0F96CDC0-4CDF-4304-B283-7B9264889EF7}' */
592 15, 3, /* string 20 'MsiPatchHeaders' */
593 9, 1 /* string 21 'StreamRef' */
595 static const char t2_data9[] = { /* SummaryInformation */
596 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
597 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
599 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
600 0x30, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00,
601 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00,
602 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x78,
603 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
604 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
605 0x00, 0x9c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00,
606 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x09,
607 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
608 0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00,
609 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
610 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
611 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
612 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
613 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00,
614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01,
615 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
616 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00,
617 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
618 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 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 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
624 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
625 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
626 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
627 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45,
628 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30,
629 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35,
630 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2d,
631 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x27, 0x09
634 static const struct table_data table_transform2_data[] = {
635 { t2_name0, t2_data0, sizeof t2_data0 },
636 { t2_name1, t2_data1, sizeof t2_data1 },
637 { t2_name2, t2_data2, sizeof t2_data2 },
638 { t2_name3, t2_data3, sizeof t2_data3 },
639 { t2_name4, t2_data4, sizeof t2_data4 },
640 { t2_name5, t2_data5, sizeof t2_data5 },
641 { t2_name6, t2_data6, sizeof t2_data6 },
642 { t2_name7, t2_data7, sizeof t2_data7 - 1 },
643 { t2_name8, t2_data8, sizeof t2_data8 },
644 { t2_name9, t2_data9, sizeof t2_data9 }
647 #define NUM_TRANSFORM2_TABLES (sizeof table_transform2_data/sizeof table_transform2_data[0])
649 static void write_tables( IStorage *stg, const struct table_data *tables, UINT num_tables )
651 IStream *stm;
652 DWORD i, count;
653 HRESULT r;
655 for (i = 0; i < num_tables; i++)
657 r = IStorage_CreateStream( stg, tables[i].name, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
658 if (FAILED( r ))
660 ok( 0, "failed to create stream 0x%08x\n", r );
661 continue;
664 r = IStream_Write( stm, tables[i].data, tables[i].size, &count );
665 if (FAILED( r ) || count != tables[i].size)
666 ok( 0, "failed to write stream\n" );
667 IStream_Release( stm );
671 static void create_patch( const char *filename )
673 IStorage *stg = NULL, *stg1 = NULL, *stg2 = NULL;
674 WCHAR *filenameW;
675 HRESULT r;
676 int len;
677 const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
679 const CLSID CLSID_MsiPatch = {0xc1086, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
680 const CLSID CLSID_MsiTransform = {0xc1082, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
682 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
683 filenameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
684 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
686 r = StgCreateDocfile( filenameW, mode, 0, &stg );
687 HeapFree( GetProcessHeap(), 0, filenameW );
688 ok( r == S_OK, "failed to create storage 0x%08x\n", r );
689 if (!stg)
690 return;
692 r = IStorage_SetClass( stg, &CLSID_MsiPatch );
693 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
695 write_tables( stg, table_patch_data, NUM_PATCH_TABLES );
697 r = IStorage_CreateStorage( stg, p_name7, mode, 0, 0, &stg1 );
698 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
700 r = IStorage_SetClass( stg1, &CLSID_MsiTransform );
701 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
703 write_tables( stg1, table_transform1_data, NUM_TRANSFORM1_TABLES );
704 IStorage_Release( stg1 );
706 r = IStorage_CreateStorage( stg, p_name8, mode, 0, 0, &stg2 );
707 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
709 r = IStorage_SetClass( stg2, &CLSID_MsiTransform );
710 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
712 write_tables( stg2, table_transform2_data, NUM_TRANSFORM2_TABLES );
713 IStorage_Release( stg2 );
714 IStorage_Release( stg );
717 static void test_simple_patch( void )
719 UINT r;
720 DWORD size;
721 char path[MAX_PATH], install_source[MAX_PATH], buffer[32];
722 const char *query;
723 WCHAR pathW[MAX_PATH];
724 MSIHANDLE hpackage, hdb, hview, hrec;
726 if (!pMsiApplyPatchA)
728 win_skip("MsiApplyPatchA is not available\n");
729 return;
731 if (is_process_limited())
733 skip("process is limited\n");
734 return;
737 CreateDirectoryA( "msitest", NULL );
738 create_file( "msitest\\patch.txt", 1000 );
740 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
741 create_patch( mspfile );
743 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
745 r = MsiInstallProductA( msifile, NULL );
746 if (r != ERROR_SUCCESS)
748 skip("Product installation failed with error code %u\n", r);
749 goto cleanup;
752 size = get_pf_file_size( "msitest\\patch.txt" );
753 ok( size == 1000, "expected 1000, got %u\n", size );
755 size = sizeof(install_source);
756 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
757 "InstallSource", install_source, &size );
758 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
760 strcpy( path, CURR_DIR );
761 strcat( path, "\\" );
762 strcat( path, msifile );
764 r = MsiOpenPackageA( path, &hpackage );
765 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
767 hdb = MsiGetActiveDatabase( hpackage );
768 ok( hdb, "failed to get database handle\n" );
770 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
771 r = MsiDatabaseOpenViewA( hdb, query, &hview );
772 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
774 r = MsiViewExecute( hview, 0 );
775 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
777 r = MsiViewFetch( hview, &hrec );
778 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
780 MsiCloseHandle( hrec );
781 MsiViewClose( hview );
782 MsiCloseHandle( hview );
784 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
785 "AND `Value` = 'Installer Database'";
786 r = MsiDatabaseOpenViewA( hdb, query, &hview );
787 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
789 r = MsiViewExecute( hview, 0 );
790 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
792 r = MsiViewFetch( hview, &hrec );
793 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
795 MsiCloseHandle( hrec );
796 MsiViewClose( hview );
797 MsiCloseHandle( hview );
799 buffer[0] = 0;
800 size = sizeof(buffer);
801 r = MsiGetPropertyA( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
802 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
803 ok( !strcmp( buffer, "Installer Database" ), "expected \'Installer Database\', got \'%s\'\n", buffer );
805 MsiCloseHandle( hdb );
806 MsiCloseHandle( hpackage );
808 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
809 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
810 "expected ERROR_SUCCESS, got %u\n", r );
812 if (r == ERROR_PATCH_PACKAGE_INVALID)
814 win_skip("Windows Installer < 3.0 detected\n");
815 goto uninstall;
818 size = get_pf_file_size( "msitest\\patch.txt" );
819 ok( size == 1002, "expected 1002, got %u\n", size );
821 /* show that MsiOpenPackage applies registered patches */
822 r = MsiOpenPackageA( path, &hpackage );
823 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
825 hdb = MsiGetActiveDatabase( hpackage );
826 ok( hdb, "failed to get database handle\n" );
828 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
829 r = MsiDatabaseOpenViewA( hdb, query, &hview );
830 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
832 r = MsiViewExecute( hview, 0 );
833 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
835 r = MsiViewFetch( hview, &hrec );
836 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
838 MsiCloseHandle( hrec );
839 MsiViewClose( hview );
840 MsiCloseHandle( hview );
842 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
843 "AND `Value` = 'Installation Database'";
844 r = MsiDatabaseOpenViewA( hdb, query, &hview );
845 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
847 r = MsiViewExecute( hview, 0 );
848 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
850 r = MsiViewFetch( hview, &hrec );
851 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
853 MsiCloseHandle( hrec );
854 MsiViewClose( hview );
855 MsiCloseHandle( hview );
857 buffer[0] = 0;
858 size = sizeof(buffer);
859 r = MsiGetPropertyA( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
860 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
861 ok( !strcmp( buffer, "Installation Database" ), "expected \'Installation Database\', got \'%s\'\n", buffer );
863 MsiCloseHandle( hdb );
864 MsiCloseHandle( hpackage );
866 /* show that patches are not committed to the local package database */
867 size = sizeof(path);
868 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
869 "LocalPackage", path, &size );
870 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
872 MultiByteToWideChar( CP_ACP, 0, path, -1, pathW, MAX_PATH );
873 r = MsiOpenDatabaseW( pathW, MSIDBOPEN_READONLY, &hdb );
874 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
876 r = MsiDatabaseOpenViewA( hdb, query, &hview );
877 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
879 r = MsiViewExecute( hview, 0 );
880 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
882 r = MsiViewFetch( hview, &hrec );
883 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
885 MsiCloseHandle( hrec );
886 MsiViewClose( hview );
887 MsiCloseHandle( hview );
888 MsiCloseHandle( hdb );
890 uninstall:
891 size = sizeof(path);
892 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
893 "InstallSource", path, &size );
894 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
895 ok( !strcasecmp( path, install_source ), "wrong path %s\n", path );
897 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
898 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
900 ok( !delete_pf( "msitest\\patch.txt", TRUE ), "file not removed\n" );
901 ok( !delete_pf( "msitest", FALSE ), "directory not removed\n" );
903 cleanup:
904 DeleteFileA( msifile );
905 DeleteFileA( mspfile );
906 DeleteFileA( "msitest\\patch.txt" );
907 RemoveDirectoryA( "msitest" );
910 static void test_MsiOpenDatabase( void )
912 UINT r;
913 MSIHANDLE hdb;
915 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_CREATE, &hdb );
916 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
918 r = MsiDatabaseCommit( hdb );
919 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
920 MsiCloseHandle( hdb );
922 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
923 ok(r == ERROR_OPEN_FAILED, "expected ERROR_OPEN_FAILED, got %u\n", r);
924 DeleteFileA( mspfile );
926 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_CREATE + MSIDBOPEN_PATCHFILE, &hdb );
927 ok(r == ERROR_SUCCESS , "failed to open database %u\n", r);
929 r = MsiDatabaseCommit( hdb );
930 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
931 MsiCloseHandle( hdb );
933 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
934 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
935 MsiCloseHandle( hdb );
936 DeleteFileA( mspfile );
938 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
939 create_patch( mspfile );
941 r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
942 ok(r == ERROR_OPEN_FAILED, "failed to open database %u\n", r );
944 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
945 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r );
946 MsiCloseHandle( hdb );
948 DeleteFileA( msifile );
949 DeleteFileA( mspfile );
952 static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry )
954 static const char fmt[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
955 char query[0x100];
956 UINT r;
957 MSIHANDLE hview, hrec;
959 sprintf( query, fmt, table, entry );
960 r = MsiDatabaseOpenViewA( hdb, query, &hview );
961 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
963 r = MsiViewExecute( hview, 0 );
964 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
966 r = MsiViewFetch( hview, &hrec );
967 MsiViewClose( hview );
968 MsiCloseHandle( hview );
969 MsiCloseHandle( hrec );
970 return r;
973 static UINT find_entryW( MSIHANDLE hdb, const WCHAR *table, const WCHAR *entry )
975 static const WCHAR fmt[] =
976 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',' ',
977 'W','H','E','R','E',' ','`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0};
978 WCHAR query[0x100];
979 MSIHANDLE hview, hrec;
980 UINT r;
982 wsprintfW( query, fmt, table, entry );
983 r = MsiDatabaseOpenViewW( hdb, query, &hview );
984 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
986 r = MsiViewExecute( hview, 0 );
987 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
989 r = MsiViewFetch( hview, &hrec );
990 MsiViewClose( hview );
991 MsiCloseHandle( hview );
992 MsiCloseHandle( hrec );
993 return r;
996 static INT get_integer( MSIHANDLE hdb, UINT field, const char *query)
998 UINT r;
999 INT ret = -1;
1000 MSIHANDLE hview, hrec;
1002 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1003 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1005 r = MsiViewExecute( hview, 0 );
1006 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1008 r = MsiViewFetch( hview, &hrec );
1009 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1010 if (r == ERROR_SUCCESS)
1012 UINT r_tmp;
1013 ret = MsiRecordGetInteger( hrec, field );
1014 MsiCloseHandle( hrec );
1016 r_tmp = MsiViewFetch( hview, &hrec );
1017 ok( r_tmp == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r);
1020 MsiViewClose( hview );
1021 MsiCloseHandle( hview );
1022 return ret;
1025 static char *get_string( MSIHANDLE hdb, UINT field, const char *query)
1027 UINT r;
1028 static char ret[MAX_PATH];
1029 MSIHANDLE hview, hrec;
1031 ret[0] = '\0';
1033 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1034 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1036 r = MsiViewExecute( hview, 0 );
1037 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1039 r = MsiViewFetch( hview, &hrec );
1040 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1041 if (r == ERROR_SUCCESS)
1043 UINT size = MAX_PATH;
1044 r = MsiRecordGetStringA( hrec, field, ret, &size );
1045 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
1046 MsiCloseHandle( hrec );
1048 r = MsiViewFetch( hview, &hrec );
1049 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r);
1052 MsiViewClose( hview );
1053 MsiCloseHandle( hview );
1054 return ret;
1057 static void test_system_tables( void )
1059 static const char patchsource[] = "MSPSRC0F96CDC04CDF4304B2837B9264889EF7";
1060 static const WCHAR streamsW[] = {'_','S','t','r','e','a','m','s',0};
1061 static const WCHAR CAB_msitest_encodedW[] = {0x3a8c,0x47cb,0x45b0,0x45ec,0x45a8,0x4837,0};
1062 UINT r;
1063 char *cr;
1064 const char *query;
1065 MSIHANDLE hproduct, hdb, hview, hrec;
1067 if (!pMsiApplyPatchA)
1069 win_skip("MsiApplyPatchA is not available\n");
1070 return;
1072 if (is_process_limited())
1074 skip("process is limited\n");
1075 return;
1078 CreateDirectoryA( "msitest", NULL );
1079 create_file( "msitest\\patch.txt", 1000 );
1081 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
1082 create_patch( mspfile );
1084 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1086 r = MsiInstallProductA( msifile, NULL );
1087 if (r != ERROR_SUCCESS)
1089 skip("Product installation failed with error code %d\n", r);
1090 goto cleanup;
1093 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1094 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1096 hdb = MsiGetActiveDatabase( hproduct );
1097 ok( hdb, "failed to get database handle\n" );
1099 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1100 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1102 query = "SELECT * FROM `_Storages`";
1103 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1104 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1106 r = MsiViewExecute( hview, 0 );
1107 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1109 r = MsiViewFetch( hview, &hrec );
1110 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1112 r = find_entry( hdb, "_Tables", "Directory" );
1113 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1115 r = find_entry( hdb, "_Tables", "File" );
1116 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1118 r = find_entry( hdb, "_Tables", "Component" );
1119 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1121 r = find_entry( hdb, "_Tables", "Feature" );
1122 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1124 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1125 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1127 r = find_entry( hdb, "_Tables", "Property" );
1128 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1130 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1131 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1133 r = find_entry( hdb, "_Tables", "Media" );
1134 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1136 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1137 ok( r == 1, "Got %u\n", r );
1139 r = find_entry( hdb, "_Tables", "_Property" );
1140 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1142 MsiCloseHandle( hrec );
1143 MsiViewClose( hview );
1144 MsiCloseHandle( hview );
1145 MsiCloseHandle( hdb );
1146 MsiCloseHandle( hproduct );
1148 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1149 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1150 "expected ERROR_SUCCESS, got %u\n", r );
1152 if (r == ERROR_PATCH_PACKAGE_INVALID)
1154 win_skip("Windows Installer < 3.0 detected\n");
1155 goto uninstall;
1158 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1159 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1161 hdb = MsiGetActiveDatabase( hproduct );
1162 ok( hdb, "failed to get database handle\n" );
1164 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1165 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1167 r = find_entryW( hdb, streamsW, CAB_msitest_encodedW );
1168 ok( r == ERROR_NO_MORE_ITEMS, "failed to find entry %u\n", r );
1170 query = "SELECT * FROM `_Storages`";
1171 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1172 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1174 r = MsiViewExecute( hview, 0 );
1175 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1177 r = MsiViewFetch( hview, &hrec );
1178 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1180 r = find_entry( hdb, "_Tables", "Directory" );
1181 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1183 r = find_entry( hdb, "_Tables", "File" );
1184 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1186 r = find_entry( hdb, "_Tables", "Component" );
1187 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1189 r = find_entry( hdb, "_Tables", "Feature" );
1190 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1192 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1193 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1195 r = find_entry( hdb, "_Tables", "Property" );
1196 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1198 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1199 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1201 r = find_entry( hdb, "_Tables", "Media" );
1202 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1204 r = find_entry( hdb, "_Tables", "_Property" );
1205 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1207 r = find_entry( hdb, "_Tables", "MsiPatchHeaders" );
1208 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1210 r = find_entry( hdb, "_Tables", "Patch" );
1211 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1213 r = find_entry( hdb, "_Tables", "PatchPackage" );
1214 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1216 cr = get_string( hdb, 6, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1217 todo_wine ok( !strcmp(cr, patchsource), "Expected \"%s\", got \"%s\"\n", patchsource, cr );
1219 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1220 todo_wine ok( r == 100, "Got %u\n", r );
1222 r = get_integer( hdb, 2, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1223 todo_wine ok( r == 10000, "Got %u\n", r );
1225 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1226 ok( r == 1, "Got %u\n", r );
1228 cr = get_string( hdb, 4, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1229 ok( !strcmp(cr, "#CAB_msitest"), "Expected \"#CAB_msitest\", got \"%s\"\n", cr );
1231 r = get_integer( hdb, 8, "SELECT * FROM `File` WHERE `File` = 'patch.txt'");
1232 ok( r == 10000, "Got %u\n", r );
1234 MsiCloseHandle( hrec );
1235 MsiViewClose( hview );
1236 MsiCloseHandle( hview );
1237 MsiCloseHandle( hdb );
1238 MsiCloseHandle( hproduct );
1240 uninstall:
1241 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1242 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1244 cleanup:
1245 DeleteFileA( msifile );
1246 DeleteFileA( mspfile );
1247 DeleteFileA( "msitest\\patch.txt" );
1248 RemoveDirectoryA( "msitest" );
1251 static void test_patch_registration( void )
1253 UINT r, size;
1254 char buffer[MAX_PATH], patch_code[39];
1256 if (!pMsiApplyPatchA || !pMsiGetPatchInfoExA || !pMsiEnumPatchesExA)
1258 win_skip("required functions not available\n");
1259 return;
1261 if (is_process_limited())
1263 skip("process is limited\n");
1264 return;
1267 CreateDirectoryA( "msitest", NULL );
1268 create_file( "msitest\\patch.txt", 1000 );
1270 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
1271 create_patch( mspfile );
1273 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1275 r = MsiInstallProductA( msifile, NULL );
1276 if (r != ERROR_SUCCESS)
1278 skip("Product installation failed with error code %d\n", r);
1279 goto cleanup;
1282 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1283 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1284 "expected ERROR_SUCCESS, got %u\n", r );
1286 if (r == ERROR_PATCH_PACKAGE_INVALID)
1288 win_skip("Windows Installer < 3.0 detected\n");
1289 goto uninstall;
1292 buffer[0] = 0;
1293 size = sizeof(buffer);
1294 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1295 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1296 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1297 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1298 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1299 ok( buffer[0], "buffer empty\n" );
1301 buffer[0] = 0;
1302 size = sizeof(buffer);
1303 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1304 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1305 NULL, MSIINSTALLCONTEXT_MACHINE,
1306 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1307 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1309 buffer[0] = 0;
1310 size = sizeof(buffer);
1311 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1312 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1313 NULL, MSIINSTALLCONTEXT_USERMANAGED,
1314 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1315 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1316 ok( !buffer[0], "got %s\n", buffer );
1318 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1319 NULL, MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_APPLIED,
1320 0, patch_code, NULL, NULL, NULL, NULL );
1321 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1322 ok( !strcmp( patch_code, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" );
1324 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1325 NULL, MSIINSTALLCONTEXT_MACHINE, MSIPATCHSTATE_APPLIED,
1326 0, patch_code, NULL, NULL, NULL, NULL );
1327 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1329 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1330 NULL, MSIINSTALLCONTEXT_USERMANAGED, MSIPATCHSTATE_APPLIED,
1331 0, patch_code, NULL, NULL, NULL, NULL );
1332 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1334 uninstall:
1335 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1336 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1338 buffer[0] = 0;
1339 size = sizeof(buffer);
1340 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1341 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1342 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1343 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1344 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1346 cleanup:
1347 DeleteFileA( msifile );
1348 DeleteFileA( mspfile );
1349 DeleteFileA( "msitest\\patch.txt" );
1350 RemoveDirectoryA( "msitest" );
1353 START_TEST(patch)
1355 DWORD len;
1356 char temp_path[MAX_PATH], prev_path[MAX_PATH];
1358 init_function_pointers();
1360 GetCurrentDirectoryA( MAX_PATH, prev_path );
1361 GetTempPathA( MAX_PATH, temp_path );
1362 SetCurrentDirectoryA( temp_path );
1364 strcpy( CURR_DIR, temp_path );
1365 len = strlen( CURR_DIR );
1367 if (len && (CURR_DIR[len - 1] == '\\'))
1368 CURR_DIR[len - 1] = 0;
1370 get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR );
1372 test_simple_patch();
1373 test_MsiOpenDatabase();
1374 test_system_tables();
1375 test_patch_registration();
1377 SetCurrentDirectoryA( prev_path );