TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / msi / tests / patch.c
blob3c2365651955f5cd27540baf51085fb8819e7303
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, 0x9c, 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, 0xf4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
482 0x04, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00,
483 0x00, 0x10, 0x00, 0x00, 0x00, 0x94, 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, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31,
496 0x30, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x06,
497 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 0x00,
498 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b, 0x39, 0x31,
499 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
500 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
501 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
502 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x39, 0x31,
503 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
504 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
505 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
506 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x41, 0x32,
507 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45, 0x32, 0x43,
508 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30, 0x39, 0x2d,
509 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35, 0x46, 0x34,
510 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
511 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22, 0x09
514 static const struct table_data table_transform1_data[] = {
515 { t1_name0, t1_data0, sizeof t1_data0 },
516 { t1_name1, t1_data1, sizeof t1_data1 - 1 },
517 { t1_name2, t1_data2, sizeof t1_data2 },
518 { t1_name3, t1_data3, sizeof t1_data3 }
521 #define NUM_TRANSFORM1_TABLES (sizeof table_transform1_data/sizeof table_transform1_data[0])
523 static const WCHAR t2_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
524 static const WCHAR t2_name1[] = { 0x4840, 0x4216, 0x4327, 0x4824, 0 }; /* Media */
525 static const WCHAR t2_name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
526 static const WCHAR t2_name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
527 static const WCHAR t2_name4[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
528 static const WCHAR t2_name5[] = { 0x4840, 0x4119, 0x41b7, 0x3e6b, 0x41a4, 0x412e, 0x422a, 0 }; /* PatchPackage */
529 static const WCHAR t2_name6[] = { 0x4840, 0x4452, 0x45f6, 0x43e4, 0x3baf, 0x423b, 0x4626,
530 0x4237, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* InstallExecuteSequence */
531 static const WCHAR t2_name7[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
532 static const WCHAR t2_name8[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
533 static const WCHAR t2_name9[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
534 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
535 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
537 static const WCHAR t2_data0[] = { /* File */
538 0x00c0, 0x0001, 0x9000, 0x83e8
540 static const WCHAR t2_data1[] = { /* Media */
541 0x0601, 0x8002, 0x03e9, 0x8000, 0x0000, 0x0007, 0x0000, 0x0008
543 static const WCHAR t2_data2[] = { /* _Columns */
544 0x0401, 0x0009, 0x0000, 0x000a, 0xad48, 0x0401, 0x0009, 0x0000, /* 0x0401 = add row (1), 4 shorts */
545 0x000b, 0xa502, 0x0401, 0x0009, 0x0000, 0x000c, 0x8104, 0x0401,
546 0x0009, 0x0000, 0x000d, 0x8502, 0x0401, 0x0009, 0x0000, 0x000e,
547 0x9900, 0x0401, 0x0009, 0x0000, 0x000f, 0x9d48, 0x0401, 0x0010,
548 0x0000, 0x0011, 0xad26, 0x0401, 0x0010, 0x0000, 0x0012, 0x8502,
549 0x0401, 0x0014, 0x0000, 0x0015, 0xad26, 0x0401, 0x0014, 0x0000,
550 0x000e, 0x8900
552 static const WCHAR t2_data3[] = { /* _Tables */
553 0x0101, 0x0009, 0x0101, 0x0010, 0x0101, 0x0014
555 static const WCHAR t2_data4[] = { /* Property */
556 0x0201, 0x0002, 0x0003, 0x0201, 0x0004, 0x0005
558 static const WCHAR t2_data5[] = { /* PatchPackage */
559 0x0201, 0x0013, 0x8002
561 static const WCHAR t2_data6[] = { /* InstallExecuteSequence */
562 0x0301, 0x0006, 0x0000, 0x87d1
564 static const char t2_data7[] = { /* _StringData */
565 "patch.txtPATCHNEWSUMMARYSUBJECTInstallation DatabasePATCHNEWPACKAGECODE{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}"
566 "PatchFiles#CAB_msitestpropPatchFile_SequencePatchSizeAttributesHeaderStreamRef_PatchPackagePatchIdMedia_"
567 "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}MsiPatchHeadersStreamRef"
569 static const WCHAR t2_data8[] = { /* _StringPool */
570 /* len, refs */
571 0, 0, /* string 0 '' */
572 9, 1, /* string 1 'patch.txt' */
573 22, 1, /* string 2 'PATCHNEWSUMMARYSUBJECT' */
574 21, 1, /* string 3 'Installation Database' */
575 19, 1, /* string 4 'PATCHNEWPACKAGECODE' */
576 38, 1, /* string 5 '{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}' */
577 10, 1, /* string 6 'PatchFiles' */
578 12, 1, /* string 7 '#CAB_msitest' */
579 4, 1, /* string 8 'prop' */
580 5, 7, /* string 9 'Patch' */
581 5, 1, /* string 10 'File_' */
582 8, 1, /* string 11 'Sequence' */
583 9, 1, /* string 12 'PatchSize' */
584 10, 1, /* string 13 'Attributes' */
585 6, 2, /* string 14 'Header' */
586 10, 1, /* string 15 'StreamRef_' */
587 12, 3, /* string 16 'PatchPackage' */
588 7, 1, /* string 17 'PatchId' */
589 6, 1, /* string 18 'Media_' */
590 38, 1, /* string 19 '{0F96CDC0-4CDF-4304-B283-7B9264889EF7}' */
591 15, 3, /* string 20 'MsiPatchHeaders' */
592 9, 1 /* string 21 'StreamRef' */
594 static const char t2_data9[] = { /* SummaryInformation */
595 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
596 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
598 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
599 0x30, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00,
600 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00,
601 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x78,
602 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
603 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
604 0x00, 0x9c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00,
605 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x09,
606 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
607 0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00,
608 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
609 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
610 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
611 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
612 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00,
613 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01,
614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
615 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00,
616 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
617 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b,
618 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
619 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
620 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
621 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
622 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
623 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
624 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
625 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
626 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45,
627 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30,
628 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35,
629 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2d,
630 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x27, 0x09
633 static const struct table_data table_transform2_data[] = {
634 { t2_name0, t2_data0, sizeof t2_data0 },
635 { t2_name1, t2_data1, sizeof t2_data1 },
636 { t2_name2, t2_data2, sizeof t2_data2 },
637 { t2_name3, t2_data3, sizeof t2_data3 },
638 { t2_name4, t2_data4, sizeof t2_data4 },
639 { t2_name5, t2_data5, sizeof t2_data5 },
640 { t2_name6, t2_data6, sizeof t2_data6 },
641 { t2_name7, t2_data7, sizeof t2_data7 - 1 },
642 { t2_name8, t2_data8, sizeof t2_data8 },
643 { t2_name9, t2_data9, sizeof t2_data9 }
646 #define NUM_TRANSFORM2_TABLES (sizeof table_transform2_data/sizeof table_transform2_data[0])
648 static void write_tables( IStorage *stg, const struct table_data *tables, UINT num_tables )
650 IStream *stm;
651 DWORD i, count;
652 HRESULT r;
654 for (i = 0; i < num_tables; i++)
656 r = IStorage_CreateStream( stg, tables[i].name, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
657 if (FAILED( r ))
659 ok( 0, "failed to create stream 0x%08x\n", r );
660 continue;
663 r = IStream_Write( stm, tables[i].data, tables[i].size, &count );
664 if (FAILED( r ) || count != tables[i].size)
665 ok( 0, "failed to write stream\n" );
666 IStream_Release( stm );
670 static void create_patch( const char *filename )
672 IStorage *stg = NULL, *stg1 = NULL, *stg2 = NULL;
673 WCHAR *filenameW;
674 HRESULT r;
675 int len;
676 const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
678 const CLSID CLSID_MsiPatch = {0xc1086, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
679 const CLSID CLSID_MsiTransform = {0xc1082, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
681 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
682 filenameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
683 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
685 r = StgCreateDocfile( filenameW, mode, 0, &stg );
686 HeapFree( GetProcessHeap(), 0, filenameW );
687 ok( r == S_OK, "failed to create storage 0x%08x\n", r );
688 if (!stg)
689 return;
691 r = IStorage_SetClass( stg, &CLSID_MsiPatch );
692 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
694 write_tables( stg, table_patch_data, NUM_PATCH_TABLES );
696 r = IStorage_CreateStorage( stg, p_name7, mode, 0, 0, &stg1 );
697 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
699 r = IStorage_SetClass( stg1, &CLSID_MsiTransform );
700 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
702 write_tables( stg1, table_transform1_data, NUM_TRANSFORM1_TABLES );
703 IStorage_Release( stg1 );
705 r = IStorage_CreateStorage( stg, p_name8, mode, 0, 0, &stg2 );
706 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
708 r = IStorage_SetClass( stg2, &CLSID_MsiTransform );
709 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
711 write_tables( stg2, table_transform2_data, NUM_TRANSFORM2_TABLES );
712 IStorage_Release( stg2 );
713 IStorage_Release( stg );
716 static void test_simple_patch( void )
718 UINT r;
719 DWORD size;
720 char path[MAX_PATH], install_source[MAX_PATH], buffer[32];
721 const char *query;
722 WCHAR pathW[MAX_PATH];
723 MSIHANDLE hpackage, hdb, hview, hrec;
725 if (!pMsiApplyPatchA)
727 win_skip("MsiApplyPatchA is not available\n");
728 return;
730 if (is_process_limited())
732 skip("process is limited\n");
733 return;
736 CreateDirectoryA( "msitest", NULL );
737 create_file( "msitest\\patch.txt", 1000 );
739 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
740 create_patch( mspfile );
742 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
744 r = MsiInstallProductA( msifile, NULL );
745 if (r != ERROR_SUCCESS)
747 skip("Product installation failed with error code %u\n", r);
748 goto cleanup;
751 size = get_pf_file_size( "msitest\\patch.txt" );
752 ok( size == 1000, "expected 1000, got %u\n", size );
754 size = sizeof(install_source);
755 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
756 "InstallSource", install_source, &size );
757 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
759 strcpy( path, CURR_DIR );
760 strcat( path, "\\" );
761 strcat( path, msifile );
763 r = MsiOpenPackageA( path, &hpackage );
764 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
766 hdb = MsiGetActiveDatabase( hpackage );
767 ok( hdb, "failed to get database handle\n" );
769 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
770 r = MsiDatabaseOpenViewA( hdb, query, &hview );
771 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
773 r = MsiViewExecute( hview, 0 );
774 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
776 r = MsiViewFetch( hview, &hrec );
777 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
779 MsiCloseHandle( hrec );
780 MsiViewClose( hview );
781 MsiCloseHandle( hview );
783 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
784 "AND `Value` = 'Installer Database'";
785 r = MsiDatabaseOpenViewA( hdb, query, &hview );
786 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
788 r = MsiViewExecute( hview, 0 );
789 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
791 r = MsiViewFetch( hview, &hrec );
792 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
794 MsiCloseHandle( hrec );
795 MsiViewClose( hview );
796 MsiCloseHandle( hview );
798 buffer[0] = 0;
799 size = sizeof(buffer);
800 r = MsiGetPropertyA( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
801 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
802 ok( !strcmp( buffer, "Installer Database" ), "expected \'Installer Database\', got \'%s\'\n", buffer );
804 MsiCloseHandle( hdb );
805 MsiCloseHandle( hpackage );
807 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
808 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
809 "expected ERROR_SUCCESS, got %u\n", r );
811 if (r == ERROR_PATCH_PACKAGE_INVALID)
813 win_skip("Windows Installer < 3.0 detected\n");
814 goto uninstall;
817 size = get_pf_file_size( "msitest\\patch.txt" );
818 ok( size == 1002, "expected 1002, got %u\n", size );
820 /* show that MsiOpenPackage applies registered patches */
821 r = MsiOpenPackageA( path, &hpackage );
822 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
824 hdb = MsiGetActiveDatabase( hpackage );
825 ok( hdb, "failed to get database handle\n" );
827 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
828 r = MsiDatabaseOpenViewA( hdb, query, &hview );
829 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
831 r = MsiViewExecute( hview, 0 );
832 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
834 r = MsiViewFetch( hview, &hrec );
835 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
837 MsiCloseHandle( hrec );
838 MsiViewClose( hview );
839 MsiCloseHandle( hview );
841 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
842 "AND `Value` = 'Installation Database'";
843 r = MsiDatabaseOpenViewA( hdb, query, &hview );
844 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
846 r = MsiViewExecute( hview, 0 );
847 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
849 r = MsiViewFetch( hview, &hrec );
850 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
852 MsiCloseHandle( hrec );
853 MsiViewClose( hview );
854 MsiCloseHandle( hview );
856 buffer[0] = 0;
857 size = sizeof(buffer);
858 r = MsiGetPropertyA( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
859 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
860 ok( !strcmp( buffer, "Installation Database" ), "expected \'Installation Database\', got \'%s\'\n", buffer );
862 MsiCloseHandle( hdb );
863 MsiCloseHandle( hpackage );
865 /* show that patches are not committed to the local package database */
866 size = sizeof(path);
867 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
868 "LocalPackage", path, &size );
869 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
871 MultiByteToWideChar( CP_ACP, 0, path, -1, pathW, MAX_PATH );
872 r = MsiOpenDatabaseW( pathW, MSIDBOPEN_READONLY, &hdb );
873 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
875 r = MsiDatabaseOpenViewA( hdb, query, &hview );
876 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
878 r = MsiViewExecute( hview, 0 );
879 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
881 r = MsiViewFetch( hview, &hrec );
882 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
884 MsiCloseHandle( hrec );
885 MsiViewClose( hview );
886 MsiCloseHandle( hview );
887 MsiCloseHandle( hdb );
889 uninstall:
890 size = sizeof(path);
891 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
892 "InstallSource", path, &size );
893 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
894 ok( !strcasecmp( path, install_source ), "wrong path %s\n", path );
896 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
897 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
899 ok( !delete_pf( "msitest\\patch.txt", TRUE ), "file not removed\n" );
900 ok( !delete_pf( "msitest", FALSE ), "directory not removed\n" );
902 cleanup:
903 DeleteFileA( msifile );
904 DeleteFileA( mspfile );
905 DeleteFileA( "msitest\\patch.txt" );
906 RemoveDirectoryA( "msitest" );
909 static void test_MsiOpenDatabase( void )
911 UINT r;
912 MSIHANDLE hdb;
914 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_CREATE, &hdb );
915 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
917 r = MsiDatabaseCommit( hdb );
918 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
919 MsiCloseHandle( hdb );
921 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
922 ok(r == ERROR_OPEN_FAILED, "expected ERROR_OPEN_FAILED, got %u\n", r);
923 DeleteFileA( mspfile );
925 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_CREATE + MSIDBOPEN_PATCHFILE, &hdb );
926 ok(r == ERROR_SUCCESS , "failed to open database %u\n", r);
928 r = MsiDatabaseCommit( hdb );
929 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
930 MsiCloseHandle( hdb );
932 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
933 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
934 MsiCloseHandle( hdb );
935 DeleteFileA( mspfile );
937 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
938 create_patch( mspfile );
940 r = MsiOpenDatabaseW( msifileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
941 ok(r == ERROR_OPEN_FAILED, "failed to open database %u\n", r );
943 r = MsiOpenDatabaseW( mspfileW, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
944 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r );
945 MsiCloseHandle( hdb );
947 DeleteFileA( msifile );
948 DeleteFileA( mspfile );
951 static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry )
953 static const char fmt[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
954 char query[0x100];
955 UINT r;
956 MSIHANDLE hview, hrec;
958 sprintf( query, fmt, table, entry );
959 r = MsiDatabaseOpenViewA( hdb, query, &hview );
960 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
962 r = MsiViewExecute( hview, 0 );
963 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
965 r = MsiViewFetch( hview, &hrec );
966 MsiViewClose( hview );
967 MsiCloseHandle( hview );
968 MsiCloseHandle( hrec );
969 return r;
972 static UINT find_entryW( MSIHANDLE hdb, const WCHAR *table, const WCHAR *entry )
974 static const WCHAR fmt[] =
975 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',' ',
976 'W','H','E','R','E',' ','`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0};
977 WCHAR query[0x100];
978 MSIHANDLE hview, hrec;
979 UINT r;
981 wsprintfW( query, fmt, table, entry );
982 r = MsiDatabaseOpenViewW( hdb, query, &hview );
983 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
985 r = MsiViewExecute( hview, 0 );
986 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
988 r = MsiViewFetch( hview, &hrec );
989 MsiViewClose( hview );
990 MsiCloseHandle( hview );
991 MsiCloseHandle( hrec );
992 return r;
995 static INT get_integer( MSIHANDLE hdb, UINT field, const char *query)
997 UINT r;
998 INT ret = -1;
999 MSIHANDLE hview, hrec;
1001 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1002 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1004 r = MsiViewExecute( hview, 0 );
1005 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1007 r = MsiViewFetch( hview, &hrec );
1008 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1009 if (r == ERROR_SUCCESS)
1011 UINT r_tmp;
1012 ret = MsiRecordGetInteger( hrec, field );
1013 MsiCloseHandle( hrec );
1015 r_tmp = MsiViewFetch( hview, &hrec );
1016 ok( r_tmp == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r);
1019 MsiViewClose( hview );
1020 MsiCloseHandle( hview );
1021 return ret;
1024 static char *get_string( MSIHANDLE hdb, UINT field, const char *query)
1026 UINT r;
1027 static char ret[MAX_PATH];
1028 MSIHANDLE hview, hrec;
1030 ret[0] = '\0';
1032 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1033 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1035 r = MsiViewExecute( hview, 0 );
1036 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1038 r = MsiViewFetch( hview, &hrec );
1039 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1040 if (r == ERROR_SUCCESS)
1042 UINT size = MAX_PATH;
1043 r = MsiRecordGetStringA( hrec, field, ret, &size );
1044 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
1045 MsiCloseHandle( hrec );
1047 r = MsiViewFetch( hview, &hrec );
1048 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r);
1051 MsiViewClose( hview );
1052 MsiCloseHandle( hview );
1053 return ret;
1056 static void test_system_tables( void )
1058 static const char patchsource[] = "MSPSRC0F96CDC04CDF4304B2837B9264889EF7";
1059 static const WCHAR streamsW[] = {'_','S','t','r','e','a','m','s',0};
1060 static const WCHAR CAB_msitest_encodedW[] = {0x3a8c,0x47cb,0x45b0,0x45ec,0x45a8,0x4837,0};
1061 UINT r;
1062 char *cr;
1063 const char *query;
1064 MSIHANDLE hproduct, hdb, hview, hrec;
1066 if (!pMsiApplyPatchA)
1068 win_skip("MsiApplyPatchA is not available\n");
1069 return;
1071 if (is_process_limited())
1073 skip("process is limited\n");
1074 return;
1077 CreateDirectoryA( "msitest", NULL );
1078 create_file( "msitest\\patch.txt", 1000 );
1080 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
1081 create_patch( mspfile );
1083 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1085 r = MsiInstallProductA( msifile, NULL );
1086 if (r != ERROR_SUCCESS)
1088 skip("Product installation failed with error code %d\n", r);
1089 goto cleanup;
1092 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1093 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1095 hdb = MsiGetActiveDatabase( hproduct );
1096 ok( hdb, "failed to get database handle\n" );
1098 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1099 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1101 query = "SELECT * FROM `_Storages`";
1102 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1103 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1105 r = MsiViewExecute( hview, 0 );
1106 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1108 r = MsiViewFetch( hview, &hrec );
1109 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1111 r = find_entry( hdb, "_Tables", "Directory" );
1112 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1114 r = find_entry( hdb, "_Tables", "File" );
1115 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1117 r = find_entry( hdb, "_Tables", "Component" );
1118 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1120 r = find_entry( hdb, "_Tables", "Feature" );
1121 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1123 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1124 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1126 r = find_entry( hdb, "_Tables", "Property" );
1127 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1129 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1130 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1132 r = find_entry( hdb, "_Tables", "Media" );
1133 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1135 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1136 ok( r == 1, "Got %u\n", r );
1138 r = find_entry( hdb, "_Tables", "_Property" );
1139 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1141 MsiCloseHandle( hrec );
1142 MsiViewClose( hview );
1143 MsiCloseHandle( hview );
1144 MsiCloseHandle( hdb );
1145 MsiCloseHandle( hproduct );
1147 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1148 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1149 "expected ERROR_SUCCESS, got %u\n", r );
1151 if (r == ERROR_PATCH_PACKAGE_INVALID)
1153 win_skip("Windows Installer < 3.0 detected\n");
1154 goto uninstall;
1157 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1158 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1160 hdb = MsiGetActiveDatabase( hproduct );
1161 ok( hdb, "failed to get database handle\n" );
1163 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1164 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1166 r = find_entryW( hdb, streamsW, CAB_msitest_encodedW );
1167 ok( r == ERROR_NO_MORE_ITEMS, "failed to find entry %u\n", r );
1169 query = "SELECT * FROM `_Storages`";
1170 r = MsiDatabaseOpenViewA( hdb, query, &hview );
1171 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1173 r = MsiViewExecute( hview, 0 );
1174 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1176 r = MsiViewFetch( hview, &hrec );
1177 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1179 r = find_entry( hdb, "_Tables", "Directory" );
1180 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1182 r = find_entry( hdb, "_Tables", "File" );
1183 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1185 r = find_entry( hdb, "_Tables", "Component" );
1186 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1188 r = find_entry( hdb, "_Tables", "Feature" );
1189 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1191 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1192 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1194 r = find_entry( hdb, "_Tables", "Property" );
1195 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1197 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1198 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1200 r = find_entry( hdb, "_Tables", "Media" );
1201 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1203 r = find_entry( hdb, "_Tables", "_Property" );
1204 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1206 r = find_entry( hdb, "_Tables", "MsiPatchHeaders" );
1207 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1209 r = find_entry( hdb, "_Tables", "Patch" );
1210 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1212 r = find_entry( hdb, "_Tables", "PatchPackage" );
1213 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1215 cr = get_string( hdb, 6, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1216 todo_wine ok( !strcmp(cr, patchsource), "Expected \"%s\", got \"%s\"\n", patchsource, cr );
1218 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1219 todo_wine ok( r == 100, "Got %u\n", r );
1221 r = get_integer( hdb, 2, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1222 todo_wine ok( r == 10000, "Got %u\n", r );
1224 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1225 ok( r == 1, "Got %u\n", r );
1227 cr = get_string( hdb, 4, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1228 ok( !strcmp(cr, "#CAB_msitest"), "Expected \"#CAB_msitest\", got \"%s\"\n", cr );
1230 r = get_integer( hdb, 8, "SELECT * FROM `File` WHERE `File` = 'patch.txt'");
1231 ok( r == 10000, "Got %u\n", r );
1233 MsiCloseHandle( hrec );
1234 MsiViewClose( hview );
1235 MsiCloseHandle( hview );
1236 MsiCloseHandle( hdb );
1237 MsiCloseHandle( hproduct );
1239 uninstall:
1240 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1241 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1243 cleanup:
1244 DeleteFileA( msifile );
1245 DeleteFileA( mspfile );
1246 DeleteFileA( "msitest\\patch.txt" );
1247 RemoveDirectoryA( "msitest" );
1250 static void test_patch_registration( void )
1252 UINT r, size;
1253 char buffer[MAX_PATH], patch_code[39];
1255 if (!pMsiApplyPatchA || !pMsiGetPatchInfoExA || !pMsiEnumPatchesExA)
1257 win_skip("required functions not available\n");
1258 return;
1260 if (is_process_limited())
1262 skip("process is limited\n");
1263 return;
1266 CreateDirectoryA( "msitest", NULL );
1267 create_file( "msitest\\patch.txt", 1000 );
1269 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
1270 create_patch( mspfile );
1272 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1274 r = MsiInstallProductA( msifile, NULL );
1275 if (r != ERROR_SUCCESS)
1277 skip("Product installation failed with error code %d\n", r);
1278 goto cleanup;
1281 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1282 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1283 "expected ERROR_SUCCESS, got %u\n", r );
1285 if (r == ERROR_PATCH_PACKAGE_INVALID)
1287 win_skip("Windows Installer < 3.0 detected\n");
1288 goto uninstall;
1291 buffer[0] = 0;
1292 size = sizeof(buffer);
1293 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1294 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1295 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1296 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1297 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1298 ok( buffer[0], "buffer empty\n" );
1300 buffer[0] = 0;
1301 size = sizeof(buffer);
1302 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1303 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1304 NULL, MSIINSTALLCONTEXT_MACHINE,
1305 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1306 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1308 buffer[0] = 0;
1309 size = sizeof(buffer);
1310 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1311 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1312 NULL, MSIINSTALLCONTEXT_USERMANAGED,
1313 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1314 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1315 ok( !buffer[0], "got %s\n", buffer );
1317 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1318 NULL, MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_APPLIED,
1319 0, patch_code, NULL, NULL, NULL, NULL );
1320 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1321 ok( !strcmp( patch_code, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" );
1323 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1324 NULL, MSIINSTALLCONTEXT_MACHINE, 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 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1329 NULL, MSIINSTALLCONTEXT_USERMANAGED, MSIPATCHSTATE_APPLIED,
1330 0, patch_code, NULL, NULL, NULL, NULL );
1331 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1333 uninstall:
1334 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1335 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1337 buffer[0] = 0;
1338 size = sizeof(buffer);
1339 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1340 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1341 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1342 INSTALLPROPERTY_LOCALPACKAGEA, buffer, &size );
1343 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1345 cleanup:
1346 DeleteFileA( msifile );
1347 DeleteFileA( mspfile );
1348 DeleteFileA( "msitest\\patch.txt" );
1349 RemoveDirectoryA( "msitest" );
1352 START_TEST(patch)
1354 DWORD len;
1355 char temp_path[MAX_PATH], prev_path[MAX_PATH];
1357 init_function_pointers();
1359 GetCurrentDirectoryA( MAX_PATH, prev_path );
1360 GetTempPathA( MAX_PATH, temp_path );
1361 SetCurrentDirectoryA( temp_path );
1363 strcpy( CURR_DIR, temp_path );
1364 len = strlen( CURR_DIR );
1366 if (len && (CURR_DIR[len - 1] == '\\'))
1367 CURR_DIR[len - 1] = 0;
1369 get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR );
1371 test_simple_patch();
1372 test_MsiOpenDatabase();
1373 test_system_tables();
1374 test_patch_registration();
1376 SetCurrentDirectoryA( prev_path );