server: Bump priority on server to process messages faster
[wine/multimedia.git] / dlls / msi / tests / patch.c
blob89d5bd0aae1ced89fb9e69fd52eabbfff741c9e4
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>
31 #include "wine/test.h"
33 static UINT (WINAPI *pMsiApplyPatchA)( LPCSTR, LPCSTR, INSTALLTYPE, LPCSTR );
34 static UINT (WINAPI *pMsiGetPatchInfoExA)( LPCSTR, LPCSTR, LPCSTR, MSIINSTALLCONTEXT,
35 LPCSTR, LPSTR, DWORD * );
36 static UINT (WINAPI *pMsiEnumPatchesExA)( LPCSTR, LPCSTR, DWORD, DWORD, DWORD, LPSTR,
37 LPSTR, MSIINSTALLCONTEXT *, LPSTR, LPDWORD );
38 static BOOL (WINAPI *pGetTokenInformation)( HANDLE, TOKEN_INFORMATION_CLASS, LPVOID, DWORD, PDWORD );
39 static BOOL (WINAPI *pOpenProcessToken)( HANDLE, DWORD, PHANDLE );
41 static const char *msifile = "winetest-patch.msi";
42 static const char *mspfile = "winetest-patch.msp";
44 static char CURR_DIR[MAX_PATH];
45 static char PROG_FILES_DIR[MAX_PATH];
46 static char COMMON_FILES_DIR[MAX_PATH];
48 /* msi database data */
50 static const char property_dat[] =
51 "Property\tValue\n"
52 "s72\tl0\n"
53 "Property\tProperty\n"
54 "Manufacturer\tWineHQ\n"
55 "ProductCode\t{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}\n"
56 "UpgradeCode\t{A2E3D643-4E2C-477F-A309-F76F552D5F43}\n"
57 "ProductLanguage\t1033\n"
58 "ProductName\tmsitest\n"
59 "ProductVersion\t1.1.1\n"
60 "PATCHNEWSUMMARYSUBJECT\tInstaller Database\n"
61 "MSIFASTINSTALL\t1\n";
63 static const char media_dat[] =
64 "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
65 "i2\ti4\tL64\tS255\tS32\tS72\n"
66 "Media\tDiskId\n"
67 "1\t1\t\t\tDISK1\t\n";
69 static const char file_dat[] =
70 "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
71 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
72 "File\tFile\n"
73 "patch.txt\tpatch\tpatch.txt\t1000\t\t\t0\t1\n";
75 static const char directory_dat[] =
76 "Directory\tDirectory_Parent\tDefaultDir\n"
77 "s72\tS72\tl255\n"
78 "Directory\tDirectory\n"
79 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
80 "ProgramFilesFolder\tTARGETDIR\t.\n"
81 "TARGETDIR\t\tSourceDir";
83 static const char component_dat[] =
84 "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
85 "s72\tS38\ts72\ti2\tS255\tS72\n"
86 "Component\tComponent\n"
87 "patch\t{4B79D87E-6D28-4FD3-92D6-CD9B26AF64F1}\tMSITESTDIR\t0\t\tpatch.txt\n";
89 static const char feature_dat[] =
90 "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
91 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
92 "Feature\tFeature\n"
93 "patch\t\t\tpatch feature\t1\t1\tMSITESTDIR\t0\n";
95 static const char feature_comp_dat[] =
96 "Feature_\tComponent_\n"
97 "s38\ts72\n"
98 "FeatureComponents\tFeature_\tComponent_\n"
99 "patch\tpatch\n";
101 static const char install_exec_seq_dat[] =
102 "Action\tCondition\tSequence\n"
103 "s72\tS255\tI2\n"
104 "InstallExecuteSequence\tAction\n"
105 "LaunchConditions\t\t100\n"
106 "CostInitialize\t\t800\n"
107 "FileCost\t\t900\n"
108 "CostFinalize\t\t1000\n"
109 "InstallValidate\t\t1400\n"
110 "InstallInitialize\t\t1500\n"
111 "ProcessComponents\t\t1600\n"
112 "RemoveFiles\t\t1700\n"
113 "InstallFiles\t\t2000\n"
114 "RegisterUser\t\t3000\n"
115 "RegisterProduct\t\t3100\n"
116 "PublishFeatures\t\t5100\n"
117 "PublishProduct\t\t5200\n"
118 "InstallFinalize\t\t6000\n";
120 struct msi_table
122 const char *filename;
123 const char *data;
124 int size;
127 #define ADD_TABLE( x ) { #x".idt", x##_dat, sizeof(x##_dat) }
129 static const struct msi_table tables[] =
131 ADD_TABLE( directory ),
132 ADD_TABLE( file ),
133 ADD_TABLE( component ),
134 ADD_TABLE( feature ),
135 ADD_TABLE( feature_comp ),
136 ADD_TABLE( property ),
137 ADD_TABLE( install_exec_seq ),
138 ADD_TABLE( media )
141 static void init_function_pointers( void )
143 HMODULE hmsi = GetModuleHandleA( "msi.dll" );
144 HMODULE hadvapi32 = GetModuleHandleA( "advapi32.dll" );
146 #define GET_PROC( mod, func ) \
147 p ## func = (void *)GetProcAddress( mod, #func ); \
148 if (!p ## func) \
149 trace( "GetProcAddress(%s) failed\n", #func );
151 GET_PROC( hmsi, MsiApplyPatchA );
152 GET_PROC( hmsi, MsiGetPatchInfoExA );
153 GET_PROC( hmsi, MsiEnumPatchesExA );
155 GET_PROC( hadvapi32, GetTokenInformation );
156 GET_PROC( hadvapi32, OpenProcessToken );
157 #undef GET_PROC
160 static BOOL is_process_limited(void)
162 HANDLE token;
164 if (!pOpenProcessToken || !pGetTokenInformation) return FALSE;
166 if (pOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
168 BOOL ret;
169 TOKEN_ELEVATION_TYPE type = TokenElevationTypeDefault;
170 DWORD size;
172 ret = pGetTokenInformation(token, TokenElevationType, &type, sizeof(type), &size);
173 CloseHandle(token);
174 return (ret && type == TokenElevationTypeLimited);
176 return FALSE;
179 static BOOL get_program_files_dir( char *buf, char *buf2 )
181 HKEY hkey;
182 DWORD type, size;
184 if (RegOpenKey( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey ))
185 return FALSE;
187 size = MAX_PATH;
188 if (RegQueryValueExA( hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size ) &&
189 RegQueryValueExA( hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size ))
191 RegCloseKey( hkey );
192 return FALSE;
194 size = MAX_PATH;
195 if (RegQueryValueExA( hkey, "CommonFilesDir", 0, &type, (LPBYTE)buf2, &size ))
197 RegCloseKey( hkey );
198 return FALSE;
200 RegCloseKey( hkey );
201 return TRUE;
204 static void create_file_data( const char *filename, const char *data, DWORD size )
206 HANDLE file;
207 DWORD written;
209 file = CreateFileA( filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
210 if (file == INVALID_HANDLE_VALUE)
211 return;
213 WriteFile( file, data, strlen( data ), &written, NULL );
214 if (size)
216 SetFilePointer( file, size, NULL, FILE_BEGIN );
217 SetEndOfFile( file );
219 CloseHandle( file );
222 #define create_file( name, size ) create_file_data( name, name, size )
224 static BOOL delete_pf( const char *rel_path, BOOL is_file )
226 char path[MAX_PATH];
228 strcpy( path, PROG_FILES_DIR );
229 strcat( path, "\\" );
230 strcat( path, rel_path );
232 if (is_file)
233 return DeleteFileA( path );
234 else
235 return RemoveDirectoryA( path );
238 static DWORD get_pf_file_size( const char *filename )
240 char path[MAX_PATH];
241 HANDLE file;
242 DWORD size;
244 strcpy( path, PROG_FILES_DIR );
245 strcat( path, "\\");
246 strcat( path, filename );
248 file = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
249 if (file == INVALID_HANDLE_VALUE)
250 return INVALID_FILE_SIZE;
252 size = GetFileSize( file, NULL );
253 CloseHandle( file );
254 return size;
257 static void write_file( const char *filename, const char *data, DWORD data_size )
259 DWORD size;
260 HANDLE file = CreateFile( filename, GENERIC_WRITE, 0, NULL,
261 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
262 WriteFile( file, data, data_size, &size, NULL );
263 CloseHandle( file );
266 static void set_suminfo( const char *filename )
268 UINT r;
269 MSIHANDLE hsi, hdb;
271 r = MsiOpenDatabaseA( filename, MSIDBOPEN_DIRECT, &hdb );
272 ok( r == ERROR_SUCCESS, "failed to open database %u\n", r );
274 r = MsiGetSummaryInformation( hdb, NULL, 7, &hsi );
275 ok( r == ERROR_SUCCESS, "failed to open summaryinfo %u\n", r );
277 r = MsiSummaryInfoSetProperty( hsi, 2, VT_LPSTR, 0, NULL, "Installation Database" );
278 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
280 r = MsiSummaryInfoSetProperty( hsi, 3, VT_LPSTR, 0, NULL, "Installation Database" );
281 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
283 r = MsiSummaryInfoSetProperty( hsi, 4, VT_LPSTR, 0, NULL, "WineHQ" );
284 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
286 r = MsiSummaryInfoSetProperty( hsi, 7, VT_LPSTR, 0, NULL, ";1033" );
287 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
289 r = MsiSummaryInfoSetProperty( hsi, 9, VT_LPSTR, 0, NULL, "{E528DDD6-4801-4BEC-BBB6-C5EE0FD097E9}" );
290 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
292 r = MsiSummaryInfoSetProperty( hsi, 14, VT_I4, 100, NULL, NULL );
293 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
295 r = MsiSummaryInfoSetProperty( hsi, 15, VT_I4, 0, NULL, NULL );
296 ok( r == ERROR_SUCCESS, "failed to set summary info %u\n", r );
298 r = MsiSummaryInfoPersist( hsi );
299 ok( r == ERROR_SUCCESS, "failed to persist suminfo %u\n", r );
301 r = MsiCloseHandle( hsi );
302 ok( r == ERROR_SUCCESS, "failed to close suminfo %u\n", r );
304 r = MsiCloseHandle( hdb );
305 ok( r == ERROR_SUCCESS, "failed to close database %u\n", r );
308 static void create_database( const char *filename, const struct msi_table *tables, UINT num_tables )
310 MSIHANDLE hdb;
311 UINT r, i;
313 r = MsiOpenDatabaseA( filename, MSIDBOPEN_CREATE, &hdb );
314 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
316 /* import the tables into the database */
317 for (i = 0; i < num_tables; i++)
319 const struct msi_table *table = &tables[i];
321 write_file( table->filename, table->data, (table->size - 1) * sizeof(char) );
323 r = MsiDatabaseImportA( hdb, CURR_DIR, table->filename );
324 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
326 DeleteFileA( table->filename );
329 r = MsiDatabaseCommit( hdb );
330 ok(r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
332 MsiCloseHandle( hdb );
333 set_suminfo( filename );
336 /* data for generating a patch */
338 /* table names - encoded as in an msi database file */
339 static const WCHAR p_name0[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
340 static const WCHAR p_name1[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
341 static const WCHAR p_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
342 static const WCHAR p_name3[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
343 static const WCHAR p_name4[] = { 0x3a8c, 0x47cb, 0x45b0, 0x45ec, 0x45a8, 0x4837, 0}; /* CAB_msitest */
344 static const WCHAR p_name5[] = { 0x4840, 0x4596, 0x3e6c, 0x45e4, 0x42e6, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* MsiPatchSequence */
345 static const WCHAR p_name6[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
346 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
347 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
348 /* substorage names */
349 static const WCHAR p_name7[] = { 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075, 0x0070,
350 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* targetToupgraded */
351 static const WCHAR p_name8[] = { 0x0023, 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075,
352 0x0070, 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* #targetToupgraded */
354 /* data in each table */
355 static const WCHAR p_data0[] = { /* _Columns */
356 0x0001, 0x0001, 0x0001, 0x0001, 0x8001, 0x8002, 0x8003, 0x8004,
357 0x0002, 0x0003, 0x0004, 0x0005, 0xad00, 0xbd26, 0x8d00, 0x9502
359 static const WCHAR p_data1[] = { /* _Tables */
360 0x0001
362 static const char p_data2[] = { /* _StringData */
363 "MsiPatchSequencePatchFamilyProductCodeSequenceAttributes1.1.19388.37230913B8D18FBB64CACA239C74C11E3FA74"
365 static const WCHAR p_data3[] = { /* _StringPool */
366 /* len, refs */
367 0, 0, /* string 0 '' */
368 16, 5, /* string 1 'MsiPatchSequence' */
369 11, 1, /* string 2 'PatchFamily' */
370 11, 1, /* string 3 'ProductCode' */
371 8, 1, /* string 4 'Sequence' */
372 10, 1, /* string 5 'Attributes' */
373 15, 1, /* string 6 '1.1.19388.37230' */
374 32, 1, /* string 7 '913B8D18FBB64CACA239C74C11E3FA74' */
376 static const char p_data4[] = { /* CAB_msitest */
377 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00,
378 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00,
379 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9e,
380 0x03, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x12,
381 0xea, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87,
382 0x3c, 0xd4, 0x80, 0x20, 0x00, 0x70, 0x61, 0x74, 0x63, 0x68, 0x2e,
383 0x74, 0x78, 0x74, 0x00, 0x0b, 0x3c, 0xd6, 0xc1, 0x4a, 0x00, 0xea,
384 0x03, 0x5b, 0x80, 0x80, 0x8d, 0x00, 0x10, 0xa1, 0x3e, 0x00, 0x00,
385 0x00, 0x00, 0x03, 0x00, 0x40, 0x30, 0x0c, 0x43, 0xf8, 0xb4, 0x85,
386 0x4d, 0x96, 0x08, 0x0a, 0x92, 0xf0, 0x52, 0xfb, 0xbb, 0x82, 0xf9,
387 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0e, 0x31, 0x7d,
388 0x56, 0xdf, 0xf7, 0x48, 0x7c, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
389 0x00, 0x00, 0x41, 0x80, 0xdf, 0xf7, 0xd8, 0x72, 0xbf, 0xb9, 0x63,
390 0x91, 0x0e, 0x57, 0x1f, 0xfa, 0x1a, 0x66, 0x54, 0x55
392 static const WCHAR p_data5[] = { /* MsiPatchSequence */
393 0x0007, 0x0000, 0x0006, 0x8000
395 static const char p_data6[] = { /* SummaryInformation */
396 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
397 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
398 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
399 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
400 0x30, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
401 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00,
402 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x90,
403 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
404 0x0f, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
405 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x30, 0x46, 0x39, 0x36, 0x43,
406 0x44, 0x43, 0x30, 0x2d, 0x34, 0x43, 0x44, 0x46, 0x2d, 0x34, 0x33,
407 0x30, 0x34, 0x2d, 0x42, 0x32, 0x38, 0x33, 0x2d, 0x37, 0x42, 0x39,
408 0x32, 0x36, 0x34, 0x38, 0x38, 0x39, 0x45, 0x46, 0x37, 0x7d, 0x00,
409 0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x39,
410 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42,
411 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39,
412 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41,
413 0x37, 0x34, 0x7d, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x25, 0x00,
414 0x00, 0x00, 0x3a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f,
415 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x3b, 0x3a, 0x23,
416 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f, 0x75, 0x70, 0x67,
417 0x72, 0x61, 0x64, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
418 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x50, 0x61, 0x74, 0x63, 0x68,
419 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x00,
420 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
423 struct table_data {
424 LPCWSTR name;
425 const void *data;
426 DWORD size;
429 static const struct table_data table_patch_data[] = {
430 { p_name0, p_data0, sizeof p_data0 },
431 { p_name1, p_data1, sizeof p_data1 },
432 { p_name2, p_data2, sizeof p_data2 - 1 },
433 { p_name3, p_data3, sizeof p_data3 },
434 { p_name4, p_data4, sizeof p_data4 },
435 { p_name5, p_data5, sizeof p_data5 },
436 { p_name6, p_data6, sizeof p_data6 }
439 #define NUM_PATCH_TABLES (sizeof table_patch_data/sizeof table_patch_data[0])
441 static const WCHAR t1_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
442 static const WCHAR t1_name1[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
443 static const WCHAR t1_name2[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
444 static const WCHAR t1_name3[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
445 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
446 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
448 static const WCHAR t1_data0[] = { /* File */
449 0x0008, 0x0001, 0x03ea, 0x8000
451 static const char t1_data1[] = { /* _StringData */
452 "patch.txt"
454 static const WCHAR t1_data2[] = { /* _StringPool */
455 /* len, refs */
456 0, 0, /* string 0 '' */
457 9, 1, /* string 1 'patch.txt' */
459 static const char t1_data3[] = { /* SummaryInformation */
460 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
462 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
463 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
464 0x30, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00,
465 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00,
466 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa8,
467 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00,
468 0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
469 0x00, 0xd0, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x00,
470 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x08,
471 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
472 0x04, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00,
473 0x00, 0x10, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x1e, 0x00,
474 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61,
475 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74,
476 0x61, 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
477 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c,
478 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74, 0x61,
479 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
480 0x07, 0x00, 0x00, 0x00, 0x57, 0x69, 0x6e, 0x65, 0x48, 0x51, 0x00,
481 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
482 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
483 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
484 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
485 0x00, 0x1e, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31,
486 0x30, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x06,
487 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 0x00,
488 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b, 0x39, 0x31,
489 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
490 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
491 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
492 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x39, 0x31,
493 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42, 0x36,
494 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39, 0x2d,
495 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41, 0x37,
496 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b, 0x41, 0x32,
497 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45, 0x32, 0x43,
498 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30, 0x39, 0x2d,
499 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35, 0x46, 0x34,
500 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00,
501 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22, 0x09
504 static const struct table_data table_transform1_data[] = {
505 { t1_name0, t1_data0, sizeof t1_data0 },
506 { t1_name1, t1_data1, sizeof t1_data1 - 1 },
507 { t1_name2, t1_data2, sizeof t1_data2 },
508 { t1_name3, t1_data3, sizeof t1_data3 }
511 #define NUM_TRANSFORM1_TABLES (sizeof table_transform1_data/sizeof table_transform1_data[0])
513 static const WCHAR t2_name0[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
514 static const WCHAR t2_name1[] = { 0x4840, 0x4216, 0x4327, 0x4824, 0 }; /* Media */
515 static const WCHAR t2_name2[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
516 static const WCHAR t2_name3[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
517 static const WCHAR t2_name4[] = { 0x4840, 0x4559, 0x44f2, 0x4568, 0x4737, 0 }; /* Property */
518 static const WCHAR t2_name5[] = { 0x4840, 0x4119, 0x41b7, 0x3e6b, 0x41a4, 0x412e, 0x422a, 0 }; /* PatchPackage */
519 static const WCHAR t2_name6[] = { 0x4840, 0x4452, 0x45f6, 0x43e4, 0x3baf, 0x423b, 0x4626,
520 0x4237, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* InstallExecuteSequence */
521 static const WCHAR t2_name7[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
522 static const WCHAR t2_name8[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
523 static const WCHAR t2_name9[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
524 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
525 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
527 static const WCHAR t2_data0[] = { /* File */
528 0x00c0, 0x0001, 0x9000, 0x83e8
530 static const WCHAR t2_data1[] = { /* Media */
531 0x0601, 0x8002, 0x03e9, 0x8000, 0x0000, 0x0007, 0x0000, 0x0008
533 static const WCHAR t2_data2[] = { /* _Columns */
534 0x0401, 0x0009, 0x0000, 0x000a, 0xad48, 0x0401, 0x0009, 0x0000, /* 0x0401 = add row (1), 4 shorts */
535 0x000b, 0xa502, 0x0401, 0x0009, 0x0000, 0x000c, 0x8104, 0x0401,
536 0x0009, 0x0000, 0x000d, 0x8502, 0x0401, 0x0009, 0x0000, 0x000e,
537 0x9900, 0x0401, 0x0009, 0x0000, 0x000f, 0x9d48, 0x0401, 0x0010,
538 0x0000, 0x0011, 0xad26, 0x0401, 0x0010, 0x0000, 0x0012, 0x8502,
539 0x0401, 0x0014, 0x0000, 0x0015, 0xad26, 0x0401, 0x0014, 0x0000,
540 0x000e, 0x8900
542 static const WCHAR t2_data3[] = { /* _Tables */
543 0x0101, 0x0009, 0x0101, 0x0010, 0x0101, 0x0014
545 static const WCHAR t2_data4[] = { /* Property */
546 0x0201, 0x0002, 0x0003, 0x0201, 0x0004, 0x0005
548 static const WCHAR t2_data5[] = { /* PatchPackage */
549 0x0201, 0x0013, 0x8002
551 static const WCHAR t2_data6[] = { /* InstallExecuteSequence */
552 0x0301, 0x0006, 0x0000, 0x87d1
554 static const char t2_data7[] = { /* _StringData */
555 "patch.txtPATCHNEWSUMMARYSUBJECTInstallation DatabasePATCHNEWPACKAGECODE{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}"
556 "PatchFiles#CAB_msitestpropPatchFile_SequencePatchSizeAttributesHeaderStreamRef_PatchPackagePatchIdMedia_"
557 "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}MsiPatchHeadersStreamRef"
559 static const WCHAR t2_data8[] = { /* _StringPool */
560 /* len, refs */
561 0, 0, /* string 0 '' */
562 9, 1, /* string 1 'patch.txt' */
563 22, 1, /* string 2 'PATCHNEWSUMMARYSUBJECT' */
564 21, 1, /* string 3 'Installation Database' */
565 19, 1, /* string 4 'PATCHNEWPACKAGECODE' */
566 38, 1, /* string 5 '{42A14A82-12F8-4E6D-970E-1B4EE7BE28B0}' */
567 10, 1, /* string 6 'PatchFiles' */
568 12, 1, /* string 7 '#CAB_msitest' */
569 4, 1, /* string 8 'prop' */
570 5, 7, /* string 9 'Patch' */
571 5, 1, /* string 10 'File_' */
572 8, 1, /* string 11 'Sequence' */
573 9, 1, /* string 12 'PatchSize' */
574 10, 1, /* string 13 'Attributes' */
575 6, 2, /* string 14 'Header' */
576 10, 1, /* string 15 'StreamRef_' */
577 12, 3, /* string 16 'PatchPackage' */
578 7, 1, /* string 17 'PatchId' */
579 6, 1, /* string 18 'Media_' */
580 38, 1, /* string 19 '{0F96CDC0-4CDF-4304-B283-7B9264889EF7}' */
581 15, 3, /* string 20 'MsiPatchHeaders' */
582 9, 1 /* string 21 'StreamRef' */
584 static const char t2_data9[] = { /* SummaryInformation */
585 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
587 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
588 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
589 0x30, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00,
590 0x00, 0x02, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00,
591 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x78,
592 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
593 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
594 0x00, 0x9c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00,
595 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x09,
596 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
597 0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00,
598 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
599 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
600 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
601 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
602 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00,
603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01,
604 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
605 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00,
606 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
607 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7b,
608 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
609 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
610 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
611 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
612 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42,
613 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33,
614 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46,
615 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b, 0x7b,
616 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34, 0x45,
617 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33, 0x30,
618 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44, 0x35,
619 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2d,
620 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x27, 0x09
623 static const struct table_data table_transform2_data[] = {
624 { t2_name0, t2_data0, sizeof t2_data0 },
625 { t2_name1, t2_data1, sizeof t2_data1 },
626 { t2_name2, t2_data2, sizeof t2_data2 },
627 { t2_name3, t2_data3, sizeof t2_data3 },
628 { t2_name4, t2_data4, sizeof t2_data4 },
629 { t2_name5, t2_data5, sizeof t2_data5 },
630 { t2_name6, t2_data6, sizeof t2_data6 },
631 { t2_name7, t2_data7, sizeof t2_data7 - 1 },
632 { t2_name8, t2_data8, sizeof t2_data8 },
633 { t2_name9, t2_data9, sizeof t2_data9 }
636 #define NUM_TRANSFORM2_TABLES (sizeof table_transform2_data/sizeof table_transform2_data[0])
638 static void write_tables( IStorage *stg, const struct table_data *tables, UINT num_tables )
640 IStream *stm;
641 DWORD i, count;
642 HRESULT r;
644 for (i = 0; i < num_tables; i++)
646 r = IStorage_CreateStream( stg, tables[i].name, STGM_WRITE|STGM_SHARE_EXCLUSIVE, 0, 0, &stm );
647 if (FAILED( r ))
649 ok( 0, "failed to create stream 0x%08x\n", r );
650 continue;
653 r = IStream_Write( stm, tables[i].data, tables[i].size, &count );
654 if (FAILED( r ) || count != tables[i].size)
655 ok( 0, "failed to write stream\n" );
656 IStream_Release( stm );
660 static void create_patch( const char *filename )
662 IStorage *stg = NULL, *stg1 = NULL, *stg2 = NULL;
663 WCHAR *filenameW;
664 HRESULT r;
665 int len;
666 const DWORD mode = STGM_CREATE|STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE;
668 const CLSID CLSID_MsiPatch = {0xc1086, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
669 const CLSID CLSID_MsiTransform = {0xc1082, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
671 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
672 filenameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
673 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
675 r = StgCreateDocfile( filenameW, mode, 0, &stg );
676 HeapFree( GetProcessHeap(), 0, filenameW );
677 ok( r == S_OK, "failed to create storage 0x%08x\n", r );
678 if (!stg)
679 return;
681 r = IStorage_SetClass( stg, &CLSID_MsiPatch );
682 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
684 write_tables( stg, table_patch_data, NUM_PATCH_TABLES );
686 r = IStorage_CreateStorage( stg, p_name7, mode, 0, 0, &stg1 );
687 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
689 r = IStorage_SetClass( stg1, &CLSID_MsiTransform );
690 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
692 write_tables( stg1, table_transform1_data, NUM_TRANSFORM1_TABLES );
693 IStorage_Release( stg1 );
695 r = IStorage_CreateStorage( stg, p_name8, mode, 0, 0, &stg2 );
696 ok( r == S_OK, "failed to create substorage 0x%08x\n", r );
698 r = IStorage_SetClass( stg2, &CLSID_MsiTransform );
699 ok( r == S_OK, "failed to set storage type 0x%08x\n", r );
701 write_tables( stg2, table_transform2_data, NUM_TRANSFORM2_TABLES );
702 IStorage_Release( stg2 );
703 IStorage_Release( stg );
706 static void test_simple_patch( void )
708 UINT r;
709 DWORD size;
710 char path[MAX_PATH], install_source[MAX_PATH], buffer[32];
711 const char *query;
712 MSIHANDLE hpackage, hdb, hview, hrec;
714 if (!pMsiApplyPatchA)
716 win_skip("MsiApplyPatchA is not available\n");
717 return;
719 if (is_process_limited())
721 skip("process is limited\n");
722 return;
725 CreateDirectoryA( "msitest", NULL );
726 create_file( "msitest\\patch.txt", 1000 );
728 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
729 create_patch( mspfile );
731 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
733 r = MsiInstallProductA( msifile, NULL );
734 if (r != ERROR_SUCCESS)
736 skip("Product installation failed with error code %u\n", r);
737 goto cleanup;
740 size = get_pf_file_size( "msitest\\patch.txt" );
741 ok( size == 1000, "expected 1000, got %u\n", size );
743 size = sizeof(install_source);
744 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
745 "InstallSource", install_source, &size );
746 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
748 strcpy( path, CURR_DIR );
749 strcat( path, "\\" );
750 strcat( path, msifile );
752 r = MsiOpenPackageA( path, &hpackage );
753 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
755 hdb = MsiGetActiveDatabase( hpackage );
756 ok( hdb, "failed to get database handle\n" );
758 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
759 r = MsiDatabaseOpenView( hdb, query, &hview );
760 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
762 r = MsiViewExecute( hview, 0 );
763 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
765 r = MsiViewFetch( hview, &hrec );
766 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
768 MsiCloseHandle( hrec );
769 MsiViewClose( hview );
770 MsiCloseHandle( hview );
772 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
773 "AND `Value` = 'Installer Database'";
774 r = MsiDatabaseOpenView( hdb, query, &hview );
775 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
777 r = MsiViewExecute( hview, 0 );
778 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
780 r = MsiViewFetch( hview, &hrec );
781 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
783 MsiCloseHandle( hrec );
784 MsiViewClose( hview );
785 MsiCloseHandle( hview );
787 buffer[0] = 0;
788 size = sizeof(buffer);
789 r = MsiGetProperty( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
790 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
791 ok( !strcmp( buffer, "Installer Database" ), "expected \'Installer Database\', got \'%s\'\n", buffer );
793 MsiCloseHandle( hdb );
794 MsiCloseHandle( hpackage );
796 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
797 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
798 "expected ERROR_SUCCESS, got %u\n", r );
800 if (r == ERROR_PATCH_PACKAGE_INVALID)
802 win_skip("Windows Installer < 3.0 detected\n");
803 goto uninstall;
806 size = get_pf_file_size( "msitest\\patch.txt" );
807 ok( size == 1002, "expected 1002, got %u\n", size );
809 /* show that MsiOpenPackage applies registered patches */
810 r = MsiOpenPackageA( path, &hpackage );
811 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
813 hdb = MsiGetActiveDatabase( hpackage );
814 ok( hdb, "failed to get database handle\n" );
816 query = "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
817 r = MsiDatabaseOpenView( hdb, query, &hview );
818 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
820 r = MsiViewExecute( hview, 0 );
821 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
823 r = MsiViewFetch( hview, &hrec );
824 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
826 MsiCloseHandle( hrec );
827 MsiViewClose( hview );
828 MsiCloseHandle( hview );
830 query = "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
831 "AND `Value` = 'Installation Database'";
832 r = MsiDatabaseOpenView( hdb, query, &hview );
833 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
835 r = MsiViewExecute( hview, 0 );
836 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
838 r = MsiViewFetch( hview, &hrec );
839 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
841 MsiCloseHandle( hrec );
842 MsiViewClose( hview );
843 MsiCloseHandle( hview );
845 buffer[0] = 0;
846 size = sizeof(buffer);
847 r = MsiGetProperty( hpackage, "PATCHNEWSUMMARYSUBJECT", buffer, &size );
848 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
849 ok( !strcmp( buffer, "Installation Database" ), "expected \'Installation Database\', got \'%s\'\n", buffer );
851 MsiCloseHandle( hdb );
852 MsiCloseHandle( hpackage );
854 /* show that patches are not committed to the local package database */
855 size = sizeof(path);
856 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
857 "LocalPackage", path, &size );
858 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
860 r = MsiOpenDatabaseA( path, MSIDBOPEN_READONLY, &hdb );
861 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
863 r = MsiDatabaseOpenView( hdb, query, &hview );
864 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
866 r = MsiViewExecute( hview, 0 );
867 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
869 r = MsiViewFetch( hview, &hrec );
870 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
872 MsiCloseHandle( hrec );
873 MsiViewClose( hview );
874 MsiCloseHandle( hview );
875 MsiCloseHandle( hdb );
877 uninstall:
878 size = sizeof(path);
879 r = MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
880 "InstallSource", path, &size );
881 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
882 ok( !strcasecmp( path, install_source ), "wrong path %s\n", path );
884 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
885 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
887 ok( !delete_pf( "msitest\\patch.txt", TRUE ), "file not removed\n" );
888 ok( !delete_pf( "msitest", FALSE ), "directory not removed\n" );
890 cleanup:
891 DeleteFileA( msifile );
892 DeleteFileA( mspfile );
893 DeleteFileA( "msitest\\patch.txt" );
894 RemoveDirectoryA( "msitest" );
897 static void test_MsiOpenDatabase( void )
899 UINT r;
900 MSIHANDLE hdb;
902 r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE, &hdb );
903 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
905 r = MsiDatabaseCommit( hdb );
906 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
907 MsiCloseHandle( hdb );
909 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
910 ok(r == ERROR_OPEN_FAILED, "expected ERROR_OPEN_FAILED, got %u\n", r);
911 DeleteFileA( mspfile );
913 r = MsiOpenDatabase( mspfile, MSIDBOPEN_CREATE + MSIDBOPEN_PATCHFILE, &hdb );
914 ok(r == ERROR_SUCCESS , "failed to open database %u\n", r);
916 r = MsiDatabaseCommit( hdb );
917 ok(r == ERROR_SUCCESS, "failed to commit database %u\n", r);
918 MsiCloseHandle( hdb );
920 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
921 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r);
922 MsiCloseHandle( hdb );
923 DeleteFileA( mspfile );
925 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
926 create_patch( mspfile );
928 r = MsiOpenDatabase( msifile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
929 ok(r == ERROR_OPEN_FAILED, "failed to open database %u\n", r );
931 r = MsiOpenDatabase( mspfile, MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE, &hdb );
932 ok(r == ERROR_SUCCESS, "failed to open database %u\n", r );
933 MsiCloseHandle( hdb );
935 DeleteFileA( msifile );
936 DeleteFileA( mspfile );
939 static UINT find_entry( MSIHANDLE hdb, const char *table, const char *entry )
941 static char fmt[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
942 char query[0x100];
943 UINT r;
944 MSIHANDLE hview, hrec;
946 sprintf( query, fmt, table, entry );
947 r = MsiDatabaseOpenView( hdb, query, &hview );
948 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
950 r = MsiViewExecute( hview, 0 );
951 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
953 r = MsiViewFetch( hview, &hrec );
954 MsiViewClose( hview );
955 MsiCloseHandle( hview );
956 MsiCloseHandle( hrec );
957 return r;
960 static INT get_integer( MSIHANDLE hdb, UINT field, const char *query)
962 UINT r;
963 INT ret = -1;
964 MSIHANDLE hview, hrec;
966 r = MsiDatabaseOpenView( hdb, query, &hview );
967 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
969 r = MsiViewExecute( hview, 0 );
970 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
972 r = MsiViewFetch( hview, &hrec );
973 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
974 if (r == ERROR_SUCCESS)
976 UINT r_tmp;
977 ret = MsiRecordGetInteger( hrec, field );
978 MsiCloseHandle( hrec );
980 r_tmp = MsiViewFetch( hview, &hrec );
981 ok( r_tmp == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r);
984 MsiViewClose( hview );
985 MsiCloseHandle( hview );
986 return ret;
989 static char *get_string( MSIHANDLE hdb, UINT field, const char *query)
991 UINT r;
992 static char ret[MAX_PATH];
993 MSIHANDLE hview, hrec;
995 ret[0] = '\0';
997 r = MsiDatabaseOpenView( hdb, query, &hview );
998 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1000 r = MsiViewExecute( hview, 0 );
1001 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1003 r = MsiViewFetch( hview, &hrec );
1004 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1005 if (r == ERROR_SUCCESS)
1007 UINT size = MAX_PATH;
1008 r = MsiRecordGetStringA( hrec, field, ret, &size );
1009 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r);
1010 MsiCloseHandle( hrec );
1012 r = MsiViewFetch( hview, &hrec );
1013 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r);
1016 MsiViewClose( hview );
1017 MsiCloseHandle( hview );
1018 return ret;
1021 static void test_system_tables( void )
1023 UINT r;
1024 char *cr;
1025 const char *query;
1026 MSIHANDLE hproduct, hdb, hview, hrec;
1027 static const char patchsource[] = "MSPSRC0F96CDC04CDF4304B2837B9264889EF7";
1029 if (!pMsiApplyPatchA)
1031 win_skip("MsiApplyPatchA is not available\n");
1032 return;
1034 if (is_process_limited())
1036 skip("process is limited\n");
1037 return;
1040 CreateDirectoryA( "msitest", NULL );
1041 create_file( "msitest\\patch.txt", 1000 );
1043 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
1044 create_patch( mspfile );
1046 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1048 r = MsiInstallProductA( msifile, NULL );
1049 if (r != ERROR_SUCCESS)
1051 skip("Product installation failed with error code %d\n", r);
1052 goto cleanup;
1055 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1056 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1058 hdb = MsiGetActiveDatabase( hproduct );
1059 ok( hdb, "failed to get database handle\n" );
1061 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1062 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1064 query = "SELECT * FROM `_Storages`";
1065 r = MsiDatabaseOpenView( hdb, query, &hview );
1066 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1068 r = MsiViewExecute( hview, 0 );
1069 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1071 r = MsiViewFetch( hview, &hrec );
1072 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1074 r = find_entry( hdb, "_Tables", "Directory" );
1075 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1077 r = find_entry( hdb, "_Tables", "File" );
1078 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1080 r = find_entry( hdb, "_Tables", "Component" );
1081 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1083 r = find_entry( hdb, "_Tables", "Feature" );
1084 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1086 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1087 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1089 r = find_entry( hdb, "_Tables", "Property" );
1090 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1092 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1093 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1095 r = find_entry( hdb, "_Tables", "Media" );
1096 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1098 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1099 ok( r == 1, "Got %u\n", r );
1101 r = find_entry( hdb, "_Tables", "_Property" );
1102 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1104 MsiCloseHandle( hrec );
1105 MsiViewClose( hview );
1106 MsiCloseHandle( hview );
1107 MsiCloseHandle( hdb );
1108 MsiCloseHandle( hproduct );
1110 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1111 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1112 "expected ERROR_SUCCESS, got %u\n", r );
1114 if (r == ERROR_PATCH_PACKAGE_INVALID)
1116 win_skip("Windows Installer < 3.0 detected\n");
1117 goto uninstall;
1120 r = MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct );
1121 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1123 hdb = MsiGetActiveDatabase( hproduct );
1124 ok( hdb, "failed to get database handle\n" );
1126 r = find_entry( hdb, "_Streams", "\5SummaryInformation" );
1127 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1129 query = "SELECT * FROM `_Storages`";
1130 r = MsiDatabaseOpenView( hdb, query, &hview );
1131 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1133 r = MsiViewExecute( hview, 0 );
1134 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1136 r = MsiViewFetch( hview, &hrec );
1137 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1139 r = find_entry( hdb, "_Tables", "Directory" );
1140 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1142 r = find_entry( hdb, "_Tables", "File" );
1143 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1145 r = find_entry( hdb, "_Tables", "Component" );
1146 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1148 r = find_entry( hdb, "_Tables", "Feature" );
1149 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1151 r = find_entry( hdb, "_Tables", "FeatureComponents" );
1152 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1154 r = find_entry( hdb, "_Tables", "Property" );
1155 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1157 r = find_entry( hdb, "_Tables", "InstallExecuteSequence" );
1158 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1160 r = find_entry( hdb, "_Tables", "Media" );
1161 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1163 r = find_entry( hdb, "_Tables", "_Property" );
1164 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1166 r = find_entry( hdb, "_Tables", "MsiPatchHeaders" );
1167 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1169 r = find_entry( hdb, "_Tables", "Patch" );
1170 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1172 r = find_entry( hdb, "_Tables", "PatchPackage" );
1173 ok( r == ERROR_SUCCESS, "failed to find entry %u\n", r );
1175 cr = get_string( hdb, 6, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1176 todo_wine ok( !strcmp(cr, patchsource), "Expected \"%s\", got \"%s\"\n", patchsource, cr );
1178 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1179 todo_wine ok( r == 100, "Got %u\n", r );
1181 r = get_integer( hdb, 2, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1182 todo_wine ok( r == 10000, "Got %u\n", r );
1184 r = get_integer( hdb, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1185 ok( r == 1, "Got %u\n", r );
1187 cr = get_string( hdb, 4, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1188 ok( !strcmp(cr, "#CAB_msitest"), "Expected \"#CAB_msitest\", got \"%s\"\n", cr );
1190 r = get_integer( hdb, 8, "SELECT * FROM `File` WHERE `File` = 'patch.txt'");
1191 ok( r == 10000, "Got %u\n", r );
1193 MsiCloseHandle( hrec );
1194 MsiViewClose( hview );
1195 MsiCloseHandle( hview );
1196 MsiCloseHandle( hdb );
1197 MsiCloseHandle( hproduct );
1199 uninstall:
1200 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1201 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1203 cleanup:
1204 DeleteFileA( msifile );
1205 DeleteFileA( mspfile );
1206 DeleteFileA( "msitest\\patch.txt" );
1207 RemoveDirectoryA( "msitest" );
1210 static void test_patch_registration( void )
1212 UINT r, size;
1213 char buffer[MAX_PATH], patch_code[39];
1215 if (!pMsiApplyPatchA || !pMsiGetPatchInfoExA || !pMsiEnumPatchesExA)
1217 win_skip("required functions not available\n");
1218 return;
1220 if (is_process_limited())
1222 skip("process is limited\n");
1223 return;
1226 CreateDirectoryA( "msitest", NULL );
1227 create_file( "msitest\\patch.txt", 1000 );
1229 create_database( msifile, tables, sizeof(tables) / sizeof(struct msi_table) );
1230 create_patch( mspfile );
1232 MsiSetInternalUI( INSTALLUILEVEL_NONE, NULL );
1234 r = MsiInstallProductA( msifile, NULL );
1235 if (r != ERROR_SUCCESS)
1237 skip("Product installation failed with error code %d\n", r);
1238 goto cleanup;
1241 r = MsiApplyPatchA( mspfile, NULL, INSTALLTYPE_DEFAULT, NULL );
1242 ok( r == ERROR_SUCCESS || broken( r == ERROR_PATCH_PACKAGE_INVALID ), /* version 2.0 */
1243 "expected ERROR_SUCCESS, got %u\n", r );
1245 if (r == ERROR_PATCH_PACKAGE_INVALID)
1247 win_skip("Windows Installer < 3.0 detected\n");
1248 goto uninstall;
1251 buffer[0] = 0;
1252 size = sizeof(buffer);
1253 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1254 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1255 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1256 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1257 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1258 ok( buffer[0], "buffer empty\n" );
1260 buffer[0] = 0;
1261 size = sizeof(buffer);
1262 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1263 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1264 NULL, MSIINSTALLCONTEXT_MACHINE,
1265 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1266 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1268 buffer[0] = 0;
1269 size = sizeof(buffer);
1270 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1271 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1272 NULL, MSIINSTALLCONTEXT_USERMANAGED,
1273 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1274 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1275 ok( !buffer[0], "got %s\n", buffer );
1277 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1278 NULL, MSIINSTALLCONTEXT_USERUNMANAGED, MSIPATCHSTATE_APPLIED,
1279 0, patch_code, NULL, NULL, NULL, NULL );
1280 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1281 ok( !strcmp( patch_code, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" );
1283 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1284 NULL, MSIINSTALLCONTEXT_MACHINE, MSIPATCHSTATE_APPLIED,
1285 0, patch_code, NULL, NULL, NULL, NULL );
1286 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1288 r = pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1289 NULL, MSIINSTALLCONTEXT_USERMANAGED, MSIPATCHSTATE_APPLIED,
1290 0, patch_code, NULL, NULL, NULL, NULL );
1291 ok( r == ERROR_NO_MORE_ITEMS, "expected ERROR_NO_MORE_ITEMS, got %u\n", r );
1293 uninstall:
1294 r = MsiInstallProductA( msifile, "REMOVE=ALL" );
1295 ok( r == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", r );
1297 buffer[0] = 0;
1298 size = sizeof(buffer);
1299 r = pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1300 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1301 NULL, MSIINSTALLCONTEXT_USERUNMANAGED,
1302 INSTALLPROPERTY_LOCALPACKAGE, buffer, &size );
1303 ok( r == ERROR_UNKNOWN_PRODUCT, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r );
1305 cleanup:
1306 DeleteFileA( msifile );
1307 DeleteFileA( mspfile );
1308 DeleteFileA( "msitest\\patch.txt" );
1309 RemoveDirectoryA( "msitest" );
1312 START_TEST(patch)
1314 DWORD len;
1315 char temp_path[MAX_PATH], prev_path[MAX_PATH];
1317 init_function_pointers();
1319 GetCurrentDirectoryA( MAX_PATH, prev_path );
1320 GetTempPath( MAX_PATH, temp_path );
1321 SetCurrentDirectoryA( temp_path );
1323 strcpy( CURR_DIR, temp_path );
1324 len = strlen( CURR_DIR );
1326 if (len && (CURR_DIR[len - 1] == '\\'))
1327 CURR_DIR[len - 1] = 0;
1329 get_program_files_dir( PROG_FILES_DIR, COMMON_FILES_DIR );
1331 test_simple_patch();
1332 test_MsiOpenDatabase();
1333 test_system_tables();
1334 test_patch_registration();
1336 SetCurrentDirectoryA( prev_path );