ReactOS  0.4.14-dev-98-gb0d4763
automation.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007 Mike McCormack for CodeWeavers
3  * Copyright (C) 2007 Misha Koshelev
4  *
5  * A test program for Microsoft Installer OLE automation functionality.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #define COBJMACROS
23 
24 #include <stdio.h>
25 
26 #include <initguid.h>
27 #include <windows.h>
28 #include <msiquery.h>
29 #include <msidefs.h>
30 #include <msi.h>
31 #include <fci.h>
32 #include <oaidl.h>
33 
34 #include "wine/test.h"
35 
36 #ifdef __REACTOS__
37 #include "ole2.h"
38 #endif
39 
40 static BOOL is_wow64;
41 
42 static BOOL (WINAPI *pCheckTokenMembership)(HANDLE,PSID,PBOOL);
43 static BOOL (WINAPI *pOpenProcessToken)(HANDLE, DWORD, PHANDLE);
44 static LONG (WINAPI *pRegDeleteKeyExA)(HKEY, LPCSTR, REGSAM, DWORD);
45 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
46 
47 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
48 
49 static const char *msifile = "winetest-automation.msi";
50 static const WCHAR szMsifile[] = {'w','i','n','e','t','e','s','t','-','a','u','t','o','m','a','t','i','o','n','.','m','s','i',0};
51 static const WCHAR szMSITEST[] = { 'M','S','I','T','E','S','T',0 };
52 static const WCHAR szProductCode[] = { '{','8','3','7','4','5','0','f','a','-','a','3','9','b','-','4','b','c','8','-','b','3','2','1','-','0','8','b','3','9','3','f','7','8','4','b','3','}',0 };
53 static const WCHAR szUpgradeCode[] = { '{','C','E','0','6','7','E','8','D','-','2','E','1','A','-','4','3','6','7','-','B','7','3','4','-','4','E','B','2','B','D','A','D','6','5','6','5','}',0 };
54 static const WCHAR szProductInfoException[] = { 'P','r','o','d','u','c','t','I','n','f','o',',','P','r','o','d','u','c','t',',','A','t','t','r','i','b','u','t','e',0 };
55 static const WCHAR WINE_INSTALLPROPERTY_PACKAGENAMEW[] = {'P','a','c','k','a','g','e','N','a','m','e',0};
56 static const WCHAR WINE_INSTALLPROPERTY_PRODUCTNAMEW[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
57 static const WCHAR WINE_INSTALLPROPERTY_LOCALPACKAGEW[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0};
61 
62 /*
63  * OLE automation data
64  **/
65 static const WCHAR szProgId[] = { 'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r','.','I','n','s','t','a','l','l','e','r',0 };
67 
68 /* msi database data */
69 
70 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
71  "s72\tS38\ts72\ti2\tS255\tS72\n"
72  "Component\tComponent\n"
73  "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
74  "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
75  "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
76  "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
77  "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
78  "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
79  "component\t\tMSITESTDIR\t0\t1\tfile\n";
80 
81 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
82  "s72\tS72\tl255\n"
83  "Directory\tDirectory\n"
84  "CABOUTDIR\tMSITESTDIR\tcabout\n"
85  "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
86  "FIRSTDIR\tMSITESTDIR\tfirst\n"
87  "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
88  "NEWDIR\tCABOUTDIR\tnew\n"
89  "ProgramFilesFolder\tTARGETDIR\t.\n"
90  "TARGETDIR\t\tSourceDir\n";
91 
92 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
93  "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
94  "Feature\tFeature\n"
95  "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
96  "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
97  "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
98  "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
99  "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
100  "feature\t\t\t\t2\t1\tTARGETDIR\t0\n";
101 
102 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
103  "s38\ts72\n"
104  "FeatureComponents\tFeature_\tComponent_\n"
105  "Five\tFive\n"
106  "Four\tFour\n"
107  "One\tOne\n"
108  "Three\tThree\n"
109  "Two\tTwo\n"
110  "feature\tcomponent\n";
111 
112 static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
113  "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
114  "File\tFile\n"
115  "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n"
116  "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n"
117  "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
118  "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
119  "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
120  "file\tcomponent\tfilename\t100\t\t\t8192\t1\n";
121 
122 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
123  "s72\tS255\tI2\n"
124  "InstallExecuteSequence\tAction\n"
125  "AllocateRegistrySpace\tNOT Installed\t1550\n"
126  "CostFinalize\t\t1000\n"
127  "CostInitialize\t\t800\n"
128  "FileCost\t\t900\n"
129  "InstallFiles\t\t4000\n"
130  "RegisterProduct\t\t6100\n"
131  "PublishProduct\t\t6400\n"
132  "InstallFinalize\t\t6600\n"
133  "InstallInitialize\t\t1500\n"
134  "InstallValidate\t\t1400\n"
135  "LaunchConditions\t\t100\n"
136  "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000\n";
137 
138 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
139  "i2\ti4\tL64\tS255\tS32\tS72\n"
140  "Media\tDiskId\n"
141  "1\t5\t\t\tDISK1\t\n";
142 
143 static const CHAR property_dat[] = "Property\tValue\n"
144  "s72\tl0\n"
145  "Property\tProperty\n"
146  "DefaultUIFont\tDlgFont8\n"
147  "HASUIRUN\t0\n"
148  "INSTALLLEVEL\t3\n"
149  "InstallMode\tTypical\n"
150  "Manufacturer\tWine\n"
151  "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
152  "ProductCode\t{837450fa-a39b-4bc8-b321-08b393f784b3}\n"
153  "ProductID\tnone\n"
154  "ProductLanguage\t1033\n"
155  "ProductName\tMSITEST\n"
156  "ProductVersion\t1.1.1\n"
157  "PROMPTROLLBACKCOST\tP\n"
158  "Setup\tSetup\n"
159  "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}\n"
160  "MSIFASTINSTALL\t1\n";
161 
162 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
163  "s72\ti2\tl255\tL255\tL0\ts72\n"
164  "Registry\tRegistry\n"
165  "Apples\t1\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
166  "Oranges\t1\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
167  "regdata\t1\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
168  "OrderTest\t1\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent\n";
169 
170 typedef struct _msi_table
171 {
172  const CHAR *filename;
173  const CHAR *data;
174  int size;
175 } msi_table;
176 
177 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
178 
179 static const msi_table tables[] =
180 {
181  ADD_TABLE(component),
184  ADD_TABLE(feature_comp),
185  ADD_TABLE(file),
186  ADD_TABLE(install_exec_seq),
187  ADD_TABLE(media),
190 };
191 
192 typedef struct _msi_summary_info
193 {
198  const CHAR *szValue;
200 
201 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
202 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
203 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
204 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
205 
207 {
208  ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"),
209  ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49C2-AD20-28E1CE0DF5F2}"),
214 };
215 
216 static void init_functionpointers(void)
217 {
218  HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
219  HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
220 
221 #define GET_PROC(dll, func) \
222  p ## func = (void *)GetProcAddress(dll, #func); \
223  if(!p ## func) \
224  trace("GetProcAddress(%s) failed\n", #func);
225 
226  GET_PROC(hadvapi32, CheckTokenMembership);
227  GET_PROC(hadvapi32, OpenProcessToken);
228  GET_PROC(hadvapi32, RegDeleteKeyExA)
230 
231 #undef GET_PROC
232 }
233 
235 {
237  PSID Group = NULL;
238  BOOL IsInGroup;
239  HANDLE token;
240 
241  if (!pCheckTokenMembership || !pOpenProcessToken) return FALSE;
242 
244  DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &Group) ||
245  !pCheckTokenMembership(NULL, Group, &IsInGroup))
246  {
247  trace("Could not check if the current user is an administrator\n");
248  FreeSid(Group);
249  return FALSE;
250  }
251  FreeSid(Group);
252 
253  if (!IsInGroup)
254  {
255  /* Only administrators have enough privileges for these tests */
256  return TRUE;
257  }
258 
259  if (pOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
260  {
261  BOOL ret;
263  DWORD size;
264 
267  return (ret && type == TokenElevationTypeLimited);
268  }
269  return FALSE;
270 }
271 
273 {
274  if (pRegDeleteKeyExA)
275  return pRegDeleteKeyExA( key, subkey, access, 0 );
276  return RegDeleteKeyA( key, subkey );
277 }
278 
279 /*
280  * Database Helpers
281  */
282 
283 static void write_file(const CHAR *filename, const char *data, int data_size)
284 {
285  DWORD size;
286 
289  WriteFile(hf, data, data_size, &size, NULL);
290  CloseHandle(hf);
291 }
292 
293 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
294 {
295  MSIHANDLE summary;
296  UINT r;
297  int j;
298 
299  r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
300  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
301 
302  /* import summary information into the stream */
303  for (j = 0; j < num_info; j++)
304  {
305  const msi_summary_info *entry = &info[j];
306 
307  r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
308  entry->iValue, entry->pftValue, entry->szValue);
309  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
310  }
311 
312  /* write the summary changes back to the stream */
313  r = MsiSummaryInfoPersist(summary);
314  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
315 
316  MsiCloseHandle(summary);
317 }
318 
319 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
320  const msi_summary_info *info, int num_info)
321 {
322  MSIHANDLE db;
323  UINT r;
324  WCHAR *nameW;
325  int j, len;
326 
327  len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
328  if (!(nameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return;
329  MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, len );
330 
332  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
333 
334  /* import the tables into the database */
335  for (j = 0; j < num_tables; j++)
336  {
337  const msi_table *table = &tables[j];
338 
339  write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
340 
341  r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
342  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
343 
344  DeleteFileA(table->filename);
345  }
346 
347  write_msi_summary_info(db, info, num_info);
348 
349  r = MsiDatabaseCommit(db);
350  ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
351 
352  MsiCloseHandle(db);
353  HeapFree( GetProcessHeap(), 0, nameW );
354 }
355 
357 {
358  static const WCHAR slashW[] = {'\\',0};
359  DWORD len;
360 
361  /* Prepare package */
363  sizeof(tables) / sizeof(msi_table), summary_info,
364  sizeof(summary_info) / sizeof(msi_summary_info));
365 
367  CURR_DIR, -1, path, MAX_PATH);
368  ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
369  if (!len)
370  return FALSE;
371 
372  lstrcatW(path, slashW);
374  return TRUE;
375 }
376 
377 /*
378  * Installation helpers
379  */
380 
382 
384 {
385  HKEY hkey;
387 
388  if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
389  return FALSE;
390 
391  size = MAX_PATH;
392  if (RegQueryValueExA(hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size) &&
393  RegQueryValueExA(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
394  return FALSE;
395 
396  RegCloseKey(hkey);
397  return TRUE;
398 }
399 
400 static void create_file(const CHAR *name, DWORD size)
401 {
402  HANDLE file;
403  DWORD written, left;
404 
406  ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
407  WriteFile(file, name, strlen(name), &written, NULL);
408  WriteFile(file, "\n", strlen("\n"), &written, NULL);
409 
410  left = size - lstrlenA(name) - 1;
411 
414 
415  CloseHandle(file);
416 }
417 
418 static void create_test_files(void)
419 {
420  CreateDirectoryA("msitest", NULL);
421  create_file("msitest\\one.txt", 100);
422  CreateDirectoryA("msitest\\first", NULL);
423  create_file("msitest\\first\\two.txt", 100);
424  CreateDirectoryA("msitest\\second", NULL);
425  create_file("msitest\\second\\three.txt", 100);
426  CreateDirectoryA("msitest\\cabout",NULL);
427  create_file("msitest\\cabout\\four.txt", 100);
428  CreateDirectoryA("msitest\\cabout\\new",NULL);
429  create_file("msitest\\cabout\\new\\five.txt", 100);
430  create_file("msitest\\filename", 100);
431 }
432 
433 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
434 {
435  CHAR path[MAX_PATH];
436 
438  lstrcatA(path, "\\");
439  lstrcatA(path, rel_path);
440 
441  if (is_file)
442  return DeleteFileA(path);
443  else
444  return RemoveDirectoryA(path);
445 }
446 
447 static void delete_test_files(void)
448 {
450  DeleteFileA("msitest\\cabout\\new\\five.txt");
451  DeleteFileA("msitest\\cabout\\four.txt");
452  DeleteFileA("msitest\\second\\three.txt");
453  DeleteFileA("msitest\\first\\two.txt");
454  DeleteFileA("msitest\\one.txt");
455  DeleteFileA("msitest\\filename");
456  RemoveDirectoryA("msitest\\cabout\\new");
457  RemoveDirectoryA("msitest\\cabout");
458  RemoveDirectoryA("msitest\\second");
459  RemoveDirectoryA("msitest\\first");
460  RemoveDirectoryA("msitest");
461 }
462 
463 /*
464  * Automation helpers and tests
465  */
466 
467 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
469 
470 #define ok_w2(format, szString1, szString2) \
471 \
472  do { \
473  WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
474  WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
475  if (lstrcmpA(string1, string2) != 0) \
476  ok(0, format, string1, string2); \
477  } while(0);
478 
479 #define ok_w2n(format, szString1, szString2, len) \
480 \
481  if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \
482  { \
483  WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
484  WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
485  ok(0, format, string1, string2); \
486  }
487 
488 #define ok_aw(format, aString, wString) \
489 \
490  WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
491  if (lstrcmpA(string1, aString) != 0) \
492  ok(0, format, string1, aString); \
493 
494 #define ok_awplus(format, extra, aString, wString) \
495 \
496  WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
497  if (lstrcmpA(string1, aString) != 0) \
498  ok(0, format, extra, string1, aString); \
499 
500 /* exception checker */
501 static const WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
502 
503 #define ok_exception(hr, szDescription) \
504  if (hr == DISP_E_EXCEPTION) \
505  { \
506  /* Compare wtype, source, and destination */ \
507  ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
508 \
509  ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
510  if (excepinfo.bstrSource) \
511  ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
512 \
513  ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
514  if (excepinfo.bstrDescription) \
515  ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
516 \
517  SysFreeString(excepinfo.bstrSource); \
518  SysFreeString(excepinfo.bstrDescription); \
519  SysFreeString(excepinfo.bstrHelpFile); \
520  }
521 
522 static DISPID get_dispid( IDispatch *disp, const char *name )
523 {
524  LPOLESTR str;
525  UINT len;
526  DISPID id = -1;
527  HRESULT r;
528 
529  len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
530  str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
531  if (str)
532  {
533  MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
534  r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
535  HeapFree(GetProcessHeap(), 0, str);
536  if (r != S_OK)
537  return -1;
538  }
539 
540  return id;
541 }
542 
543 typedef struct {
545  const char *name;
547 } get_did_t;
548 
549 static const get_did_t get_did_data[] = {
550  { 1, "CreateRecord" },
551  { 2, "OpenPackage" },
552  { 3, "OpenProduct" },
553  { 4, "OpenDatabase" },
554  { 5, "SummaryInformation" },
555  { 6, "UILevel" },
556  { 7, "EnableLog" },
557  { 8, "InstallProduct" },
558  { 9, "Version" },
559  { 10, "LastErrorRecord" },
560  { 11, "RegistryValue" },
561  { 12, "Environment" },
562  { 13, "FileAttributes" },
563  { 15, "FileSize" },
564  { 16, "FileVersion" },
565  { 17, "ProductState" },
566  { 18, "ProductInfo" },
567  { 19, "ConfigureProduct", TRUE },
568  { 20, "ReinstallProduct", TRUE },
569  { 21, "CollectUserInfo", TRUE },
570  { 22, "ApplyPatch", TRUE },
571  { 23, "FeatureParent", TRUE },
572  { 24, "FeatureState", TRUE },
573  { 25, "UseFeature", TRUE },
574  { 26, "FeatureUsageCount", TRUE },
575  { 27, "FeatureUsageDate", TRUE },
576  { 28, "ConfigureFeature", TRUE },
577  { 29, "ReinstallFeature", TRUE },
578  { 30, "ProvideComponent", TRUE },
579  { 31, "ComponentPath", TRUE },
580  { 32, "ProvideQualifiedComponent", TRUE },
581  { 33, "QualifierDescription", TRUE },
582  { 34, "ComponentQualifiers", TRUE },
583  { 35, "Products" },
584  { 36, "Features", TRUE },
585  { 37, "Components", TRUE },
586  { 38, "ComponentClients", TRUE },
587  { 39, "Patches", TRUE },
588  { 40, "RelatedProducts" },
589  { 41, "PatchInfo", TRUE },
590  { 42, "PatchTransforms", TRUE },
591  { 43, "AddSource", TRUE },
592  { 44, "ClearSourceList", TRUE },
593  { 45, "ForceSourceListResolution", TRUE },
594  { 46, "ShortcutTarget", TRUE },
595  { 47, "FileHash", TRUE },
596  { 48, "FileSignatureInfo", TRUE },
597  { 0 }
598 };
599 
600 static void test_dispid(void)
601 {
602  const get_did_t *ptr = get_did_data;
603  DISPID dispid;
604 
605  while (ptr->name)
606  {
607  dispid = get_dispid(pInstaller, ptr->name);
608  todo_wine_if (ptr->todo)
609  ok(dispid == ptr->did, "%s: expected %d, got %d\n", ptr->name, ptr->did, dispid);
610  ptr++;
611  }
612 
613  dispid = get_dispid(pInstaller, "RemovePatches");
614  ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
615  dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
616  ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
617  dispid = get_dispid(pInstaller, "ProductsEx");
618  ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
619  dispid = get_dispid(pInstaller, "PatchesEx");
620  ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
621  dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
622  ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
623  dispid = get_dispid( pInstaller, "ProductElevated" );
624  ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
625  dispid = get_dispid( pInstaller, "ProvideAssembly" );
626  ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
627  dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
628  ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
629  dispid = get_dispid( pInstaller, "AdvertiseProduct" );
630  ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
631  dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
632  ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
633  dispid = get_dispid( pInstaller, "PatchFiles" );
634  ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
635 }
636 
637 /* Test basic IDispatch functions */
638 static void test_dispatch(void)
639 {
640  static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
641  static const WCHAR szOpenPackageException[] = {'O','p','e','n','P','a','c','k','a','g','e',',','P','a','c','k','a','g','e','P','a','t','h',',','O','p','t','i','o','n','s',0};
642  static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
643  HRESULT hr;
644  DISPID dispid;
645  OLECHAR *name;
646  VARIANT varresult;
647  VARIANTARG vararg[3];
649  DISPPARAMS dispparams = {NULL, NULL, 0, 0};
650 
651  /* Test getting ID of a function name that does not exist */
652  name = (WCHAR *)szMsifile;
653  hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
654  ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
655 
656  /* Test invoking this function */
657  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
658  ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
659 
660  /* Test getting ID of a function name that does exist */
661  name = szOpenPackage;
662  hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
663  ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
664 
665  /* Test invoking this function (without parameters passed) */
666  if (0) /* All of these crash MSI on Windows XP */
667  {
668  IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
669  IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
670  VariantInit(&varresult);
671  IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
672  }
673 
674  /* Try with NULL params */
675  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
676  ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
677 
678  /* Try one empty parameter */
679  dispparams.rgvarg = vararg;
680  dispparams.cArgs = 1;
681  VariantInit(&vararg[0]);
682  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
683  ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
684 
685  /* Try two empty parameters */
686  dispparams.cArgs = 2;
687  VariantInit(&vararg[0]);
688  VariantInit(&vararg[1]);
689  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
690  ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
691 
692  /* Try one parameter, the required BSTR. Second parameter is optional.
693  * NOTE: The specified package does not exist, which is why the call fails.
694  */
695  dispparams.cArgs = 1;
696  VariantInit(&vararg[0]);
697  V_VT(&vararg[0]) = VT_BSTR;
698  V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
699  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
700  ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
701  ok_exception(hr, szOpenPackageException);
702  VariantClear(&vararg[0]);
703 
704  /* Provide the required BSTR and an empty second parameter.
705  * NOTE: The specified package does not exist, which is why the call fails.
706  */
707  dispparams.cArgs = 2;
708  VariantInit(&vararg[1]);
709  V_VT(&vararg[1]) = VT_BSTR;
710  V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
711  VariantInit(&vararg[0]);
712  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
713  ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
714  ok_exception(hr, szOpenPackageException);
715  VariantClear(&vararg[1]);
716 
717  /* Provide the required BSTR and two empty parameters.
718  * NOTE: The specified package does not exist, which is why the call fails.
719  */
720  dispparams.cArgs = 3;
721  VariantInit(&vararg[2]);
722  V_VT(&vararg[2]) = VT_BSTR;
723  V_BSTR(&vararg[2]) = SysAllocString(szMsifile);
724  VariantInit(&vararg[1]);
725  VariantInit(&vararg[0]);
726  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
727  ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
728  ok_exception(hr, szOpenPackageException);
729  VariantClear(&vararg[2]);
730 
731  /* Provide the required BSTR and a second parameter with the wrong type. */
732  dispparams.cArgs = 2;
733  VariantInit(&vararg[1]);
734  V_VT(&vararg[1]) = VT_BSTR;
735  V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
736  VariantInit(&vararg[0]);
737  V_VT(&vararg[0]) = VT_BSTR;
738  V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
739  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
740  ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
741  VariantClear(&vararg[0]);
742  VariantClear(&vararg[1]);
743 
744  /* Create a proper installer package. */
746 
747  /* Try one parameter, the required BSTR. Second parameter is optional.
748  * Proper installer package exists. Path to the package is relative.
749  */
750  dispparams.cArgs = 1;
751  VariantInit(&vararg[0]);
752  V_VT(&vararg[0]) = VT_BSTR;
753  V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
754  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
755  todo_wine ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
756  ok_exception(hr, szOpenPackageException);
757  VariantClear(&vararg[0]);
758  if (hr != DISP_E_EXCEPTION)
759  VariantClear(&varresult);
760 
761  /* Try one parameter, the required BSTR. Second parameter is optional.
762  * Proper installer package exists. Path to the package is absolute.
763  */
764  dispparams.cArgs = 1;
765  VariantInit(&vararg[0]);
766  V_VT(&vararg[0]) = VT_BSTR;
767  V_BSTR(&vararg[0]) = SysAllocString(path);
768  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
769  if (hr == DISP_E_EXCEPTION)
770  {
771  skip("OpenPackage failed, insufficient rights?\n");
772  DeleteFileW(path);
773  return;
774  }
775  ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
776  VariantClear(&vararg[0]);
777  VariantClear(&varresult);
778 
779  /* Provide the required BSTR and an empty second parameter. Proper
780  * installation package exists.
781  */
782  dispparams.cArgs = 2;
783  VariantInit(&vararg[1]);
784  V_VT(&vararg[1]) = VT_BSTR;
785  V_BSTR(&vararg[1]) = SysAllocString(path);
786  VariantInit(&vararg[0]);
787  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
788  ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
789  VariantClear(&vararg[1]);
790  VariantClear(&varresult);
791 
792  /* Provide the required BSTR and two empty parameters. Proper
793  * installation package exists.
794  */
795  dispparams.cArgs = 3;
796  VariantInit(&vararg[2]);
797  V_VT(&vararg[2]) = VT_BSTR;
798  V_BSTR(&vararg[2]) = SysAllocString(path);
799  VariantInit(&vararg[1]);
800  VariantInit(&vararg[0]);
801  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
802  ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
803  VariantClear(&vararg[2]);
804  VariantClear(&varresult);
805 
806  /* Provide the required BSTR and a second parameter with the wrong type. */
807  dispparams.cArgs = 2;
808  VariantInit(&vararg[1]);
809  V_VT(&vararg[1]) = VT_BSTR;
810  V_BSTR(&vararg[1]) = SysAllocString(path);
811  VariantInit(&vararg[0]);
812  V_VT(&vararg[0]) = VT_BSTR;
813  V_BSTR(&vararg[0]) = SysAllocString(path);
814  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
815  ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
816  VariantClear(&vararg[0]);
817  VariantClear(&vararg[1]);
818 
819  /* Provide the required BSTR and a second parameter that can be coerced to
820  * VT_I4.
821  */
822  dispparams.cArgs = 2;
823  VariantInit(&vararg[1]);
824  V_VT(&vararg[1]) = VT_BSTR;
825  V_BSTR(&vararg[1]) = SysAllocString(path);
826  VariantInit(&vararg[0]);
827  V_VT(&vararg[0]) = VT_I2;
828  V_BSTR(&vararg[0]) = 0;
829  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
830  ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
831  VariantClear(&vararg[1]);
832  VariantClear(&varresult);
833 
834  DeleteFileW(path);
835 
836  /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
837  VariantInit(&vararg[0]);
838  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
839  ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
840 
841  VariantInit(&vararg[0]);
842  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
843  ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
844 
845  /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
846  name = szProductState;
847  hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
848  ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
849 
850  dispparams.rgvarg = NULL;
851  dispparams.cArgs = 0;
852  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
853  ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
854 
855  dispparams.rgvarg = NULL;
856  dispparams.cArgs = 0;
857  hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
858  ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
859 }
860 
861 /* invocation helper function */
862 static int _invoke_todo_vtResult = 0;
863 
864 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
865 {
866  OLECHAR *name = NULL;
867  DISPID dispid;
868  HRESULT hr;
869  UINT i;
870  UINT len;
871 
872  memset(pVarResult, 0, sizeof(VARIANT));
873  VariantInit(pVarResult);
874 
875  len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
876  name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
877  if (!name) return E_FAIL;
879  hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
881  ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
882  if (hr != S_OK) return hr;
883 
884  memset(&excepinfo, 0, sizeof(excepinfo));
885  hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
886 
887  if (hr == S_OK)
888  {
890  ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
891  if (vtResult != VT_EMPTY)
892  {
893  hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
894  ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
895  }
896  }
897 
898  for (i=0; i<pDispParams->cArgs; i++)
899  VariantClear(&pDispParams->rgvarg[i]);
900 
901  return hr;
902 }
903 
904 /* Object_Property helper functions */
905 
907 {
908  VARIANT varresult;
909  VARIANTARG vararg[1];
910  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
911  HRESULT hr;
912 
913  VariantInit(&vararg[0]);
914  V_VT(&vararg[0]) = VT_I4;
915  V_I4(&vararg[0]) = count;
916 
917  hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
918  *pRecord = V_DISPATCH(&varresult);
919  return hr;
920 }
921 
922 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
923 {
924  VARIANTARG vararg[3];
925  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
926 
927  VariantInit(&vararg[2]);
928  V_VT(&vararg[2]) = VT_I4;
929  V_I4(&vararg[2]) = (INT_PTR)hkey;
930  VariantInit(&vararg[1]);
931  V_VT(&vararg[1]) = VT_BSTR;
932  V_BSTR(&vararg[1]) = SysAllocString(szKey);
933  VariantInit(&vararg[0]);
934  VariantCopy(&vararg[0], &vValue);
935  VariantClear(&vValue);
936 
937  return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
938 }
939 
940 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
941 {
942  VARIANT varresult;
943  VARIANTARG vararg;
944  HRESULT hr;
945 
946  VariantInit(&vararg);
947  V_VT(&vararg) = VT_EMPTY;
948  hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
949  *pBool = V_BOOL(&varresult);
950  VariantClear(&varresult);
951  return hr;
952 }
953 
954 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
955 {
956  VARIANT varresult;
957  VARIANTARG vararg;
958  HRESULT hr;
959 
960  VariantInit(&vararg);
961  V_VT(&vararg) = VT_BSTR;
962  V_BSTR(&vararg) = SysAllocString(szValue);
963 
964  hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
965  if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
966  VariantClear(&varresult);
967  return hr;
968 }
969 
970 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
971 {
972  VARIANT varresult;
973  VARIANTARG vararg;
974  HRESULT hr;
975 
976  VariantInit(&vararg);
977  V_VT(&vararg) = VT_I4;
978  V_I4(&vararg) = iValue;
979 
980  hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
981  if (SUCCEEDED(hr) && vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
982  VariantClear(&varresult);
983  return hr;
984 }
985 
986 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
987 {
988  VARIANT varresult;
989  VARIANTARG vararg[2];
990  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
991  HRESULT hr;
992 
993  VariantInit(&vararg[1]);
994  V_VT(&vararg[1]) = VT_BSTR;
995  V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
996  VariantInit(&vararg[0]);
997  V_VT(&vararg[0]) = VT_I4;
998  V_I4(&vararg[0]) = options;
999 
1000  hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1001  *pSession = V_DISPATCH(&varresult);
1002  return hr;
1003 }
1004 
1005 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
1006 {
1007  VARIANT varresult;
1008  VARIANTARG vararg[2];
1009  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1010  HRESULT hr;
1011 
1012  VariantInit(&vararg[1]);
1013  V_VT(&vararg[1]) = VT_BSTR;
1014  V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
1015  VariantInit(&vararg[0]);
1016  V_VT(&vararg[0]) = VT_I4;
1017  V_I4(&vararg[0]) = openmode;
1018 
1019  hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1020  *pDatabase = V_DISPATCH(&varresult);
1021  return hr;
1022 }
1023 
1024 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
1025 {
1026  VARIANT varresult;
1027  VARIANTARG vararg[2];
1028  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1029 
1030  VariantInit(&vararg[1]);
1031  V_VT(&vararg[1]) = VT_BSTR;
1032  V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
1033  VariantInit(&vararg[0]);
1034  V_VT(&vararg[0]) = VT_BSTR;
1035  V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
1036 
1037  return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1038 }
1039 
1040 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
1041 {
1042  VARIANT varresult;
1043  VARIANTARG vararg[1];
1044  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1045  HRESULT hr;
1046 
1047  VariantInit(&vararg[0]);
1048  V_VT(&vararg[0]) = VT_BSTR;
1049  V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1050 
1051  hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1052  *pInstallState = V_I4(&varresult);
1053  VariantClear(&varresult);
1054  return hr;
1055 }
1056 
1058 {
1059  VARIANT varresult;
1060  VARIANTARG vararg[2];
1061  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1062  HRESULT hr;
1063 
1064  VariantInit(&vararg[1]);
1065  V_VT(&vararg[1]) = VT_BSTR;
1066  V_BSTR(&vararg[1]) = SysAllocString(szProduct);
1067  VariantInit(&vararg[0]);
1068  V_VT(&vararg[0]) = VT_BSTR;
1069  V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
1070 
1071  hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1072  if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1073  VariantClear(&varresult);
1074  return hr;
1075 }
1076 
1077 static HRESULT Installer_Products(IDispatch **pStringList)
1078 {
1079  VARIANT varresult;
1080  DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1081  HRESULT hr;
1082 
1083  hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1084  *pStringList = V_DISPATCH(&varresult);
1085  return hr;
1086 }
1087 
1088 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
1089 {
1090  VARIANT varresult;
1091  VARIANTARG vararg[1];
1092  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1093  HRESULT hr;
1094 
1095  VariantInit(&vararg[0]);
1096  V_VT(&vararg[0]) = VT_BSTR;
1097  V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1098 
1099  hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1100  *pStringList = V_DISPATCH(&varresult);
1101  return hr;
1102 }
1103 
1105 {
1106  VARIANT varresult;
1107  DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1108  HRESULT hr;
1109 
1110  hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1111  if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
1112  VariantClear(&varresult);
1113  return hr;
1114 }
1115 
1117 {
1118  VARIANT varresult;
1119  VARIANTARG vararg;
1120  DISPID dispid = DISPID_PROPERTYPUT;
1121  DISPPARAMS dispparams = {&vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1122 
1123  VariantInit(&vararg);
1124  V_VT(&vararg) = VT_I4;
1125  V_I4(&vararg) = level;
1126 
1127  return invoke(pInstaller, "UILevel", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1128 }
1129 
1130 static HRESULT Installer_SummaryInformation(BSTR PackagePath, int UpdateCount, IDispatch **pSumInfo)
1131 {
1132  VARIANT varresult;
1133  VARIANTARG vararg[2];
1134  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1135  HRESULT hr;
1136 
1137  VariantInit(&vararg[1]);
1138  V_VT(&vararg[1]) = VT_BSTR;
1139  V_BSTR(&vararg[1]) = SysAllocString(PackagePath);
1140  VariantInit(&vararg[0]);
1141  V_VT(&vararg[0]) = VT_I4;
1142  V_I4(&vararg[0]) = UpdateCount;
1143 
1144  hr = invoke(pInstaller, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1145  *pSumInfo = V_DISPATCH(&varresult);
1146  return hr;
1147 }
1148 
1149 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
1150 {
1151  VARIANT varresult;
1152  DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1153  HRESULT hr;
1154 
1155  hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1156  *pInst = V_DISPATCH(&varresult);
1157  return hr;
1158 }
1159 
1161 {
1162  VARIANT varresult;
1163  VARIANTARG vararg[1];
1164  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1165  HRESULT hr;
1166 
1167  VariantInit(&vararg[0]);
1168  V_VT(&vararg[0]) = VT_BSTR;
1169  V_BSTR(&vararg[0]) = SysAllocString(szName);
1170 
1171  hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1172  if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
1173  VariantClear(&varresult);
1174  return hr;
1175 }
1176 
1178 {
1179  VARIANT varresult;
1180  VARIANTARG vararg[2];
1181  DISPID dispid = DISPID_PROPERTYPUT;
1182  DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1183 
1184  VariantInit(&vararg[1]);
1185  V_VT(&vararg[1]) = VT_BSTR;
1186  V_BSTR(&vararg[1]) = SysAllocString(szName);
1187  VariantInit(&vararg[0]);
1188  V_VT(&vararg[0]) = VT_BSTR;
1189  V_BSTR(&vararg[0]) = SysAllocString(szValue);
1190 
1191  return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1192 }
1193 
1194 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
1195 {
1196  VARIANT varresult;
1197  DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1198  HRESULT hr;
1199 
1200  hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1201  *pLangId = V_I4(&varresult);
1202  VariantClear(&varresult);
1203  return hr;
1204 }
1205 
1206 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, VARIANT_BOOL *mode)
1207 {
1208  VARIANT varresult;
1209  VARIANTARG vararg[1];
1210  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1211  HRESULT hr;
1212 
1213  VariantInit(&vararg[0]);
1214  V_VT(&vararg[0]) = VT_I4;
1215  V_I4(&vararg[0]) = iFlag;
1216 
1217  hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
1218  *mode = V_BOOL(&varresult);
1219  VariantClear(&varresult);
1220  return hr;
1221 }
1222 
1223 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, VARIANT_BOOL mode)
1224 {
1225  VARIANT varresult;
1226  VARIANTARG vararg[2];
1227  DISPID dispid = DISPID_PROPERTYPUT;
1228  DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1229 
1230  VariantInit(&vararg[1]);
1231  V_VT(&vararg[1]) = VT_I4;
1232  V_I4(&vararg[1]) = iFlag;
1233  VariantInit(&vararg[0]);
1234  V_VT(&vararg[0]) = VT_BOOL;
1235  V_BOOL(&vararg[0]) = mode;
1236 
1237  return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1238 }
1239 
1240 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1241 {
1242  VARIANT varresult;
1243  DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1244  HRESULT hr;
1245 
1246  hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1247  *pDatabase = V_DISPATCH(&varresult);
1248  return hr;
1249 }
1250 
1251 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1252 {
1253  VARIANT varresult;
1254  VARIANTARG vararg[1];
1255  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1256  HRESULT hr;
1257 
1258  VariantInit(&vararg[0]);
1259  V_VT(&vararg[0]) = VT_BSTR;
1260  V_BSTR(&vararg[0]) = SysAllocString(szAction);
1261 
1262  hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1263  *iReturn = V_I4(&varresult);
1264  VariantClear(&varresult);
1265  return hr;
1266 }
1267 
1268 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1269 {
1270  VARIANT varresult;
1271  VARIANTARG vararg[1];
1272  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1273  HRESULT hr;
1274 
1275  VariantInit(&vararg[0]);
1276  V_VT(&vararg[0]) = VT_BSTR;
1277  V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1278 
1279  hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1280  *iReturn = V_I4(&varresult);
1281  VariantClear(&varresult);
1282  return hr;
1283 }
1284 
1285 static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret)
1286 {
1287  VARIANT varresult;
1288  VARIANTARG vararg[2];
1289  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1290  HRESULT hr;
1291 
1292  VariantInit(&varresult);
1293  V_VT(vararg) = VT_DISPATCH;
1294  V_DISPATCH(vararg) = record;
1295  V_VT(vararg+1) = VT_I4;
1296  V_I4(vararg+1) = kind;
1297 
1298  hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1299 
1300  ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1301  *ret = V_I4(&varresult);
1302 
1303  return hr;
1304 }
1305 
1306 static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel)
1307 {
1308  VARIANT varresult;
1309  VARIANTARG vararg[1];
1310  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1311 
1312  VariantInit(&vararg[0]);
1313  V_VT(&vararg[0]) = VT_I4;
1314  V_I4(&vararg[0]) = iInstallLevel;
1315 
1316  return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1317 }
1318 
1320 {
1321  VARIANT varresult;
1322  VARIANTARG vararg[1];
1323  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1324  HRESULT hr;
1325 
1326  VariantInit(&vararg[0]);
1327  V_VT(&vararg[0]) = VT_BSTR;
1328  V_BSTR(&vararg[0]) = SysAllocString(szName);
1329 
1330  hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1331  *pState = V_I4(&varresult);
1332  VariantClear(&varresult);
1333  return hr;
1334 }
1335 
1337 {
1338  VARIANT varresult;
1339  VARIANTARG vararg[1];
1340  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1341  HRESULT hr;
1342 
1343  VariantInit(&vararg[0]);
1344  V_VT(&vararg[0]) = VT_BSTR;
1345  V_BSTR(&vararg[0]) = SysAllocString(szName);
1346 
1347  hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1348  *pState = V_I4(&varresult);
1349  VariantClear(&varresult);
1350  return hr;
1351 }
1352 
1354 {
1355  VARIANT varresult;
1356  VARIANTARG vararg[2];
1357  DISPID dispid = DISPID_PROPERTYPUT;
1358  DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1359 
1360  VariantInit(&vararg[1]);
1361  V_VT(&vararg[1]) = VT_BSTR;
1362  V_BSTR(&vararg[1]) = SysAllocString(szName);
1363  VariantInit(&vararg[0]);
1364  V_VT(&vararg[0]) = VT_I4;
1365  V_I4(&vararg[0]) = iState;
1366 
1367  return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1368 }
1369 
1370 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1371 {
1372  VARIANT varresult;
1373  VARIANTARG vararg[1];
1374  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1375  HRESULT hr;
1376 
1377  VariantInit(&vararg[0]);
1378  V_VT(&vararg[0]) = VT_BSTR;
1379  V_BSTR(&vararg[0]) = SysAllocString(szSql);
1380 
1381  hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1382  *pView = V_DISPATCH(&varresult);
1383  return hr;
1384 }
1385 
1386 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1387 {
1388  VARIANT varresult;
1389  VARIANTARG vararg[1];
1390  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1391  HRESULT hr;
1392 
1393  VariantInit(&vararg[0]);
1394  V_VT(&vararg[0]) = VT_I4;
1395  V_I4(&vararg[0]) = iUpdateCount;
1396 
1397  hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1398  *pSummaryInfo = V_DISPATCH(&varresult);
1399  return hr;
1400 }
1401 
1402 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1403 {
1404  VARIANT varresult;
1405  VARIANTARG vararg[1];
1406  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1407 
1408  VariantInit(&vararg[0]);
1409  V_VT(&vararg[0]) = VT_DISPATCH;
1410  V_DISPATCH(&vararg[0]) = pRecord;
1411 
1412  return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1413 }
1414 
1415 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1416 {
1417  VARIANT varresult;
1418  DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1419  HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1420  *ppRecord = V_DISPATCH(&varresult);
1421  return hr;
1422 }
1423 
1424 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1425 {
1426  VARIANT varresult;
1427  VARIANTARG vararg[2];
1428  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1429 
1430  VariantInit(&vararg[1]);
1431  V_VT(&vararg[1]) = VT_I4;
1432  V_I4(&vararg[1]) = iMode;
1433  VariantInit(&vararg[0]);
1434  V_VT(&vararg[0]) = VT_DISPATCH;
1435  V_DISPATCH(&vararg[0]) = pRecord;
1436  if (pRecord)
1437  IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1438 
1439  return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1440 }
1441 
1443 {
1444  VARIANT varresult;
1445  DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1446  return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1447 }
1448 
1449 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1450 {
1451  VARIANT varresult;
1452  DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1453  HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1454  *pFieldCount = V_I4(&varresult);
1455  VariantClear(&varresult);
1456  return hr;
1457 }
1458 
1459 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1460 {
1461  VARIANT varresult;
1462  VARIANTARG vararg[1];
1463  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1464  HRESULT hr;
1465 
1466  VariantInit(&vararg[0]);
1467  V_VT(&vararg[0]) = VT_I4;
1468  V_I4(&vararg[0]) = iField;
1469 
1470  hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1471  if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1472  VariantClear(&varresult);
1473  return hr;
1474 }
1475 
1476 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1477 {
1478  VARIANT varresult;
1479  VARIANTARG vararg[2];
1480  DISPID dispid = DISPID_PROPERTYPUT;
1481  DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1482 
1483  VariantInit(&vararg[1]);
1484  V_VT(&vararg[1]) = VT_I4;
1485  V_I4(&vararg[1]) = iField;
1486  VariantInit(&vararg[0]);
1487  V_VT(&vararg[0]) = VT_BSTR;
1488  V_BSTR(&vararg[0]) = SysAllocString(szString);
1489 
1490  return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1491 }
1492 
1493 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1494 {
1495  VARIANT varresult;
1496  VARIANTARG vararg[1];
1497  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1498  HRESULT hr;
1499 
1500  VariantInit(&vararg[0]);
1501  V_VT(&vararg[0]) = VT_I4;
1502  V_I4(&vararg[0]) = iField;
1503 
1504  hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1505  *pValue = V_I4(&varresult);
1506  VariantClear(&varresult);
1507  return hr;
1508 }
1509 
1510 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1511 {
1512  VARIANT varresult;
1513  VARIANTARG vararg[2];
1514  DISPID dispid = DISPID_PROPERTYPUT;
1515  DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1516 
1517  VariantInit(&vararg[1]);
1518  V_VT(&vararg[1]) = VT_I4;
1519  V_I4(&vararg[1]) = iField;
1520  VariantInit(&vararg[0]);
1521  V_VT(&vararg[0]) = VT_I4;
1522  V_I4(&vararg[0]) = iValue;
1523 
1524  return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1525 }
1526 
1527 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1528 {
1529  VARIANT varresult;
1530  DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1531  HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1532  *ppEnumVARIANT = V_UNKNOWN(&varresult);
1533  return hr;
1534 }
1535 
1536 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1537 {
1538  VARIANT varresult;
1539  VARIANTARG vararg[1];
1540  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1541  HRESULT hr;
1542 
1543  VariantInit(&vararg[0]);
1544  V_VT(&vararg[0]) = VT_I4;
1545  V_I4(&vararg[0]) = iIndex;
1546 
1547  hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1548  if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1549  VariantClear(&varresult);
1550  return hr;
1551 }
1552 
1553 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1554 {
1555  VARIANT varresult;
1556  DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1557  HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1558  *pCount = V_I4(&varresult);
1559  VariantClear(&varresult);
1560  return hr;
1561 }
1562 
1563 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1564 {
1565  VARIANTARG vararg[1];
1566  DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1567 
1568  VariantInit(&vararg[0]);
1569  V_VT(&vararg[0]) = VT_I4;
1570  V_I4(&vararg[0]) = pid;
1571  return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1572 }
1573 
1574 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1575 {
1576  VARIANT varresult;
1577  VARIANTARG vararg[2];
1578  DISPID dispid = DISPID_PROPERTYPUT;
1579  DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1580 
1581  VariantInit(&vararg[1]);
1582  V_VT(&vararg[1]) = VT_I4;
1583  V_I4(&vararg[1]) = pid;
1584  VariantInit(&vararg[0]);
1585  VariantCopyInd(vararg, pVariant);
1586 
1587  return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1588 }
1589 
1590 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1591 {
1592  VARIANT varresult;
1593  DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1594  HRESULT hr;
1595 
1596  hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1597  *pCount = V_I4(&varresult);
1598  VariantClear(&varresult);
1599  return hr;
1600 }
1601 
1602 /* Test the various objects */
1603 
1604 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1605 
1606 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1607 {
1608  static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1609  static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1610  VARIANT varresult, var;
1611  SYSTEMTIME st;
1612  HRESULT hr;
1613  int j;
1614 
1615  /* SummaryInfo::PropertyCount */
1616  hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1617  ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1618  ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1619 
1620  /* SummaryInfo::Property, get for properties we have set */
1621  for (j = 0; j < num_info; j++)
1622  {
1623  const msi_summary_info *entry = &info[j];
1624 
1625  int vt = entry->datatype;
1626  if (vt == VT_LPSTR) vt = VT_BSTR;
1627  else if (vt == VT_FILETIME) vt = VT_DATE;
1628  else if (vt == VT_I2) vt = VT_I4;
1629 
1630  hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1631  ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1632  if (V_VT(&varresult) != vt)
1633  skip("Skipping property tests due to type mismatch\n");
1634  else if (vt == VT_I4)
1635  ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1636  entry->property, entry->iValue, V_I4(&varresult));
1637  else if (vt == VT_DATE)
1638  {
1639  FILETIME ft;
1640  DATE d;
1641 
1642  FileTimeToLocalFileTime(entry->pftValue, &ft);
1643  FileTimeToSystemTime(&ft, &st);
1644  SystemTimeToVariantTime(&st, &d);
1645  ok(d == V_DATE(&varresult), "SummaryInfo_Property (pid %d) DATE result expected to be %lf, but was %lf\n", entry->property, d, V_DATE(&varresult));
1646  }
1647  else if (vt == VT_BSTR)
1648  {
1649  ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1650  }
1651  else
1652  skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1653 
1654  VariantClear(&varresult);
1655  }
1656 
1657  /* SummaryInfo::Property, get; invalid arguments */
1658 
1659  /* Invalid pids */
1660  hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1661  ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1662  ok_exception(hr, szPropertyException);
1663 
1664  hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1665  ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1666  ok_exception(hr, szPropertyException);
1667 
1668  /* Unsupported pids */
1669  hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1670  ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1671 
1672  hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1673  ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1674 
1675  /* Pids we have not set, one for each type */
1676  hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1677  ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1678 
1679  hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1680  ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1681 
1682  hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1683  ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1684 
1685  hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1686  ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1687 
1688  if (!readonly)
1689  {
1690  /* SummaryInfo::Property, put; one for each type */
1691 
1692  /* VT_I2 */
1693  VariantInit(&var);
1694  V_VT(&var) = VT_I2;
1695  V_I2(&var) = 1;
1696  hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1697  ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1698 
1699  hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1700  ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1701  ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1702  VariantClear(&varresult);
1703  VariantClear(&var);
1704 
1705  /* VT_BSTR */
1706  V_VT(&var) = VT_BSTR;
1707  V_BSTR(&var) = SysAllocString(szTitle);
1708  hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1709  ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1710 
1711  hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1712  ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1713  ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1714  VariantClear(&varresult);
1715  VariantClear(&var);
1716 
1717  /* VT_DATE */
1718  V_VT(&var) = VT_DATE;
1720  SystemTimeToVariantTime(&st, &V_DATE(&var));
1721  hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1722  ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1723 
1724  hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1725  ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1726  ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1727  VariantClear(&varresult);
1728  VariantClear(&var);
1729 
1730  /* VT_I4 */
1731  V_VT(&var) = VT_I4;
1732  V_I4(&var) = 1000;
1733  hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1734  ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1735 
1736  hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1737  ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1738  ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1739  VariantClear(&varresult);
1740  VariantClear(&var);
1741 
1742  /* SummaryInfo::PropertyCount */
1743  hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1744  ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1745  ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1746  }
1747 }
1748 
1749 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1750 {
1751  static const WCHAR szSql[] = { 'S','E','L','E','C','T',' ','`','F','e','a','t','u','r','e','`',' ','F','R','O','M',' ','`','F','e','a','t','u','r','e','`',' ','W','H','E','R','E',' ','`','F','e','a','t','u','r','e','_','P','a','r','e','n','t','`','=','\'','O','n','e','\'',0 };
1752  static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1753  static const WCHAR szTwo[] = { 'T','w','o',0 };
1754  static const WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1755  static const WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1756  IDispatch *pView = NULL, *pSummaryInfo = NULL;
1757  HRESULT hr;
1758 
1759  hr = Database_OpenView(pDatabase, szSql, &pView);
1760  ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1761  if (hr == S_OK)
1762  {
1763  IDispatch *pRecord = NULL;
1764  WCHAR szString[MAX_PATH];
1765 
1766  /* View::Execute */
1767  hr = View_Execute(pView, NULL);
1768  ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1769 
1770  /* View::Fetch */
1771  hr = View_Fetch(pView, &pRecord);
1772  ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1773  ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1774  if (pRecord)
1775  {
1776  /* Record::StringDataGet */
1777  memset(szString, 0, sizeof(szString));
1778  hr = Record_StringDataGet(pRecord, 1, szString);
1779  ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1780  ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1781 
1782  /* Record::StringDataPut with correct index */
1783  hr = Record_StringDataPut(pRecord, 1, szTwo);
1784  ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1785 
1786  /* Record::StringDataGet */
1787  memset(szString, 0, sizeof(szString));
1788  hr = Record_StringDataGet(pRecord, 1, szString);
1789  ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1790  ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1791 
1792  /* Record::StringDataPut with incorrect index */
1793  hr = Record_StringDataPut(pRecord, -1, szString);
1794  ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1795  ok_exception(hr, szStringDataField);
1796 
1797  /* View::Modify with incorrect parameters */
1798  hr = View_Modify(pView, -5, NULL);
1799  ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1800  ok_exception(hr, szModifyModeRecord);
1801 
1802  hr = View_Modify(pView, -5, pRecord);
1803  ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1804  ok_exception(hr, szModifyModeRecord);
1805 
1806  hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1807  ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1808  ok_exception(hr, szModifyModeRecord);
1809 
1810  hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1811  ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1812 
1813  /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1814  memset(szString, 0, sizeof(szString));
1815  hr = Record_StringDataGet(pRecord, 1, szString);
1816  ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1817  todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1818 
1819  IDispatch_Release(pRecord);
1820  }
1821 
1822  /* View::Fetch */
1823  hr = View_Fetch(pView, &pRecord);
1824  ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1825  ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1826  if (pRecord)
1827  {
1828  /* Record::StringDataGet */
1829  memset(szString, 0, sizeof(szString));
1830  hr = Record_StringDataGet(pRecord, 1, szString);
1831  ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1832  ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1833 
1834  IDispatch_Release(pRecord);
1835  }
1836 
1837  /* View::Fetch */
1838  hr = View_Fetch(pView, &pRecord);
1839  ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1840  ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1841  if (pRecord)
1842  IDispatch_Release(pRecord);
1843 
1844  /* View::Close */
1845  hr = View_Close(pView);
1846  ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1847 
1848  IDispatch_Release(pView);
1849  }
1850 
1851  /* Database::SummaryInformation */
1853  ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1854  ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1855  if (pSummaryInfo)
1856  {
1857  test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1858  IDispatch_Release(pSummaryInfo);
1859  }
1860 }
1861 
1862 static void test_Session(IDispatch *pSession)
1863 {
1864  static const WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1865  static const WCHAR szOne[] = { 'O','n','e',0 };
1866  static const WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1867  static const WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1868  static const WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1869  static const WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1870  static const WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1871  static const WCHAR szEmpty[] = { 0 };
1872  static const WCHAR szEquals[] = { '=',0 };
1873  static const WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1874  static const WCHAR szModeFlag[] = { 'M','o','d','e',',','F','l','a','g',0 };
1876  CHAR string[MAX_PATH];
1877  UINT len;
1879  int myint;
1880  IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1881  ULONG refs_before, refs_after;
1882  HRESULT hr;
1883 
1884  /* Session::Installer */
1885  hr = Session_Installer(pSession, &pInst);
1886  ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1887  ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1888  ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1889  refs_before = IDispatch_AddRef(pInst);
1890 
1891  hr = Session_Installer(pSession, &pInst);
1892  ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1893  ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1894  ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1895  refs_after = IDispatch_Release(pInst);
1896  ok(refs_before == refs_after, "got %u and %u\n", refs_before, refs_after);
1897 
1898  /* Session::Property, get */
1899  memset(stringw, 0, sizeof(stringw));
1900  hr = Session_PropertyGet(pSession, szProductName, stringw);
1901  ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1902  if (lstrcmpW(stringw, szMSITEST) != 0)
1903  {
1904  len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1905  ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1906  ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1907  }
1908 
1909  /* Session::Property, put */
1910  hr = Session_PropertyPut(pSession, szProductName, szProductName);
1911  ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1912  memset(stringw, 0, sizeof(stringw));
1913  hr = Session_PropertyGet(pSession, szProductName, stringw);
1914  ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1915  if (lstrcmpW(stringw, szProductName) != 0)
1916  {
1917  len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1918  ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1919  ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1920  }
1921 
1922  /* Try putting a property using empty property identifier */
1923  hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1924  ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1925  ok_exception(hr, szPropertyName);
1926 
1927  /* Try putting a property using illegal property identifier */
1928  hr = Session_PropertyPut(pSession, szEquals, szProductName);
1929  ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1930 
1931  /* Session::Language, get */
1932  hr = Session_LanguageGet(pSession, &len);
1933  ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1934  /* Not sure how to check the language is correct */
1935 
1936  /* Session::Mode, get */
1937  hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1938  ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1939  ok(!bool, "Reboot at end session mode is %d\n", bool);
1940 
1941  hr = Session_ModeGet(pSession, MSIRUNMODE_MAINTENANCE, &bool);
1942  ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1943  ok(!bool, "Maintenance mode is %d\n", bool);
1944 
1945  /* Session::Mode, put */
1946  hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, VARIANT_TRUE);
1947  ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1948  hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1949  ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1950  ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1951  hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, VARIANT_FALSE); /* set it again so we don't reboot */
1952  ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1953 
1954  hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, VARIANT_TRUE);
1955  ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1956  ok_exception(hr, szModeFlag);
1957 
1958  hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTNOW, &bool);
1959  ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1960  ok(bool, "Reboot now mode is %d, expected 1\n", bool);
1961 
1962  hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, VARIANT_FALSE); /* set it again so we don't reboot */
1963  ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1964  ok_exception(hr, szModeFlag);
1965 
1966  hr = Session_ModePut(pSession, MSIRUNMODE_MAINTENANCE, VARIANT_TRUE);
1967  ok(hr == DISP_E_EXCEPTION, "Session_ModePut failed, hresult 0x%08x\n", hr);
1968  ok_exception(hr, szModeFlag);
1969 
1970  /* Session::Database, get */
1971  hr = Session_Database(pSession, &pDatabase);
1972  ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1973  if (hr == S_OK)
1974  {
1975  test_Database(pDatabase, TRUE);
1976  IDispatch_Release(pDatabase);
1977  }
1978 
1979  /* Session::EvaluateCondition */
1980  hr = Session_EvaluateCondition(pSession, NULL, &myint);
1981  ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1982  ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1983 
1984  hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1985  ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1986  ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1987 
1988  hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1989  ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1990  ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1991 
1992  /* Session::DoAction(CostInitialize) must occur before the next statements */
1993  hr = Session_DoAction(pSession, szCostInitialize, &myint);
1994  ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1995  ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1996 
1997  /* Session::SetInstallLevel */
1999  ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
2000 
2001  /* Session::FeatureCurrentState, get */
2002  hr = Session_FeatureCurrentState(pSession, szOne, &myint);
2003  ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
2004  ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2005 
2006  /* Session::Message */
2008  ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
2009  hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
2010  ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
2011  ok(myint == 0, "Session_Message returned %x\n", myint);
2012 
2013  /* Session::EvaluateCondition */
2014  hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
2015  ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2016  ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2017 
2018  hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
2019  ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2020  ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2021 
2022  /* Session::FeatureRequestState, put */
2024  ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
2025  hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
2026  ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
2027  ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
2028 
2029  /* Session::EvaluateCondition */
2030  hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
2031  ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2032  ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2033 
2034  hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
2035  ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2036  ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2037 }
2038 
2039 /* delete key and all its subkeys */
2040 static DWORD delete_key( HKEY hkey )
2041 {
2042  char name[MAX_PATH];
2043  DWORD ret;
2044 
2045  while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
2046  {
2047  HKEY tmp;
2048  if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
2049  {
2050  ret = delete_key( tmp );
2051  RegCloseKey( tmp );
2052  }
2053  if (ret) break;
2054  }
2055  if (ret != ERROR_NO_MORE_ITEMS) return ret;
2056  RegDeleteKeyA( hkey, "" );
2057  return 0;
2058 }
2059 
2061 {
2062  static const DWORD qw[2] = { 0x12345678, 0x87654321 };
2063  static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
2064  static const WCHAR szOne[] = { 'O','n','e',0 };
2065  static const WCHAR szTwo[] = { 'T','w','o',0 };
2066  static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
2067  static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
2068  static const WCHAR szFour[] = { 'F','o','u','r',0 };
2069  static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
2070  static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
2071  static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
2072  static const WCHAR szSix[] = { 'S','i','x',0 };
2073  static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
2074  static const WCHAR szREG_2[] = { '(','R','E','G','_','?','?',')',0 };
2075  static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
2076  static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
2077  static const WCHAR szBlank[] = { 0 };
2078  VARIANT varresult;
2079  VARIANTARG vararg;
2080  WCHAR szString[MAX_PATH];
2081  HKEY hkey, hkey_sub;
2082  HKEY curr_user = (HKEY)1;
2083  HRESULT hr;
2084  BOOL bRet;
2085  LONG lRet;
2086 
2087  /* Delete keys */
2088  SetLastError(0xdeadbeef);
2089  lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey );
2090  if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2091  {
2092  win_skip("Needed W-functions are not implemented\n");
2093  return;
2094  }
2095  if (!lRet)
2096  delete_key( hkey );
2097 
2098  /* Does our key exist? Shouldn't; check with all three possible value parameter types */
2099  hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2100  ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2101  ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
2102 
2103  memset(szString, 0, sizeof(szString));
2104  hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2105  ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2106 
2107  memset(szString, 0, sizeof(szString));
2108  hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2109  ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2110 
2111  /* Create key */
2112  ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
2113 
2114  ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2115  "RegSetValueExW failed\n");
2116  ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
2117  "RegSetValueExW failed\n");
2118  ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
2119  "RegSetValueExW failed\n");
2120  bRet = SetEnvironmentVariableA("MSITEST", "Four");
2121  ok(bRet, "SetEnvironmentVariableA failed %d\n", GetLastError());
2122  ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
2123  "RegSetValueExW failed\n");
2124  ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
2125  "RegSetValueExW failed\n");
2126  ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
2127  "RegSetValueExW failed\n");
2128  ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0),
2129  "RegSetValueExW failed\n");
2130 
2131  ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2132  "RegSetValueExW failed\n");
2133 
2134  ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
2135 
2136  /* Does our key exist? It should, and make sure we retrieve the correct default value */
2137  bRet = FALSE;
2138  hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2139  ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2140  ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
2141 
2142  memset(szString, 0, sizeof(szString));
2143  hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2144  ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2145  ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2146 
2147  /* Ask for the value of a nonexistent key */
2148  memset(szString, 0, sizeof(szString));
2149  hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
2150  ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2151 
2152  /* Get values of keys */
2153  memset(szString, 0, sizeof(szString));
2154  hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
2155  ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2156  ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2157 
2158  VariantInit(&vararg);
2159  V_VT(&vararg) = VT_BSTR;
2160  V_BSTR(&vararg) = SysAllocString(szTwo);
2161  hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
2162  ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2163  ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
2164  VariantClear(&varresult);
2165 
2166  memset(szString, 0, sizeof(szString));
2167  hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
2168  ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2169  ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
2170 
2171  memset(szString, 0, sizeof(szString));
2172  hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
2173  ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2174  ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
2175 
2176  /* Vista does not NULL-terminate this case */
2177  memset(szString, 0, sizeof(szString));
2178  hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
2179  ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2180  ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
2181  szString, szFiveHi, lstrlenW(szFiveHi));
2182 
2183  memset(szString, 0, sizeof(szString));
2184  hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
2185  ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2186  ok(!lstrcmpW(szString, szREG_2) || broken(!lstrcmpW(szString, szREG_)),
2187  "Registry value does not match\n");
2188 
2189  VariantInit(&vararg);
2190  V_VT(&vararg) = VT_BSTR;
2191  V_BSTR(&vararg) = SysAllocString(szSeven);
2192  hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
2193  ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2194 
2195  /* Get string class name for the key */
2196  memset(szString, 0, sizeof(szString));
2197  hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2198  ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2199  ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
2200 
2201  /* Get name of a value by positive number (RegEnumValue like), valid index */
2202  memset(szString, 0, sizeof(szString));
2203  hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
2204  ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2205  /* RegEnumValue order seems different on wine */
2206  todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
2207 
2208  /* Get name of a value by positive number (RegEnumValue like), invalid index */
2209  memset(szString, 0, sizeof(szString));
2210  hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
2211  ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2212 
2213  /* Get name of a subkey by negative number (RegEnumValue like), valid index */
2214  memset(szString, 0, sizeof(szString));
2215  hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
2216  ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2217  ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
2218 
2219  /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
2220  memset(szString, 0, sizeof(szString));
2221  hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
2222  ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2223 
2224  /* clean up */
2225  delete_key(hkey);
2226 }
2227 
2228 static void test_Installer_Products(BOOL bProductInstalled)
2229 {
2230  WCHAR szString[MAX_PATH];
2231  HRESULT hr;
2232  int idx;
2233  IUnknown *pUnk = NULL;
2234  IEnumVARIANT *pEnum = NULL;
2235  VARIANT var;
2236  ULONG celt;
2237  int iCount, iValue;
2238  IDispatch *pStringList = NULL;
2239  BOOL bProductFound = FALSE;
2240 
2241  /* Installer::Products */
2242  hr = Installer_Products(&pStringList);
2243  ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
2244  if (hr == S_OK)
2245  {
2246  /* StringList::_NewEnum */
2247  hr = StringList__NewEnum(pStringList, &pUnk);
2248  ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
2249  if (hr == S_OK)
2250  {
2251  hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2252  ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2253  }
2254  if (!pEnum)
2255  skip("IEnumVARIANT tests\n");
2256 
2257  /* StringList::Count */
2258  hr = StringList_Count(pStringList, &iCount);
2259  ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2260 
2261  for (idx=0; idx<iCount; idx++)
2262  {
2263  /* StringList::Item */
2264  memset(szString, 0, sizeof(szString));
2265  hr = StringList_Item(pStringList, idx, szString);
2266  ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2267 
2268  if (hr == S_OK)
2269  {
2270  /* Installer::ProductState */
2271  hr = Installer_ProductState(szString, &iValue);
2272  ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2273  if (hr == S_OK)
2274  ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2275 
2276  /* Not found our product code yet? Check */
2277  if (!bProductFound && !lstrcmpW(szString, szProductCode))
2278  bProductFound = TRUE;
2279 
2280  /* IEnumVARIANT::Next */
2281  if (pEnum)
2282  {
2283  hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2284  ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2285  ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2286  ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2287  ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2288  VariantClear(&var);
2289  }
2290  }
2291  }
2292 
2293  if (bProductInstalled)
2294  {
2295  ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2296  bProductInstalled ? "be" : "not be",
2297  bProductFound ? "found" : "not found");
2298  }
2299 
2300  if (pEnum)
2301  {
2302  IEnumVARIANT *pEnum2 = NULL;
2303 
2304  if (0) /* Crashes on Windows XP */
2305  {
2306  /* IEnumVARIANT::Clone, NULL pointer */
2307  IEnumVARIANT_Clone(pEnum, NULL);
2308  }
2309 
2310  /* IEnumVARIANT::Clone */
2311  hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2312  ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2313  if (hr == S_OK)
2314  {
2315  /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2316 
2317  /* IEnumVARIANT::Next of the clone */
2318  if (iCount)
2319  {
2320  hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2321  ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2322  ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2323  ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2324  VariantClear(&var);
2325  }
2326  else
2327  skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2328 
2329  IEnumVARIANT_Release(pEnum2);
2330  }
2331 
2332  /* IEnumVARIANT::Skip should fail */
2333  hr = IEnumVARIANT_Skip(pEnum, 1);
2334  ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2335 
2336  /* IEnumVARIANT::Next, NULL variant pointer */
2337  hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2338  ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2339  ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2340 
2341  /* IEnumVARIANT::Next, should not return any more items */
2342  hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2343  ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2344  ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2345  VariantClear(&var);
2346 
2347  /* IEnumVARIANT::Reset */
2348  hr = IEnumVARIANT_Reset(pEnum);
2349  ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2350 
2351  if (iCount)
2352  {
2353  /* IEnumVARIANT::Skip to the last product */
2354  hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2355  ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2356 
2357  /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2358  * NULL celt pointer. */
2359  hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2360  ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2361  ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2362  ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2363  VariantClear(&var);
2364  }
2365  else
2366  skip("IEnumVARIANT::Skip impossible for 0 products\n");
2367  }
2368 
2369  /* StringList::Item using an invalid index */
2370  memset(szString, 0, sizeof(szString));
2371  hr = StringList_Item(pStringList, iCount, szString);
2372  ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2373 
2374  if (pEnum) IEnumVARIANT_Release(pEnum);
2375  if (pUnk) IUnknown_Release(pUnk);
2376  IDispatch_Release(pStringList);
2377  }
2378 }
2379 
2380 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2381  * deleting the subkeys first) */
2382 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey, REGSAM access)
2383 {
2384  UINT ret;
2385  CHAR *string = NULL;
2386  HKEY hkey;
2387  DWORD dwSize;
2388 
2389  ret = RegOpenKeyExA(hkeyParent, subkey, 0, access, &hkey);
2390  if (ret != ERROR_SUCCESS) return ret;
2392  if (ret != ERROR_SUCCESS) return ret;
2393  if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2394 
2395  while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2396  delete_registry_key(hkey, string, access);
2397 
2398  RegCloseKey(hkey);
2399  HeapFree(GetProcessHeap(), 0, string);
2400  delete_key_portable(hkeyParent, subkey, access);
2401  return ERROR_SUCCESS;
2402 }
2403 
2404 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2405 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, REGSAM access, HKEY *phkey)
2406 {
2407  UINT ret;
2408  CHAR *string = NULL;
2409  int idx = 0;
2410  HKEY hkey;
2411  DWORD dwSize;
2412  BOOL found = FALSE;
2413 
2414  *phkey = 0;
2415 
2416  ret = RegOpenKeyExA(hkeyParent, subkey, 0, access, &hkey);
2417  if (ret != ERROR_SUCCESS) return ret;
2419  if (ret != ERROR_SUCCESS) return ret;
2420  if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2421 
2422  while (!found &&
2423  RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2424  {
2425  if (!strcmp(string, findkey))
2426  {
2427  *phkey = hkey;
2428  found = TRUE;
2429  }
2430  else if (find_registry_key(hkey, string, findkey, access, phkey) == ERROR_SUCCESS) found = TRUE;
2431  }
2432 
2433  if (*phkey != hkey) RegCloseKey(hkey);
2434  HeapFree(GetProcessHeap(), 0, string);
2435  return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2436 }
2437 
2439 {
2440  HRESULT hr;
2441  CHAR path[MAX_PATH];
2442  WCHAR szString[MAX_PATH];
2443  LONG res;
2444  HKEY hkey;
2445  DWORD num, size, type;
2446  int iValue, iCount;
2447  IDispatch *pStringList = NULL;
2449 
2450  if (is_process_limited())
2451  {
2452  /* In fact InstallProduct would succeed but then Windows XP
2453  * would not allow us to clean up the registry!
2454  */
2455  skip("Installer_InstallProduct (insufficient privileges)\n");
2456  return;
2457  }
2458 
2459  if (is_wow64)
2461 
2463 
2464  /* Avoid an interactive dialog in case of insufficient privileges. */
2466  ok(hr == S_OK, "Expected UILevel property put invoke to return S_OK, got 0x%08x\n", hr);
2467 
2468  /* Installer::InstallProduct */
2470  if (hr == DISP_E_EXCEPTION)
2471  {
2472  skip("InstallProduct failed, insufficient rights?\n");
2474  return;
2475  }
2476  ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2477 
2478  /* Installer::ProductState for our product code, which has been installed */
2480  ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2481  ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2482 
2483  /* Installer::ProductInfo for our product code */
2484 
2485  /* NULL attribute */
2486  memset(szString, 0, sizeof(szString));
2488  ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2490 
2491  /* Nonexistent attribute */
2492  memset(szString, 0, sizeof(szString));
2494  ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2496 
2497  /* Package name */
2498  memset(szString, 0, sizeof(szString));
2500  ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2501  todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2502 
2503  /* Product name */
2504  memset(szString, 0, sizeof(szString));
2506  ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2507  todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2508 
2509  /* Installer::Products */
2511 
2512  /* Installer::RelatedProducts for our upgrade code */
2513  hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2514  ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2515  if (hr == S_OK)
2516  {
2517  /* StringList::Count */
2518  hr = StringList_Count(pStringList, &iCount);
2519  ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2520  ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2521 
2522  /* StringList::Item */
2523  memset(szString, 0, sizeof(szString));
2524  hr = StringList_Item(pStringList, 0, szString);
2525  ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2526  ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2527 
2528  IDispatch_Release(pStringList);
2529  }
2530 
2532  ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2533  DeleteFileW( szString );
2534 
2535  /* Check & clean up installed files & registry keys */
2536  ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2537  ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n");
2538  ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2539  ok(delete_pf("msitest\\cabout", FALSE), "Directory not created\n");
2540  ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2541  ok(delete_pf("msitest\\changed", FALSE), "Directory not created\n");
2542  ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2543  ok(delete_pf("msitest\\first", FALSE), "Directory not created\n");
2544  ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2545  ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2546  ok(delete_pf("msitest", FALSE), "Directory not created\n");
2547 
2548  res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest", &hkey);
2549  ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2550 
2551  size = MAX_PATH;
2552  type = REG_SZ;
2553  res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2554  ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2555  ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2556 
2557  size = MAX_PATH;
2558  type = REG_SZ;
2559  res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2560  ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2561 
2562  size = sizeof(num);
2563  type = REG_DWORD;
2564  res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2565  ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2566  ok(num == 314, "Expected 314, got %d\n", num);
2567 
2568  size = MAX_PATH;
2569  type = REG_SZ;
2570  res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2571  ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2572  ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2573 
2574  RegCloseKey(hkey);
2575 
2576  res = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest");
2577  ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2578 
2579  /* Remove registry keys written by RegisterProduct standard action */
2581  "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{837450fa-a39b-4bc8-b321-08b393f784b3}",
2582  KEY_WOW64_32KEY);
2583  ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2584 
2586  "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656", access);
2587  ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2588 
2590  "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "af054738b93a8cb43b12803b397f483b", access, &hkey);
2591  ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2592 
2593  res = delete_registry_key(hkey, "af054738b93a8cb43b12803b397f483b", access);
2594  ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2595  RegCloseKey(hkey);
2596 
2598  "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\af054738b93a8cb43b12803b397f483b", access);
2599  ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2600 
2601  /* Remove registry keys written by PublishProduct standard action */
2602  res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2603  ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2604 
2605  res = delete_registry_key(hkey, "Products\\af054738b93a8cb43b12803b397f483b", KEY_ALL_ACCESS);
2606  ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2607 
2608  res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2609  ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2610 
2611  RegCloseKey(hkey);
2612 
2613  /* Delete installation files we created */
2615 }
2616 
2617 static void test_Installer(void)
2618 {
2619  static const WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2620  static const WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2622  HRESULT hr;
2623  IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL, *pSumInfo = NULL;
2624  int iValue, iCount;
2625 
2626  if (!pInstaller) return;
2627 
2628  /* Installer::CreateRecord */
2629 
2630  /* Test for error */
2631  hr = Installer_CreateRecord(-1, &pRecord);
2632  ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2633  ok_exception(hr, szCreateRecordException);
2634 
2635  /* Test for success */
2636  hr = Installer_CreateRecord(1, &pRecord);
2637  ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2638  ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2639  if (pRecord)
2640  {
2641  /* Record::FieldCountGet */
2642  hr = Record_FieldCountGet(pRecord, &iValue);
2643  ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2644  ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2645 
2646  /* Record::IntegerDataGet */
2647  hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2648  ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2649  ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2650 
2651  /* Record::IntegerDataGet, bad index */
2652  hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2653  ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2654  ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2655 
2656  /* Record::IntegerDataPut */
2657  hr = Record_IntegerDataPut(pRecord, 1, 100);
2658  ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2659 
2660  /* Record::IntegerDataPut, bad index */
2661  hr = Record_IntegerDataPut(pRecord, 10, 100);
2662  ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2663  ok_exception(hr, szIntegerDataException);
2664 
2665  /* Record::IntegerDataGet */
2666  hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2667  ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2668  ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2669 
2670  IDispatch_Release(pRecord);
2671  }
2672 
2674 
2675  /* Installer::OpenPackage */
2676  hr = Installer_OpenPackage(szPath, 0, &pSession);
2677  if (hr == DISP_E_EXCEPTION)
2678  {
2679  skip("OpenPackage failed, insufficient rights?\n");
2681  return;
2682  }
2683  ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2684  if (hr == S_OK)
2685  {
2686  test_Session(pSession);
2687  IDispatch_Release(pSession);
2688  }
2689 
2690  /* Installer::OpenDatabase */
2692  ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2693  if (hr == S_OK)
2694  {
2695  test_Database(pDatabase, FALSE);
2696  IDispatch_Release(pDatabase);
2697  }
2698 
2699  /* Installer::SummaryInformation */
2700  hr = Installer_SummaryInformation(szPath, 0, &pSumInfo);
2701  ok(hr == S_OK, "Installer_SummaryInformation failed, hresult 0x%08x\n", hr);
2702  if (hr == S_OK)
2703  {
2704  test_SummaryInfo(pSumInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), TRUE);
2705  IDispatch_Release(pSumInfo);
2706  }
2707 
2708  hr = Installer_SummaryInformation(NULL, 0, &pSumInfo);
2709  ok(hr == DISP_E_EXCEPTION, "Installer_SummaryInformation failed, hresult 0x%08x\n", hr);
2710 
2711  /* Installer::RegistryValue */
2713 
2714  /* Installer::ProductState for our product code, which should not be installed */
2716  ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2717  ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2718 
2719  /* Installer::ProductInfo for our product code, which should not be installed */
2720 
2721  /* Package name */
2722  memset(szPath, 0, sizeof(szPath));
2724  ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2726 
2727  /* NULL attribute and NULL product code */
2728  memset(szPath, 0, sizeof(szPath));
2730  ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2732 
2733  /* Installer::Products */
2735 
2736  /* Installer::RelatedProducts for our upgrade code, should not find anything */
2737  hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2738  ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2739  if (hr == S_OK)
2740  {
2741  /* StringList::Count */
2742  hr = StringList_Count(pStringList, &iCount);
2743  ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2744  ok(!iCount, "Expected no related products but found %d\n", iCount);
2745 
2746  IDispatch_Release(pStringList);
2747  }
2748 
2749  /* Installer::Version */
2750  memset(szPath, 0, sizeof(szPath));
2752  ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2753 
2754  /* Installer::InstallProduct and other tests that depend on our product being installed */
2756 }
2757 
2758 START_TEST(automation)
2759 {
2760  DWORD len;
2761  char temp_path[MAX_PATH], prev_path[MAX_PATH];
2762  HRESULT hr;
2763  CLSID clsid;
2764  IUnknown *pUnk;
2765 
2767 
2768  if (pIsWow64Process)
2769  pIsWow64Process(GetCurrentProcess(), &is_wow64);
2770 
2772 
2773  GetCurrentDirectoryA(MAX_PATH, prev_path);
2776 
2778  len = lstrlenA(CURR_DIR);
2779 
2780  if(len && (CURR_DIR[len - 1] == '\\'))
2781  CURR_DIR[len - 1] = 0;
2782 
2784 
2785  hr = OleInitialize(NULL);
2786  ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2788  ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2789  hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2790  ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2791 
2792  if (pUnk)
2793  {
2794  hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2795  ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2796 
2797  test_dispid();
2798  test_dispatch();
2799  test_Installer();
2800 
2801  IDispatch_Release(pInstaller);
2802  IUnknown_Release(pUnk);
2803  }
2804 
2805  OleUninitialize();
2806 
2807  SetCurrentDirectoryA(prev_path);
2808 }
static const WCHAR szUpgradeCode[]
Definition: automation.c:53
static void delete_test_files(void)
Definition: automation.c:447
static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
Definition: automation.c:1590
#define DISP_E_EXCEPTION
Definition: winerror.h:2518
#define PID_TEMPLATE
Definition: suminfo.c:49
static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel)
Definition: automation.c:1306
static const CHAR media_dat[]
Definition: automation.c:138
#define DISP_E_UNKNOWNNAME
Definition: winerror.h:2515
WCHAR OLECHAR
Definition: compat.h:1933
INTERNETFEATURELIST feature
Definition: misc.c:1689
LONG WINAPI RegOpenKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:3257
static const CHAR registry_dat[]
Definition: automation.c:162
disp
Definition: i386-dis.c:3181
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
Definition: automation.c:1177
LONG WINAPI RegQueryValueExA(_In_ HKEY hkeyorg, _In_ LPCSTR name, _In_ LPDWORD reserved, _Out_opt_ LPDWORD type, _Out_opt_ LPBYTE data, _Inout_opt_ LPDWORD count)
Definition: reg.c:4023
static const CHAR directory_dat[]
Definition: automation.c:81
static const WCHAR szProductInfoException[]
Definition: automation.c:54
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid
Definition: winddi.h:3835
GLint level
Definition: gl.h:1546
VOID WINAPI GetSystemTimeAsFileTime(OUT PFILETIME lpFileTime)
Definition: time.c:128
static const CHAR install_exec_seq_dat[]
Definition: automation.c:122
enum _TOKEN_ELEVATION_TYPE TOKEN_ELEVATION_TYPE
#define TRUE
Definition: types.h:120
#define IDOK
Definition: winuser.h:824
static const msi_summary_info summary_info[]
Definition: automation.c:206
#define CloseHandle
Definition: compat.h:398
Definition: compat.h:1939
static void test_Installer_Products(BOOL bProductInstalled)
Definition: automation.c:2228
#define DISPATCH_PROPERTYGET
Definition: oleauto.h:1007
#define PID_CHARCOUNT
Definition: suminfo.c:58
static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
Definition: automation.c:1268
const CHAR * szValue
Definition: automation.c:198
static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
Definition: automation.c:1149
#define ERROR_SUCCESS
Definition: deptool.c:10
static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
Definition: automation.c:433
#define WideCharToMultiByte
Definition: compat.h:101
static BOOL get_program_files_dir(LPSTR buf)
Definition: automation.c:383
HRESULT hr
Definition: shlfolder.c:183
static void write_file(const CHAR *filename, const char *data, int data_size)
Definition: automation.c:283
static const WCHAR WINE_INSTALLPROPERTY_PRODUCTNAMEW[]
Definition: automation.c:56
_In_ ULONG iMode
Definition: winddi.h:3520
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:95
LONG WINAPI RegDeleteKeyExA(_In_ HKEY hKey, _In_ LPCSTR lpSubKey, _In_ REGSAM samDesired, _In_ DWORD Reserved)
Definition: reg.c:1252
struct _msi_summary_info msi_summary_info
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
#define REG_BINARY
Definition: nt_native.h:1496
static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
Definition: automation.c:1476
static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
Definition: automation.c:1424
static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
Definition: automation.c:1563
LONG WINAPI RegQueryInfoKeyA(HKEY hKey, LPSTR lpClass, LPDWORD lpcClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcMaxSubKeyLen, LPDWORD lpcMaxClassLen, LPDWORD lpcValues, LPDWORD lpcMaxValueNameLen, LPDWORD lpcMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime)
Definition: reg.c:3607
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
static char PROG_FILES_DIR[MAX_PATH]
Definition: automation.c:381
#define CP_ACP
Definition: compat.h:99
static const WCHAR szCostInitialize[]
Definition: msipriv.h:1191
#define LOCALE_USER_DEFAULT
int WINAPI lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:170
GLuint GLuint GLsizei count
Definition: gl.h:1545
static DWORD delete_key(HKEY hkey)
Definition: automation.c:2040
#define HKEY_CURRENT_USER
Definition: winreg.h:11
static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
Definition: automation.c:1160
_In_opt_ PSID Group
Definition: rtlfuncs.h:1606
static CHAR string2[MAX_PATH]
Definition: automation.c:468
char CHAR
Definition: xmlstorage.h:175
#define FILE_CURRENT
Definition: winbase.h:113
BOOL WINAPI SetEndOfFile(HANDLE hFile)
Definition: fileinfo.c:1154
static CHAR string1[MAX_PATH]
Definition: automation.c:468
static HRESULT View_Close(IDispatch *pView)
Definition: automation.c:1442
#define MB_PRECOMPOSED
Definition: winnls.h:278
#define V_I2(A)
Definition: oleauto.h:245
#define DISP_E_MEMBERNOTFOUND
Definition: winerror.h:2512
static CHAR CURR_DIR[MAX_PATH]
Definition: automation.c:59
static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
Definition: automation.c:1402
static HINSTANCE hkernel32
Definition: process.c:66
struct _msi_table msi_table
HRESULT WINAPI VariantCopyInd(VARIANT *pvargDest, VARIANTARG *pvargSrc)
Definition: variant.c:850
static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
Definition: automation.c:1386
static const WCHAR szProductCode[]
Definition: automation.c:52
double DATE
Definition: compat.h:1894
LONG WINAPI RegOpenKeyExA(_In_ HKEY hKey, _In_ LPCSTR lpSubKey, _In_ DWORD ulOptions, _In_ REGSAM samDesired, _Out_ PHKEY phkResult)
Definition: reg.c:3331
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
int WINAPI lstrcmpA(LPCSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:18
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
Definition: automation.c:1088
BOOL todo
Definition: automation.c:546
BOOL WINAPI CheckTokenMembership(IN HANDLE ExistingTokenHandle, IN PSID SidToCheck, OUT PBOOL IsMember)
Definition: token.c:21
#define MSI_NULL_INTEGER
Definition: msiquery.h:32
static void test_Installer_RegistryValue(void)
Definition: automation.c:2060
static BOOL create_package(LPWSTR path)
Definition: automation.c:356
static void init_functionpointers(void)
Definition: automation.c:216
OLECHAR * BSTR
Definition: compat.h:1934
void WINAPI VariantInit(VARIANTARG *pVarg)
Definition: variant.c:571
const CHAR * data
Definition: automation.c:173
int32_t INT_PTR
Definition: typedefs.h:62
#define PID_REVNUMBER
Definition: suminfo.c:51
static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
Definition: automation.c:1553
static LONG(WINAPI *pRegDeleteKeyExA)(HKEY
char * LPSTR
Definition: xmlstorage.h:182
static const WCHAR WINE_INSTALLPROPERTY_PACKAGENAMEW[]
Definition: automation.c:55
const char * filename
Definition: ioapi.h:135
static const WCHAR szAttribute[]
Definition: domdoc.c:1179
static LPOLESTR
Definition: stg_prop.c:27
BOOL WINAPI FileTimeToLocalFileTime(IN CONST FILETIME *lpFileTime, OUT LPFILETIME lpLocalFileTime)
Definition: time.c:211
#define lstrlenW
Definition: compat.h:407
#define E_FAIL
Definition: ddrawi.h:102
static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
Definition: automation.c:1449
HRESULT WINAPI DECLSPEC_HOTPATCH CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
Definition: compobj.c:2511
int32_t INT
Definition: typedefs.h:56
short VARIANT_BOOL
Definition: compat.h:1931
#define PID_CODEPAGE
Definition: suminfo.c:43
unsigned long MSIHANDLE
Definition: msiserver.idl:25
static DWORD
Definition: automation.c:43
#define PID_LASTPRINTED
Definition: suminfo.c:53
#define V_I4(A)
Definition: oleauto.h:247
#define DISPATCH_METHOD
Definition: oleauto.h:1006
static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
Definition: automation.c:1336
DWORD WINAPI DECLSPEC_HOTPATCH SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod)
Definition: fileinfo.c:204
#define V_DISPATCH(A)
Definition: oleauto.h:239
static const CHAR file_dat[]
Definition: automation.c:112
static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, VARIANT_BOOL *mode)
Definition: automation.c:1206
static void test_Installer(void)
Definition: automation.c:2617
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define ok_exception(hr, szDescription)
Definition: automation.c:503
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
unsigned char * LPBYTE
Definition: typedefs.h:52
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
static BOOL is_process_limited(void)
Definition: automation.c:234
#define PID_LASTSAVE_DTM
Definition: suminfo.c:55
static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
Definition: automation.c:1353
PVOID WINAPI FreeSid(PSID pSid)
Definition: security.c:577
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat token
Definition: glfuncs.h:210
LONG WINAPI RegOpenKeyW(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:3296
#define REG_MULTI_SZ
Definition: nt_native.h:1501
#define GENERIC_WRITE
Definition: nt_native.h:90
static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, REGSAM access, HKEY *phkey)
Definition: automation.c:2405
static const CHAR component_dat[]
Definition: automation.c:70
static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
Definition: automation.c:986
static PVOID ptr
Definition: dispmode.c:27
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
unsigned int idx
Definition: utils.c:41
#define S_FALSE
Definition: winerror.h:2357
static const CHAR property_dat[]
Definition: automation.c:143
UINT WINAPI MsiSummaryInfoSetPropertyA(MSIHANDLE handle, UINT uiProperty, UINT uiDataType, INT iValue, FILETIME *pftValue, LPCSTR szValue)
Definition: suminfo.c:863
const WCHAR * str
START_TEST(automation)
Definition: automation.c:2758
#define GET_PROC(dll, func)
BOOL WINAPI CreateDirectoryA(IN LPCSTR lpPathName, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: dir.c:37
smooth NULL
Definition: ftsmooth.c:416
BSTR WINAPI SysAllocString(LPCOLESTR str)
Definition: oleaut.c:241
static FILETIME systemtime
Definition: automation.c:58
static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
Definition: automation.c:1057
BOOL WINAPI DeleteFileA(IN LPCSTR lpFileName)
Definition: delete.c:24
const char ** registry
Definition: cffdrivr.c:690
#define ADD_INFO_FILETIME(property, pftValue)
Definition: automation.c:204
const char * LPCSTR
Definition: xmlstorage.h:183
static const msi_table tables[]
Definition: automation.c:179
static void test_Installer_InstallProduct(void)
Definition: automation.c:2438
#define DISPATCH_PROPERTYPUT
Definition: oleauto.h:1008
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
int options
Definition: main.c:106
static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
Definition: automation.c:1459
#define SECURITY_NT_AUTHORITY
Definition: setypes.h:526
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
typedef bool(CARDLIBPROC *pCanDragProc)(CardRegion &stackobj
static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
Definition: automation.c:940
static const WCHAR nameW[]
Definition: main.c:46
static REGSAM
Definition: automation.c:44
static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
Definition: automation.c:1493
static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
Definition: automation.c:293
static const WCHAR szEmpty[]
Definition: provider.c:47
BOOL WINAPI IsWow64Process(IN HANDLE hProcess, OUT PBOOL Wow64Process)
Definition: proc.c:1974
#define todo_wine_if(is_todo)
Definition: test.h:155
#define KEY_WOW64_64KEY
Definition: cmtypes.h:46
LONG WINAPI RegSetValueExW(_In_ HKEY hKey, _In_ LPCWSTR lpValueName, _In_ DWORD Reserved, _In_ DWORD dwType, _In_ CONST BYTE *lpData, _In_ DWORD cbData)
Definition: reg.c:4895
static const char * msifile
Definition: automation.c:49
LPSTR WINAPI lstrcatA(LPSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:123
#define PID_THUMBNAIL
Definition: suminfo.c:59
__u8 media
Definition: mkdosfs.c:367
#define DISP_E_TYPEMISMATCH
Definition: winerror.h:2514
BOOL WINAPI FileTimeToSystemTime(IN CONST FILETIME *lpFileTime, OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:178
static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
Definition: automation.c:954
GLsizeiptr size
Definition: glext.h:5919
static DISPID get_dispid(IDispatch *disp, const char *name)
Definition: automation.c:522
#define GetProcessHeap()
Definition: compat.h:395
#define trace
Definition: atltest.h:70
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
#define d
Definition: ke_i.h:81
#define SECURITY_BUILTIN_DOMAIN_RID
Definition: setypes.h:553
#define TOKEN_QUERY
Definition: setypes.h:874
#define PID_PAGECOUNT
Definition: suminfo.c:56
static const WCHAR szMSITEST[]
Definition: automation.c:51
__wchar_t WCHAR
Definition: xmlstorage.h:180
LONG HRESULT
Definition: typedefs.h:77
static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
Definition: automation.c:864
static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
Definition: automation.c:1370
static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
Definition: automation.c:1319
BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentVariableA(IN LPCSTR lpName, IN LPCSTR lpValue)
Definition: environ.c:218
const GUID IID_IUnknown
HANDLE WINAPI GetCurrentProcess(VOID)
Definition: proc.c:1138
static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
Definition: automation.c:1415
static PSID
Definition: automation.c:42
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
const char file[]
Definition: icontest.c:11
static IDispatch * pInstaller
Definition: automation.c:66
#define MSIDBOPEN_CREATE
Definition: msiquery.h:69
#define V_BOOL(A)
Definition: oleauto.h:224
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned long DWORD
Definition: ntddk_ex.h:95
PVOID HANDLE
Definition: typedefs.h:71
GLuint GLuint num
Definition: glext.h:9618
GLint left
Definition: glext.h:7726
#define MSIDBOPEN_TRANSACT
Definition: msiquery.h:67
#define ADD_INFO_I4(property, iValue)
Definition: automation.c:202
static int _invoke_todo_vtResult
Definition: automation.c:862
#define SetLastError(x)
Definition: compat.h:409
static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
Definition: automation.c:922
static REFPROPVARIANT PROPVAR_CHANGE_FLAGS VARTYPE vt
Definition: suminfo.c:85
static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
Definition: automation.c:1574
const CHAR * filename
Definition: automation.c:172
static PHANDLE
Definition: automation.c:43
static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
Definition: automation.c:906
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
LPSTR WINAPI lstrcpyA(LPSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:100
TCHAR szTitle[MAX_LOADSTRING]
Definition: magnifier.c:35
#define PID_EDITTIME
Definition: msidefs.h:272
#define PID_TITLE
Definition: suminfo.c:44
static HRESULT Installer_Products(IDispatch **pStringList)
Definition: automation.c:1077
const GUID IID_IDispatch
static LPCWSTR szVersion
Definition: asmcache.c:748
static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
Definition: automation.c:1536
int ret
LONG WINAPI RegEnumKeyA(HKEY hKey, DWORD dwIndex, LPSTR lpName, DWORD cbName)
Definition: reg.c:2391
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:126
REFCLSID clsid
Definition: msctf.c:84
HRESULT WINAPI DECLSPEC_HOTPATCH VariantClear(VARIANTARG *pVarg)
Definition: variant.c:651
#define IID_NULL
Definition: guiddef.h:98
#define todo_wine
Definition: test.h:154
UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase, LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle)
Definition: suminfo.c:586
static HRESULT Installer_UILevelPut(int level)
Definition: automation.c:1116
static const WCHAR szSource[]
Definition: automation.c:501
#define V_VT(A)
Definition: oleauto.h:211
BOOL WINAPI SetCurrentDirectoryA(IN LPCSTR lpPathName)
Definition: path.c:2205
uint32_t entry
Definition: isohybrid.c:63
GLenum GLsizei len
Definition: glext.h:6722
unsigned char BYTE
Definition: mem.h:68
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:821
LONG WINAPI RegCreateKeyW(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:1199
#define GUID_NULL
Definition: ks.h:106
static const WCHAR szMsifile[]
Definition: automation.c:50
static HRESULT Installer_SummaryInformation(BSTR PackagePath, int UpdateCount, IDispatch **pSumInfo)
Definition: automation.c:1130
#define V_UNKNOWN(A)
Definition: oleauto.h:281
GLenum mode
Definition: glext.h:6217
#define V_BSTR(A)
Definition: oleauto.h:226
UINT WINAPI MsiCloseHandle(MSIHANDLE handle)
Definition: handle.c:270
#define broken(x)
Definition: _sntprintf.h:21
HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID iid, LPVOID *ppv)
Definition: compobj.c:3234
#define ok_w2(format, szString1, szString2)
Definition: automation.c:470
HRESULT WINAPI DECLSPEC_HOTPATCH OleInitialize(LPVOID reserved)
Definition: ole2.c:172
_In_ DWORD _Out_ _In_ WORD wFlags
Definition: wincon.h:519
LONG WINAPI RegDeleteKeyA(_In_ HKEY hKey, _In_ LPCSTR lpSubKey)
Definition: reg.c:1222
const char * name
Definition: automation.c:545
#define PID_CREATE_DTM
Definition: suminfo.c:54
static void test_dispid(void)
Definition: automation.c:600
DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
static HRESULT Installer_VersionGet(LPWSTR szVersion)
Definition: automation.c:1104
struct stdole::EXCEPINFO EXCEPINFO
#define S_OK
Definition: intsafe.h:59
static VARIANTARG static DISPID
Definition: ordinal.c:49
#define CREATE_ALWAYS
Definition: disk.h:72
static LONG delete_key_portable(HKEY key, LPCSTR subkey, REGSAM access)
Definition: automation.c:272
static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
Definition: automation.c:1024
int WINAPI lstrlenA(LPCSTR lpString)
Definition: lstring.c:145
#define lstrcpyW
Definition: compat.h:406
DWORD WINAPI GetTempPathA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2053
BYTE * data
GLuint GLint GLboolean GLint GLenum access
Definition: glext.h:7866
LPCWSTR szPath
Definition: env.c:35
static const WCHAR szProgId[]
Definition: automation.c:65
UINT WINAPI MsiDatabaseCommit(MSIHANDLE hdb)
Definition: msiquery.c:813
static BOOL is_wow64
Definition: automation.c:40
#define KEY_ALL_ACCESS
Definition: nt_native.h:1041
static void test_Session(IDispatch *pSession)
Definition: automation.c:1862
#define REG_EXPAND_SZ
Definition: nt_native.h:1494
static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
Definition: automation.c:1510
#define ok(value,...)
Definition: atltest.h:57
DWORD WINAPI GetCurrentDirectoryA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2145
Definition: services.c:325
UINT WINAPI MsiOpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB)
Definition: database.c:303
static const WCHAR WINE_INSTALLPROPERTY_LOCALPACKAGEW[]
Definition: automation.c:57
ACCESS_MASK REGSAM
Definition: winreg.h:69
BOOL WINAPI RemoveDirectoryA(IN LPCSTR lpPathName)
Definition: dir.c:714
unsigned short VARTYPE
Definition: compat.h:1895
static const WCHAR szOne[]
Definition: msipriv.h:1108
FILETIME * pftValue
Definition: automation.c:197
unsigned int UINT
Definition: ndis.h:50
BOOL WINAPI OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle)
Definition: security.c:296
static void create_file(const CHAR *name, DWORD size)
Definition: automation.c:400
static PBOOL
Definition: automation.c:42
#define MultiByteToWideChar
Definition: compat.h:100
DISPID did
Definition: automation.c:544
static void test_dispatch(void)
Definition: automation.c:638
#define skip(...)
Definition: atltest.h:64
UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE handle)
Definition: suminfo.c:1152
static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, VARIANT_BOOL mode)
Definition: automation.c:1223
static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
Definition: automation.c:1005
#define PID_WORDCOUNT
Definition: suminfo.c:57
#define PID_DICTIONARY
Definition: suminfo.c:42
static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
Definition: automation.c:1240
Definition: name.c:36
static const WCHAR szName[]
Definition: msipriv.h:1194
static EXCEPINFO excepinfo
Definition: automation.c:60
GLuint res
Definition: glext.h:9613
struct stdole::DISPPARAMS DISPPARAMS
static const get_did_t get_did_data[]
Definition: automation.c:549
static LPCSTR
Definition: automation.c:44
HANDLE HKEY
Definition: registry.h:24
#define REG_QWORD
Definition: sdbapi.c:597
unsigned int ULONG
Definition: retypes.h:1
GLenum GLuint id
Definition: glext.h:5579
BOOL WINAPI GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength, PDWORD ReturnLength)
Definition: security.c:413
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
#define ERROR_CALL_NOT_IMPLEMENTED
Definition: compat.h:92
static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
Definition: automation.c:1251
#define LOCALE_NEUTRAL
#define KEY_WOW64_32KEY
Definition: cmtypes.h:45
#define DISP_E_BADINDEX
Definition: winerror.h:2520
#define ADD_TABLE(x)
Definition: automation.c:177
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
#define REG_NONE
Definition: nt_native.h:1492
#define CreateFileA(a, b, c, d, e, f, g)
Definition: compat.h:399
static const CHAR feature_dat[]
Definition: automation.c:92
WCHAR * LPWSTR
Definition: xmlstorage.h:184
static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
Definition: automation.c:1606
HRESULT WINAPI VariantCopy(VARIANTARG *pvargDest, VARIANTARG *pvargSrc)
Definition: variant.c:751
static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey, REGSAM access)
Definition: automation.c:2382
#define ok_w2n(format, szString1, szString2, len)
Definition: automation.c:479
void WINAPI DECLSPEC_HOTPATCH OleUninitialize(void)
Definition: ole2.c:233
#define memset(x, y, z)
Definition: compat.h:39
#define REG_DWORD
Definition: sdbapi.c:596
#define DOMAIN_ALIAS_RID_ADMINS
Definition: setypes.h:624
#define ADD_INFO_LPSTR(property, szValue)
Definition: automation.c:203
static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
Definition: automation.c:1527
static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
Definition: automation.c:1194
static void *static void *static LPDIRECTPLAY IUnknown * pUnk
Definition: dplayx.c:30
static char * stringw(char *buf, char *end, const wchar_t *sw, int len, int field_width, int precision, int flags)
Definition: sprintf.c:335
#define win_skip
Definition: test.h:141
INT WINAPI SystemTimeToVariantTime(LPSYSTEMTIME lpSt, double *pDateOut)
Definition: variant.c:1289
static void create_database(const CHAR *name, const msi_table *tables, int num_tables, const msi_summary_info *info, int num_info)
Definition: automation.c:319
#define HeapFree(x, y, z)
Definition: compat.h:394
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:54
static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
Definition: automation.c:1040
Definition: compat.h:1938
static void test_Database(IDispatch *pDatabase, BOOL readonly)
Definition: automation.c:1749
static BOOL(WINAPI *pCheckTokenMembership)(HANDLE
#define V_DATE(A)
Definition: oleauto.h:231
#define SUCCEEDED(hr)
Definition: intsafe.h:57
#define ok_awplus(format, extra, aString, wString)
Definition: automation.c:494
SID_IDENTIFIER_AUTHORITY NtAuthority
Definition: database.c:19
static void create_test_files(void)
Definition: automation.c:418
UINT WINAPI MsiDatabaseImportA(MSIHANDLE handle, LPCSTR szFolder, LPCSTR szFilename)
Definition: database.c:900
HRESULT WINAPI VariantChangeTypeEx(VARIANTARG *pvargDest, VARIANTARG *pvargSrc, LCID lcid, USHORT wFlags, VARTYPE vt)
Definition: variant.c:991
BOOL WINAPI AllocateAndInitializeSid(PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount, DWORD nSubAuthority0, DWORD nSubAuthority1, DWORD nSubAuthority2, DWORD nSubAuthority3, DWORD nSubAuthority4, DWORD nSubAuthority5, DWORD nSubAuthority6, DWORD nSubAuthority7, PSID *pSid)
Definition: security.c:553
static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
Definition: automation.c:970
Definition: path.c:42
static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret)
Definition: automation.c:1285
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define KEY_ENUMERATE_SUB_KEYS
Definition: nt_native.h:1019
#define TEST_SUMMARYINFO_PROPERTIES_MODIFIED
Definition: automation.c:1604
static const CHAR feature_comp_dat[]
Definition: automation.c:102
Definition: fci.c:126
char temp_path[MAX_PATH]
Definition: mspatcha.c:123
#define REG_SZ
Definition: layer.c:22
GLuint const GLchar * name
Definition: glext.h:6031
static const WCHAR slashW[]
Definition: devenum.c:62