crypt32: Introduce function to encode an array of items as a set.
[wine] / dlls / msi / tests / msi.c
1 /*
2  * tests for Microsoft Installer functionality
3  *
4  * Copyright 2005 Mike McCormack for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdio.h>
22 #include <windows.h>
23 #include <msi.h>
24 #include <msiquery.h>
25 #include <sddl.h>
26
27 #include "wine/test.h"
28
29 typedef struct test_MSIFILEHASHINFO {
30     ULONG dwFileHashInfoSize;
31     ULONG dwData[4];
32 } test_MSIFILEHASHINFO, *test_PMSIFILEHASHINFO;
33
34 typedef INSTALLSTATE (WINAPI *fnMsiUseFeatureExA)(LPCSTR, LPCSTR ,DWORD, DWORD );
35 fnMsiUseFeatureExA pMsiUseFeatureExA;
36 typedef UINT (WINAPI *fnMsiOpenPackageExA)(LPCSTR, DWORD, MSIHANDLE*);
37 fnMsiOpenPackageExA pMsiOpenPackageExA;
38 typedef UINT (WINAPI *fnMsiOpenPackageExW)(LPCWSTR, DWORD, MSIHANDLE*);
39 fnMsiOpenPackageExW pMsiOpenPackageExW;
40 typedef INSTALLSTATE (WINAPI *fnMsiGetComponentPathA)(LPCSTR, LPCSTR, LPSTR, DWORD*);
41 fnMsiGetComponentPathA pMsiGetComponentPathA;
42 typedef UINT (WINAPI *fnMsiGetFileHashA)(LPCSTR, DWORD, test_PMSIFILEHASHINFO);
43 fnMsiGetFileHashA pMsiGetFileHashA;
44
45 static void test_usefeature(void)
46 {
47     UINT r;
48
49     if (!pMsiUseFeatureExA)
50         return;
51
52     r = MsiQueryFeatureState(NULL,NULL);
53     ok( r == INSTALLSTATE_INVALIDARG, "wrong return val\n");
54
55     r = MsiQueryFeatureState("{9085040-6000-11d3-8cfe-0150048383c9}" ,NULL);
56     ok( r == INSTALLSTATE_INVALIDARG, "wrong return val\n");
57
58     r = pMsiUseFeatureExA(NULL,NULL,0,0);
59     ok( r == INSTALLSTATE_INVALIDARG, "wrong return val\n");
60
61     r = pMsiUseFeatureExA(NULL, "WORDVIEWFiles", -2, 1 );
62     ok( r == INSTALLSTATE_INVALIDARG, "wrong return val\n");
63
64     r = pMsiUseFeatureExA("{90850409-6000-11d3-8cfe-0150048383c9}", 
65                          NULL, -2, 0 );
66     ok( r == INSTALLSTATE_INVALIDARG, "wrong return val\n");
67
68     r = pMsiUseFeatureExA("{9085040-6000-11d3-8cfe-0150048383c9}", 
69                          "WORDVIEWFiles", -2, 0 );
70     ok( r == INSTALLSTATE_INVALIDARG, "wrong return val\n");
71
72     r = pMsiUseFeatureExA("{0085040-6000-11d3-8cfe-0150048383c9}", 
73                          "WORDVIEWFiles", -2, 0 );
74     ok( r == INSTALLSTATE_INVALIDARG, "wrong return val\n");
75
76     r = pMsiUseFeatureExA("{90850409-6000-11d3-8cfe-0150048383c9}", 
77                          "WORDVIEWFiles", -2, 1 );
78     ok( r == INSTALLSTATE_INVALIDARG, "wrong return val\n");
79 }
80
81 static void test_null(void)
82 {
83     MSIHANDLE hpkg;
84     UINT r;
85     HKEY hkey;
86     DWORD dwType, cbData;
87     LPBYTE lpData = NULL;
88
89     r = pMsiOpenPackageExW(NULL, 0, &hpkg);
90     ok( r == ERROR_INVALID_PARAMETER,"wrong error\n");
91
92     r = MsiQueryProductStateW(NULL);
93     ok( r == INSTALLSTATE_INVALIDARG, "wrong return\n");
94
95     r = MsiEnumFeaturesW(NULL,0,NULL,NULL);
96     ok( r == ERROR_INVALID_PARAMETER,"wrong error\n");
97
98     r = MsiConfigureFeatureW(NULL, NULL, 0);
99     ok( r == ERROR_INVALID_PARAMETER, "wrong error\n");
100
101     r = MsiConfigureFeatureA("{00000000-0000-0000-0000-000000000000}", NULL, 0);
102     ok( r == ERROR_INVALID_PARAMETER, "wrong error\n");
103
104     r = MsiConfigureFeatureA("{00000000-0000-0000-0000-000000000000}", "foo", 0);
105     ok( r == ERROR_INVALID_PARAMETER, "wrong error %d\n", r);
106
107     r = MsiConfigureFeatureA("{00000000-0000-0000-0000-000000000000}", "foo", INSTALLSTATE_DEFAULT);
108     ok( r == ERROR_UNKNOWN_PRODUCT, "wrong error %d\n", r);
109
110     /* make sure empty string to MsiGetProductInfo is not a handle to default registry value, saving and restoring the
111      * necessary registry values */
112
113     /* empty product string */
114     r = RegOpenKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", &hkey);
115     ok( r == ERROR_SUCCESS, "wrong error %d\n", r);
116
117     r = RegQueryValueExA(hkey, NULL, 0, &dwType, lpData, &cbData);
118     ok ( r == ERROR_SUCCESS || r == ERROR_FILE_NOT_FOUND, "wrong error %d\n", r);
119     if ( r == ERROR_SUCCESS )
120     {
121         lpData = HeapAlloc(GetProcessHeap(), 0, cbData);
122         if (!lpData)
123             skip("Out of memory\n");
124         else
125         {
126             r = RegQueryValueExA(hkey, NULL, 0, &dwType, lpData, &cbData);
127             ok ( r == ERROR_SUCCESS, "wrong error %d\n", r);
128         }
129     }
130
131     r = RegSetValueA(hkey, NULL, REG_SZ, "test", strlen("test"));
132     ok( r == ERROR_SUCCESS, "wrong error %d\n", r);
133
134     r = MsiGetProductInfoA("", "", NULL, NULL);
135     ok ( r == ERROR_INVALID_PARAMETER, "wrong error %d\n", r);
136
137     if (lpData)
138     {
139         r = RegSetValueExA(hkey, NULL, 0, dwType, lpData, cbData);
140         ok ( r == ERROR_SUCCESS, "wrong error %d\n", r);
141
142         HeapFree(GetProcessHeap(), 0, lpData);
143     }
144     else
145     {
146         r = RegDeleteValueA(hkey, NULL);
147         ok ( r == ERROR_SUCCESS, "wrong error %d\n", r);
148     }
149
150     r = RegCloseKey(hkey);
151     ok( r == ERROR_SUCCESS, "wrong error %d\n", r);
152
153     /* empty attribute */
154     r = RegCreateKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}", &hkey);
155     ok( r == ERROR_SUCCESS, "wrong error %d\n", r);
156
157     r = RegSetValueA(hkey, NULL, REG_SZ, "test", strlen("test"));
158     ok( r == ERROR_SUCCESS, "wrong error %d\n", r);
159
160     r = MsiGetProductInfoA("{F1C3AF50-8B56-4A69-A00C-00773FE42F30}", "", NULL, NULL);
161     ok ( r == ERROR_UNKNOWN_PROPERTY, "wrong error %d\n", r);
162
163     r = RegCloseKey(hkey);
164     ok( r == ERROR_SUCCESS, "wrong error %d\n", r);
165
166     r = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
167     ok( r == ERROR_SUCCESS, "wrong error %d\n", r);
168 }
169
170 static void test_getcomponentpath(void)
171 {
172     INSTALLSTATE r;
173     char buffer[0x100];
174     DWORD sz;
175
176     if(!pMsiGetComponentPathA)
177         return;
178
179     r = pMsiGetComponentPathA( NULL, NULL, NULL, NULL );
180     ok( r == INSTALLSTATE_INVALIDARG, "wrong return value\n");
181
182     r = pMsiGetComponentPathA( "bogus", "bogus", NULL, NULL );
183     ok( r == INSTALLSTATE_INVALIDARG, "wrong return value\n");
184
185     r = pMsiGetComponentPathA( "bogus", "{00000000-0000-0000-000000000000}", NULL, NULL );
186     ok( r == INSTALLSTATE_INVALIDARG, "wrong return value\n");
187
188     sz = sizeof buffer;
189     buffer[0]=0;
190     r = pMsiGetComponentPathA( "bogus", "{00000000-0000-0000-000000000000}", buffer, &sz );
191     ok( r == INSTALLSTATE_INVALIDARG, "wrong return value\n");
192
193     r = pMsiGetComponentPathA( "{00000000-78E1-11D2-B60F-006097C998E7}",
194         "{00000000-0000-0000-0000-000000000000}", buffer, &sz );
195     ok( r == INSTALLSTATE_UNKNOWN, "wrong return value\n");
196
197     r = pMsiGetComponentPathA( "{00000409-78E1-11D2-B60F-006097C998E7}",
198         "{00000000-0000-0000-0000-00000000}", buffer, &sz );
199     ok( r == INSTALLSTATE_INVALIDARG, "wrong return value\n");
200
201     r = pMsiGetComponentPathA( "{00000409-78E1-11D2-B60F-006097C998E7}",
202         "{029E403D-A86A-1D11-5B5B0006799C897E}", buffer, &sz );
203     ok( r == INSTALLSTATE_INVALIDARG, "wrong return value\n");
204
205     r = pMsiGetComponentPathA( "{00000000-78E1-11D2-B60F-006097C9987e}",
206                             "{00000000-A68A-11d1-5B5B-0006799C897E}", buffer, &sz );
207     ok( r == INSTALLSTATE_UNKNOWN, "wrong return value\n");
208 }
209
210 static void test_filehash(void)
211 {
212     const char name[] = "msitest.bin";
213     const char data[] = {'a','b','c'};
214     HANDLE handle;
215     UINT r;
216     test_MSIFILEHASHINFO hash;
217     DWORD count = 0;
218
219     if (!pMsiGetFileHashA)
220         return;
221
222     DeleteFile(name);
223
224     memset(&hash, 0, sizeof hash);
225     r = pMsiGetFileHashA(name, 0, &hash);
226     ok( r == ERROR_INVALID_PARAMETER, "wrong error %d\n", r);
227
228     r = pMsiGetFileHashA(name, 0, NULL);
229     ok( r == ERROR_INVALID_PARAMETER, "wrong error %d\n", r);
230
231     memset(&hash, 0, sizeof hash);
232     hash.dwFileHashInfoSize = sizeof hash;
233     r = pMsiGetFileHashA(name, 0, &hash);
234     ok( r == ERROR_FILE_NOT_FOUND, "wrong error %d\n", r);
235
236     handle = CreateFile(name, GENERIC_READ|GENERIC_WRITE, 0, NULL, 
237                 CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL);
238     ok(handle != INVALID_HANDLE_VALUE, "failed to create file\n");
239
240     WriteFile(handle, data, sizeof data, &count, NULL);
241     CloseHandle(handle);
242
243     memset(&hash, 0, sizeof hash);
244     r = pMsiGetFileHashA(name, 0, &hash);
245     ok( r == ERROR_INVALID_PARAMETER, "wrong error %d\n", r);
246
247     memset(&hash, 0, sizeof hash);
248     hash.dwFileHashInfoSize = sizeof hash;
249     r = pMsiGetFileHashA(name, 1, &hash);
250     ok( r == ERROR_INVALID_PARAMETER, "wrong error %d\n", r);
251
252     r = pMsiGetFileHashA(name, 0, &hash);
253     ok( r == ERROR_SUCCESS, "wrong error %d\n", r);
254
255     ok(hash.dwFileHashInfoSize == sizeof hash, "hash size changed\n");
256     ok(hash.dwData[0] == 0x98500190 &&
257        hash.dwData[1] == 0xb04fd23c &&
258        hash.dwData[2] == 0x7d3f96d6 &&
259        hash.dwData[3] == 0x727fe128, "hash of abc incorrect\n");
260
261     DeleteFile(name);
262 }
263
264 /* copied from dlls/msi/registry.c */
265 static BOOL squash_guid(LPCWSTR in, LPWSTR out)
266 {
267     DWORD i,n=1;
268     GUID guid;
269
270     if (FAILED(CLSIDFromString((LPOLESTR)in, &guid)))
271         return FALSE;
272
273     for(i=0; i<8; i++)
274         out[7-i] = in[n++];
275     n++;
276     for(i=0; i<4; i++)
277         out[11-i] = in[n++];
278     n++;
279     for(i=0; i<4; i++)
280         out[15-i] = in[n++];
281     n++;
282     for(i=0; i<2; i++)
283     {
284         out[17+i*2] = in[n++];
285         out[16+i*2] = in[n++];
286     }
287     n++;
288     for( ; i<8; i++)
289     {
290         out[17+i*2] = in[n++];
291         out[16+i*2] = in[n++];
292     }
293     out[32]=0;
294     return TRUE;
295 }
296
297 static void create_test_guid(LPSTR prodcode, LPSTR squashed)
298 {
299     WCHAR guidW[MAX_PATH];
300     WCHAR squashedW[MAX_PATH];
301     GUID guid;
302     HRESULT hr;
303     int size;
304
305     hr = CoCreateGuid(&guid);
306     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
307
308     size = StringFromGUID2(&guid, (LPOLESTR)guidW, MAX_PATH);
309     ok(size == 39, "Expected 39, got %d\n", hr);
310
311     WideCharToMultiByte(CP_ACP, 0, guidW, size, prodcode, MAX_PATH, NULL, NULL);
312     squash_guid(guidW, squashedW);
313     WideCharToMultiByte(CP_ACP, 0, squashedW, -1, squashed, MAX_PATH, NULL, NULL);
314 }
315
316 static void get_user_sid(LPSTR *usersid)
317 {
318     HANDLE token;
319     BYTE buf[1024];
320     DWORD size;
321     PTOKEN_USER user;
322
323     OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token);
324     size = sizeof(buf);
325     GetTokenInformation(token, TokenUser, (void *)buf, size, &size);
326     user = (PTOKEN_USER)buf;
327     ConvertSidToStringSid(user->User.Sid, usersid);
328 }
329
330 static void test_MsiQueryProductState(void)
331 {
332     CHAR prodcode[MAX_PATH];
333     CHAR prod_squashed[MAX_PATH];
334     CHAR keypath[MAX_PATH*2];
335     LPSTR usersid;
336     INSTALLSTATE state;
337     LONG res;
338     HKEY userkey, localkey, props;
339     DWORD data;
340
341     create_test_guid(prodcode, prod_squashed);
342     get_user_sid(&usersid);
343
344     /* NULL prodcode */
345     state = MsiQueryProductStateA(NULL);
346     ok(state == INSTALLSTATE_INVALIDARG, "Expected INSTALLSTATE_INVALIDARG, got %d\n", state);
347
348     /* empty prodcode */
349     state = MsiQueryProductStateA("");
350     ok(state == INSTALLSTATE_INVALIDARG, "Expected INSTALLSTATE_INVALIDARG, got %d\n", state);
351
352     /* garbage prodcode */
353     state = MsiQueryProductStateA("garbage");
354     ok(state == INSTALLSTATE_INVALIDARG, "Expected INSTALLSTATE_INVALIDARG, got %d\n", state);
355
356     /* guid without brackets */
357     state = MsiQueryProductStateA("6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D");
358     ok(state == INSTALLSTATE_INVALIDARG, "Expected INSTALLSTATE_INVALIDARG, got %d\n", state);
359
360     /* guid with brackets */
361     state = MsiQueryProductStateA("{6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D}");
362     ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state);
363
364     /* same length as guid, but random */
365     state = MsiQueryProductStateA("A938G02JF-2NF3N93-VN3-2NNF-3KGKALDNF93");
366     ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state);
367
368     /* created guid cannot possibly be an installed product code */
369     state = MsiQueryProductStateA(prodcode);
370     ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state);
371
372     lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Products\\");
373     lstrcatA(keypath, prod_squashed);
374
375     res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey);
376     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
377
378     /* user product key exists */
379     state = MsiQueryProductStateA(prodcode);
380     ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state);
381
382     lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\");
383     lstrcatA(keypath, prodcode);
384
385     res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &localkey);
386     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
387
388     /* local uninstall key exists */
389     state = MsiQueryProductStateA(prodcode);
390     ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state);
391
392     data = 1;
393     res = RegSetValueExA(localkey, "WindowsInstaller", 0, REG_DWORD, (const BYTE *)&data, sizeof(DWORD));
394     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
395
396     /* WindowsInstaller value exists */
397     state = MsiQueryProductStateA(prodcode);
398     ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state);
399
400     RegDeleteValueA(localkey, "WindowsInstaller");
401     RegDeleteKeyA(localkey, "");
402
403     lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\");
404     lstrcatA(keypath, usersid);
405     lstrcatA(keypath, "\\Products\\");
406     lstrcatA(keypath, prod_squashed);
407
408     res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &localkey);
409     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
410
411     /* local product key exists */
412     state = MsiQueryProductStateA(prodcode);
413     ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state);
414
415     res = RegCreateKeyA(localkey, "InstallProperties", &props);
416     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
417
418     /* install properties key exists */
419     state = MsiQueryProductStateA(prodcode);
420     ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state);
421
422     data = 1;
423     res = RegSetValueExA(props, "WindowsInstaller", 0, REG_DWORD, (const BYTE *)&data, sizeof(DWORD));
424     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
425
426     /* WindowsInstaller value exists */
427     state = MsiQueryProductStateA(prodcode);
428     ok(state == INSTALLSTATE_DEFAULT, "Expected INSTALLSTATE_DEFAULT, got %d\n", state);
429
430     data = 2;
431     res = RegSetValueExA(props, "WindowsInstaller", 0, REG_DWORD, (const BYTE *)&data, sizeof(DWORD));
432     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
433
434     /* WindowsInstaller value is not 1 */
435     state = MsiQueryProductStateA(prodcode);
436     ok(state == INSTALLSTATE_DEFAULT, "Expected INSTALLSTATE_DEFAULT, got %d\n", state);
437
438     RegDeleteKeyA(userkey, "");
439
440     /* user product key does not exist */
441     state = MsiQueryProductStateA(prodcode);
442     ok(state == INSTALLSTATE_ABSENT, "Expected INSTALLSTATE_ABSENT, got %d\n", state);
443
444     LocalFree(usersid);
445     RegDeleteValueA(props, "WindowsInstaller");
446     RegDeleteKeyA(props, "");
447     RegDeleteKeyA(localkey, "");
448     RegCloseKey(userkey);
449     RegCloseKey(localkey);
450     RegCloseKey(props);
451 }
452
453 static const char table_enc85[] =
454 "!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO"
455 "PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx"
456 "yz{}~";
457
458 /*
459  *  Encodes a base85 guid given a GUID pointer
460  *  Caller should provide a 21 character buffer for the encoded string.
461  *
462  *  returns TRUE if successful, FALSE if not
463  */
464 static BOOL encode_base85_guid( GUID *guid, LPWSTR str )
465 {
466     unsigned int x, *p, i;
467
468     p = (unsigned int*) guid;
469     for( i=0; i<4; i++ )
470     {
471         x = p[i];
472         *str++ = table_enc85[x%85];
473         x = x/85;
474         *str++ = table_enc85[x%85];
475         x = x/85;
476         *str++ = table_enc85[x%85];
477         x = x/85;
478         *str++ = table_enc85[x%85];
479         x = x/85;
480         *str++ = table_enc85[x%85];
481     }
482     *str = 0;
483
484     return TRUE;
485 }
486
487 static void compose_base85_guid(LPSTR component, LPSTR comp_base85, LPSTR squashed)
488 {
489     WCHAR guidW[MAX_PATH];
490     WCHAR base85W[MAX_PATH];
491     WCHAR squashedW[MAX_PATH];
492     GUID guid;
493     HRESULT hr;
494     int size;
495
496     hr = CoCreateGuid(&guid);
497     ok(hr == S_OK, "Expected S_OK, got %d\n", hr);
498
499     size = StringFromGUID2(&guid, (LPOLESTR)guidW, MAX_PATH);
500     ok(size == 39, "Expected 39, got %d\n", hr);
501
502     WideCharToMultiByte(CP_ACP, 0, guidW, size, component, MAX_PATH, NULL, NULL);
503     encode_base85_guid(&guid, base85W);
504     WideCharToMultiByte(CP_ACP, 0, base85W, -1, comp_base85, MAX_PATH, NULL, NULL);
505     squash_guid(guidW, squashedW);
506     WideCharToMultiByte(CP_ACP, 0, squashedW, -1, squashed, MAX_PATH, NULL, NULL);
507 }
508
509 static void test_MsiQueryFeatureState(void)
510 {
511     HKEY userkey, localkey, compkey;
512     CHAR prodcode[MAX_PATH];
513     CHAR prod_squashed[MAX_PATH];
514     CHAR component[MAX_PATH];
515     CHAR comp_base85[MAX_PATH];
516     CHAR comp_squashed[MAX_PATH];
517     CHAR keypath[MAX_PATH*2];
518     INSTALLSTATE state;
519     LPSTR usersid;
520     LONG res;
521
522     create_test_guid(prodcode, prod_squashed);
523     compose_base85_guid(component, comp_base85, comp_squashed);
524     get_user_sid(&usersid);
525
526     /* NULL prodcode */
527     state = MsiQueryFeatureStateA(NULL, "feature");
528     ok(state == INSTALLSTATE_INVALIDARG, "Expected INSTALLSTATE_INVALIDARG, got %d\n", state);
529
530     /* empty prodcode */
531     state = MsiQueryFeatureStateA("", "feature");
532     ok(state == INSTALLSTATE_INVALIDARG, "Expected INSTALLSTATE_INVALIDARG, got %d\n", state);
533
534     /* garbage prodcode */
535     state = MsiQueryFeatureStateA("garbage", "feature");
536     ok(state == INSTALLSTATE_INVALIDARG, "Expected INSTALLSTATE_INVALIDARG, got %d\n", state);
537
538     /* guid without brackets */
539     state = MsiQueryFeatureStateA("6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D", "feature");
540     ok(state == INSTALLSTATE_INVALIDARG, "Expected INSTALLSTATE_INVALIDARG, got %d\n", state);
541
542     /* guid with brackets */
543     state = MsiQueryFeatureStateA("{6700E8CF-95AB-4D9C-BC2C-15840DEA7A5D}", "feature");
544     ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state);
545
546     /* same length as guid, but random */
547     state = MsiQueryFeatureStateA("A938G02JF-2NF3N93-VN3-2NNF-3KGKALDNF93", "feature");
548     ok(state == INSTALLSTATE_INVALIDARG, "Expected INSTALLSTATE_INVALIDARG, got %d\n", state);
549
550     /* NULL szFeature */
551     state = MsiQueryFeatureStateA(prodcode, NULL);
552     ok(state == INSTALLSTATE_INVALIDARG, "Expected INSTALLSTATE_INVALIDARG, got %d\n", state);
553
554     /* empty szFeature */
555     state = MsiQueryFeatureStateA(prodcode, "");
556     ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state);
557
558     /* feature key does not exist yet */
559     state = MsiQueryFeatureStateA(prodcode, "feature");
560     ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state);
561
562     lstrcpyA(keypath, "Software\\Microsoft\\Installer\\Features\\");
563     lstrcatA(keypath, prod_squashed);
564
565     res = RegCreateKeyA(HKEY_CURRENT_USER, keypath, &userkey);
566     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
567
568     /* feature key exists */
569     state = MsiQueryFeatureStateA(prodcode, "feature");
570     ok(state == INSTALLSTATE_UNKNOWN, "Expected INSTALLSTATE_UNKNOWN, got %d\n", state);
571
572     res = RegSetValueExA(userkey, "feature", 0, REG_SZ, (const BYTE *)"", 8);
573     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
574
575     state = MsiQueryFeatureStateA(prodcode, "feature");
576     ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state);
577
578     lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\");
579     lstrcatA(keypath, usersid);
580     lstrcatA(keypath, "\\Products\\");
581     lstrcatA(keypath, prod_squashed);
582     lstrcatA(keypath, "\\Features");
583
584     res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &localkey);
585     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
586
587     state = MsiQueryFeatureStateA(prodcode, "feature");
588     ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state);
589
590     res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)"aaaaaaaaaaaaaaaaaaa", 20);
591     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
592
593     state = MsiQueryFeatureStateA(prodcode, "feature");
594     ok(state == INSTALLSTATE_BADCONFIG, "Expected INSTALLSTATE_BADCONFIG, got %d\n", state);
595
596     res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)"aaaaaaaaaaaaaaaaaaaa", 21);
597     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
598
599     state = MsiQueryFeatureStateA(prodcode, "feature");
600     ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state);
601
602     res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)"aaaaaaaaaaaaaaaaaaaaa", 22);
603     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
604
605     state = MsiQueryFeatureStateA(prodcode, "feature");
606     ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state);
607
608     res = RegSetValueExA(localkey, "feature", 0, REG_SZ, (const BYTE *)comp_base85, 21);
609     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
610
611     state = MsiQueryFeatureStateA(prodcode, "feature");
612     ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state);
613
614     lstrcpyA(keypath, "Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\");
615     lstrcatA(keypath, usersid);
616     lstrcatA(keypath, "\\Components\\");
617     lstrcatA(keypath, comp_squashed);
618
619     res = RegCreateKeyA(HKEY_LOCAL_MACHINE, keypath, &compkey);
620     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
621
622     state = MsiQueryFeatureStateA(prodcode, "feature");
623     ok(state == INSTALLSTATE_ADVERTISED, "Expected INSTALLSTATE_ADVERTISED, got %d\n", state);
624
625     res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"", 1);
626     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
627
628     state = MsiQueryFeatureStateA(prodcode, "feature");
629     ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state);
630
631     res = RegSetValueExA(compkey, prod_squashed, 0, REG_SZ, (const BYTE *)"apple", 1);
632     ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
633
634     state = MsiQueryFeatureStateA(prodcode, "feature");
635     ok(state == INSTALLSTATE_LOCAL, "Expected INSTALLSTATE_LOCAL, got %d\n", state);
636
637     RegDeleteValueA(compkey, prod_squashed);
638     RegDeleteValueA(compkey, "");
639     RegDeleteValueA(localkey, "feature");
640     RegDeleteValueA(userkey, "feature");
641     RegDeleteKeyA(userkey, "");
642     RegCloseKey(compkey);
643     RegCloseKey(localkey);
644     RegCloseKey(userkey);
645 }
646
647 START_TEST(msi)
648 {
649     HMODULE hmod = GetModuleHandle("msi.dll");
650     pMsiUseFeatureExA = (fnMsiUseFeatureExA) 
651         GetProcAddress(hmod, "MsiUseFeatureExA");
652     pMsiOpenPackageExA = (fnMsiOpenPackageExA) 
653         GetProcAddress(hmod, "MsiOpenPackageExA");
654     pMsiOpenPackageExW = (fnMsiOpenPackageExW) 
655         GetProcAddress(hmod, "MsiOpenPackageExW");
656     pMsiGetComponentPathA = (fnMsiGetComponentPathA)
657         GetProcAddress(hmod, "MsiGetComponentPathA" );
658     pMsiGetFileHashA = (fnMsiGetFileHashA)
659         GetProcAddress(hmod, "MsiGetFileHashA" );
660
661     test_usefeature();
662     test_null();
663     test_getcomponentpath();
664     test_filehash();
665     test_MsiQueryProductState();
666     test_MsiQueryFeatureState();
667 }