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
23 static UINT (WINAPI
*pMsiApplyPatchA
)( LPCSTR
, LPCSTR
, INSTALLTYPE
, LPCSTR
);
24 static UINT (WINAPI
*pMsiGetPatchInfoExA
)( LPCSTR
, LPCSTR
, LPCSTR
, MSIINSTALLCONTEXT
,
25 LPCSTR
, LPSTR
, DWORD
* );
26 static UINT (WINAPI
*pMsiEnumPatchesExA
)( LPCSTR
, LPCSTR
, DWORD
, DWORD
, DWORD
, LPSTR
,
27 LPSTR
, MSIINSTALLCONTEXT
*, LPSTR
, LPDWORD
);
28 static BOOL (WINAPI
*pOpenProcessToken
)( HANDLE
, DWORD
, PHANDLE
);
30 static const char *msifile
= "winetest-patch.msi";
31 static const char *mspfile
= "winetest-patch.msp";
32 static const WCHAR msifileW
[] =
33 {'w','i','n','e','t','e','s','t','-','p','a','t','c','h','.','m','s','i',0};
34 static const WCHAR mspfileW
[] =
35 {'w','i','n','e','t','e','s','t','-','p','a','t','c','h','.','m','s','p',0};
37 static char CURR_DIR
[MAX_PATH
];
38 static char PROG_FILES_DIR
[MAX_PATH
];
39 static char COMMON_FILES_DIR
[MAX_PATH
];
41 /* msi database data */
43 static const char property_dat
[] =
46 "Property\tProperty\n"
47 "Manufacturer\tWineHQ\n"
48 "ProductCode\t{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}\n"
49 "UpgradeCode\t{A2E3D643-4E2C-477F-A309-F76F552D5F43}\n"
50 "ProductLanguage\t1033\n"
51 "ProductName\tmsitest\n"
52 "ProductVersion\t1.1.1\n"
53 "PATCHNEWSUMMARYSUBJECT\tInstaller Database\n"
54 "MSIFASTINSTALL\t1\n";
56 static const char media_dat
[] =
57 "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
58 "i2\ti4\tL64\tS255\tS32\tS72\n"
60 "1\t1\t\t\tDISK1\t\n";
62 static const char file_dat
[] =
63 "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
64 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
66 "patch.txt\tpatch\tpatch.txt\t1000\t\t\t0\t1\n";
68 static const char directory_dat
[] =
69 "Directory\tDirectory_Parent\tDefaultDir\n"
71 "Directory\tDirectory\n"
72 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
73 "ProgramFilesFolder\tTARGETDIR\t.\n"
74 "TARGETDIR\t\tSourceDir";
76 static const char component_dat
[] =
77 "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
78 "s72\tS38\ts72\ti2\tS255\tS72\n"
79 "Component\tComponent\n"
80 "patch\t{4B79D87E-6D28-4FD3-92D6-CD9B26AF64F1}\tMSITESTDIR\t0\t\tpatch.txt\n";
82 static const char feature_dat
[] =
83 "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
84 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
86 "patch\t\t\tpatch feature\t1\t1\tMSITESTDIR\t0\n";
88 static const char feature_comp_dat
[] =
89 "Feature_\tComponent_\n"
91 "FeatureComponents\tFeature_\tComponent_\n"
94 static const char install_exec_seq_dat
[] =
95 "Action\tCondition\tSequence\n"
97 "InstallExecuteSequence\tAction\n"
98 "LaunchConditions\t\t100\n"
99 "CostInitialize\t\t800\n"
101 "CostFinalize\t\t1000\n"
102 "InstallValidate\t\t1400\n"
103 "InstallInitialize\t\t1500\n"
104 "ProcessComponents\t\t1600\n"
105 "RemoveFiles\t\t1700\n"
106 "InstallFiles\t\t2000\n"
107 "RegisterUser\t\t3000\n"
108 "RegisterProduct\t\t3100\n"
109 "PublishFeatures\t\t5100\n"
110 "PublishProduct\t\t5200\n"
111 "InstallFinalize\t\t6000\n";
115 const char *filename
;
120 #define ADD_TABLE( x ) { #x".idt", x##_dat, sizeof(x##_dat) }
122 static const struct msi_table tables
[] =
124 ADD_TABLE( directory
),
126 ADD_TABLE( component
),
127 ADD_TABLE( feature
),
128 ADD_TABLE( feature_comp
),
129 ADD_TABLE( property
),
130 ADD_TABLE( install_exec_seq
),
134 static void init_function_pointers( void )
136 HMODULE hmsi
= GetModuleHandleA( "msi.dll" );
137 HMODULE hadvapi32
= GetModuleHandleA( "advapi32.dll" );
139 #define GET_PROC( mod, func ) \
140 p ## func = (void *)GetProcAddress( mod, #func ); \
142 trace( "GetProcAddress(%s) failed\n", #func );
144 GET_PROC( hmsi
, MsiApplyPatchA
);
145 GET_PROC( hmsi
, MsiGetPatchInfoExA
);
146 GET_PROC( hmsi
, MsiEnumPatchesExA
);
148 GET_PROC( hadvapi32
, OpenProcessToken
);
152 static BOOL
is_process_limited(void)
156 if (!pOpenProcessToken
) return FALSE
;
158 if (pOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &token
))
161 TOKEN_ELEVATION_TYPE type
= TokenElevationTypeDefault
;
164 ret
= GetTokenInformation(token
, TokenElevationType
, &type
, sizeof(type
), &size
);
166 return (ret
&& type
== TokenElevationTypeLimited
);
171 static BOOL
get_program_files_dir( char *buf
, char *buf2
)
176 if (RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey
))
180 if (RegQueryValueExA( hkey
, "ProgramFilesDir (x86)", 0, &type
, (LPBYTE
)buf
, &size
) &&
181 RegQueryValueExA( hkey
, "ProgramFilesDir", 0, &type
, (LPBYTE
)buf
, &size
))
187 if (RegQueryValueExA( hkey
, "CommonFilesDir", 0, &type
, (LPBYTE
)buf2
, &size
))
196 static void create_file_data( const char *filename
, const char *data
, DWORD size
)
201 file
= CreateFileA( filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
202 if (file
== INVALID_HANDLE_VALUE
)
205 WriteFile( file
, data
, strlen( data
), &written
, NULL
);
208 SetFilePointer( file
, size
, NULL
, FILE_BEGIN
);
209 SetEndOfFile( file
);
214 #define create_file( name, size ) create_file_data( name, name, size )
216 static BOOL
delete_pf( const char *rel_path
, BOOL is_file
)
220 strcpy( path
, PROG_FILES_DIR
);
221 strcat( path
, "\\" );
222 strcat( path
, rel_path
);
225 return DeleteFileA( path
);
227 return RemoveDirectoryA( path
);
230 static DWORD
get_pf_file_size( const char *filename
)
236 strcpy( path
, PROG_FILES_DIR
);
238 strcat( path
, filename
);
240 file
= CreateFileA( path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
241 if (file
== INVALID_HANDLE_VALUE
)
242 return INVALID_FILE_SIZE
;
244 size
= GetFileSize( file
, NULL
);
249 static void write_file( const char *filename
, const char *data
, DWORD data_size
)
252 HANDLE file
= CreateFileA( filename
, GENERIC_WRITE
, 0, NULL
,
253 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
254 WriteFile( file
, data
, data_size
, &size
, NULL
);
258 static void set_suminfo( const WCHAR
*filename
)
263 r
= MsiOpenDatabaseW( filename
, MSIDBOPEN_DIRECT
, &hdb
);
264 ok( r
== ERROR_SUCCESS
, "failed to open database %u\n", r
);
266 r
= MsiGetSummaryInformationA( hdb
, NULL
, 7, &hsi
);
267 ok( r
== ERROR_SUCCESS
, "failed to open summaryinfo %u\n", r
);
269 r
= MsiSummaryInfoSetPropertyA( hsi
, 2, VT_LPSTR
, 0, NULL
, "Installation Database" );
270 ok( r
== ERROR_SUCCESS
, "failed to set summary info %u\n", r
);
272 r
= MsiSummaryInfoSetPropertyA( hsi
, 3, VT_LPSTR
, 0, NULL
, "Installation Database" );
273 ok( r
== ERROR_SUCCESS
, "failed to set summary info %u\n", r
);
275 r
= MsiSummaryInfoSetPropertyA( hsi
, 4, VT_LPSTR
, 0, NULL
, "WineHQ" );
276 ok( r
== ERROR_SUCCESS
, "failed to set summary info %u\n", r
);
278 r
= MsiSummaryInfoSetPropertyA( hsi
, 7, VT_LPSTR
, 0, NULL
, ";1033" );
279 ok( r
== ERROR_SUCCESS
, "failed to set summary info %u\n", r
);
281 r
= MsiSummaryInfoSetPropertyA( hsi
, 9, VT_LPSTR
, 0, NULL
, "{E528DDD6-4801-4BEC-BBB6-C5EE0FD097E9}" );
282 ok( r
== ERROR_SUCCESS
, "failed to set summary info %u\n", r
);
284 r
= MsiSummaryInfoSetPropertyA( hsi
, 14, VT_I4
, 100, NULL
, NULL
);
285 ok( r
== ERROR_SUCCESS
, "failed to set summary info %u\n", r
);
287 r
= MsiSummaryInfoSetPropertyA( hsi
, 15, VT_I4
, 0, NULL
, NULL
);
288 ok( r
== ERROR_SUCCESS
, "failed to set summary info %u\n", r
);
290 r
= MsiSummaryInfoPersist( hsi
);
291 ok( r
== ERROR_SUCCESS
, "failed to persist suminfo %u\n", r
);
293 r
= MsiCloseHandle( hsi
);
294 ok( r
== ERROR_SUCCESS
, "failed to close suminfo %u\n", r
);
296 r
= MsiCloseHandle( hdb
);
297 ok( r
== ERROR_SUCCESS
, "failed to close database %u\n", r
);
300 static void create_database( const char *filename
, const struct msi_table
*tables
, UINT num_tables
)
307 len
= MultiByteToWideChar( CP_ACP
, 0, filename
, -1, NULL
, 0 );
308 if (!(filenameW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return;
309 MultiByteToWideChar( CP_ACP
, 0, filename
, -1, filenameW
, len
);
311 r
= MsiOpenDatabaseW( filenameW
, MSIDBOPEN_CREATE
, &hdb
);
312 ok(r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
314 /* import the tables into the database */
315 for (i
= 0; i
< num_tables
; i
++)
317 const struct msi_table
*table
= &tables
[i
];
319 write_file( table
->filename
, table
->data
, (table
->size
- 1) * sizeof(char) );
321 r
= MsiDatabaseImportA( hdb
, CURR_DIR
, table
->filename
);
322 ok(r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
324 DeleteFileA( table
->filename
);
327 r
= MsiDatabaseCommit( hdb
);
328 ok(r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
330 MsiCloseHandle( hdb
);
331 set_suminfo( filenameW
);
332 HeapFree( GetProcessHeap(), 0, filenameW
);
335 /* data for generating a patch */
337 /* table names - encoded as in an msi database file */
338 static const WCHAR p_name0
[] = { 0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0 }; /* _Columns */
339 static const WCHAR p_name1
[] = { 0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0 }; /* _Tables */
340 static const WCHAR p_name2
[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
341 static const WCHAR p_name3
[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
342 static const WCHAR p_name4
[] = { 0x3a8c, 0x47cb, 0x45b0, 0x45ec, 0x45a8, 0x4837, 0}; /* CAB_msitest */
343 static const WCHAR p_name5
[] = { 0x4840, 0x4596, 0x3e6c, 0x45e4, 0x42e6, 0x421c, 0x4634, 0x4468, 0x4226, 0 }; /* MsiPatchSequence */
344 static const WCHAR p_name6
[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
345 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
346 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
347 /* substorage names */
348 static const WCHAR p_name7
[] = { 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075, 0x0070,
349 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* targetToupgraded */
350 static const WCHAR p_name8
[] = { 0x0023, 0x0074, 0x0061, 0x0072, 0x0067, 0x0065, 0x0074, 0x0054, 0x006f, 0x0075,
351 0x0070, 0x0067, 0x0072, 0x0061, 0x0064, 0x0065, 0x0064, 0 }; /* #targetToupgraded */
353 /* data in each table */
354 static const WCHAR p_data0
[] = { /* _Columns */
355 0x0001, 0x0001, 0x0001, 0x0001, 0x8001, 0x8002, 0x8003, 0x8004,
356 0x0002, 0x0003, 0x0004, 0x0005, 0xad00, 0xbd26, 0x8d00, 0x9502
358 static const WCHAR p_data1
[] = { /* _Tables */
361 static const char p_data2
[] = { /* _StringData */
362 "MsiPatchSequencePatchFamilyProductCodeSequenceAttributes1.1.19388.37230913B8D18FBB64CACA239C74C11E3FA74"
364 static const WCHAR p_data3
[] = { /* _StringPool */
366 0, 0, /* string 0 '' */
367 16, 5, /* string 1 'MsiPatchSequence' */
368 11, 1, /* string 2 'PatchFamily' */
369 11, 1, /* string 3 'ProductCode' */
370 8, 1, /* string 4 'Sequence' */
371 10, 1, /* string 5 'Attributes' */
372 15, 1, /* string 6 '1.1.19388.37230' */
373 32, 1, /* string 7 '913B8D18FBB64CACA239C74C11E3FA74' */
375 static const char p_data4
[] = { /* CAB_msitest */
376 0x4d, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00,
377 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00,
378 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9e,
379 0x03, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x12,
380 0xea, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87,
381 0x3c, 0xd4, 0x80, 0x20, 0x00, 0x70, 0x61, 0x74, 0x63, 0x68, 0x2e,
382 0x74, 0x78, 0x74, 0x00, 0x0b, 0x3c, 0xd6, 0xc1, 0x4a, 0x00, 0xea,
383 0x03, 0x5b, 0x80, 0x80, 0x8d, 0x00, 0x10, 0xa1, 0x3e, 0x00, 0x00,
384 0x00, 0x00, 0x03, 0x00, 0x40, 0x30, 0x0c, 0x43, 0xf8, 0xb4, 0x85,
385 0x4d, 0x96, 0x08, 0x0a, 0x92, 0xf0, 0x52, 0xfb, 0xbb, 0x82, 0xf9,
386 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0e, 0x31, 0x7d,
387 0x56, 0xdf, 0xf7, 0x48, 0x7c, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
388 0x00, 0x00, 0x41, 0x80, 0xdf, 0xf7, 0xd8, 0x72, 0xbf, 0xb9, 0x63,
389 0x91, 0x0e, 0x57, 0x1f, 0xfa, 0x1a, 0x66, 0x54, 0x55
391 static const WCHAR p_data5
[] = { /* MsiPatchSequence */
392 0x0007, 0x0000, 0x0006, 0x8000
394 static const char p_data6
[] = { /* SummaryInformation */
395 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
396 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
397 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
398 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
399 0x30, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
400 0x00, 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00,
401 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x90,
402 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
403 0x0f, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
404 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x30, 0x46, 0x39, 0x36, 0x43,
405 0x44, 0x43, 0x30, 0x2d, 0x34, 0x43, 0x44, 0x46, 0x2d, 0x34, 0x33,
406 0x30, 0x34, 0x2d, 0x42, 0x32, 0x38, 0x33, 0x2d, 0x37, 0x42, 0x39,
407 0x32, 0x36, 0x34, 0x38, 0x38, 0x39, 0x45, 0x46, 0x37, 0x7d, 0x00,
408 0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x7b, 0x39,
409 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46, 0x42, 0x42,
410 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32, 0x33, 0x39,
411 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33, 0x46, 0x41,
412 0x37, 0x34, 0x7d, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x25, 0x00,
413 0x00, 0x00, 0x3a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f,
414 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x3b, 0x3a, 0x23,
415 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x54, 0x6f, 0x75, 0x70, 0x67,
416 0x72, 0x61, 0x64, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
417 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x50, 0x61, 0x74, 0x63, 0x68,
418 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x00,
419 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
428 static const struct table_data table_patch_data
[] = {
429 { p_name0
, p_data0
, sizeof p_data0
},
430 { p_name1
, p_data1
, sizeof p_data1
},
431 { p_name2
, p_data2
, sizeof p_data2
- 1 },
432 { p_name3
, p_data3
, sizeof p_data3
},
433 { p_name4
, p_data4
, sizeof p_data4
},
434 { p_name5
, p_data5
, sizeof p_data5
},
435 { p_name6
, p_data6
, sizeof p_data6
}
438 #define NUM_PATCH_TABLES (sizeof table_patch_data/sizeof table_patch_data[0])
440 static const WCHAR t1_name0
[] = { 0x4840, 0x430f, 0x422f, 0 }; /* File */
441 static const WCHAR t1_name1
[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3b6a, 0x45e4, 0x4824, 0 }; /* _StringData */
442 static const WCHAR t1_name2
[] = { 0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0 }; /* _StringPool */
443 static const WCHAR t1_name3
[] = { 0x0005, 0x0053, 0x0075, 0x006d, 0x006d, 0x0061, 0x0072,
444 0x0079, 0x0049, 0x006e, 0x0066, 0x006f, 0x0072, 0x006d,
445 0x0061, 0x0074, 0x0069, 0x006f, 0x006e, 0 }; /* SummaryInformation */
447 static const WCHAR t1_data0
[] = { /* File */
448 0x0008, 0x0001, 0x03ea, 0x8000
450 static const char t1_data1
[] = { /* _StringData */
453 static const WCHAR t1_data2
[] = { /* _StringPool */
455 0, 0, /* string 0 '' */
456 9, 1, /* string 1 'patch.txt' */
458 static const char t1_data3
[] = { /* SummaryInformation */
459 0xfe, 0xff, 0x00, 0x00, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
460 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
461 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x9f, 0xf2, 0xf9,
462 0x4f, 0x68, 0x10, 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9,
463 0x30, 0x00, 0x00, 0x00, 0x9f, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00,
464 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00,
465 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa8,
466 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00,
467 0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
468 0x00, 0xd0, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdc, 0x00,
469 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x08,
470 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
471 0x07, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8f, 0x01, 0x00,
472 0x00, 0x10, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00, 0x1e, 0x00,
473 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61,
474 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74,
475 0x61, 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
476 0x00, 0x16, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c,
477 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x44, 0x61, 0x74, 0x61,
478 0x62, 0x61, 0x73, 0x65, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
479 0x07, 0x00, 0x00, 0x00, 0x57, 0x69, 0x6e, 0x65, 0x48, 0x51, 0x00,
480 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
481 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
482 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
483 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
484 0x00, 0x1e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x78, 0x38,
485 0x36, 0x3b, 0x31, 0x30, 0x33, 0x33, 0x00, 0x00, 0x00, 0x1e, 0x00,
486 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x30, 0x33, 0x33,
487 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
488 0x7b, 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46,
489 0x42, 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32,
490 0x33, 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33,
491 0x46, 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b,
492 0x7b, 0x39, 0x31, 0x33, 0x42, 0x38, 0x44, 0x31, 0x38, 0x2d, 0x46,
493 0x42, 0x42, 0x36, 0x2d, 0x34, 0x43, 0x41, 0x43, 0x2d, 0x41, 0x32,
494 0x33, 0x39, 0x2d, 0x43, 0x37, 0x34, 0x43, 0x31, 0x31, 0x45, 0x33,
495 0x46, 0x41, 0x37, 0x34, 0x7d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x3b,
496 0x7b, 0x41, 0x32, 0x45, 0x33, 0x44, 0x36, 0x34, 0x33, 0x2d, 0x34,
497 0x45, 0x32, 0x43, 0x2d, 0x34, 0x37, 0x37, 0x46, 0x2d, 0x41, 0x33,
498 0x30, 0x39, 0x2d, 0x46, 0x37, 0x36, 0x46, 0x35, 0x35, 0x32, 0x44,
499 0x35, 0x46, 0x34, 0x33, 0x7d, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
500 0x64, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x22,
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,
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 */
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
)
644 for (i
= 0; i
< num_tables
; i
++)
646 r
= IStorage_CreateStream( stg
, tables
[i
].name
, STGM_WRITE
|STGM_SHARE_EXCLUSIVE
, 0, 0, &stm
);
649 ok( 0, "failed to create stream 0x%08x\n", r
);
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
;
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
);
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 )
710 char path
[MAX_PATH
], install_source
[MAX_PATH
], buffer
[32];
712 WCHAR pathW
[MAX_PATH
];
713 MSIHANDLE hpackage
, hdb
, hview
, hrec
;
715 if (!pMsiApplyPatchA
)
717 win_skip("MsiApplyPatchA is not available\n");
720 if (is_process_limited())
722 skip("process is limited\n");
726 CreateDirectoryA( "msitest", NULL
);
727 create_file( "msitest\\patch.txt", 1000 );
729 create_database( msifile
, tables
, sizeof(tables
) / sizeof(struct msi_table
) );
730 create_patch( mspfile
);
732 MsiSetInternalUI( INSTALLUILEVEL_NONE
, NULL
);
734 r
= MsiInstallProductA( msifile
, NULL
);
735 if (r
!= ERROR_SUCCESS
)
737 skip("Product installation failed with error code %u\n", r
);
741 size
= get_pf_file_size( "msitest\\patch.txt" );
742 ok( size
== 1000, "expected 1000, got %u\n", size
);
744 size
= sizeof(install_source
);
745 r
= MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
746 "InstallSource", install_source
, &size
);
747 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
749 strcpy( path
, CURR_DIR
);
750 strcat( path
, "\\" );
751 strcat( path
, msifile
);
753 r
= MsiOpenPackageA( path
, &hpackage
);
754 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
756 hdb
= MsiGetActiveDatabase( hpackage
);
757 ok( hdb
, "failed to get database handle\n" );
759 query
= "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
760 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
761 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
763 r
= MsiViewExecute( hview
, 0 );
764 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
766 r
= MsiViewFetch( hview
, &hrec
);
767 ok( r
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
769 MsiCloseHandle( hrec
);
770 MsiViewClose( hview
);
771 MsiCloseHandle( hview
);
773 query
= "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
774 "AND `Value` = 'Installer Database'";
775 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
776 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
778 r
= MsiViewExecute( hview
, 0 );
779 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
781 r
= MsiViewFetch( hview
, &hrec
);
782 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
784 MsiCloseHandle( hrec
);
785 MsiViewClose( hview
);
786 MsiCloseHandle( hview
);
789 size
= sizeof(buffer
);
790 r
= MsiGetPropertyA( hpackage
, "PATCHNEWSUMMARYSUBJECT", buffer
, &size
);
791 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
792 ok( !strcmp( buffer
, "Installer Database" ), "expected \'Installer Database\', got \'%s\'\n", buffer
);
794 MsiCloseHandle( hdb
);
795 MsiCloseHandle( hpackage
);
797 r
= MsiApplyPatchA( mspfile
, NULL
, INSTALLTYPE_DEFAULT
, NULL
);
798 ok( r
== ERROR_SUCCESS
|| broken( r
== ERROR_PATCH_PACKAGE_INVALID
), /* version 2.0 */
799 "expected ERROR_SUCCESS, got %u\n", r
);
801 if (r
== ERROR_PATCH_PACKAGE_INVALID
)
803 win_skip("Windows Installer < 3.0 detected\n");
807 size
= get_pf_file_size( "msitest\\patch.txt" );
808 ok( size
== 1002, "expected 1002, got %u\n", size
);
810 /* show that MsiOpenPackage applies registered patches */
811 r
= MsiOpenPackageA( path
, &hpackage
);
812 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
814 hdb
= MsiGetActiveDatabase( hpackage
);
815 ok( hdb
, "failed to get database handle\n" );
817 query
= "SELECT * FROM `Property` where `Property` = 'PATCHNEWPACKAGECODE'";
818 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
819 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
821 r
= MsiViewExecute( hview
, 0 );
822 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
824 r
= MsiViewFetch( hview
, &hrec
);
825 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
827 MsiCloseHandle( hrec
);
828 MsiViewClose( hview
);
829 MsiCloseHandle( hview
);
831 query
= "SELECT * FROM `Property` WHERE `Property` = 'PATCHNEWSUMMARYSUBJECT' "
832 "AND `Value` = 'Installation Database'";
833 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
834 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
836 r
= MsiViewExecute( hview
, 0 );
837 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
839 r
= MsiViewFetch( hview
, &hrec
);
840 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
842 MsiCloseHandle( hrec
);
843 MsiViewClose( hview
);
844 MsiCloseHandle( hview
);
847 size
= sizeof(buffer
);
848 r
= MsiGetPropertyA( hpackage
, "PATCHNEWSUMMARYSUBJECT", buffer
, &size
);
849 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
850 ok( !strcmp( buffer
, "Installation Database" ), "expected \'Installation Database\', got \'%s\'\n", buffer
);
852 MsiCloseHandle( hdb
);
853 MsiCloseHandle( hpackage
);
855 /* show that patches are not committed to the local package database */
857 r
= MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
858 "LocalPackage", path
, &size
);
859 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
861 MultiByteToWideChar( CP_ACP
, 0, path
, -1, pathW
, MAX_PATH
);
862 r
= MsiOpenDatabaseW( pathW
, MSIDBOPEN_READONLY
, &hdb
);
863 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
865 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
866 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
868 r
= MsiViewExecute( hview
, 0 );
869 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
871 r
= MsiViewFetch( hview
, &hrec
);
872 ok( r
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
874 MsiCloseHandle( hrec
);
875 MsiViewClose( hview
);
876 MsiCloseHandle( hview
);
877 MsiCloseHandle( hdb
);
881 r
= MsiGetProductInfoA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
882 "InstallSource", path
, &size
);
883 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
884 ok( !strcasecmp( path
, install_source
), "wrong path %s\n", path
);
886 r
= MsiInstallProductA( msifile
, "REMOVE=ALL" );
887 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
889 ok( !delete_pf( "msitest\\patch.txt", TRUE
), "file not removed\n" );
890 ok( !delete_pf( "msitest", FALSE
), "directory not removed\n" );
893 DeleteFileA( msifile
);
894 DeleteFileA( mspfile
);
895 DeleteFileA( "msitest\\patch.txt" );
896 RemoveDirectoryA( "msitest" );
899 static void test_MsiOpenDatabase( void )
904 r
= MsiOpenDatabaseW( mspfileW
, MSIDBOPEN_CREATE
, &hdb
);
905 ok(r
== ERROR_SUCCESS
, "failed to open database %u\n", r
);
907 r
= MsiDatabaseCommit( hdb
);
908 ok(r
== ERROR_SUCCESS
, "failed to commit database %u\n", r
);
909 MsiCloseHandle( hdb
);
911 r
= MsiOpenDatabaseW( mspfileW
, MSIDBOPEN_READONLY
+ MSIDBOPEN_PATCHFILE
, &hdb
);
912 ok(r
== ERROR_OPEN_FAILED
, "expected ERROR_OPEN_FAILED, got %u\n", r
);
913 DeleteFileA( mspfile
);
915 r
= MsiOpenDatabaseW( mspfileW
, MSIDBOPEN_CREATE
+ MSIDBOPEN_PATCHFILE
, &hdb
);
916 ok(r
== ERROR_SUCCESS
, "failed to open database %u\n", r
);
918 r
= MsiDatabaseCommit( hdb
);
919 ok(r
== ERROR_SUCCESS
, "failed to commit database %u\n", r
);
920 MsiCloseHandle( hdb
);
922 r
= MsiOpenDatabaseW( mspfileW
, MSIDBOPEN_READONLY
+ MSIDBOPEN_PATCHFILE
, &hdb
);
923 ok(r
== ERROR_SUCCESS
, "failed to open database %u\n", r
);
924 MsiCloseHandle( hdb
);
925 DeleteFileA( mspfile
);
927 create_database( msifile
, tables
, sizeof(tables
) / sizeof(struct msi_table
) );
928 create_patch( mspfile
);
930 r
= MsiOpenDatabaseW( msifileW
, MSIDBOPEN_READONLY
+ MSIDBOPEN_PATCHFILE
, &hdb
);
931 ok(r
== ERROR_OPEN_FAILED
, "failed to open database %u\n", r
);
933 r
= MsiOpenDatabaseW( mspfileW
, MSIDBOPEN_READONLY
+ MSIDBOPEN_PATCHFILE
, &hdb
);
934 ok(r
== ERROR_SUCCESS
, "failed to open database %u\n", r
);
935 MsiCloseHandle( hdb
);
937 DeleteFileA( msifile
);
938 DeleteFileA( mspfile
);
941 static UINT
find_entry( MSIHANDLE hdb
, const char *table
, const char *entry
)
943 static const char fmt
[] = "SELECT * FROM `%s` WHERE `Name` = '%s'";
946 MSIHANDLE hview
, hrec
;
948 sprintf( query
, fmt
, table
, entry
);
949 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
950 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
952 r
= MsiViewExecute( hview
, 0 );
953 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
955 r
= MsiViewFetch( hview
, &hrec
);
956 MsiViewClose( hview
);
957 MsiCloseHandle( hview
);
958 MsiCloseHandle( hrec
);
962 static UINT
find_entryW( MSIHANDLE hdb
, const WCHAR
*table
, const WCHAR
*entry
)
964 static const WCHAR fmt
[] =
965 {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',' ',
966 'W','H','E','R','E',' ','`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0};
968 MSIHANDLE hview
, hrec
;
971 wsprintfW( query
, fmt
, table
, entry
);
972 r
= MsiDatabaseOpenViewW( hdb
, query
, &hview
);
973 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
975 r
= MsiViewExecute( hview
, 0 );
976 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
978 r
= MsiViewFetch( hview
, &hrec
);
979 MsiViewClose( hview
);
980 MsiCloseHandle( hview
);
981 MsiCloseHandle( hrec
);
985 static INT
get_integer( MSIHANDLE hdb
, UINT field
, const char *query
)
989 MSIHANDLE hview
, hrec
;
991 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
992 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
994 r
= MsiViewExecute( hview
, 0 );
995 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
997 r
= MsiViewFetch( hview
, &hrec
);
998 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
999 if (r
== ERROR_SUCCESS
)
1002 ret
= MsiRecordGetInteger( hrec
, field
);
1003 MsiCloseHandle( hrec
);
1005 r_tmp
= MsiViewFetch( hview
, &hrec
);
1006 ok( r_tmp
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
1009 MsiViewClose( hview
);
1010 MsiCloseHandle( hview
);
1014 static char *get_string( MSIHANDLE hdb
, UINT field
, const char *query
)
1017 static char ret
[MAX_PATH
];
1018 MSIHANDLE hview
, hrec
;
1022 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
1023 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1025 r
= MsiViewExecute( hview
, 0 );
1026 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1028 r
= MsiViewFetch( hview
, &hrec
);
1029 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1030 if (r
== ERROR_SUCCESS
)
1032 UINT size
= MAX_PATH
;
1033 r
= MsiRecordGetStringA( hrec
, field
, ret
, &size
);
1034 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1035 MsiCloseHandle( hrec
);
1037 r
= MsiViewFetch( hview
, &hrec
);
1038 ok( r
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
1041 MsiViewClose( hview
);
1042 MsiCloseHandle( hview
);
1046 static void test_system_tables( void )
1048 static const char patchsource
[] = "MSPSRC0F96CDC04CDF4304B2837B9264889EF7";
1049 static const WCHAR streamsW
[] = {'_','S','t','r','e','a','m','s',0};
1050 static const WCHAR CAB_msitest_encodedW
[] = {0x3a8c,0x47cb,0x45b0,0x45ec,0x45a8,0x4837,0};
1054 MSIHANDLE hproduct
, hdb
, hview
, hrec
;
1056 if (!pMsiApplyPatchA
)
1058 win_skip("MsiApplyPatchA is not available\n");
1061 if (is_process_limited())
1063 skip("process is limited\n");
1067 CreateDirectoryA( "msitest", NULL
);
1068 create_file( "msitest\\patch.txt", 1000 );
1070 create_database( msifile
, tables
, sizeof(tables
) / sizeof(struct msi_table
) );
1071 create_patch( mspfile
);
1073 MsiSetInternalUI( INSTALLUILEVEL_NONE
, NULL
);
1075 r
= MsiInstallProductA( msifile
, NULL
);
1076 if (r
!= ERROR_SUCCESS
)
1078 skip("Product installation failed with error code %d\n", r
);
1082 r
= MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct
);
1083 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1085 hdb
= MsiGetActiveDatabase( hproduct
);
1086 ok( hdb
, "failed to get database handle\n" );
1088 r
= find_entry( hdb
, "_Streams", "\5SummaryInformation" );
1089 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1091 query
= "SELECT * FROM `_Storages`";
1092 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
1093 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1095 r
= MsiViewExecute( hview
, 0 );
1096 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1098 r
= MsiViewFetch( hview
, &hrec
);
1099 ok( r
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
1101 r
= find_entry( hdb
, "_Tables", "Directory" );
1102 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1104 r
= find_entry( hdb
, "_Tables", "File" );
1105 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1107 r
= find_entry( hdb
, "_Tables", "Component" );
1108 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1110 r
= find_entry( hdb
, "_Tables", "Feature" );
1111 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1113 r
= find_entry( hdb
, "_Tables", "FeatureComponents" );
1114 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1116 r
= find_entry( hdb
, "_Tables", "Property" );
1117 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1119 r
= find_entry( hdb
, "_Tables", "InstallExecuteSequence" );
1120 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1122 r
= find_entry( hdb
, "_Tables", "Media" );
1123 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1125 r
= get_integer( hdb
, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1126 ok( r
== 1, "Got %u\n", r
);
1128 r
= find_entry( hdb
, "_Tables", "_Property" );
1129 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1131 MsiCloseHandle( hrec
);
1132 MsiViewClose( hview
);
1133 MsiCloseHandle( hview
);
1134 MsiCloseHandle( hdb
);
1135 MsiCloseHandle( hproduct
);
1137 r
= MsiApplyPatchA( mspfile
, NULL
, INSTALLTYPE_DEFAULT
, NULL
);
1138 ok( r
== ERROR_SUCCESS
|| broken( r
== ERROR_PATCH_PACKAGE_INVALID
), /* version 2.0 */
1139 "expected ERROR_SUCCESS, got %u\n", r
);
1141 if (r
== ERROR_PATCH_PACKAGE_INVALID
)
1143 win_skip("Windows Installer < 3.0 detected\n");
1147 r
= MsiOpenProductA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}", &hproduct
);
1148 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1150 hdb
= MsiGetActiveDatabase( hproduct
);
1151 ok( hdb
, "failed to get database handle\n" );
1153 r
= find_entry( hdb
, "_Streams", "\5SummaryInformation" );
1154 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1156 r
= find_entryW( hdb
, streamsW
, CAB_msitest_encodedW
);
1157 ok( r
== ERROR_NO_MORE_ITEMS
, "failed to find entry %u\n", r
);
1159 query
= "SELECT * FROM `_Storages`";
1160 r
= MsiDatabaseOpenViewA( hdb
, query
, &hview
);
1161 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1163 r
= MsiViewExecute( hview
, 0 );
1164 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1166 r
= MsiViewFetch( hview
, &hrec
);
1167 ok( r
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
1169 r
= find_entry( hdb
, "_Tables", "Directory" );
1170 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1172 r
= find_entry( hdb
, "_Tables", "File" );
1173 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1175 r
= find_entry( hdb
, "_Tables", "Component" );
1176 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1178 r
= find_entry( hdb
, "_Tables", "Feature" );
1179 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1181 r
= find_entry( hdb
, "_Tables", "FeatureComponents" );
1182 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1184 r
= find_entry( hdb
, "_Tables", "Property" );
1185 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1187 r
= find_entry( hdb
, "_Tables", "InstallExecuteSequence" );
1188 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1190 r
= find_entry( hdb
, "_Tables", "Media" );
1191 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1193 r
= find_entry( hdb
, "_Tables", "_Property" );
1194 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1196 r
= find_entry( hdb
, "_Tables", "MsiPatchHeaders" );
1197 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1199 r
= find_entry( hdb
, "_Tables", "Patch" );
1200 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1202 r
= find_entry( hdb
, "_Tables", "PatchPackage" );
1203 ok( r
== ERROR_SUCCESS
, "failed to find entry %u\n", r
);
1205 cr
= get_string( hdb
, 6, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1206 todo_wine
ok( !strcmp(cr
, patchsource
), "Expected \"%s\", got \"%s\"\n", patchsource
, cr
);
1208 r
= get_integer( hdb
, 1, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1209 todo_wine
ok( r
== 100, "Got %u\n", r
);
1211 r
= get_integer( hdb
, 2, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1212 todo_wine
ok( r
== 10000, "Got %u\n", r
);
1214 r
= get_integer( hdb
, 1, "SELECT * FROM `Media` WHERE `VolumeLabel`=\'DISK1\'");
1215 ok( r
== 1, "Got %u\n", r
);
1217 cr
= get_string( hdb
, 4, "SELECT * FROM `Media` WHERE `Source` IS NOT NULL");
1218 ok( !strcmp(cr
, "#CAB_msitest"), "Expected \"#CAB_msitest\", got \"%s\"\n", cr
);
1220 r
= get_integer( hdb
, 8, "SELECT * FROM `File` WHERE `File` = 'patch.txt'");
1221 ok( r
== 10000, "Got %u\n", r
);
1223 MsiCloseHandle( hrec
);
1224 MsiViewClose( hview
);
1225 MsiCloseHandle( hview
);
1226 MsiCloseHandle( hdb
);
1227 MsiCloseHandle( hproduct
);
1230 r
= MsiInstallProductA( msifile
, "REMOVE=ALL" );
1231 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1234 DeleteFileA( msifile
);
1235 DeleteFileA( mspfile
);
1236 DeleteFileA( "msitest\\patch.txt" );
1237 RemoveDirectoryA( "msitest" );
1240 static void test_patch_registration( void )
1243 char buffer
[MAX_PATH
], patch_code
[39];
1245 if (!pMsiApplyPatchA
|| !pMsiGetPatchInfoExA
|| !pMsiEnumPatchesExA
)
1247 win_skip("required functions not available\n");
1250 if (is_process_limited())
1252 skip("process is limited\n");
1256 CreateDirectoryA( "msitest", NULL
);
1257 create_file( "msitest\\patch.txt", 1000 );
1259 create_database( msifile
, tables
, sizeof(tables
) / sizeof(struct msi_table
) );
1260 create_patch( mspfile
);
1262 MsiSetInternalUI( INSTALLUILEVEL_NONE
, NULL
);
1264 r
= MsiInstallProductA( msifile
, NULL
);
1265 if (r
!= ERROR_SUCCESS
)
1267 skip("Product installation failed with error code %d\n", r
);
1271 r
= MsiApplyPatchA( mspfile
, NULL
, INSTALLTYPE_DEFAULT
, NULL
);
1272 ok( r
== ERROR_SUCCESS
|| broken( r
== ERROR_PATCH_PACKAGE_INVALID
), /* version 2.0 */
1273 "expected ERROR_SUCCESS, got %u\n", r
);
1275 if (r
== ERROR_PATCH_PACKAGE_INVALID
)
1277 win_skip("Windows Installer < 3.0 detected\n");
1282 size
= sizeof(buffer
);
1283 r
= pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1284 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1285 NULL
, MSIINSTALLCONTEXT_USERUNMANAGED
,
1286 INSTALLPROPERTY_LOCALPACKAGEA
, buffer
, &size
);
1287 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1288 ok( buffer
[0], "buffer empty\n" );
1291 size
= sizeof(buffer
);
1292 r
= pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1293 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1294 NULL
, MSIINSTALLCONTEXT_MACHINE
,
1295 INSTALLPROPERTY_LOCALPACKAGEA
, buffer
, &size
);
1296 ok( r
== ERROR_UNKNOWN_PRODUCT
, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r
);
1299 size
= sizeof(buffer
);
1300 r
= pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1301 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1302 NULL
, MSIINSTALLCONTEXT_USERMANAGED
,
1303 INSTALLPROPERTY_LOCALPACKAGEA
, buffer
, &size
);
1304 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1305 ok( !buffer
[0], "got %s\n", buffer
);
1307 r
= pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1308 NULL
, MSIINSTALLCONTEXT_USERUNMANAGED
, MSIPATCHSTATE_APPLIED
,
1309 0, patch_code
, NULL
, NULL
, NULL
, NULL
);
1310 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1311 ok( !strcmp( patch_code
, "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}" ), "wrong patch code\n" );
1313 r
= pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1314 NULL
, MSIINSTALLCONTEXT_MACHINE
, MSIPATCHSTATE_APPLIED
,
1315 0, patch_code
, NULL
, NULL
, NULL
, NULL
);
1316 ok( r
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
1318 r
= pMsiEnumPatchesExA( "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1319 NULL
, MSIINSTALLCONTEXT_USERMANAGED
, MSIPATCHSTATE_APPLIED
,
1320 0, patch_code
, NULL
, NULL
, NULL
, NULL
);
1321 ok( r
== ERROR_NO_MORE_ITEMS
, "expected ERROR_NO_MORE_ITEMS, got %u\n", r
);
1324 r
= MsiInstallProductA( msifile
, "REMOVE=ALL" );
1325 ok( r
== ERROR_SUCCESS
, "expected ERROR_SUCCESS, got %u\n", r
);
1328 size
= sizeof(buffer
);
1329 r
= pMsiGetPatchInfoExA( "{0F96CDC0-4CDF-4304-B283-7B9264889EF7}",
1330 "{913B8D18-FBB6-4CAC-A239-C74C11E3FA74}",
1331 NULL
, MSIINSTALLCONTEXT_USERUNMANAGED
,
1332 INSTALLPROPERTY_LOCALPACKAGEA
, buffer
, &size
);
1333 ok( r
== ERROR_UNKNOWN_PRODUCT
, "expected ERROR_UNKNOWN_PRODUCT, got %u\n", r
);
1336 DeleteFileA( msifile
);
1337 DeleteFileA( mspfile
);
1338 DeleteFileA( "msitest\\patch.txt" );
1339 RemoveDirectoryA( "msitest" );
1345 char temp_path
[MAX_PATH
], prev_path
[MAX_PATH
];
1347 init_function_pointers();
1349 GetCurrentDirectoryA( MAX_PATH
, prev_path
);
1350 GetTempPathA( MAX_PATH
, temp_path
);
1351 SetCurrentDirectoryA( temp_path
);
1353 strcpy( CURR_DIR
, temp_path
);
1354 len
= strlen( CURR_DIR
);
1356 if (len
&& (CURR_DIR
[len
- 1] == '\\'))
1357 CURR_DIR
[len
- 1] = 0;
1359 get_program_files_dir( PROG_FILES_DIR
, COMMON_FILES_DIR
);
1361 test_simple_patch();
1362 test_MsiOpenDatabase();
1363 test_system_tables();
1364 test_patch_registration();
1366 SetCurrentDirectoryA( prev_path
);