Reactos
1/*
2 * Unit tests for profile functions
3 *
4 * Copyright (c) 2003 Stefan Leichter
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 <stdarg.h>
22#include <stdio.h>
23
24#include "wine/test.h"
25#include "windef.h"
26#include "winbase.h"
27#include "windows.h"
28#include "sddl.h"
29
30#define KEY "ProfileInt"
31#define SECTION "Test"
32#define TESTFILE ".\\testwine.ini"
33#define TESTFILE2 ".\\testwine2.ini"
34
35static void check_profile_string_(int line, const char *section, const char *name, const char *file, const char *expect)
36{
37 char value[200] = {0};
38 DWORD ret = GetPrivateProfileStringA(section, name, "default", value, sizeof(value), file);
39 ok_(__FILE__, line)(ret == strlen(expect), "expected len %Iu, got %lu\n", strlen(expect), ret);
40 ok_(__FILE__, line)(!strcmp(value, expect), "expected %s, got %s\n", debugstr_a(expect), debugstr_a(value));
41}
42#define check_profile_string(a, b, c, d) check_profile_string_(__LINE__, a, b, c, d);
43
44struct _profileInt {
45 LPCSTR section;
46 LPCSTR key;
47 LPCSTR value;
48 LPCSTR iniFile;
49 INT defaultVal;
50 UINT result;
51};
52
53static void test_profile_int(void)
54{
55 struct _profileInt profileInt[]={
56 { NULL, NULL, NULL, NULL, 70, 0}, /* 0 */
57 { NULL, NULL, NULL, TESTFILE, -1, 4294967295U},
58 { NULL, NULL, NULL, TESTFILE, 1, 1},
59 { SECTION, NULL, NULL, TESTFILE, -1, 4294967295U},
60 { SECTION, NULL, NULL, TESTFILE, 1, 1},
61 { NULL, KEY, NULL, TESTFILE, -1, 4294967295U}, /* 5 */
62 { NULL, KEY, NULL, TESTFILE, 1, 1},
63 { SECTION, KEY, NULL, TESTFILE, -1, 4294967295U},
64 { SECTION, KEY, NULL, TESTFILE, 1, 1},
65 { SECTION, KEY, "-1", TESTFILE, -1, 4294967295U},
66 { SECTION, KEY, "-1", TESTFILE, 1, 4294967295U}, /* 10 */
67 { SECTION, KEY, "1", TESTFILE, -1, 1},
68 { SECTION, KEY, "1", TESTFILE, 1, 1},
69 { SECTION, KEY, "+1", TESTFILE, -1, 1},
70 { SECTION, KEY, "+1", TESTFILE, 1, 1},
71 { SECTION, KEY, "4294967296", TESTFILE, -1, 0}, /* 15 */
72 { SECTION, KEY, "4294967296", TESTFILE, 1, 0},
73 { SECTION, KEY, "4294967297", TESTFILE, -1, 1},
74 { SECTION, KEY, "4294967297", TESTFILE, 1, 1},
75 { SECTION, KEY, "-4294967297", TESTFILE, -1, 4294967295U},
76 { SECTION, KEY, "-4294967297", TESTFILE, 1, 4294967295U}, /* 20 */
77 { SECTION, KEY, "42A94967297", TESTFILE, -1, 42},
78 { SECTION, KEY, "42A94967297", TESTFILE, 1, 42},
79 { SECTION, KEY, "B4294967297", TESTFILE, -1, 0},
80 { SECTION, KEY, "B4294967297", TESTFILE, 1, 0},
81 };
82 int i, num_test = ARRAY_SIZE(profileInt);
83 char section[64];
84 UINT res;
85
86 DeleteFileA( TESTFILE);
87
88 for (i=0; i < num_test; i++) {
89 if (profileInt[i].value)
90 WritePrivateProfileStringA(SECTION, KEY, profileInt[i].value,
91 profileInt[i].iniFile);
92
93 res = GetPrivateProfileIntA(profileInt[i].section, profileInt[i].key,
94 profileInt[i].defaultVal, profileInt[i].iniFile);
95 ok((res == profileInt[i].result), "test<%02d>: ret<%010u> exp<%010u>\n",
96 i, res, profileInt[i].result);
97
98 sprintf(section, " %s ", profileInt[i].section);
99 res = GetPrivateProfileIntA(profileInt[i].section, profileInt[i].key,
100 profileInt[i].defaultVal, profileInt[i].iniFile);
101 ok((res == profileInt[i].result), "test<%02d>: ret<%010u> exp<%010u>\n",
102 i, res, profileInt[i].result);
103 }
104
105 DeleteFileA( TESTFILE);
106}
107
108static void test_profile_string(void)
109{
110 static WCHAR emptyW[] = { 0 }; /* if "const", GetPrivateProfileStringW(emptyW, ...) crashes on win2k */
111 static const WCHAR keyW[] = { 'k','e','y',0 };
112 static const WCHAR sW[] = { 's',0 };
113 static const WCHAR TESTFILE2W[] = {'.','\\','t','e','s','t','w','i','n','e','2','.','i','n','i',0};
114 static const WCHAR valsectionW[] = {'v','a','l','_','e','_','s','e','c','t','i','o','n',0 };
115 static const WCHAR valnokeyW[] = {'v','a','l','_','n','o','_','k','e','y',0};
116 HANDLE h;
117 int ret;
118 DWORD count;
119 char buf[100];
120 WCHAR bufW[100];
121 char *p;
122 /* test that lines without an '=' will not be enumerated */
123 /* in the case below, name2 is a key while name3 is not. */
124 char content[]="[s]\r\nname1=val1\r\nname2=\r\nname3\r\nname4=val4\r\n";
125 char content2[]="\r\nkey=val_no_section\r\n[]\r\nkey=val_e_section\r\n"
126 "[s]\r\n=val_no_key\r\n[t]\r\n";
127 DeleteFileA( TESTFILE2);
128 h = CreateFileA( TESTFILE2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
129 FILE_ATTRIBUTE_NORMAL, NULL);
130 ok( h != INVALID_HANDLE_VALUE, " cannot create %s\n", TESTFILE2);
131 if( h == INVALID_HANDLE_VALUE) return;
132 WriteFile( h, content, sizeof(content), &count, NULL);
133 CloseHandle( h);
134
135 /* enumerate the keys */
136 ret=GetPrivateProfileStringA( "s", NULL, "", buf, sizeof(buf),
137 TESTFILE2);
138 for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1)
139 p[-1] = ',';
140 /* and test */
141 ok( ret == 18 && !strcmp( buf, "name1,name2,name4"), "wrong keys returned(%d): %s\n", ret,
142 buf);
143
144 /* add a new key to test that the file is quite usable */
145 WritePrivateProfileStringA( "s", "name5", "val5", TESTFILE2);
146 ret=GetPrivateProfileStringA( "s", NULL, "", buf, sizeof(buf),
147 TESTFILE2);
148 for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1)
149 p[-1] = ',';
150 ok( ret == 24 && !strcmp( buf, "name1,name2,name4,name5"), "wrong keys returned(%d): %s\n",
151 ret, buf);
152
153 h = CreateFileA( TESTFILE2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
154 FILE_ATTRIBUTE_NORMAL, NULL);
155 ok( h != INVALID_HANDLE_VALUE, " cannot create %s\n", TESTFILE2);
156 if( h == INVALID_HANDLE_VALUE) return;
157 WriteFile( h, content2, sizeof(content2), &count, NULL);
158 CloseHandle( h);
159
160 /* works only in unicode, ansi crashes */
161 ret=GetPrivateProfileStringW(emptyW, keyW, emptyW, bufW, ARRAY_SIZE(bufW), TESTFILE2W);
162 todo_wine
163 ok(ret == 13, "expected 13, got %u\n", ret);
164 todo_wine
165 ok(!lstrcmpW(valsectionW,bufW), "expected %s, got %s\n",
166 wine_dbgstr_w(valsectionW), wine_dbgstr_w(bufW) );
167
168 /* works only in unicode, ansi crashes */
169 ret=GetPrivateProfileStringW(sW, emptyW, emptyW, bufW, ARRAY_SIZE(bufW), TESTFILE2W);
170 ok(ret == 10, "expected 10, got %u\n", ret);
171 ok(!lstrcmpW(valnokeyW,bufW), "expected %s, got %s\n",
172 wine_dbgstr_w(valnokeyW), wine_dbgstr_w(bufW) );
173
174 DeleteFileA( TESTFILE2);
175}
176
177static void test_profile_sections(void)
178{
179 HANDLE h;
180 int ret;
181 DWORD count;
182 char buf[100];
183 char *p;
184 static const char content[]="[section1]\r\nname1=val1\r\nname2=\r\nname3\r\nname4=val4\r\n[section2]\r\n[section3]\r\n=val5\r\n";
185 static const char testfile4[]=".\\testwine4.ini";
186 BOOL on_win98 = FALSE;
187
188 DeleteFileA( testfile4 );
189 h = CreateFileA( testfile4, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
190 ok( h != INVALID_HANDLE_VALUE, " cannot create %s\n", testfile4);
191 if( h == INVALID_HANDLE_VALUE) return;
192 WriteFile( h, content, sizeof(content), &count, NULL);
193 CloseHandle( h);
194
195 /* Some parameter checking */
196 SetLastError(0xdeadbeef);
197 ret = GetPrivateProfileSectionA( NULL, NULL, 0, NULL );
198 ok( ret == 0, "expected return size 0, got %d\n", ret );
199 ok( GetLastError() == ERROR_INVALID_PARAMETER ||
200 GetLastError() == 0xdeadbeef /* Win98 */,
201 "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
202 if (GetLastError() == 0xdeadbeef) on_win98 = TRUE;
203
204 SetLastError(0xdeadbeef);
205 ret = GetPrivateProfileSectionA( NULL, NULL, 0, testfile4 );
206 ok( ret == 0, "expected return size 0, got %d\n", ret );
207 ok( GetLastError() == ERROR_INVALID_PARAMETER ||
208 GetLastError() == 0xdeadbeef /* Win98 */,
209 "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
210
211 if (!on_win98)
212 {
213 SetLastError(0xdeadbeef);
214 ret = GetPrivateProfileSectionA( "section1", NULL, 0, testfile4 );
215 ok( ret == 0, "expected return size 0, got %d\n", ret );
216 ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
217 }
218
219 SetLastError(0xdeadbeef);
220 ret = GetPrivateProfileSectionA( NULL, buf, sizeof(buf), testfile4 );
221 ok( ret == 0, "expected return size 0, got %d\n", ret );
222 ok( GetLastError() == ERROR_INVALID_PARAMETER,
223 "expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError());
224
225 SetLastError(0xdeadbeef);
226 ret = GetPrivateProfileSectionA( "section1", buf, sizeof(buf), NULL );
227 ok( ret == 0, "expected return size 0, got %d\n", ret );
228 todo_wine
229 ok( GetLastError() == ERROR_FILE_NOT_FOUND,
230 "expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
231
232 /* Existing empty section with no keys */
233 SetLastError(0xdeadbeef);
234 ret=GetPrivateProfileSectionA("section2", buf, sizeof(buf), testfile4);
235 ok( ret == 0, "expected return size 0, got %d\n", ret );
236 ok( GetLastError() == ERROR_SUCCESS,
237 "expected ERROR_SUCCESS, got %ld\n", GetLastError());
238
239 /* Existing section with keys and values*/
240 SetLastError(0xdeadbeef);
241 ret=GetPrivateProfileSectionA("section1", buf, sizeof(buf), testfile4);
242 for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1)
243 p[-1] = ',';
244 ok( ret == 35 && !strcmp( buf, "name1=val1,name2=,name3,name4=val4"), "wrong section returned(%d): %s\n",
245 ret, buf);
246 ok( buf[ret-1] == 0 && buf[ret] == 0, "returned buffer not terminated with double-null\n" );
247 ok( GetLastError() == ERROR_SUCCESS,
248 "expected ERROR_SUCCESS, got %ld\n", GetLastError());
249
250 /* Existing section with no keys but has values */
251 SetLastError(0xdeadbeef);
252 ret=GetPrivateProfileSectionA("section3", buf, sizeof(buf), testfile4);
253 trace("section3 return: %s\n", buf);
254 for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1)
255 p[-1] = ',';
256 ok( ret == 6 && !strcmp( buf, "=val5"), "wrong section returned(%d): %s\n",
257 ret, buf);
258 ok( buf[ret-1] == 0 && buf[ret] == 0, "returned buffer not terminated with double-null\n" );
259 ok( GetLastError() == ERROR_SUCCESS,
260 "expected ERROR_SUCCESS, got %ld\n", GetLastError());
261
262 /* Overflow*/
263 ret=GetPrivateProfileSectionA("section1", buf, 24, testfile4);
264 for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1)
265 p[-1] = ',';
266 ok( ret == 22 && !strcmp( buf, "name1=val1,name2=,name"), "wrong section returned(%d): %s\n",
267 ret, buf);
268 ok( buf[ret] == 0 && buf[ret+1] == 0, "returned buffer not terminated with double-null\n" );
269
270 DeleteFileA( testfile4 );
271}
272
273static void test_profile_sections_names(void)
274{
275 HANDLE h;
276 int ret;
277 DWORD count;
278 char buf[100];
279 WCHAR bufW[100];
280 static const char content[]="[ section1 ]\r\n[section2]\r\n[section3]\r\n";
281 static const char testfile3[]=".\\testwine3.ini";
282 static const WCHAR testfile3W[]={ '.','\\','t','e','s','t','w','i','n','e','3','.','i','n','i',0 };
283 static const WCHAR not_here[] = {'.','\\','n','o','t','_','h','e','r','e','.','i','n','i',0};
284 DeleteFileA( testfile3 );
285 h = CreateFileA( testfile3, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
286 FILE_ATTRIBUTE_NORMAL, NULL);
287 ok( h != INVALID_HANDLE_VALUE, " cannot create %s\n", testfile3);
288 if( h == INVALID_HANDLE_VALUE) return;
289 WriteFile( h, content, sizeof(content), &count, NULL);
290 CloseHandle( h);
291
292 /* Test with sufficiently large buffer */
293 memset(buf, 0xc, sizeof(buf));
294 ret = GetPrivateProfileSectionNamesA( buf, 29, testfile3 );
295 ok( ret == 27, "expected return size 27, got %d\n", ret );
296 ok( (buf[ret-1] == 0 && buf[ret] == 0),
297 "returned buffer not terminated with double-null\n" );
298 ok( !strcmp(buf, "section1"), "Unexpected content %s.\n", debugstr_a(buf));
299
300 /* Test with exactly fitting buffer */
301 memset(buf, 0xc, sizeof(buf));
302 ret = GetPrivateProfileSectionNamesA( buf, 28, testfile3 );
303 ok( ret == 26, "expected return size 26, got %d\n", ret );
304 todo_wine
305 ok( (buf[ret+1] == 0 && buf[ret] == 0) || /* W2K3 and higher */
306 broken(buf[ret+1] == 0xc && buf[ret] == 0), /* NT4, W2K, WinXP */
307 "returned buffer not terminated with double-null\n" );
308
309 /* Test with a buffer too small */
310 memset(buf, 0xc, sizeof(buf));
311 ret = GetPrivateProfileSectionNamesA( buf, 27, testfile3 );
312 ok( ret == 25, "expected return size 25, got %d\n", ret );
313 count = strlen("section1") + sizeof(CHAR) + strlen("section2");
314 todo_wine
315 ok( buf[ret+1] == 0 && buf[ret] == 0,
316 "returned buffer not terminated with double-null\n" );
317
318 /* Tests on nonexistent file */
319 memset(buf, 0xc, sizeof(buf));
320 ret = GetPrivateProfileSectionNamesA( buf, 10, ".\\not_here.ini" );
321 ok( ret == 0, "expected return size 0, got %d\n", ret );
322 ok( buf[0] == 0, "returned buffer not terminated with null\n" );
323 ok( buf[1] != 0, "returned buffer terminated with double-null\n" );
324
325 /* Test with sufficiently large buffer */
326 SetLastError(0xdeadbeef);
327 memset(bufW, 0xcc, sizeof(bufW));
328 ret = GetPrivateProfileSectionNamesW( bufW, 29, testfile3W );
329 if (ret == 0 && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
330 {
331 win_skip("GetPrivateProfileSectionNamesW is not implemented\n");
332 DeleteFileA( testfile3 );
333 return;
334 }
335 ok( ret == 27, "expected return size 27, got %d\n", ret );
336 ok( bufW[ret-1] == 0 && bufW[ret] == 0, "returned buffer not terminated with double-null\n" );
337
338 /* Test with exactly fitting buffer */
339 memset(bufW, 0xcc, sizeof(bufW));
340 ret = GetPrivateProfileSectionNamesW( bufW, 28, testfile3W );
341 ok( ret == 26, "expected return size 26, got %d\n", ret );
342 ok( (bufW[ret+1] == 0 && bufW[ret] == 0) || /* W2K3 and higher */
343 broken(bufW[ret+1] == 0xcccc && bufW[ret] == 0), /* NT4, W2K, WinXP */
344 "returned buffer not terminated with double-null\n" );
345
346 /* Test with a buffer too small */
347 memset(bufW, 0xcc, sizeof(bufW));
348 ret = GetPrivateProfileSectionNamesW( bufW, 27, testfile3W );
349 ok( ret == 25, "expected return size 25, got %d\n", ret );
350 ok( bufW[ret+1] == 0 && bufW[ret] == 0, "returned buffer not terminated with double-null\n" );
351
352 DeleteFileA( testfile3 );
353
354 /* Tests on nonexistent file */
355 memset(bufW, 0xcc, sizeof(bufW));
356 ret = GetPrivateProfileSectionNamesW( bufW, 10, not_here );
357 ok( ret == 0, "expected return size 0, got %d\n", ret );
358 ok( bufW[0] == 0, "returned buffer not terminated with null\n" );
359 ok( bufW[1] != 0, "returned buffer terminated with double-null\n" );
360}
361
362/* If the ini-file has already been opened with CreateFile, WritePrivateProfileString failed in wine with an error ERROR_SHARING_VIOLATION, some testing here */
363static void test_profile_existing(void)
364{
365 static const char *testfile1 = ".\\winesharing1.ini";
366 static const char *testfile2 = ".\\winesharing2.ini";
367
368 static const struct {
369 DWORD dwDesiredAccess;
370 DWORD dwShareMode;
371 DWORD write_error;
372 BOOL read_error;
373 DWORD broken_error;
374 } pe[] = {
375 {GENERIC_READ, FILE_SHARE_READ, ERROR_SHARING_VIOLATION, FALSE },
376 {GENERIC_READ, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION, TRUE },
377 {GENERIC_WRITE, FILE_SHARE_READ, ERROR_SHARING_VIOLATION, FALSE },
378 {GENERIC_WRITE, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION, TRUE },
379 {GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, ERROR_SHARING_VIOLATION, FALSE },
380 {GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION, TRUE },
381 {GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, FALSE, ERROR_SHARING_VIOLATION /* nt4 */},
382 {GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, FALSE, ERROR_SHARING_VIOLATION /* nt4 */},
383 /*Thief demo (bug 5024) opens .ini file like this*/
384 {GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, FALSE, ERROR_SHARING_VIOLATION /* nt4 */}
385 };
386
387 int i;
388 BOOL ret;
389 DWORD size;
390 HANDLE h = 0;
391 char buffer[MAX_PATH];
392
393 for (i=0; i < ARRAY_SIZE(pe); i++)
394 {
395 h = CreateFileA(testfile1, pe[i].dwDesiredAccess, pe[i].dwShareMode, NULL,
396 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
397 ok(INVALID_HANDLE_VALUE != h, "%d: CreateFile failed\n",i);
398 SetLastError(0xdeadbeef);
399
400 ret = WritePrivateProfileStringA(SECTION, KEY, "12345", testfile1);
401 if (!pe[i].write_error)
402 {
403 if (!ret)
404 ok( broken(GetLastError() == pe[i].broken_error),
405 "%d: WritePrivateProfileString failed with error %lu\n", i, GetLastError() );
406 CloseHandle(h);
407 size = GetPrivateProfileStringA(SECTION, KEY, 0, buffer, MAX_PATH, testfile1);
408 if (ret)
409 ok( size == 5, "%d: test failed, number of characters copied: %ld instead of 5\n", i, size );
410 else
411 ok( !size, "%d: test failed, number of characters copied: %ld instead of 0\n", i, size );
412 }
413 else
414 {
415 DWORD err = GetLastError();
416 ok( !ret, "%d: WritePrivateProfileString succeeded\n", i );
417 if (!ret)
418 ok( err == pe[i].write_error, "%d: WritePrivateProfileString failed with error %lu/%lu\n",
419 i, err, pe[i].write_error );
420 CloseHandle(h);
421 size = GetPrivateProfileStringA(SECTION, KEY, 0, buffer, MAX_PATH, testfile1);
422 ok( !size, "%d: test failed, number of characters copied: %ld instead of 0\n", i, size );
423 }
424
425 ok( DeleteFileA(testfile1), "delete failed\n" );
426 }
427
428 h = CreateFileA(testfile2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
429 sprintf( buffer, "[%s]\r\n%s=123\r\n", SECTION, KEY );
430 ok( WriteFile( h, buffer, strlen(buffer), &size, NULL ), "failed to write\n" );
431 CloseHandle( h );
432
433 for (i=0; i < ARRAY_SIZE(pe); i++)
434 {
435 h = CreateFileA(testfile2, pe[i].dwDesiredAccess, pe[i].dwShareMode, NULL,
436 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
437 ok(INVALID_HANDLE_VALUE != h, "%d: CreateFile failed\n",i);
438 SetLastError(0xdeadbeef);
439 ret = GetPrivateProfileStringA(SECTION, KEY, NULL, buffer, MAX_PATH, testfile2);
440 if (!pe[i].read_error)
441 ok( ret, "%d: GetPrivateProfileString failed with error %lu\n", i, GetLastError() );
442 else
443 ok( !ret, "%d: GetPrivateProfileString succeeded\n", i );
444 CloseHandle(h);
445 }
446 ok( DeleteFileA(testfile2), "delete failed\n" );
447}
448
449static void test_profile_delete_on_close(void)
450{
451 HANDLE h;
452 DWORD size, res;
453 static const CHAR testfile[] = ".\\testwine5.ini";
454 static const char contents[] = "[" SECTION "]\n" KEY "=123\n";
455
456 h = CreateFileA(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL,
457 CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
458 res = WriteFile( h, contents, sizeof contents - 1, &size, NULL );
459 ok( res, "Cannot write test file: %lx\n", GetLastError() );
460 ok( size == sizeof contents - 1, "Test file: partial write\n");
461
462 SetLastError(0xdeadbeef);
463 res = GetPrivateProfileIntA(SECTION, KEY, 0, testfile);
464 ok( res == 123, "Got %ld instead of 123\n", res);
465
466 /* This also deletes the file */
467 CloseHandle(h);
468}
469
470static void test_profile_refresh(void)
471{
472 static const CHAR testfile[] = ".\\winetest4.ini";
473 HANDLE h;
474 DWORD size, res;
475 static const char contents1[] = "[" SECTION "]\n" KEY "=123\n";
476 static const char contents2[] = "[" SECTION "]\n" KEY "=124\n";
477
478 h = CreateFileA(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL,
479 CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
480 res = WriteFile( h, contents1, sizeof contents1 - 1, &size, NULL );
481 ok( res, "Cannot write test file: %lx\n", GetLastError() );
482 ok( size == sizeof contents1 - 1, "Test file: partial write\n");
483
484 SetLastError(0xdeadbeef);
485 res = GetPrivateProfileIntA(SECTION, KEY, 0, testfile);
486 ok( res == 123, "Got %ld instead of 123\n", res);
487
488 CloseHandle(h);
489
490 /* Test proper invalidation of wine's profile file cache */
491
492 h = CreateFileA(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL,
493 CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
494 res = WriteFile( h, contents2, sizeof contents2 - 1, &size, NULL );
495 ok( res, "Cannot write test file: %lx\n", GetLastError() );
496 ok( size == sizeof contents2 - 1, "Test file: partial write\n");
497
498 SetLastError(0xdeadbeef);
499 res = GetPrivateProfileIntA(SECTION, KEY, 0, testfile);
500 ok( res == 124, "Got %ld instead of 124\n", res);
501
502 /* This also deletes the file */
503 CloseHandle(h);
504
505 /* Cache must be invalidated if file no longer exists and default must be returned */
506 SetLastError(0xdeadbeef);
507 res = GetPrivateProfileIntA(SECTION, KEY, 421, testfile);
508 ok( res == 421, "Got %ld instead of 421\n", res);
509}
510
511static void create_test_file(LPCSTR name, LPCSTR data, DWORD size)
512{
513 HANDLE hfile;
514 DWORD count;
515
516 hfile = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
517 ok(hfile != INVALID_HANDLE_VALUE, "cannot create %s\n", name);
518 WriteFile(hfile, data, size, &count, NULL);
519 CloseHandle(hfile);
520}
521
522static BOOL emptystr_ok(CHAR emptystr[MAX_PATH])
523{
524 int i;
525
526 for(i = 0;i < MAX_PATH;++i)
527 if(emptystr[i] != 0)
528 {
529 trace("emptystr[%d] = %d\n",i,emptystr[i]);
530 return FALSE;
531 }
532
533 return TRUE;
534}
535
536static void test_profile_directory_readonly(void)
537{
538 BOOL ret;
539 CHAR path_folder[MAX_PATH];
540 CHAR path_file[MAX_PATH];
541 const char *sddl_string_everyone_readonly = "D:PAI(A;;0x1200a9;;;WD)";
542 SECURITY_ATTRIBUTES attributes = {0};
543 char lpStruct[] = { 's', 't', 'r', 'i', 'n', 'g' };
544
545 attributes.nLength = sizeof(attributes);
546 ret = ConvertStringSecurityDescriptorToSecurityDescriptorA(sddl_string_everyone_readonly, SDDL_REVISION_1, &attributes.lpSecurityDescriptor, NULL);
547 ok(ret == TRUE, "ConvertStringSecurityDescriptorToSecurityDescriptor failed: %ld\n", GetLastError());
548
549 GetTempPathA(MAX_PATH, path_folder);
550 lstrcatA(path_folder, "wine-test");
551
552 strcpy(path_file, path_folder);
553 lstrcatA(path_file, "\\tmp.ini");
554
555 ret = CreateDirectoryA(path_folder, &attributes);
556 ok(ret == TRUE, "CreateDirectoryA failed: %ld\n", GetLastError());
557
558 ret = WritePrivateProfileStringA("App", "key", "string", path_file);
559 ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
560
561 ret = WritePrivateProfileSectionA("App", "key=string", path_file);
562 ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
563
564 ret = WritePrivateProfileStructA("App", "key", lpStruct, sizeof(lpStruct), path_file);
565 ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
566
567 ret = RemoveDirectoryA(path_folder);
568 ok(ret == TRUE, "RemoveDirectoryA failed: %ld\n", GetLastError());
569
570 LocalFree(attributes.lpSecurityDescriptor);
571}
572
573static void test_GetPrivateProfileString(const char *content, const char *descript)
574{
575 DWORD ret, len;
576 CHAR buf[MAX_PATH];
577 CHAR def_val[MAX_PATH];
578 CHAR path[MAX_PATH];
579 CHAR windir[MAX_PATH];
580 /* NT series crashes on r/o empty strings, so pass an r/w
581 empty string and check for modification */
582 CHAR emptystr[MAX_PATH] = "";
583 LPSTR tempfile;
584
585 static const char filename[] = ".\\winetest.ini";
586
587 trace("test_GetPrivateProfileStringA: %s\n", descript);
588
589 create_test_file(filename, content, lstrlenA(content));
590
591 /* Run this test series with caching. Wine won't cache profile
592 files younger than 2.1 seconds. */
593 Sleep(2500);
594
595 /* lpAppName is NULL */
596 memset(buf, 0xc, sizeof(buf));
597 lstrcpyA(buf, "kumquat");
598 ret = GetPrivateProfileStringA(NULL, "name1", "default",
599 buf, MAX_PATH, filename);
600 ok(ret == 18, "Expected 18, got %ld\n", ret);
601 len = lstrlenA("section1") + sizeof(CHAR) + lstrlenA("section2") + 2 * sizeof(CHAR);
602
603 ok(!memcmp(buf, "section1\0section2\0", len),
604 "Expected \"section1\\x00section2\\x00\\x00\", got %s\n",
605 debugstr_an(buf, (ret + 2 >= MAX_PATH ? MAX_PATH : ret + 1)));
606
607 /* lpAppName is empty */
608 memset(buf, 0xc, sizeof(buf));
609 lstrcpyA(buf, "kumquat");
610 ret = GetPrivateProfileStringA(emptystr, "name1", "default",
611 buf, MAX_PATH, filename);
612 ok(ret == 7, "Expected 7, got %ld\n", ret);
613 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf);
614 ok(emptystr_ok(emptystr), "AppName modified\n");
615
616 /* lpAppName is missing */
617 memset(buf, 0xc,sizeof(buf));
618 lstrcpyA(buf, "kumquat");
619 ret = GetPrivateProfileStringA("notasection", "name1", "default",
620 buf, MAX_PATH, filename);
621 ok(ret == 7, "Expected 7, got %ld\n", ret);
622 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf);
623
624 /* lpAppName is empty, lpDefault is NULL */
625 memset(buf, 0xc,sizeof(buf));
626 lstrcpyA(buf, "kumquat");
627 ret = GetPrivateProfileStringA(emptystr, "name1", NULL,
628 buf, MAX_PATH, filename);
629 ok(ret == 0, "Expected 0, got %ld\n", ret);
630 ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
631 ok(emptystr_ok(emptystr), "AppName modified\n");
632
633 /* lpAppName is empty, lpDefault is empty */
634 memset(buf, 0xc,sizeof(buf));
635 lstrcpyA(buf, "kumquat");
636 ret = GetPrivateProfileStringA(emptystr, "name1", "",
637 buf, MAX_PATH, filename);
638 ok(ret == 0, "Expected 0, got %ld\n", ret);
639 ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
640 ok(emptystr_ok(emptystr), "AppName modified\n");
641
642 /* lpAppName is empty, lpDefault has trailing blank characters */
643 memset(buf, 0xc,sizeof(buf));
644 lstrcpyA(buf, "kumquat");
645 /* lpDefault must be writable (trailing blanks are removed inplace in win9x) */
646 lstrcpyA(def_val, "default ");
647 ret = GetPrivateProfileStringA(emptystr, "name1", def_val,
648 buf, MAX_PATH, filename);
649 ok(ret == 7, "Expected 7, got %ld\n", ret);
650 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf);
651 ok(emptystr_ok(emptystr), "AppName modified\n");
652
653 /* lpAppName is empty, many blank characters in lpDefault */
654 memset(buf, 0xc,sizeof(buf));
655 lstrcpyA(buf, "kumquat");
656 /* lpDefault must be writable (trailing blanks are removed inplace in win9x) */
657 lstrcpyA(def_val, "one two ");
658 ret = GetPrivateProfileStringA(emptystr, "name1", def_val,
659 buf, MAX_PATH, filename);
660 ok(ret == 7, "Expected 7, got %ld\n", ret);
661 ok(!lstrcmpA(buf, "one two"), "Expected \"one two\", got \"%s\"\n", buf);
662 ok(emptystr_ok(emptystr), "AppName modified\n");
663
664 /* lpAppName is empty, blank character but not trailing in lpDefault */
665 memset(buf, 0xc,sizeof(buf));
666 lstrcpyA(buf, "kumquat");
667 ret = GetPrivateProfileStringA(emptystr, "name1", "one two",
668 buf, MAX_PATH, filename);
669 ok(ret == 7, "Expected 7, got %ld\n", ret);
670 ok(!lstrcmpA(buf, "one two"), "Expected \"one two\", got \"%s\"\n", buf);
671 ok(emptystr_ok(emptystr), "AppName modified\n");
672
673 /* lpKeyName is NULL */
674 memset(buf, 0xc,sizeof(buf));
675 lstrcpyA(buf, "kumquat");
676 ret = GetPrivateProfileStringA("section1", NULL, "default",
677 buf, MAX_PATH, filename);
678 ok(ret == 18, "Expected 18, got %ld\n", ret);
679 ok(!memcmp(buf, "name1\0name2\0name4\0", ret + 1),
680 "Expected \"name1\\x00name2\\x00name4\\x00\\x00\", got %s\n",
681 debugstr_an(buf, (ret + 2 >= MAX_PATH ? MAX_PATH : ret + 1)));
682
683 /* lpKeyName is empty */
684 memset(buf, 0xc,sizeof(buf));
685 lstrcpyA(buf, "kumquat");
686 ret = GetPrivateProfileStringA("section1", emptystr, "default",
687 buf, MAX_PATH, filename);
688 ok(ret == 7, "Expected 7, got %ld\n", ret);
689 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf);
690 ok(emptystr_ok(emptystr), "KeyName modified\n");
691
692 /* lpKeyName is missing */
693 memset(buf, 0xc,sizeof(buf));
694 lstrcpyA(buf, "kumquat");
695 ret = GetPrivateProfileStringA("section1", "notakey", "default",
696 buf, MAX_PATH, filename);
697 ok(ret == 7, "Expected 7, got %ld\n", ret);
698 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf);
699
700 /* lpKeyName is empty, lpDefault is NULL */
701 memset(buf, 0xc,sizeof(buf));
702 lstrcpyA(buf, "kumquat");
703 ret = GetPrivateProfileStringA("section1", emptystr, NULL,
704 buf, MAX_PATH, filename);
705 ok(ret == 0, "Expected 0, got %ld\n", ret);
706 ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
707 ok(emptystr_ok(emptystr), "KeyName modified\n");
708
709 /* lpKeyName is empty, lpDefault is empty */
710 memset(buf, 0xc,sizeof(buf));
711 lstrcpyA(buf, "kumquat");
712 ret = GetPrivateProfileStringA("section1", emptystr, "",
713 buf, MAX_PATH, filename);
714 ok(ret == 0, "Expected 0, got %ld\n", ret);
715 ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
716 ok(emptystr_ok(emptystr), "KeyName modified\n");
717
718 /* lpKeyName is empty, lpDefault has trailing blank characters */
719 memset(buf, 0xc,sizeof(buf));
720 lstrcpyA(buf, "kumquat");
721 /* lpDefault must be writable (trailing blanks are removed inplace in win9x) */
722 lstrcpyA(def_val, "default ");
723 ret = GetPrivateProfileStringA("section1", emptystr, def_val,
724 buf, MAX_PATH, filename);
725 ok(ret == 7, "Expected 7, got %ld\n", ret);
726 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf);
727 ok(emptystr_ok(emptystr), "KeyName modified\n");
728
729 if (0) /* crashes */
730 {
731 /* lpReturnedString is NULL */
732 ret = GetPrivateProfileStringA("section1", "name1", "default",
733 NULL, MAX_PATH, filename);
734 }
735
736 /* lpFileName is NULL */
737 memset(buf, 0xc,sizeof(buf));
738 lstrcpyA(buf, "kumquat");
739 ret = GetPrivateProfileStringA("section1", "name1", "default",
740 buf, MAX_PATH, NULL);
741 ok(ret == 7, "Expected 7, got %ld\n", ret);
742 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf);
743
744 /* lpFileName is empty */
745 memset(buf, 0xc,sizeof(buf));
746 lstrcpyA(buf, "kumquat");
747 ret = GetPrivateProfileStringA("section1", "name1", "default",
748 buf, MAX_PATH, "");
749 ok(ret == 7, "Expected 7, got %ld\n", ret);
750 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf);
751
752 /* lpFileName is nonexistent */
753 memset(buf, 0xc,sizeof(buf));
754 lstrcpyA(buf, "kumquat");
755 ret = GetPrivateProfileStringA("section1", "name1", "default",
756 buf, MAX_PATH, "nonexistent");
757 ok(ret == 7, "Expected 7, got %ld\n", ret);
758 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf);
759
760 /* nSize is 0 */
761 memset(buf, 0xc,sizeof(buf));
762 lstrcpyA(buf, "kumquat");
763 ret = GetPrivateProfileStringA("section1", "name1", "default",
764 buf, 0, filename);
765 ok(ret == 0, "Expected 0, got %ld\n", ret);
766 ok(!lstrcmpA(buf, "kumquat"), "Expected buf to be unchanged, got \"%s\"\n", buf);
767
768 /* nSize is exact size of output */
769 memset(buf, 0xc,sizeof(buf));
770 lstrcpyA(buf, "kumquat");
771 ret = GetPrivateProfileStringA("section1", "name1", "default",
772 buf, 4, filename);
773 ok(ret == 3, "Expected 3, got %ld\n", ret);
774 ok(!lstrcmpA(buf, "val"), "Expected \"val\", got \"%s\"\n", buf);
775
776 /* nSize has room for NULL terminator */
777 memset(buf, 0xc,sizeof(buf));
778 lstrcpyA(buf, "kumquat");
779 ret = GetPrivateProfileStringA("section1", "name1", "default",
780 buf, 5, filename);
781 ok(ret == 4, "Expected 4, got %ld\n", ret);
782 ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf);
783
784 /* output is 1 character */
785 memset(buf, 0xc,sizeof(buf));
786 lstrcpyA(buf, "kumquat");
787 ret = GetPrivateProfileStringA("section1", "name4", "default",
788 buf, MAX_PATH, filename);
789 ok(ret == 1, "Expected 1, got %ld\n", ret);
790 ok(!lstrcmpA(buf, "a"), "Expected \"a\", got \"%s\"\n", buf);
791
792 /* output is 1 character, no room for NULL terminator */
793 memset(buf, 0xc,sizeof(buf));
794 lstrcpyA(buf, "kumquat");
795 ret = GetPrivateProfileStringA("section1", "name4", "default",
796 buf, 1, filename);
797 ok(ret == 0, "Expected 0, got %ld\n", ret);
798 ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
799
800 /* lpAppName is NULL, not enough room for final section name */
801 memset(buf, 0xc,sizeof(buf));
802 lstrcpyA(buf, "kumquat");
803 ret = GetPrivateProfileStringA(NULL, "name1", "default",
804 buf, 16, filename);
805 ok(ret == 14, "Expected 14, got %ld\n", ret);
806 len = lstrlenA("section1") + 2 * sizeof(CHAR);
807 todo_wine
808 ok(!memcmp(buf, "section1\0secti\0", ret + 2),
809 "Expected \"section1\\x00secti\\x00\\x00\", got %s\n",
810 debugstr_an(buf, (ret + 2 >= 16 ? 16 : ret + 1)));
811
812 /* lpKeyName is NULL, not enough room for final key name */
813 memset(buf, 0xc,sizeof(buf));
814 lstrcpyA(buf, "kumquat");
815 ret = GetPrivateProfileStringA("section1", NULL, "default",
816 buf, 16, filename);
817 ok(ret == 14, "Expected 14, got %ld\n", ret);
818 todo_wine
819 ok(!memcmp(buf, "name1\0name2\0na\0", ret + 2),
820 "Expected \"name1\\x00name2\\x00na\\x00\\x00\", got %s\n",
821 debugstr_an(buf, (ret + 2 >= 16 ? 16 : ret + 1)));
822
823 /* key value has quotation marks which are stripped */
824 memset(buf, 0xc,sizeof(buf));
825 lstrcpyA(buf, "kumquat");
826 ret = GetPrivateProfileStringA("section1", "name2", "default",
827 buf, MAX_PATH, filename);
828 ok(ret == 4, "Expected 4, got %ld\n", ret);
829 ok(!lstrcmpA(buf, "val2"), "Expected \"val2\", got \"%s\"\n", buf);
830
831 /* case does not match */
832 memset(buf, 0xc,sizeof(buf));
833 lstrcpyA(buf, "kumquat");
834 ret = GetPrivateProfileStringA("section1", "NaMe1", "default",
835 buf, MAX_PATH, filename);
836 ok(ret == 4, "Expected 4, got %ld\n", ret);
837 ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf);
838
839 /* only filename is used */
840 memset(buf, 0xc,sizeof(buf));
841 lstrcpyA(buf, "kumquat");
842 ret = GetPrivateProfileStringA("section1", "NaMe1", "default",
843 buf, MAX_PATH, "winetest.ini");
844 ok(ret == 7, "Expected 7, got %ld\n", ret);
845 ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf);
846
847 GetWindowsDirectoryA(windir, MAX_PATH);
848 SetLastError(0xdeadbeef);
849 ret = GetTempFileNameA(windir, "pre", 0, path);
850 if (!ret && GetLastError() == ERROR_ACCESS_DENIED)
851 {
852 skip("Not allowed to create a file in the Windows directory\n");
853 DeleteFileA(filename);
854 return;
855 }
856 tempfile = strrchr(path, '\\') + 1;
857 create_test_file(path, content, lstrlenA(content));
858
859 /* only filename is used, file exists in windows directory */
860 memset(buf, 0xc,sizeof(buf));
861 lstrcpyA(buf, "kumquat");
862 ret = GetPrivateProfileStringA("section1", "NaMe1", "default",
863 buf, MAX_PATH, tempfile);
864 ok(ret == 4, "Expected 4, got %ld\n", ret);
865 ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf);
866
867 /* successful case */
868 memset(buf, 0xc,sizeof(buf));
869 lstrcpyA(buf, "kumquat");
870 ret = GetPrivateProfileStringA("section1", "name1", "default",
871 buf, MAX_PATH, filename);
872 ok(ret == 4, "Expected 4, got %ld\n", ret);
873 ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf);
874
875 /* Existing section with no keys in an existing file */
876 memset(buf, 0xc,sizeof(buf));
877 SetLastError(0xdeadbeef);
878 ret=GetPrivateProfileStringA("section2", "DoesntExist", "",
879 buf, MAX_PATH, filename);
880 ok( ret == 0, "expected return size 0, got %ld\n", ret );
881 ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf);
882 todo_wine
883 ok( GetLastError() == 0xdeadbeef ||
884 GetLastError() == ERROR_FILE_NOT_FOUND /* Win 7 */,
885 "expected 0xdeadbeef or ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
886
887
888 DeleteFileA(path);
889 DeleteFileA(filename);
890}
891
892static BOOL check_binary_file_data(LPCSTR path, const VOID *data, DWORD size)
893{
894 HANDLE file;
895 CHAR buf[MAX_PATH];
896 BOOL ret;
897
898 file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
899 if (file == INVALID_HANDLE_VALUE)
900 return FALSE;
901
902 if(size != GetFileSize(file, NULL) )
903 {
904 CloseHandle(file);
905 return FALSE;
906 }
907
908 ret = ReadFile(file, buf, size, &size, NULL);
909 CloseHandle(file);
910 if (!ret)
911 return FALSE;
912
913 return !memcmp(buf, data, size);
914}
915
916static BOOL check_file_data(LPCSTR path, LPCSTR data)
917{
918 return check_binary_file_data(path, data, lstrlenA(data));
919}
920
921static void test_WritePrivateProfileString(void)
922{
923 BOOL ret;
924 LPCSTR data;
925 CHAR path[MAX_PATH];
926 CHAR temp[MAX_PATH];
927 HANDLE file;
928
929 GetTempPathA(MAX_PATH, temp);
930 GetTempFileNameA(temp, "wine", 0, path);
931 DeleteFileA(path);
932
933 /* path is not created yet */
934
935 /* NULL lpAppName */
936 SetLastError(0xdeadbeef);
937 ret = WritePrivateProfileStringA(NULL, "key", "string", path);
938 ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
939 ok(GetLastError() == ERROR_FILE_NOT_FOUND,
940 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
941 ok(GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES,
942 "Expected path to not exist\n");
943
944 GetTempFileNameA(temp, "wine", 0, path);
945
946 /* NULL lpAppName, path exists */
947 data = "";
948 SetLastError(0xdeadbeef);
949 ret = WritePrivateProfileStringA(NULL, "key", "string", path);
950 ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
951 ok(GetLastError() == ERROR_FILE_NOT_FOUND,
952 "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
953 ok(check_file_data(path, data), "File doesn't match\n");
954 DeleteFileA(path);
955
956 if (0)
957 {
958 /* empty lpAppName, crashes on NT4 and higher */
959 data = "[]\r\n"
960 "key=string\r\n";
961 ret = WritePrivateProfileStringA("", "key", "string", path);
962 ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
963 ok(check_file_data(path, data), "File doesn't match\n");
964 DeleteFileA(path);
965 }
966
967 /* NULL lpKeyName */
968 data = "";
969 ret = WritePrivateProfileStringA("App", NULL, "string", path);
970 ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
971 todo_wine
972 {
973 ok(check_file_data(path, data), "File doesn't match\n");
974 }
975 DeleteFileA(path);
976
977 if (0)
978 {
979 /* empty lpKeyName, crashes on NT4 and higher */
980 data = "[App]\r\n"
981 "=string\r\n";
982 ret = WritePrivateProfileStringA("App", "", "string", path);
983 ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
984 todo_wine
985 {
986 ok(check_file_data(path, data), "File doesn't match\n");
987 }
988 DeleteFileA(path);
989 }
990
991 /* NULL lpString */
992 data = "";
993 ret = WritePrivateProfileStringA("App", "key", NULL, path);
994 ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
995 todo_wine
996 {
997 ok(check_file_data(path, data), "File doesn't match\n");
998 }
999 DeleteFileA(path);
1000
1001 /* empty lpString */
1002 data = "[App]\r\n"
1003 "key=\r\n";
1004 ret = WritePrivateProfileStringA("App", "key", "", path);
1005 ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1006 ok(check_file_data(path, data), "File doesn't match\n");
1007 DeleteFileA(path);
1008
1009 /* empty lpFileName */
1010 SetLastError(0xdeadbeef);
1011 ret = WritePrivateProfileStringA("App", "key", "string", "");
1012 ok(ret == FALSE, "Expected FALSE, got %d\n", ret);
1013 ok(GetLastError() == ERROR_ACCESS_DENIED,
1014 "Expected ERROR_ACCESS_DENIED, got %ld\n", GetLastError());
1015
1016 /* Relative paths are relative to X:\\%WINDIR% */
1017 GetWindowsDirectoryA(path, MAX_PATH);
1018 strcat(path, "\\win1.tmp");
1019 file = CreateFileA(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1020 if (!ret && GetLastError() == ERROR_ACCESS_DENIED)
1021 skip("Not allowed to create a file in the Windows directory\n");
1022 else
1023 {
1024 CloseHandle(file);
1025 DeleteFileA(path);
1026
1027 data = "[App]\r\n"
1028 "key=string\r\n";
1029 ret = WritePrivateProfileStringA("App", "key", "string", "win1.tmp");
1030 ok(ret == TRUE, "Expected TRUE, got %d, le=%lu\n", ret, GetLastError());
1031 ok(check_file_data(path, data), "File doesn't match\n");
1032 DeleteFileA(path);
1033 }
1034
1035 GetTempPathA(MAX_PATH, temp);
1036 GetTempFileNameA(temp, "wine", 0, path);
1037
1038 /* build up an INI file */
1039 WritePrivateProfileStringA("App1", "key1", "string1", path);
1040 WritePrivateProfileStringA("App1", "key2", "string2", path);
1041 WritePrivateProfileStringA("App1", "key3", "string3", path);
1042 WritePrivateProfileStringA("App2", "key4", "string4", path);
1043
1044 /* make an addition and verify the INI */
1045 data = "[App1]\r\n"
1046 "key1=string1\r\n"
1047 "key2=string2\r\n"
1048 "key3=string3\r\n"
1049 "[App2]\r\n"
1050 "key4=string4\r\n"
1051 "[App3]\r\n"
1052 "key5=string5\r\n";
1053 ret = WritePrivateProfileStringA("App3", "key5", "string5", path);
1054 ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1055 ok(check_file_data(path, data), "File doesn't match\n");
1056
1057 /* lpString is NULL, key2 key is deleted */
1058 data = "[App1]\r\n"
1059 "key1=string1\r\n"
1060 "key3=string3\r\n"
1061 "[App2]\r\n"
1062 "key4=string4\r\n"
1063 "[App3]\r\n"
1064 "key5=string5\r\n";
1065 ret = WritePrivateProfileStringA("App1", "key2", NULL, path);
1066 ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1067 ok(check_file_data(path, data), "File doesn't match\n");
1068
1069 /* try to delete key2 again */
1070 data = "[App1]\r\n"
1071 "key1=string1\r\n"
1072 "key3=string3\r\n"
1073 "[App2]\r\n"
1074 "key4=string4\r\n"
1075 "[App3]\r\n"
1076 "key5=string5\r\n";
1077 ret = WritePrivateProfileStringA("App1", "key2", NULL, path);
1078 ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1079 ok(check_file_data(path, data), "File doesn't match\n");
1080
1081 /* lpKeyName is NULL, App1 section is deleted */
1082 data = "[App2]\r\n"
1083 "key4=string4\r\n"
1084 "[App3]\r\n"
1085 "key5=string5\r\n";
1086 ret = WritePrivateProfileStringA("App1", NULL, "string1", path);
1087 ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1088 ok(check_file_data(path, data), "File doesn't match\n");
1089
1090 /* lpString is not needed to delete a section */
1091 data = "[App3]\r\n"
1092 "key5=string5\r\n";
1093 ret = WritePrivateProfileStringA("App2", NULL, NULL, path);
1094 ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1095 ok(check_file_data(path, data), "File doesn't match\n");
1096
1097 /* leave just the section */
1098 data = "[App3]\r\n";
1099 ret = WritePrivateProfileStringA("App3", "key5", NULL, path);
1100 ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1101 ok(check_file_data(path, data), "File doesn't match\n");
1102 DeleteFileA(path);
1103
1104 /* NULLs in file before first section. Should be preserved in output */
1105 data = "Data \0 before \0 first \0 section" /* 31 bytes */
1106 "\r\n[section1]\r\n" /* 14 bytes */
1107 "key1=string1\r\n"; /* 14 bytes */
1108 GetTempFileNameA(temp, "wine", 0, path);
1109 create_test_file(path, data, 31);
1110 ret = WritePrivateProfileStringA("section1", "key1", "string1", path);
1111 ok(ret == TRUE, "Expected TRUE, got %d\n", ret);
1112 todo_wine
1113 ok( check_binary_file_data(path, data, 59), "File doesn't match\n");
1114 DeleteFileA(path);
1115}
1116
1117static void test_profile_struct(void)
1118{
1119 static const char expect_data[] = "[s]\r\nkey=616261637573006F\r\n";
1120 static const char expect_data_empty[] = "[s]\r\n";
1121 char buffer[20];
1122 BOOL ret;
1123
1124 SetLastError(0xdeadbeef);
1125 ret = GetPrivateProfileStructA("s", "key", buffer, sizeof(buffer), "./winetest.ini");
1126 ok(!ret, "expected failure\n");
1127 todo_wine ok(GetLastError() == ERROR_BAD_LENGTH, "got error %lu\n", GetLastError());
1128
1129 ret = WritePrivateProfileStructA("s", "key", (void *)"abacus", sizeof("abacus"), "./winetest.ini");
1130 ok(ret, "got error %lu\n", GetLastError());
1131 ok(check_file_data("./winetest.ini", expect_data), "file doesn't match\n");
1132
1133 SetLastError(0xdeadbeef);
1134 ret = GetPrivateProfileStructA("s", "key", buffer, 6, "./winetest.ini");
1135 ok(!ret, "expected failure\n");
1136 todo_wine ok(GetLastError() == ERROR_BAD_LENGTH, "got error %lu\n", GetLastError());
1137
1138 SetLastError(0xdeadbeef);
1139 ret = GetPrivateProfileStructA("s", "key", buffer, 8, "./winetest.ini");
1140 ok(!ret, "expected failure\n");
1141 todo_wine ok(GetLastError() == ERROR_BAD_LENGTH, "got error %lu\n", GetLastError());
1142
1143 memset(buffer, 0xcc, sizeof(buffer));
1144 ret = GetPrivateProfileStructA("s", "key", buffer, 7, "./winetest.ini");
1145 ok(ret, "got error %lu\n", GetLastError());
1146 ok(!strcmp(buffer, "abacus"), "data didn't match\n");
1147
1148 memset(buffer, 0xcc, sizeof(buffer));
1149 ret = GetPrivateProfileStringA("s", "key", "default", buffer, sizeof(buffer), "./winetest.ini");
1150 ok(ret == 16, "got size %u\n", ret);
1151 ok(!strcmp(buffer, "616261637573006F"), "got %s\n", debugstr_a(buffer));
1152
1153 ret = WritePrivateProfileStringA("s", "key", "636163747573006F", "./winetest.ini");
1154 ok(ret, "got error %lu\n", GetLastError());
1155
1156 SetLastError(0xdeadbeef);
1157 ret = GetPrivateProfileStructA("s", "key", buffer, 7, "./winetest.ini");
1158 ok(!ret, "expected failure\n");
1159 todo_wine ok(GetLastError() == ERROR_INVALID_DATA, "got error %lu\n", GetLastError());
1160
1161 ret = WritePrivateProfileStringA("s", "key", "6361637475730083", "./winetest.ini");
1162 ok(ret, "got error %lu\n", GetLastError());
1163
1164 memset(buffer, 0xcc, sizeof(buffer));
1165 ret = GetPrivateProfileStructA("s", "key", buffer, 7, "./winetest.ini");
1166 ok(ret, "got error %lu\n", GetLastError());
1167 ok(!strcmp(buffer, "cactus"), "data didn't match\n");
1168
1169 ret = WritePrivateProfileStringA("s", "key", "636163747573008Q", "./winetest.ini");
1170 ok(ret, "got error %lu\n", GetLastError());
1171
1172 SetLastError(0xdeadbeef);
1173 ret = GetPrivateProfileStructA("s", "key", buffer, 7, "./winetest.ini");
1174 ok(!ret, "expected failure\n");
1175 todo_wine ok(GetLastError() == ERROR_INVALID_DATA, "got error %lu\n", GetLastError());
1176
1177 ret = WritePrivateProfileStringA("s", "key", "16361637475730083", "./winetest.ini");
1178 ok(ret, "got error %lu\n", GetLastError());
1179
1180 SetLastError(0xdeadbeef);
1181 ret = GetPrivateProfileStructA("s", "key", buffer, 7, "./winetest.ini");
1182 ok(!ret, "expected failure\n");
1183 todo_wine ok(GetLastError() == ERROR_BAD_LENGTH, "got error %lu\n", GetLastError());
1184
1185 /* Test deleting struct */
1186#ifdef __REACTOS__
1187 if (is_reactos()) {
1188 ok(FALSE, "FIXME: Deleting private profile struct crashes on ReactOS!\n");
1189 } else {
1190#endif
1191 ret = WritePrivateProfileStructA("s", "key", NULL, sizeof("abacus"), "./winetest.ini");
1192 ok(ret, "got error %lu\n", GetLastError());
1193 ok(check_file_data("./winetest.ini", expect_data_empty), "file doesn't match\n");
1194#ifdef __REACTOS__
1195 }
1196#endif
1197
1198 ret = DeleteFileA("./winetest.ini");
1199 ok(ret, "got error %lu\n", GetLastError());
1200}
1201
1202static void check_registry_value_(int line, HKEY key, const char *value, const char *expect)
1203{
1204 char buffer[30];
1205 DWORD type, size = sizeof(buffer);
1206 LSTATUS ret;
1207
1208 memset(buffer, 0xcc, sizeof(buffer));
1209 ret = RegQueryValueExA(key, value, 0, &type, (BYTE *)buffer, &size);
1210 ok_(__FILE__, line)(!ret, "got error %lu\n", ret);
1211 ok_(__FILE__, line)(!strcmp(buffer, expect), "expected %s, got %s\n", debugstr_a(expect), debugstr_a(buffer));
1212 ok_(__FILE__, line)(type == REG_SZ, "got type %lu\n", type);
1213}
1214#define check_registry_value(a, b, c) check_registry_value_(__LINE__, a, b, c)
1215
1216static void test_registry_mapping(void)
1217{
1218 static const DWORD ivalue = 0xabacab;
1219 HKEY mapping_key, mapped_key, mapping_subkey;
1220 char buffer[30];
1221 LSTATUS ret;
1222#ifdef __REACTOS__
1223 char path[MAX_PATH];
1224
1225 /* Get the real system root, use forward slashes, and lowercase everything other than "C:\" */
1226 GetWindowsDirectoryA(path, sizeof(path));
1227 for (char *p = path; *p; p++)
1228 if (*p == '\\') *p = '/';
1229 else if (p != path) *p = (char)tolower((unsigned char)*p);
1230 strcat(path, "/winetest_map.ini");
1231#endif
1232
1233 /* impersonate ourselves to prevent registry virtualization */
1234 ret = ImpersonateSelf(SecurityImpersonation);
1235 ok(ret, "got error %lu\n", GetLastError());
1236
1237 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE,
1238 "Software\\Microsoft\\Windows NT\\CurrentVersion\\IniFileMapping\\winetest_map.ini",
1239 0, NULL, 0, KEY_READ | KEY_WRITE | KEY_WOW64_64KEY, NULL, &mapping_key, NULL);
1240 if (ret == ERROR_ACCESS_DENIED)
1241 {
1242 skip("Not enough permissions to write to the IniFileMapping key.\n");
1243 return;
1244 }
1245 ok(!ret, "got error %lu\n", ret);
1246
1247 ret = RegSetValueExA(mapping_key, "section1", 0, REG_SZ, (BYTE *)"USR:winetest_map", sizeof("USR:winetest_map"));
1248 ok(!ret, "got error %lu\n", ret);
1249 ret = WritePrivateProfileStringA(NULL, NULL, NULL, "winetest_map.ini");
1250 todo_wine ok(ret, "got error %lu\n", GetLastError());
1251
1252 check_profile_string("section1", "name1", "winetest_map.ini", "default");
1253
1254 ret = WritePrivateProfileStringA("section1", "name1", "value1", "winetest_map.ini");
1255 ok(ret, "got error %lu\n", GetLastError());
1256
1257 check_profile_string("section1", "name1", "winetest_map.ini", "value1");
1258 check_profile_string("section1", "name1", "C:/fake/path/winetest_map.ini", "value1");
1259
1260 ret = RegOpenKeyExA(HKEY_CURRENT_USER, "winetest_map", 0, KEY_READ | KEY_WRITE, &mapped_key);
1261 ok(!ret, "got error %lu\n", ret);
1262 check_registry_value(mapped_key, "name1", "value1");
1263
1264 ret = RegSetValueExA(mapped_key, "name2", 0, REG_SZ, (BYTE *)"value2", sizeof("value2"));
1265 ok(!ret, "got error %lu\n", ret);
1266
1267 check_profile_string("section1", "name2", "winetest_map.ini", "value2");
1268
1269#ifdef __REACTOS__
1270 ret = GetFileAttributesA(path);
1271#else
1272 ret = GetFileAttributesA("C:/windows/winetest_map.ini");
1273#endif
1274 ok(ret == INVALID_FILE_ATTRIBUTES, "winetest_map.ini should not exist.\n");
1275
1276 ret = WritePrivateProfileStringA("section1", "name2", NULL, "winetest_map.ini");
1277 ok(ret, "got error %lu\n", GetLastError());
1278 ret = RegQueryValueExA(mapped_key, "name2", 0, NULL, NULL, NULL);
1279 ok(ret == ERROR_FILE_NOT_FOUND, "got error %lu\n", ret);
1280
1281 /* Test non-string types. */
1282
1283 ret = RegSetValueExA(mapped_key, "name3", 0, REG_DWORD, (BYTE *)&ivalue, sizeof(ivalue));
1284 ok(!ret, "got error %lu\n", ret);
1285 check_profile_string("section1", "name3", "winetest_map.ini", "default");
1286
1287 ret = GetPrivateProfileIntA("section1", "name3", 0, "winetest_map.ini");
1288 ok(ret == 0, "got %#lx\n", ret);
1289
1290 ret = RegSetValueExA(mapped_key, "name3", 0, REG_BINARY, (BYTE *)"value3", sizeof("value3"));
1291 ok(!ret, "got error %lu\n", ret);
1292 check_profile_string("section1", "name3", "winetest_map.ini", "default");
1293
1294 ret = RegSetValueExA(mapped_key, "name3", 0, REG_MULTI_SZ, (BYTE *)"one\0two\0", sizeof("one\0two\0"));
1295 ok(!ret, "got error %lu\n", ret);
1296 check_profile_string("section1", "name3", "winetest_map.ini", "default");
1297
1298 ret = RegSetValueExA(mapped_key, "name3", 0, REG_EXPAND_SZ, (BYTE *)"x%SystemRoot%", sizeof("x%SystemRoot%"));
1299 ok(!ret, "got error %lu\n", ret);
1300 check_profile_string("section1", "name3", "winetest_map.ini", "default");
1301
1302 /* Test WritePrivateProfileSection(). Unlike with .ini files, it doesn't
1303 * remove existing entries. */
1304
1305 ret = WritePrivateProfileStringA("section1", "name4", "value4", "winetest_map.ini");
1306 ok(ret, "got error %lu\n", GetLastError());
1307 ret = WritePrivateProfileStringA("section1", "name5", "value5", "winetest_map.ini");
1308 ok(ret, "got error %lu\n", GetLastError());
1309 ret = WritePrivateProfileSectionA("section1", "name4=four\0name6=six\0", "winetest_map.ini");
1310 ok(ret, "got error %lu\n", GetLastError());
1311 check_profile_string("section1", "name4", "winetest_map.ini", "four");
1312 check_profile_string("section1", "name5", "winetest_map.ini", "value5");
1313 check_profile_string("section1", "name6", "winetest_map.ini", "six");
1314
1315 /* Test deleting the section. */
1316
1317 RegCloseKey(mapped_key);
1318
1319 ret = RegCreateKeyExA(HKEY_CURRENT_USER, "winetest_map\\subkey", 0, NULL, 0, 0, NULL, &mapped_key, NULL);
1320 ok(!ret, "got error %lu\n", ret);
1321 RegCloseKey(mapped_key);
1322
1323 ret = WritePrivateProfileStringA("section1", "name1", "value1", "winetest_map.ini");
1324 ok(ret, "got error %lu\n", GetLastError());
1325 ret = WritePrivateProfileStringA("section1", NULL, NULL, "winetest_map.ini");
1326 ok(ret, "got error %lu\n", GetLastError());
1327 check_profile_string("section1", "name1", "winetest_map.ini", "default");
1328
1329 ret = WritePrivateProfileStringA("section1", "name1", "value1", "winetest_map.ini");
1330 ok(ret, "got error %lu\n", GetLastError());
1331 ret = WritePrivateProfileSectionA("section1", NULL, "winetest_map.ini");
1332 ok(ret, "got error %lu\n", GetLastError());
1333 check_profile_string("section1", "name1", "winetest_map.ini", "default");
1334
1335 ret = RegDeleteKeyA(HKEY_CURRENT_USER, "winetest_map\\subkey");
1336 ok(!ret, "got error %lu\n", ret);
1337 ret = RegDeleteKeyA(HKEY_CURRENT_USER, "winetest_map");
1338 ok(!ret, "got error %lu\n", ret);
1339
1340 /* Test GetPrivateProfileSectionNames(). */
1341
1342 memset(buffer, 0xcc, sizeof(buffer));
1343 ret = GetPrivateProfileSectionNamesA(buffer, 5, "winetest_map.ini");
1344 ok(ret == 3, "got %lu\n", ret);
1345 ok(!memcmp(buffer, "sec\0", 5), "got %s\n", debugstr_an(buffer, ret));
1346
1347 memset(buffer, 0xcc, sizeof(buffer));
1348 ret = GetPrivateProfileSectionNamesA(buffer, sizeof(buffer), "winetest_map.ini");
1349 ok(ret == 9, "got %lu\n", ret);
1350 ok(!memcmp(buffer, "section1\0", 10), "got %s\n", debugstr_an(buffer, ret));
1351
1352 ret = WritePrivateProfileStringA("file_section", "name1", "value1", "winetest_map.ini");
1353 ok(ret, "got error %lu\n", GetLastError());
1354
1355 memset(buffer, 0xcc, sizeof(buffer));
1356 ret = GetPrivateProfileSectionNamesA(buffer, 5, "winetest_map.ini");
1357 ok(ret == 3, "got %lu\n", ret);
1358 ok(!memcmp(buffer, "sec\0", 5), "got %s\n", debugstr_an(buffer, ret));
1359
1360 memset(buffer, 0xcc, sizeof(buffer));
1361 ret = GetPrivateProfileSectionNamesA(buffer, sizeof(buffer), "winetest_map.ini");
1362 ok(ret == 22, "got %lu\n", ret);
1363 ok(!memcmp(buffer, "section1\0file_section\0", 23), "got %s\n", debugstr_an(buffer, ret));
1364
1365#ifdef __REACTOS__
1366 ret = DeleteFileA(path);
1367#else
1368 ret = DeleteFileA("C:/windows/winetest_map.ini");
1369#endif
1370 ok(ret, "got error %lu\n", GetLastError());
1371
1372 /* Test the SYS: prefix. */
1373
1374 ret = RegSetValueExA(mapping_key, "section2", 0, REG_SZ, (BYTE *)"SYS:winetest_map", sizeof("SYS:winetest_map"));
1375 ok(!ret, "got error %lu\n", ret);
1376 ret = WritePrivateProfileStringA(NULL, NULL, NULL, "winetest_map.ini");
1377 todo_wine ok(ret, "got error %lu\n", GetLastError());
1378
1379 check_profile_string("section2", "name1", "winetest_map.ini", "default");
1380
1381 ret = WritePrivateProfileStringA("section2", "name1", "value1", "winetest_map.ini");
1382 ok(ret, "got error %lu\n", GetLastError());
1383
1384 check_profile_string("section2", "name1", "winetest_map.ini", "value1");
1385
1386 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\winetest_map", 0, KEY_READ | KEY_WRITE, &mapped_key);
1387 ok(!ret, "got error %lu\n", ret);
1388 check_registry_value(mapped_key, "name1", "value1");
1389
1390 ret = RegSetValueExA(mapped_key, "name2", 0, REG_SZ, (BYTE *)"value2", sizeof("value2"));
1391 ok(!ret, "got error %lu\n", ret);
1392
1393 check_profile_string("section2", "name2", "winetest_map.ini", "value2");
1394
1395#ifdef __REACTOS__
1396 ret = GetFileAttributesA(path);
1397#else
1398 ret = GetFileAttributesA("C:/windows/winetest_map.ini");
1399#endif
1400 ok(ret == INVALID_FILE_ATTRIBUTES, "winetest_map.ini should not exist.\n");
1401
1402 ret = RegDeleteKeyA(mapped_key, "");
1403 ok(!ret, "got error %lu\n", ret);
1404 RegCloseKey(mapped_key);
1405
1406 /* Try writing directly to the .ini file on disk instead. */
1407
1408 ret = WritePrivateProfileStringA("section3", "name1", "value1", "winetest_map.ini");
1409 ok(ret, "got error %lu\n", GetLastError());
1410 check_profile_string("section3", "name1", "winetest_map.ini", "value1");
1411
1412 ret = RegSetValueExA(mapping_key, "section3", 0, REG_SZ, (BYTE *)"USR:winetest_map", sizeof("USR:winetest_map"));
1413 ok(!ret, "got error %lu\n", ret);
1414 ret = WritePrivateProfileStringA(NULL, NULL, NULL, "winetest_map.ini");
1415 todo_wine ok(ret, "got error %lu\n", GetLastError());
1416
1417 check_profile_string("section3", "name1", "winetest_map.ini", "default");
1418
1419 ret = RegOpenKeyExA(HKEY_CURRENT_USER, "winetest_section3", 0, KEY_READ | KEY_WRITE, &mapped_key);
1420 ok(ret == ERROR_FILE_NOT_FOUND, "got error %lu\n", ret);
1421
1422 ret = WritePrivateProfileStringA("section3", "name1", "value2", "winetest_map.ini");
1423 ok(ret, "got error %lu\n", GetLastError());
1424
1425 check_profile_string("section3", "name1", "winetest_map.ini", "value2");
1426
1427 ret = RegOpenKeyExA(HKEY_CURRENT_USER, "winetest_map", 0, KEY_READ | KEY_WRITE, &mapped_key);
1428 ok(!ret, "got error %lu\n", ret);
1429
1430 ret = RegDeleteKeyA(mapped_key, "");
1431 ok(!ret, "got error %lu\n", ret);
1432 RegCloseKey(mapped_key);
1433
1434 ret = RegDeleteValueA(mapping_key, "section3");
1435 ok(!ret, "got error %lu\n", ret);
1436 ret = WritePrivateProfileStringA(NULL, NULL, NULL, "winetest_map.ini");
1437 todo_wine ok(ret, "got error %lu\n", GetLastError());
1438
1439 check_profile_string("section3", "name1", "winetest_map.ini", "value1");
1440
1441#ifdef __REACTOS__
1442 ret = DeleteFileA(path);
1443#else
1444 ret = DeleteFileA("C:/windows/winetest_map.ini");
1445#endif
1446 ok(ret, "got error %lu\n", GetLastError());
1447
1448 /* Test default keys. */
1449
1450 ret = WritePrivateProfileStringA("section4", "name1", "value1", "winetest_map.ini");
1451 ok(ret, "got error %lu\n", GetLastError());
1452
1453 check_profile_string("section4", "name1", "winetest_map.ini", "value1");
1454
1455#ifdef __REACTOS__
1456 ret = DeleteFileA(path);
1457#else
1458 ret = DeleteFileA("C:/windows/winetest_map.ini");
1459#endif
1460 ok(ret, "got error %lu\n", GetLastError());
1461
1462 ret = RegSetValueExA(mapping_key, NULL, 0, REG_SZ, (BYTE *)"SYS:winetest_default", sizeof("SYS:winetest_default"));
1463 ok(!ret, "got error %lu\n", ret);
1464 ret = WritePrivateProfileStringA(NULL, NULL, NULL, "winetest_map.ini");
1465 todo_wine ok(ret, "got error %lu\n", GetLastError());
1466
1467 ret = WritePrivateProfileStringA("section4", "name1", "value1", "winetest_map.ini");
1468 ok(ret, "got error %lu\n", GetLastError());
1469
1470 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\winetest_default\\section4", 0, KEY_READ, &mapped_key);
1471 ok(!ret, "got error %lu\n", ret);
1472 check_registry_value(mapped_key, "name1", "value1");
1473 RegCloseKey(mapped_key);
1474
1475 ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\winetest_default\\section5",
1476 0, NULL, 0, KEY_WRITE, NULL, &mapped_key, NULL);
1477 ok(!ret, "got error %lu\n", ret);
1478 ret = RegSetValueExA(mapped_key, "name2", 0, REG_SZ, (BYTE *)"value2", sizeof("value2"));
1479 ok(!ret, "got error %lu\n", ret);
1480 RegCloseKey(mapped_key);
1481
1482 check_profile_string("section5", "name2", "winetest_map.ini", "value2");
1483
1484#ifdef __REACTOS__
1485 ret = GetFileAttributesA(path);
1486#else
1487 ret = GetFileAttributesA("C:/windows/winetest_map.ini");
1488#endif
1489 ok(ret == INVALID_FILE_ATTRIBUTES, "winetest_map.ini should not exist.\n");
1490
1491 ret = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "Software\\winetest_default\\Section4");
1492 ret = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "Software\\winetest_default\\Section5");
1493 ret = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "Software\\winetest_default");
1494 ok(!ret, "got error %lu\n", ret);
1495 ret = RegDeleteValueA(mapping_key, NULL);
1496 ok(!ret, "got error %lu\n", ret);
1497
1498 /* Test name-specific mapping. */
1499
1500 ret = RegCreateKeyExA(mapping_key, "section6", 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &mapping_subkey, NULL);
1501 ok(!ret, "got error %lu\n", ret);
1502 ret = RegSetValueExA(mapping_subkey, "name1", 0, REG_SZ, (BYTE *)"USR:winetest_name1", sizeof("USR:winetest_name1"));
1503 ok(!ret, "got error %lu\n", ret);
1504 ret = RegSetValueExA(mapping_subkey, "name2", 0, REG_SZ, (BYTE *)"SYS:winetest_name2", sizeof("SYS:winetest_name2"));
1505 ok(!ret, "got error %lu\n", ret);
1506 ret = WritePrivateProfileStringA(NULL, NULL, NULL, "winetest_map.ini");
1507 todo_wine ok(ret, "got error %lu\n", GetLastError());
1508
1509 ret = WritePrivateProfileStringA("section6", "name1", "value1", "winetest_map.ini");
1510 ok(ret, "got error %lu\n", GetLastError());
1511 check_profile_string("section6", "name1", "winetest_map.ini", "value1");
1512
1513 ret = RegOpenKeyExA(HKEY_CURRENT_USER, "winetest_name1", 0, KEY_READ | KEY_WRITE, &mapped_key);
1514 ok(!ret, "got error %lu\n", ret);
1515 check_registry_value(mapped_key, "name1", "value1");
1516
1517 ret = RegSetValueExA(mapped_key, "name1", 0, REG_SZ, (BYTE *)"one", sizeof("one"));
1518 ok(!ret, "got error %lu\n", ret);
1519 check_profile_string("section6", "name1", "winetest_map.ini", "one");
1520
1521 ret = RegDeleteKeyA(mapped_key, "");
1522 ok(!ret, "got error %lu\n", ret);
1523 RegCloseKey(mapped_key);
1524
1525 ret = WritePrivateProfileStringA("section6", "name2", "value2", "winetest_map.ini");
1526 ok(ret, "got error %lu\n", GetLastError());
1527
1528 ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\winetest_name2", 0, KEY_READ | KEY_WRITE, &mapped_key);
1529 ok(!ret, "got error %lu\n", ret);
1530 check_registry_value(mapped_key, "name2", "value2");
1531
1532 ret = RegSetValueExA(mapped_key, "name2", 0, REG_SZ, (BYTE *)"two", sizeof("two"));
1533 ok(!ret, "got error %lu\n", ret);
1534 check_profile_string("section6", "name2", "winetest_map.ini", "two");
1535
1536 ret = RegDeleteKeyA(mapped_key, "");
1537 ok(!ret, "got error %lu\n", ret);
1538 RegCloseKey(mapped_key);
1539
1540 ret = WritePrivateProfileStringA("section6", "name3", "value3", "winetest_map.ini");
1541 ok(ret, "got error %lu\n", GetLastError());
1542 check_profile_string("section6", "name3", "winetest_map.ini", "value3");
1543#ifdef __REACTOS__
1544 ret = DeleteFileA(path);
1545#else
1546 ret = DeleteFileA("C:/windows/winetest_map.ini");
1547#endif
1548 ok(ret, "got error %lu\n", GetLastError());
1549
1550 /* Test name-specific mapping with Get/WritePrivateProfileSection(). */
1551
1552 ret = WritePrivateProfileStringA("section6", "name2", "value2", "winetest_map.ini");
1553 ok(ret, "got error %lu\n", GetLastError());
1554
1555 ret = WritePrivateProfileStringA("section6", "name3", "value3", "winetest_map.ini");
1556 ok(ret, "got error %lu\n", GetLastError());
1557
1558 ret = WritePrivateProfileSectionA("section6", "name1=one\0name3=three\0", "winetest_map.ini");
1559 ok(ret, "got error %lu\n", GetLastError());
1560 check_profile_string("section6", "name1", "winetest_map.ini", "one");
1561 check_profile_string("section6", "name2", "winetest_map.ini", "value2");
1562 check_profile_string("section6", "name3", "winetest_map.ini", "value3");
1563
1564 ret = RegOpenKeyExA(HKEY_CURRENT_USER, "winetest_name1", 0, KEY_READ | KEY_WRITE, &mapped_key);
1565 ok(!ret, "got error %lu\n", ret);
1566 ret = RegDeleteValueA(mapped_key, "name1");
1567 ok(!ret, "got error %lu\n", ret);
1568 RegCloseKey(mapped_key);
1569
1570 memset(buffer, 0xcc, sizeof(buffer));
1571 ret = GetPrivateProfileSectionA("section6", buffer, 5, "winetest_map.ini");
1572 ok(ret == 3, "got %lu\n", ret);
1573 ok(!memcmp(buffer, "nam\0", 5), "got %s\n", debugstr_an(buffer, ret));
1574
1575 memset(buffer, 0xcc, sizeof(buffer));
1576 ret = GetPrivateProfileSectionA("section6", buffer, sizeof(buffer), "winetest_map.ini");
1577 ok(ret == 26, "got %lu\n", ret);
1578 ok(!memcmp(buffer, "name2=value2\0name3=value3\0", 27), "got %s\n", debugstr_an(buffer, ret));
1579
1580 ret = WritePrivateProfileStringA("section6", NULL, NULL, "winetest_map.ini");
1581 ok(ret, "got error %lu\n", GetLastError());
1582 check_profile_string("section6", "name1", "winetest_map.ini", "default");
1583 check_profile_string("section6", "name2", "winetest_map.ini", "default");
1584 check_profile_string("section6", "name3", "winetest_map.ini", "default");
1585
1586 ret = RegDeleteKeyA(HKEY_CURRENT_USER, "winetest_name1");
1587 ok(!ret, "got error %lu\n", ret);
1588 ret = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "Software\\winetest_name2");
1589 ok(!ret, "got error %lu\n", ret);
1590#ifdef __REACTOS__
1591 ret = DeleteFileA(path);
1592#else
1593 ret = DeleteFileA("C:/windows/winetest_map.ini");
1594#endif
1595 ok(ret, "got error %lu\n", GetLastError());
1596
1597 /* Test name-specific mapping with a default value. */
1598
1599 ret = RegSetValueExA(mapping_subkey, NULL, 0, REG_SZ, (BYTE *)"USR:winetest_default", sizeof("USR:winetest_default"));
1600 ok(!ret, "got error %lu\n", ret);
1601 ret = WritePrivateProfileStringA(NULL, NULL, NULL, "winetest_map.ini");
1602 todo_wine ok(ret, "got error %lu\n", GetLastError());
1603
1604 ret = WritePrivateProfileStringA("section6", "name2", "value2", "winetest_map.ini");
1605 ok(ret, "got error %lu\n", GetLastError());
1606 ret = WritePrivateProfileStringA("section6", "name3", "value3", "winetest_map.ini");
1607 ok(ret, "got error %lu\n", GetLastError());
1608
1609 ret = RegOpenKeyExA(HKEY_CURRENT_USER, "winetest_default", 0, KEY_READ | KEY_WRITE, &mapped_key);
1610 ok(!ret, "got error %lu\n", ret);
1611 check_registry_value(mapped_key, "name3", "value3");
1612
1613 ret = RegSetValueExA(mapped_key, "name3", 0, REG_SZ, (BYTE *)"three", sizeof("three"));
1614 ok(!ret, "got error %lu\n", ret);
1615 check_profile_string("section6", "name3", "winetest_map.ini", "three");
1616
1617 memset(buffer, 0xcc, sizeof(buffer));
1618 ret = GetPrivateProfileSectionA("section6", buffer, sizeof(buffer), "winetest_map.ini");
1619 ok(ret == 25, "got %lu\n", ret);
1620 todo_wine ok(!memcmp(buffer, "name2=value2\0name3=three\0", 26), "got %s\n", debugstr_an(buffer, ret));
1621
1622 ret = WritePrivateProfileSectionA("section6", "name2=duo\0name3=treis\0", "winetest_map.ini");
1623 ok(ret, "got error %lu\n", GetLastError());
1624 check_profile_string("section6", "name2", "winetest_map.ini", "duo");
1625 check_profile_string("section6", "name3", "winetest_map.ini", "treis");
1626
1627 ret = WritePrivateProfileStringA("section6", NULL, NULL, "winetest_map.ini");
1628 ok(ret, "got error %lu\n", GetLastError());
1629 check_profile_string("section6", "name2", "winetest_map.ini", "default");
1630 check_profile_string("section6", "name3", "winetest_map.ini", "default");
1631
1632 ret = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "Software\\winetest_name2");
1633 ok(!ret, "got error %lu\n", ret);
1634 ret = RegDeleteKeyA(HKEY_CURRENT_USER, "winetest_name1");
1635 ok(!ret, "got error %lu\n", ret);
1636 ret = RegDeleteKeyA(mapped_key, "");
1637 ok(!ret, "got error %lu\n", ret);
1638 RegCloseKey(mapped_key);
1639
1640 ret = RegDeleteKeyA(mapping_subkey, "");
1641 ok(!ret, "got error %lu\n", ret);
1642 RegCloseKey(mapping_subkey);
1643
1644 ret = RegDeleteKeyA(mapping_key, "");
1645 ok(!ret, "got error %lu\n", ret);
1646 RegCloseKey(mapping_key);
1647
1648#ifdef __REACTOS__
1649 ret = DeleteFileA(path);
1650#else
1651 ret = DeleteFileA("C:/windows/winetest_map.ini");
1652#endif
1653 ok(!ret, "expected failure\n");
1654 ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %lu\n", GetLastError());
1655 ret = RevertToSelf();
1656 ok(ret, "got error %lu\n", GetLastError());
1657}
1658
1659START_TEST(profile)
1660{
1661 test_profile_int();
1662 test_profile_string();
1663 test_profile_sections();
1664 test_profile_sections_names();
1665 test_profile_existing();
1666 test_profile_delete_on_close();
1667 test_profile_refresh();
1668 test_profile_directory_readonly();
1669 test_GetPrivateProfileString(
1670 "[section1]\r\n"
1671 "name1=val1\r\n"
1672 "name2=\"val2\"\r\n"
1673 "name3\r\n"
1674 "name4=a\r\n"
1675 "[section2]\r\n",
1676 "CR+LF");
1677 test_GetPrivateProfileString(
1678 "[section1]\r"
1679 "name1=val1\r"
1680 "name2=\"val2\"\r"
1681 "name3\r"
1682 "name4=a\r"
1683 "[section2]\r",
1684 "CR only");
1685 test_WritePrivateProfileString();
1686 test_profile_struct();
1687 test_registry_mapping();
1688}